• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (c) 2007 SWSoft.  All Rights Reserved.
4  * Author: Andrew Vagin <avagin@sw.ru>
5  *
6  * DESCRIPTION
7  *     Check that inotify work for a directory
8  *
9  * ALGORITHM
10  *     Execute sequence file's operation and check return events
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 			if (tst_kvercmp(2, 6, 25) < 0
137 					&& event_set[test_cnt - 1].mask ==
138 					event->mask)
139 				tst_res(TWARN,
140 					"This may be kernel bug. "
141 					"Before kernel 2.6.25, a kernel bug "
142 					"meant that the kernel code that was "
143 					"intended to coalesce successive identical "
144 					"events (i.e., the two most recent "
145 					"events could potentially be coalesced "
146 					"if the older had not yet been read) "
147 					"instead checked if the most recent event "
148 					"could be coalesced with the oldest "
149 					"unread event. This has been fixed by commit"
150 					"1c17d18e3775485bf1e0ce79575eb637a94494a2.");
151 			tst_res(TFAIL,
152 				"get unnecessary event: "
153 				"wd=%d mask=%08x cookie=%-5u len=%-2u "
154 				"name=\"%.*s\"", event->wd, event->mask,
155 				event->cookie, event->len, event->len,
156 				event->name);
157 
158 		} else if ((event_set[test_num].mask == event->mask)
159 				&&
160 				(!strncmp
161 				 (event_set[test_num].name, event->name,
162 				  event->len))) {
163 			int fail = 0;
164 
165 			if (event->mask == IN_MOVED_FROM) {
166 				if (event->cookie == 0)
167 					fail = 1;
168 				else
169 					stored_cookie = event->cookie;
170 			} else if (event->mask == IN_MOVED_TO) {
171 				if (event->cookie != stored_cookie)
172 					fail = 1;
173 				else
174 					stored_cookie = UINT_MAX;
175 			} else {
176 				if (event->cookie != 0)
177 					fail = 1;
178 			}
179 			if (!fail) {
180 				tst_res(TPASS,
181 					"get event: wd=%d mask=%08x "
182 					"cookie=%-5u len=%-2u name=\"%.*s\"",
183 					event->wd, event->mask,
184 					event->cookie, event->len,
185 					event->len, event->name);
186 			} else {
187 				tst_res(TFAIL,
188 					"get event: wd=%d mask=%08x "
189 					"cookie=%-5u (wrong) len=%-2u "
190 					"name=\"%s\"",
191 					event->wd, event->mask,
192 					event->cookie, event->len,
193 					event->name);
194 			}
195 		} else {
196 			tst_res(TFAIL, "get event: wd=%d mask=%08x "
197 				"(expected %x) cookie=%-5u len=%-2u "
198 				"name=\"%s\" (expected \"%s\") %d",
199 				event->wd, event->mask,
200 				event_set[test_num].mask,
201 				event->cookie, event->len, event->name,
202 				event_set[test_num].name,
203 				strcmp(event_set[test_num].name,
204 					event->name));
205 		}
206 		test_num++;
207 		i += EVENT_SIZE + event->len;
208 	}
209 
210 	for (; test_num < test_cnt; test_num++) {
211 		tst_res(TFAIL, "didn't get event: mask=%08x ",
212 			event_set[test_num].mask);
213 	}
214 }
215 
setup(void)216 static void setup(void)
217 {
218 	fd_notify = SAFE_MYINOTIFY_INIT();
219 
220 	wd = SAFE_MYINOTIFY_ADD_WATCH(fd_notify, ".", IN_ALL_EVENTS);
221 	reap_wd = 1;
222 }
223 
cleanup(void)224 static void cleanup(void)
225 {
226 	if (reap_wd && myinotify_rm_watch(fd_notify, wd) < 0) {
227 		tst_res(TWARN,
228 			"inotify_rm_watch (%d, %d) failed,", fd_notify, wd);
229 	}
230 
231 	if (fd_notify > 0)
232 		SAFE_CLOSE(fd_notify);
233 }
234 
235 static struct tst_test test = {
236 	.needs_tmpdir = 1,
237 	.setup = setup,
238 	.cleanup = cleanup,
239 	.test_all = verify_inotify,
240 };
241 
242 #else
243 	TST_TEST_TCONF("system doesn't have required inotify support");
244 #endif
245