• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Waiting for a subprocess to finish.
2    Copyright (C) 2001-2003, 2005-2012 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
cleanup_slaves(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
register_slave_subprocess(pid_t child)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 void
unregister_slave_subprocess(pid_t child)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
wait_subprocess(pid_t child,const char * progname,bool ignore_sigpipe,bool null_stderr,bool slave_process,bool exit_on_error,int * termsigp)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 }
362