~ubuntu-branches/ubuntu/precise/wget/precise-proposed

« back to all changes in this revision

Viewing changes to lib/wait-process.c

  • Committer: Bazaar Package Importer
  • Author(s): Steve Langasek
  • Date: 2011-10-19 00:00:09 UTC
  • mfrom: (2.1.13 sid)
  • Revision ID: james.westby@ubuntu.com-20111019000009-8p33w3wz4b1rdri0
Tags: 1.13-1ubuntu1
* Merge from Debian unstable, remaining changes:
  - Add wget-udeb to ship wget.gnu as alternative to busybox wget
    implementation.
  - Depend on libssl-dev 0.9.8k-7ubuntu4 (LP: #503339)
* Dropped changes, superseded in Debian:
  - Keep build dependencies in main:
    + debian/control: remove info2man build-dep
    + debian/patches/series: disable wget-infopod_generated_manpage
  - Mark wget Multi-Arch: foreign, so packages that aren't of the same arch
    can depend on it.
* Pass --with-ssl=openssl; we don't want to use gnutls, there's no udeb for
  it.
* Add a second build pass for the udeb, so we can build without libidn.

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