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 * $FreeBSD: releng/10.3/tests/sys/kqueue/vnode.c 200483 2009-12-13 20:27:46Z rwatson $
17 */
18
19#include "common.h"
20
21int kqfd;
22int vnode_fd;
23
24void
25test_kevent_vnode_add(void)
26{
27    const char *test_id = "kevent(EVFILT_VNODE, EV_ADD)";
28    const char *testfile = "/tmp/kqueue-test.tmp";
29    struct kevent kev;
30
31    test_begin(test_id);
32
33    system("touch /tmp/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
48void
49test_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("/tmp/kqueue-test.tmp") < 0)
61        err(1, "unlink");
62
63    kevent_cmp(&kev, kevent_get(kqfd));
64
65    success();
66}
67
68void
69test_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 >> /tmp/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
92void
93test_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 /tmp/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
120void
121test_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 /tmp/kqueue-test.tmp /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 /tmp/kqueue-test2.tmp /tmp/kqueue-test.tmp") < 0)
146        err(1, "system");
147
148    success();
149}
150
151void
152test_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
166void
167test_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 /tmp/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 /tmp/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
209void
210test_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 /tmp/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 /tmp/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
251void
252test_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