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