#define _OPENBSD_SOURCE #include #include #include #include #include #include #include #include #include #include #define LIMIT 256 /* print one initial line at startup */ int initial = 0; int main(int argc, char *argv[]) { char **filenames; int fd, first_file_index, i, kq, n; size_t file_count; struct kevent changes[LIMIT]; struct kevent events[LIMIT]; struct rlimit rlp; file_count = argc - 1; first_file_index = 1; /* index of first file argument */ /* disable buffering even non-interactively */ setbuf(stdout, NULL); if (argc < 2) goto usage; /* quit if no arguments */ if (argv[1][0] == '-') { if (argc < 3) goto usage; /* quit if no filenames */ /* adjust indices */ file_count = argc - 2; first_file_index = 2; if (strcmp(argv[1], "-i") == 0) initial = 1; else goto usage; } if (file_count > LIMIT) errx(1, "more than %d files", LIMIT); if ((kq = kqueue()) == -1) err(1, "kqueue"); /* save filenames by file descriptor */ if (getrlimit(RLIMIT_NOFILE, &rlp) == -1) err(1, "getrlimit"); if ((filenames = reallocarray(NULL, rlp.rlim_max, sizeof(char **))) == NULL) err(1, "reallocarray"); /* add each file to change list */ for (i = first_file_index; i < argc; i++) { if ((fd = open(argv[i], O_RDONLY)) == -1) err(1, "%s", argv[i]); filenames[fd] = argv[i]; if (initial) printf("%s\n", argv[i]); /* specify watched events */ struct kevent change = { .ident = fd, .filter = EVFILT_VNODE, .flags = EV_ADD | EV_CLEAR, .fflags = NOTE_WRITE | NOTE_DELETE, .data = 0, .udata = 0 }; changes[i - first_file_index] = change; } #ifdef __OpenBSD__ if (pledge("stdio", NULL) == -1) err(1, "pledge"); #endif for (;;) { /* register changes and wait for events */ if ((n = kevent(kq, changes, file_count, events, file_count, NULL)) == -1) err(1, "kevent wait"); if (n > 0) { for (i = 0; i < n; i++) { if (events[i].flags & EV_ERROR) errx(1, "event error: %s", strerror(events[i].data)); if (events[i].fflags & NOTE_WRITE) printf("%s\n", filenames[events[i].ident]); if (events[i].fflags & NOTE_DELETE) errx(1, "%s was deleted", filenames[events[i].ident]); } } } return 0; /* assume that the kernel closes the file descriptors */ usage: fprintf(stderr, "usage: %s [-i] file\n", argv[0]); return 1; }