1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (c) 2020 CTERA Networks. All Rights Reserved.
4 *
5 * Started by Amir Goldstein <amir73il@gmail.com>
6 */
7
8 /*\
9 * [Description]
10 * Check fanotify directory entry modification events, events on child and
11 * on self with group init flags:
12 *
13 * - FAN_REPORT_DFID_NAME (dir fid + name)
14 * - FAN_REPORT_DIR_FID (dir fid)
15 * - FAN_REPORT_DIR_FID | FAN_REPORT_FID (dir fid + child fid)
16 * - FAN_REPORT_DFID_NAME | FAN_REPORT_FID (dir fid + name + child fid)
17 */
18
19 #define _GNU_SOURCE
20 #include "config.h"
21
22 #include <stdio.h>
23 #include <sys/stat.h>
24 #include <sys/types.h>
25 #include <errno.h>
26 #include <string.h>
27 #include <sys/mount.h>
28 #include <sys/syscall.h>
29 #include "tst_test.h"
30
31 #ifdef HAVE_SYS_FANOTIFY_H
32 #include "fanotify.h"
33
34 #define EVENT_MAX 20
35
36 /* Size of the event structure, not including file handle */
37 #define EVENT_SIZE (sizeof(struct fanotify_event_metadata) + \
38 sizeof(struct fanotify_event_info_fid))
39 /* Tripple events buffer size to account for file handles and names */
40 #define EVENT_BUF_LEN (EVENT_MAX * EVENT_SIZE * 3)
41
42
43 #define BUF_SIZE 256
44
45 #ifdef HAVE_NAME_TO_HANDLE_AT
46 struct event_t {
47 unsigned long long mask;
48 struct fanotify_fid_t *fid;
49 struct fanotify_fid_t *child_fid;
50 char name[BUF_SIZE];
51 };
52
53 static char fname1[BUF_SIZE + 11], fname2[BUF_SIZE + 11];
54 static char dname1[BUF_SIZE], dname2[BUF_SIZE];
55 static int fd_notify;
56
57 static struct event_t event_set[EVENT_MAX];
58
59 static char event_buf[EVENT_BUF_LEN];
60
61 #define DIR_NAME1 "test_dir1"
62 #define DIR_NAME2 "test_dir2"
63 #define FILE_NAME1 "test_file1"
64 #define FILE_NAME2 "test_file2"
65 #define MOUNT_PATH "fs_mnt"
66
67 static struct test_case_t {
68 const char *tname;
69 struct fanotify_group_type group;
70 struct fanotify_mark_type mark;
71 unsigned long mask;
72 struct fanotify_mark_type sub_mark;
73 unsigned long sub_mask;
74 } test_cases[] = {
75 {
76 "FAN_REPORT_DFID_NAME monitor filesystem for create/delete/move/open/close",
77 INIT_FANOTIFY_GROUP_TYPE(REPORT_DFID_NAME),
78 INIT_FANOTIFY_MARK_TYPE(FILESYSTEM),
79 FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR,
80 /* Mount watch for events possible on children */
81 INIT_FANOTIFY_MARK_TYPE(MOUNT),
82 FAN_OPEN | FAN_CLOSE | FAN_ONDIR,
83 },
84 {
85 "FAN_REPORT_DFID_NAME monitor directories for create/delete/move/open/close",
86 INIT_FANOTIFY_GROUP_TYPE(REPORT_DFID_NAME),
87 INIT_FANOTIFY_MARK_TYPE(INODE),
88 FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_ONDIR,
89 /* Watches for self events on subdir and events on subdir's children */
90 INIT_FANOTIFY_MARK_TYPE(INODE),
91 FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR |
92 FAN_OPEN | FAN_CLOSE | FAN_EVENT_ON_CHILD,
93 },
94 {
95 "FAN_REPORT_DIR_FID monitor filesystem for create/delete/move/open/close",
96 INIT_FANOTIFY_GROUP_TYPE(REPORT_DIR_FID),
97 INIT_FANOTIFY_MARK_TYPE(FILESYSTEM),
98 FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR,
99 /* Mount watch for events possible on children */
100 INIT_FANOTIFY_MARK_TYPE(MOUNT),
101 FAN_OPEN | FAN_CLOSE | FAN_ONDIR,
102 },
103 {
104 "FAN_REPORT_DIR_FID monitor directories for create/delete/move/open/close",
105 INIT_FANOTIFY_GROUP_TYPE(REPORT_DIR_FID),
106 INIT_FANOTIFY_MARK_TYPE(INODE),
107 FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_ONDIR,
108 /* Watches for self events on subdir and events on subdir's children */
109 INIT_FANOTIFY_MARK_TYPE(INODE),
110 FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR |
111 FAN_OPEN | FAN_CLOSE | FAN_EVENT_ON_CHILD,
112 },
113 {
114 "FAN_REPORT_DFID_FID monitor filesystem for create/delete/move/open/close",
115 INIT_FANOTIFY_GROUP_TYPE(REPORT_DFID_FID),
116 INIT_FANOTIFY_MARK_TYPE(FILESYSTEM),
117 FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR,
118 /* Mount watch for events possible on children */
119 INIT_FANOTIFY_MARK_TYPE(MOUNT),
120 FAN_OPEN | FAN_CLOSE | FAN_ONDIR,
121 },
122 {
123 "FAN_REPORT_DFID_FID monitor directories for create/delete/move/open/close",
124 INIT_FANOTIFY_GROUP_TYPE(REPORT_DFID_FID),
125 INIT_FANOTIFY_MARK_TYPE(INODE),
126 FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_ONDIR,
127 /* Watches for self events on subdir and events on subdir's children */
128 INIT_FANOTIFY_MARK_TYPE(INODE),
129 FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR |
130 FAN_OPEN | FAN_CLOSE | FAN_EVENT_ON_CHILD,
131 },
132 {
133 "FAN_REPORT_DFID_NAME_FID monitor filesystem for create/delete/move/open/close",
134 INIT_FANOTIFY_GROUP_TYPE(REPORT_DFID_NAME_FID),
135 INIT_FANOTIFY_MARK_TYPE(FILESYSTEM),
136 FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR,
137 /* Mount watch for events possible on children */
138 INIT_FANOTIFY_MARK_TYPE(MOUNT),
139 FAN_OPEN | FAN_CLOSE | FAN_ONDIR,
140 },
141 {
142 "FAN_REPORT_DFID_NAME_FID monitor directories for create/delete/move/open/close",
143 INIT_FANOTIFY_GROUP_TYPE(REPORT_DFID_NAME_FID),
144 INIT_FANOTIFY_MARK_TYPE(INODE),
145 FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_ONDIR,
146 /* Watches for self events on subdir and events on subdir's children */
147 INIT_FANOTIFY_MARK_TYPE(INODE),
148 FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR |
149 FAN_OPEN | FAN_CLOSE | FAN_EVENT_ON_CHILD,
150 },
151 };
152
do_test(unsigned int number)153 static void do_test(unsigned int number)
154 {
155 int fd, dirfd, len = 0, i = 0, test_num = 0, tst_count = 0;
156 struct test_case_t *tc = &test_cases[number];
157 struct fanotify_group_type *group = &tc->group;
158 struct fanotify_mark_type *mark = &tc->mark;
159 struct fanotify_mark_type *sub_mark = &tc->sub_mark;
160 struct fanotify_fid_t root_fid, dir_fid, file_fid;
161
162 tst_res(TINFO, "Test #%d: %s", number, tc->tname);
163
164 fd_notify = SAFE_FANOTIFY_INIT(group->flag, 0);
165
166 /*
167 * Watch dir modify events with name in filesystem/dir
168 */
169 SAFE_FANOTIFY_MARK(fd_notify, FAN_MARK_ADD | mark->flag, tc->mask,
170 AT_FDCWD, MOUNT_PATH);
171
172 /* Save the mount root fid */
173 fanotify_save_fid(MOUNT_PATH, &root_fid);
174
175 /*
176 * Create subdir and watch open events "on children" with name.
177 * Make it a mount root.
178 */
179 SAFE_MKDIR(dname1, 0755);
180 SAFE_MOUNT(dname1, dname1, "none", MS_BIND, NULL);
181
182 /* Save the subdir fid */
183 fanotify_save_fid(dname1, &dir_fid);
184
185 if (tc->sub_mask)
186 SAFE_FANOTIFY_MARK(fd_notify, FAN_MARK_ADD | sub_mark->flag,
187 tc->sub_mask, AT_FDCWD, dname1);
188
189 event_set[tst_count].mask = FAN_CREATE | FAN_ONDIR;
190 event_set[tst_count].fid = &root_fid;
191 event_set[tst_count].child_fid = NULL;
192 strcpy(event_set[tst_count].name, DIR_NAME1);
193 tst_count++;
194
195 /* Generate modify events "on child" */
196 fd = SAFE_CREAT(fname1, 0755);
197
198 /* Save the file fid */
199 fanotify_save_fid(fname1, &file_fid);
200
201 SAFE_WRITE(1, fd, "1", 1);
202 SAFE_RENAME(fname1, fname2);
203
204 SAFE_CLOSE(fd);
205
206 /* Generate delete events with fname2 */
207 SAFE_UNLINK(fname2);
208
209 /* Read events on files in subdir */
210 len += SAFE_READ(0, fd_notify, event_buf + len, EVENT_BUF_LEN - len);
211
212 /*
213 * FAN_CREATE|FAN_DELETE|FAN_MOVE events with the same name are merged.
214 */
215 event_set[tst_count].mask = FAN_CREATE | FAN_MOVED_FROM;
216 event_set[tst_count].fid = &dir_fid;
217 event_set[tst_count].child_fid = NULL;
218 strcpy(event_set[tst_count].name, FILE_NAME1);
219 tst_count++;
220 /*
221 * Event on non-dir child with the same name may be merged with the
222 * directory entry modification events above, unless FAN_REPORT_FID is
223 * set and child fid is reported. If FAN_REPORT_FID is set but
224 * FAN_REPORT_NAME is not set, then FAN_CREATE above is merged with
225 * FAN_DELETE below and FAN_OPEN will be merged with FAN_CLOSE.
226 */
227 if (group->flag & FAN_REPORT_NAME) {
228 event_set[tst_count].mask = FAN_OPEN;
229 event_set[tst_count].fid = &dir_fid;
230 event_set[tst_count].child_fid = &file_fid;
231 strcpy(event_set[tst_count].name, FILE_NAME1);
232 tst_count++;
233 }
234
235 event_set[tst_count].mask = FAN_DELETE | FAN_MOVED_TO;
236 event_set[tst_count].fid = &dir_fid;
237 event_set[tst_count].child_fid = NULL;
238 strcpy(event_set[tst_count].name, FILE_NAME2);
239 tst_count++;
240 /*
241 * When not reporting name, open of FILE_NAME1 is merged
242 * with close of FILE_NAME2.
243 */
244 if (!(group->flag & FAN_REPORT_NAME)) {
245 event_set[tst_count].mask = FAN_OPEN | FAN_CLOSE_WRITE;
246 event_set[tst_count].fid = &dir_fid;
247 event_set[tst_count].child_fid = &file_fid;
248 strcpy(event_set[tst_count].name, "");
249 tst_count++;
250 }
251 /*
252 * Directory watch does not get self events on children.
253 * Filesystem watch gets self event w/o name info if FAN_REPORT_FID
254 * is set.
255 */
256 if (mark->flag == FAN_MARK_FILESYSTEM && (group->flag & FAN_REPORT_FID)) {
257 event_set[tst_count].mask = FAN_DELETE_SELF | FAN_MOVE_SELF;
258 event_set[tst_count].fid = &file_fid;
259 event_set[tst_count].child_fid = NULL;
260 strcpy(event_set[tst_count].name, "");
261 tst_count++;
262 }
263 /*
264 * When reporting name, close of FILE_NAME2 is not merged with
265 * open of FILE_NAME1 and it is received after the merged self
266 * events.
267 */
268 if (group->flag & FAN_REPORT_NAME) {
269 event_set[tst_count].mask = FAN_CLOSE_WRITE;
270 event_set[tst_count].fid = &dir_fid;
271 event_set[tst_count].child_fid = &file_fid;
272 strcpy(event_set[tst_count].name, FILE_NAME2);
273 tst_count++;
274 }
275
276 dirfd = SAFE_OPEN(dname1, O_RDONLY | O_DIRECTORY);
277 SAFE_CLOSE(dirfd);
278
279 SAFE_UMOUNT(dname1);
280
281 /*
282 * Directory watch gets open/close events on itself and on its subdirs.
283 * Filesystem watch gets open/close event on all directories with name ".".
284 */
285 event_set[tst_count].mask = FAN_OPEN | FAN_CLOSE_NOWRITE | FAN_ONDIR;
286 event_set[tst_count].fid = &dir_fid;
287 event_set[tst_count].child_fid = NULL;
288 strcpy(event_set[tst_count].name, ".");
289 tst_count++;
290 /*
291 * Directory watch gets self event on itself and filesystem watch gets
292 * self event on all directories with name ".".
293 */
294 event_set[tst_count].mask = FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR;
295 event_set[tst_count].fid = &dir_fid;
296 event_set[tst_count].child_fid = NULL;
297 strcpy(event_set[tst_count].name, ".");
298 tst_count++;
299
300 SAFE_RENAME(dname1, dname2);
301 SAFE_RMDIR(dname2);
302
303 /* Read more events on dirs */
304 len += SAFE_READ(0, fd_notify, event_buf + len, EVENT_BUF_LEN - len);
305
306 event_set[tst_count].mask = FAN_MOVED_FROM | FAN_ONDIR;
307 event_set[tst_count].fid = &root_fid;
308 event_set[tst_count].child_fid = NULL;
309 strcpy(event_set[tst_count].name, DIR_NAME1);
310 tst_count++;
311 event_set[tst_count].mask = FAN_DELETE | FAN_MOVED_TO | FAN_ONDIR;
312 event_set[tst_count].fid = &root_fid;
313 event_set[tst_count].child_fid = NULL;
314 strcpy(event_set[tst_count].name, DIR_NAME2);
315 tst_count++;
316 /* Expect no more events */
317 event_set[tst_count].mask = 0;
318
319 /*
320 * Cleanup the marks
321 */
322 SAFE_CLOSE(fd_notify);
323 fd_notify = -1;
324
325 while (i < len) {
326 struct event_t *expected = &event_set[test_num];
327 struct fanotify_event_metadata *event;
328 struct fanotify_event_info_fid *event_fid;
329 struct fanotify_event_info_fid *child_fid;
330 struct fanotify_fid_t *expected_fid = expected->fid;
331 struct fanotify_fid_t *expected_child_fid = expected->child_fid;
332 struct file_handle *file_handle;
333 unsigned int fhlen;
334 const char *filename;
335 int namelen, info_type, mask_match, info_id = 0;
336
337 event = (struct fanotify_event_metadata *)&event_buf[i];
338 event_fid = (struct fanotify_event_info_fid *)(event + 1);
339 file_handle = (struct file_handle *)event_fid->handle;
340 fhlen = file_handle->handle_bytes;
341 filename = (char *)file_handle->f_handle + fhlen;
342 child_fid = (void *)((char *)event_fid + event_fid->hdr.len);
343 namelen = (char *)child_fid - (char *)filename;
344 /* End of event_fid could have name, zero padding, both or none */
345 if (namelen > 0) {
346 namelen = strlen(filename);
347 } else {
348 filename = "";
349 namelen = 0;
350 }
351 /* Is there a child fid after first fid record? */
352 if (((char *)child_fid - (char *)event) >= event->event_len)
353 child_fid = NULL;
354
355 if (!(group->flag & FAN_REPORT_FID))
356 expected_child_fid = NULL;
357
358 if (!(group->flag & FAN_REPORT_NAME))
359 expected->name[0] = 0;
360
361 if (expected->name[0]) {
362 info_type = FAN_EVENT_INFO_TYPE_DFID_NAME;
363 } else if (expected->mask & FAN_ONDIR) {
364 info_type = FAN_EVENT_INFO_TYPE_DFID;
365 } else if (expected->mask & (FAN_DELETE_SELF | FAN_MOVE_SELF)) {
366 /* Self event on non-dir has only child fid */
367 info_type = FAN_EVENT_INFO_TYPE_FID;
368 } else {
369 info_type = FAN_EVENT_INFO_TYPE_DFID;
370 }
371
372 /*
373 * Event may contain more than the expected mask, but it must
374 * have all the bits in expected mask.
375 * Expected event on dir must not get event on non dir and the
376 * other way around.
377 */
378 mask_match = ((event->mask & expected->mask) &&
379 !(expected->mask & ~event->mask) &&
380 !((event->mask ^ expected->mask) & FAN_ONDIR));
381
382 check_match:
383 if (test_num >= tst_count) {
384 tst_res(TFAIL,
385 "got unnecessary event: mask=%llx "
386 "pid=%u fd=%d name='%s' "
387 "len=%d info_type=%d info_len=%d fh_len=%d",
388 (unsigned long long)event->mask,
389 (unsigned)event->pid, event->fd, filename,
390 event->event_len, event_fid->hdr.info_type,
391 event_fid->hdr.len, fhlen);
392 } else if (!fhlen || namelen < 0) {
393 tst_res(TFAIL,
394 "got event without fid: mask=%llx pid=%u fd=%d, "
395 "len=%d info_type=%d info_len=%d fh_len=%d",
396 (unsigned long long)event->mask,
397 (unsigned)event->pid, event->fd,
398 event->event_len, event_fid->hdr.info_type,
399 event_fid->hdr.len, fhlen);
400 } else if (!mask_match) {
401 tst_res(TFAIL,
402 "got event: mask=%llx (expected %llx) "
403 "pid=%u fd=%d name='%s' "
404 "len=%d info_type=%d info_len=%d fh_len=%d",
405 (unsigned long long)event->mask, expected->mask,
406 (unsigned)event->pid, event->fd, filename,
407 event->event_len, event_fid->hdr.info_type,
408 event_fid->hdr.len, fhlen);
409 } else if (info_type != event_fid->hdr.info_type) {
410 tst_res(TFAIL,
411 "got event: mask=%llx pid=%u fd=%d, "
412 "len=%d info_type=%d expected(%d) info_len=%d fh_len=%d",
413 (unsigned long long)event->mask,
414 (unsigned)event->pid, event->fd,
415 event->event_len, event_fid->hdr.info_type,
416 info_type, event_fid->hdr.len, fhlen);
417 } else if (fhlen != expected_fid->handle.handle_bytes) {
418 tst_res(TFAIL,
419 "got event: mask=%llx pid=%u fd=%d name='%s' "
420 "len=%d info_type=%d info_len=%d fh_len=%d expected(%d) "
421 "fh_type=%d",
422 (unsigned long long)event->mask,
423 (unsigned)event->pid, event->fd, filename,
424 event->event_len, info_type,
425 event_fid->hdr.len, fhlen,
426 expected_fid->handle.handle_bytes,
427 file_handle->handle_type);
428 } else if (file_handle->handle_type !=
429 expected_fid->handle.handle_type) {
430 tst_res(TFAIL,
431 "got event: mask=%llx pid=%u fd=%d name='%s' "
432 "len=%d info_type=%d info_len=%d fh_len=%d "
433 "fh_type=%d expected(%x)",
434 (unsigned long long)event->mask,
435 (unsigned)event->pid, event->fd, filename,
436 event->event_len, info_type,
437 event_fid->hdr.len, fhlen,
438 file_handle->handle_type,
439 expected_fid->handle.handle_type);
440 } else if (memcmp(file_handle->f_handle,
441 expected_fid->handle.f_handle, fhlen)) {
442 tst_res(TFAIL,
443 "got event: mask=%llx pid=%u fd=%d name='%s' "
444 "len=%d info_type=%d info_len=%d fh_len=%d "
445 "fh_type=%d unexpected file handle (%x...)",
446 (unsigned long long)event->mask,
447 (unsigned)event->pid, event->fd, filename,
448 event->event_len, info_type,
449 event_fid->hdr.len, fhlen,
450 file_handle->handle_type,
451 *(int *)(file_handle->f_handle));
452 } else if (memcmp(&event_fid->fsid, &expected_fid->fsid,
453 sizeof(event_fid->fsid)) != 0) {
454 tst_res(TFAIL,
455 "got event: mask=%llx pid=%u fd=%d name='%s' "
456 "len=%d info_type=%d info_len=%d fh_len=%d "
457 "fsid=%x.%x (expected %x.%x)",
458 (unsigned long long)event->mask,
459 (unsigned)event->pid, event->fd, filename,
460 event->event_len, info_type,
461 event_fid->hdr.len, fhlen,
462 FSID_VAL_MEMBER(event_fid->fsid, 0),
463 FSID_VAL_MEMBER(event_fid->fsid, 1),
464 expected_fid->fsid.val[0],
465 expected_fid->fsid.val[1]);
466 } else if (strcmp(expected->name, filename)) {
467 tst_res(TFAIL,
468 "got event: mask=%llx "
469 "pid=%u fd=%d name='%s' expected('%s') "
470 "len=%d info_type=%d info_len=%d fh_len=%d",
471 (unsigned long long)event->mask,
472 (unsigned)event->pid, event->fd,
473 filename, expected->name,
474 event->event_len, event_fid->hdr.info_type,
475 event_fid->hdr.len, fhlen);
476 } else if (event->pid != getpid()) {
477 tst_res(TFAIL,
478 "got event: mask=%llx pid=%u "
479 "(expected %u) fd=%d name='%s' "
480 "len=%d info_type=%d info_len=%d fh_len=%d",
481 (unsigned long long)event->mask,
482 (unsigned)event->pid,
483 (unsigned)getpid(),
484 event->fd, filename,
485 event->event_len, event_fid->hdr.info_type,
486 event_fid->hdr.len, fhlen);
487 } else if (!!child_fid != !!expected_child_fid) {
488 tst_res(TFAIL,
489 "got event: mask=%llx "
490 "pid=%u fd=%d name='%s' num_info=%d (expected %d) "
491 "len=%d info_type=%d info_len=%d fh_len=%d",
492 (unsigned long long)event->mask,
493 (unsigned)event->pid, event->fd,
494 filename, 1 + !!child_fid, 1 + !!expected_child_fid,
495 event->event_len, event_fid->hdr.info_type,
496 event_fid->hdr.len, fhlen);
497 } else if (child_fid) {
498 tst_res(TINFO,
499 "got event #%d: info #%d: info_type=%d info_len=%d fh_len=%d",
500 test_num, info_id, event_fid->hdr.info_type,
501 event_fid->hdr.len, fhlen);
502
503 /* Recheck event_fid match with child_fid */
504 event_fid = child_fid;
505 expected_fid = expected->child_fid;
506 info_id = 1;
507 info_type = FAN_EVENT_INFO_TYPE_FID;
508 file_handle = (struct file_handle *)event_fid->handle;
509 fhlen = file_handle->handle_bytes;
510 child_fid = NULL;
511 expected_child_fid = NULL;
512 goto check_match;
513 } else {
514 tst_res(TPASS,
515 "got event #%d: mask=%llx pid=%u fd=%d name='%s' "
516 "len=%d; info #%d: info_type=%d info_len=%d fh_len=%d",
517 test_num, (unsigned long long)event->mask,
518 (unsigned)event->pid, event->fd, filename,
519 event->event_len, info_id, event_fid->hdr.info_type,
520 event_fid->hdr.len, fhlen);
521 }
522
523 if (test_num < tst_count)
524 test_num++;
525
526 if (mask_match) {
527 /* In case of merged event match next expected mask */
528 event->mask &= ~expected->mask | FAN_ONDIR;
529 if (event->mask & ~FAN_ONDIR)
530 continue;
531 }
532
533 i += event->event_len;
534 if (event->fd > 0)
535 SAFE_CLOSE(event->fd);
536 }
537
538 for (; test_num < tst_count; test_num++) {
539 tst_res(TFAIL, "didn't get event: mask=%llx, name='%s'",
540 event_set[test_num].mask, event_set[test_num].name);
541
542 }
543 }
544
setup(void)545 static void setup(void)
546 {
547 REQUIRE_FANOTIFY_INIT_FLAGS_SUPPORTED_ON_FS(FAN_REPORT_DIR_FID, MOUNT_PATH);
548
549 sprintf(dname1, "%s/%s", MOUNT_PATH, DIR_NAME1);
550 sprintf(dname2, "%s/%s", MOUNT_PATH, DIR_NAME2);
551 sprintf(fname1, "%s/%s", dname1, FILE_NAME1);
552 sprintf(fname2, "%s/%s", dname1, FILE_NAME2);
553 }
554
cleanup(void)555 static void cleanup(void)
556 {
557 if (fd_notify > 0)
558 SAFE_CLOSE(fd_notify);
559 }
560
561 static struct tst_test test = {
562 .test = do_test,
563 .tcnt = ARRAY_SIZE(test_cases),
564 .setup = setup,
565 .cleanup = cleanup,
566 .mount_device = 1,
567 .mntpoint = MOUNT_PATH,
568 .all_filesystems = 1,
569 .needs_root = 1
570 };
571
572 #else
573 TST_TEST_TCONF("system does not have required name_to_handle_at() support");
574 #endif
575 #else
576 TST_TEST_TCONF("system doesn't have required fanotify support");
577 #endif
578