160 lines
4.7 KiB
C
160 lines
4.7 KiB
C
/* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
The author of the program may be contacted at ian@airs.com or
|
|
c/o Cygnus Support, Building 200, 1 Kendall Square, Cambridge, MA 02139.
|
|
*/
|
|
|
|
#include "uucp.h"
|
|
|
|
#include "uudefs.h"
|
|
#include "sysdep.h"
|
|
|
|
#include <errno.h>
|
|
|
|
#if HAVE_SYS_WAIT_H
|
|
#include <sys/wait.h>
|
|
#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;
|
|
}
|