1 /*
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 #define _GNU_SOURCE
29 #include "config.h"
30
31 #include <stdio.h>
32 #include <sys/stat.h>
33 #include <sys/types.h>
34 #include <sys/fcntl.h>
35 #include <errno.h>
36 #include <string.h>
37 #include <sys/syscall.h>
38 #include "test.h"
39 #include "linux_syscall_numbers.h"
40 #include "fanotify.h"
41 #include "safe_macros.h"
42
43 char *TCID = "fanotify02";
44 int TST_TOTAL = 8;
45
46 #if defined(HAVE_SYS_FANOTIFY_H)
47 #include <sys/fanotify.h>
48
49 #define EVENT_MAX 1024
50 /* size of the event structure, not counting name */
51 #define EVENT_SIZE (sizeof (struct fanotify_event_metadata))
52 /* reasonable guess as to size of 1024 events */
53 #define EVENT_BUF_LEN (EVENT_MAX * EVENT_SIZE)
54
55 static void setup(void);
56 static void cleanup(void);
57
58 #define BUF_SIZE 256
59 static char fname[BUF_SIZE];
60 static char buf[BUF_SIZE];
61 static int fd, fd_notify;
62
63 static unsigned long long event_set[EVENT_MAX];
64
65 static char event_buf[EVENT_BUF_LEN];
66
main(int ac,char ** av)67 int main(int ac, char **av)
68 {
69 int lc;
70
71 tst_parse_opts(ac, av, NULL, NULL);
72
73 setup();
74
75 for (lc = 0; TEST_LOOPING(lc); lc++) {
76 int ret, len, i = 0, test_num = 0;
77
78 tst_count = 0;
79
80 if (fanotify_mark(fd_notify, FAN_MARK_ADD, FAN_ACCESS |
81 FAN_MODIFY | FAN_CLOSE | FAN_OPEN |
82 FAN_EVENT_ON_CHILD | FAN_ONDIR, AT_FDCWD,
83 ".") < 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 | FAN_ONDIR, AT_FDCWD, '.') "
88 "failed", 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 */
136 if (fanotify_mark(fd_notify, FAN_MARK_REMOVE,
137 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
setup(void)225 static 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
234 if ((fd_notify = fanotify_init(FAN_CLASS_NOTIF, O_RDONLY)) < 0) {
235 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
cleanup(void)245 static void cleanup(void)
246 {
247 if (fd_notify > 0 && close(fd_notify))
248 tst_resm(TWARN | TERRNO, "close(%d) failed", fd_notify);
249
250 tst_rmdir();
251 }
252
253 #else
254
main(void)255 int main(void)
256 {
257 tst_brkm(TCONF, NULL, "system doesn't have required fanotify support");
258 }
259
260 #endif
261