xref: /freebsd/tests/sys/kern/inotify_test.c (revision 4ea7a920de22d283dd801a38588f35f56cdddcb6)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2025 Klara, Inc.
5  */
6 
7 #include <sys/capsicum.h>
8 #include <sys/filio.h>
9 #include <sys/inotify.h>
10 #include <sys/ioccom.h>
11 #include <sys/mount.h>
12 #include <sys/socket.h>
13 #include <sys/stat.h>
14 #include <sys/sysctl.h>
15 #include <sys/un.h>
16 
17 #include <dirent.h>
18 #include <errno.h>
19 #include <fcntl.h>
20 #include <limits.h>
21 #include <mntopts.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <unistd.h>
26 
27 #include <atf-c.h>
28 
29 static const char *
ev2name(int event)30 ev2name(int event)
31 {
32 	switch (event) {
33 	case IN_ACCESS:
34 		return ("IN_ACCESS");
35 	case IN_ATTRIB:
36 		return ("IN_ATTRIB");
37 	case IN_CLOSE_WRITE:
38 		return ("IN_CLOSE_WRITE");
39 	case IN_CLOSE_NOWRITE:
40 		return ("IN_CLOSE_NOWRITE");
41 	case IN_CREATE:
42 		return ("IN_CREATE");
43 	case IN_DELETE:
44 		return ("IN_DELETE");
45 	case IN_DELETE_SELF:
46 		return ("IN_DELETE_SELF");
47 	case IN_MODIFY:
48 		return ("IN_MODIFY");
49 	case IN_MOVE_SELF:
50 		return ("IN_MOVE_SELF");
51 	case IN_MOVED_FROM:
52 		return ("IN_MOVED_FROM");
53 	case IN_MOVED_TO:
54 		return ("IN_MOVED_TO");
55 	case IN_OPEN:
56 		return ("IN_OPEN");
57 	default:
58 		return (NULL);
59 	}
60 }
61 
62 static void
close_checked(int fd)63 close_checked(int fd)
64 {
65 	ATF_REQUIRE(close(fd) == 0);
66 }
67 
68 /*
69  * Make sure that no other events are pending, and close the inotify descriptor.
70  */
71 static void
close_inotify(int fd)72 close_inotify(int fd)
73 {
74 	int n;
75 
76 	ATF_REQUIRE(ioctl(fd, FIONREAD, &n) == 0);
77 	ATF_REQUIRE(n == 0);
78 	close_checked(fd);
79 }
80 
81 static uint32_t
consume_event_cookie(int ifd,int wd,unsigned int event,unsigned int flags,const char * name)82 consume_event_cookie(int ifd, int wd, unsigned int event, unsigned int flags,
83     const char *name)
84 {
85 	struct inotify_event *ev;
86 	size_t evsz, namelen;
87 	ssize_t n;
88 	uint32_t cookie;
89 
90 	/* Only read one record. */
91 	namelen = name == NULL ? 0 : strlen(name);
92 	evsz = sizeof(*ev) + _IN_NAMESIZE(namelen);
93 	ev = malloc(evsz);
94 	ATF_REQUIRE(ev != NULL);
95 
96 	n = read(ifd, ev, evsz);
97 	ATF_REQUIRE_MSG(n >= 0, "failed to read event %s", ev2name(event));
98 	ATF_REQUIRE((size_t)n >= sizeof(*ev));
99 	ATF_REQUIRE((size_t)n == sizeof(*ev) + ev->len);
100 	ATF_REQUIRE((size_t)n == evsz);
101 
102 	ATF_REQUIRE_MSG((ev->mask & IN_ALL_EVENTS) == event,
103 	    "expected event %#x, got %#x", event, ev->mask);
104 	ATF_REQUIRE_MSG((ev->mask & _IN_ALL_RETFLAGS) == flags,
105 	    "expected flags %#x, got %#x", flags, ev->mask);
106 	ATF_REQUIRE_MSG(ev->wd == wd,
107 	    "expected wd %d, got %d", wd, ev->wd);
108 	ATF_REQUIRE_MSG(name == NULL || strcmp(name, ev->name) == 0,
109 	    "expected name '%s', got '%s'", name, ev->name);
110 	cookie = ev->cookie;
111 	if ((ev->mask & (IN_MOVED_FROM | IN_MOVED_TO)) == 0)
112 		ATF_REQUIRE(cookie == 0);
113 	free(ev);
114 	return (cookie);
115 }
116 
117 /*
118  * Read an event from the inotify file descriptor and check that it
119  * matches the expected values.
120  */
121 static void
consume_event(int ifd,int wd,unsigned int event,unsigned int flags,const char * name)122 consume_event(int ifd, int wd, unsigned int event, unsigned int flags,
123     const char *name)
124 {
125 	(void)consume_event_cookie(ifd, wd, event, flags, name);
126 }
127 
128 static int
inotify(int flags)129 inotify(int flags)
130 {
131 	int ifd;
132 
133 	ifd = inotify_init1(flags);
134 	ATF_REQUIRE(ifd != -1);
135 	return (ifd);
136 }
137 
138 static void
mount_nullfs(char * dir,char * src)139 mount_nullfs(char *dir, char *src)
140 {
141 	struct iovec *iov;
142 	char errmsg[1024];
143 	int error, iovlen;
144 
145 	iov = NULL;
146 	iovlen = 0;
147 
148 	build_iovec(&iov, &iovlen, "fstype", "nullfs", (size_t)-1);
149 	build_iovec(&iov, &iovlen, "fspath", dir, (size_t)-1);
150 	build_iovec(&iov, &iovlen, "target", src, (size_t)-1);
151 	build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof(errmsg));
152 
153 	errmsg[0] = '\0';
154 	error = nmount(iov, iovlen, 0);
155 	ATF_REQUIRE_MSG(error == 0,
156 	    "mount nullfs %s %s: %s", src, dir,
157 	    errmsg[0] == '\0' ? strerror(errno) : errmsg);
158 
159 	free_iovec(&iov, &iovlen);
160 }
161 
162 static void
mount_tmpfs(const char * dir)163 mount_tmpfs(const char *dir)
164 {
165 	struct iovec *iov;
166 	char errmsg[1024];
167 	int error, iovlen;
168 
169 	iov = NULL;
170 	iovlen = 0;
171 
172 	build_iovec(&iov, &iovlen, "fstype", "tmpfs", (size_t)-1);
173 	build_iovec(&iov, &iovlen, "fspath", __DECONST(char *, dir),
174 	    (size_t)-1);
175 	build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof(errmsg));
176 
177 	errmsg[0] = '\0';
178 	error = nmount(iov, iovlen, 0);
179 	ATF_REQUIRE_MSG(error == 0,
180 	    "mount tmpfs %s: %s", dir,
181 	    errmsg[0] == '\0' ? strerror(errno) : errmsg);
182 
183 	free_iovec(&iov, &iovlen);
184 }
185 
186 static int
watch_file(int ifd,int events,char * path)187 watch_file(int ifd, int events, char *path)
188 {
189 	int fd, wd;
190 
191 	strncpy(path, "test.XXXXXX", PATH_MAX);
192 	fd = mkstemp(path);
193 	ATF_REQUIRE(fd != -1);
194 	close_checked(fd);
195 
196 	wd = inotify_add_watch(ifd, path, events);
197 	ATF_REQUIRE(wd != -1);
198 
199 	return (wd);
200 }
201 
202 static int
watch_dir(int ifd,int events,char * path)203 watch_dir(int ifd, int events, char *path)
204 {
205 	char *p;
206 	int wd;
207 
208 	strlcpy(path, "test.XXXXXX", PATH_MAX);
209 	p = mkdtemp(path);
210 	ATF_REQUIRE(p == path);
211 
212 	wd = inotify_add_watch(ifd, path, events);
213 	ATF_REQUIRE(wd != -1);
214 
215 	return (wd);
216 }
217 
218 /*
219  * Verify that Capsicum restrictions are applied as expected.
220  */
221 ATF_TC_WITHOUT_HEAD(inotify_capsicum);
ATF_TC_BODY(inotify_capsicum,tc)222 ATF_TC_BODY(inotify_capsicum, tc)
223 {
224 	int error, dfd, ifd, wd;
225 
226 	ifd = inotify(IN_NONBLOCK);
227 	ATF_REQUIRE(ifd != -1);
228 
229 	dfd = open(".", O_RDONLY | O_DIRECTORY);
230 	ATF_REQUIRE(dfd != -1);
231 
232 	error = mkdirat(dfd, "testdir", 0755);
233 	ATF_REQUIRE(error == 0);
234 
235 	error = cap_enter();
236 	ATF_REQUIRE(error == 0);
237 
238 	/*
239 	 * Plain inotify_add_watch() is disallowed.
240 	 */
241 	wd = inotify_add_watch(ifd, ".", IN_DELETE_SELF);
242 	ATF_REQUIRE_ERRNO(ECAPMODE, wd == -1);
243 	wd = inotify_add_watch_at(ifd, dfd, "testdir", IN_DELETE_SELF);
244 	ATF_REQUIRE(wd >= 0);
245 
246 	/*
247 	 * Generate a record and consume it.
248 	 */
249 	error = unlinkat(dfd, "testdir", AT_REMOVEDIR);
250 	ATF_REQUIRE(error == 0);
251 	consume_event(ifd, wd, IN_DELETE_SELF, IN_ISDIR, NULL);
252 	consume_event(ifd, wd, 0, IN_IGNORED, NULL);
253 
254 	close_checked(dfd);
255 	close_inotify(ifd);
256 }
257 
258 /*
259  * Make sure that duplicate, back-to-back events are coalesced.
260  */
261 ATF_TC_WITHOUT_HEAD(inotify_coalesce);
ATF_TC_BODY(inotify_coalesce,tc)262 ATF_TC_BODY(inotify_coalesce, tc)
263 {
264 	char file[PATH_MAX], path[PATH_MAX];
265 	int fd, fd1, ifd, n, wd;
266 
267 	ifd = inotify(IN_NONBLOCK);
268 
269 	/* Create a directory and watch it. */
270 	wd = watch_dir(ifd, IN_OPEN, path);
271 	/* Create a file in the directory and open it. */
272 	snprintf(file, sizeof(file), "%s/file", path);
273 	fd = open(file, O_RDWR | O_CREAT, 0644);
274 	ATF_REQUIRE(fd != -1);
275 	close_checked(fd);
276 	fd = open(file, O_RDWR);
277 	ATF_REQUIRE(fd != -1);
278 	fd1 = open(file, O_RDONLY);
279 	ATF_REQUIRE(fd1 != -1);
280 	close_checked(fd1);
281 	close_checked(fd);
282 
283 	consume_event(ifd, wd, IN_OPEN, 0, "file");
284 	ATF_REQUIRE(ioctl(ifd, FIONREAD, &n) == 0);
285 	ATF_REQUIRE(n == 0);
286 
287 	close_inotify(ifd);
288 }
289 
290 /*
291  * Check handling of IN_MASK_CREATE.
292  */
293 ATF_TC_WITHOUT_HEAD(inotify_mask_create);
ATF_TC_BODY(inotify_mask_create,tc)294 ATF_TC_BODY(inotify_mask_create, tc)
295 {
296 	char path[PATH_MAX];
297 	int ifd, wd, wd1;
298 
299 	ifd = inotify(IN_NONBLOCK);
300 
301 	/* Create a directory and watch it. */
302 	wd = watch_dir(ifd, IN_CREATE, path);
303 	/* Updating the watch with IN_MASK_CREATE should result in an error. */
304 	wd1 = inotify_add_watch(ifd, path, IN_MODIFY | IN_MASK_CREATE);
305 	ATF_REQUIRE_ERRNO(EEXIST, wd1 == -1);
306 	/* It's an error to specify IN_MASK_ADD with IN_MASK_CREATE. */
307 	wd1 = inotify_add_watch(ifd, path, IN_MODIFY | IN_MASK_ADD |
308 	    IN_MASK_CREATE);
309 	ATF_REQUIRE_ERRNO(EINVAL, wd1 == -1);
310 	/* Updating the watch without IN_MASK_CREATE should work. */
311 	wd1 = inotify_add_watch(ifd, path, IN_MODIFY);
312 	ATF_REQUIRE(wd1 != -1);
313 	ATF_REQUIRE_EQ(wd, wd1);
314 
315 	close_inotify(ifd);
316 }
317 
318 /*
319  * Make sure that inotify cooperates with nullfs: if a lower vnode is the
320  * subject of an event, the upper vnode should be notified, and if the upper
321  * vnode is the subject of an event, the lower vnode should be notified.
322  */
323 ATF_TC_WITH_CLEANUP(inotify_nullfs);
ATF_TC_HEAD(inotify_nullfs,tc)324 ATF_TC_HEAD(inotify_nullfs, tc)
325 {
326 	atf_tc_set_md_var(tc, "require.user", "root");
327 }
ATF_TC_BODY(inotify_nullfs,tc)328 ATF_TC_BODY(inotify_nullfs, tc)
329 {
330 	char path[PATH_MAX], *p;
331 	int dfd, error, fd, ifd, mask, wd;
332 
333 	mask = IN_CREATE | IN_OPEN;
334 
335 	ifd = inotify(IN_NONBLOCK);
336 
337 	strlcpy(path, "./test.XXXXXX", sizeof(path));
338 	p = mkdtemp(path);
339 	ATF_REQUIRE(p == path);
340 
341 	error = mkdir("./mnt", 0755);
342 	ATF_REQUIRE(error == 0);
343 
344 	/* Mount the testdir onto ./mnt. */
345 	mount_nullfs("./mnt", path);
346 
347 	wd = inotify_add_watch(ifd, "./mnt", mask);
348 	ATF_REQUIRE(wd != -1);
349 
350 	/* Create a file in the lower directory and open it. */
351 	dfd = open(path, O_RDONLY | O_DIRECTORY);
352 	ATF_REQUIRE(dfd != -1);
353 	fd = openat(dfd, "file", O_RDWR | O_CREAT, 0644);
354 	close_checked(fd);
355 	close_checked(dfd);
356 
357 	/* We should see events via the nullfs mount. */
358 	consume_event(ifd, wd, IN_OPEN, IN_ISDIR, NULL);
359 	consume_event(ifd, wd, IN_CREATE, 0, "file");
360 	consume_event(ifd, wd, IN_OPEN, 0, "file");
361 
362 	error = inotify_rm_watch(ifd, wd);
363 	ATF_REQUIRE(error == 0);
364 	consume_event(ifd, wd, 0, IN_IGNORED, NULL);
365 
366 	/* Watch the lower directory. */
367 	wd = inotify_add_watch(ifd, path, mask);
368 	ATF_REQUIRE(wd != -1);
369 	/* ... and create a file in the upper directory and open it. */
370 	dfd = open("./mnt", O_RDONLY | O_DIRECTORY);
371 	ATF_REQUIRE(dfd != -1);
372 	fd = openat(dfd, "file2", O_RDWR | O_CREAT, 0644);
373 	ATF_REQUIRE(fd != -1);
374 	close_checked(fd);
375 	close_checked(dfd);
376 
377 	/* We should see events via the lower directory. */
378 	consume_event(ifd, wd, IN_OPEN, IN_ISDIR, NULL);
379 	consume_event(ifd, wd, IN_CREATE, 0, "file2");
380 	consume_event(ifd, wd, IN_OPEN, 0, "file2");
381 
382 	close_inotify(ifd);
383 }
ATF_TC_CLEANUP(inotify_nullfs,tc)384 ATF_TC_CLEANUP(inotify_nullfs, tc)
385 {
386 	int error;
387 
388 	error = unmount("./mnt", 0);
389 	if (error != 0) {
390 		perror("unmount");
391 		exit(1);
392 	}
393 }
394 
395 /*
396  * Make sure that exceeding max_events pending events results in an overflow
397  * event.
398  */
399 ATF_TC_WITHOUT_HEAD(inotify_queue_overflow);
ATF_TC_BODY(inotify_queue_overflow,tc)400 ATF_TC_BODY(inotify_queue_overflow, tc)
401 {
402 	char path[PATH_MAX];
403 	size_t size;
404 	int error, dfd, ifd, max, wd;
405 
406 	size = sizeof(max);
407 	error = sysctlbyname("vfs.inotify.max_queued_events", &max, &size, NULL,
408 	    0);
409 	ATF_REQUIRE(error == 0);
410 
411 	ifd = inotify(IN_NONBLOCK);
412 
413 	/* Create a directory and watch it for file creation events. */
414 	wd = watch_dir(ifd, IN_CREATE, path);
415 	dfd = open(path, O_DIRECTORY);
416 	ATF_REQUIRE(dfd != -1);
417 	/* Generate max+1 file creation events. */
418 	for (int i = 0; i < max + 1; i++) {
419 		char name[NAME_MAX];
420 		int fd;
421 
422 		(void)snprintf(name, sizeof(name), "file%d", i);
423 		fd = openat(dfd, name, O_CREAT | O_RDWR, 0644);
424 		ATF_REQUIRE(fd != -1);
425 		close_checked(fd);
426 	}
427 
428 	/*
429 	 * Read our events.  We should see files 0..max-1 and then an overflow
430 	 * event.
431 	 */
432 	for (int i = 0; i < max; i++) {
433 		char name[NAME_MAX];
434 
435 		(void)snprintf(name, sizeof(name), "file%d", i);
436 		consume_event(ifd, wd, IN_CREATE, 0, name);
437 	}
438 
439 	/* Look for an overflow event. */
440 	consume_event(ifd, -1, 0, IN_Q_OVERFLOW, NULL);
441 
442 	close_checked(dfd);
443 	close_inotify(ifd);
444 }
445 
446 ATF_TC_WITHOUT_HEAD(inotify_event_access_file);
ATF_TC_BODY(inotify_event_access_file,tc)447 ATF_TC_BODY(inotify_event_access_file, tc)
448 {
449 	char path[PATH_MAX], buf[16];
450 	off_t nb;
451 	ssize_t n;
452 	int error, fd, fd1, ifd, s[2], wd;
453 
454 	ifd = inotify(IN_NONBLOCK);
455 
456 	wd = watch_file(ifd, IN_ACCESS, path);
457 
458 	fd = open(path, O_RDWR);
459 	n = write(fd, "test", 4);
460 	ATF_REQUIRE(n == 4);
461 
462 	/* A simple read(2) should generate an access. */
463 	ATF_REQUIRE(lseek(fd, 0, SEEK_SET) == 0);
464 	n = read(fd, buf, sizeof(buf));
465 	ATF_REQUIRE(n == 4);
466 	ATF_REQUIRE(memcmp(buf, "test", 4) == 0);
467 	consume_event(ifd, wd, IN_ACCESS, 0, NULL);
468 
469 	/* copy_file_range(2) should as well. */
470 	ATF_REQUIRE(lseek(fd, 0, SEEK_SET) == 0);
471 	fd1 = open("sink", O_RDWR | O_CREAT, 0644);
472 	ATF_REQUIRE(fd1 != -1);
473 	n = copy_file_range(fd, NULL, fd1, NULL, 4, 0);
474 	ATF_REQUIRE(n == 4);
475 	close_checked(fd1);
476 	consume_event(ifd, wd, IN_ACCESS, 0, NULL);
477 
478 	/* As should sendfile(2). */
479 	error = socketpair(AF_UNIX, SOCK_STREAM, 0, s);
480 	ATF_REQUIRE(error == 0);
481 	error = sendfile(fd, s[0], 0, 4, NULL, &nb, 0);
482 	ATF_REQUIRE(error == 0);
483 	ATF_REQUIRE(nb == 4);
484 	consume_event(ifd, wd, IN_ACCESS, 0, NULL);
485 	close_checked(s[0]);
486 	close_checked(s[1]);
487 
488 	close_checked(fd);
489 
490 	close_inotify(ifd);
491 }
492 
493 ATF_TC_WITHOUT_HEAD(inotify_event_access_dir);
ATF_TC_BODY(inotify_event_access_dir,tc)494 ATF_TC_BODY(inotify_event_access_dir, tc)
495 {
496 	char root[PATH_MAX], path[PATH_MAX];
497 	struct dirent *ent;
498 	DIR *dir;
499 	int error, ifd, wd;
500 
501 	ifd = inotify(IN_NONBLOCK);
502 
503 	wd = watch_dir(ifd, IN_ACCESS, root);
504 	snprintf(path, sizeof(path), "%s/dir", root);
505 	error = mkdir(path, 0755);
506 	ATF_REQUIRE(error == 0);
507 
508 	/* Read an entry and generate an access. */
509 	dir = opendir(path);
510 	ATF_REQUIRE(dir != NULL);
511 	ent = readdir(dir);
512 	ATF_REQUIRE(ent != NULL);
513 	ATF_REQUIRE(strcmp(ent->d_name, ".") == 0 ||
514 	    strcmp(ent->d_name, "..") == 0);
515 	ATF_REQUIRE(closedir(dir) == 0);
516 	consume_event(ifd, wd, IN_ACCESS, IN_ISDIR, "dir");
517 
518 	/*
519 	 * Reading the watched directory should generate an access event.
520 	 * This is contrary to Linux's inotify man page, which states that
521 	 * IN_ACCESS is only generated for accesses to objects in a watched
522 	 * directory.
523 	 */
524 	dir = opendir(root);
525 	ATF_REQUIRE(dir != NULL);
526 	ent = readdir(dir);
527 	ATF_REQUIRE(ent != NULL);
528 	ATF_REQUIRE(strcmp(ent->d_name, ".") == 0 ||
529 	    strcmp(ent->d_name, "..") == 0);
530 	ATF_REQUIRE(closedir(dir) == 0);
531 	consume_event(ifd, wd, IN_ACCESS, IN_ISDIR, NULL);
532 
533 	close_inotify(ifd);
534 }
535 
536 ATF_TC_WITHOUT_HEAD(inotify_event_attrib);
ATF_TC_BODY(inotify_event_attrib,tc)537 ATF_TC_BODY(inotify_event_attrib, tc)
538 {
539 	char path[PATH_MAX];
540 	int error, ifd, fd, wd;
541 
542 	ifd = inotify(IN_NONBLOCK);
543 
544 	wd = watch_file(ifd, IN_ATTRIB, path);
545 
546 	fd = open(path, O_RDWR);
547 	ATF_REQUIRE(fd != -1);
548 	error = fchmod(fd, 0600);
549 	ATF_REQUIRE(error == 0);
550 	consume_event(ifd, wd, IN_ATTRIB, 0, NULL);
551 
552 	error = fchown(fd, getuid(), getgid());
553 	ATF_REQUIRE(error == 0);
554 	consume_event(ifd, wd, IN_ATTRIB, 0, NULL);
555 
556 	close_checked(fd);
557 	close_inotify(ifd);
558 }
559 
560 ATF_TC_WITHOUT_HEAD(inotify_event_close_nowrite);
ATF_TC_BODY(inotify_event_close_nowrite,tc)561 ATF_TC_BODY(inotify_event_close_nowrite, tc)
562 {
563 	char file[PATH_MAX], file1[PATH_MAX], dir[PATH_MAX];
564 	int ifd, fd, wd1, wd2;
565 
566 	ifd = inotify(IN_NONBLOCK);
567 
568 	wd1 = watch_dir(ifd, IN_CLOSE_NOWRITE, dir);
569 	wd2 = watch_file(ifd, IN_CLOSE_NOWRITE | IN_CLOSE_WRITE, file);
570 
571 	fd = open(dir, O_DIRECTORY);
572 	ATF_REQUIRE(fd != -1);
573 	close_checked(fd);
574 	consume_event(ifd, wd1, IN_CLOSE_NOWRITE, IN_ISDIR, NULL);
575 
576 	fd = open(file, O_RDONLY);
577 	ATF_REQUIRE(fd != -1);
578 	close_checked(fd);
579 	consume_event(ifd, wd2, IN_CLOSE_NOWRITE, 0, NULL);
580 
581 	snprintf(file1, sizeof(file1), "%s/file", dir);
582 	fd = open(file1, O_RDONLY | O_CREAT, 0644);
583 	ATF_REQUIRE(fd != -1);
584 	close_checked(fd);
585 	consume_event(ifd, wd1, IN_CLOSE_NOWRITE, 0, "file");
586 
587 	close_inotify(ifd);
588 }
589 
590 ATF_TC_WITHOUT_HEAD(inotify_event_close_write);
ATF_TC_BODY(inotify_event_close_write,tc)591 ATF_TC_BODY(inotify_event_close_write, tc)
592 {
593 	char path[PATH_MAX];
594 	int ifd, fd, wd;
595 
596 	ifd = inotify(IN_NONBLOCK);
597 
598 	wd = watch_file(ifd, IN_CLOSE_NOWRITE | IN_CLOSE_WRITE, path);
599 
600 	fd = open(path, O_RDWR);
601 	ATF_REQUIRE(fd != -1);
602 	close_checked(fd);
603 	consume_event(ifd, wd, IN_CLOSE_WRITE, 0, NULL);
604 
605 	close_inotify(ifd);
606 }
607 
608 /* Verify that various operations in a directory generate IN_CREATE events. */
609 ATF_TC_WITHOUT_HEAD(inotify_event_create);
ATF_TC_BODY(inotify_event_create,tc)610 ATF_TC_BODY(inotify_event_create, tc)
611 {
612 	struct sockaddr_un sun;
613 	char path[PATH_MAX], path1[PATH_MAX], root[PATH_MAX];
614 	ssize_t n;
615 	int error, ifd, ifd1, fd, s, wd, wd1;
616 	char b;
617 
618 	ifd = inotify(IN_NONBLOCK);
619 
620 	wd = watch_dir(ifd, IN_CREATE, root);
621 
622 	/* Regular file. */
623 	snprintf(path, sizeof(path), "%s/file", root);
624 	fd = open(path, O_RDWR | O_CREAT, 0644);
625 	ATF_REQUIRE(fd != -1);
626 	/*
627 	 * Make sure we get an event triggered by the fd used to create the
628 	 * file.
629 	 */
630 	ifd1 = inotify(IN_NONBLOCK);
631 	wd1 = inotify_add_watch(ifd1, root, IN_MODIFY);
632 	b = 42;
633 	n = write(fd, &b, sizeof(b));
634 	ATF_REQUIRE(n == sizeof(b));
635 	close_checked(fd);
636 	consume_event(ifd, wd, IN_CREATE, 0, "file");
637 	consume_event(ifd1, wd1, IN_MODIFY, 0, "file");
638 	close_inotify(ifd1);
639 
640 	/* Hard link. */
641 	snprintf(path1, sizeof(path1), "%s/link", root);
642 	error = link(path, path1);
643 	ATF_REQUIRE(error == 0);
644 	consume_event(ifd, wd, IN_CREATE, 0, "link");
645 
646 	/* Directory. */
647 	snprintf(path, sizeof(path), "%s/dir", root);
648 	error = mkdir(path, 0755);
649 	ATF_REQUIRE(error == 0);
650 	consume_event(ifd, wd, IN_CREATE, IN_ISDIR, "dir");
651 
652 	/* Symbolic link. */
653 	snprintf(path1, sizeof(path1), "%s/symlink", root);
654 	error = symlink(path, path1);
655 	ATF_REQUIRE(error == 0);
656 	consume_event(ifd, wd, IN_CREATE, 0, "symlink");
657 
658 	/* FIFO. */
659 	snprintf(path, sizeof(path), "%s/fifo", root);
660 	error = mkfifo(path, 0644);
661 	ATF_REQUIRE(error == 0);
662 	consume_event(ifd, wd, IN_CREATE, 0, "fifo");
663 
664 	/* Binding a socket. */
665 	s = socket(AF_UNIX, SOCK_STREAM, 0);
666 	memset(&sun, 0, sizeof(sun));
667 	sun.sun_family = AF_UNIX;
668 	sun.sun_len = sizeof(sun);
669 	snprintf(sun.sun_path, sizeof(sun.sun_path), "%s/socket", root);
670 	error = bind(s, (struct sockaddr *)&sun, sizeof(sun));
671 	ATF_REQUIRE(error == 0);
672 	close_checked(s);
673 	consume_event(ifd, wd, IN_CREATE, 0, "socket");
674 
675 	close_inotify(ifd);
676 }
677 
678 ATF_TC_WITHOUT_HEAD(inotify_event_delete);
ATF_TC_BODY(inotify_event_delete,tc)679 ATF_TC_BODY(inotify_event_delete, tc)
680 {
681 	char root[PATH_MAX], path[PATH_MAX], file[PATH_MAX];
682 	int error, fd, ifd, wd, wd2;
683 
684 	ifd = inotify(IN_NONBLOCK);
685 
686 	wd = watch_dir(ifd, IN_DELETE | IN_DELETE_SELF, root);
687 
688 	snprintf(path, sizeof(path), "%s/file", root);
689 	fd = open(path, O_RDWR | O_CREAT, 0644);
690 	ATF_REQUIRE(fd != -1);
691 	error = unlink(path);
692 	ATF_REQUIRE(error == 0);
693 	consume_event(ifd, wd, IN_DELETE, 0, "file");
694 	close_checked(fd);
695 
696 	/*
697 	 * Make sure that renaming over a file generates a delete event when and
698 	 * only when that file is watched.
699 	 */
700 	fd = open(path, O_RDWR | O_CREAT, 0644);
701 	ATF_REQUIRE(fd != -1);
702 	close_checked(fd);
703 	wd2 = inotify_add_watch(ifd, path, IN_DELETE | IN_DELETE_SELF);
704 	ATF_REQUIRE(wd2 != -1);
705 	snprintf(file, sizeof(file), "%s/file2", root);
706 	fd = open(file, O_RDWR | O_CREAT, 0644);
707 	ATF_REQUIRE(fd != -1);
708 	close_checked(fd);
709 	error = rename(file, path);
710 	ATF_REQUIRE(error == 0);
711 	consume_event(ifd, wd2, IN_DELETE_SELF, 0, NULL);
712 	consume_event(ifd, wd2, 0, IN_IGNORED, NULL);
713 
714 	error = unlink(path);
715 	ATF_REQUIRE(error == 0);
716 	consume_event(ifd, wd, IN_DELETE, 0, "file");
717 	error = rmdir(root);
718 	ATF_REQUIRE(error == 0);
719 	consume_event(ifd, wd, IN_DELETE_SELF, IN_ISDIR, NULL);
720 	consume_event(ifd, wd, 0, IN_IGNORED, NULL);
721 
722 	close_inotify(ifd);
723 }
724 
725 ATF_TC_WITHOUT_HEAD(inotify_event_move);
ATF_TC_BODY(inotify_event_move,tc)726 ATF_TC_BODY(inotify_event_move, tc)
727 {
728 	char dir1[PATH_MAX], dir2[PATH_MAX], path1[PATH_MAX], path2[PATH_MAX];
729 	char path3[PATH_MAX];
730 	int error, ifd, fd, wd1, wd2, wd3;
731 	uint32_t cookie1, cookie2;
732 
733 	ifd = inotify(IN_NONBLOCK);
734 
735 	wd1 = watch_dir(ifd, IN_MOVE | IN_MOVE_SELF, dir1);
736 	wd2 = watch_dir(ifd, IN_MOVE | IN_MOVE_SELF, dir2);
737 
738 	snprintf(path1, sizeof(path1), "%s/file", dir1);
739 	fd = open(path1, O_RDWR | O_CREAT, 0644);
740 	ATF_REQUIRE(fd != -1);
741 	close_checked(fd);
742 	snprintf(path2, sizeof(path2), "%s/file2", dir2);
743 	error = rename(path1, path2);
744 	ATF_REQUIRE(error == 0);
745 	cookie1 = consume_event_cookie(ifd, wd1, IN_MOVED_FROM, 0, "file");
746 	cookie2 = consume_event_cookie(ifd, wd2, IN_MOVED_TO, 0, "file2");
747 	ATF_REQUIRE_MSG(cookie1 == cookie2,
748 	    "expected cookie %u, got %u", cookie1, cookie2);
749 
750 	snprintf(path2, sizeof(path2), "%s/dir", dir2);
751 	error = rename(dir1, path2);
752 	ATF_REQUIRE(error == 0);
753 	consume_event(ifd, wd1, IN_MOVE_SELF, IN_ISDIR, NULL);
754 	consume_event(ifd, wd2, IN_MOVED_TO, IN_ISDIR, "dir");
755 
756 	wd3 = watch_file(ifd, IN_MOVE_SELF, path3);
757 	error = rename(path3, "foo");
758 	ATF_REQUIRE(error == 0);
759 	consume_event(ifd, wd3, IN_MOVE_SELF, 0, NULL);
760 
761 	close_inotify(ifd);
762 }
763 
764 ATF_TC_WITHOUT_HEAD(inotify_event_open);
ATF_TC_BODY(inotify_event_open,tc)765 ATF_TC_BODY(inotify_event_open, tc)
766 {
767 	char root[PATH_MAX], path[PATH_MAX];
768 	int error, ifd, fd, wd;
769 
770 	ifd = inotify(IN_NONBLOCK);
771 
772 	wd = watch_dir(ifd, IN_OPEN, root);
773 
774 	snprintf(path, sizeof(path), "%s/file", root);
775 	fd = open(path, O_RDWR | O_CREAT, 0644);
776 	ATF_REQUIRE(fd != -1);
777 	close_checked(fd);
778 	consume_event(ifd, wd, IN_OPEN, 0, "file");
779 
780 	fd = open(path, O_PATH);
781 	ATF_REQUIRE(fd != -1);
782 	close_checked(fd);
783 	consume_event(ifd, wd, IN_OPEN, 0, "file");
784 
785 	fd = open(root, O_DIRECTORY);
786 	ATF_REQUIRE(fd != -1);
787 	close_checked(fd);
788 	consume_event(ifd, wd, IN_OPEN, IN_ISDIR, NULL);
789 
790 	snprintf(path, sizeof(path), "%s/fifo", root);
791 	error = mkfifo(path, 0644);
792 	ATF_REQUIRE(error == 0);
793 	fd = open(path, O_RDWR);
794 	ATF_REQUIRE(fd != -1);
795 	close_checked(fd);
796 	consume_event(ifd, wd, IN_OPEN, 0, "fifo");
797 
798 	close_inotify(ifd);
799 }
800 
801 ATF_TC_WITH_CLEANUP(inotify_event_unmount);
ATF_TC_HEAD(inotify_event_unmount,tc)802 ATF_TC_HEAD(inotify_event_unmount, tc)
803 {
804 	atf_tc_set_md_var(tc, "require.user", "root");
805 }
ATF_TC_BODY(inotify_event_unmount,tc)806 ATF_TC_BODY(inotify_event_unmount, tc)
807 {
808 	int error, fd, ifd, wd;
809 
810 	ifd = inotify(IN_NONBLOCK);
811 
812 	error = mkdir("./root", 0755);
813 	ATF_REQUIRE(error == 0);
814 
815 	mount_tmpfs("./root");
816 
817 	error = mkdir("./root/dir", 0755);
818 	ATF_REQUIRE(error == 0);
819 	wd = inotify_add_watch(ifd, "./root/dir", IN_OPEN);
820 	ATF_REQUIRE(wd >= 0);
821 
822 	fd = open("./root/dir", O_RDONLY | O_DIRECTORY);
823 	ATF_REQUIRE(fd != -1);
824 	consume_event(ifd, wd, IN_OPEN, IN_ISDIR, NULL);
825 	close_checked(fd);
826 
827 	/* A regular unmount should fail, as inotify holds a vnode reference. */
828 	error = unmount("./root", 0);
829 	ATF_REQUIRE_ERRNO(EBUSY, error == -1);
830 	error = unmount("./root", MNT_FORCE);
831 	ATF_REQUIRE_MSG(error == 0,
832 	    "unmounting ./root failed: %s", strerror(errno));
833 
834 	consume_event(ifd, wd, 0, IN_UNMOUNT, NULL);
835 	consume_event(ifd, wd, 0, IN_IGNORED, NULL);
836 
837 	close_inotify(ifd);
838 }
ATF_TC_CLEANUP(inotify_event_unmount,tc)839 ATF_TC_CLEANUP(inotify_event_unmount, tc)
840 {
841 	(void)unmount("./root", MNT_FORCE);
842 }
843 
ATF_TP_ADD_TCS(tp)844 ATF_TP_ADD_TCS(tp)
845 {
846 	/* Tests for the inotify syscalls. */
847 	ATF_TP_ADD_TC(tp, inotify_capsicum);
848 	ATF_TP_ADD_TC(tp, inotify_coalesce);
849 	ATF_TP_ADD_TC(tp, inotify_mask_create);
850 	ATF_TP_ADD_TC(tp, inotify_nullfs);
851 	ATF_TP_ADD_TC(tp, inotify_queue_overflow);
852 	/* Tests for the various inotify event types. */
853 	ATF_TP_ADD_TC(tp, inotify_event_access_file);
854 	ATF_TP_ADD_TC(tp, inotify_event_access_dir);
855 	ATF_TP_ADD_TC(tp, inotify_event_attrib);
856 	ATF_TP_ADD_TC(tp, inotify_event_close_nowrite);
857 	ATF_TP_ADD_TC(tp, inotify_event_close_write);
858 	ATF_TP_ADD_TC(tp, inotify_event_create);
859 	ATF_TP_ADD_TC(tp, inotify_event_delete);
860 	ATF_TP_ADD_TC(tp, inotify_event_move);
861 	ATF_TP_ADD_TC(tp, inotify_event_open);
862 	ATF_TP_ADD_TC(tp, inotify_event_unmount);
863 	return (atf_no_error());
864 }
865