Imported Upstream version 1.4.19
[platform/upstream/m4.git] / lib / wait-process.c
1 /* Waiting for a subprocess to finish.
2    Copyright (C) 2001-2003, 2005-2021 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 <https://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 _WIN32 && ! defined __CYGWIN__
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 _GL_ASYNC_SAFE 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 /* The cleanup action, taking a signal argument.
106    It gets called asynchronously.  */
107 static _GL_ASYNC_SAFE void
108 cleanup_slaves_action (int sig _GL_UNUSED)
109 {
110   cleanup_slaves ();
111 }
112
113 /* Register a subprocess as being a slave process.  This means that the
114    subprocess will be terminated when its creator receives a catchable fatal
115    signal or exits normally.  Registration ends when wait_subprocess()
116    notices that the subprocess has exited.  */
117 void
118 register_slave_subprocess (pid_t child)
119 {
120   static bool cleanup_slaves_registered = false;
121   if (!cleanup_slaves_registered)
122     {
123       atexit (cleanup_slaves);
124       if (at_fatal_signal (cleanup_slaves_action) < 0)
125         xalloc_die ();
126       cleanup_slaves_registered = true;
127     }
128
129   /* Try to store the new slave in an unused entry of the slaves array.  */
130   {
131     slaves_entry_t *s = slaves;
132     slaves_entry_t *s_end = s + slaves_count;
133
134     for (; s < s_end; s++)
135       if (!s->used)
136         {
137           /* The two uses of 'volatile' in the slaves_entry_t type above
138              (and ISO C 99 section 5.1.2.3.(5)) ensure that we mark the
139              entry as used only after the child pid has been written to the
140              memory location s->child.  */
141           s->child = child;
142           s->used = 1;
143           return;
144         }
145   }
146
147   if (slaves_count == slaves_allocated)
148     {
149       /* Extend the slaves array.  Note that we cannot use xrealloc(),
150          because then the cleanup_slaves() function could access an already
151          deallocated array.  */
152       slaves_entry_t *old_slaves = slaves;
153       size_t new_slaves_allocated = 2 * slaves_allocated;
154       slaves_entry_t *new_slaves =
155         (slaves_entry_t *)
156         malloc (new_slaves_allocated * sizeof (slaves_entry_t));
157       if (new_slaves == NULL)
158         {
159           /* xalloc_die() will call exit() which will invoke cleanup_slaves().
160              Additionally we need to kill child, because it's not yet among
161              the slaves list.  */
162           kill (child, TERMINATOR);
163           xalloc_die ();
164         }
165       memcpy (new_slaves, old_slaves,
166               slaves_allocated * sizeof (slaves_entry_t));
167       slaves = new_slaves;
168       slaves_allocated = new_slaves_allocated;
169       /* Now we can free the old slaves array.  */
170       if (old_slaves != static_slaves)
171         free (old_slaves);
172     }
173   /* The three uses of 'volatile' in the types above (and ISO C 99 section
174      5.1.2.3.(5)) ensure that we increment the slaves_count only after the
175      new slave and its 'used' bit have been written to the memory locations
176      that make up slaves[slaves_count].  */
177   slaves[slaves_count].child = child;
178   slaves[slaves_count].used = 1;
179   slaves_count++;
180 }
181
182 /* Unregister a child from the list of slave subprocesses.  */
183 static void
184 unregister_slave_subprocess (pid_t child)
185 {
186   /* The easiest way to remove an entry from a list that can be used by
187      an asynchronous signal handler is just to mark it as unused.  For this,
188      we rely on sig_atomic_t.  */
189   slaves_entry_t *s = slaves;
190   slaves_entry_t *s_end = s + slaves_count;
191
192   for (; s < s_end; s++)
193     if (s->used && s->child == child)
194       s->used = 0;
195 }
196
197
198 /* Wait for a subprocess to finish.  Return its exit code.
199    If it didn't terminate correctly, exit if exit_on_error is true, otherwise
200    return 127.  */
201 int
202 wait_subprocess (pid_t child, const char *progname,
203                  bool ignore_sigpipe, bool null_stderr,
204                  bool slave_process, bool exit_on_error,
205                  int *termsigp)
206 {
207 #if HAVE_WAITID && defined WNOWAIT && 0
208   /* Commented out because waitid() without WEXITED and with WNOWAIT doesn't
209      work: On Solaris 7 and OSF/1 4.0, it returns -1 and sets errno = ECHILD,
210      and on HP-UX 10.20 it just hangs.  */
211   /* Use of waitid() with WNOWAIT avoids a race condition: If slave_process is
212      true, and this process sleeps a very long time between the return from
213      waitpid() and the execution of unregister_slave_subprocess(), and
214      meanwhile another process acquires the same PID as child, and then - still
215      before unregister_slave_subprocess() - this process gets a fatal signal,
216      it would kill the other totally unrelated process.  */
217   siginfo_t info;
218
219   if (termsigp != NULL)
220     *termsigp = 0;
221   for (;;)
222     {
223       if (waitid (P_PID, child, &info, WEXITED | (slave_process ? WNOWAIT : 0))
224           < 0)
225         {
226 # ifdef EINTR
227           if (errno == EINTR)
228             continue;
229 # endif
230           if (exit_on_error || !null_stderr)
231             error (exit_on_error ? EXIT_FAILURE : 0, errno,
232                    _("%s subprocess"), progname);
233           return 127;
234         }
235
236       /* info.si_code is set to one of CLD_EXITED, CLD_KILLED, CLD_DUMPED,
237          CLD_TRAPPED, CLD_STOPPED, CLD_CONTINUED.  Loop until the program
238          terminates.  */
239       if (info.si_code == CLD_EXITED
240           || info.si_code == CLD_KILLED || info.si_code == CLD_DUMPED)
241         break;
242     }
243
244   /* The child process has exited or was signalled.  */
245
246   if (slave_process)
247     {
248       /* Unregister the child from the list of slave subprocesses, so that
249          later, when we exit, we don't kill a totally unrelated process which
250          may have acquired the same pid.  */
251       unregister_slave_subprocess (child);
252
253       /* Now remove the zombie from the process list.  */
254       for (;;)
255         {
256           if (waitid (P_PID, child, &info, WEXITED) < 0)
257             {
258 # ifdef EINTR
259               if (errno == EINTR)
260                 continue;
261 # endif
262               if (exit_on_error || !null_stderr)
263                 error (exit_on_error ? EXIT_FAILURE : 0, errno,
264                        _("%s subprocess"), progname);
265               return 127;
266             }
267           break;
268         }
269     }
270
271   switch (info.si_code)
272     {
273     case CLD_KILLED:
274     case CLD_DUMPED:
275       if (termsigp != NULL)
276         *termsigp = info.si_status; /* TODO: or info.si_signo? */
277 # ifdef SIGPIPE
278       if (info.si_status == SIGPIPE && ignore_sigpipe)
279         return 0;
280 # endif
281       if (exit_on_error || (!null_stderr && termsigp == NULL))
282         error (exit_on_error ? EXIT_FAILURE : 0, 0,
283                _("%s subprocess got fatal signal %d"),
284                progname, info.si_status);
285       return 127;
286     case CLD_EXITED:
287       if (info.si_status == 127)
288         {
289           if (exit_on_error || !null_stderr)
290             error (exit_on_error ? EXIT_FAILURE : 0, 0,
291                    _("%s subprocess failed"), progname);
292           return 127;
293         }
294       return info.si_status;
295     default:
296       abort ();
297     }
298 #else
299   /* waitpid() is just as portable as wait() nowadays.  */
300   int status;
301
302   if (termsigp != NULL)
303     *termsigp = 0;
304   status = 0;
305   for (;;)
306     {
307       int result = waitpid (child, &status, 0);
308
309       if (result != child)
310         {
311 # ifdef EINTR
312           if (errno == EINTR)
313             continue;
314 # endif
315 # if 0 /* defined ECHILD */
316           if (errno == ECHILD)
317             {
318               /* Child process nonexistent?! Assume it terminated
319                  successfully.  */
320               status = 0;
321               break;
322             }
323 # endif
324           if (exit_on_error || !null_stderr)
325             error (exit_on_error ? EXIT_FAILURE : 0, errno,
326                    _("%s subprocess"), progname);
327           return 127;
328         }
329
330       /* One of WIFSIGNALED (status), WIFEXITED (status), WIFSTOPPED (status)
331          must always be true, since we did not specify WCONTINUED in the
332          waitpid() call.  Loop until the program terminates.  */
333       if (!WIFSTOPPED (status))
334         break;
335     }
336
337   /* The child process has exited or was signalled.  */
338
339   if (slave_process)
340     /* Unregister the child from the list of slave subprocesses, so that
341        later, when we exit, we don't kill a totally unrelated process which
342        may have acquired the same pid.  */
343     unregister_slave_subprocess (child);
344
345   if (WIFSIGNALED (status))
346     {
347       if (termsigp != NULL)
348         *termsigp = WTERMSIG (status);
349 # ifdef SIGPIPE
350       if (WTERMSIG (status) == SIGPIPE && ignore_sigpipe)
351         return 0;
352 # endif
353       if (exit_on_error || (!null_stderr && termsigp == NULL))
354         error (exit_on_error ? EXIT_FAILURE : 0, 0,
355                _("%s subprocess got fatal signal %d"),
356                progname, (int) WTERMSIG (status));
357       return 127;
358     }
359   if (!WIFEXITED (status))
360     abort ();
361   if (WEXITSTATUS (status) == 127)
362     {
363       if (exit_on_error || !null_stderr)
364         error (exit_on_error ? EXIT_FAILURE : 0, 0,
365                _("%s subprocess failed"), progname);
366       return 127;
367     }
368   return WEXITSTATUS (status);
369 #endif
370 }