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 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 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 66 test_kevent_vnode_note_delete_fifo(void) 67 { 68 const char *test_id = "kevent(EVFILT_VNODE, NOTE_DELETE, FIFO)"; 69 const char *fifo_path = "./kqueue-fifo.tmp"; 70 struct kevent kev; 71 int fd; 72 pid_t pid; 73 74 test_begin(test_id); 75 76 if (mkfifo(fifo_path, 0600) != 0) 77 err(1, "mkfifo"); 78 79 pid = fork(); 80 if (pid == -1) 81 err(1, "fork"); 82 83 if (pid == 0) { 84 char buf[4]; 85 86 fd = open(fifo_path, O_RDONLY); 87 if (fd == -1) 88 _exit(1); 89 90 while (read(fd, buf, sizeof(buf)) != 0) { 91 } 92 93 _exit(0); 94 } 95 96 sleep(1); 97 if (waitpid(pid, NULL, WNOHANG) == pid) { 98 unlink(fifo_path); 99 err(1, "open"); 100 } 101 102 fd = open(fifo_path, O_WRONLY); 103 if (fd < 0) { 104 unlink(fifo_path); 105 err(1, "open"); 106 } 107 108 EV_SET(&kev, fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, NOTE_DELETE, 0, NULL); 109 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) { 110 unlink(fifo_path); 111 err(1, "%s", test_id); 112 } 113 114 if (unlink(fifo_path) < 0) 115 err(1, "unlink"); 116 117 kevent_cmp(&kev, kevent_get(kqfd)); 118 close(fd); 119 120 success(); 121 } 122 123 static void 124 test_kevent_vnode_note_write(void) 125 { 126 const char *test_id = "kevent(EVFILT_VNODE, NOTE_WRITE)"; 127 struct kevent kev; 128 129 test_begin(test_id); 130 131 EV_SET(&kev, vnode_fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, NOTE_WRITE, 0, NULL); 132 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 133 err(1, "%s", test_id); 134 135 if (system("echo hello >> ./kqueue-test.tmp") < 0) 136 err(1, "system"); 137 138 /* BSD kqueue adds NOTE_EXTEND even though it was not requested */ 139 /* BSD kqueue removes EV_ENABLE */ 140 kev.flags &= ~EV_ENABLE; // XXX-FIXME compatibility issue 141 kev.fflags |= NOTE_EXTEND; // XXX-FIXME compatibility issue 142 kevent_cmp(&kev, kevent_get(kqfd)); 143 144 success(); 145 } 146 147 static void 148 test_kevent_vnode_note_attrib(void) 149 { 150 const char *test_id = "kevent(EVFILT_VNODE, NOTE_ATTRIB)"; 151 struct kevent kev; 152 int nfds; 153 154 test_begin(test_id); 155 156 EV_SET(&kev, vnode_fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, NOTE_ATTRIB, 0, NULL); 157 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 158 err(1, "%s", test_id); 159 160 if (system("touch ./kqueue-test.tmp") < 0) 161 err(1, "system"); 162 163 nfds = kevent(kqfd, NULL, 0, &kev, 1, NULL); 164 if (nfds < 1) 165 err(1, "%s", test_id); 166 if (kev.ident != (uintptr_t)vnode_fd || 167 kev.filter != EVFILT_VNODE || 168 kev.fflags != NOTE_ATTRIB) 169 err(1, "%s - incorrect event (sig=%u; filt=%d; flags=%d)", 170 test_id, (unsigned int)kev.ident, kev.filter, kev.flags); 171 172 success(); 173 } 174 175 static void 176 test_kevent_vnode_note_rename(void) 177 { 178 const char *test_id = "kevent(EVFILT_VNODE, NOTE_RENAME)"; 179 struct kevent kev; 180 int nfds; 181 182 test_begin(test_id); 183 184 EV_SET(&kev, vnode_fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, NOTE_RENAME, 0, NULL); 185 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 186 err(1, "%s", test_id); 187 188 if (system("mv ./kqueue-test.tmp ./kqueue-test2.tmp") < 0) 189 err(1, "system"); 190 191 nfds = kevent(kqfd, NULL, 0, &kev, 1, NULL); 192 if (nfds < 1) 193 err(1, "%s", test_id); 194 if (kev.ident != (uintptr_t)vnode_fd || 195 kev.filter != EVFILT_VNODE || 196 kev.fflags != NOTE_RENAME) 197 err(1, "%s - incorrect event (sig=%u; filt=%d; flags=%d)", 198 test_id, (unsigned int)kev.ident, kev.filter, kev.flags); 199 200 if (system("mv ./kqueue-test2.tmp ./kqueue-test.tmp") < 0) 201 err(1, "system"); 202 203 success(); 204 } 205 206 static void 207 test_kevent_vnode_del(void) 208 { 209 const char *test_id = "kevent(EVFILT_VNODE, EV_DELETE)"; 210 struct kevent kev; 211 212 test_begin(test_id); 213 214 EV_SET(&kev, vnode_fd, EVFILT_VNODE, EV_DELETE, 0, 0, NULL); 215 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 216 err(1, "%s", test_id); 217 218 success(); 219 } 220 221 static void 222 test_kevent_vnode_disable_and_enable(void) 223 { 224 const char *test_id = "kevent(EVFILT_VNODE, EV_DISABLE and EV_ENABLE)"; 225 struct kevent kev; 226 int nfds; 227 228 test_begin(test_id); 229 230 test_no_kevents(); 231 232 /* Add the watch and immediately disable it */ 233 EV_SET(&kev, vnode_fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, NOTE_ATTRIB, 0, NULL); 234 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 235 err(1, "%s", test_id); 236 kev.flags = EV_DISABLE; 237 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 238 err(1, "%s", test_id); 239 240 /* Confirm that the watch is disabled */ 241 if (system("touch ./kqueue-test.tmp") < 0) 242 err(1, "system"); 243 test_no_kevents(); 244 245 /* Re-enable and check again */ 246 kev.flags = EV_ENABLE; 247 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 248 err(1, "%s", test_id); 249 if (system("touch ./kqueue-test.tmp") < 0) 250 err(1, "system"); 251 nfds = kevent(kqfd, NULL, 0, &kev, 1, NULL); 252 if (nfds < 1) 253 err(1, "%s", test_id); 254 if (kev.ident != (uintptr_t)vnode_fd || 255 kev.filter != EVFILT_VNODE || 256 kev.fflags != NOTE_ATTRIB) 257 err(1, "%s - incorrect event (sig=%u; filt=%d; flags=%d)", 258 test_id, (unsigned int)kev.ident, kev.filter, kev.flags); 259 260 success(); 261 } 262 263 #if HAVE_EV_DISPATCH 264 static void 265 test_kevent_vnode_dispatch(void) 266 { 267 const char *test_id = "kevent(EVFILT_VNODE, EV_DISPATCH)"; 268 struct kevent kev; 269 int nfds; 270 271 test_begin(test_id); 272 273 test_no_kevents(); 274 275 EV_SET(&kev, vnode_fd, EVFILT_VNODE, EV_ADD | EV_DISPATCH, NOTE_ATTRIB, 0, NULL); 276 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 277 err(1, "%s", test_id); 278 279 if (system("touch ./kqueue-test.tmp") < 0) 280 err(1, "system"); 281 282 nfds = kevent(kqfd, NULL, 0, &kev, 1, NULL); 283 if (nfds < 1) 284 err(1, "%s", test_id); 285 if (kev.ident != (uintptr_t)vnode_fd || 286 kev.filter != EVFILT_VNODE || 287 kev.fflags != NOTE_ATTRIB) 288 err(1, "%s - incorrect event (sig=%u; filt=%d; flags=%d)", 289 test_id, (unsigned int)kev.ident, kev.filter, kev.flags); 290 291 /* Confirm that the watch is disabled automatically */ 292 puts("-- checking that watch is disabled"); 293 if (system("touch ./kqueue-test.tmp") < 0) 294 err(1, "system"); 295 test_no_kevents(); 296 297 /* Delete the watch */ 298 EV_SET(&kev, vnode_fd, EVFILT_VNODE, EV_DELETE, NOTE_ATTRIB, 0, NULL); 299 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) 300 err(1, "remove watch failed: %s", test_id); 301 302 success(); 303 } 304 #endif /* HAVE_EV_DISPATCH */ 305 306 void 307 test_evfilt_vnode(void) 308 { 309 kqfd = kqueue(); 310 test_kevent_vnode_add(); 311 test_kevent_vnode_del(); 312 test_kevent_vnode_disable_and_enable(); 313 #if HAVE_EV_DISPATCH 314 test_kevent_vnode_dispatch(); 315 #endif 316 test_kevent_vnode_note_write(); 317 test_kevent_vnode_note_attrib(); 318 test_kevent_vnode_note_rename(); 319 test_kevent_vnode_note_delete(); 320 test_kevent_vnode_note_delete_fifo(); 321 close(kqfd); 322 } 323