• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2013 SUSE.  All Rights Reserved.
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms of version 2 of the GNU General Public License as
6  * published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it would be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11  *
12  * Further, this software is distributed without any warranty that it is
13  * free of the rightful claim of any third person regarding infringement
14  * or the like.  Any license provided herein, whether implied or
15  * otherwise, applies only to this software file.  Patent licenses, if
16  * any, provided herein do not apply to combinations of this program with
17  * other software, or any other product whatsoever.
18  *
19  * You should have received a copy of the GNU General Public License along
20  * with this program; if not, write the Free Software Foundation, Inc.,
21  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22  *
23  * Started by Jan Kara <jack@suse.cz>
24  *
25  * DESCRIPTION
26  *     Check that fanotify work for children of a directory
27  */
28 #define _GNU_SOURCE
29 #include "config.h"
30 
31 #include <stdio.h>
32 #include <sys/stat.h>
33 #include <sys/types.h>
34 #include <sys/fcntl.h>
35 #include <errno.h>
36 #include <string.h>
37 #include <sys/syscall.h>
38 #include "test.h"
39 #include "linux_syscall_numbers.h"
40 #include "fanotify.h"
41 #include "safe_macros.h"
42 
43 char *TCID = "fanotify02";
44 int TST_TOTAL = 8;
45 
46 #if defined(HAVE_SYS_FANOTIFY_H)
47 #include <sys/fanotify.h>
48 
49 #define EVENT_MAX 1024
50 /* size of the event structure, not counting name */
51 #define EVENT_SIZE  (sizeof (struct fanotify_event_metadata))
52 /* reasonable guess as to size of 1024 events */
53 #define EVENT_BUF_LEN        (EVENT_MAX * EVENT_SIZE)
54 
55 static void setup(void);
56 static void cleanup(void);
57 
58 #define BUF_SIZE 256
59 static char fname[BUF_SIZE];
60 static char buf[BUF_SIZE];
61 static int fd, fd_notify;
62 
63 static unsigned long long event_set[EVENT_MAX];
64 
65 static char event_buf[EVENT_BUF_LEN];
66 
main(int ac,char ** av)67 int main(int ac, char **av)
68 {
69 	int lc;
70 
71 	tst_parse_opts(ac, av, NULL, NULL);
72 
73 	setup();
74 
75 	for (lc = 0; TEST_LOOPING(lc); lc++) {
76 		int ret, len, i = 0, test_num = 0;
77 
78 		tst_count = 0;
79 
80 		if (fanotify_mark(fd_notify, FAN_MARK_ADD, FAN_ACCESS |
81 				    FAN_MODIFY | FAN_CLOSE | FAN_OPEN |
82 				    FAN_EVENT_ON_CHILD | FAN_ONDIR, AT_FDCWD,
83 				  ".") < 0) {
84 			tst_brkm(TBROK | TERRNO, cleanup,
85 			    "fanotify_mark (%d, FAN_MARK_ADD, FAN_ACCESS | "
86 			    "FAN_MODIFY | FAN_CLOSE | FAN_OPEN | "
87 			    "FAN_EVENT_ON_CHILD | FAN_ONDIR, AT_FDCWD, '.') "
88 			    "failed", fd_notify);
89 		}
90 
91 		/*
92 		 * generate sequence of events
93 		 */
94 		fd = SAFE_OPEN(cleanup, fname, O_RDWR | O_CREAT, 0700);
95 		event_set[tst_count] = FAN_OPEN;
96 		tst_count++;
97 
98 		SAFE_WRITE(cleanup, 1, fd, fname, strlen(fname));
99 		event_set[tst_count] = FAN_MODIFY;
100 		tst_count++;
101 
102 		SAFE_CLOSE(cleanup, fd);
103 		event_set[tst_count] = FAN_CLOSE_WRITE;
104 		tst_count++;
105 
106 		/*
107 		 * Get list of events so far. We get events here to avoid
108 		 * merging of following events with the previous ones.
109 		 */
110 		ret = SAFE_READ(cleanup, 0, fd_notify, event_buf,
111 				EVENT_BUF_LEN);
112 		len = ret;
113 
114 		fd = SAFE_OPEN(cleanup, fname, O_RDONLY);
115 		event_set[tst_count] = FAN_OPEN;
116 		tst_count++;
117 
118 		SAFE_READ(cleanup, 0, fd, buf, BUF_SIZE);
119 		event_set[tst_count] = FAN_ACCESS;
120 		tst_count++;
121 
122 		SAFE_CLOSE(cleanup, fd);
123 		event_set[tst_count] = FAN_CLOSE_NOWRITE;
124 		tst_count++;
125 
126 		/*
127 		 * get next events
128 		 */
129 		ret = SAFE_READ(cleanup, 0, fd_notify, event_buf + len,
130 				EVENT_BUF_LEN - len);
131 		len += ret;
132 
133 		/*
134 		 * now remove child mark
135 		 */
136 		if (fanotify_mark(fd_notify, FAN_MARK_REMOVE,
137 				    FAN_EVENT_ON_CHILD, AT_FDCWD, ".") < 0) {
138 			tst_brkm(TBROK | TERRNO, cleanup,
139 			    "fanotify_mark (%d, FAN_MARK REMOVE, "
140 			    "FAN_EVENT_ON_CHILD, AT_FDCWD, '.') failed",
141 			    fd_notify);
142 		}
143 
144 		/*
145 		 * Do something to verify events didn't get generated
146 		 */
147 		fd = SAFE_OPEN(cleanup, fname, O_RDONLY);
148 
149 		SAFE_CLOSE(cleanup, fd);
150 
151 		fd = SAFE_OPEN(cleanup, ".", O_RDONLY | O_DIRECTORY);
152 		event_set[tst_count] = FAN_OPEN;
153 		tst_count++;
154 
155 		SAFE_CLOSE(cleanup, fd);
156 		event_set[tst_count] = FAN_CLOSE_NOWRITE;
157 		tst_count++;
158 
159 		/*
160 		 * Check events got generated only for the directory
161 		 */
162 		ret = SAFE_READ(cleanup, 0, fd_notify, event_buf + len,
163 				EVENT_BUF_LEN - len);
164 		len += ret;
165 
166 		if (TST_TOTAL != tst_count) {
167 			tst_brkm(TBROK, cleanup,
168 				 "TST_TOTAL and tst_count are not equal");
169 		}
170 		tst_count = 0;
171 
172 		/*
173 		 * check events
174 		 */
175 		while (i < len) {
176 			struct fanotify_event_metadata *event;
177 
178 			event = (struct fanotify_event_metadata *)&event_buf[i];
179 			if (test_num >= TST_TOTAL) {
180 				tst_resm(TFAIL,
181 					 "get unnecessary event: mask=%llx "
182 					 "pid=%u fd=%u",
183 					 (unsigned long long)event->mask,
184 					 (unsigned)event->pid, event->fd);
185 			} else if (!(event->mask & event_set[test_num])) {
186 				tst_resm(TFAIL,
187 					 "get event: mask=%llx (expected %llx) "
188 					 "pid=%u fd=%u",
189 					 (unsigned long long)event->mask,
190 					 event_set[test_num],
191 					 (unsigned)event->pid, event->fd);
192 			} else if (event->pid != getpid()) {
193 				tst_resm(TFAIL,
194 					 "get event: mask=%llx pid=%u "
195 					 "(expected %u) fd=%u",
196 					 (unsigned long long)event->mask,
197 					 (unsigned)event->pid,
198 					 (unsigned)getpid(),
199 					 event->fd);
200 			} else {
201 				tst_resm(TPASS,
202 					    "get event: mask=%llx pid=%u fd=%u",
203 					    (unsigned long long)event->mask,
204 					    (unsigned)event->pid, event->fd);
205 			}
206 			event->mask &= ~event_set[test_num];
207 			/* No events left in current mask? Go for next event */
208 			if (event->mask == 0) {
209 				i += event->event_len;
210 				close(event->fd);
211 			}
212 			test_num++;
213 		}
214 		for (; test_num < TST_TOTAL; test_num++) {
215 			tst_resm(TFAIL, "didn't get event: mask=%llx",
216 				 event_set[test_num]);
217 
218 		}
219 	}
220 
221 	cleanup();
222 	tst_exit();
223 }
224 
setup(void)225 static void setup(void)
226 {
227 	tst_sig(NOFORK, DEF_HANDLER, cleanup);
228 
229 	TEST_PAUSE;
230 
231 	tst_tmpdir();
232 	sprintf(fname, "fname_%d", getpid());
233 
234 	if ((fd_notify = fanotify_init(FAN_CLASS_NOTIF, O_RDONLY)) < 0) {
235 		if (errno == ENOSYS) {
236 			tst_brkm(TCONF, cleanup,
237 				 "fanotify is not configured in this kernel.");
238 		} else {
239 			tst_brkm(TBROK | TERRNO, cleanup,
240 				 "fanotify_init failed");
241 		}
242 	}
243 }
244 
cleanup(void)245 static void cleanup(void)
246 {
247 	if (fd_notify > 0 && close(fd_notify))
248 		tst_resm(TWARN | TERRNO, "close(%d) failed", fd_notify);
249 
250 	tst_rmdir();
251 }
252 
253 #else
254 
main(void)255 int main(void)
256 {
257 	tst_brkm(TCONF, NULL, "system doesn't have required fanotify support");
258 }
259 
260 #endif
261