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 file
27 *
28 * ALGORITHM
29 *     Execute sequence file's operation and check return events
30 */
31#include "config.h"
32
33#include <stdio.h>
34#include <sys/stat.h>
35#include <sys/types.h>
36#include <fcntl.h>
37#include <errno.h>
38#include <string.h>
39#include <sys/syscall.h>
40#include "test.h"
41#include "safe_macros.h"
42#include "lapi/syscalls.h"
43#include "inotify.h"
44
45#if defined(HAVE_SYS_INOTIFY_H)
46#include <sys/inotify.h>
47
48#define EVENT_MAX 1024
49/* size of the event structure, not counting name */
50#define EVENT_SIZE  (sizeof (struct inotify_event))
51/* reasonable guess as to size of 1024 events */
52#define EVENT_BUF_LEN        (EVENT_MAX * (EVENT_SIZE + 16))
53
54char *TCID = "inotify01";
55int TST_TOTAL = 7;
56
57static void setup(void);
58static void cleanup(void);
59
60#define BUF_SIZE 256
61static char fname[BUF_SIZE];
62static char buf[BUF_SIZE];
63static int fd, fd_notify;
64static int wd, reap_wd;
65
66static int event_set[EVENT_MAX];
67
68static char event_buf[EVENT_BUF_LEN];
69
70int main(int ac, char **av)
71{
72	int lc;
73
74	tst_parse_opts(ac, av, NULL, NULL);
75
76	setup();
77
78	for (lc = 0; TEST_LOOPING(lc); lc++) {
79		tst_count = 0;
80
81		/*
82		 * generate sequence of events
83		 */
84		SAFE_CHMOD(cleanup, fname, 0755);
85		event_set[tst_count] = IN_ATTRIB;
86		tst_count++;
87
88		if ((fd = open(fname, O_RDONLY)) == -1) {
89			tst_brkm(TBROK | TERRNO, cleanup,
90				 "open(%s, O_RDWR|O_CREAT,0700) failed", fname);
91		}
92		event_set[tst_count] = IN_OPEN;
93		tst_count++;
94
95		if (read(fd, buf, BUF_SIZE) == -1) {
96			tst_brkm(TBROK | TERRNO, cleanup,
97				 "read(%d, buf, %d) failed", fd, BUF_SIZE);
98		}
99		event_set[tst_count] = IN_ACCESS;
100		tst_count++;
101
102		SAFE_CLOSE(cleanup, fd);
103		event_set[tst_count] = IN_CLOSE_NOWRITE;
104		tst_count++;
105
106		if ((fd = open(fname, O_RDWR | O_CREAT, 0700)) == -1) {
107			tst_brkm(TBROK, cleanup,
108				 "open(%s, O_RDWR|O_CREAT,0700) failed", fname);
109		}
110		event_set[tst_count] = IN_OPEN;
111		tst_count++;
112
113		if (write(fd, buf, BUF_SIZE) == -1) {
114			tst_brkm(TBROK, cleanup,
115				 "write(%d, %s, 1) failed", fd, fname);
116		}
117		event_set[tst_count] = IN_MODIFY;
118		tst_count++;
119
120		SAFE_CLOSE(cleanup, fd);
121		event_set[tst_count] = IN_CLOSE_WRITE;
122		tst_count++;
123
124		if (TST_TOTAL != tst_count) {
125			tst_brkm(TBROK, cleanup,
126				 "TST_TOTAL and tst_count are not equal");
127		}
128		tst_count = 0;
129
130		/*
131		 * get list on events
132		 */
133		int len, i = 0, test_num = 0;
134		if ((len = read(fd_notify, event_buf, EVENT_BUF_LEN)) < 0) {
135			tst_brkm(TBROK, cleanup,
136				 "read(%d, buf, %zu) failed",
137				 fd_notify, EVENT_BUF_LEN);
138
139		}
140
141		/*
142		 * check events
143		 */
144		while (i < len) {
145			struct inotify_event *event;
146			event = (struct inotify_event *)&event_buf[i];
147			if (test_num >= TST_TOTAL) {
148				tst_resm(TFAIL,
149					 "get unnecessary event: wd=%d mask=%x "
150					 "cookie=%u len=%u",
151					 event->wd, event->mask,
152					 event->cookie, event->len);
153			} else if (event_set[test_num] == event->mask) {
154				if (event->cookie != 0) {
155					tst_resm(TFAIL,
156						 "get event: wd=%d mask=%x "
157						 "cookie=%u (expected 0) len=%u",
158						 event->wd, event->mask,
159						 event->cookie, event->len);
160				} else {
161					tst_resm(TPASS, "get event: wd=%d "
162						 "mask=%x cookie=%u len=%u",
163						 event->wd, event->mask,
164						 event->cookie, event->len);
165				}
166
167			} else {
168				tst_resm(TFAIL, "get event: wd=%d mask=%x "
169					 "(expected %x) cookie=%u len=%u",
170					 event->wd, event->mask,
171					 event_set[test_num],
172					 event->cookie, event->len);
173			}
174			test_num++;
175			i += EVENT_SIZE + event->len;
176		}
177		for (; test_num < TST_TOTAL; test_num++) {
178			tst_resm(TFAIL, "didn't get event: mask=%x",
179				 event_set[test_num]);
180
181		}
182
183	}
184
185	cleanup();
186	tst_exit();
187}
188
189static void setup(void)
190{
191
192	tst_sig(NOFORK, DEF_HANDLER, cleanup);
193
194	TEST_PAUSE;
195
196	tst_tmpdir();
197
198	sprintf(fname, "tfile_%d", getpid());
199	if ((fd = open(fname, O_RDWR | O_CREAT, 0700)) == -1) {
200		tst_brkm(TBROK | TERRNO, cleanup,
201			 "open(%s, O_RDWR|O_CREAT,0700) failed", fname);
202	}
203	if ((write(fd, fname, 1)) == -1) {
204		tst_brkm(TBROK | TERRNO, cleanup, "write(%d, %s, 1) failed",
205			 fd, fname);
206	}
207
208	/* close the file we have open */
209	SAFE_CLOSE(cleanup, fd);
210	if ((fd_notify = myinotify_init()) < 0) {
211		if (errno == ENOSYS) {
212			tst_brkm(TCONF, cleanup,
213				 "inotify is not configured in this kernel.");
214		} else {
215			tst_brkm(TBROK | TERRNO, cleanup,
216				 "inotify_init failed");
217		}
218	}
219
220	if ((wd = myinotify_add_watch(fd_notify, fname, IN_ALL_EVENTS)) < 0) {
221		tst_brkm(TBROK | TERRNO, cleanup,
222			 "inotify_add_watch (%d, %s, IN_ALL_EVENTS) failed",
223			 fd_notify, fname);
224		reap_wd = 1;
225	};
226
227}
228
229static void cleanup(void)
230{
231	if (reap_wd && myinotify_rm_watch(fd_notify, wd) < 0) {
232		tst_resm(TWARN | TERRNO, "inotify_rm_watch (%d, %d) failed",
233			 fd_notify, wd);
234
235	}
236
237	if (fd_notify > 0 && close(fd_notify))
238		tst_resm(TWARN, "close(%d) failed", fd_notify);
239
240	tst_rmdir();
241}
242
243#else
244
245char *TCID = "inotify01";
246int TST_TOTAL = 0;
247
248int main(void)
249{
250	tst_brkm(TCONF, NULL, "system doesn't have required inotify support");
251}
252
253#endif
254