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