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$ 17 */ 18 19 #include "common.h" 20 21 int vnode_fd; 22 23 static 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 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 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 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 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 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 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 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 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