/*- * Copyright (c) 2000 Brian Fundakowski Feldman * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ * */ #include #include #include #include #include #include #include #include enum waitfor { WF_NONE = 0, WF_EXEC = 1, WF_EXIT = 2, WF_FORK = 4, WF_ALL = 7 }; void usage(void); void dowait(pid_t pid, enum waitfor events, int quiet); int main(int argc, char **argv) { pid_t pid; enum waitfor waitfor = WF_NONE; int quiet = 0, ch; while ((ch = getopt(argc, argv, "eifq")) != -1) { switch (ch) { case 'e': waitfor |= WF_EXEC; break; case 'i': waitfor |= WF_EXIT; break; case 'f': waitfor |= WF_FORK; break; case 'q': quiet++; break; default: usage(); } } argc -= optind; argv += optind; if (argc != 1 || sscanf(argv[0], "%d", &pid) != 1) usage(); if (pid > NOTE_PDATAMASK) errx(1, "pid cannot be greater than %d", NOTE_PDATAMASK); if (waitfor == WF_NONE) waitfor = WF_ALL; dowait(pid, waitfor, quiet); /* NOTREACHED */ } void dowait(pid_t pid, enum waitfor waitfor, int quiet) { struct kevent ke, *keip = &ke, ke2, *kep = &ke2; int kq, delta; kq = kqueue(); if (kq == -1) err(1, "kqueue"); bzero(&ke, sizeof(ke)); ke.filter = EVFILT_PROC; ke.flags = EV_ADD | EV_ONESHOT; ke.ident = pid; ke.fflags = ((waitfor & WF_EXEC) ? NOTE_EXEC : 0) | ((waitfor & WF_EXIT) ? NOTE_EXIT : 0) | ((waitfor & WF_FORK) ? NOTE_FORK : 0); if (kevent(kq, 1, &keip, 0, NULL, NULL) == -1) err(1, "kevent register"); delta = kevent(kq, 0, NULL, 1, kep, NULL); if (delta == -1) err(1, "kevent check"); else if (delta == 0) errx(1, "kevent returned no events"); if (kep->flags & EV_ERROR) { errno = kep->data; err(1, "kevent"); } if (quiet < 2) { switch (kep->fflags) { case NOTE_EXIT: if (quiet == 0) printf("pid %d: exit %d (type %#x)\n", kep->ident, kep->data & 0xff, kep->data & 0xff00); else printf("exit\n"); break; case NOTE_FORK: if (quiet == 0) printf("pid %d: fork\n", kep->ident); else printf("fork\n"); break; case NOTE_EXEC: if (quiet == 0) printf("pid %d: exec\n", kep->ident); else printf("exec\n"); break; case 0: if (quiet == 0) printf("pid %d: gone\n", kep->ident); else printf("gone\n"); break; default: errx(1, "pid %d: invalid data %#x -- cannot happen!", kep->ident, kep->fflags); } } exit(0); } void usage(void) { fprintf(stderr, "usage: wait4 [-eif] [-q...] pid\n" " -e Wait for an exec event.\n" " -i Wait for an exit event.\n" " -f Wait for a fork event.\n" " -q Make output quieter. Use twice for no output.\n"); exit(1); }