summaryrefslogtreecommitdiff
path: root/gnu/libexec/uucp/libunix/iswait.c
blob: d13db6ebeba15997fd5c598a38e1747330e7c941 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
/* 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 <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;
}