--- wait_on.c +++ wait_on.c @@ -24,6 +24,8 @@ static void version(void) ATTRIBUTE_NORETURN; +u_int8_t options; + int main(int argc, char *const argv[]) { int c, /* function returns + misc */ ev, /* value to exit with */ @@ -32,7 +34,6 @@ struct kevent *events; struct timespec *pts, /* pointer to ts or NULL */ ts; /* timeout */ - u_int8_t options; /* make sure we remember our program name */ setprogname(argv[0]); @@ -42,7 +43,7 @@ pts = NULL; /* handle command line options */ - while ((c = getopt(argc, argv, "chit:vw")) != -1) { + while ((c = getopt(argc, argv, "chipqt:vwx")) != -1) { switch (c) { case 'c': /* copyright/version */ @@ -56,6 +57,14 @@ /* set exit value to indicate which file/directory changed */ options |= I_FLAG; break; + case 'p': + /* only interested in PIDs */ + options |= P_FLAG; + break; + case 'q': + /* silent */ + options |= Q_FLAG; + break; case 't': /* timeout */ pts = &ts; @@ -73,6 +82,10 @@ /* only interested in writes */ options |= W_FLAG; break; + case 'x': + /* only interested in exits */ + options |= X_FLAG; + break; case '?': default: /* unknown option */ @@ -89,7 +102,7 @@ /* see if there are soo many files/directories to watch that that our exit * value may be ambiguous */ - if ((options & I_FLAG) && (argc >= EX__BASE)) { + if ((options & I_FLAG) && (~options & Q_FLAG) && (argc >= EX__BASE)) { warnx("-i specified with >= %d files - exit code may be ambiguous", EX__BASE); } @@ -100,13 +113,23 @@ /* fill the event array */ for (i = 0; i < argc; ++i) { + if (options & P_FLAG) { + events[i].ident = strtol(argv[i], (char **)NULL, 10); + events[i].filter = EVFILT_PROC; + if (options & X_FLAG) { + /* only interested in exits */ + events[i].fflags = NOTE_EXIT; + } else { + /* interested in everything */ + events[i].fflags = NOTE_EXIT | NOTE_FORK | NOTE_EXEC | NOTE_TRACK | NOTE_TRACKERR; + } + } else { /* optain a file descriptor for the file/directory */ if ((c = open(argv[i], O_RDONLY | O_NONBLOCK)) == -1) { err(EX_NOINPUT, "can't open \"%s\" for reading", argv[i]); } events[i].ident = c; events[i].filter = EVFILT_VNODE; - events[i].flags = EV_ADD | EV_ENABLE | EV_CLEAR; if (options & W_FLAG) { /* only interested in writes */ events[i].fflags = NOTE_WRITE; @@ -115,7 +138,9 @@ events[i].fflags = NOTE_DELETE | NOTE_WRITE | NOTE_EXTEND | NOTE_ATTRIB | NOTE_LINK | NOTE_RENAME | NOTE_REVOKE; } /* store filename in udata for later retrieval */ - events[i].udata = (void *)argv[i]; + } + events[i].flags = EV_ADD | EV_ENABLE | EV_CLEAR; + events[i].udata = (void *)argv[i]; } /* obtain a kq */ @@ -128,6 +153,7 @@ * we are only interested in one event as we can only signal one event * so in the hope of efficiency we lie the second time about the size of * the events array */ + ev = EX_OK; switch (c = kevent(kq, events, argc, events, 1, pts)) { case -1: /* kevent failed */ @@ -142,7 +168,7 @@ for (i = 0; i < c; ++i) { if (events[i].flags & EV_ERROR) { /* error occured while processing a filter */ - warnc(events[i].data, "%s", (char *)events[i].udata); + if (~options & Q_FLAG) warnc(events[i].data, "%s", (char *)events[i].udata); /* set ev in case this is all we get */ ev = EX_UNAVAILABLE; continue; @@ -150,23 +176,27 @@ /* something reportable must have happened */ if (options & H_FLAG) { /* human readable output */ + if (options & P_FLAG) { + display_human_p(&events[i]); + } else { display_human(&events[i]); - } + } } if (options & I_FLAG) { /* user wants to know which file */ ev = which_happened(&events[i], argc, argv); } else { /* user wants to know what happened */ + if (options & P_FLAG) { + ev = what_happened_p(&events[i]); + } else { ev = what_happened(&events[i]); - } + } } exit(ev); } } break; } - - /* NOT REACHED */ - return 0; + exit(ev); } void display_human(struct kevent *event) { @@ -197,6 +227,31 @@ printf("\n"); } +void display_human_p(struct kevent *event) { + + /* display process event to stdout */ + printf("Process %s:", (char *)event->udata); + if (event->fflags & NOTE_EXIT) { + printf(" exited"); + } + if (event->fflags & NOTE_FORK) { + printf(" forked"); + } + if (event->fflags & NOTE_EXEC) { + printf(" execute"); + } + if (event->fflags & NOTE_TRACK) { + printf(" tracked"); + } + if (event->fflags & NOTE_CHILD) { + printf(" child of %d", event->data); + } + if (event->fflags & NOTE_TRACKERR) { + printf(" tracking error"); + } + printf("\n"); +} + /* indicate what sort of event occured (returns an EXIT_ value) */ int what_happened(struct kevent *event) { @@ -223,7 +278,34 @@ } /* unknown event */ - warnx("unknown event of type %u occured to %s", event->fflags, (char *)event->udata); + if (~options & Q_FLAG) warnx("unknown event of type %u occured to %s", event->fflags, (char *)event->udata); + return EX_OSERR; +} + +/* indicate what sort of process event occured (returns an EXIT_ value) */ +int what_happened_p(struct kevent *event) { + + if (event->fflags & NOTE_EXIT) { + return(EXIT_EXIT); + } + if (event->fflags & NOTE_FORK) { + return(EXIT_FORK); + } + if (event->fflags & NOTE_EXEC) { + return(EXIT_EXEC); + } + if (event->fflags & NOTE_TRACK) { + return(EXIT_TRACK); + } + if (event->fflags & NOTE_CHILD) { + return(EXIT_CHILD); + } + if (event->fflags & NOTE_TRACKERR) { + return(EXIT_TRACKERR); + } + + /* unknown event */ + if (~options & Q_FLAG) warnx("unknown event of type %u occured to process %s", event->fflags, (char *)event->udata); return EX_OSERR; } @@ -239,18 +321,20 @@ } /* it was a file we didn't ask about...*/ - warnx("event on unknown file (%s)", (char *)event->udata); + if (~options & Q_FLAG) warnx("event on unknown file (%s)", (char *)event->udata); return EX_OSERR; } static void usage(void) { - fprintf(stderr, "usage: %s [-chivw] [-t timeout] file1 [...]\n", getprogname()); + fprintf(stderr, "usage: %s [-chipqvwx] [-t timeout] {file1|PID} [...]\n", getprogname()); exit(EX_USAGE); } static void version(void) { - printf("%s version 1.0 Copyright 2002 Andrew Stevenson \n", getprogname()); + printf("%s version 1.1 Copyright 2002 Andrew Stevenson Changed @BABOLO\n" + , getprogname() + ); exit(EX_OK); }