~ubuntu-branches/debian/experimental/parted/experimental

« back to all changes in this revision

Viewing changes to gnulib/lib/wait-process.c

  • Committer: Bazaar Package Importer
  • Author(s): Otavio Salvador, Otavio Salvador, Colin Watson, Xavier Oswald, Xavier Oswald, Colin Watson
  • Date: 2010-02-06 16:39:19 UTC
  • mfrom: (1.1.4 upstream) (7.1.3 squeeze)
  • Revision ID: james.westby@ubuntu.com-20100206163919-rt7jssmitulmp010
Tags: 2.1-1
* New upstream release

[ Otavio Salvador ]
* control.in: bump preferred soname for libreadline (closes: #553824).

[ Colin Watson ]
* control.in: Remove copy-and-paste error from libparted1.8-i18n
  description (closes: #497626).
* copyright: Document parted.info's licence, namely GFDL 1.1 with no
  invariant sections, front-cover texts, or back-cover texts (closes:
  #500201).
* rules: Cell partition tables are misdetected as pc98, so disable pc98
  support on powerpc (closes: #487833).
* control.in: Don't build-depend on libdevmapper-dev on hurd-i386.
* control.in: Build-depend on libdevmapper-dev (>= 1.02.33), for
  dm_task_set_major_minor.

[ Xavier Oswald ]
* debian/control.in: 
  - Change my mail address
  - Bump Standards-Version to 3.8.3
  - Update Build-Depends on debhelper 7
* debian/compat: update version to 7
* Parted not informing the kernel of changes to the partition table 
  (Closes: #557044), fixed upstream

[ Otavio Salvador ]
* debian/watch: fix URL to download
* Switch to quilt to manage patches
  - unpartitioned-disks.dpatch, drop (merged upstream)
  - unblacklist-md.dpatch, drop (merged upstream)
  - amiga-raid-lvm-fix.dpatch, drop (not used for ages)
  - devfs.dpatch, drop (devfs is not used)
  - reiserfs-libname.dpatch, drop (referenced library is unavailable)

[ Xavier Oswald, Colin Watson ]
* Refresh update-ext4-code.patch

[ Otavio Salvador ]
* Fix parted-doc info files installation
* Add lintian overrides for parted package
* Use soname in libparted udeb name

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Waiting for a subprocess to finish.
2
 
   Copyright (C) 2001-2003, 2005-2007 Free Software Foundation, Inc.
3
 
   Written by Bruno Haible <haible@clisp.cons.org>, 2001.
4
 
 
5
 
   This program is free software; you can redistribute it and/or modify
6
 
   it under the terms of the GNU General Public License as published by
7
 
   the Free Software Foundation; either version 2, or (at your option)
8
 
   any later version.
9
 
 
10
 
   This program is distributed in the hope that it will be useful,
11
 
   but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 
   GNU General Public License for more details.
14
 
 
15
 
   You should have received a copy of the GNU General Public License
16
 
   along with this program; if not, write to the Free Software Foundation,
17
 
   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
18
 
 
19
 
 
20
 
#include <config.h>
21
 
 
22
 
/* Specification.  */
23
 
#include "wait-process.h"
24
 
 
25
 
#include <errno.h>
26
 
#include <stdlib.h>
27
 
#include <string.h>
28
 
#include <signal.h>
29
 
 
30
 
#include <sys/types.h>
31
 
 
32
 
#if defined _MSC_VER || defined __MINGW32__
33
 
 
34
 
/* Native Woe32 API.  */
35
 
#include <process.h>
36
 
#define waitpid(pid,statusp,options) _cwait (statusp, pid, WAIT_CHILD)
37
 
#define WAIT_T int
38
 
#define WTERMSIG(x) ((x) & 0xff) /* or: SIGABRT ?? */
39
 
#define WCOREDUMP(x) 0
40
 
#define WEXITSTATUS(x) (((x) >> 8) & 0xff) /* or: (x) ?? */
41
 
#define WIFSIGNALED(x) (WTERMSIG (x) != 0) /* or: ((x) == 3) ?? */
42
 
#define WIFEXITED(x) (WTERMSIG (x) == 0) /* or: ((x) != 3) ?? */
43
 
#define WIFSTOPPED(x) 0
44
 
 
45
 
#else
46
 
 
47
 
/* Unix API.  */
48
 
#include <sys/wait.h>
49
 
/* On Linux, WEXITSTATUS are bits 15..8 and WTERMSIG are bits 7..0, while
50
 
   BeOS uses the contrary.  Therefore we use the abstract macros.  */
51
 
#if HAVE_UNION_WAIT
52
 
# define WAIT_T union wait
53
 
# ifndef WTERMSIG
54
 
#  define WTERMSIG(x) ((x).w_termsig)
55
 
# endif
56
 
# ifndef WCOREDUMP
57
 
#  define WCOREDUMP(x) ((x).w_coredump)
58
 
# endif
59
 
# ifndef WEXITSTATUS
60
 
#  define WEXITSTATUS(x) ((x).w_retcode)
61
 
# endif
62
 
#else
63
 
# define WAIT_T int
64
 
# ifndef WTERMSIG
65
 
#  define WTERMSIG(x) ((x) & 0x7f)
66
 
# endif
67
 
# ifndef WCOREDUMP
68
 
#  define WCOREDUMP(x) ((x) & 0x80)
69
 
# endif
70
 
# ifndef WEXITSTATUS
71
 
#  define WEXITSTATUS(x) (((x) >> 8) & 0xff)
72
 
# endif
73
 
#endif
74
 
/* For valid x, exactly one of WIFSIGNALED(x), WIFEXITED(x), WIFSTOPPED(x)
75
 
   is true.  */
76
 
#ifndef WIFSIGNALED
77
 
# define WIFSIGNALED(x) (WTERMSIG (x) != 0 && WTERMSIG(x) != 0x7f)
78
 
#endif
79
 
#ifndef WIFEXITED
80
 
# define WIFEXITED(x) (WTERMSIG (x) == 0)
81
 
#endif
82
 
#ifndef WIFSTOPPED
83
 
# define WIFSTOPPED(x) (WTERMSIG (x) == 0x7f)
84
 
#endif
85
 
/* Note that portable applications may access
86
 
   WTERMSIG(x) only if WIFSIGNALED(x) is true, and
87
 
   WEXITSTATUS(x) only if WIFEXITED(x) is true.  */
88
 
 
89
 
#endif
90
 
 
91
 
#include "error.h"
92
 
#include "fatal-signal.h"
93
 
#include "xalloc.h"
94
 
#include "gettext.h"
95
 
 
96
 
#define _(str) gettext (str)
97
 
 
98
 
#define SIZEOF(a) (sizeof(a) / sizeof(a[0]))
99
 
 
100
 
 
101
 
#if defined _MSC_VER || defined __MINGW32__
102
 
 
103
 
#define WIN32_LEAN_AND_MEAN
104
 
#include <windows.h>
105
 
 
106
 
/* The return value of spawnvp() is really a process handle as returned
107
 
   by CreateProcess().  Therefore we can kill it using TerminateProcess.  */
108
 
#define kill(pid,sig) TerminateProcess ((HANDLE) (pid), sig)
109
 
 
110
 
#endif
111
 
 
112
 
 
113
 
/* Type of an entry in the slaves array.
114
 
   The 'used' bit determines whether this entry is currently in use.
115
 
   (If pid_t was an atomic type like sig_atomic_t, we could just set the
116
 
   'child' field to 0 when unregistering a slave process, and wouldn't need
117
 
   the 'used' field.)
118
 
   The 'used' and 'child' fields are accessed from within the cleanup_slaves()
119
 
   action, therefore we mark them as 'volatile'.  */
120
 
typedef struct
121
 
{
122
 
  volatile sig_atomic_t used;
123
 
  volatile pid_t child;
124
 
}
125
 
slaves_entry_t;
126
 
 
127
 
/* The registered slave subprocesses.  */
128
 
static slaves_entry_t static_slaves[32];
129
 
static slaves_entry_t * volatile slaves = static_slaves;
130
 
static sig_atomic_t volatile slaves_count = 0;
131
 
static size_t slaves_allocated = SIZEOF (static_slaves);
132
 
 
133
 
/* The termination signal for slave subprocesses.
134
 
   2003-10-07:  Terminator becomes Governator.  */
135
 
#ifdef SIGHUP
136
 
# define TERMINATOR SIGHUP
137
 
#else
138
 
# define TERMINATOR SIGTERM
139
 
#endif
140
 
 
141
 
/* The cleanup action.  It gets called asynchronously.  */
142
 
static void
143
 
cleanup_slaves (void)
144
 
{
145
 
  for (;;)
146
 
    {
147
 
      /* Get the last registered slave.  */
148
 
      size_t n = slaves_count;
149
 
      if (n == 0)
150
 
        break;
151
 
      n--;
152
 
      slaves_count = n;
153
 
      /* Skip unused entries in the slaves array.  */
154
 
      if (slaves[n].used)
155
 
        {
156
 
          pid_t slave = slaves[n].child;
157
 
 
158
 
          /* Kill the slave.  */
159
 
          kill (slave, TERMINATOR);
160
 
        }
161
 
    }
162
 
}
163
 
 
164
 
/* Register a subprocess as being a slave process.  This means that the
165
 
   subprocess will be terminated when its creator receives a catchable fatal
166
 
   signal or exits normally.  Registration ends when wait_subprocess()
167
 
   notices that the subprocess has exited.  */
168
 
void
169
 
register_slave_subprocess (pid_t child)
170
 
{
171
 
  static bool cleanup_slaves_registered = false;
172
 
  if (!cleanup_slaves_registered)
173
 
    {
174
 
      atexit (cleanup_slaves);
175
 
      at_fatal_signal (cleanup_slaves);
176
 
      cleanup_slaves_registered = true;
177
 
    }
178
 
 
179
 
  /* Try to store the new slave in an unused entry of the slaves array.  */
180
 
  {
181
 
    slaves_entry_t *s = slaves;
182
 
    slaves_entry_t *s_end = s + slaves_count;
183
 
 
184
 
    for (; s < s_end; s++)
185
 
      if (!s->used)
186
 
        {
187
 
          /* The two uses of 'volatile' in the slaves_entry_t type above
188
 
             (and ISO C 99 section 5.1.2.3.(5)) ensure that we mark the
189
 
             entry as used only after the child pid has been written to the
190
 
             memory location s->child.  */
191
 
          s->child = child;
192
 
          s->used = 1;
193
 
          return;
194
 
        }
195
 
  }
196
 
 
197
 
  if (slaves_count == slaves_allocated)
198
 
    {
199
 
      /* Extend the slaves array.  Note that we cannot use xrealloc(),
200
 
         because then the cleanup_slaves() function could access an already
201
 
         deallocated array.  */
202
 
      slaves_entry_t *old_slaves = slaves;
203
 
      size_t new_slaves_allocated = 2 * slaves_allocated;
204
 
      slaves_entry_t *new_slaves =
205
 
        (slaves_entry_t *)
206
 
        malloc (new_slaves_allocated * sizeof (slaves_entry_t));
207
 
      if (new_slaves == NULL)
208
 
        {
209
 
          /* xalloc_die() will call exit() which will invoke cleanup_slaves().
210
 
             Additionally we need to kill child, because it's not yet among
211
 
             the slaves list.  */
212
 
          kill (child, TERMINATOR);
213
 
          xalloc_die ();
214
 
        }
215
 
      memcpy (new_slaves, old_slaves,
216
 
              slaves_allocated * sizeof (slaves_entry_t));
217
 
      slaves = new_slaves;
218
 
      slaves_allocated = new_slaves_allocated;
219
 
      /* Now we can free the old slaves array.  */
220
 
      if (old_slaves != static_slaves)
221
 
        free (old_slaves);
222
 
    }
223
 
  /* The three uses of 'volatile' in the types above (and ISO C 99 section
224
 
     5.1.2.3.(5)) ensure that we increment the slaves_count only after the
225
 
     new slave and its 'used' bit have been written to the memory locations
226
 
     that make up slaves[slaves_count].  */
227
 
  slaves[slaves_count].child = child;
228
 
  slaves[slaves_count].used = 1;
229
 
  slaves_count++;
230
 
}
231
 
 
232
 
/* Unregister a child from the list of slave subprocesses.  */
233
 
static inline void
234
 
unregister_slave_subprocess (pid_t child)
235
 
{
236
 
  /* The easiest way to remove an entry from a list that can be used by
237
 
     an asynchronous signal handler is just to mark it as unused.  For this,
238
 
     we rely on sig_atomic_t.  */
239
 
  slaves_entry_t *s = slaves;
240
 
  slaves_entry_t *s_end = s + slaves_count;
241
 
 
242
 
  for (; s < s_end; s++)
243
 
    if (s->used && s->child == child)
244
 
      s->used = 0;
245
 
}
246
 
 
247
 
 
248
 
/* Wait for a subprocess to finish.  Return its exit code.
249
 
   If it didn't terminate correctly, exit if exit_on_error is true, otherwise
250
 
   return 127.  */
251
 
int
252
 
wait_subprocess (pid_t child, const char *progname,
253
 
                 bool ignore_sigpipe, bool null_stderr,
254
 
                 bool slave_process, bool exit_on_error)
255
 
{
256
 
#if HAVE_WAITID && defined WNOWAIT && 0
257
 
  /* Commented out because waitid() with WNOWAIT doesn't work: On Solaris 7
258
 
     and OSF/1 4.0, it returns -1 and sets errno = ECHILD, and on HP-UX 10.20
259
 
     it just hangs.  */
260
 
  /* Use of waitid() with WNOWAIT avoids a race condition: If slave_process is
261
 
     true, and this process sleeps a very long time between the return from
262
 
     waitpid() and the execution of unregister_slave_subprocess(), and
263
 
     meanwhile another process acquires the same PID as child, and then - still
264
 
     before unregister_slave_subprocess() - this process gets a fatal signal,
265
 
     it would kill the other totally unrelated process.  */
266
 
  siginfo_t info;
267
 
  for (;;)
268
 
    {
269
 
      if (waitid (P_PID, child, &info, slave_process ? WNOWAIT : 0) < 0)
270
 
        {
271
 
# ifdef EINTR
272
 
          if (errno == EINTR)
273
 
            continue;
274
 
# endif
275
 
          if (exit_on_error || !null_stderr)
276
 
            error (exit_on_error ? EXIT_FAILURE : 0, errno,
277
 
                   _("%s subprocess"), progname);
278
 
          return 127;
279
 
        }
280
 
 
281
 
      /* info.si_code is set to one of CLD_EXITED, CLD_KILLED, CLD_DUMPED,
282
 
         CLD_TRAPPED, CLD_STOPPED, CLD_CONTINUED.  Loop until the program
283
 
         terminates.  */
284
 
      if (info.si_code == CLD_EXITED
285
 
          || info.si_code == CLD_KILLED || info.si_code == CLD_DUMPED)
286
 
        break;
287
 
    }
288
 
 
289
 
  /* The child process has exited or was signalled.  */
290
 
 
291
 
  if (slave_process)
292
 
    {
293
 
      /* Unregister the child from the list of slave subprocesses, so that
294
 
         later, when we exit, we don't kill a totally unrelated process which
295
 
         may have acquired the same pid.  */
296
 
      unregister_slave_subprocess (child);
297
 
 
298
 
      /* Now remove the zombie from the process list.  */
299
 
      for (;;)
300
 
        {
301
 
          if (waitid (P_PID, child, &info, 0) < 0)
302
 
            {
303
 
# ifdef EINTR
304
 
              if (errno == EINTR)
305
 
                continue;
306
 
# endif
307
 
              if (exit_on_error || !null_stderr)
308
 
                error (exit_on_error ? EXIT_FAILURE : 0, errno,
309
 
                       _("%s subprocess"), progname);
310
 
              return 127;
311
 
            }
312
 
          break;
313
 
        }
314
 
    }
315
 
 
316
 
  switch (info.si_code)
317
 
    {
318
 
    case CLD_KILLED:
319
 
    case CLD_DUMPED:
320
 
# ifdef SIGPIPE
321
 
      if (info.si_status == SIGPIPE && ignore_sigpipe)
322
 
        return 0;
323
 
# endif
324
 
      if (exit_on_error || !null_stderr)
325
 
        error (exit_on_error ? EXIT_FAILURE : 0, 0,
326
 
               _("%s subprocess got fatal signal %d"),
327
 
               progname, info.si_status);
328
 
      return 127;
329
 
    case CLD_EXITED:
330
 
      if (info.si_status == 127)
331
 
        {
332
 
          if (exit_on_error || !null_stderr)
333
 
            error (exit_on_error ? EXIT_FAILURE : 0, 0,
334
 
                   _("%s subprocess failed"), progname);
335
 
          return 127;
336
 
        }
337
 
      return info.si_status;
338
 
    default:
339
 
      abort ();
340
 
    }
341
 
#else
342
 
  /* waitpid() is just as portable as wait() nowadays.  */
343
 
  WAIT_T status;
344
 
 
345
 
  *(int *) &status = 0;
346
 
  for (;;)
347
 
    {
348
 
      int result = waitpid (child, &status, 0);
349
 
 
350
 
      if (result != child)
351
 
        {
352
 
# ifdef EINTR
353
 
          if (errno == EINTR)
354
 
            continue;
355
 
# endif
356
 
# if 0 /* defined ECHILD */
357
 
          if (errno == ECHILD)
358
 
            {
359
 
              /* Child process nonexistent?! Assume it terminated
360
 
                 successfully.  */
361
 
              *(int *) &status = 0;
362
 
              break;
363
 
            }
364
 
# endif
365
 
          if (exit_on_error || !null_stderr)
366
 
            error (exit_on_error ? EXIT_FAILURE : 0, errno,
367
 
                   _("%s subprocess"), progname);
368
 
          return 127;
369
 
        }
370
 
 
371
 
      /* One of WIFSIGNALED (status), WIFEXITED (status), WIFSTOPPED (status)
372
 
         must always be true.  Loop until the program terminates.  */
373
 
      if (!WIFSTOPPED (status))
374
 
        break;
375
 
    }
376
 
 
377
 
  /* The child process has exited or was signalled.  */
378
 
 
379
 
  if (slave_process)
380
 
    /* Unregister the child from the list of slave subprocesses, so that
381
 
       later, when we exit, we don't kill a totally unrelated process which
382
 
       may have acquired the same pid.  */
383
 
    unregister_slave_subprocess (child);
384
 
 
385
 
  if (WIFSIGNALED (status))
386
 
    {
387
 
# ifdef SIGPIPE
388
 
      if (WTERMSIG (status) == SIGPIPE && ignore_sigpipe)
389
 
        return 0;
390
 
# endif
391
 
      if (exit_on_error || !null_stderr)
392
 
        error (exit_on_error ? EXIT_FAILURE : 0, 0,
393
 
               _("%s subprocess got fatal signal %d"),
394
 
               progname, (int) WTERMSIG (status));
395
 
      return 127;
396
 
    }
397
 
  if (WEXITSTATUS (status) == 127)
398
 
    {
399
 
      if (exit_on_error || !null_stderr)
400
 
        error (exit_on_error ? EXIT_FAILURE : 0, 0,
401
 
               _("%s subprocess failed"), progname);
402
 
      return 127;
403
 
    }
404
 
  return WEXITSTATUS (status);
405
 
#endif
406
 
}