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