xref: /aosp_15_r20/external/ltp/testcases/kernel/syscalls/fcntl/fcntl38.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  * DESCRIPTION
8  *     Check that dnotify event is reported to both parent and subdir
9  */
10 
11 #include <signal.h>
12 #include <stdio.h>
13 #include <unistd.h>
14 #include "tst_test.h"
15 #include "lapi/fcntl.h"
16 
17 #define	TEST_DIR	"test_dir"
18 
19 #define TEST_SIG SIGRTMIN+1
20 
21 static int parent_fd, subdir_fd;
22 static int got_parent_event, got_subdir_event;
23 
dnotify_handler(int sig,siginfo_t * si,void * data)24 static void dnotify_handler(int sig, siginfo_t *si, void *data __attribute__((unused)))
25 {
26 	if (si->si_fd == parent_fd)
27 		got_parent_event = 1;
28 	else if (si->si_fd == subdir_fd)
29 		got_subdir_event = 1;
30 	else
31 		tst_brk(TBROK, "Got unexpected signal %d with si_fd %d", sig, si->si_fd);
32 }
33 
setup_dnotify(int fd)34 static void setup_dnotify(int fd)
35 {
36 	struct sigaction act;
37 
38 	act.sa_sigaction = dnotify_handler;
39 	sigemptyset(&act.sa_mask);
40 	act.sa_flags = SA_SIGINFO;
41 	sigaction(TEST_SIG, &act, NULL);
42 
43 	TEST(fcntl(fd, F_SETSIG, TEST_SIG));
44 	if (TST_RET != 0) {
45 		tst_brk(TBROK, "F_SETSIG failed errno = %d : %s",
46 			TST_ERR, strerror(TST_ERR));
47 	}
48 	TEST(fcntl(fd, F_NOTIFY, DN_ATTRIB|DN_MULTISHOT));
49 	if (TST_RET != 0) {
50 		tst_brk(TBROK, "F_NOTIFY failed errno = %d : %s",
51 			TST_ERR, strerror(TST_ERR));
52 	}
53 }
54 
verify_dnotify(void)55 static void verify_dnotify(void)
56 {
57 	parent_fd = SAFE_OPEN(".", O_RDONLY);
58 	subdir_fd = SAFE_OPEN(TEST_DIR, O_RDONLY);
59 	/* Watch "." and its children for changes */
60 	setup_dnotify(parent_fd);
61 	/* Also watch subdir itself for changes */
62 	setup_dnotify(subdir_fd);
63 	/* Generate DN_ATTRIB event on subdir that should send a signal on both fds */
64 	SAFE_CHMOD(TEST_DIR, 0755);
65 	if (got_parent_event)
66 		tst_res(TPASS, "Got event on parent as expected");
67 	else
68 		tst_res(TFAIL, "Missing event on parent");
69 	if (got_subdir_event)
70 		tst_res(TPASS, "Got event on subdir as expected");
71 	else
72 		tst_res(TFAIL, "Missing event on subdir");
73 	SAFE_CLOSE(parent_fd);
74 	SAFE_CLOSE(subdir_fd);
75 }
76 
setup(void)77 static void setup(void)
78 {
79 	SAFE_MKDIR(TEST_DIR, 00700);
80 }
81 
cleanup(void)82 static void cleanup(void)
83 {
84 	if (parent_fd > 0)
85 		SAFE_CLOSE(parent_fd);
86 	if (subdir_fd > 0)
87 		SAFE_CLOSE(subdir_fd);
88 }
89 
90 static struct tst_test test = {
91 	.needs_tmpdir = 1,
92 	.setup = setup,
93 	.cleanup = cleanup,
94 	.test_all = verify_dnotify,
95 	.needs_kconfigs = (const char *[]) { "CONFIG_DNOTIFY=y", NULL },
96 };
97