1199458Sjilles/*-
2199458Sjilles * Copyright (c) 2004-2009, Jilles Tjoelker
3199458Sjilles * All rights reserved.
4199458Sjilles *
5199458Sjilles * Redistribution and use in source and binary forms, with
6199458Sjilles * or without modification, are permitted provided that the
7199458Sjilles * following conditions are met:
8199458Sjilles *
9199458Sjilles * 1. Redistributions of source code must retain the above
10199458Sjilles *    copyright notice, this list of conditions and the
11199458Sjilles *    following disclaimer.
12199458Sjilles * 2. Redistributions in binary form must reproduce the
13199458Sjilles *    above copyright notice, this list of conditions and
14199458Sjilles *    the following disclaimer in the documentation and/or
15199458Sjilles *    other materials provided with the distribution.
16199458Sjilles *
17199458Sjilles * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
18199458Sjilles * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
19199458Sjilles * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20199458Sjilles * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
21199458Sjilles * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22199458Sjilles * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY
23199458Sjilles * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24199458Sjilles * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25199458Sjilles * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
26199458Sjilles * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27199458Sjilles * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28199458Sjilles * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29199458Sjilles * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
30199458Sjilles * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
31199458Sjilles * OF SUCH DAMAGE.
32199458Sjilles */
33199458Sjilles
34199458Sjilles#include <sys/cdefs.h>
35199458Sjilles__FBSDID("$FreeBSD$");
36199458Sjilles
37199458Sjilles#include <sys/types.h>
38199458Sjilles#include <sys/event.h>
39199458Sjilles#include <sys/time.h>
40199458Sjilles#include <sys/wait.h>
41199458Sjilles
42199458Sjilles#include <err.h>
43199458Sjilles#include <errno.h>
44199458Sjilles#include <fcntl.h>
45199458Sjilles#include <signal.h>
46199458Sjilles#include <stdio.h>
47199458Sjilles#include <stdlib.h>
48199458Sjilles#include <string.h>
49199458Sjilles#include <sysexits.h>
50199458Sjilles#include <unistd.h>
51199458Sjilles
52199458Sjillesstatic void
53199458Sjillesusage(void)
54199458Sjilles{
55199458Sjilles
56199458Sjilles	fprintf(stderr, "usage: pwait [-v] pid ...\n");
57199458Sjilles	exit(EX_USAGE);
58199458Sjilles}
59199458Sjilles
60199458Sjilles/*
61199458Sjilles * pwait - wait for processes to terminate
62199458Sjilles */
63199458Sjillesint
64199458Sjillesmain(int argc, char *argv[])
65199458Sjilles{
66199458Sjilles	int kq;
67199458Sjilles	struct kevent *e;
68199458Sjilles	int verbose = 0;
69199458Sjilles	int opt, nleft, n, i, duplicate, status;
70199458Sjilles	long pid;
71199458Sjilles	char *s, *end;
72199458Sjilles
73199458Sjilles	while ((opt = getopt(argc, argv, "v")) != -1) {
74199458Sjilles		switch (opt) {
75199458Sjilles		case 'v':
76199458Sjilles			verbose = 1;
77199458Sjilles			break;
78199458Sjilles		default:
79199458Sjilles			usage();
80199458Sjilles			/* NOTREACHED */
81199458Sjilles		}
82199458Sjilles	}
83199458Sjilles
84199458Sjilles	argc -= optind;
85199458Sjilles	argv += optind;
86199458Sjilles
87199458Sjilles	if (argc == 0)
88199458Sjilles		usage();
89199458Sjilles
90199458Sjilles	kq = kqueue();
91199458Sjilles	if (kq == -1)
92199458Sjilles		err(1, "kqueue");
93199458Sjilles
94199458Sjilles	e = malloc(argc * sizeof(struct kevent));
95199458Sjilles	if (e == NULL)
96199458Sjilles		err(1, "malloc");
97199458Sjilles	nleft = 0;
98199458Sjilles	for (n = 0; n < argc; n++) {
99199458Sjilles		s = argv[n];
100199458Sjilles		if (!strncmp(s, "/proc/", 6)) /* Undocumented Solaris compat */
101199458Sjilles			s += 6;
102199458Sjilles		errno = 0;
103199458Sjilles		pid = strtol(s, &end, 10);
104199458Sjilles		if (pid < 0 || *end != '\0' || errno != 0) {
105199458Sjilles			warnx("%s: bad process id", s);
106199458Sjilles			continue;
107199458Sjilles		}
108199458Sjilles		duplicate = 0;
109199458Sjilles		for (i = 0; i < nleft; i++)
110199458Sjilles			if (e[i].ident == (uintptr_t)pid)
111199458Sjilles				duplicate = 1;
112199458Sjilles		if (!duplicate) {
113199458Sjilles			EV_SET(e + nleft, pid, EVFILT_PROC, EV_ADD, NOTE_EXIT,
114199458Sjilles			    0, NULL);
115199458Sjilles			if (kevent(kq, e + nleft, 1, NULL, 0, NULL) == -1)
116199458Sjilles				warn("%ld", pid);
117199458Sjilles			else
118199458Sjilles				nleft++;
119199458Sjilles		}
120199458Sjilles	}
121199458Sjilles
122199458Sjilles	while (nleft > 0) {
123199458Sjilles		n = kevent(kq, NULL, 0, e, nleft, NULL);
124199458Sjilles		if (n == -1)
125199458Sjilles			err(1, "kevent");
126199458Sjilles		if (verbose)
127199458Sjilles			for (i = 0; i < n; i++) {
128199458Sjilles				status = e[i].data;
129199458Sjilles				if (WIFEXITED(status))
130199458Sjilles					printf("%ld: exited with status %d.\n",
131199458Sjilles					    (long)e[i].ident,
132199458Sjilles					    WEXITSTATUS(status));
133199458Sjilles				else if (WIFSIGNALED(status))
134199458Sjilles					printf("%ld: killed by signal %d.\n",
135199458Sjilles					    (long)e[i].ident,
136199458Sjilles					    WTERMSIG(status));
137199458Sjilles				else
138199458Sjilles					printf("%ld: terminated.\n",
139199458Sjilles					    (long)e[i].ident);
140199458Sjilles			}
141199458Sjilles		nleft -= n;
142199458Sjilles	}
143199458Sjilles
144245506Sdelphij	exit(EX_OK);
145199458Sjilles}
146