• 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 <fcntl.h>
38 #include <errno.h>
39 #include <string.h>
40 #include <sys/syscall.h>
41 #include <limits.h>
42 #include "tst_test.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 #define BUF_SIZE 256
59 static char fname1[BUF_SIZE], fname2[BUF_SIZE], fname3[BUF_SIZE];
60 static int fd, fd_notify, reap_wd;
61 static int wd;
62 
63 struct event_t {
64 	char name[BUF_SIZE];
65 	unsigned int mask;
66 };
67 #define FILE_NAME1 "test_file1"
68 #define FILE_NAME2 "test_file2"
69 
70 static struct event_t event_set[EVENT_MAX];
71 
72 static char event_buf[EVENT_BUF_LEN];
73 
verify_inotify(void)74 void verify_inotify(void)
75 {
76 	unsigned int stored_cookie = UINT_MAX;
77 
78 	int test_cnt = 0;
79 
80 	/*
81 	 * generate sequence of events
82 	 */
83 	SAFE_CHMOD(".", 0755);
84 	event_set[test_cnt].mask = IN_ISDIR | IN_ATTRIB;
85 	strcpy(event_set[test_cnt].name, "");
86 	test_cnt++;
87 
88 	if ((fd = creat(FILE_NAME1, 0755)) == -1) {
89 		tst_brk(TBROK | TERRNO,
90 			"creat(\"%s\", 755) failed", FILE_NAME1);
91 	}
92 
93 	event_set[test_cnt].mask = IN_CREATE;
94 	strcpy(event_set[test_cnt].name, FILE_NAME1);
95 	test_cnt++;
96 	event_set[test_cnt].mask = IN_OPEN;
97 	strcpy(event_set[test_cnt].name, FILE_NAME1);
98 	test_cnt++;
99 
100 	SAFE_CLOSE(fd);
101 	event_set[test_cnt].mask = IN_CLOSE_WRITE;
102 	strcpy(event_set[test_cnt].name, FILE_NAME1);
103 	test_cnt++;
104 
105 	SAFE_RENAME(FILE_NAME1, FILE_NAME2);
106 	event_set[test_cnt].mask = IN_MOVED_FROM;
107 	strcpy(event_set[test_cnt].name, FILE_NAME1);
108 	test_cnt++;
109 	event_set[test_cnt].mask = IN_MOVED_TO;
110 	strcpy(event_set[test_cnt].name, FILE_NAME2);
111 	test_cnt++;
112 
113 	if (getcwd(fname1, BUF_SIZE) == NULL) {
114 		tst_brk(TBROK | TERRNO,
115 			"getcwd(%p, %d) failed", fname1, BUF_SIZE);
116 	}
117 
118 	snprintf(fname2, BUF_SIZE, "%s.rename1", fname1);
119 	SAFE_RENAME(fname1, fname2);
120 	event_set[test_cnt].mask = IN_MOVE_SELF;
121 	strcpy(event_set[test_cnt].name, "");
122 	test_cnt++;
123 
124 	SAFE_UNLINK(FILE_NAME2);
125 	event_set[test_cnt].mask = IN_DELETE;
126 	strcpy(event_set[test_cnt].name, FILE_NAME2);
127 	test_cnt++;
128 
129 	/*
130 	 * test that duplicate events will be coalesced into
131 	 * a single event. This test case should be last, that
132 	 * we can correct determine kernel bug which exist before
133 	 * 2.6.25. See comment below.
134 	 */
135 	snprintf(fname3, BUF_SIZE, "%s.rename2", fname1);
136 	SAFE_RENAME(fname2, fname3);
137 
138 	SAFE_RENAME(fname3, fname1);
139 	event_set[test_cnt].mask = IN_MOVE_SELF;
140 	strcpy(event_set[test_cnt].name, "");
141 	test_cnt++;
142 
143 	int len, i = 0, test_num = 0;
144 	if ((len = read(fd_notify, event_buf, EVENT_BUF_LEN)) == -1) {
145 		tst_brk(TBROK | TERRNO,
146 			"read(%d, buf, %zu) failed",
147 			fd_notify, EVENT_BUF_LEN);
148 
149 	}
150 
151 	while (i < len) {
152 		struct inotify_event *event;
153 		event = (struct inotify_event *)&event_buf[i];
154 		if (test_num >= test_cnt) {
155 			if (tst_kvercmp(2, 6, 25) < 0
156 					&& event_set[test_cnt - 1].mask ==
157 					event->mask)
158 				tst_res(TWARN,
159 					"This may be kernel bug. "
160 					"Before kernel 2.6.25, a kernel bug "
161 					"meant that the kernel code that was "
162 					"intended to coalesce successive identical "
163 					"events (i.e., the two most recent "
164 					"events could potentially be coalesced "
165 					"if the older had not yet been read) "
166 					"instead checked if the most recent event "
167 					"could be coalesced with the oldest "
168 					"unread event. This has been fixed by commit"
169 					"1c17d18e3775485bf1e0ce79575eb637a94494a2.");
170 			tst_res(TFAIL,
171 				"get unnecessary event: "
172 				"wd=%d mask=%08x cookie=%-5u len=%-2u"
173 				"name=\"%.*s\"", event->wd, event->mask,
174 				event->cookie, event->len, event->len,
175 				event->name);
176 
177 		} else if ((event_set[test_num].mask == event->mask)
178 				&&
179 				(!strncmp
180 				 (event_set[test_num].name, event->name,
181 				  event->len))) {
182 			int fail = 0;
183 
184 			if (event->mask == IN_MOVED_FROM) {
185 				if (event->cookie == 0)
186 					fail = 1;
187 				else
188 					stored_cookie = event->cookie;
189 			} else if (event->mask == IN_MOVED_TO) {
190 				if (event->cookie != stored_cookie)
191 					fail = 1;
192 				else
193 					stored_cookie = UINT_MAX;
194 			} else {
195 				if (event->cookie != 0)
196 					fail = 1;
197 			}
198 			if (!fail) {
199 				tst_res(TPASS,
200 					"get event: wd=%d mask=%08x "
201 					"cookie=%-5u len=%-2u name=\"%.*s\"",
202 					event->wd, event->mask,
203 					event->cookie, event->len,
204 					event->len, event->name);
205 			} else {
206 				tst_res(TFAIL,
207 					"get event: wd=%d mask=%08x "
208 					"cookie=%-5u (wrong) len=%-2u "
209 					"name=\"%s\"",
210 					event->wd, event->mask,
211 					event->cookie, event->len,
212 					event->name);
213 			}
214 		} else {
215 			tst_res(TFAIL, "get event: wd=%d mask=%08x "
216 				"(expected %x) cookie=%-5u len=%-2u "
217 				"name=\"%s\" (expected \"%s\") %d",
218 				event->wd, event->mask,
219 				event_set[test_num].mask,
220 				event->cookie, event->len, event->name,
221 				event_set[test_num].name,
222 				strcmp(event_set[test_num].name,
223 					event->name));
224 		}
225 		test_num++;
226 		i += EVENT_SIZE + event->len;
227 	}
228 
229 	for (; test_num < test_cnt; test_num++) {
230 		tst_res(TFAIL, "didn't get event: mask=%08x ",
231 			event_set[test_num].mask);
232 	}
233 }
234 
setup(void)235 static void setup(void)
236 {
237 	if ((fd_notify = myinotify_init()) < 0) {
238 		if (errno == ENOSYS) {
239 			tst_brk(TCONF,
240 				"inotify is not configured in this kernel.");
241 		} else {
242 			tst_brk(TBROK | TERRNO,
243 				"inotify_init () failed");
244 		}
245 	}
246 
247 	if ((wd = myinotify_add_watch(fd_notify, ".", IN_ALL_EVENTS)) < 0) {
248 		tst_brk(TBROK | TERRNO,
249 			 "inotify_add_watch (%d, \".\", IN_ALL_EVENTS) failed",
250 			 fd_notify);
251 		reap_wd = 1;
252 	};
253 }
254 
cleanup(void)255 static void cleanup(void)
256 {
257 	if (reap_wd && myinotify_rm_watch(fd_notify, wd) < 0) {
258 		tst_res(TWARN,
259 			"inotify_rm_watch (%d, %d) failed,", fd_notify, wd);
260 
261 	}
262 
263 	if (fd_notify > 0)
264 		SAFE_CLOSE(fd_notify);
265 }
266 
267 static struct tst_test test = {
268 	.needs_tmpdir = 1,
269 	.setup = setup,
270 	.cleanup = cleanup,
271 	.test_all = verify_inotify,
272 };
273 
274 #else
275 	TST_TEST_TCONF("system doesn't have required inotify support");
276 #endif
277