• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2007 SWSoft.  All Rights Reserved.
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms of version 2 of the GNU General Public License as
6  * published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it would be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11  *
12  * Further, this software is distributed without any warranty that it is
13  * free of the rightful claim of any third person regarding infringement
14  * or the like.  Any license provided herein, whether implied or
15  * otherwise, applies only to this software file.  Patent licenses, if
16  * any, provided herein do not apply to combinations of this program with
17  * other software, or any other product whatsoever.
18  *
19  * You should have received a copy of the GNU General Public License along
20  * with this program; if not, write the Free Software Foundation, Inc.,
21  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22  *
23  * Started by Andrew Vagin <avagin@sw.ru>
24  *
25  * DESCRIPTION
26  *     Check that inotify work for a directory
27  *
28  * ALGORITHM
29  *     Execute sequence file's operation and check return events
30  */
31 
32 #include "config.h"
33 
34 #include <stdio.h>
35 #include <sys/stat.h>
36 #include <sys/types.h>
37 #include <sys/fcntl.h>
38 #include <errno.h>
39 #include <string.h>
40 #include <sys/syscall.h>
41 #include "test.h"
42 #include "linux_syscall_numbers.h"
43 #include "inotify.h"
44 
45 #if defined(HAVE_SYS_INOTIFY_H)
46 #include <sys/inotify.h>
47 
48 #ifndef IN_MOVE_SELF
49 #define IN_MOVE_SELF            0x00000800
50 #endif
51 
52 #define EVENT_MAX 1024
53 /* size of the event structure, not counting name */
54 #define EVENT_SIZE  (sizeof (struct inotify_event))
55 /* reasonable guess as to size of 1024 events */
56 #define EVENT_BUF_LEN        (EVENT_MAX * (EVENT_SIZE + 16))
57 
58 static void setup(void);
59 static void cleanup(void);
60 
61 char *TCID = "inotify02";
62 int TST_TOTAL = 9;
63 
64 #define BUF_SIZE 256
65 static char fname1[BUF_SIZE], fname2[BUF_SIZE], fname3[BUF_SIZE];
66 static int fd, fd_notify, reap_wd;
67 static int wd;
68 
69 struct event_t {
70 	char name[BUF_SIZE];
71 	unsigned int mask;
72 };
73 #define FILE_NAME1 "test_file1"
74 #define FILE_NAME2 "test_file2"
75 
76 static struct event_t event_set[EVENT_MAX];
77 
78 static char event_buf[EVENT_BUF_LEN];
79 
main(int ac,char ** av)80 int main(int ac, char **av)
81 {
82 	int lc;
83 	unsigned int stored_cookie = UINT_MAX;
84 
85 	tst_parse_opts(ac, av, NULL, NULL);
86 
87 	setup();
88 
89 	for (lc = 0; TEST_LOOPING(lc); lc++) {
90 
91 		tst_count = 0;
92 
93 		/*
94 		 * generate sequence of events
95 		 */
96 		if (chmod(".", 0755) < 0) {
97 			tst_brkm(TBROK | TERRNO, cleanup,
98 				 "chmod(\".\", 0755) failed");
99 		}
100 		event_set[tst_count].mask = IN_ISDIR | IN_ATTRIB;
101 		strcpy(event_set[tst_count].name, "");
102 		tst_count++;
103 
104 		if ((fd = creat(FILE_NAME1, 0755)) == -1) {
105 			tst_brkm(TBROK | TERRNO, cleanup,
106 				 "creat(\"%s\", 755) failed", FILE_NAME1);
107 		}
108 
109 		event_set[tst_count].mask = IN_CREATE;
110 		strcpy(event_set[tst_count].name, FILE_NAME1);
111 		tst_count++;
112 		event_set[tst_count].mask = IN_OPEN;
113 		strcpy(event_set[tst_count].name, FILE_NAME1);
114 		tst_count++;
115 
116 		if (close(fd) == -1) {
117 			tst_brkm(TBROK | TERRNO, cleanup,
118 				 "close(%s) failed", FILE_NAME1);
119 		}
120 		event_set[tst_count].mask = IN_CLOSE_WRITE;
121 		strcpy(event_set[tst_count].name, FILE_NAME1);
122 		tst_count++;
123 
124 		if (rename(FILE_NAME1, FILE_NAME2) == -1) {
125 			tst_brkm(TBROK | TERRNO, cleanup,
126 				 "rename(%s, %s) failed",
127 				 FILE_NAME1, FILE_NAME2);
128 		}
129 		event_set[tst_count].mask = IN_MOVED_FROM;
130 		strcpy(event_set[tst_count].name, FILE_NAME1);
131 		tst_count++;
132 		event_set[tst_count].mask = IN_MOVED_TO;
133 		strcpy(event_set[tst_count].name, FILE_NAME2);
134 		tst_count++;
135 
136 		if (getcwd(fname1, BUF_SIZE) == NULL) {
137 			tst_brkm(TBROK | TERRNO, cleanup,
138 				 "getcwd(%p, %d) failed", fname1, BUF_SIZE);
139 		}
140 
141 		snprintf(fname2, BUF_SIZE, "%s.rename1", fname1);
142 		if (rename(fname1, fname2) == -1) {
143 			tst_brkm(TBROK | TERRNO, cleanup,
144 				 "rename(%s, %s) failed", fname1, fname2);
145 		}
146 		event_set[tst_count].mask = IN_MOVE_SELF;
147 		strcpy(event_set[tst_count].name, "");
148 		tst_count++;
149 
150 		if (unlink(FILE_NAME2) == -1) {
151 			tst_brkm(TBROK | TERRNO, cleanup,
152 				 "unlink(%s) failed", FILE_NAME2);
153 		}
154 		event_set[tst_count].mask = IN_DELETE;
155 		strcpy(event_set[tst_count].name, FILE_NAME2);
156 		tst_count++;
157 
158 		/*
159 		 * test that duplicate events will be coalesced into
160 		 * a single event. This test case should be last, that
161 		 * we can correct determine kernel bug which exist before
162 		 * 2.6.25. See comment below.
163 		 */
164 		snprintf(fname3, BUF_SIZE, "%s.rename2", fname1);
165 		if (rename(fname2, fname3) == -1) {
166 			tst_brkm(TBROK | TERRNO, cleanup,
167 				 "rename(%s, %s) failed", fname2, fname3);
168 		}
169 
170 		if (rename(fname3, fname1) == -1) {
171 			tst_brkm(TBROK | TERRNO, cleanup,
172 				 "rename(%s, %s) failed", fname3, fname1);
173 		}
174 		event_set[tst_count].mask = IN_MOVE_SELF;
175 		strcpy(event_set[tst_count].name, "");
176 		tst_count++;
177 
178 		if (tst_count != TST_TOTAL) {
179 			tst_brkm(TBROK, cleanup,
180 				 "tst_count and TST_TOTAL are not equal");
181 		}
182 
183 		tst_count = 0;
184 
185 		int len, i = 0, test_num = 0;
186 		if ((len = read(fd_notify, event_buf, EVENT_BUF_LEN)) == -1) {
187 			tst_brkm(TBROK | TERRNO, cleanup,
188 				 "read(%d, buf, %zu) failed",
189 				 fd_notify, EVENT_BUF_LEN);
190 
191 		}
192 
193 		while (i < len) {
194 			struct inotify_event *event;
195 			event = (struct inotify_event *)&event_buf[i];
196 			if (test_num >= TST_TOTAL) {
197 				if (tst_kvercmp(2, 6, 25) < 0
198 				    && event_set[TST_TOTAL - 1].mask ==
199 				    event->mask)
200 					tst_resm(TWARN,
201 						 "This may be kernel bug. "
202 						 "Before kernel 2.6.25, a kernel bug "
203 						 "meant that the kernel code that was "
204 						 "intended to coalesce successive identical "
205 						 "events (i.e., the two most recent "
206 						 "events could potentially be coalesced "
207 						 "if the older had not yet been read) "
208 						 "instead checked if the most recent event "
209 						 "could be coalesced with the oldest "
210 						 "unread event. This has been fixed by commit"
211 						 "1c17d18e3775485bf1e0ce79575eb637a94494a2.");
212 				tst_resm(TFAIL,
213 					 "get unnecessary event: "
214 					 "wd=%d mask=%x cookie=%u len=%u"
215 					 "name=\"%.*s\"", event->wd, event->mask,
216 					 event->cookie, event->len, event->len,
217 					 event->name);
218 
219 			} else if ((event_set[test_num].mask == event->mask)
220 				   &&
221 				   (!strncmp
222 				    (event_set[test_num].name, event->name,
223 				     event->len))) {
224 				int fail = 0;
225 
226 				if (event->mask == IN_MOVED_FROM) {
227 					if (event->cookie == 0)
228 						fail = 1;
229 					else
230 						stored_cookie = event->cookie;
231 				} else if (event->mask == IN_MOVED_TO) {
232 					if (event->cookie != stored_cookie)
233 						fail = 1;
234 					else
235 						stored_cookie = UINT_MAX;
236 				} else {
237 					if (event->cookie != 0)
238 						fail = 1;
239 				}
240 				if (!fail) {
241 					tst_resm(TPASS,
242 						 "get event: wd=%d mask=%x "
243 						 "cookie=%u len=%u name=\"%.*s\"",
244 						 event->wd, event->mask,
245 						 event->cookie, event->len,
246 						 event->len, event->name);
247 				} else {
248 					tst_resm(TFAIL,
249 						 "get event: wd=%d mask=%x "
250 						 "cookie=%u (wrong) len=%u "
251 						 "name=\"%s\"",
252 						 event->wd, event->mask,
253 						 event->cookie, event->len,
254 						 event->name);
255 				}
256 			} else {
257 				tst_resm(TFAIL, "get event: wd=%d mask=%x "
258 					 "(expected %x) cookie=%u len=%u "
259 					 "name=\"%s\" (expected \"%s\") %d",
260 					 event->wd, event->mask,
261 					 event_set[test_num].mask,
262 					 event->cookie, event->len, event->name,
263 					 event_set[test_num].name,
264 					 strcmp(event_set[test_num].name,
265 						event->name));
266 			}
267 			test_num++;
268 			i += EVENT_SIZE + event->len;
269 		}
270 
271 		for (; test_num < TST_TOTAL; test_num++) {
272 			tst_resm(TFAIL, "didn't get event: mask=%x ",
273 				 event_set[test_num].mask);
274 		}
275 	}
276 
277 	cleanup();
278 	tst_exit();
279 }
280 
setup(void)281 static void setup(void)
282 {
283 
284 	tst_sig(NOFORK, DEF_HANDLER, cleanup);
285 
286 	TEST_PAUSE;
287 
288 	tst_tmpdir();
289 
290 	if ((fd_notify = myinotify_init()) < 0) {
291 		if (errno == ENOSYS) {
292 			tst_brkm(TCONF, cleanup,
293 				 "inotify is not configured in this kernel.");
294 		} else {
295 			tst_brkm(TBROK | TERRNO, cleanup,
296 				 "inotify_init () failed");
297 		}
298 	}
299 
300 	if ((wd = myinotify_add_watch(fd_notify, ".", IN_ALL_EVENTS)) < 0) {
301 		tst_brkm(TBROK | TERRNO, cleanup,
302 			 "inotify_add_watch (%d, \".\", IN_ALL_EVENTS) failed",
303 			 fd_notify);
304 		reap_wd = 1;
305 	};
306 
307 }
308 
cleanup(void)309 static void cleanup(void)
310 {
311 	if (reap_wd && myinotify_rm_watch(fd_notify, wd) < 0) {
312 		tst_resm(TWARN,
313 			 "inotify_rm_watch (%d, %d) failed,", fd_notify, wd);
314 
315 	}
316 
317 	if (fd_notify > 0 && close(fd_notify))
318 		tst_resm(TWARN, "close(%d) failed", fd_notify);
319 
320 	tst_rmdir();
321 }
322 
323 #else
324 
325 char *TCID = "inotify02";
326 int TST_TOTAL = 0;
327 
main(void)328 int main(void)
329 {
330 	tst_brkm(TCONF, NULL, "system doesn't have required inotify support");
331 }
332 
333 #endif
334