/* iswait.c Wait for a process to finish. Copyright (C) 1992 Ian Lance Taylor This file is part of the Taylor UUCP package. 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 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 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. The author of the program may be contacted at ian@airs.com or c/o Cygnus Support, 48 Grove Street, Somerville, MA 02144. */ #include "uucp.h" #include "uudefs.h" #include "sysdep.h" #include #if HAVE_SYS_WAIT_H #include #endif /* We use a typedef wait_status for wait (waitpid, wait4) to put results into. We define the POSIX examination functions we need if they are not already defined (if they aren't defined, I assume that we have a standard wait status). */ #if HAVE_UNION_WAIT typedef union wait wait_status; #ifndef WIFEXITED #define WIFEXITED(u) ((u).w_termsig == 0) #endif #ifndef WEXITSTATUS #define WEXITSTATUS(u) ((u).w_retcode) #endif #ifndef WTERMSIG #define WTERMSIG(u) ((u).w_termsig) #endif #else /* ! HAVE_UNION_WAIT */ typedef int wait_status; #ifndef WIFEXITED #define WIFEXITED(i) (((i) & 0xff) == 0) #endif #ifndef WEXITSTATUS #define WEXITSTATUS(i) (((i) >> 8) & 0xff) #endif #ifndef WTERMSIG #define WTERMSIG(i) ((i) & 0x7f) #endif #endif /* ! HAVE_UNION_WAIT */ /* Wait for a particular process to finish. The ipid argument should be pid_t, but then we couldn't have a prototype. If the zreport argument is not NULL, then a wait error will be logged, and if the exit status is non-zero it will be logged with zreport as the header of the log message. If the zreport argument is NULL, no errors will be logged. This function returns the exit status if the process exited normally, or -1 on error or if the process was killed by a signal (I don't just always return the exit status because then the calling code would have to prepared to handle union wait status vs. int status, and none of the callers care which signal killed the program anyhow). This functions keeps waiting until the process finished, even if it is interrupted by a signal. I think this is right for all uses. The controversial one would be when called from uuxqt to wait for a requested process. Hitting uuxqt with SIGKILL will approximate the actions taken if we return from here with an error anyhow. If we do get a signal, we call ulog with a NULL argument to get it in the log file at about the right time. */ int ixswait (ipid, zreport) unsigned long ipid; const char *zreport; { wait_status istat; #if HAVE_WAITPID while (waitpid ((pid_t) ipid, (pointer) &istat, 0) < 0) { if (errno != EINTR) { if (zreport != NULL) ulog (LOG_ERROR, "waitpid: %s", strerror (errno)); return -1; } ulog (LOG_ERROR, (const char *) NULL); } #else /* ! HAVE_WAITPID */ #if HAVE_WAIT4 while (wait4 ((pid_t) ipid, (pointer) &istat, 0, (struct rusage *) NULL) < 0) { if (errno != EINTR) { if (zreport != NULL) ulog (LOG_ERROR, "wait4: %s", strerror (errno)); return -1; } ulog (LOG_ERROR, (const char *) NULL); } #else /* ! HAVE_WAIT4 */ pid_t igot; /* We could theoretically get the wrong child here if we're in some kind of weird pipeline, so we don't give any error messages for it. */ while ((igot = wait ((pointer) &istat)) != (pid_t) ipid) { if (igot < 0) { if (errno != EINTR) { if (zreport != NULL) ulog (LOG_ERROR, "wait: %s", strerror (errno)); return -1; } ulog (LOG_ERROR, (const char *) NULL); } } #endif /* ! HAVE_WAIT4 */ #endif /* ! HAVE_WAITPID */ DEBUG_MESSAGE2 (DEBUG_EXECUTE, "%s %d", WIFEXITED (istat) ? "Exit status" : "Signal", WIFEXITED (istat) ? WEXITSTATUS (istat) : WTERMSIG (istat)); if (WIFEXITED (istat) && WEXITSTATUS (istat) == 0) return 0; if (zreport != NULL) { if (! WIFEXITED (istat)) ulog (LOG_ERROR, "%s: Got signal %d", zreport, WTERMSIG (istat)); else ulog (LOG_ERROR, "%s: Exit status %d", zreport, WEXITSTATUS (istat)); } if (WIFEXITED (istat)) return WEXITSTATUS (istat); else return -1; }