blob: d7d22b223dda88eab9316f4b43967a952fdebb1d [file] [log] [blame]
Jan Karaf057c1c2013-11-20 23:43:13 +01001/*
2 * Copyright (c) 2013 SUSE. 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 Jan Kara <jack@suse.cz>
24 *
25 * DESCRIPTION
26 * Check that fanotify work for children of a directory
27 */
28#include "config.h"
29
30#include <stdio.h>
31#include <sys/stat.h>
32#include <sys/types.h>
33#include <sys/fcntl.h>
34#include <errno.h>
35#include <string.h>
36#include <sys/syscall.h>
37#include "test.h"
Jan Karaf057c1c2013-11-20 23:43:13 +010038#include "linux_syscall_numbers.h"
39#include "fanotify.h"
40#include "safe_macros.h"
41
42char *TCID = "fanotify02";
43int TST_TOTAL = 8;
44
45#if defined(HAVE_SYS_FANOTIFY_H)
46#include <sys/fanotify.h>
47
48#define EVENT_MAX 1024
49/* size of the event structure, not counting name */
50#define EVENT_SIZE (sizeof (struct fanotify_event_metadata))
51/* reasonable guess as to size of 1024 events */
52#define EVENT_BUF_LEN (EVENT_MAX * EVENT_SIZE)
53
54static void setup(void);
55static void cleanup(void);
56
57#define BUF_SIZE 256
58static char fname[BUF_SIZE];
59static char buf[BUF_SIZE];
60static int fd, fd_notify;
61
62static unsigned long long event_set[EVENT_MAX];
63
64static char event_buf[EVENT_BUF_LEN];
65
66int main(int ac, char **av)
67{
68 int lc;
Cyril Hrubis0b9589f2014-05-27 17:40:33 +020069 const char *msg;
Jan Karaf057c1c2013-11-20 23:43:13 +010070
71 if ((msg = parse_opts(ac, av, NULL, NULL)) != NULL)
72 tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg);
73
74 setup();
75
76 for (lc = 0; TEST_LOOPING(lc); lc++) {
77 int ret, len, i = 0, test_num = 0;
78
79 tst_count = 0;
80
Helge Dellerff964762014-07-29 18:10:40 +020081 if (fanotify_mark(fd_notify, FAN_MARK_ADD, FAN_ACCESS |
Jan Karaf057c1c2013-11-20 23:43:13 +010082 FAN_MODIFY | FAN_CLOSE | FAN_OPEN |
83 FAN_EVENT_ON_CHILD, AT_FDCWD, ".") < 0) {
84 tst_brkm(TBROK | TERRNO, cleanup,
85 "fanotify_mark (%d, FAN_MARK_ADD, FAN_ACCESS | "
86 "FAN_MODIFY | FAN_CLOSE | FAN_OPEN | "
87 "FAN_EVENT_ON_CHILD, AT_FDCWD, '.') failed",
88 fd_notify);
89 }
90
91 /*
92 * generate sequence of events
93 */
94 fd = SAFE_OPEN(cleanup, fname, O_RDWR | O_CREAT, 0700);
95 event_set[tst_count] = FAN_OPEN;
96 tst_count++;
97
98 SAFE_WRITE(cleanup, 1, fd, fname, strlen(fname));
99 event_set[tst_count] = FAN_MODIFY;
100 tst_count++;
101
102 SAFE_CLOSE(cleanup, fd);
103 event_set[tst_count] = FAN_CLOSE_WRITE;
104 tst_count++;
105
106 /*
107 * Get list of events so far. We get events here to avoid
108 * merging of following events with the previous ones.
109 */
110 ret = SAFE_READ(cleanup, 0, fd_notify, event_buf,
111 EVENT_BUF_LEN);
112 len = ret;
113
114 fd = SAFE_OPEN(cleanup, fname, O_RDONLY);
115 event_set[tst_count] = FAN_OPEN;
116 tst_count++;
117
118 SAFE_READ(cleanup, 0, fd, buf, BUF_SIZE);
119 event_set[tst_count] = FAN_ACCESS;
120 tst_count++;
121
122 SAFE_CLOSE(cleanup, fd);
123 event_set[tst_count] = FAN_CLOSE_NOWRITE;
124 tst_count++;
125
126 /*
127 * get next events
128 */
129 ret = SAFE_READ(cleanup, 0, fd_notify, event_buf + len,
130 EVENT_BUF_LEN - len);
131 len += ret;
132
133 /*
134 * now remove child mark
135 */
Helge Dellerff964762014-07-29 18:10:40 +0200136 if (fanotify_mark(fd_notify, FAN_MARK_REMOVE,
Jan Karaf057c1c2013-11-20 23:43:13 +0100137 FAN_EVENT_ON_CHILD, AT_FDCWD, ".") < 0) {
138 tst_brkm(TBROK | TERRNO, cleanup,
139 "fanotify_mark (%d, FAN_MARK REMOVE, "
140 "FAN_EVENT_ON_CHILD, AT_FDCWD, '.') failed",
141 fd_notify);
142 }
143
144 /*
145 * Do something to verify events didn't get generated
146 */
147 fd = SAFE_OPEN(cleanup, fname, O_RDONLY);
148
149 SAFE_CLOSE(cleanup, fd);
150
151 fd = SAFE_OPEN(cleanup, ".", O_RDONLY | O_DIRECTORY);
152 event_set[tst_count] = FAN_OPEN;
153 tst_count++;
154
155 SAFE_CLOSE(cleanup, fd);
156 event_set[tst_count] = FAN_CLOSE_NOWRITE;
157 tst_count++;
158
159 /*
160 * Check events got generated only for the directory
161 */
162 ret = SAFE_READ(cleanup, 0, fd_notify, event_buf + len,
163 EVENT_BUF_LEN - len);
164 len += ret;
165
166 if (TST_TOTAL != tst_count) {
167 tst_brkm(TBROK, cleanup,
168 "TST_TOTAL and tst_count are not equal");
169 }
170 tst_count = 0;
171
172 /*
173 * check events
174 */
175 while (i < len) {
176 struct fanotify_event_metadata *event;
177
178 event = (struct fanotify_event_metadata *)&event_buf[i];
179 if (test_num >= TST_TOTAL) {
180 tst_resm(TFAIL,
181 "get unnecessary event: mask=%llx "
182 "pid=%u fd=%u",
183 (unsigned long long)event->mask,
184 (unsigned)event->pid, event->fd);
185 } else if (!(event->mask & event_set[test_num])) {
186 tst_resm(TFAIL,
187 "get event: mask=%llx (expected %llx) "
188 "pid=%u fd=%u",
189 (unsigned long long)event->mask,
190 event_set[test_num],
191 (unsigned)event->pid, event->fd);
192 } else if (event->pid != getpid()) {
193 tst_resm(TFAIL,
194 "get event: mask=%llx pid=%u "
195 "(expected %u) fd=%u",
196 (unsigned long long)event->mask,
197 (unsigned)event->pid,
198 (unsigned)getpid(),
199 event->fd);
200 } else {
201 tst_resm(TPASS,
202 "get event: mask=%llx pid=%u fd=%u",
203 (unsigned long long)event->mask,
204 (unsigned)event->pid, event->fd);
205 }
206 event->mask &= ~event_set[test_num];
207 /* No events left in current mask? Go for next event */
208 if (event->mask == 0) {
209 i += event->event_len;
210 close(event->fd);
211 }
212 test_num++;
213 }
214 for (; test_num < TST_TOTAL; test_num++) {
215 tst_resm(TFAIL, "didn't get event: mask=%llx",
216 event_set[test_num]);
217
218 }
219 }
220
221 cleanup();
222 tst_exit();
223}
224
225static void setup(void)
226{
227 tst_sig(NOFORK, DEF_HANDLER, cleanup);
228
229 TEST_PAUSE;
230
231 tst_tmpdir();
232 sprintf(fname, "fname_%d", getpid());
233
Helge Dellerff964762014-07-29 18:10:40 +0200234 if ((fd_notify = fanotify_init(FAN_CLASS_NOTIF, O_RDONLY)) < 0) {
Jan Karaf057c1c2013-11-20 23:43:13 +0100235 if (errno == ENOSYS) {
236 tst_brkm(TCONF, cleanup,
237 "fanotify is not configured in this kernel.");
238 } else {
239 tst_brkm(TBROK | TERRNO, cleanup,
240 "fanotify_init failed");
241 }
242 }
243}
244
245static void cleanup(void)
246{
247 if (close(fd_notify) == -1)
248 tst_resm(TWARN, "close(%d) failed", fd_notify);
249
Jan Karaf057c1c2013-11-20 23:43:13 +0100250 tst_rmdir();
251}
252
253#else
254
255int main(void)
256{
257 tst_brkm(TCONF, NULL, "system doesn't have required fanotify support");
258}
259
260#endif