Verify an assumption.
[gnulib.git] / lib / wait-process.c
index 0fd6f26..7db25e9 100644 (file)
@@ -1,11 +1,11 @@
 /* Waiting for a subprocess to finish.
-   Copyright (C) 2001-2003 Free Software Foundation, Inc.
+   Copyright (C) 2001-2003, 2005-2008 Free Software Foundation, Inc.
    Written by Bruno Haible <haible@clisp.cons.org>, 2001.
 
-   This program is free software; you can redistribute it and/or modify
+   This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2, or (at your option)
-   any later version.
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software Foundation,
-   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
+#include <config.h>
 
 /* Specification.  */
 #include "wait-process.h"
 #include <signal.h>
 
 #include <sys/types.h>
-
-#if defined _MSC_VER || defined __MINGW32__
-
-/* Native Woe32 API.  */
-#include <process.h>
-#define waitpid(pid,statusp,options) _cwait (statusp, pid, WAIT_CHILD)
-#define WAIT_T int
-#define WTERMSIG(x) ((x) & 0xff) /* or: SIGABRT ?? */
-#define WCOREDUMP(x) 0
-#define WEXITSTATUS(x) (((x) >> 8) & 0xff) /* or: (x) ?? */
-#define WIFSIGNALED(x) (WTERMSIG (x) != 0) /* or: ((x) == 3) ?? */
-#define WIFEXITED(x) (WTERMSIG (x) == 0) /* or: ((x) != 3) ?? */
-#define WIFSTOPPED(x) 0
-
-#else
-
-/* Unix API.  */
 #include <sys/wait.h>
-/* On Linux, WEXITSTATUS are bits 15..8 and WTERMSIG are bits 7..0, while
-   BeOS uses the contrary.  Therefore we use the abstract macros.  */
-#if HAVE_UNION_WAIT
-# define WAIT_T union wait
-# ifndef WTERMSIG
-#  define WTERMSIG(x) ((x).w_termsig)
-# endif
-# ifndef WCOREDUMP
-#  define WCOREDUMP(x) ((x).w_coredump)
-# endif
-# ifndef WEXITSTATUS
-#  define WEXITSTATUS(x) ((x).w_retcode)
-# endif
-#else
-# define WAIT_T int
-# ifndef WTERMSIG
-#  define WTERMSIG(x) ((x) & 0x7f)
-# endif
-# ifndef WCOREDUMP
-#  define WCOREDUMP(x) ((x) & 0x80)
-# endif
-# ifndef WEXITSTATUS
-#  define WEXITSTATUS(x) (((x) >> 8) & 0xff)
-# endif
-#endif
-/* For valid x, exactly one of WIFSIGNALED(x), WIFEXITED(x), WIFSTOPPED(x)
-   is true.  */
-#ifndef WIFSIGNALED
-# define WIFSIGNALED(x) (WTERMSIG (x) != 0 && WTERMSIG(x) != 0x7f)
-#endif
-#ifndef WIFEXITED
-# define WIFEXITED(x) (WTERMSIG (x) == 0)
-#endif
-#ifndef WIFSTOPPED
-# define WIFSTOPPED(x) (WTERMSIG (x) == 0x7f)
-#endif
-/* Note that portable applications may access
-   WTERMSIG(x) only if WIFSIGNALED(x) is true, and
-   WEXITSTATUS(x) only if WIFEXITED(x) is true.  */
-
-#endif
 
 #include "error.h"
-#include "exit.h"
 #include "fatal-signal.h"
 #include "xalloc.h"
 #include "gettext.h"
@@ -205,6 +143,7 @@ register_slave_subprocess (pid_t child)
       slaves_entry_t *old_slaves = slaves;
       size_t new_slaves_allocated = 2 * slaves_allocated;
       slaves_entry_t *new_slaves =
