1 /*
2 * Copyright (c) 2009 Mark Heily <mark@heily.com>
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
17 #include "common.h"
18
19 int vnode_fd;
20
21 static void
test_kevent_vnode_add(void)22 test_kevent_vnode_add(void)
23 {
24 const char *test_id = "kevent(EVFILT_VNODE, EV_ADD)";
25 const char *testfile = "./kqueue-test.tmp";
26 struct kevent kev;
27
28 test_begin(test_id);
29
30 system("touch ./kqueue-test.tmp");
31 vnode_fd = open(testfile, O_RDONLY);
32 if (vnode_fd < 0)
33 err(1, "open of %s", testfile);
34 else
35 printf("vnode_fd = %d\n", vnode_fd);
36
37 EV_SET(&kev, vnode_fd, EVFILT_VNODE, EV_ADD,
38 NOTE_WRITE | NOTE_ATTRIB | NOTE_RENAME | NOTE_DELETE, 0, NULL);
39 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
40 err(1, "%s", test_id);
41
42 success();
43 }
44
45 static void
test_kevent_vnode_note_delete(void)46 test_kevent_vnode_note_delete(void)
47 {
48 const char *test_id = "kevent(EVFILT_VNODE, NOTE_DELETE)";
49 struct kevent kev;
50
51 test_begin(test_id);
52
53 EV_SET(&kev, vnode_fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, NOTE_DELETE, 0, NULL);
54 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
55 err(1, "%s", test_id);
56
57 if (unlink("./kqueue-test.tmp") < 0)
58 err(1, "unlink");
59
60 kevent_cmp(&kev, kevent_get(kqfd));
61
62 success();
63 }
64
65 static void
test_kevent_vnode_note_write(void)66 test_kevent_vnode_note_write(void)
67 {
68 const char *test_id = "kevent(EVFILT_VNODE, NOTE_WRITE)";
69 struct kevent kev;
70
71 test_begin(test_id);
72
73 EV_SET(&kev, vnode_fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, NOTE_WRITE, 0, NULL);
74 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
75 err(1, "%s", test_id);
76
77 if (system("echo hello >> ./kqueue-test.tmp") < 0)
78 err(1, "system");
79
80 /* BSD kqueue adds NOTE_EXTEND even though it was not requested */
81 /* BSD kqueue removes EV_ENABLE */
82 kev.flags &= ~EV_ENABLE; // XXX-FIXME compatibility issue
83 kev.fflags |= NOTE_EXTEND; // XXX-FIXME compatibility issue
84 kevent_cmp(&kev, kevent_get(kqfd));
85
86 success();
87 }
88
89 static void
test_kevent_vnode_note_attrib(void)90 test_kevent_vnode_note_attrib(void)
91 {
92 const char *test_id = "kevent(EVFILT_VNODE, NOTE_ATTRIB)";
93 struct kevent kev;
94 int nfds;
95
96 test_begin(test_id);
97
98 EV_SET(&kev, vnode_fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, NOTE_ATTRIB, 0, NULL);
99 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
100 err(1, "%s", test_id);
101
102 if (system("touch ./kqueue-test.tmp") < 0)
103 err(1, "system");
104
105 nfds = kevent(kqfd, NULL, 0, &kev, 1, NULL);
106 if (nfds < 1)
107 err(1, "%s", test_id);
108 if (kev.ident != (uintptr_t)vnode_fd ||
109 kev.filter != EVFILT_VNODE ||
110 kev.fflags != NOTE_ATTRIB)
111 err(1, "%s - incorrect event (sig=%u; filt=%d; flags=%d)",
112 test_id, (unsigned int)kev.ident, kev.filter, kev.flags);
113
114 success();
115 }
116
117 static void
test_kevent_vnode_note_rename(void)118 test_kevent_vnode_note_rename(void)
119 {
120 const char *test_id = "kevent(EVFILT_VNODE, NOTE_RENAME)";
121 struct kevent kev;
122 int nfds;
123
124 test_begin(test_id);
125
126 EV_SET(&kev, vnode_fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, NOTE_RENAME, 0, NULL);
127 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
128 err(1, "%s", test_id);
129
130 if (system("mv ./kqueue-test.tmp ./kqueue-test2.tmp") < 0)
131 err(1, "system");
132
133 nfds = kevent(kqfd, NULL, 0, &kev, 1, NULL);
134 if (nfds < 1)
135 err(1, "%s", test_id);
136 if (kev.ident != (uintptr_t)vnode_fd ||
137 kev.filter != EVFILT_VNODE ||
138 kev.fflags != NOTE_RENAME)
139 err(1, "%s - incorrect event (sig=%u; filt=%d; flags=%d)",
140 test_id, (unsigned int)kev.ident, kev.filter, kev.flags);
141
142 if (system("mv ./kqueue-test2.tmp ./kqueue-test.tmp") < 0)
143 err(1, "system");
144
145 success();
146 }
147
148 static void
test_kevent_vnode_del(void)149 test_kevent_vnode_del(void)
150 {
151 const char *test_id = "kevent(EVFILT_VNODE, EV_DELETE)";
152 struct kevent kev;
153
154 test_begin(test_id);
155
156 EV_SET(&kev, vnode_fd, EVFILT_VNODE, EV_DELETE, 0, 0, NULL);
157 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
158 err(1, "%s", test_id);
159
160 success();
161 }
162
163 static void
test_kevent_vnode_disable_and_enable(void)164 test_kevent_vnode_disable_and_enable(void)
165 {
166 const char *test_id = "kevent(EVFILT_VNODE, EV_DISABLE and EV_ENABLE)";
167 struct kevent kev;
168 int nfds;
169
170 test_begin(test_id);
171
172 test_no_kevents();
173
174 /* Add the watch and immediately disable it */
175 EV_SET(&kev, vnode_fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, NOTE_ATTRIB, 0, NULL);
176 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
177 err(1, "%s", test_id);
178 kev.flags = EV_DISABLE;
179 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
180 err(1, "%s", test_id);
181
182 /* Confirm that the watch is disabled */
183 if (system("touch ./kqueue-test.tmp") < 0)
184 err(1, "system");
185 test_no_kevents();
186
187 /* Re-enable and check again */
188 kev.flags = EV_ENABLE;
189 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
190 err(1, "%s", test_id);
191 if (system("touch ./kqueue-test.tmp") < 0)
192 err(1, "system");
193 nfds = kevent(kqfd, NULL, 0, &kev, 1, NULL);
194 if (nfds < 1)
195 err(1, "%s", test_id);
196 if (kev.ident != (uintptr_t)vnode_fd ||
197 kev.filter != EVFILT_VNODE ||
198 kev.fflags != NOTE_ATTRIB)
199 err(1, "%s - incorrect event (sig=%u; filt=%d; flags=%d)",
200 test_id, (unsigned int)kev.ident, kev.filter, kev.flags);
201
202 success();
203 }
204
205 #if HAVE_EV_DISPATCH
206 static void
test_kevent_vnode_dispatch(void)207 test_kevent_vnode_dispatch(void)
208 {
209 const char *test_id = "kevent(EVFILT_VNODE, EV_DISPATCH)";
210 struct kevent kev;
211 int nfds;
212
213 test_begin(test_id);
214
215 test_no_kevents();
216
217 EV_SET(&kev, vnode_fd, EVFILT_VNODE, EV_ADD | EV_DISPATCH, NOTE_ATTRIB, 0, NULL);
218 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
219 err(1, "%s", test_id);
220
221 if (system("touch ./kqueue-test.tmp") < 0)
222 err(1, "system");
223
224 nfds = kevent(kqfd, NULL, 0, &kev, 1, NULL);
225 if (nfds < 1)
226 err(1, "%s", test_id);
227 if (kev.ident != (uintptr_t)vnode_fd ||
228 kev.filter != EVFILT_VNODE ||
229 kev.fflags != NOTE_ATTRIB)
230 err(1, "%s - incorrect event (sig=%u; filt=%d; flags=%d)",
231 test_id, (unsigned int)kev.ident, kev.filter, kev.flags);
232
233 /* Confirm that the watch is disabled automatically */
234 puts("-- checking that watch is disabled");
235 if (system("touch ./kqueue-test.tmp") < 0)
236 err(1, "system");
237 test_no_kevents();
238
239 /* Delete the watch */
240 EV_SET(&kev, vnode_fd, EVFILT_VNODE, EV_DELETE, NOTE_ATTRIB, 0, NULL);
241 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
242 err(1, "remove watch failed: %s", test_id);
243
244 success();
245 }
246 #endif /* HAVE_EV_DISPATCH */
247
248 void
test_evfilt_vnode(void)249 test_evfilt_vnode(void)
250 {
251 kqfd = kqueue();
252 test_kevent_vnode_add();
253 test_kevent_vnode_del();
254 test_kevent_vnode_disable_and_enable();
255 #if HAVE_EV_DISPATCH
256 test_kevent_vnode_dispatch();
257 #endif
258 test_kevent_vnode_note_write();
259 test_kevent_vnode_note_attrib();
260 test_kevent_vnode_note_rename();
261 test_kevent_vnode_note_delete();
262 close(kqfd);
263 }
264