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