1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
|
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <err.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/event.h>
#include <sys/time.h>
#include <sys/resource.h>
#define LIMIT 256
bool initial = false; // print one initial line at startup
int main(int argc, char *argv[]) {
char **filenames;
int first_file_index, kq;
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
setbuf(stdout, NULL); // disable buffering even non-interactively
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 = true;
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 (int i = first_file_index; i < argc; i++) {
int fd;
if ((fd = open(argv[i], O_RDONLY)) == -1)
err(1, "%s", argv[i]);
filenames[fd] = argv[i];
if (initial)
printf("%s\n", argv[i]);
struct kevent change = { // event to watch for
.ident = fd,
.filter = EVFILT_VNODE,
.flags = EV_ADD | EV_CLEAR,
.fflags = NOTE_WRITE | NOTE_DELETE,
.data = 0,
.udata = NULL
};
changes[i - first_file_index] = change;
}
if (pledge("stdio", NULL) == -1) err(1, "pledge");
for (;;) {
int n;
/* 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 (int 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]);
}
|