• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2013 SUSE.  All Rights Reserved.
4  *
5  * Started by Jan Kara <jack@suse.cz>
6  */
7 
8 /*\
9  * [Description]
10  * Check that fanotify work for children of a directory.
11  */
12 
13 #define _GNU_SOURCE
14 #include "config.h"
15 
16 #include <stdio.h>
17 #include <sys/stat.h>
18 #include <sys/types.h>
19 #include <errno.h>
20 #include <string.h>
21 #include <sys/syscall.h>
22 #include "tst_test.h"
23 
24 #ifdef HAVE_SYS_FANOTIFY_H
25 #include "fanotify.h"
26 
27 #define EVENT_MAX 1024
28 /* size of the event structure, not counting name */
29 #define EVENT_SIZE  (sizeof (struct fanotify_event_metadata))
30 /* reasonable guess as to size of 1024 events */
31 #define EVENT_BUF_LEN        (EVENT_MAX * EVENT_SIZE)
32 
33 #define BUF_SIZE 256
34 #define TST_TOTAL 8
35 
36 static char fname[BUF_SIZE];
37 static char buf[BUF_SIZE];
38 static int fd, fd_notify;
39 
40 static unsigned long long event_set[EVENT_MAX];
41 
42 static char event_buf[EVENT_BUF_LEN];
43 
test01(void)44 void test01(void)
45 {
46 	int ret, len, i = 0, test_num = 0;
47 
48 	int tst_count = 0;
49 
50 	SAFE_FANOTIFY_MARK(fd_notify, FAN_MARK_ADD, FAN_ACCESS |
51 			  FAN_MODIFY | FAN_CLOSE | FAN_OPEN | FAN_EVENT_ON_CHILD |
52 			  FAN_ONDIR, AT_FDCWD, ".");
53 
54 	/*
55 	 * generate sequence of events
56 	 */
57 	fd = SAFE_OPEN(fname, O_RDWR | O_CREAT, 0700);
58 	event_set[tst_count] = FAN_OPEN;
59 	tst_count++;
60 
61 	SAFE_WRITE(1, fd, fname, strlen(fname));
62 	event_set[tst_count] = FAN_MODIFY;
63 	tst_count++;
64 
65 	SAFE_CLOSE(fd);
66 	event_set[tst_count] = FAN_CLOSE_WRITE;
67 	tst_count++;
68 
69 	/*
70 	 * Get list of events so far. We get events here to avoid
71 	 * merging of following events with the previous ones.
72 	 */
73 	ret = SAFE_READ(0, fd_notify, event_buf,
74 			EVENT_BUF_LEN);
75 	len = ret;
76 
77 	fd = SAFE_OPEN(fname, O_RDONLY);
78 	event_set[tst_count] = FAN_OPEN;
79 	tst_count++;
80 
81 	SAFE_READ(0, fd, buf, BUF_SIZE);
82 	event_set[tst_count] = FAN_ACCESS;
83 	tst_count++;
84 
85 	SAFE_CLOSE(fd);
86 	event_set[tst_count] = FAN_CLOSE_NOWRITE;
87 	tst_count++;
88 
89 	/*
90 	 * get next events
91 	 */
92 	ret = SAFE_READ(0, fd_notify, event_buf + len,
93 			EVENT_BUF_LEN - len);
94 	len += ret;
95 
96 	/*
97 	 * now remove child mark
98 	 */
99 	SAFE_FANOTIFY_MARK(fd_notify, FAN_MARK_REMOVE,
100 			  FAN_EVENT_ON_CHILD, AT_FDCWD, ".");
101 
102 	/*
103 	 * Do something to verify events didn't get generated
104 	 */
105 	fd = SAFE_OPEN(fname, O_RDONLY);
106 
107 	SAFE_CLOSE(fd);
108 
109 	fd = SAFE_OPEN(".", O_RDONLY | O_DIRECTORY);
110 	event_set[tst_count] = FAN_OPEN;
111 	tst_count++;
112 
113 	SAFE_CLOSE(fd);
114 	event_set[tst_count] = FAN_CLOSE_NOWRITE;
115 	tst_count++;
116 
117 	/*
118 	 * Check events got generated only for the directory
119 	 */
120 	ret = SAFE_READ(0, fd_notify, event_buf + len,
121 			EVENT_BUF_LEN - len);
122 	len += ret;
123 
124 	if (TST_TOTAL != tst_count) {
125 		tst_brk(TBROK,
126 			"TST_TOTAL and tst_count are not equal");
127 	}
128 	tst_count = 0;
129 
130 	/*
131 	 * check events
132 	 */
133 	while (i < len) {
134 		struct fanotify_event_metadata *event;
135 
136 		event = (struct fanotify_event_metadata *)&event_buf[i];
137 		if (test_num >= TST_TOTAL) {
138 			tst_res(TFAIL,
139 				"get unnecessary event: mask=%llx "
140 				"pid=%u fd=%d",
141 				(unsigned long long)event->mask,
142 				(unsigned)event->pid, event->fd);
143 		} else if (!(event->mask & event_set[test_num])) {
144 			tst_res(TFAIL,
145 				"got event: mask=%llx (expected %llx) "
146 				"pid=%u fd=%d",
147 				(unsigned long long)event->mask,
148 				event_set[test_num],
149 				(unsigned)event->pid, event->fd);
150 		} else if (event->pid != getpid()) {
151 			tst_res(TFAIL,
152 				"got event: mask=%llx pid=%u "
153 				"(expected %u) fd=%d",
154 				(unsigned long long)event->mask,
155 				(unsigned)event->pid,
156 				(unsigned)getpid(),
157 				event->fd);
158 		} else {
159 			tst_res(TPASS,
160 				"got event: mask=%llx pid=%u fd=%u",
161 				(unsigned long long)event->mask,
162 				(unsigned)event->pid, event->fd);
163 		}
164 		event->mask &= ~event_set[test_num];
165 		/* No events left in current mask? Go for next event */
166 		if (event->mask == 0) {
167 			i += event->event_len;
168 			if (event->fd != FAN_NOFD)
169 				SAFE_CLOSE(event->fd);
170 		}
171 		test_num++;
172 	}
173 	for (; test_num < TST_TOTAL; test_num++) {
174 		tst_res(TFAIL, "didn't get event: mask=%llx",
175 			event_set[test_num]);
176 
177 	}
178 }
179 
setup(void)180 static void setup(void)
181 {
182 	sprintf(fname, "fname_%d", getpid());
183 	fd_notify = SAFE_FANOTIFY_INIT(FAN_CLASS_NOTIF, O_RDONLY);
184 }
185 
cleanup(void)186 static void cleanup(void)
187 {
188 	if (fd_notify > 0)
189 		SAFE_CLOSE(fd_notify);
190 }
191 
192 static struct tst_test test = {
193 	.test_all = test01,
194 	.setup = setup,
195 	.cleanup = cleanup,
196 	.needs_tmpdir = 1,
197 	.needs_root = 1
198 };
199 
200 #else
201 	TST_TEST_TCONF("system doesn't have required fanotify support");
202 #endif
203