xref: /aosp_15_r20/external/ltp/testcases/kernel/syscalls/inotify/inotify02.c (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (c) 2007 SWSoft.  All Rights Reserved.
4  * Author: Andrew Vagin <[email protected]>
5  */
6 
7 /*\
8  * [Description]
9  *
10  * Basic test for inotify events on directory.
11  */
12 
13 #include "config.h"
14 
15 #include <stdio.h>
16 #include <sys/stat.h>
17 #include <sys/types.h>
18 #include <fcntl.h>
19 #include <errno.h>
20 #include <string.h>
21 #include <sys/syscall.h>
22 #include <limits.h>
23 #include "tst_test.h"
24 #include "inotify.h"
25 
26 #if defined(HAVE_SYS_INOTIFY_H)
27 #include <sys/inotify.h>
28 
29 #ifndef IN_MOVE_SELF
30 #define IN_MOVE_SELF            0x00000800
31 #endif
32 
33 #define EVENT_MAX 1024
34 /* size of the event structure, not counting name */
35 #define EVENT_SIZE  (sizeof (struct inotify_event))
36 /* reasonable guess as to size of 1024 events */
37 #define EVENT_BUF_LEN        (EVENT_MAX * (EVENT_SIZE + 16))
38 
39 #define BUF_SIZE 256
40 static char fname1[BUF_SIZE], fname2[BUF_SIZE], fname3[BUF_SIZE];
41 static int fd, fd_notify, reap_wd;
42 static int wd;
43 
44 struct event_t {
45 	char name[BUF_SIZE];
46 	unsigned int mask;
47 };
48 #define FILE_NAME1 "test_file1"
49 #define FILE_NAME2 "test_file2"
50 
51 static struct event_t event_set[EVENT_MAX];
52 
53 static char event_buf[EVENT_BUF_LEN];
54 
verify_inotify(void)55 void verify_inotify(void)
56 {
57 	unsigned int stored_cookie = UINT_MAX;
58 
59 	int test_cnt = 0;
60 
61 	/*
62 	 * generate sequence of events
63 	 */
64 	SAFE_CHMOD(".", 0755);
65 	event_set[test_cnt].mask = IN_ISDIR | IN_ATTRIB;
66 	strcpy(event_set[test_cnt].name, "");
67 	test_cnt++;
68 
69 	if ((fd = creat(FILE_NAME1, 0755)) == -1) {
70 		tst_brk(TBROK | TERRNO,
71 			"creat(\"%s\", 755) failed", FILE_NAME1);
72 	}
73 
74 	event_set[test_cnt].mask = IN_CREATE;
75 	strcpy(event_set[test_cnt].name, FILE_NAME1);
76 	test_cnt++;
77 	event_set[test_cnt].mask = IN_OPEN;
78 	strcpy(event_set[test_cnt].name, FILE_NAME1);
79 	test_cnt++;
80 
81 	SAFE_CLOSE(fd);
82 	event_set[test_cnt].mask = IN_CLOSE_WRITE;
83 	strcpy(event_set[test_cnt].name, FILE_NAME1);
84 	test_cnt++;
85 
86 	SAFE_RENAME(FILE_NAME1, FILE_NAME2);
87 	event_set[test_cnt].mask = IN_MOVED_FROM;
88 	strcpy(event_set[test_cnt].name, FILE_NAME1);
89 	test_cnt++;
90 	event_set[test_cnt].mask = IN_MOVED_TO;
91 	strcpy(event_set[test_cnt].name, FILE_NAME2);
92 	test_cnt++;
93 
94 	if (getcwd(fname1, BUF_SIZE) == NULL) {
95 		tst_brk(TBROK | TERRNO,
96 			"getcwd(%p, %d) failed", fname1, BUF_SIZE);
97 	}
98 
99 	snprintf(fname2, BUF_SIZE, "%s.rename1", fname1);
100 	SAFE_RENAME(fname1, fname2);
101 	event_set[test_cnt].mask = IN_MOVE_SELF;
102 	strcpy(event_set[test_cnt].name, "");
103 	test_cnt++;
104 
105 	SAFE_UNLINK(FILE_NAME2);
106 	event_set[test_cnt].mask = IN_DELETE;
107 	strcpy(event_set[test_cnt].name, FILE_NAME2);
108 	test_cnt++;
109 
110 	/*
111 	 * test that duplicate events will be coalesced into
112 	 * a single event. This test case should be last, that
113 	 * we can correct determine kernel bug which exist before
114 	 * 2.6.25. See comment below.
115 	 */
116 	snprintf(fname3, BUF_SIZE, "%s.rename2", fname1);
117 	SAFE_RENAME(fname2, fname3);
118 
119 	SAFE_RENAME(fname3, fname1);
120 	event_set[test_cnt].mask = IN_MOVE_SELF;
121 	strcpy(event_set[test_cnt].name, "");
122 	test_cnt++;
123 
124 	int len, i = 0, test_num = 0;
125 	if ((len = read(fd_notify, event_buf, EVENT_BUF_LEN)) == -1) {
126 		tst_brk(TBROK | TERRNO,
127 			"read(%d, buf, %zu) failed",
128 			fd_notify, EVENT_BUF_LEN);
129 
130 	}
131 
132 	while (i < len) {
133 		struct inotify_event *event;
134 		event = (struct inotify_event *)&event_buf[i];
135 		if (test_num >= test_cnt) {
136 			tst_res(TFAIL,
137 				"get unnecessary event: "
138 				"wd=%d mask=%08x cookie=%-5u len=%-2u "
139 				"name=\"%.*s\"", event->wd, event->mask,
140 				event->cookie, event->len, event->len,
141 				event->name);
142 
143 		} else if ((event_set[test_num].mask == event->mask)
144 				&&
145 				(!strncmp
146 				 (event_set[test_num].name, event->name,
147 				  event->len))) {
148 			int fail = 0;
149 
150 			if (event->mask == IN_MOVED_FROM) {
151 				if (event->cookie == 0)
152 					fail = 1;
153 				else
154 					stored_cookie = event->cookie;
155 			} else if (event->mask == IN_MOVED_TO) {
156 				if (event->cookie != stored_cookie)
157 					fail = 1;
158 				else
159 					stored_cookie = UINT_MAX;
160 			} else {
161 				if (event->cookie != 0)
162 					fail = 1;
163 			}
164 			if (!fail) {
165 				tst_res(TPASS,
166 					"get event: wd=%d mask=%08x "
167 					"cookie=%-5u len=%-2u name=\"%.*s\"",
168 					event->wd, event->mask,
169 					event->cookie, event->len,
170 					event->len, event->name);
171 			} else {
172 				tst_res(TFAIL,
173 					"get event: wd=%d mask=%08x "
174 					"cookie=%-5u (wrong) len=%-2u "
175 					"name=\"%s\"",
176 					event->wd, event->mask,
177 					event->cookie, event->len,
178 					event->name);
179 			}
180 		} else {
181 			tst_res(TFAIL, "get event: wd=%d mask=%08x "
182 				"(expected %x) cookie=%-5u len=%-2u "
183 				"name=\"%s\" (expected \"%s\") %d",
184 				event->wd, event->mask,
185 				event_set[test_num].mask,
186 				event->cookie, event->len, event->name,
187 				event_set[test_num].name,
188 				strcmp(event_set[test_num].name,
189 					event->name));
190 		}
191 		test_num++;
192 		i += EVENT_SIZE + event->len;
193 	}
194 
195 	for (; test_num < test_cnt; test_num++) {
196 		tst_res(TFAIL, "didn't get event: mask=%08x ",
197 			event_set[test_num].mask);
198 	}
199 }
200 
setup(void)201 static void setup(void)
202 {
203 	fd_notify = SAFE_MYINOTIFY_INIT();
204 
205 	wd = SAFE_MYINOTIFY_ADD_WATCH(fd_notify, ".", IN_ALL_EVENTS);
206 	reap_wd = 1;
207 }
208 
cleanup(void)209 static void cleanup(void)
210 {
211 	if (reap_wd && myinotify_rm_watch(fd_notify, wd) < 0) {
212 		tst_res(TWARN,
213 			"inotify_rm_watch (%d, %d) failed,", fd_notify, wd);
214 	}
215 
216 	if (fd_notify > 0)
217 		SAFE_CLOSE(fd_notify);
218 }
219 
220 static struct tst_test test = {
221 	.needs_tmpdir = 1,
222 	.setup = setup,
223 	.cleanup = cleanup,
224 	.test_all = verify_inotify,
225 };
226 
227 #else
228 	TST_TEST_TCONF("system doesn't have required inotify support");
229 #endif
230