• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  * - FAN_REPORT_DFID_NAME_TARGET (dir fid + name + created/deleted file fid)
18  */
19 
20 #define _GNU_SOURCE
21 #include "config.h"
22 
23 #include <stdio.h>
24 #include <sys/stat.h>
25 #include <sys/types.h>
26 #include <errno.h>
27 #include <string.h>
28 #include <sys/mount.h>
29 #include <sys/syscall.h>
30 #include "tst_test.h"
31 
32 #ifdef HAVE_SYS_FANOTIFY_H
33 #include "fanotify.h"
34 
35 #define EVENT_MAX 20
36 
37 /* Size of the event structure, not including file handle */
38 #define EVENT_SIZE (sizeof(struct fanotify_event_metadata) + \
39 		    sizeof(struct fanotify_event_info_fid))
40 
41 /* Tripple events buffer size to account for file handles and names */
42 #define EVENT_BUF_LEN (EVENT_MAX * EVENT_SIZE * 3)
43 
44 #define BUF_SIZE 256
45 
46 #ifdef HAVE_NAME_TO_HANDLE_AT
47 struct event_t {
48 	unsigned long long mask;
49 	struct fanotify_fid_t *fid;
50 	struct fanotify_fid_t *child_fid;
51 	char name[BUF_SIZE];
52 	char name2[BUF_SIZE];
53 	char *old_name;
54 	char *new_name;
55 };
56 
57 static char fname1[BUF_SIZE + 11], fname2[BUF_SIZE + 11];
58 static char dname1[BUF_SIZE], dname2[BUF_SIZE], tmpdir[BUF_SIZE];
59 static int fd_notify;
60 
61 static struct event_t event_set[EVENT_MAX];
62 
63 static char event_buf[EVENT_BUF_LEN];
64 
65 #define DIR_NAME1 "test_dir1"
66 #define DIR_NAME2 "test_dir2"
67 #define FILE_NAME1 "test_file1"
68 #define FILE_NAME2 "test_file2"
69 #define MOUNT_PATH "fs_mnt"
70 #define TEMP_DIR MOUNT_PATH "/temp_dir"
71 
72 static int fan_report_target_fid_unsupported;
73 static int rename_events_unsupported;
74 
75 static struct test_case_t {
76 	const char *tname;
77 	struct fanotify_group_type group;
78 	struct fanotify_mark_type mark;
79 	unsigned long mask;
80 	struct fanotify_mark_type sub_mark;
81 	unsigned long sub_mask;
82 	unsigned long tmpdir_ignored_mask;
83 } test_cases[] = {
84 	{
85 		"FAN_REPORT_DFID_NAME monitor filesystem for create/delete/move/open/close",
86 		INIT_FANOTIFY_GROUP_TYPE(REPORT_DFID_NAME),
87 		INIT_FANOTIFY_MARK_TYPE(FILESYSTEM),
88 		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR,
89 		/* Mount watch for events possible on children */
90 		INIT_FANOTIFY_MARK_TYPE(MOUNT),
91 		FAN_OPEN | FAN_CLOSE | FAN_ONDIR,
92 		0,
93 	},
94 	{
95 		"FAN_REPORT_DFID_NAME monitor directories for create/delete/move/open/close",
96 		INIT_FANOTIFY_GROUP_TYPE(REPORT_DFID_NAME),
97 		INIT_FANOTIFY_MARK_TYPE(INODE),
98 		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_ONDIR,
99 		/* Watches for self events on subdir and events on subdir's children */
100 		INIT_FANOTIFY_MARK_TYPE(INODE),
101 		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR |
102 		FAN_OPEN | FAN_CLOSE | FAN_EVENT_ON_CHILD,
103 		0,
104 	},
105 	{
106 		"FAN_REPORT_DIR_FID monitor filesystem for create/delete/move/open/close",
107 		INIT_FANOTIFY_GROUP_TYPE(REPORT_DIR_FID),
108 		INIT_FANOTIFY_MARK_TYPE(FILESYSTEM),
109 		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR,
110 		/* Mount watch for events possible on children */
111 		INIT_FANOTIFY_MARK_TYPE(MOUNT),
112 		FAN_OPEN | FAN_CLOSE | FAN_ONDIR,
113 		0,
114 	},
115 	{
116 		"FAN_REPORT_DIR_FID monitor directories for create/delete/move/open/close",
117 		INIT_FANOTIFY_GROUP_TYPE(REPORT_DIR_FID),
118 		INIT_FANOTIFY_MARK_TYPE(INODE),
119 		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_ONDIR,
120 		/* Watches for self events on subdir and events on subdir's children */
121 		INIT_FANOTIFY_MARK_TYPE(INODE),
122 		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR |
123 		FAN_OPEN | FAN_CLOSE | FAN_EVENT_ON_CHILD,
124 		0,
125 	},
126 	{
127 		"FAN_REPORT_DFID_FID monitor filesystem for create/delete/move/open/close",
128 		INIT_FANOTIFY_GROUP_TYPE(REPORT_DFID_FID),
129 		INIT_FANOTIFY_MARK_TYPE(FILESYSTEM),
130 		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR,
131 		/* Mount watch for events possible on children */
132 		INIT_FANOTIFY_MARK_TYPE(MOUNT),
133 		FAN_OPEN | FAN_CLOSE | FAN_ONDIR,
134 		0,
135 	},
136 	{
137 		"FAN_REPORT_DFID_FID monitor directories for create/delete/move/open/close",
138 		INIT_FANOTIFY_GROUP_TYPE(REPORT_DFID_FID),
139 		INIT_FANOTIFY_MARK_TYPE(INODE),
140 		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_ONDIR,
141 		/* Watches for self events on subdir and events on subdir's children */
142 		INIT_FANOTIFY_MARK_TYPE(INODE),
143 		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR |
144 		FAN_OPEN | FAN_CLOSE | FAN_EVENT_ON_CHILD,
145 		0,
146 	},
147 	{
148 		"FAN_REPORT_DFID_NAME_FID monitor filesystem for create/delete/move/open/close",
149 		INIT_FANOTIFY_GROUP_TYPE(REPORT_DFID_NAME_FID),
150 		INIT_FANOTIFY_MARK_TYPE(FILESYSTEM),
151 		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR,
152 		/* Mount watch for events possible on children */
153 		INIT_FANOTIFY_MARK_TYPE(MOUNT),
154 		FAN_OPEN | FAN_CLOSE | FAN_ONDIR,
155 		0,
156 	},
157 	{
158 		"FAN_REPORT_DFID_NAME_FID monitor directories for create/delete/move/open/close",
159 		INIT_FANOTIFY_GROUP_TYPE(REPORT_DFID_NAME_FID),
160 		INIT_FANOTIFY_MARK_TYPE(INODE),
161 		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_ONDIR,
162 		/* Watches for self events on subdir and events on subdir's children */
163 		INIT_FANOTIFY_MARK_TYPE(INODE),
164 		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR |
165 		FAN_OPEN | FAN_CLOSE | FAN_EVENT_ON_CHILD,
166 		0,
167 	},
168 	{
169 		"FAN_REPORT_DFID_NAME_TARGET monitor filesystem for create/delete/move/open/close",
170 		INIT_FANOTIFY_GROUP_TYPE(REPORT_DFID_NAME_TARGET),
171 		INIT_FANOTIFY_MARK_TYPE(FILESYSTEM),
172 		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR,
173 		/* Mount watch for events possible on children */
174 		INIT_FANOTIFY_MARK_TYPE(MOUNT),
175 		FAN_OPEN | FAN_CLOSE | FAN_ONDIR,
176 		0,
177 	},
178 	{
179 		"FAN_REPORT_DFID_NAME_TARGET monitor directories for create/delete/move/open/close",
180 		INIT_FANOTIFY_GROUP_TYPE(REPORT_DFID_NAME_TARGET),
181 		INIT_FANOTIFY_MARK_TYPE(INODE),
182 		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_ONDIR,
183 		/* Watches for self events on subdir and events on subdir's children */
184 		INIT_FANOTIFY_MARK_TYPE(INODE),
185 		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR |
186 		FAN_OPEN | FAN_CLOSE | FAN_EVENT_ON_CHILD,
187 		0,
188 	},
189 	{
190 		"FAN_REPORT_DFID_NAME_FID monitor filesystem for create/delete/move/rename/open/close",
191 		INIT_FANOTIFY_GROUP_TYPE(REPORT_DFID_NAME_FID),
192 		INIT_FANOTIFY_MARK_TYPE(FILESYSTEM),
193 		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_RENAME | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR,
194 		/* Mount watch for events possible on children */
195 		INIT_FANOTIFY_MARK_TYPE(MOUNT),
196 		FAN_OPEN | FAN_CLOSE | FAN_ONDIR,
197 		0,
198 	},
199 	{
200 		"FAN_REPORT_DFID_NAME_FID monitor directories for create/delete/move/rename/open/close",
201 		INIT_FANOTIFY_GROUP_TYPE(REPORT_DFID_NAME_FID),
202 		INIT_FANOTIFY_MARK_TYPE(INODE),
203 		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_RENAME | FAN_ONDIR,
204 		/* Watches for self events on subdir and events on subdir's children */
205 		INIT_FANOTIFY_MARK_TYPE(INODE),
206 		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_RENAME | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR |
207 		FAN_OPEN | FAN_CLOSE | FAN_EVENT_ON_CHILD,
208 		0,
209 	},
210 	{
211 		"FAN_REPORT_DFID_NAME_TARGET monitor filesystem for create/delete/move/rename/open/close",
212 		INIT_FANOTIFY_GROUP_TYPE(REPORT_DFID_NAME_TARGET),
213 		INIT_FANOTIFY_MARK_TYPE(FILESYSTEM),
214 		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_RENAME | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR,
215 		/* Mount watch for events possible on children */
216 		INIT_FANOTIFY_MARK_TYPE(MOUNT),
217 		FAN_OPEN | FAN_CLOSE | FAN_ONDIR,
218 		0,
219 	},
220 	{
221 		"FAN_REPORT_DFID_NAME_TARGET monitor directories for create/delete/move/rename/open/close",
222 		INIT_FANOTIFY_GROUP_TYPE(REPORT_DFID_NAME_TARGET),
223 		INIT_FANOTIFY_MARK_TYPE(INODE),
224 		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_RENAME | FAN_ONDIR,
225 		/* Watches for self events on subdir and events on subdir's children */
226 		INIT_FANOTIFY_MARK_TYPE(INODE),
227 		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_RENAME | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR |
228 		FAN_OPEN | FAN_CLOSE | FAN_EVENT_ON_CHILD,
229 		0,
230 	},
231 	{
232 		"FAN_REPORT_DFID_NAME_FID monitor directories and ignore FAN_RENAME events to/from temp directory",
233 		INIT_FANOTIFY_GROUP_TYPE(REPORT_DFID_NAME_FID),
234 		INIT_FANOTIFY_MARK_TYPE(INODE),
235 		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_RENAME | FAN_ONDIR,
236 		/* Watches for self events on subdir and events on subdir's children */
237 		INIT_FANOTIFY_MARK_TYPE(INODE),
238 		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_RENAME | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR |
239 		FAN_OPEN | FAN_CLOSE | FAN_EVENT_ON_CHILD,
240 		/* Ignore FAN_RENAME to/from tmpdir */
241 		FAN_MOVE | FAN_RENAME,
242 	},
243 	{
244 		"FAN_REPORT_DFID_NAME_FID monitor filesystem and ignore FAN_RENAME events to/from temp directory",
245 		INIT_FANOTIFY_GROUP_TYPE(REPORT_DFID_NAME_FID),
246 		INIT_FANOTIFY_MARK_TYPE(FILESYSTEM),
247 		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_RENAME | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR,
248 		/* Mount watch for events possible on children */
249 		INIT_FANOTIFY_MARK_TYPE(MOUNT),
250 		FAN_OPEN | FAN_CLOSE | FAN_ONDIR,
251 		/* Ignore FAN_RENAME to/from tmpdir */
252 		FAN_MOVE | FAN_RENAME,
253 	},
254 };
255 
do_test(unsigned int number)256 static void do_test(unsigned int number)
257 {
258 	int fd, dirfd, len = 0, i = 0, test_num = 0, tst_count = 0;
259 	struct test_case_t *tc = &test_cases[number];
260 	struct fanotify_group_type *group = &tc->group;
261 	struct fanotify_mark_type *mark = &tc->mark;
262 	struct fanotify_mark_type *sub_mark = &tc->sub_mark;
263 	struct fanotify_fid_t root_fid, dir_fid, file_fid;
264 	struct fanotify_fid_t *child_fid = NULL, *subdir_fid = NULL;
265 	int report_name = (group->flag & FAN_REPORT_NAME);
266 	int report_target_fid = (group->flag & FAN_REPORT_TARGET_FID);
267 	int report_rename = (tc->mask & FAN_RENAME);
268 	int fs_mark = (mark->flag == FAN_MARK_FILESYSTEM);
269 	int rename_ignored = (tc->tmpdir_ignored_mask & FAN_RENAME);
270 
271 	tst_res(TINFO, "Test #%d: %s", number, tc->tname);
272 
273 	if (report_rename && rename_events_unsupported) {
274 		tst_res(TCONF, "FAN_RENAME not supported in kernel?");
275 		return;
276 	}
277 
278 	if (fan_report_target_fid_unsupported && report_target_fid) {
279 		FANOTIFY_INIT_FLAGS_ERR_MSG(FAN_REPORT_TARGET_FID,
280 					    fan_report_target_fid_unsupported);
281 		return;
282 	}
283 
284 	fd_notify = SAFE_FANOTIFY_INIT(group->flag, 0);
285 
286 	/*
287 	 * Watch dir modify events with name in filesystem/dir
288 	 */
289 	SAFE_FANOTIFY_MARK(fd_notify, FAN_MARK_ADD | mark->flag, tc->mask,
290 			   AT_FDCWD, MOUNT_PATH);
291 
292 	/* Save the mount root fid */
293 	fanotify_save_fid(MOUNT_PATH, &root_fid);
294 
295 	/*
296 	 * Create subdir and watch open events "on children" with name.
297 	 * Make it a mount root.
298 	 */
299 	SAFE_MKDIR(dname1, 0755);
300 	SAFE_MOUNT(dname1, dname1, "none", MS_BIND, NULL);
301 
302 	/* Save the subdir fid */
303 	fanotify_save_fid(dname1, &dir_fid);
304 	/* With FAN_REPORT_TARGET_FID, report subdir fid also for dirent events */
305 	if (report_target_fid)
306 		subdir_fid = &dir_fid;
307 
308 	if (tc->sub_mask)
309 		SAFE_FANOTIFY_MARK(fd_notify, FAN_MARK_ADD | sub_mark->flag,
310 				   tc->sub_mask, AT_FDCWD, dname1);
311 	/*
312 	 * ignore FAN_RENAME to/from tmpdir, so we won't get the FAN_RENAME events
313 	 * when subdir is moved via tmpdir.
314 	 * FAN_MOVE is also set in ignored mark of tmpdir, but it will have no effect
315 	 * and the MOVED_FROM/TO events will still be reported.
316 	 */
317 	if (tc->tmpdir_ignored_mask)
318 		SAFE_FANOTIFY_MARK(fd_notify, FAN_MARK_ADD |
319 				   FAN_MARK_IGNORED_MASK |
320 				   FAN_MARK_IGNORED_SURV_MODIFY,
321 				   tc->tmpdir_ignored_mask, AT_FDCWD, TEMP_DIR);
322 
323 	memset(event_set, 0, sizeof(event_set));
324 	event_set[tst_count].mask = FAN_CREATE | FAN_ONDIR;
325 	event_set[tst_count].fid = &root_fid;
326 	event_set[tst_count].child_fid = subdir_fid;
327 	strcpy(event_set[tst_count].name, DIR_NAME1);
328 	tst_count++;
329 
330 	/* Generate modify events "on child" */
331 	fd = SAFE_CREAT(fname1, 0755);
332 
333 	/* Save the file fid */
334 	fanotify_save_fid(fname1, &file_fid);
335 	/* With FAN_REPORT_TARGET_FID, report child fid also for dirent events */
336 	if (report_target_fid)
337 		child_fid = &file_fid;
338 
339 	SAFE_WRITE(SAFE_WRITE_ALL, fd, "1", 1);
340 	SAFE_RENAME(fname1, fname2);
341 
342 	SAFE_CLOSE(fd);
343 
344 	/* Generate delete events with fname2 */
345 	SAFE_UNLINK(fname2);
346 
347 	/* Read events on files in subdir */
348 	len += SAFE_READ(0, fd_notify, event_buf + len, EVENT_BUF_LEN - len);
349 
350 	/*
351 	 * FAN_CREATE|FAN_DELETE|FAN_MOVE events with the same name are merged.
352 	 */
353 	event_set[tst_count].mask = FAN_CREATE | FAN_MOVED_FROM;
354 	event_set[tst_count].fid = &dir_fid;
355 	event_set[tst_count].child_fid = child_fid;
356 	strcpy(event_set[tst_count].name, FILE_NAME1);
357 	tst_count++;
358 	/*
359 	 * Event on non-dir child with the same name may be merged with the
360 	 * directory entry modification events above, unless FAN_REPORT_FID is
361 	 * set and child fid is reported. If FAN_REPORT_FID is set but
362 	 * FAN_REPORT_NAME is not set, then FAN_CREATE above is merged with
363 	 * FAN_DELETE below and FAN_OPEN will be merged with FAN_CLOSE.
364 	 */
365 	if (report_name) {
366 		event_set[tst_count].mask = FAN_OPEN;
367 		event_set[tst_count].fid = &dir_fid;
368 		event_set[tst_count].child_fid = &file_fid;
369 		strcpy(event_set[tst_count].name, FILE_NAME1);
370 		tst_count++;
371 	}
372 	/*
373 	 * FAN_RENAME event is independent of MOVED_FROM/MOVED_TO and not merged
374 	 * with any other event because it has different info records.
375 	 */
376 	if (report_rename) {
377 		event_set[tst_count].mask = FAN_RENAME;
378 		event_set[tst_count].fid = &dir_fid;
379 		event_set[tst_count].child_fid = child_fid;
380 		strcpy(event_set[tst_count].name, FILE_NAME1);
381 		strcpy(event_set[tst_count].name2, FILE_NAME2);
382 		event_set[tst_count].old_name = event_set[tst_count].name;
383 		event_set[tst_count].new_name = event_set[tst_count].name2;
384 		tst_count++;
385 	}
386 
387 	event_set[tst_count].mask = FAN_DELETE | FAN_MOVED_TO;
388 	/*
389 	 * With FAN_REPORT_TARGET_FID, close of FILE_NAME2 is merged with
390 	 * moved_to and delete events, because they all have parent and
391 	 * child fid records.
392 	 */
393 	if (report_target_fid)
394 		event_set[tst_count].mask |= FAN_CLOSE_WRITE;
395 	event_set[tst_count].fid = &dir_fid;
396 	event_set[tst_count].child_fid = child_fid;
397 	strcpy(event_set[tst_count].name, FILE_NAME2);
398 	tst_count++;
399 	/*
400 	 * When not reporting name, open of FILE_NAME1 is merged
401 	 * with close of FILE_NAME2.
402 	 */
403 	if (!report_name) {
404 		event_set[tst_count].mask = FAN_OPEN | FAN_CLOSE_WRITE;
405 		event_set[tst_count].fid = &dir_fid;
406 		event_set[tst_count].child_fid = &file_fid;
407 		strcpy(event_set[tst_count].name, "");
408 		tst_count++;
409 	}
410 	/*
411 	 * Directory watch does not get self events on children.
412 	 * Filesystem watch gets self event w/o name info if FAN_REPORT_FID
413 	 * is set.
414 	 */
415 	if (fs_mark && (group->flag & FAN_REPORT_FID)) {
416 		event_set[tst_count].mask = FAN_DELETE_SELF | FAN_MOVE_SELF;
417 		event_set[tst_count].fid = &file_fid;
418 		event_set[tst_count].child_fid = NULL;
419 		strcpy(event_set[tst_count].name, "");
420 		tst_count++;
421 	}
422 	/*
423 	 * Without FAN_REPORT_TARGET_FID, close of FILE_NAME2 is not merged with
424 	 * open of FILE_NAME1 and it is received after the merged self events.
425 	 */
426 	if (report_name && !report_target_fid) {
427 		event_set[tst_count].mask = FAN_CLOSE_WRITE;
428 		event_set[tst_count].fid = &dir_fid;
429 		event_set[tst_count].child_fid = &file_fid;
430 		strcpy(event_set[tst_count].name, FILE_NAME2);
431 		tst_count++;
432 	}
433 
434 	dirfd = SAFE_OPEN(dname1, O_RDONLY | O_DIRECTORY);
435 	SAFE_CLOSE(dirfd);
436 
437 	SAFE_UMOUNT(dname1);
438 
439 	/*
440 	 * Directory watch gets open/close events on itself and on its subdirs.
441 	 * Filesystem watch gets open/close event on all directories with name ".".
442 	 */
443 	event_set[tst_count].mask = FAN_OPEN | FAN_CLOSE_NOWRITE | FAN_ONDIR;
444 	event_set[tst_count].fid = &dir_fid;
445 	event_set[tst_count].child_fid = NULL;
446 	strcpy(event_set[tst_count].name, ".");
447 	tst_count++;
448 	/*
449 	 * Directory watch gets self event on itself and filesystem watch gets
450 	 * self event on all directories with name ".".
451 	 */
452 	event_set[tst_count].mask = FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR;
453 	event_set[tst_count].fid = &dir_fid;
454 	event_set[tst_count].child_fid = NULL;
455 	strcpy(event_set[tst_count].name, ".");
456 	tst_count++;
457 
458 	/*
459 	 * If only root dir and subdir are watched, a rename via an unwatched tmpdir
460 	 * will observe the same MOVED_FROM/MOVED_TO events as a direct rename,
461 	 * but will observe 2 FAN_RENAME events with 1 info dir+name record each
462 	 * instead of 1 FAN_RENAME event with 2 dir+name info records.
463 	 *
464 	 * If tmpdir is ignoring FAN_RENAME, we will get the MOVED_FROM/MOVED_TO
465 	 * events and will not get the FAN_RENAME event for rename via tmpdir.
466 	 */
467 	if (!fs_mark || rename_ignored) {
468 		SAFE_RENAME(dname1, tmpdir);
469 		SAFE_RENAME(tmpdir, dname2);
470 	} else {
471 		SAFE_RENAME(dname1, dname2);
472 	}
473 	SAFE_RMDIR(dname2);
474 
475 	/* Read more events on dirs */
476 	len += SAFE_READ(0, fd_notify, event_buf + len, EVENT_BUF_LEN - len);
477 
478 	/*
479 	 * FAN_RENAME event is independent of MOVED_FROM/MOVED_TO and not merged
480 	 * with any other event because it has different info records.
481 	 * When renamed via an unwatched tmpdir, the 1st FAN_RENAME event has the
482 	 * info record of root_fid+DIR_NAME1 and the 2nd FAN_RENAME event has the
483 	 * info record of root_fid+DIR_NAME2.
484 	 * If tmpdir is ignoring FAN_RENAME, we get no FAN_RENAME events at all.
485 	 */
486 	if (report_rename && !rename_ignored) {
487 		event_set[tst_count].mask = FAN_RENAME | FAN_ONDIR;
488 		event_set[tst_count].fid = &root_fid;
489 		event_set[tst_count].child_fid = subdir_fid;
490 		strcpy(event_set[tst_count].name, DIR_NAME1);
491 		event_set[tst_count].old_name = event_set[tst_count].name;
492 		if (fs_mark) {
493 			strcpy(event_set[tst_count].name2, DIR_NAME2);
494 			event_set[tst_count].new_name = event_set[tst_count].name2;
495 		}
496 		tst_count++;
497 	}
498 	event_set[tst_count].mask = FAN_MOVED_FROM | FAN_ONDIR;
499 	event_set[tst_count].fid = &root_fid;
500 	event_set[tst_count].child_fid = subdir_fid;
501 	strcpy(event_set[tst_count].name, DIR_NAME1);
502 	tst_count++;
503 	if (report_rename && !fs_mark && !rename_ignored) {
504 		event_set[tst_count].mask = FAN_RENAME | FAN_ONDIR;
505 		event_set[tst_count].fid = &root_fid;
506 		event_set[tst_count].child_fid = subdir_fid;
507 		strcpy(event_set[tst_count].name, DIR_NAME2);
508 		event_set[tst_count].new_name = event_set[tst_count].name;
509 		tst_count++;
510 	}
511 	event_set[tst_count].mask = FAN_DELETE | FAN_MOVED_TO | FAN_ONDIR;
512 	event_set[tst_count].fid = &root_fid;
513 	event_set[tst_count].child_fid = subdir_fid;
514 	strcpy(event_set[tst_count].name, DIR_NAME2);
515 	tst_count++;
516 	/* Expect no more events */
517 	event_set[tst_count].mask = 0;
518 
519 	/*
520 	 * Cleanup the marks
521 	 */
522 	SAFE_CLOSE(fd_notify);
523 	fd_notify = -1;
524 
525 	while (i < len) {
526 		struct event_t *expected = &event_set[test_num];
527 		struct fanotify_event_metadata *event;
528 		struct fanotify_event_info_fid *event_fid;
529 		struct fanotify_event_info_fid *child_fid;
530 		struct fanotify_fid_t *expected_fid = expected->fid;
531 		struct fanotify_fid_t *expected_child_fid = expected->child_fid;
532 		struct file_handle *file_handle;
533 		unsigned int fhlen;
534 		const char *filename;
535 		int namelen, info_type, mask_match, info_id = 0;
536 
537 		event = (struct fanotify_event_metadata *)&event_buf[i];
538 		event_fid = (struct fanotify_event_info_fid *)(event + 1);
539 		file_handle = (struct file_handle *)event_fid->handle;
540 		fhlen = file_handle->handle_bytes;
541 		filename = (char *)file_handle->f_handle + fhlen;
542 		child_fid = (void *)((char *)event_fid + event_fid->hdr.len);
543 		namelen = (char *)child_fid - (char *)filename;
544 		/* End of event_fid could have name, zero padding, both or none */
545 		if (namelen > 0) {
546 			namelen = strlen(filename);
547 		} else {
548 			filename = "";
549 			namelen = 0;
550 		}
551 		/* Is there a child fid after first fid record? */
552 		if (((char *)child_fid - (char *)event) >= event->event_len)
553 			child_fid = NULL;
554 
555 		if (!(group->flag & FAN_REPORT_FID))
556 			expected_child_fid = NULL;
557 
558 		if (!report_name)
559 			expected->name[0] = 0;
560 
561 		if (expected->mask & FAN_RENAME) {
562 			/* If old name is not reported, first record is new name */
563 			info_type = expected->old_name ?
564 				FAN_EVENT_INFO_TYPE_OLD_DFID_NAME :
565 				FAN_EVENT_INFO_TYPE_NEW_DFID_NAME;
566 			/* The 2nd fid is same as 1st becaue we rename in same parent */
567 			if (expected->name2[0])
568 				expected_child_fid = expected_fid;
569 		} else if (expected->name[0]) {
570 			info_type = FAN_EVENT_INFO_TYPE_DFID_NAME;
571 		} else if (expected->mask & FAN_ONDIR) {
572 			info_type = FAN_EVENT_INFO_TYPE_DFID;
573 		} else if (expected->mask & (FAN_DELETE_SELF | FAN_MOVE_SELF)) {
574 			/* Self event on non-dir has only child fid */
575 			info_type = FAN_EVENT_INFO_TYPE_FID;
576 		} else {
577 			info_type = FAN_EVENT_INFO_TYPE_DFID;
578 		}
579 
580 		/*
581 		 * Event may contain more than the expected mask, but it must
582 		 * have all the bits in expected mask.
583 		 * Expected event on dir must not get event on non dir and the
584 		 * other way around.
585 		 */
586 		mask_match = ((event->mask & expected->mask) &&
587 			      !(expected->mask & ~event->mask) &&
588 			      !((event->mask ^ expected->mask) & FAN_ONDIR));
589 
590 check_match:
591 		if (test_num >= tst_count) {
592 			tst_res(TFAIL,
593 				"got unnecessary event: mask=%llx "
594 				"pid=%u fd=%d name='%s' "
595 				"len=%d info_type=%d info_len=%d fh_len=%d",
596 				(unsigned long long)event->mask,
597 				(unsigned int)event->pid, event->fd, filename,
598 				event->event_len, event_fid->hdr.info_type,
599 				event_fid->hdr.len, fhlen);
600 		} else if (!fhlen || namelen < 0) {
601 			tst_res(TFAIL,
602 				"got event without fid: mask=%llx pid=%u fd=%d, "
603 				"len=%d info_type=%d info_len=%d fh_len=%d",
604 				(unsigned long long)event->mask,
605 				(unsigned int)event->pid, event->fd,
606 				event->event_len, event_fid->hdr.info_type,
607 				event_fid->hdr.len, fhlen);
608 		} else if (!mask_match) {
609 			tst_res(TFAIL,
610 				"got event: mask=%llx (expected %llx) "
611 				"pid=%u fd=%d name='%s' "
612 				"len=%d info_type=%d info_len=%d fh_len=%d",
613 				(unsigned long long)event->mask, expected->mask,
614 				(unsigned int)event->pid, event->fd, filename,
615 				event->event_len, event_fid->hdr.info_type,
616 				event_fid->hdr.len, fhlen);
617 		} else if (info_type != event_fid->hdr.info_type) {
618 			tst_res(TFAIL,
619 				"got event: mask=%llx pid=%u fd=%d, "
620 				"len=%d info_type=%d expected(%d) info_len=%d fh_len=%d",
621 				(unsigned long long)event->mask,
622 				(unsigned int)event->pid, event->fd,
623 				event->event_len, event_fid->hdr.info_type,
624 				info_type, event_fid->hdr.len, fhlen);
625 		} else if (fhlen != expected_fid->handle.handle_bytes) {
626 			tst_res(TFAIL,
627 				"got event: mask=%llx pid=%u fd=%d name='%s' "
628 				"len=%d info_type=%d info_len=%d fh_len=%d expected(%d) "
629 				"fh_type=%d",
630 				(unsigned long long)event->mask,
631 				(unsigned int)event->pid, event->fd, filename,
632 				event->event_len, info_type,
633 				event_fid->hdr.len, fhlen,
634 				expected_fid->handle.handle_bytes,
635 				file_handle->handle_type);
636 		} else if (file_handle->handle_type !=
637 			   expected_fid->handle.handle_type) {
638 			tst_res(TFAIL,
639 				"got event: mask=%llx pid=%u fd=%d name='%s' "
640 				"len=%d info_type=%d info_len=%d fh_len=%d "
641 				"fh_type=%d expected(%x)",
642 				(unsigned long long)event->mask,
643 				(unsigned int)event->pid, event->fd, filename,
644 				event->event_len, info_type,
645 				event_fid->hdr.len, fhlen,
646 				file_handle->handle_type,
647 				expected_fid->handle.handle_type);
648 		} else if (memcmp(file_handle->f_handle,
649 				  expected_fid->handle.f_handle, fhlen)) {
650 			tst_res(TFAIL,
651 				"got event: mask=%llx pid=%u fd=%d name='%s' "
652 				"len=%d info_type=%d info_len=%d fh_len=%d "
653 				"fh_type=%d unexpected file handle (%x...)",
654 				(unsigned long long)event->mask,
655 				(unsigned int)event->pid, event->fd, filename,
656 				event->event_len, info_type,
657 				event_fid->hdr.len, fhlen,
658 				file_handle->handle_type,
659 				*(int *)(file_handle->f_handle));
660 		} else if (memcmp(&event_fid->fsid, &expected_fid->fsid,
661 				  sizeof(event_fid->fsid)) != 0) {
662 			tst_res(TFAIL,
663 				"got event: mask=%llx pid=%u fd=%d name='%s' "
664 				"len=%d info_type=%d info_len=%d fh_len=%d "
665 				"fsid=%x.%x (expected %x.%x)",
666 				(unsigned long long)event->mask,
667 				(unsigned int)event->pid, event->fd, filename,
668 				event->event_len, info_type,
669 				event_fid->hdr.len, fhlen,
670 				FSID_VAL_MEMBER(event_fid->fsid, 0),
671 				FSID_VAL_MEMBER(event_fid->fsid, 1),
672 				expected_fid->fsid.val[0],
673 				expected_fid->fsid.val[1]);
674 		} else if (strcmp(expected->name, filename)) {
675 			tst_res(TFAIL,
676 				"got event: mask=%llx "
677 				"pid=%u fd=%d name='%s' expected('%s') "
678 				"len=%d info_type=%d info_len=%d fh_len=%d",
679 				(unsigned long long)event->mask,
680 				(unsigned int)event->pid, event->fd,
681 				filename, expected->name,
682 				event->event_len, event_fid->hdr.info_type,
683 				event_fid->hdr.len, fhlen);
684 		} else if (event->pid != getpid()) {
685 			tst_res(TFAIL,
686 				"got event: mask=%llx pid=%u "
687 				"(expected %u) fd=%d name='%s' "
688 				"len=%d info_type=%d info_len=%d fh_len=%d",
689 				(unsigned long long)event->mask,
690 				(unsigned int)event->pid,
691 				(unsigned int)getpid(),
692 				event->fd, filename,
693 				event->event_len, event_fid->hdr.info_type,
694 				event_fid->hdr.len, fhlen);
695 		} else if (!!child_fid != !!expected_child_fid) {
696 			tst_res(TFAIL,
697 				"got event: mask=%llx "
698 				"pid=%u fd=%d name='%s' num_info=%d (expected %d) "
699 				"len=%d info_type=%d info_len=%d fh_len=%d",
700 				(unsigned long long)event->mask,
701 				(unsigned int)event->pid, event->fd,
702 				filename, 1 + !!child_fid, 1 + !!expected_child_fid,
703 				event->event_len, event_fid->hdr.info_type,
704 				event_fid->hdr.len, fhlen);
705 		} else if (child_fid) {
706 			tst_res(TINFO,
707 				"got event #%d: info #%d: info_type=%d info_len=%d fh_len=%d",
708 				test_num, info_id, event_fid->hdr.info_type,
709 				event_fid->hdr.len, fhlen);
710 
711 			/* Recheck event_fid match with child_fid */
712 			event_fid = child_fid;
713 			expected_fid = expected->child_fid;
714 			info_id = 1;
715 			info_type = FAN_EVENT_INFO_TYPE_FID;
716 			/*
717 			 * With FAN_RENAME event, expect a second record of
718 			 * type NEW_DFID_NAME, which in our case
719 			 * has the same fid as the source dir in 1st record.
720 			 * TODO: check the 2nd name and the 3rd child fid record.
721 			 */
722 			if (event->mask & FAN_RENAME && expected->name2[0]) {
723 				info_type = FAN_EVENT_INFO_TYPE_NEW_DFID_NAME;
724 				expected_fid = expected->fid;
725 			}
726 			file_handle = (struct file_handle *)event_fid->handle;
727 			fhlen = file_handle->handle_bytes;
728 			child_fid = NULL;
729 			expected_child_fid = NULL;
730 			goto check_match;
731 		} else {
732 			tst_res(TPASS,
733 				"got event #%d: mask=%llx pid=%u fd=%d name='%s' "
734 				"len=%d; info #%d: info_type=%d info_len=%d fh_len=%d",
735 				test_num, (unsigned long long)event->mask,
736 				(unsigned int)event->pid, event->fd, filename,
737 				event->event_len, info_id, event_fid->hdr.info_type,
738 				event_fid->hdr.len, fhlen);
739 		}
740 
741 		if (test_num < tst_count)
742 			test_num++;
743 
744 		if (mask_match) {
745 			/* In case of merged event match next expected mask */
746 			event->mask &= ~expected->mask | FAN_ONDIR;
747 			if (event->mask & ~FAN_ONDIR)
748 				continue;
749 		}
750 
751 		i += event->event_len;
752 		if (event->fd > 0)
753 			SAFE_CLOSE(event->fd);
754 	}
755 
756 	for (; test_num < tst_count; test_num++) {
757 		tst_res(TFAIL, "didn't get event: mask=%llx, name='%s'",
758 			 event_set[test_num].mask, event_set[test_num].name);
759 
760 	}
761 }
762 
setup(void)763 static void setup(void)
764 {
765 	REQUIRE_FANOTIFY_INIT_FLAGS_SUPPORTED_ON_FS(FAN_REPORT_DIR_FID, MOUNT_PATH);
766 	fan_report_target_fid_unsupported =
767 		fanotify_init_flags_supported_on_fs(FAN_REPORT_DFID_NAME_TARGET, MOUNT_PATH);
768 	rename_events_unsupported =
769 		fanotify_events_supported_by_kernel(FAN_RENAME, FAN_REPORT_DFID_NAME, 0);
770 
771 	SAFE_MKDIR(TEMP_DIR, 0755);
772 	sprintf(dname1, "%s/%s", MOUNT_PATH, DIR_NAME1);
773 	sprintf(dname2, "%s/%s", MOUNT_PATH, DIR_NAME2);
774 	sprintf(tmpdir, "%s/%s", TEMP_DIR, DIR_NAME2);
775 	sprintf(fname1, "%s/%s", dname1, FILE_NAME1);
776 	sprintf(fname2, "%s/%s", dname1, FILE_NAME2);
777 }
778 
cleanup(void)779 static void cleanup(void)
780 {
781 	if (fd_notify > 0)
782 		SAFE_CLOSE(fd_notify);
783 }
784 
785 static struct tst_test test = {
786 	.test = do_test,
787 	.tcnt = ARRAY_SIZE(test_cases),
788 	.setup = setup,
789 	.cleanup = cleanup,
790 	.mount_device = 1,
791 	.mntpoint = MOUNT_PATH,
792 	.all_filesystems = 1,
793 	.needs_root = 1
794 };
795 
796 #else
797 	TST_TEST_TCONF("system does not have required name_to_handle_at() support");
798 #endif
799 #else
800 	TST_TEST_TCONF("system doesn't have required fanotify support");
801 #endif
802