1 /*
2 * Copyright (c) 2014 SUSE Linux. 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 * Started by Jan Kara <jack@suse.cz>
20 *
21 * DESCRIPTION
22 * Check that inotify overflow event is properly generated
23 *
24 * ALGORITHM
25 * Generate enough events without reading them and check that overflow
26 * event is generated.
27 */
28 #include "config.h"
29
30 #include <stdio.h>
31 #include <sys/stat.h>
32 #include <sys/types.h>
33 #include <fcntl.h>
34 #include <errno.h>
35 #include <string.h>
36 #include <sys/syscall.h>
37 #include "test.h"
38 #include "lapi/syscalls.h"
39 #include "inotify.h"
40 #include "safe_macros.h"
41
42 char *TCID = "inotify05";
43 int TST_TOTAL = 1;
44
45 #if defined(HAVE_SYS_INOTIFY_H)
46 #include <sys/inotify.h>
47
48 /* size of the event structure, not counting name */
49 #define EVENT_SIZE (sizeof(struct inotify_event))
50 #define EVENT_BUF_LEN (EVENT_SIZE * 16)
51
52 static void setup(void);
53 static void cleanup(void);
54
55 #define BUF_SIZE 256
56 static char fname[BUF_SIZE];
57 static char buf[BUF_SIZE];
58 static int fd, fd_notify;
59 static int wd;
60 static int max_events;
61
62 static char event_buf[EVENT_BUF_LEN];
63
main(int ac,char ** av)64 int main(int ac, char **av)
65 {
66 int lc, i;
67 int len, stop;
68
69 tst_parse_opts(ac, av, NULL, NULL);
70
71 setup();
72
73 for (lc = 0; TEST_LOOPING(lc); lc++) {
74 /*
75 * generate events
76 */
77 fd = SAFE_OPEN(cleanup, fname, O_RDWR);
78
79 for (i = 0; i < max_events; i++) {
80 SAFE_LSEEK(cleanup, fd, 0, SEEK_SET);
81 SAFE_READ(cleanup, 1, fd, buf, BUF_SIZE);
82 SAFE_LSEEK(cleanup, fd, 0, SEEK_SET);
83 SAFE_WRITE(cleanup, 1, fd, buf, BUF_SIZE);
84 }
85
86 SAFE_CLOSE(cleanup, fd);
87
88 stop = 0;
89 while (!stop) {
90 /*
91 * get list on events
92 */
93 len = read(fd_notify, event_buf, EVENT_BUF_LEN);
94 if (len < 0) {
95 tst_brkm(TBROK | TERRNO, cleanup,
96 "read(%d, buf, %zu) failed",
97 fd_notify, EVENT_BUF_LEN);
98 }
99
100 /*
101 * check events
102 */
103 i = 0;
104 while (i < len) {
105 struct inotify_event *event;
106
107 event = (struct inotify_event *)&event_buf[i];
108 if (event->mask != IN_ACCESS &&
109 event->mask != IN_MODIFY &&
110 event->mask != IN_OPEN &&
111 event->mask != IN_Q_OVERFLOW) {
112 tst_resm(TFAIL,
113 "get event: wd=%d mask=%x "
114 "cookie=%u (expected 0) len=%u",
115 event->wd, event->mask,
116 event->cookie, event->len);
117 stop = 1;
118 break;
119 }
120 if (event->mask == IN_Q_OVERFLOW) {
121 if (event->len != 0 ||
122 event->cookie != 0 ||
123 event->wd != -1) {
124 tst_resm(TFAIL,
125 "invalid overflow event: "
126 "wd=%d mask=%x "
127 "cookie=%u len=%u",
128 event->wd, event->mask,
129 event->cookie,
130 event->len);
131 stop = 1;
132 break;
133 }
134 if ((int)(i + EVENT_SIZE) != len) {
135 tst_resm(TFAIL,
136 "overflow event is not last");
137 stop = 1;
138 break;
139 }
140 tst_resm(TPASS, "get event: wd=%d "
141 "mask=%x cookie=%u len=%u",
142 event->wd, event->mask,
143 event->cookie, event->len);
144 stop = 1;
145 break;
146 }
147 i += EVENT_SIZE + event->len;
148 }
149 }
150 }
151
152 cleanup();
153 tst_exit();
154 }
155
setup(void)156 static void setup(void)
157 {
158 tst_sig(NOFORK, DEF_HANDLER, cleanup);
159
160 TEST_PAUSE;
161
162 tst_tmpdir();
163
164 sprintf(fname, "tfile_%d", getpid());
165 fd = SAFE_OPEN(cleanup, fname, O_RDWR | O_CREAT, 0700);
166 SAFE_WRITE(cleanup, 1, fd, buf, BUF_SIZE);
167 SAFE_CLOSE(cleanup, fd);
168
169 fd_notify = syscall(__NR_inotify_init1, O_NONBLOCK);
170 if (fd_notify < 0) {
171 if (errno == ENOSYS) {
172 tst_brkm(TCONF, cleanup,
173 "inotify is not configured in this kernel.");
174 } else {
175 tst_brkm(TBROK | TERRNO, cleanup,
176 "inotify_init failed");
177 }
178 }
179
180 wd = myinotify_add_watch(fd_notify, fname, IN_ALL_EVENTS);
181 if (wd < 0) {
182 tst_brkm(TBROK | TERRNO, cleanup,
183 "inotify_add_watch (%d, %s, IN_ALL_EVENTS) failed",
184 fd_notify, fname);
185 };
186
187 SAFE_FILE_SCANF(cleanup, "/proc/sys/fs/inotify/max_queued_events",
188 "%d", &max_events);
189 }
190
cleanup(void)191 static void cleanup(void)
192 {
193 if (fd_notify > 0 && myinotify_rm_watch(fd_notify, wd) == -1) {
194 tst_resm(TWARN | TERRNO, "inotify_rm_watch (%d, %d) failed",
195 fd_notify, wd);
196
197 }
198
199 if (fd_notify > 0 && close(fd_notify) == -1)
200 tst_resm(TWARN, "close(%d) failed", fd_notify);
201
202 tst_rmdir();
203 }
204
205 #else
206
main(void)207 int main(void)
208 {
209 tst_brkm(TCONF, NULL, "system doesn't have required inotify support");
210 }
211
212 #endif
213