+       (slaves_entry_t *)
        malloc (new_slaves_allocated * sizeof (slaves_entry_t));
       if (new_slaves == NULL)
        {
@@ -251,14 +190,15 @@ unregister_slave_subprocess (pid_t child)
    If it didn't terminate correctly, exit if exit_on_error is true, otherwise
    return 127.  */
 int
-wait_subprocess (pid_t child, const char *progname, int *exitsignal,
+wait_subprocess (pid_t child, const char *progname,
                 bool ignore_sigpipe, bool null_stderr,
-                bool slave_process, bool exit_on_error)
+                bool slave_process, bool exit_on_error,
+                int *termsigp)
 {
 #if HAVE_WAITID && defined WNOWAIT && 0
-  /* Commented out because waitid() with WNOWAIT doesn't work: On Solaris 7
-     and OSF/1 4.0, it returns -1 and sets errno = ECHILD, and on HP-UX 10.20
-     it just hangs.  */
+  /* Commented out because waitid() without WEXITED and with WNOWAIT doesn't
+     work: On Solaris 7 and OSF/1 4.0, it returns -1 and sets errno = ECHILD,
+     and on HP-UX 10.20 it just hangs.  */
   /* Use of waitid() with WNOWAIT avoids a race condition: If slave_process is
      true, and this process sleeps a very long time between the return from
      waitpid() and the execution of unregister_slave_subprocess(), and
@@ -266,9 +206,13 @@ wait_subprocess (pid_t child, const char *progname, int *exitsignal,
      before unregister_slave_subprocess() - this process gets a fatal signal,
      it would kill the other totally unrelated process.  */
   siginfo_t info;
+
+  if (termsigp != NULL)
+    *termsigp = 0;
   for (;;)
     {
-      if (waitid (P_PID, child, &info, slave_process ? WNOWAIT : 0) < 0)
+      if (waitid (P_PID, child, &info, WEXITED | (slave_process ? WNOWAIT : 0))
+         < 0)
        {
 # ifdef EINTR
          if (errno == EINTR)
@@ -300,7 +244,7 @@ wait_subprocess (pid_t child, const char *progname, int *exitsignal,
       /* Now remove the zombie from the process list.  */
       for (;;)
        {
-         if (waitid (P_PID, child, &info, 0) < 0)
+         if (waitid (P_PID, child, &info, WEXITED) < 0)
            {
 # ifdef EINTR
              if (errno == EINTR)
@@ -319,6 +263,8 @@ wait_subprocess (pid_t child, const char *progname, int *exitsignal,
     {
     case CLD_KILLED:
     case CLD_DUMPED:
+      if (termsigp != NULL)
+       *termsigp = info.si_status; /* TODO: or info.si_signo? */
 # ifdef SIGPIPE
       if (info.si_status == SIGPIPE && ignore_sigpipe)
        return 0;
@@ -342,10 +288,11 @@ wait_subprocess (pid_t child, const char *progname, int *exitsignal,
     }
 #else
   /* waitpid() is just as portable as wait() nowadays.  */
-  WAIT_T status;
+  int status;
 
+  if (termsigp != NULL)
+    *termsigp = 0;
   *(int *) &status = 0;
-  if (exitsignal) *exitsignal = 0;
   for (;;)
     {
       int result = waitpid (child, &status, 0);
@@ -372,7 +319,8 @@ wait_subprocess (pid_t child, const char *progname, int *exitsignal,
        }
 
       /* One of WIFSIGNALED (status), WIFEXITED (status), WIFSTOPPED (status)
-        must always be true.  Loop until the program terminates.  */
+        must always be true, since we did not specify WCONTINUED in the
+        waitpid() call.  Loop until the program terminates.  */
       if (!WIFSTOPPED (status))
        break;
     }
@@ -387,6 +335,8 @@ wait_subprocess (pid_t child, const char *progname, int *exitsignal,
 
   if (WIFSIGNALED (status))
     {
+      if (termsigp != NULL)
+       *termsigp = WTERMSIG (status);
 # ifdef SIGPIPE
       if (WTERMSIG (status) == SIGPIPE && ignore_sigpipe)
        return 0;
@@ -395,9 +345,10 @@ wait_subprocess (pid_t child, const char *progname, int *exitsignal,
        error (exit_on_error ? EXIT_FAILURE : 0, 0,
               _("%s subprocess got fatal signal %d"),
               progname, (int) WTERMSIG (status));
-      if (exitsignal) *exitsignal = WTERMSIG (status);
       return 127;
     }
+  if (!WIFEXITED (status))
+    abort ();
   if (WEXITSTATUS (status) == 127)
     {
       if (exit_on_error || !null_stderr)