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