xref: /aosp_15_r20/external/ltp/testcases/kernel/syscalls/inotify/inotify03.c (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (c) 2008 Parallels.  All Rights Reserved.
4  * Author: Andrew Vagin <[email protected]>
5  */
6 
7 /*\
8  * [Description]
9  *
10  * Check that inotify get IN_UNMOUNT event and don't block the umount command.
11  */
12 
13 #include "config.h"
14 
15 #include <stdio.h>
16 #include <sys/mount.h>
17 #include <sys/stat.h>
18 #include <sys/types.h>
19 #include <fcntl.h>
20 #include <errno.h>
21 #include <string.h>
22 #include <sys/syscall.h>
23 #include <signal.h>
24 #include "tst_test.h"
25 #include "inotify.h"
26 
27 #if defined(HAVE_SYS_INOTIFY_H)
28 #include <sys/inotify.h>
29 
30 #define EVENT_MAX 1024
31 /* size of the event structure, not counting name */
32 #define EVENT_SIZE (sizeof(struct inotify_event))
33 /* reasonable guess as to size of 1024 events */
34 #define EVENT_BUF_LEN		(EVENT_MAX * (EVENT_SIZE + 16))
35 
36 #define BUF_SIZE 1024
37 static char fname[BUF_SIZE];
38 static int fd, fd_notify;
39 static int wd;
40 
41 static unsigned int event_set[EVENT_MAX];
42 
43 static char event_buf[EVENT_BUF_LEN];
44 
45 #define DIR_MODE	(S_IRWXU | S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP)
46 
47 static char *mntpoint = "mntpoint";
48 static int mount_flag;
49 
verify_inotify(void)50 void verify_inotify(void)
51 {
52 	int ret;
53 	int len, i, test_num;
54 
55 	int test_cnt = 0;
56 
57 	SAFE_MOUNT(tst_device->dev, mntpoint, tst_device->fs_type, 0, NULL);
58 	mount_flag = 1;
59 
60 	wd = SAFE_MYINOTIFY_ADD_WATCH(fd_notify, fname, IN_ALL_EVENTS);
61 
62 	event_set[test_cnt] = IN_UNMOUNT;
63 	test_cnt++;
64 	event_set[test_cnt] = IN_IGNORED;
65 	test_cnt++;
66 
67 	/*check exit code from inotify_rm_watch */
68 	test_cnt++;
69 
70 	tst_res(TINFO, "umount %s", tst_device->dev);
71 	TEST(tst_umount(mntpoint));
72 	if (TST_RET != 0) {
73 		tst_brk(TBROK, "umount(2) Failed "
74 			"while unmounting errno = %d : %s",
75 			TST_ERR, strerror(TST_ERR));
76 	}
77 	mount_flag = 0;
78 
79 	len = read(fd_notify, event_buf, EVENT_BUF_LEN);
80 	if (len < 0) {
81 		tst_brk(TBROK | TERRNO,
82 			"read(%d, buf, %zu) failed", fd_notify, EVENT_BUF_LEN);
83 	}
84 
85 	/* check events */
86 	test_num = 0;
87 	i = 0;
88 	while (i < len) {
89 		struct inotify_event *event;
90 		event = (struct inotify_event *)&event_buf[i];
91 		if (test_num >= (test_cnt - 1)) {
92 			tst_res(TFAIL,
93 				"get unnecessary event: wd=%d mask=%x "
94 				"cookie=%u len=%u",
95 				event->wd, event->mask,
96 				event->cookie, event->len);
97 		} else if (event_set[test_num] == event->mask) {
98 			tst_res(TPASS, "get event: wd=%d mask=%x"
99 				" cookie=%u len=%u",
100 				event->wd, event->mask,
101 				event->cookie, event->len);
102 
103 		} else {
104 			tst_res(TFAIL, "get event: wd=%d mask=%x "
105 				"(expected %x) cookie=%u len=%u",
106 				event->wd, event->mask,
107 				event_set[test_num],
108 				event->cookie, event->len);
109 		}
110 		test_num++;
111 		i += EVENT_SIZE + event->len;
112 	}
113 	for (; test_num < test_cnt - 1; test_num++) {
114 		tst_res(TFAIL, "don't get event: mask=%x ",
115 			event_set[test_num]);
116 
117 	}
118 	ret = myinotify_rm_watch(fd_notify, wd);
119 	if (ret != -1 || errno != EINVAL)
120 		tst_res(TFAIL | TERRNO,
121 			"inotify_rm_watch (%d, %d) didn't return EINVAL",
122 			fd_notify, wd);
123 	else
124 		tst_res(TPASS, "inotify_rm_watch (%d, %d) returned EINVAL",
125 			fd_notify, wd);
126 }
127 
setup(void)128 static void setup(void)
129 {
130 	int ret;
131 
132 	SAFE_MKDIR(mntpoint, DIR_MODE);
133 
134 	SAFE_MOUNT(tst_device->dev, mntpoint, tst_device->fs_type, 0, NULL);
135 	mount_flag = 1;
136 
137 	sprintf(fname, "%s/tfile_%d", mntpoint, getpid());
138 	fd = SAFE_OPEN(fname, O_RDWR | O_CREAT, 0700);
139 
140 	ret = write(fd, fname, 1);
141 	if (ret == -1) {
142 		tst_brk(TBROK | TERRNO,
143 			 "write(%d, %s, 1) failed", fd, fname);
144 	}
145 
146 	/* close the file we have open */
147 	SAFE_CLOSE(fd);
148 
149 	fd_notify = SAFE_MYINOTIFY_INIT();
150 
151 	tst_umount(mntpoint);
152 	mount_flag = 0;
153 }
154 
cleanup(void)155 static void cleanup(void)
156 {
157 	if (fd_notify > 0)
158 		SAFE_CLOSE(fd_notify);
159 
160 	if (mount_flag) {
161 		TEST(tst_umount(mntpoint));
162 		if (TST_RET != 0)
163 			tst_res(TWARN | TTERRNO, "umount(%s) failed",
164 				mntpoint);
165 	}
166 }
167 
168 static struct tst_test test = {
169 	.needs_root = 1,
170 	.format_device = 1,
171 	.setup = setup,
172 	.cleanup = cleanup,
173 	.test_all = verify_inotify,
174 };
175 
176 #else
177 	TST_TEST_TCONF("system doesn't have required inotify support");
178 #endif
179