1cb5fe245SEnji Cooper /*
2cb5fe245SEnji Cooper * Copyright (c) 2009 Mark Heily <mark@heily.com>
3cb5fe245SEnji Cooper *
4cb5fe245SEnji Cooper * Permission to use, copy, modify, and distribute this software for any
5cb5fe245SEnji Cooper * purpose with or without fee is hereby granted, provided that the above
6cb5fe245SEnji Cooper * copyright notice and this permission notice appear in all copies.
7cb5fe245SEnji Cooper *
8cb5fe245SEnji Cooper * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9cb5fe245SEnji Cooper * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10cb5fe245SEnji Cooper * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11cb5fe245SEnji Cooper * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12cb5fe245SEnji Cooper * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13cb5fe245SEnji Cooper * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14cb5fe245SEnji Cooper * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15cb5fe245SEnji Cooper */
16cb5fe245SEnji Cooper
17cb5fe245SEnji Cooper #include "common.h"
18cb5fe245SEnji Cooper
19cb5fe245SEnji Cooper int vnode_fd;
20cb5fe245SEnji Cooper
21c9c283bdSAlex Richardson static void
test_kevent_vnode_add(void)22cb5fe245SEnji Cooper test_kevent_vnode_add(void)
23cb5fe245SEnji Cooper {
24cb5fe245SEnji Cooper const char *test_id = "kevent(EVFILT_VNODE, EV_ADD)";
25cb5fe245SEnji Cooper const char *testfile = "./kqueue-test.tmp";
26cb5fe245SEnji Cooper struct kevent kev;
27cb5fe245SEnji Cooper
28cb5fe245SEnji Cooper test_begin(test_id);
29cb5fe245SEnji Cooper
30cb5fe245SEnji Cooper system("touch ./kqueue-test.tmp");
31cb5fe245SEnji Cooper vnode_fd = open(testfile, O_RDONLY);
32cb5fe245SEnji Cooper if (vnode_fd < 0)
33cb5fe245SEnji Cooper err(1, "open of %s", testfile);
34cb5fe245SEnji Cooper else
35cb5fe245SEnji Cooper printf("vnode_fd = %d\n", vnode_fd);
36cb5fe245SEnji Cooper
37cb5fe245SEnji Cooper EV_SET(&kev, vnode_fd, EVFILT_VNODE, EV_ADD,
38cb5fe245SEnji Cooper NOTE_WRITE | NOTE_ATTRIB | NOTE_RENAME | NOTE_DELETE, 0, NULL);
39cb5fe245SEnji Cooper if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
40cb5fe245SEnji Cooper err(1, "%s", test_id);
41cb5fe245SEnji Cooper
42cb5fe245SEnji Cooper success();
43cb5fe245SEnji Cooper }
44cb5fe245SEnji Cooper
45c9c283bdSAlex Richardson static void
test_kevent_vnode_note_delete(void)46cb5fe245SEnji Cooper test_kevent_vnode_note_delete(void)
47cb5fe245SEnji Cooper {
48cb5fe245SEnji Cooper const char *test_id = "kevent(EVFILT_VNODE, NOTE_DELETE)";
49cb5fe245SEnji Cooper struct kevent kev;
50cb5fe245SEnji Cooper
51cb5fe245SEnji Cooper test_begin(test_id);
52cb5fe245SEnji Cooper
53cb5fe245SEnji Cooper EV_SET(&kev, vnode_fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, NOTE_DELETE, 0, NULL);
54cb5fe245SEnji Cooper if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
55cb5fe245SEnji Cooper err(1, "%s", test_id);
56cb5fe245SEnji Cooper
57cb5fe245SEnji Cooper if (unlink("./kqueue-test.tmp") < 0)
58cb5fe245SEnji Cooper err(1, "unlink");
59cb5fe245SEnji Cooper
60cb5fe245SEnji Cooper kevent_cmp(&kev, kevent_get(kqfd));
61cb5fe245SEnji Cooper
62cb5fe245SEnji Cooper success();
63cb5fe245SEnji Cooper }
64cb5fe245SEnji Cooper
65c9c283bdSAlex Richardson static void
test_kevent_vnode_note_delete_fifo(void)66*7259ca31SKyle Evans test_kevent_vnode_note_delete_fifo(void)
67*7259ca31SKyle Evans {
68*7259ca31SKyle Evans const char *test_id = "kevent(EVFILT_VNODE, NOTE_DELETE, FIFO)";
69*7259ca31SKyle Evans const char *fifo_path = "./kqueue-fifo.tmp";
70*7259ca31SKyle Evans struct kevent kev;
71*7259ca31SKyle Evans int fd;
72*7259ca31SKyle Evans pid_t pid;
73*7259ca31SKyle Evans
74*7259ca31SKyle Evans test_begin(test_id);
75*7259ca31SKyle Evans
76*7259ca31SKyle Evans if (mkfifo(fifo_path, 0600) != 0)
77*7259ca31SKyle Evans err(1, "mkfifo");
78*7259ca31SKyle Evans
79*7259ca31SKyle Evans pid = fork();
80*7259ca31SKyle Evans if (pid == -1)
81*7259ca31SKyle Evans err(1, "fork");
82*7259ca31SKyle Evans
83*7259ca31SKyle Evans if (pid == 0) {
84*7259ca31SKyle Evans char buf[4];
85*7259ca31SKyle Evans
86*7259ca31SKyle Evans fd = open(fifo_path, O_RDONLY);
87*7259ca31SKyle Evans if (fd == -1)
88*7259ca31SKyle Evans _exit(1);
89*7259ca31SKyle Evans
90*7259ca31SKyle Evans while (read(fd, buf, sizeof(buf)) != 0) {
91*7259ca31SKyle Evans }
92*7259ca31SKyle Evans
93*7259ca31SKyle Evans _exit(0);
94*7259ca31SKyle Evans }
95*7259ca31SKyle Evans
96*7259ca31SKyle Evans sleep(1);
97*7259ca31SKyle Evans if (waitpid(pid, NULL, WNOHANG) == pid) {
98*7259ca31SKyle Evans unlink(fifo_path);
99*7259ca31SKyle Evans err(1, "open");
100*7259ca31SKyle Evans }
101*7259ca31SKyle Evans
102*7259ca31SKyle Evans fd = open(fifo_path, O_WRONLY);
103*7259ca31SKyle Evans if (fd < 0) {
104*7259ca31SKyle Evans unlink(fifo_path);
105*7259ca31SKyle Evans err(1, "open");
106*7259ca31SKyle Evans }
107*7259ca31SKyle Evans
108*7259ca31SKyle Evans EV_SET(&kev, fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, NOTE_DELETE, 0, NULL);
109*7259ca31SKyle Evans if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) {
110*7259ca31SKyle Evans unlink(fifo_path);
111*7259ca31SKyle Evans err(1, "%s", test_id);
112*7259ca31SKyle Evans }
113*7259ca31SKyle Evans
114*7259ca31SKyle Evans if (unlink(fifo_path) < 0)
115*7259ca31SKyle Evans err(1, "unlink");
116*7259ca31SKyle Evans
117*7259ca31SKyle Evans kevent_cmp(&kev, kevent_get(kqfd));
118*7259ca31SKyle Evans close(fd);
119*7259ca31SKyle Evans
120*7259ca31SKyle Evans success();
121*7259ca31SKyle Evans }
122*7259ca31SKyle Evans
123*7259ca31SKyle Evans static void
test_kevent_vnode_note_write(void)124cb5fe245SEnji Cooper test_kevent_vnode_note_write(void)
125cb5fe245SEnji Cooper {
126cb5fe245SEnji Cooper const char *test_id = "kevent(EVFILT_VNODE, NOTE_WRITE)";
127cb5fe245SEnji Cooper struct kevent kev;
128cb5fe245SEnji Cooper
129cb5fe245SEnji Cooper test_begin(test_id);
130cb5fe245SEnji Cooper
131cb5fe245SEnji Cooper EV_SET(&kev, vnode_fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, NOTE_WRITE, 0, NULL);
132cb5fe245SEnji Cooper if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
133cb5fe245SEnji Cooper err(1, "%s", test_id);
134cb5fe245SEnji Cooper
135cb5fe245SEnji Cooper if (system("echo hello >> ./kqueue-test.tmp") < 0)
136cb5fe245SEnji Cooper err(1, "system");
137cb5fe245SEnji Cooper
138cb5fe245SEnji Cooper /* BSD kqueue adds NOTE_EXTEND even though it was not requested */
139cb5fe245SEnji Cooper /* BSD kqueue removes EV_ENABLE */
140cb5fe245SEnji Cooper kev.flags &= ~EV_ENABLE; // XXX-FIXME compatibility issue
141cb5fe245SEnji Cooper kev.fflags |= NOTE_EXTEND; // XXX-FIXME compatibility issue
142cb5fe245SEnji Cooper kevent_cmp(&kev, kevent_get(kqfd));
143cb5fe245SEnji Cooper
144cb5fe245SEnji Cooper success();
145cb5fe245SEnji Cooper }
146cb5fe245SEnji Cooper
147c9c283bdSAlex Richardson static void
test_kevent_vnode_note_attrib(void)148cb5fe245SEnji Cooper test_kevent_vnode_note_attrib(void)
149cb5fe245SEnji Cooper {
150cb5fe245SEnji Cooper const char *test_id = "kevent(EVFILT_VNODE, NOTE_ATTRIB)";
151cb5fe245SEnji Cooper struct kevent kev;
152cb5fe245SEnji Cooper int nfds;
153cb5fe245SEnji Cooper
154cb5fe245SEnji Cooper test_begin(test_id);
155cb5fe245SEnji Cooper
156cb5fe245SEnji Cooper EV_SET(&kev, vnode_fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, NOTE_ATTRIB, 0, NULL);
157cb5fe245SEnji Cooper if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
158cb5fe245SEnji Cooper err(1, "%s", test_id);
159cb5fe245SEnji Cooper
160cb5fe245SEnji Cooper if (system("touch ./kqueue-test.tmp") < 0)
161cb5fe245SEnji Cooper err(1, "system");
162cb5fe245SEnji Cooper
163cb5fe245SEnji Cooper nfds = kevent(kqfd, NULL, 0, &kev, 1, NULL);
164cb5fe245SEnji Cooper if (nfds < 1)
165cb5fe245SEnji Cooper err(1, "%s", test_id);
166c9c283bdSAlex Richardson if (kev.ident != (uintptr_t)vnode_fd ||
167cb5fe245SEnji Cooper kev.filter != EVFILT_VNODE ||
168cb5fe245SEnji Cooper kev.fflags != NOTE_ATTRIB)
169cb5fe245SEnji Cooper err(1, "%s - incorrect event (sig=%u; filt=%d; flags=%d)",
170cb5fe245SEnji Cooper test_id, (unsigned int)kev.ident, kev.filter, kev.flags);
171cb5fe245SEnji Cooper
172cb5fe245SEnji Cooper success();
173cb5fe245SEnji Cooper }
174cb5fe245SEnji Cooper
175c9c283bdSAlex Richardson static void
test_kevent_vnode_note_rename(void)176cb5fe245SEnji Cooper test_kevent_vnode_note_rename(void)
177cb5fe245SEnji Cooper {
178cb5fe245SEnji Cooper const char *test_id = "kevent(EVFILT_VNODE, NOTE_RENAME)";
179cb5fe245SEnji Cooper struct kevent kev;
180cb5fe245SEnji Cooper int nfds;
181cb5fe245SEnji Cooper
182cb5fe245SEnji Cooper test_begin(test_id);
183cb5fe245SEnji Cooper
184cb5fe245SEnji Cooper EV_SET(&kev, vnode_fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, NOTE_RENAME, 0, NULL);
185cb5fe245SEnji Cooper if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
186cb5fe245SEnji Cooper err(1, "%s", test_id);
187cb5fe245SEnji Cooper
188cb5fe245SEnji Cooper if (system("mv ./kqueue-test.tmp ./kqueue-test2.tmp") < 0)
189cb5fe245SEnji Cooper err(1, "system");
190cb5fe245SEnji Cooper
191cb5fe245SEnji Cooper nfds = kevent(kqfd, NULL, 0, &kev, 1, NULL);
192cb5fe245SEnji Cooper if (nfds < 1)
193cb5fe245SEnji Cooper err(1, "%s", test_id);
194c9c283bdSAlex Richardson if (kev.ident != (uintptr_t)vnode_fd ||
195cb5fe245SEnji Cooper kev.filter != EVFILT_VNODE ||
196cb5fe245SEnji Cooper kev.fflags != NOTE_RENAME)
197cb5fe245SEnji Cooper err(1, "%s - incorrect event (sig=%u; filt=%d; flags=%d)",
198cb5fe245SEnji Cooper test_id, (unsigned int)kev.ident, kev.filter, kev.flags);
199cb5fe245SEnji Cooper
200cb5fe245SEnji Cooper if (system("mv ./kqueue-test2.tmp ./kqueue-test.tmp") < 0)
201cb5fe245SEnji Cooper err(1, "system");
202cb5fe245SEnji Cooper
203cb5fe245SEnji Cooper success();
204cb5fe245SEnji Cooper }
205cb5fe245SEnji Cooper
206c9c283bdSAlex Richardson static void
test_kevent_vnode_del(void)207cb5fe245SEnji Cooper test_kevent_vnode_del(void)
208cb5fe245SEnji Cooper {
209cb5fe245SEnji Cooper const char *test_id = "kevent(EVFILT_VNODE, EV_DELETE)";
210cb5fe245SEnji Cooper struct kevent kev;
211cb5fe245SEnji Cooper
212cb5fe245SEnji Cooper test_begin(test_id);
213cb5fe245SEnji Cooper
214cb5fe245SEnji Cooper EV_SET(&kev, vnode_fd, EVFILT_VNODE, EV_DELETE, 0, 0, NULL);
215cb5fe245SEnji Cooper if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
216cb5fe245SEnji Cooper err(1, "%s", test_id);
217cb5fe245SEnji Cooper
218cb5fe245SEnji Cooper success();
219cb5fe245SEnji Cooper }
220cb5fe245SEnji Cooper
221c9c283bdSAlex Richardson static void
test_kevent_vnode_disable_and_enable(void)222cb5fe245SEnji Cooper test_kevent_vnode_disable_and_enable(void)
223cb5fe245SEnji Cooper {
224cb5fe245SEnji Cooper const char *test_id = "kevent(EVFILT_VNODE, EV_DISABLE and EV_ENABLE)";
225cb5fe245SEnji Cooper struct kevent kev;
226cb5fe245SEnji Cooper int nfds;
227cb5fe245SEnji Cooper
228cb5fe245SEnji Cooper test_begin(test_id);
229cb5fe245SEnji Cooper
230cb5fe245SEnji Cooper test_no_kevents();
231cb5fe245SEnji Cooper
232cb5fe245SEnji Cooper /* Add the watch and immediately disable it */
233cb5fe245SEnji Cooper EV_SET(&kev, vnode_fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, NOTE_ATTRIB, 0, NULL);
234cb5fe245SEnji Cooper if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
235cb5fe245SEnji Cooper err(1, "%s", test_id);
236cb5fe245SEnji Cooper kev.flags = EV_DISABLE;
237cb5fe245SEnji Cooper if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
238cb5fe245SEnji Cooper err(1, "%s", test_id);
239cb5fe245SEnji Cooper
240cb5fe245SEnji Cooper /* Confirm that the watch is disabled */
241cb5fe245SEnji Cooper if (system("touch ./kqueue-test.tmp") < 0)
242cb5fe245SEnji Cooper err(1, "system");
243cb5fe245SEnji Cooper test_no_kevents();
244cb5fe245SEnji Cooper
245cb5fe245SEnji Cooper /* Re-enable and check again */
246cb5fe245SEnji Cooper kev.flags = EV_ENABLE;
247cb5fe245SEnji Cooper if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
248cb5fe245SEnji Cooper err(1, "%s", test_id);
249cb5fe245SEnji Cooper if (system("touch ./kqueue-test.tmp") < 0)
250cb5fe245SEnji Cooper err(1, "system");
251cb5fe245SEnji Cooper nfds = kevent(kqfd, NULL, 0, &kev, 1, NULL);
252cb5fe245SEnji Cooper if (nfds < 1)
253cb5fe245SEnji Cooper err(1, "%s", test_id);
254c9c283bdSAlex Richardson if (kev.ident != (uintptr_t)vnode_fd ||
255cb5fe245SEnji Cooper kev.filter != EVFILT_VNODE ||
256cb5fe245SEnji Cooper kev.fflags != NOTE_ATTRIB)
257cb5fe245SEnji Cooper err(1, "%s - incorrect event (sig=%u; filt=%d; flags=%d)",
258cb5fe245SEnji Cooper test_id, (unsigned int)kev.ident, kev.filter, kev.flags);
259cb5fe245SEnji Cooper
260cb5fe245SEnji Cooper success();
261cb5fe245SEnji Cooper }
262cb5fe245SEnji Cooper
263cb5fe245SEnji Cooper #if HAVE_EV_DISPATCH
264c9c283bdSAlex Richardson static void
test_kevent_vnode_dispatch(void)265cb5fe245SEnji Cooper test_kevent_vnode_dispatch(void)
266cb5fe245SEnji Cooper {
267cb5fe245SEnji Cooper const char *test_id = "kevent(EVFILT_VNODE, EV_DISPATCH)";
268cb5fe245SEnji Cooper struct kevent kev;
269cb5fe245SEnji Cooper int nfds;
270cb5fe245SEnji Cooper
271cb5fe245SEnji Cooper test_begin(test_id);
272cb5fe245SEnji Cooper
273cb5fe245SEnji Cooper test_no_kevents();
274cb5fe245SEnji Cooper
275cb5fe245SEnji Cooper EV_SET(&kev, vnode_fd, EVFILT_VNODE, EV_ADD | EV_DISPATCH, NOTE_ATTRIB, 0, NULL);
276cb5fe245SEnji Cooper if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
277cb5fe245SEnji Cooper err(1, "%s", test_id);
278cb5fe245SEnji Cooper
279cb5fe245SEnji Cooper if (system("touch ./kqueue-test.tmp") < 0)
280cb5fe245SEnji Cooper err(1, "system");
281cb5fe245SEnji Cooper
282cb5fe245SEnji Cooper nfds = kevent(kqfd, NULL, 0, &kev, 1, NULL);
283cb5fe245SEnji Cooper if (nfds < 1)
284cb5fe245SEnji Cooper err(1, "%s", test_id);
285c9c283bdSAlex Richardson if (kev.ident != (uintptr_t)vnode_fd ||
286cb5fe245SEnji Cooper kev.filter != EVFILT_VNODE ||
287cb5fe245SEnji Cooper kev.fflags != NOTE_ATTRIB)
288cb5fe245SEnji Cooper err(1, "%s - incorrect event (sig=%u; filt=%d; flags=%d)",
289cb5fe245SEnji Cooper test_id, (unsigned int)kev.ident, kev.filter, kev.flags);
290cb5fe245SEnji Cooper
291cb5fe245SEnji Cooper /* Confirm that the watch is disabled automatically */
292cb5fe245SEnji Cooper puts("-- checking that watch is disabled");
293cb5fe245SEnji Cooper if (system("touch ./kqueue-test.tmp") < 0)
294cb5fe245SEnji Cooper err(1, "system");
295cb5fe245SEnji Cooper test_no_kevents();
296cb5fe245SEnji Cooper
297cb5fe245SEnji Cooper /* Delete the watch */
298cb5fe245SEnji Cooper EV_SET(&kev, vnode_fd, EVFILT_VNODE, EV_DELETE, NOTE_ATTRIB, 0, NULL);
299cb5fe245SEnji Cooper if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
300cb5fe245SEnji Cooper err(1, "remove watch failed: %s", test_id);
301cb5fe245SEnji Cooper
302cb5fe245SEnji Cooper success();
303cb5fe245SEnji Cooper }
304cb5fe245SEnji Cooper #endif /* HAVE_EV_DISPATCH */
305cb5fe245SEnji Cooper
306cb5fe245SEnji Cooper void
test_evfilt_vnode(void)307c9c283bdSAlex Richardson test_evfilt_vnode(void)
308cb5fe245SEnji Cooper {
309cb5fe245SEnji Cooper kqfd = kqueue();
310cb5fe245SEnji Cooper test_kevent_vnode_add();
311cb5fe245SEnji Cooper test_kevent_vnode_del();
312cb5fe245SEnji Cooper test_kevent_vnode_disable_and_enable();
313cb5fe245SEnji Cooper #if HAVE_EV_DISPATCH
314cb5fe245SEnji Cooper test_kevent_vnode_dispatch();
315cb5fe245SEnji Cooper #endif
316cb5fe245SEnji Cooper test_kevent_vnode_note_write();
317cb5fe245SEnji Cooper test_kevent_vnode_note_attrib();
318cb5fe245SEnji Cooper test_kevent_vnode_note_rename();
319cb5fe245SEnji Cooper test_kevent_vnode_note_delete();
320*7259ca31SKyle Evans test_kevent_vnode_note_delete_fifo();
321cb5fe245SEnji Cooper close(kqfd);
322cb5fe245SEnji Cooper }
323