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