1/* $NetBSD: pwait.c,v 1.6 2017/07/30 20:37:35 dholland 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.6 2017/07/30 20:37:35 dholland 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#include <assert.h> 57 58static __dead void 59usage(void) 60{ 61 62 fprintf(stderr, "Usage: %s [-isv] [-t <timeout>] <pid> ...\n", 63 getprogname()); 64 exit(EX_USAGE); 65} 66 67/* 68 * pwait - wait for processes to terminate 69 */ 70int 71main(int argc, char *argv[]) 72{ 73 int kq; 74 struct kevent *e; 75 int verbose = 0, childstatus = 0; 76 int opt, duplicate, status, immediately = 0; 77 size_t nleft, n, i; 78 pid_t pid; 79 char *s, *end; 80 double timeout = 0; 81 struct timespec ts, *tsp; 82 83 setprogname(argv[0]); 84 while ((opt = getopt(argc, argv, "ist:v")) != -1) { 85 switch (opt) { 86 case 'i': 87 immediately = 1; 88 break; 89 case 's': 90 childstatus = 1; 91 break; 92 case 't': 93 timeout = atof(optarg); 94 if (timeout < 0) 95 timeout = 0; 96 break; 97 case 'v': 98 verbose = 1; 99 break; 100 default: 101 usage(); 102 /* NOTREACHED */ 103 } 104 } 105 106 argc -= optind; 107 argv += optind; 108 109 if (argc == 0) 110 usage(); 111 112 if (timeout != 0) { 113 ts.tv_sec = (time_t)timeout; 114 timeout -= (double)ts.tv_sec; 115 ts.tv_nsec = (long)(timeout * 1000000000L); 116 while (ts.tv_nsec < 0) { 117 ts.tv_sec--; 118 ts.tv_nsec += 1000000000L; 119 } 120 tsp = &ts; 121 } else 122 tsp = NULL; 123 124 kq = kqueue(); 125 if (kq == -1) 126 err(EXIT_FAILURE, "kqueue"); 127 128 e = malloc((size_t)argc * sizeof(*e)); 129 if (e == NULL) 130 err(EXIT_FAILURE, "malloc"); 131 nleft = 0; 132 for (n = 0; n < (size_t)argc; n++) { 133 long pidl; 134 s = argv[n]; 135 if (!strncmp(s, "/proc/", 6)) /* Undocumented Solaris compat */ 136 s += 6; 137 errno = 0; 138 pidl = strtol(s, &end, 10); 139 if (pidl < 0 || *end != '\0' || errno != 0) { 140 warnx("%s: bad process id", s); 141 continue; 142 } 143 pid = (pid_t)pidl; 144 duplicate = 0; 145 for (i = 0; i < nleft; i++) 146 if (e[i].ident == (uintptr_t)pid) 147 duplicate = 1; 148 if (!duplicate) { 149 EV_SET(e + nleft, (uintptr_t)pid, EVFILT_PROC, EV_ADD, 150 NOTE_EXIT, 0, 0); 151 if (kevent(kq, e + nleft, 1, NULL, 0, NULL) == -1) 152 warn("%jd", (intmax_t)pid); 153 else 154 nleft++; 155 } 156 } 157 158 while (nleft > 0) { 159 int rv; 160 161 switch (rv = kevent(kq, NULL, 0, e, nleft, tsp)) { 162 case 0: 163 if (verbose) 164 printf("timed out\n"); 165 if (childstatus) 166 return 255; 167 return EX_OK; 168 case -1: 169 err(EXIT_FAILURE, "kevent"); 170 default: 171 n = (size_t)rv; 172 break; 173 } 174 175 assert(n > 0); 176 for (i = 0; i < n; i++) { 177 status = (int)e[i].data; 178 if (verbose) { 179 if (WIFEXITED(status)) 180 printf("%ld: exited with status %d.\n", 181 (long)e[i].ident, 182 WEXITSTATUS(status)); 183 else if (WIFSIGNALED(status)) 184 printf("%ld: killed by signal %d.\n", 185 (long)e[i].ident, 186 WTERMSIG(status)); 187 else 188 printf("%ld: terminated.\n", 189 (long)e[i].ident); 190 } 191 if (childstatus) 192 return status; 193 } 194 nleft -= n; 195 if (immediately) 196 break; 197 } 198 199 return EX_OK; 200} 201