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