1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0
2f08c3bdfSopenharmony_ci/*
3f08c3bdfSopenharmony_ci * Copyright (c) 2021 CTERA Networks. All Rights Reserved.
4f08c3bdfSopenharmony_ci *
5f08c3bdfSopenharmony_ci * Started by Amir Goldstein <amir73il@gmail.com>
6f08c3bdfSopenharmony_ci */
7f08c3bdfSopenharmony_ci
8f08c3bdfSopenharmony_ci/*\
9f08c3bdfSopenharmony_ci * [Description]
10f08c3bdfSopenharmony_ci *
11f08c3bdfSopenharmony_ci * Check that dnotify DN_RENAME event is reported only on rename inside same parent.
12f08c3bdfSopenharmony_ci */
13f08c3bdfSopenharmony_ci
14f08c3bdfSopenharmony_ci#include <fcntl.h>
15f08c3bdfSopenharmony_ci#include <signal.h>
16f08c3bdfSopenharmony_ci#include <stdio.h>
17f08c3bdfSopenharmony_ci#include <unistd.h>
18f08c3bdfSopenharmony_ci#include "tst_test.h"
19f08c3bdfSopenharmony_ci#include "lapi/fcntl.h"
20f08c3bdfSopenharmony_ci
21f08c3bdfSopenharmony_ci#define	TEST_DIR	"test_dir"
22f08c3bdfSopenharmony_ci#define	TEST_DIR2	"test_dir2"
23f08c3bdfSopenharmony_ci#define	TEST_FILE	"test_file"
24f08c3bdfSopenharmony_ci
25f08c3bdfSopenharmony_ci#define TEST_SIG (SIGRTMIN+1)
26f08c3bdfSopenharmony_ci
27f08c3bdfSopenharmony_cistatic int parent_fd, subdir_fd;
28f08c3bdfSopenharmony_cistatic int got_parent_event, got_subdir_event;
29f08c3bdfSopenharmony_ci
30f08c3bdfSopenharmony_cistatic void dnotify_handler(int sig, siginfo_t *si, void *data LTP_ATTRIBUTE_UNUSED)
31f08c3bdfSopenharmony_ci{
32f08c3bdfSopenharmony_ci	if (si->si_fd == parent_fd)
33f08c3bdfSopenharmony_ci		got_parent_event = 1;
34f08c3bdfSopenharmony_ci	else if (si->si_fd == subdir_fd)
35f08c3bdfSopenharmony_ci		got_subdir_event = 1;
36f08c3bdfSopenharmony_ci	else
37f08c3bdfSopenharmony_ci		tst_brk(TBROK, "Got unexpected signal %d with si_fd %d", sig, si->si_fd);
38f08c3bdfSopenharmony_ci}
39f08c3bdfSopenharmony_ci
40f08c3bdfSopenharmony_cistatic void setup_dnotify(int fd)
41f08c3bdfSopenharmony_ci{
42f08c3bdfSopenharmony_ci	struct sigaction act;
43f08c3bdfSopenharmony_ci
44f08c3bdfSopenharmony_ci	act.sa_sigaction = dnotify_handler;
45f08c3bdfSopenharmony_ci	sigemptyset(&act.sa_mask);
46f08c3bdfSopenharmony_ci	act.sa_flags = SA_SIGINFO;
47f08c3bdfSopenharmony_ci	sigaction(TEST_SIG, &act, NULL);
48f08c3bdfSopenharmony_ci
49f08c3bdfSopenharmony_ci	TEST(fcntl(fd, F_SETSIG, TEST_SIG));
50f08c3bdfSopenharmony_ci	if (TST_RET != 0) {
51f08c3bdfSopenharmony_ci		tst_brk(TBROK, "F_SETSIG failed errno = %d : %s",
52f08c3bdfSopenharmony_ci			TST_ERR, strerror(TST_ERR));
53f08c3bdfSopenharmony_ci	}
54f08c3bdfSopenharmony_ci
55f08c3bdfSopenharmony_ci	TEST(fcntl(fd, F_NOTIFY, DN_RENAME|DN_MULTISHOT));
56f08c3bdfSopenharmony_ci	if (TST_RET != 0) {
57f08c3bdfSopenharmony_ci		tst_brk(TBROK, "F_NOTIFY failed errno = %d : %s",
58f08c3bdfSopenharmony_ci			TST_ERR, strerror(TST_ERR));
59f08c3bdfSopenharmony_ci	}
60f08c3bdfSopenharmony_ci}
61f08c3bdfSopenharmony_ci
62f08c3bdfSopenharmony_cistatic void verify_dnotify(void)
63f08c3bdfSopenharmony_ci{
64f08c3bdfSopenharmony_ci	parent_fd = SAFE_OPEN(".", O_RDONLY);
65f08c3bdfSopenharmony_ci	subdir_fd = SAFE_OPEN(TEST_DIR, O_RDONLY);
66f08c3bdfSopenharmony_ci
67f08c3bdfSopenharmony_ci	/* Watch renames inside ".", but not in and out of "." */
68f08c3bdfSopenharmony_ci	setup_dnotify(parent_fd);
69f08c3bdfSopenharmony_ci
70f08c3bdfSopenharmony_ci	/* Also watch for renames inside subdir, but not in and out of subdir */
71f08c3bdfSopenharmony_ci	setup_dnotify(subdir_fd);
72f08c3bdfSopenharmony_ci
73f08c3bdfSopenharmony_ci	/* Rename file from "." to subdir should not generate DN_RENAME on either */
74f08c3bdfSopenharmony_ci	tst_res(TINFO, "Testing no DN_RENAME on rename from parent to subdir");
75f08c3bdfSopenharmony_ci	SAFE_RENAME(TEST_FILE, TEST_DIR "/" TEST_FILE);
76f08c3bdfSopenharmony_ci
77f08c3bdfSopenharmony_ci	if (got_parent_event)
78f08c3bdfSopenharmony_ci		tst_res(TFAIL, "Got unexpected event on parent");
79f08c3bdfSopenharmony_ci	else
80f08c3bdfSopenharmony_ci		tst_res(TPASS, "No event on parent as expected");
81f08c3bdfSopenharmony_ci
82f08c3bdfSopenharmony_ci	if (got_subdir_event)
83f08c3bdfSopenharmony_ci		tst_res(TFAIL, "Got unexpected event on subdir");
84f08c3bdfSopenharmony_ci	else
85f08c3bdfSopenharmony_ci		tst_res(TPASS, "No event on subdir as expected");
86f08c3bdfSopenharmony_ci
87f08c3bdfSopenharmony_ci	/* Rename subdir itself should generate DN_RENAME on ".", but not on itself */
88f08c3bdfSopenharmony_ci	tst_res(TINFO, "Testing DN_RENAME on rename of subdir itself");
89f08c3bdfSopenharmony_ci	SAFE_RENAME(TEST_DIR, TEST_DIR2);
90f08c3bdfSopenharmony_ci
91f08c3bdfSopenharmony_ci	if (got_parent_event)
92f08c3bdfSopenharmony_ci		tst_res(TPASS, "Got event on parent as expected");
93f08c3bdfSopenharmony_ci	else
94f08c3bdfSopenharmony_ci		tst_res(TFAIL, "Missing event on parent");
95f08c3bdfSopenharmony_ci
96f08c3bdfSopenharmony_ci	if (got_subdir_event)
97f08c3bdfSopenharmony_ci		tst_res(TFAIL, "Got unexpected event on subdir");
98f08c3bdfSopenharmony_ci	else
99f08c3bdfSopenharmony_ci		tst_res(TPASS, "No event on subdir as expected");
100f08c3bdfSopenharmony_ci
101f08c3bdfSopenharmony_ci	SAFE_CLOSE(parent_fd);
102f08c3bdfSopenharmony_ci	SAFE_CLOSE(subdir_fd);
103f08c3bdfSopenharmony_ci
104f08c3bdfSopenharmony_ci	/* Cleanup before rerun */
105f08c3bdfSopenharmony_ci	SAFE_RENAME(TEST_DIR2 "/" TEST_FILE, TEST_FILE);
106f08c3bdfSopenharmony_ci	SAFE_RENAME(TEST_DIR2, TEST_DIR);
107f08c3bdfSopenharmony_ci	got_parent_event = 0;
108f08c3bdfSopenharmony_ci	got_subdir_event = 0;
109f08c3bdfSopenharmony_ci}
110f08c3bdfSopenharmony_ci
111f08c3bdfSopenharmony_cistatic void setup(void)
112f08c3bdfSopenharmony_ci{
113f08c3bdfSopenharmony_ci	SAFE_MKDIR(TEST_DIR, 00700);
114f08c3bdfSopenharmony_ci	SAFE_TOUCH(TEST_FILE, 0666, NULL);
115f08c3bdfSopenharmony_ci}
116f08c3bdfSopenharmony_ci
117f08c3bdfSopenharmony_cistatic void cleanup(void)
118f08c3bdfSopenharmony_ci{
119f08c3bdfSopenharmony_ci	if (parent_fd > 0)
120f08c3bdfSopenharmony_ci		SAFE_CLOSE(parent_fd);
121f08c3bdfSopenharmony_ci
122f08c3bdfSopenharmony_ci	if (subdir_fd > 0)
123f08c3bdfSopenharmony_ci		SAFE_CLOSE(subdir_fd);
124f08c3bdfSopenharmony_ci}
125f08c3bdfSopenharmony_ci
126f08c3bdfSopenharmony_cistatic struct tst_test test = {
127f08c3bdfSopenharmony_ci	.needs_tmpdir = 1,
128f08c3bdfSopenharmony_ci	.setup = setup,
129f08c3bdfSopenharmony_ci	.cleanup = cleanup,
130f08c3bdfSopenharmony_ci	.test_all = verify_dnotify,
131f08c3bdfSopenharmony_ci	.needs_kconfigs = (const char *[]) { "CONFIG_DNOTIFY=y", NULL },
132f08c3bdfSopenharmony_ci};
133