Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/bin/pwait/pwait.c
39475 views
1
/*-
2
* Copyright (c) 2004-2009, Jilles Tjoelker
3
* All rights reserved.
4
*
5
* Redistribution and use in source and binary forms, with
6
* or without modification, are permitted provided that the
7
* following conditions are met:
8
*
9
* 1. Redistributions of source code must retain the above
10
* copyright notice, this list of conditions and the
11
* following disclaimer.
12
* 2. Redistributions in binary form must reproduce the
13
* above copyright notice, this list of conditions and
14
* the following disclaimer in the documentation and/or
15
* other materials provided with the distribution.
16
*
17
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
18
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
19
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
21
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY
23
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
26
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
30
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
31
* OF SUCH DAMAGE.
32
*/
33
34
#include <sys/types.h>
35
#include <sys/event.h>
36
#include <sys/time.h>
37
#include <sys/wait.h>
38
39
#include <err.h>
40
#include <errno.h>
41
#include <signal.h>
42
#include <stdbool.h>
43
#include <stdio.h>
44
#include <stdlib.h>
45
#include <string.h>
46
#include <sysexits.h>
47
#include <unistd.h>
48
49
static void
50
usage(void)
51
{
52
fprintf(stderr, "usage: pwait [-t timeout] [-ov] pid ...\n");
53
exit(EX_USAGE);
54
}
55
56
/*
57
* pwait - wait for processes to terminate
58
*/
59
int
60
main(int argc, char *argv[])
61
{
62
struct itimerval itv;
63
struct kevent *e;
64
char *end, *s;
65
double timeout;
66
long pid;
67
int i, kq, n, nleft, opt, status;
68
bool oflag, tflag, verbose;
69
70
oflag = false;
71
tflag = false;
72
verbose = false;
73
memset(&itv, 0, sizeof(itv));
74
75
while ((opt = getopt(argc, argv, "ot:v")) != -1) {
76
switch (opt) {
77
case 'o':
78
oflag = 1;
79
break;
80
case 't':
81
tflag = true;
82
errno = 0;
83
timeout = strtod(optarg, &end);
84
if (end == optarg || errno == ERANGE || timeout < 0) {
85
errx(EX_DATAERR, "timeout value");
86
}
87
switch (*end) {
88
case '\0':
89
break;
90
case 's':
91
end++;
92
break;
93
case 'h':
94
timeout *= 60;
95
/* FALLTHROUGH */
96
case 'm':
97
timeout *= 60;
98
end++;
99
break;
100
default:
101
errx(EX_DATAERR, "timeout unit");
102
}
103
if (*end != '\0') {
104
errx(EX_DATAERR, "timeout unit");
105
}
106
if (timeout > 100000000L) {
107
errx(EX_DATAERR, "timeout value");
108
}
109
itv.it_value.tv_sec = (time_t)timeout;
110
timeout -= (time_t)timeout;
111
itv.it_value.tv_usec =
112
(suseconds_t)(timeout * 1000000UL);
113
break;
114
case 'v':
115
verbose = true;
116
break;
117
default:
118
usage();
119
/* NOTREACHED */
120
}
121
}
122
123
argc -= optind;
124
argv += optind;
125
126
if (argc == 0) {
127
usage();
128
}
129
130
kq = kqueue();
131
if (kq == -1) {
132
err(EX_OSERR, "kqueue");
133
}
134
135
e = malloc((argc + tflag) * sizeof(struct kevent));
136
if (e == NULL) {
137
err(EX_OSERR, "malloc");
138
}
139
nleft = 0;
140
for (n = 0; n < argc; n++) {
141
s = argv[n];
142
/* Undocumented Solaris compat */
143
if (strncmp(s, "/proc/", 6) == 0) {
144
s += 6;
145
}
146
errno = 0;
147
pid = strtol(s, &end, 10);
148
if (pid < 0 || *end != '\0' || errno != 0) {
149
warnx("%s: bad process id", s);
150
continue;
151
}
152
if (pid == getpid()) {
153
warnx("%s: skipping my own pid", s);
154
continue;
155
}
156
for (i = 0; i < nleft; i++) {
157
if (e[i].ident == (uintptr_t)pid) {
158
break;
159
}
160
}
161
if (i < nleft) {
162
/* Duplicate. */
163
continue;
164
}
165
EV_SET(e + nleft, pid, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, NULL);
166
if (kevent(kq, e + nleft, 1, NULL, 0, NULL) == -1) {
167
warn("%ld", pid);
168
if (oflag) {
169
exit(EX_OK);
170
}
171
} else {
172
nleft++;
173
}
174
}
175
176
if (nleft > 0 && tflag) {
177
/*
178
* Explicitly detect SIGALRM so that an exit status of 124
179
* can be returned rather than 142.
180
*/
181
EV_SET(e + nleft, SIGALRM, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL);
182
if (kevent(kq, e + nleft, 1, NULL, 0, NULL) == -1) {
183
err(EX_OSERR, "kevent");
184
}
185
/* Ignore SIGALRM to not interrupt kevent(2). */
186
signal(SIGALRM, SIG_IGN);
187
if (setitimer(ITIMER_REAL, &itv, NULL) == -1) {
188
err(EX_OSERR, "setitimer");
189
}
190
}
191
while (nleft > 0) {
192
n = kevent(kq, NULL, 0, e, nleft + tflag, NULL);
193
if (n == -1) {
194
err(EX_OSERR, "kevent");
195
}
196
for (i = 0; i < n; i++) {
197
if (e[i].filter == EVFILT_SIGNAL) {
198
if (verbose) {
199
printf("timeout\n");
200
}
201
exit(124);
202
}
203
if (verbose) {
204
status = e[i].data;
205
if (WIFEXITED(status)) {
206
printf("%ld: exited with status %d.\n",
207
(long)e[i].ident,
208
WEXITSTATUS(status));
209
} else if (WIFSIGNALED(status)) {
210
printf("%ld: killed by signal %d.\n",
211
(long)e[i].ident,
212
WTERMSIG(status));
213
} else {
214
printf("%ld: terminated.\n",
215
(long)e[i].ident);
216
}
217
}
218
if (oflag) {
219
exit(EX_OK);
220
}
221
--nleft;
222
}
223
}
224
225
exit(EX_OK);
226
}
227
228