blob: 9421d7192174023fafaf8489261b9e6b4f843a59 [file] [log] [blame]
Jan Karab432e8b2014-11-10 18:11:58 +01001/*
2 * Copyright (c) 2014 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 properly merges ignore mask of an inode and
27 * mountpoint.
28 */
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"
Jan Karab432e8b2014-11-10 18:11:58 +010039#include "linux_syscall_numbers.h"
40#include "fanotify.h"
41#include "safe_macros.h"
42
43char *TCID = "fanotify06";
44
45#if defined(HAVE_SYS_FANOTIFY_H)
46#include <sys/fanotify.h>
47
48#define EVENT_MAX 1024
49/* size of the event structure, not counting name */
50#define EVENT_SIZE (sizeof (struct fanotify_event_metadata))
51/* reasonable guess as to size of 1024 events */
52#define EVENT_BUF_LEN (EVENT_MAX * EVENT_SIZE)
53
54static void setup(void);
55static void cleanup(void);
56
57unsigned int fanotify_prio[] = {
58 FAN_CLASS_PRE_CONTENT,
59 FAN_CLASS_CONTENT,
60 FAN_CLASS_NOTIF
61};
62#define FANOTIFY_PRIORITIES ARRAY_SIZE(fanotify_prio)
63
64#define GROUPS_PER_PRIO 3
65
66int TST_TOTAL = GROUPS_PER_PRIO * FANOTIFY_PRIORITIES;
67
68#define BUF_SIZE 256
69static char fname[BUF_SIZE];
70static int fd;
71static int fd_notify[FANOTIFY_PRIORITIES][GROUPS_PER_PRIO];
72
73static char event_buf[EVENT_BUF_LEN];
74
75static void create_fanotify_groups(void)
76{
77 unsigned int p, i;
78 int ret;
79
80 for (p = 0; p < FANOTIFY_PRIORITIES; p++) {
81 for (i = 0; i < GROUPS_PER_PRIO; i++) {
82 fd_notify[p][i] = fanotify_init(fanotify_prio[p] |
83 FAN_NONBLOCK,
84 O_RDONLY);
85 if (fd_notify[p][i] < 0) {
86 if (errno == ENOSYS) {
87 tst_brkm(TCONF, cleanup,
88 "fanotify is not configured in"
89 " this kernel.");
90 } else {
91 tst_brkm(TBROK | TERRNO, cleanup,
92 "fanotify_init failed");
93 }
94 }
95 /* Add mount mark for each group */
96 ret = fanotify_mark(fd_notify[p][i],
97 FAN_MARK_ADD | FAN_MARK_MOUNT,
98 FAN_MODIFY,
99 AT_FDCWD, ".");
100 if (ret < 0) {
101 tst_brkm(TBROK | TERRNO, cleanup,
102 "fanotify_mark(%d, FAN_MARK_ADD | "
103 "FAN_MARK_MOUNT, FAN_MODIFY, AT_FDCWD,"
104 " '.') failed", fd_notify[p][i]);
105 }
106 /* Add ignore mark for groups with higher priority */
107 if (p == 0)
108 continue;
109 ret = fanotify_mark(fd_notify[p][i],
110 FAN_MARK_ADD |
111 FAN_MARK_IGNORED_MASK |
112 FAN_MARK_IGNORED_SURV_MODIFY,
113 FAN_MODIFY, AT_FDCWD, fname);
114 if (ret < 0) {
115 tst_brkm(TBROK | TERRNO, cleanup,
116 "fanotify_mark(%d, FAN_MARK_ADD | "
117 "FAN_MARK_IGNORED_MASK | "
118 "FAN_MARK_IGNORED_SURV_MODIFY, "
119 "FAN_MODIFY, AT_FDCWD, %s) failed",
120 fd_notify[p][i], fname);
121 }
122 }
123 }
124}
125
126static void cleanup_fanotify_groups(void)
127{
128 unsigned int i, p;
129
130 for (p = 0; p < FANOTIFY_PRIORITIES; p++) {
131 for (i = 0; i < GROUPS_PER_PRIO; i++) {
132 if (fd_notify[p][i] && fd_notify[p][i] != -1) {
133 if (close(fd_notify[p][i]) == -1)
134 tst_resm(TWARN, "close(%d) failed",
135 fd_notify[p][i]);
136 fd_notify[p][i] = 0;
137 }
138 }
139 }
140}
141
142static void verify_event(int group, struct fanotify_event_metadata *event)
143{
144 if (event->mask != FAN_MODIFY) {
145 tst_resm(TFAIL, "group %d get event: mask %llx (expected %llx) "
146 "pid=%u fd=%u", group, (unsigned long long)event->mask,
147 (unsigned long long)FAN_MODIFY,
148 (unsigned)event->pid, event->fd);
149 } else if (event->pid != getpid()) {
150 tst_resm(TFAIL, "group %d get event: mask %llx pid=%u "
151 "(expected %u) fd=%u", group,
152 (unsigned long long)event->mask, (unsigned)event->pid,
153 (unsigned)getpid(), event->fd);
154 } else {
155 tst_resm(TPASS, "group %d get event: mask %llx pid=%u fd=%u",
156 group, (unsigned long long)event->mask,
157 (unsigned)event->pid, event->fd);
158 }
159}
160
161int main(int ac, char **av)
162{
163 int lc;
164 const char *msg;
165
166 if ((msg = parse_opts(ac, av, NULL, NULL)) != NULL)
167 tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg);
168
169 setup();
170
171 for (lc = 0; TEST_LOOPING(lc); lc++) {
172 int ret;
173 unsigned int p, i;
174 struct fanotify_event_metadata *event;
175
176 create_fanotify_groups();
177
178 /*
179 * generate sequence of events
180 */
181 fd = SAFE_OPEN(cleanup, fname, O_RDWR);
182 SAFE_WRITE(cleanup, 1, fd, fname, strlen(fname));
183 SAFE_CLOSE(cleanup, fd);
184
185 /* First verify all groups without ignore mask got the event */
186 for (i = 0; i < GROUPS_PER_PRIO; i++) {
187 ret = read(fd_notify[0][i], event_buf, EVENT_BUF_LEN);
188 if (ret < 0) {
189 if (errno == EAGAIN) {
190 tst_resm(TFAIL, "group %d did not get "
191 "event", i);
192 }
193 tst_brkm(TBROK | TERRNO, cleanup,
194 "reading fanotify events failed");
195 }
196 if (ret < (int)FAN_EVENT_METADATA_LEN) {
197 tst_brkm(TBROK, cleanup,
198 "short read when reading fanotify "
199 "events (%d < %d)", ret,
200 (int)EVENT_BUF_LEN);
201 }
202 event = (struct fanotify_event_metadata *)event_buf;
203 if (ret > (int)event->event_len) {
204 tst_resm(TFAIL, "group %d got more than one "
205 "event (%d > %d)", i, ret,
206 event->event_len);
207 } else
208 verify_event(i, event);
209 close(event->fd);
210 }
211 for (p = 1; p < FANOTIFY_PRIORITIES; p++) {
212 for (i = 0; i < GROUPS_PER_PRIO; i++) {
213 ret = read(fd_notify[p][i], event_buf, EVENT_BUF_LEN);
214 if (ret > 0) {
215 tst_resm(TFAIL, "group %d got event",
216 p*GROUPS_PER_PRIO + i);
217 } else if (ret == 0) {
218 tst_brkm(TBROK, cleanup, "zero length "
219 "read from fanotify fd");
220 } else if (errno != EAGAIN) {
221 tst_brkm(TBROK | TERRNO, cleanup,
222 "reading fanotify events failed");
223 } else {
224 tst_resm(TPASS, "group %d got no event",
225 p*GROUPS_PER_PRIO + i);
226 }
227 }
228 }
229 cleanup_fanotify_groups();
230 }
231
232 cleanup();
233 tst_exit();
234}
235
236static void setup(void)
237{
238 tst_sig(NOFORK, DEF_HANDLER, cleanup);
239
240 TEST_PAUSE;
241
242 tst_tmpdir();
243
244 sprintf(fname, "tfile_%d", getpid());
245 fd = SAFE_OPEN(cleanup, fname, O_RDWR | O_CREAT, 0700);
246 SAFE_WRITE(cleanup, 1, fd, fname, 1);
247
248 /* close the file we have open */
249 SAFE_CLOSE(cleanup, fd);
250}
251
252static void cleanup(void)
253{
254 cleanup_fanotify_groups();
Jan Karab432e8b2014-11-10 18:11:58 +0100255 tst_rmdir();
256}
257
258#else
259
260int main(void)
261{
262 tst_brkm(TCONF, NULL, "system doesn't have required fanotify support");
263}
264
265#endif