1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0
2f08c3bdfSopenharmony_ci/*
3f08c3bdfSopenharmony_ci * Copyright (c) 2018 Matthew Bobrowski. All Rights Reserved.
4f08c3bdfSopenharmony_ci * Copyright (c) Linux Test Project, 2020-2022
5f08c3bdfSopenharmony_ci *
6f08c3bdfSopenharmony_ci * Started by Matthew Bobrowski <mbobrowski@mbobrowski.org>
7f08c3bdfSopenharmony_ci */
8f08c3bdfSopenharmony_ci
9f08c3bdfSopenharmony_ci/*\
10f08c3bdfSopenharmony_ci * [Description]
11f08c3bdfSopenharmony_ci * This test file has been designed to ensure that the fanotify
12f08c3bdfSopenharmony_ci * system calls fanotify_init(2) and fanotify_mark(2) return the
13f08c3bdfSopenharmony_ci * correct error code to the calling process when an invalid flag or
14f08c3bdfSopenharmony_ci * mask value has been specified in conjunction with FAN_REPORT_FID.
15f08c3bdfSopenharmony_ci */
16f08c3bdfSopenharmony_ci
17f08c3bdfSopenharmony_ci/*
18f08c3bdfSopenharmony_ci * The ENOTDIR test cases are regression tests for commits:
19f08c3bdfSopenharmony_ci *
20f08c3bdfSopenharmony_ci *     ceaf69f8eadc fanotify: do not allow setting dirent events in mask of non-dir
21f08c3bdfSopenharmony_ci *     8698e3bab4dd fanotify: refine the validation checks on non-dir inode mask
22f08c3bdfSopenharmony_ci *
23f08c3bdfSopenharmony_ci * The pipes test cases are regression tests for commit:
24f08c3bdfSopenharmony_ci *     69562eb0bd3e fanotify: disallow mount/sb marks on kernel internal pseudo fs
25f08c3bdfSopenharmony_ci */
26f08c3bdfSopenharmony_ci
27f08c3bdfSopenharmony_ci#define _GNU_SOURCE
28f08c3bdfSopenharmony_ci#include "tst_test.h"
29f08c3bdfSopenharmony_ci#include <errno.h>
30f08c3bdfSopenharmony_ci
31f08c3bdfSopenharmony_ci#ifdef HAVE_SYS_FANOTIFY_H
32f08c3bdfSopenharmony_ci#include "fanotify.h"
33f08c3bdfSopenharmony_ci
34f08c3bdfSopenharmony_ci#define MNTPOINT "mntpoint"
35f08c3bdfSopenharmony_ci#define FILE1 MNTPOINT"/file1"
36f08c3bdfSopenharmony_ci
37f08c3bdfSopenharmony_ci/*
38f08c3bdfSopenharmony_ci * List of inode events that are only available when notification group is
39f08c3bdfSopenharmony_ci * set to report fid.
40f08c3bdfSopenharmony_ci */
41f08c3bdfSopenharmony_ci#define INODE_EVENTS (FAN_ATTRIB | FAN_CREATE | FAN_DELETE | FAN_MOVE | \
42f08c3bdfSopenharmony_ci		      FAN_DELETE_SELF | FAN_MOVE_SELF)
43f08c3bdfSopenharmony_ci
44f08c3bdfSopenharmony_ci#define FLAGS_DESC(flags) {(flags), (#flags)}
45f08c3bdfSopenharmony_ci
46f08c3bdfSopenharmony_cistatic int pipes[2] = {-1, -1};
47f08c3bdfSopenharmony_cistatic int fanotify_fd;
48f08c3bdfSopenharmony_cistatic int fan_report_target_fid_unsupported;
49f08c3bdfSopenharmony_cistatic int ignore_mark_unsupported;
50f08c3bdfSopenharmony_ci
51f08c3bdfSopenharmony_cistruct test_case_flags_t {
52f08c3bdfSopenharmony_ci	unsigned long long flags;
53f08c3bdfSopenharmony_ci	const char *desc;
54f08c3bdfSopenharmony_ci};
55f08c3bdfSopenharmony_ci
56f08c3bdfSopenharmony_ci/*
57f08c3bdfSopenharmony_ci * Each test case has been designed in a manner whereby the values defined
58f08c3bdfSopenharmony_ci * within should result in the interface to return an error to the calling
59f08c3bdfSopenharmony_ci * process.
60f08c3bdfSopenharmony_ci */
61f08c3bdfSopenharmony_cistatic struct test_case_t {
62f08c3bdfSopenharmony_ci	struct test_case_flags_t init;
63f08c3bdfSopenharmony_ci	struct test_case_flags_t mark;
64f08c3bdfSopenharmony_ci	/* when mask.flags == 0, fanotify_init() is expected to fail */
65f08c3bdfSopenharmony_ci	struct test_case_flags_t mask;
66f08c3bdfSopenharmony_ci	int expected_errno;
67f08c3bdfSopenharmony_ci	int *pfd;
68f08c3bdfSopenharmony_ci} test_cases[] = {
69f08c3bdfSopenharmony_ci	/* FAN_REPORT_FID without class FAN_CLASS_NOTIF is not valid */
70f08c3bdfSopenharmony_ci	{
71f08c3bdfSopenharmony_ci		.init = FLAGS_DESC(FAN_CLASS_CONTENT | FAN_REPORT_FID),
72f08c3bdfSopenharmony_ci		.expected_errno = EINVAL,
73f08c3bdfSopenharmony_ci	},
74f08c3bdfSopenharmony_ci
75f08c3bdfSopenharmony_ci	/* FAN_REPORT_FID without class FAN_CLASS_NOTIF is not valid */
76f08c3bdfSopenharmony_ci	{
77f08c3bdfSopenharmony_ci		.init = FLAGS_DESC(FAN_CLASS_PRE_CONTENT | FAN_REPORT_FID),
78f08c3bdfSopenharmony_ci		.expected_errno = EINVAL,
79f08c3bdfSopenharmony_ci	},
80f08c3bdfSopenharmony_ci
81f08c3bdfSopenharmony_ci	/* INODE_EVENTS in mask without class FAN_REPORT_FID are not valid */
82f08c3bdfSopenharmony_ci	{
83f08c3bdfSopenharmony_ci		.init = FLAGS_DESC(FAN_CLASS_NOTIF),
84f08c3bdfSopenharmony_ci		.mark = FLAGS_DESC(FAN_MARK_INODE),
85f08c3bdfSopenharmony_ci		.mask = FLAGS_DESC(INODE_EVENTS),
86f08c3bdfSopenharmony_ci		.expected_errno = EINVAL,
87f08c3bdfSopenharmony_ci	},
88f08c3bdfSopenharmony_ci
89f08c3bdfSopenharmony_ci	/* INODE_EVENTS in mask with FAN_MARK_MOUNT are not valid */
90f08c3bdfSopenharmony_ci	{
91f08c3bdfSopenharmony_ci		.init = FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_FID),
92f08c3bdfSopenharmony_ci		.mark = FLAGS_DESC(FAN_MARK_MOUNT),
93f08c3bdfSopenharmony_ci		.mask = FLAGS_DESC(INODE_EVENTS),
94f08c3bdfSopenharmony_ci		.expected_errno = EINVAL,
95f08c3bdfSopenharmony_ci	},
96f08c3bdfSopenharmony_ci
97f08c3bdfSopenharmony_ci	/* FAN_REPORT_NAME without FAN_REPORT_DIR_FID is not valid */
98f08c3bdfSopenharmony_ci	{
99f08c3bdfSopenharmony_ci		.init = FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_NAME),
100f08c3bdfSopenharmony_ci		.expected_errno = EINVAL,
101f08c3bdfSopenharmony_ci	},
102f08c3bdfSopenharmony_ci
103f08c3bdfSopenharmony_ci	/* FAN_REPORT_NAME without FAN_REPORT_DIR_FID is not valid */
104f08c3bdfSopenharmony_ci	{
105f08c3bdfSopenharmony_ci		.init = FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_FID | FAN_REPORT_NAME),
106f08c3bdfSopenharmony_ci		.expected_errno = EINVAL,
107f08c3bdfSopenharmony_ci	},
108f08c3bdfSopenharmony_ci
109f08c3bdfSopenharmony_ci	/* FAN_REPORT_TARGET_FID without FAN_REPORT_FID is not valid */
110f08c3bdfSopenharmony_ci	{
111f08c3bdfSopenharmony_ci		.init = FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_TARGET_FID | FAN_REPORT_DFID_NAME),
112f08c3bdfSopenharmony_ci		.expected_errno = EINVAL,
113f08c3bdfSopenharmony_ci	},
114f08c3bdfSopenharmony_ci
115f08c3bdfSopenharmony_ci	/* FAN_REPORT_TARGET_FID without FAN_REPORT_NAME is not valid */
116f08c3bdfSopenharmony_ci	{
117f08c3bdfSopenharmony_ci		.init = FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_TARGET_FID | FAN_REPORT_DFID_FID),
118f08c3bdfSopenharmony_ci		.expected_errno = EINVAL,
119f08c3bdfSopenharmony_ci	},
120f08c3bdfSopenharmony_ci
121f08c3bdfSopenharmony_ci	/* FAN_RENAME without FAN_REPORT_NAME is not valid */
122f08c3bdfSopenharmony_ci	{
123f08c3bdfSopenharmony_ci		.init = FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_DFID_FID),
124f08c3bdfSopenharmony_ci		.mark = FLAGS_DESC(FAN_MARK_INODE),
125f08c3bdfSopenharmony_ci		.mask = FLAGS_DESC(FAN_RENAME),
126f08c3bdfSopenharmony_ci		.expected_errno = EINVAL,
127f08c3bdfSopenharmony_ci	},
128f08c3bdfSopenharmony_ci
129f08c3bdfSopenharmony_ci	/* With FAN_MARK_ONLYDIR on non-dir is not valid */
130f08c3bdfSopenharmony_ci	{
131f08c3bdfSopenharmony_ci		.init = FLAGS_DESC(FAN_CLASS_NOTIF),
132f08c3bdfSopenharmony_ci		.mark = FLAGS_DESC(FAN_MARK_ONLYDIR),
133f08c3bdfSopenharmony_ci		.mask = FLAGS_DESC(FAN_OPEN),
134f08c3bdfSopenharmony_ci		.expected_errno = ENOTDIR,
135f08c3bdfSopenharmony_ci	},
136f08c3bdfSopenharmony_ci
137f08c3bdfSopenharmony_ci	/* With FAN_REPORT_TARGET_FID, FAN_DELETE on non-dir is not valid */
138f08c3bdfSopenharmony_ci	{
139f08c3bdfSopenharmony_ci		.init = FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_DFID_NAME_TARGET),
140f08c3bdfSopenharmony_ci		.mark = FLAGS_DESC(FAN_MARK_INODE),
141f08c3bdfSopenharmony_ci		.mask = FLAGS_DESC(FAN_DELETE),
142f08c3bdfSopenharmony_ci		.expected_errno = ENOTDIR,
143f08c3bdfSopenharmony_ci	},
144f08c3bdfSopenharmony_ci
145f08c3bdfSopenharmony_ci	/* With FAN_REPORT_TARGET_FID, FAN_RENAME on non-dir is not valid */
146f08c3bdfSopenharmony_ci	{
147f08c3bdfSopenharmony_ci		.init = FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_DFID_NAME_TARGET),
148f08c3bdfSopenharmony_ci		.mark = FLAGS_DESC(FAN_MARK_INODE),
149f08c3bdfSopenharmony_ci		.mask = FLAGS_DESC(FAN_RENAME),
150f08c3bdfSopenharmony_ci		.expected_errno = ENOTDIR,
151f08c3bdfSopenharmony_ci	},
152f08c3bdfSopenharmony_ci
153f08c3bdfSopenharmony_ci	/* With FAN_REPORT_TARGET_FID, FAN_ONDIR on non-dir is not valid */
154f08c3bdfSopenharmony_ci	{
155f08c3bdfSopenharmony_ci		.init = FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_DFID_NAME_TARGET),
156f08c3bdfSopenharmony_ci		.mark = FLAGS_DESC(FAN_MARK_INODE),
157f08c3bdfSopenharmony_ci		.mask = FLAGS_DESC(FAN_OPEN | FAN_ONDIR),
158f08c3bdfSopenharmony_ci		.expected_errno = ENOTDIR,
159f08c3bdfSopenharmony_ci	},
160f08c3bdfSopenharmony_ci
161f08c3bdfSopenharmony_ci	/* With FAN_REPORT_TARGET_FID, FAN_EVENT_ON_CHILD on non-dir is not valid */
162f08c3bdfSopenharmony_ci	{
163f08c3bdfSopenharmony_ci		.init = FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_DFID_NAME_TARGET),
164f08c3bdfSopenharmony_ci		.mark = FLAGS_DESC(FAN_MARK_INODE),
165f08c3bdfSopenharmony_ci		.mask = FLAGS_DESC(FAN_OPEN | FAN_EVENT_ON_CHILD),
166f08c3bdfSopenharmony_ci		.expected_errno = ENOTDIR,
167f08c3bdfSopenharmony_ci	},
168f08c3bdfSopenharmony_ci
169f08c3bdfSopenharmony_ci	/* FAN_MARK_IGNORE_SURV with FAN_DELETE on non-dir is not valid */
170f08c3bdfSopenharmony_ci	{
171f08c3bdfSopenharmony_ci		.init = FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_DFID_NAME),
172f08c3bdfSopenharmony_ci		.mark = FLAGS_DESC(FAN_MARK_IGNORE_SURV),
173f08c3bdfSopenharmony_ci		.mask = FLAGS_DESC(FAN_DELETE),
174f08c3bdfSopenharmony_ci		.expected_errno = ENOTDIR,
175f08c3bdfSopenharmony_ci	},
176f08c3bdfSopenharmony_ci
177f08c3bdfSopenharmony_ci	/* FAN_MARK_IGNORE_SURV with FAN_RENAME on non-dir is not valid */
178f08c3bdfSopenharmony_ci	{
179f08c3bdfSopenharmony_ci		.init = FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_DFID_NAME),
180f08c3bdfSopenharmony_ci		.mark = FLAGS_DESC(FAN_MARK_IGNORE_SURV),
181f08c3bdfSopenharmony_ci		.mask = FLAGS_DESC(FAN_RENAME),
182f08c3bdfSopenharmony_ci		.expected_errno = ENOTDIR,
183f08c3bdfSopenharmony_ci	},
184f08c3bdfSopenharmony_ci
185f08c3bdfSopenharmony_ci	/* FAN_MARK_IGNORE_SURV with FAN_ONDIR on non-dir is not valid */
186f08c3bdfSopenharmony_ci	{
187f08c3bdfSopenharmony_ci		.init = FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_DFID_NAME),
188f08c3bdfSopenharmony_ci		.mark = FLAGS_DESC(FAN_MARK_IGNORE_SURV),
189f08c3bdfSopenharmony_ci		.mask = FLAGS_DESC(FAN_OPEN | FAN_ONDIR),
190f08c3bdfSopenharmony_ci		.expected_errno = ENOTDIR,
191f08c3bdfSopenharmony_ci	},
192f08c3bdfSopenharmony_ci
193f08c3bdfSopenharmony_ci	/* FAN_MARK_IGNORE_SURV with FAN_EVENT_ON_CHILD on non-dir is not valid */
194f08c3bdfSopenharmony_ci	{
195f08c3bdfSopenharmony_ci		.init = FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_DFID_NAME),
196f08c3bdfSopenharmony_ci		.mark = FLAGS_DESC(FAN_MARK_IGNORE_SURV),
197f08c3bdfSopenharmony_ci		.mask = FLAGS_DESC(FAN_OPEN | FAN_EVENT_ON_CHILD),
198f08c3bdfSopenharmony_ci		.expected_errno = ENOTDIR,
199f08c3bdfSopenharmony_ci	},
200f08c3bdfSopenharmony_ci
201f08c3bdfSopenharmony_ci	/* FAN_MARK_IGNORE without FAN_MARK_IGNORED_SURV_MODIFY on directory is not valid */
202f08c3bdfSopenharmony_ci	{
203f08c3bdfSopenharmony_ci		.init = FLAGS_DESC(FAN_CLASS_NOTIF),
204f08c3bdfSopenharmony_ci		.mark = FLAGS_DESC(FAN_MARK_IGNORE),
205f08c3bdfSopenharmony_ci		.mask = FLAGS_DESC(FAN_OPEN),
206f08c3bdfSopenharmony_ci		.expected_errno = EISDIR,
207f08c3bdfSopenharmony_ci	},
208f08c3bdfSopenharmony_ci
209f08c3bdfSopenharmony_ci	/* FAN_MARK_IGNORE without FAN_MARK_IGNORED_SURV_MODIFY on mount mark is not valid */
210f08c3bdfSopenharmony_ci	{
211f08c3bdfSopenharmony_ci		.init = FLAGS_DESC(FAN_CLASS_NOTIF),
212f08c3bdfSopenharmony_ci		.mark = FLAGS_DESC(FAN_MARK_MOUNT | FAN_MARK_IGNORE),
213f08c3bdfSopenharmony_ci		.mask = FLAGS_DESC(FAN_OPEN),
214f08c3bdfSopenharmony_ci		.expected_errno = EINVAL,
215f08c3bdfSopenharmony_ci	},
216f08c3bdfSopenharmony_ci
217f08c3bdfSopenharmony_ci	/* FAN_MARK_IGNORE without FAN_MARK_IGNORED_SURV_MODIFY on filesystem mark is not valid */
218f08c3bdfSopenharmony_ci	{
219f08c3bdfSopenharmony_ci		.init = FLAGS_DESC(FAN_CLASS_NOTIF),
220f08c3bdfSopenharmony_ci		.mark = FLAGS_DESC(FAN_MARK_FILESYSTEM | FAN_MARK_IGNORE),
221f08c3bdfSopenharmony_ci		.mask = FLAGS_DESC(FAN_OPEN),
222f08c3bdfSopenharmony_ci		.expected_errno = EINVAL,
223f08c3bdfSopenharmony_ci	},
224f08c3bdfSopenharmony_ci	/* mount mark on anonymous pipe is not valid */
225f08c3bdfSopenharmony_ci	{
226f08c3bdfSopenharmony_ci		.init = FLAGS_DESC(FAN_CLASS_NOTIF),
227f08c3bdfSopenharmony_ci		.mark = FLAGS_DESC(FAN_MARK_MOUNT),
228f08c3bdfSopenharmony_ci		.mask = { FAN_ACCESS, "anonymous pipe"},
229f08c3bdfSopenharmony_ci		.pfd = pipes,
230f08c3bdfSopenharmony_ci		.expected_errno = EINVAL,
231f08c3bdfSopenharmony_ci	},
232f08c3bdfSopenharmony_ci	/* filesystem mark on anonymous pipe is not valid */
233f08c3bdfSopenharmony_ci	{
234f08c3bdfSopenharmony_ci		.init = FLAGS_DESC(FAN_CLASS_NOTIF),
235f08c3bdfSopenharmony_ci		.mark = FLAGS_DESC(FAN_MARK_FILESYSTEM),
236f08c3bdfSopenharmony_ci		.mask = { FAN_ACCESS, "anonymous pipe"},
237f08c3bdfSopenharmony_ci		.pfd = pipes,
238f08c3bdfSopenharmony_ci		.expected_errno = EINVAL,
239f08c3bdfSopenharmony_ci	},
240f08c3bdfSopenharmony_ci};
241f08c3bdfSopenharmony_ci
242f08c3bdfSopenharmony_cistatic void do_test(unsigned int number)
243f08c3bdfSopenharmony_ci{
244f08c3bdfSopenharmony_ci	struct test_case_t *tc = &test_cases[number];
245f08c3bdfSopenharmony_ci
246f08c3bdfSopenharmony_ci	tst_res(TINFO, "Test case %d: fanotify_init(%s, O_RDONLY)", number,
247f08c3bdfSopenharmony_ci		tc->init.desc);
248f08c3bdfSopenharmony_ci
249f08c3bdfSopenharmony_ci	if (fan_report_target_fid_unsupported && tc->init.flags & FAN_REPORT_TARGET_FID) {
250f08c3bdfSopenharmony_ci		FANOTIFY_INIT_FLAGS_ERR_MSG(FAN_REPORT_TARGET_FID,
251f08c3bdfSopenharmony_ci					    fan_report_target_fid_unsupported);
252f08c3bdfSopenharmony_ci		return;
253f08c3bdfSopenharmony_ci	}
254f08c3bdfSopenharmony_ci
255f08c3bdfSopenharmony_ci	if (ignore_mark_unsupported && tc->mark.flags & FAN_MARK_IGNORE) {
256f08c3bdfSopenharmony_ci		tst_res(TCONF, "FAN_MARK_IGNORE not supported in kernel?");
257f08c3bdfSopenharmony_ci		return;
258f08c3bdfSopenharmony_ci	}
259f08c3bdfSopenharmony_ci
260f08c3bdfSopenharmony_ci	if (!tc->mask.flags && tc->expected_errno) {
261f08c3bdfSopenharmony_ci		TST_EXP_FAIL(fanotify_init(tc->init.flags, O_RDONLY),
262f08c3bdfSopenharmony_ci			tc->expected_errno);
263f08c3bdfSopenharmony_ci	} else {
264f08c3bdfSopenharmony_ci		TST_EXP_FD(fanotify_init(tc->init.flags, O_RDONLY));
265f08c3bdfSopenharmony_ci	}
266f08c3bdfSopenharmony_ci
267f08c3bdfSopenharmony_ci	fanotify_fd = TST_RET;
268f08c3bdfSopenharmony_ci
269f08c3bdfSopenharmony_ci	if (fanotify_fd < 0)
270f08c3bdfSopenharmony_ci		return;
271f08c3bdfSopenharmony_ci
272f08c3bdfSopenharmony_ci	if (!tc->mask.flags)
273f08c3bdfSopenharmony_ci		goto out;
274f08c3bdfSopenharmony_ci
275f08c3bdfSopenharmony_ci	/* Set mark on non-dir only when expecting error ENOTDIR */
276f08c3bdfSopenharmony_ci	const char *path = tc->expected_errno == ENOTDIR ? FILE1 : MNTPOINT;
277f08c3bdfSopenharmony_ci	int dirfd = AT_FDCWD;
278f08c3bdfSopenharmony_ci
279f08c3bdfSopenharmony_ci	if (tc->pfd) {
280f08c3bdfSopenharmony_ci		dirfd = tc->pfd[0];
281f08c3bdfSopenharmony_ci		path = NULL;
282f08c3bdfSopenharmony_ci	}
283f08c3bdfSopenharmony_ci
284f08c3bdfSopenharmony_ci	tst_res(TINFO, "Testing %s with %s",
285f08c3bdfSopenharmony_ci		tc->mark.desc, tc->mask.desc);
286f08c3bdfSopenharmony_ci	TST_EXP_FD_OR_FAIL(fanotify_mark(fanotify_fd, FAN_MARK_ADD | tc->mark.flags,
287f08c3bdfSopenharmony_ci					 tc->mask.flags, dirfd, path),
288f08c3bdfSopenharmony_ci					 tc->expected_errno);
289f08c3bdfSopenharmony_ci
290f08c3bdfSopenharmony_ci	/*
291f08c3bdfSopenharmony_ci	 * ENOTDIR are errors for events/flags not allowed on a non-dir inode.
292f08c3bdfSopenharmony_ci	 * Try to set an inode mark on a directory and it should succeed.
293f08c3bdfSopenharmony_ci	 * Try to set directory events in filesystem mark mask on non-dir
294f08c3bdfSopenharmony_ci	 * and it should succeed.
295f08c3bdfSopenharmony_ci	 */
296f08c3bdfSopenharmony_ci	if (TST_PASS && tc->expected_errno == ENOTDIR) {
297f08c3bdfSopenharmony_ci		SAFE_FANOTIFY_MARK(fanotify_fd, FAN_MARK_ADD | tc->mark.flags,
298f08c3bdfSopenharmony_ci				   tc->mask.flags, AT_FDCWD, MNTPOINT);
299f08c3bdfSopenharmony_ci		tst_res(TPASS,
300f08c3bdfSopenharmony_ci			"Adding an inode mark on directory did not fail with "
301f08c3bdfSopenharmony_ci			"ENOTDIR error as on non-dir inode");
302f08c3bdfSopenharmony_ci
303f08c3bdfSopenharmony_ci		if (!(tc->mark.flags & FAN_MARK_ONLYDIR)) {
304f08c3bdfSopenharmony_ci			SAFE_FANOTIFY_MARK(fanotify_fd, FAN_MARK_ADD | tc->mark.flags |
305f08c3bdfSopenharmony_ci					   FAN_MARK_FILESYSTEM, tc->mask.flags,
306f08c3bdfSopenharmony_ci					   AT_FDCWD, FILE1);
307f08c3bdfSopenharmony_ci			tst_res(TPASS,
308f08c3bdfSopenharmony_ci				"Adding a filesystem mark on non-dir did not fail with "
309f08c3bdfSopenharmony_ci				"ENOTDIR error as with an inode mark");
310f08c3bdfSopenharmony_ci		}
311f08c3bdfSopenharmony_ci	}
312f08c3bdfSopenharmony_ci
313f08c3bdfSopenharmony_ciout:
314f08c3bdfSopenharmony_ci	if (fanotify_fd > 0)
315f08c3bdfSopenharmony_ci		SAFE_CLOSE(fanotify_fd);
316f08c3bdfSopenharmony_ci}
317f08c3bdfSopenharmony_ci
318f08c3bdfSopenharmony_cistatic void do_setup(void)
319f08c3bdfSopenharmony_ci{
320f08c3bdfSopenharmony_ci	/* Require FAN_REPORT_FID support for all tests to simplify per test case requirements */
321f08c3bdfSopenharmony_ci	REQUIRE_FANOTIFY_INIT_FLAGS_SUPPORTED_ON_FS(FAN_REPORT_FID, MNTPOINT);
322f08c3bdfSopenharmony_ci
323f08c3bdfSopenharmony_ci	fan_report_target_fid_unsupported =
324f08c3bdfSopenharmony_ci		fanotify_init_flags_supported_on_fs(FAN_REPORT_DFID_NAME_TARGET, MNTPOINT);
325f08c3bdfSopenharmony_ci	ignore_mark_unsupported = fanotify_mark_supported_by_kernel(FAN_MARK_IGNORE_SURV);
326f08c3bdfSopenharmony_ci
327f08c3bdfSopenharmony_ci	/* Create temporary test file to place marks on */
328f08c3bdfSopenharmony_ci	SAFE_FILE_PRINTF(FILE1, "0");
329f08c3bdfSopenharmony_ci	/* Create anonymous pipes to place marks on */
330f08c3bdfSopenharmony_ci	SAFE_PIPE2(pipes, O_CLOEXEC);
331f08c3bdfSopenharmony_ci}
332f08c3bdfSopenharmony_ci
333f08c3bdfSopenharmony_cistatic void do_cleanup(void)
334f08c3bdfSopenharmony_ci{
335f08c3bdfSopenharmony_ci	if (fanotify_fd > 0)
336f08c3bdfSopenharmony_ci		SAFE_CLOSE(fanotify_fd);
337f08c3bdfSopenharmony_ci	if (pipes[0] != -1)
338f08c3bdfSopenharmony_ci		SAFE_CLOSE(pipes[0]);
339f08c3bdfSopenharmony_ci	if (pipes[1] != -1)
340f08c3bdfSopenharmony_ci		SAFE_CLOSE(pipes[1]);
341f08c3bdfSopenharmony_ci}
342f08c3bdfSopenharmony_ci
343f08c3bdfSopenharmony_cistatic struct tst_test test = {
344f08c3bdfSopenharmony_ci	.needs_root = 1,
345f08c3bdfSopenharmony_ci	.test = do_test,
346f08c3bdfSopenharmony_ci	.tcnt = ARRAY_SIZE(test_cases),
347f08c3bdfSopenharmony_ci	.setup = do_setup,
348f08c3bdfSopenharmony_ci	.cleanup = do_cleanup,
349f08c3bdfSopenharmony_ci	.mount_device = 1,
350f08c3bdfSopenharmony_ci	.mntpoint = MNTPOINT,
351f08c3bdfSopenharmony_ci	.all_filesystems = 1,
352f08c3bdfSopenharmony_ci	.tags = (const struct tst_tag[]) {
353f08c3bdfSopenharmony_ci		{"linux-git", "ceaf69f8eadc"},
354f08c3bdfSopenharmony_ci		{"linux-git", "8698e3bab4dd"},
355f08c3bdfSopenharmony_ci		{"linux-git", "69562eb0bd3e"},
356f08c3bdfSopenharmony_ci		{}
357f08c3bdfSopenharmony_ci	}
358f08c3bdfSopenharmony_ci};
359f08c3bdfSopenharmony_ci
360f08c3bdfSopenharmony_ci#else
361f08c3bdfSopenharmony_ci	TST_TEST_TCONF("System does not have required fanotify support");
362f08c3bdfSopenharmony_ci#endif
363