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