10e5e4167SJilles Tjoelker /*- 20e5e4167SJilles Tjoelker * Copyright (c) 2004-2009, Jilles Tjoelker 30e5e4167SJilles Tjoelker * All rights reserved. 40e5e4167SJilles Tjoelker * 50e5e4167SJilles Tjoelker * Redistribution and use in source and binary forms, with 60e5e4167SJilles Tjoelker * or without modification, are permitted provided that the 70e5e4167SJilles Tjoelker * following conditions are met: 80e5e4167SJilles Tjoelker * 90e5e4167SJilles Tjoelker * 1. Redistributions of source code must retain the above 100e5e4167SJilles Tjoelker * copyright notice, this list of conditions and the 110e5e4167SJilles Tjoelker * following disclaimer. 120e5e4167SJilles Tjoelker * 2. Redistributions in binary form must reproduce the 130e5e4167SJilles Tjoelker * above copyright notice, this list of conditions and 140e5e4167SJilles Tjoelker * the following disclaimer in the documentation and/or 150e5e4167SJilles Tjoelker * other materials provided with the distribution. 160e5e4167SJilles Tjoelker * 170e5e4167SJilles Tjoelker * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 180e5e4167SJilles Tjoelker * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED 190e5e4167SJilles Tjoelker * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 200e5e4167SJilles Tjoelker * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 210e5e4167SJilles Tjoelker * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 220e5e4167SJilles Tjoelker * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY 230e5e4167SJilles Tjoelker * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 240e5e4167SJilles Tjoelker * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 250e5e4167SJilles Tjoelker * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 260e5e4167SJilles Tjoelker * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 270e5e4167SJilles Tjoelker * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 280e5e4167SJilles Tjoelker * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 290e5e4167SJilles Tjoelker * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 300e5e4167SJilles Tjoelker * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 310e5e4167SJilles Tjoelker * OF SUCH DAMAGE. 320e5e4167SJilles Tjoelker */ 330e5e4167SJilles Tjoelker 340e5e4167SJilles Tjoelker #include <sys/cdefs.h> 350e5e4167SJilles Tjoelker __FBSDID("$FreeBSD$"); 360e5e4167SJilles Tjoelker 370e5e4167SJilles Tjoelker #include <sys/types.h> 380e5e4167SJilles Tjoelker #include <sys/event.h> 390e5e4167SJilles Tjoelker #include <sys/time.h> 400e5e4167SJilles Tjoelker #include <sys/wait.h> 410e5e4167SJilles Tjoelker 420e5e4167SJilles Tjoelker #include <err.h> 430e5e4167SJilles Tjoelker #include <errno.h> 440e5e4167SJilles Tjoelker #include <signal.h> 450e5e4167SJilles Tjoelker #include <stdio.h> 460e5e4167SJilles Tjoelker #include <stdlib.h> 470e5e4167SJilles Tjoelker #include <string.h> 480e5e4167SJilles Tjoelker #include <sysexits.h> 490e5e4167SJilles Tjoelker #include <unistd.h> 500e5e4167SJilles Tjoelker 510e5e4167SJilles Tjoelker static void 520e5e4167SJilles Tjoelker usage(void) 530e5e4167SJilles Tjoelker { 540e5e4167SJilles Tjoelker 55d731a314SPawel Jakub Dawidek fprintf(stderr, "usage: pwait [-t timeout] [-ov] pid ...\n"); 56d731a314SPawel Jakub Dawidek exit(EX_USAGE); 570e5e4167SJilles Tjoelker } 580e5e4167SJilles Tjoelker 590e5e4167SJilles Tjoelker /* 600e5e4167SJilles Tjoelker * pwait - wait for processes to terminate 610e5e4167SJilles Tjoelker */ 620e5e4167SJilles Tjoelker int 630e5e4167SJilles Tjoelker main(int argc, char *argv[]) 640e5e4167SJilles Tjoelker { 65b06b52baSBryan Drewery struct itimerval itv; 660e5e4167SJilles Tjoelker struct kevent *e; 672362bc2cSPawel Jakub Dawidek int oflag, tflag, verbose; 6896773547SPawel Jakub Dawidek int i, kq, n, nleft, opt, status; 690e5e4167SJilles Tjoelker long pid; 7096773547SPawel Jakub Dawidek char *end, *s; 71b06b52baSBryan Drewery double timeout; 720e5e4167SJilles Tjoelker 732362bc2cSPawel Jakub Dawidek oflag = 0; 742362bc2cSPawel Jakub Dawidek tflag = 0; 752362bc2cSPawel Jakub Dawidek verbose = 0; 76b06b52baSBryan Drewery memset(&itv, 0, sizeof(itv)); 772362bc2cSPawel Jakub Dawidek 7896773547SPawel Jakub Dawidek while ((opt = getopt(argc, argv, "ot:v")) != -1) { 790e5e4167SJilles Tjoelker switch (opt) { 802362bc2cSPawel Jakub Dawidek case 'o': 812362bc2cSPawel Jakub Dawidek oflag = 1; 822362bc2cSPawel Jakub Dawidek break; 83b06b52baSBryan Drewery case 't': 84b06b52baSBryan Drewery tflag = 1; 85b06b52baSBryan Drewery errno = 0; 86b06b52baSBryan Drewery timeout = strtod(optarg, &end); 8796773547SPawel Jakub Dawidek if (end == optarg || errno == ERANGE || timeout < 0) { 88b06b52baSBryan Drewery errx(EX_DATAERR, "timeout value"); 8996773547SPawel Jakub Dawidek } 90b06b52baSBryan Drewery switch(*end) { 91b06b52baSBryan Drewery case 0: 92b06b52baSBryan Drewery case 's': 93b06b52baSBryan Drewery break; 94b06b52baSBryan Drewery case 'h': 95b06b52baSBryan Drewery timeout *= 60; 96b06b52baSBryan Drewery /* FALLTHROUGH */ 97b06b52baSBryan Drewery case 'm': 98b06b52baSBryan Drewery timeout *= 60; 99b06b52baSBryan Drewery break; 100b06b52baSBryan Drewery default: 101b06b52baSBryan Drewery errx(EX_DATAERR, "timeout unit"); 102b06b52baSBryan Drewery } 10396773547SPawel Jakub Dawidek if (timeout > 100000000L) { 104b06b52baSBryan Drewery errx(EX_DATAERR, "timeout value"); 10596773547SPawel Jakub Dawidek } 106b06b52baSBryan Drewery itv.it_value.tv_sec = (time_t)timeout; 107b06b52baSBryan Drewery timeout -= (time_t)timeout; 108b06b52baSBryan Drewery itv.it_value.tv_usec = 109b06b52baSBryan Drewery (suseconds_t)(timeout * 1000000UL); 110b06b52baSBryan Drewery break; 1110e5e4167SJilles Tjoelker case 'v': 1120e5e4167SJilles Tjoelker verbose = 1; 1130e5e4167SJilles Tjoelker break; 1140e5e4167SJilles Tjoelker default: 1150e5e4167SJilles Tjoelker usage(); 1160e5e4167SJilles Tjoelker /* NOTREACHED */ 1170e5e4167SJilles Tjoelker } 1180e5e4167SJilles Tjoelker } 1190e5e4167SJilles Tjoelker 1200e5e4167SJilles Tjoelker argc -= optind; 1210e5e4167SJilles Tjoelker argv += optind; 1220e5e4167SJilles Tjoelker 12396773547SPawel Jakub Dawidek if (argc == 0) { 1240e5e4167SJilles Tjoelker usage(); 12596773547SPawel Jakub Dawidek } 1260e5e4167SJilles Tjoelker 1270e5e4167SJilles Tjoelker kq = kqueue(); 12896773547SPawel Jakub Dawidek if (kq == -1) { 129532b3f47SPawel Jakub Dawidek err(EX_OSERR, "kqueue"); 13096773547SPawel Jakub Dawidek } 1310e5e4167SJilles Tjoelker 132b06b52baSBryan Drewery e = malloc((argc + tflag) * sizeof(struct kevent)); 13396773547SPawel Jakub Dawidek if (e == NULL) { 134532b3f47SPawel Jakub Dawidek err(EX_OSERR, "malloc"); 13596773547SPawel Jakub Dawidek } 1360e5e4167SJilles Tjoelker nleft = 0; 1370e5e4167SJilles Tjoelker for (n = 0; n < argc; n++) { 1380e5e4167SJilles Tjoelker s = argv[n]; 13996773547SPawel Jakub Dawidek /* Undocumented Solaris compat */ 14096773547SPawel Jakub Dawidek if (!strncmp(s, "/proc/", 6)) { 1410e5e4167SJilles Tjoelker s += 6; 14296773547SPawel Jakub Dawidek } 1430e5e4167SJilles Tjoelker errno = 0; 1440e5e4167SJilles Tjoelker pid = strtol(s, &end, 10); 1450e5e4167SJilles Tjoelker if (pid < 0 || *end != '\0' || errno != 0) { 1460e5e4167SJilles Tjoelker warnx("%s: bad process id", s); 1470e5e4167SJilles Tjoelker continue; 1480e5e4167SJilles Tjoelker } 1495bdce6ffSAlexander V. Chernikov if (pid == getpid()) { 150*bbff3a72SAlexander V. Chernikov warnx("%s: skipping my own pid", s); 1515bdce6ffSAlexander V. Chernikov continue; 1525bdce6ffSAlexander V. Chernikov } 1533f50bbafSPawel Jakub Dawidek for (i = 0; i < nleft; i++) { 15496773547SPawel Jakub Dawidek if (e[i].ident == (uintptr_t)pid) { 1553f50bbafSPawel Jakub Dawidek break; 1563f50bbafSPawel Jakub Dawidek } 15796773547SPawel Jakub Dawidek } 1583f50bbafSPawel Jakub Dawidek if (i < nleft) { 1593f50bbafSPawel Jakub Dawidek /* Duplicate. */ 1603f50bbafSPawel Jakub Dawidek continue; 1613f50bbafSPawel Jakub Dawidek } 1623f50bbafSPawel Jakub Dawidek EV_SET(e + nleft, pid, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, NULL); 1632362bc2cSPawel Jakub Dawidek if (kevent(kq, e + nleft, 1, NULL, 0, NULL) == -1) { 1640e5e4167SJilles Tjoelker warn("%ld", pid); 16596773547SPawel Jakub Dawidek if (oflag) { 1662362bc2cSPawel Jakub Dawidek exit(EX_OK); 16796773547SPawel Jakub Dawidek } 1682362bc2cSPawel Jakub Dawidek } else { 1690e5e4167SJilles Tjoelker nleft++; 1700e5e4167SJilles Tjoelker } 1712362bc2cSPawel Jakub Dawidek } 1720e5e4167SJilles Tjoelker 1735e2e2222SPawel Jakub Dawidek if (nleft > 0 && tflag) { 174b06b52baSBryan Drewery /* 175b06b52baSBryan Drewery * Explicitly detect SIGALRM so that an exit status of 124 176b06b52baSBryan Drewery * can be returned rather than 142. 177b06b52baSBryan Drewery */ 178b06b52baSBryan Drewery EV_SET(e + nleft, SIGALRM, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL); 17996773547SPawel Jakub Dawidek if (kevent(kq, e + nleft, 1, NULL, 0, NULL) == -1) { 180b06b52baSBryan Drewery err(EX_OSERR, "kevent"); 18196773547SPawel Jakub Dawidek } 182b06b52baSBryan Drewery /* Ignore SIGALRM to not interrupt kevent(2). */ 183b06b52baSBryan Drewery signal(SIGALRM, SIG_IGN); 18496773547SPawel Jakub Dawidek if (setitimer(ITIMER_REAL, &itv, NULL) == -1) { 185b06b52baSBryan Drewery err(EX_OSERR, "setitimer"); 186b06b52baSBryan Drewery } 18796773547SPawel Jakub Dawidek } 1880e5e4167SJilles Tjoelker while (nleft > 0) { 189b06b52baSBryan Drewery n = kevent(kq, NULL, 0, e, nleft + tflag, NULL); 19096773547SPawel Jakub Dawidek if (n == -1) { 191532b3f47SPawel Jakub Dawidek err(EX_OSERR, "kevent"); 19296773547SPawel Jakub Dawidek } 1930e5e4167SJilles Tjoelker for (i = 0; i < n; i++) { 194b06b52baSBryan Drewery if (e[i].filter == EVFILT_SIGNAL) { 19596773547SPawel Jakub Dawidek if (verbose) { 196b06b52baSBryan Drewery printf("timeout\n"); 19796773547SPawel Jakub Dawidek } 198532b3f47SPawel Jakub Dawidek exit(124); 199b06b52baSBryan Drewery } 200b06b52baSBryan Drewery if (verbose) { 2010e5e4167SJilles Tjoelker status = e[i].data; 20296773547SPawel Jakub Dawidek if (WIFEXITED(status)) { 2030e5e4167SJilles Tjoelker printf("%ld: exited with status %d.\n", 2040e5e4167SJilles Tjoelker (long)e[i].ident, 2050e5e4167SJilles Tjoelker WEXITSTATUS(status)); 20696773547SPawel Jakub Dawidek } else if (WIFSIGNALED(status)) { 2070e5e4167SJilles Tjoelker printf("%ld: killed by signal %d.\n", 2080e5e4167SJilles Tjoelker (long)e[i].ident, 2090e5e4167SJilles Tjoelker WTERMSIG(status)); 21096773547SPawel Jakub Dawidek } else { 2110e5e4167SJilles Tjoelker printf("%ld: terminated.\n", 2120e5e4167SJilles Tjoelker (long)e[i].ident); 2130e5e4167SJilles Tjoelker } 21496773547SPawel Jakub Dawidek } 21596773547SPawel Jakub Dawidek if (oflag) { 2162362bc2cSPawel Jakub Dawidek exit(EX_OK); 21796773547SPawel Jakub Dawidek } 218b06b52baSBryan Drewery --nleft; 219b06b52baSBryan Drewery } 2200e5e4167SJilles Tjoelker } 2210e5e4167SJilles Tjoelker 222f3de285bSXin LI exit(EX_OK); 2230e5e4167SJilles Tjoelker } 224