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
102
103
104
105
106
|
#define _OPENBSD_SOURCE
#include <err.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/event.h>
#include <sys/resource.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#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;
}
|