xref: /netbsd/usr.bin/pwait/pwait.c (revision b4f103c9)
1 /*	$NetBSD: pwait.c,v 1.2 2015/03/02 21:53:48 christos Exp $	*/
2 
3 /*-
4  * Copyright (c) 2004-2009, Jilles Tjoelker
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with
8  * or without modification, are permitted provided that the
9  * following conditions are met:
10  *
11  * 1. Redistributions of source code must retain the above
12  *    copyright notice, this list of conditions and the
13  *    following disclaimer.
14  * 2. Redistributions in binary form must reproduce the
15  *    above copyright notice, this list of conditions and
16  *    the following disclaimer in the documentation and/or
17  *    other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
20  * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
21  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
23  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY
25  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
28  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
31  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
32  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
33  * OF SUCH DAMAGE.
34  */
35 
36 #include <sys/cdefs.h>
37 #ifdef __FBSDID
38 __FBSDID("$FreeBSD: head/bin/pwait/pwait.c 245506 2013-01-16 18:15:25Z delphij $");
39 #endif
40 __RCSID("$NetBSD: pwait.c,v 1.2 2015/03/02 21:53:48 christos Exp $");
41 
42 #include <sys/types.h>
43 #include <sys/event.h>
44 #include <sys/time.h>
45 #include <sys/wait.h>
46 
47 #include <err.h>
48 #include <errno.h>
49 #include <fcntl.h>
50 #include <signal.h>
51 #include <stdio.h>
52 #include <stdlib.h>
53 #include <string.h>
54 #include <sysexits.h>
55 #include <unistd.h>
56 
57 static void
58 usage(void)
59 {
60 
61 	fprintf(stderr, "usage: pwait [-v] pid ...\n");
62 	exit(EX_USAGE);
63 }
64 
65 /*
66  * pwait - wait for processes to terminate
67  */
68 int
69 main(int argc, char *argv[])
70 {
71 	int kq;
72 	struct kevent *e;
73 	int verbose = 0, childstatus = 0;
74 	int opt, duplicate, status;
75 	size_t nleft, n, i;
76 	pid_t pid;
77 	char *s, *end;
78 
79 	while ((opt = getopt(argc, argv, "sv")) != -1) {
80 		switch (opt) {
81 		case 's':
82 			childstatus = 1;
83 			break;
84 		case 'v':
85 			verbose = 1;
86 			break;
87 		default:
88 			usage();
89 			/* NOTREACHED */
90 		}
91 	}
92 
93 	argc -= optind;
94 	argv += optind;
95 
96 	if (argc == 0)
97 		usage();
98 
99 	kq = kqueue();
100 	if (kq == -1)
101 		err(EXIT_FAILURE, "kqueue");
102 
103 	e = malloc((size_t)argc * sizeof(*e));
104 	if (e == NULL)
105 		err(EXIT_FAILURE, "malloc");
106 	nleft = 0;
107 	for (n = 0; n < (size_t)argc; n++) {
108 		long pidl;
109 		s = argv[n];
110 		if (!strncmp(s, "/proc/", 6)) /* Undocumented Solaris compat */
111 			s += 6;
112 		errno = 0;
113 		pidl = strtol(s, &end, 10);
114 		if (pidl < 0 || *end != '\0' || errno != 0) {
115 			warnx("%s: bad process id", s);
116 			continue;
117 		}
118 		pid = (pid_t)pidl;
119 		duplicate = 0;
120 		for (i = 0; i < nleft; i++)
121 			if (e[i].ident == (uintptr_t)pid)
122 				duplicate = 1;
123 		if (!duplicate) {
124 			EV_SET(e + nleft, (uintptr_t)pid, EVFILT_PROC, EV_ADD,
125 			    NOTE_EXIT, 0, NULL);
126 			if (kevent(kq, e + nleft, 1, NULL, 0, NULL) == -1)
127 				warn("%jd", (intmax_t)pid);
128 			else
129 				nleft++;
130 		}
131 	}
132 
133 	while (nleft > 0) {
134 		int rv = kevent(kq, NULL, 0, e, nleft, NULL);
135 		if (rv == -1)
136 			err(EXIT_FAILURE, "kevent");
137 		for (i = 0; i < n; i++) {
138 			status = (int)e[i].data;
139 			if (verbose) {
140 				if (WIFEXITED(status))
141 					printf("%ld: exited with status %d.\n",
142 					    (long)e[i].ident,
143 					    WEXITSTATUS(status));
144 				else if (WIFSIGNALED(status))
145 					printf("%ld: killed by signal %d.\n",
146 					    (long)e[i].ident,
147 					    WTERMSIG(status));
148 				else
149 					printf("%ld: terminated.\n",
150 					    (long)e[i].ident);
151 			}
152 			if (childstatus)
153 				return status;
154 		}
155 		nleft -= n;
156 	}
157 
158 	return EX_OK;
159 }
160