1 /*
2 * Copyright (c) 2008 Parallels. 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 Andrew Vagin <avagin@gmail.com>
24 *
25 * DESCRIPTION
26 * Check that inotify get IN_UNMOUNT event and
27 * don't block the umount command.
28 *
29 * ALGORITHM
30 * Execute sequence file's operation and check return events
31 *
32 */
33 #include "config.h"
34
35 #include <stdio.h>
36 #include <sys/mount.h>
37 #include <sys/stat.h>
38 #include <sys/types.h>
39 #include <sys/fcntl.h>
40 #include <errno.h>
41 #include <string.h>
42 #include <sys/syscall.h>
43 #include <signal.h>
44 #include "test.h"
45 #include "linux_syscall_numbers.h"
46 #include "inotify.h"
47
48 char *TCID = "inotify03";
49 int TST_TOTAL = 3;
50
51 #if defined(HAVE_SYS_INOTIFY_H)
52 #include <sys/inotify.h>
53
54 #define EVENT_MAX 1024
55 /* size of the event structure, not counting name */
56 #define EVENT_SIZE (sizeof(struct inotify_event))
57 /* reasonable guess as to size of 1024 events */
58 #define EVENT_BUF_LEN (EVENT_MAX * (EVENT_SIZE + 16))
59
60 static void setup(void);
61 static void cleanup(void);
62
63 #define BUF_SIZE 1024
64 static char fname[BUF_SIZE];
65 static int fd, fd_notify;
66 static int wd;
67
68 static int event_set[EVENT_MAX];
69
70 static char event_buf[EVENT_BUF_LEN];
71
72 #define DIR_MODE (S_IRWXU | S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP)
73
74 static char *mntpoint = "mntpoint";
75 static int mount_flag;
76 static const char *device;
77 static const char *fs_type;
78
main(int argc,char * argv[])79 int main(int argc, char *argv[])
80 {
81 int ret;
82 int len, i, test_num;
83
84 tst_parse_opts(argc, argv, NULL, NULL);
85
86 setup();
87
88 tst_count = 0;
89
90 event_set[tst_count] = IN_UNMOUNT;
91 tst_count++;
92 event_set[tst_count] = IN_IGNORED;
93 tst_count++;
94
95 /*check exit code from inotify_rm_watch */
96 tst_count++;
97
98 if (TST_TOTAL != tst_count) {
99 tst_brkm(TBROK, cleanup,
100 "TST_TOTAL and tst_count are not equal");
101 }
102 tst_count = 0;
103
104 tst_resm(TINFO, "umount %s", device);
105 TEST(tst_umount(mntpoint));
106 if (TEST_RETURN != 0) {
107 tst_brkm(TBROK, cleanup, "umount(2) Failed "
108 "while unmounting errno = %d : %s",
109 TEST_ERRNO, strerror(TEST_ERRNO));
110 }
111 mount_flag = 0;
112
113 len = read(fd_notify, event_buf, EVENT_BUF_LEN);
114 if (len < 0) {
115 tst_brkm(TBROK | TERRNO, cleanup,
116 "read(%d, buf, %zu) failed", fd_notify, EVENT_BUF_LEN);
117 }
118
119 /* check events */
120 test_num = 0;
121 i = 0;
122 while (i < len) {
123 struct inotify_event *event;
124 event = (struct inotify_event *)&event_buf[i];
125 if (test_num >= (TST_TOTAL - 1)) {
126 tst_resm(TFAIL,
127 "get unnecessary event: wd=%d mask=%x "
128 "cookie=%u len=%u",
129 event->wd, event->mask,
130 event->cookie, event->len);
131 } else if (event_set[test_num] == event->mask) {
132 tst_resm(TPASS, "get event: wd=%d mask=%x"
133 " cookie=%u len=%u",
134 event->wd, event->mask,
135 event->cookie, event->len);
136
137 } else {
138 tst_resm(TFAIL, "get event: wd=%d mask=%x "
139 "(expected %x) cookie=%u len=%u",
140 event->wd, event->mask,
141 event_set[test_num],
142 event->cookie, event->len);
143 }
144 test_num++;
145 i += EVENT_SIZE + event->len;
146 }
147 for (; test_num < TST_TOTAL - 1; test_num++) {
148 tst_resm(TFAIL, "don't get event: mask=%x ",
149 event_set[test_num]);
150
151 }
152 ret = myinotify_rm_watch(fd_notify, wd);
153 if (ret != -1 || errno != EINVAL)
154 tst_resm(TFAIL | TERRNO,
155 "inotify_rm_watch (%d, %d) didn't return EINVAL",
156 fd_notify, wd);
157 else
158 tst_resm(TPASS, "inotify_rm_watch (%d, %d) returned EINVAL",
159 fd_notify, wd);
160
161 cleanup();
162 tst_exit();
163 }
164
setup(void)165 static void setup(void)
166 {
167 int ret;
168
169 tst_sig(NOFORK, DEF_HANDLER, cleanup);
170
171 TEST_PAUSE;
172
173 fs_type = tst_dev_fs_type();
174
175 tst_tmpdir();
176
177 device = tst_acquire_device(cleanup);
178 if (!device)
179 tst_brkm(TCONF, cleanup, "Failed to obtain block device");
180
181 tst_mkfs(cleanup, device, fs_type, NULL, NULL);
182
183 if (mkdir(mntpoint, DIR_MODE) < 0) {
184 tst_brkm(TBROK | TERRNO, cleanup, "mkdir(%s, %#o) failed",
185 mntpoint, DIR_MODE);
186 }
187
188 /* Call mount(2) */
189 tst_resm(TINFO, "mount %s to %s fs_type=%s", device, mntpoint, fs_type);
190 TEST(mount(device, mntpoint, fs_type, 0, NULL));
191
192 /* check return code */
193 if (TEST_RETURN != 0) {
194 tst_brkm(TBROK | TTERRNO, cleanup, "mount(2) failed");
195 }
196 mount_flag = 1;
197
198 sprintf(fname, "%s/tfile_%d", mntpoint, getpid());
199 fd = open(fname, O_RDWR | O_CREAT, 0700);
200 if (fd == -1) {
201 tst_brkm(TBROK | TERRNO, cleanup,
202 "open(%s, O_RDWR|O_CREAT,0700) failed", fname);
203 }
204
205 ret = write(fd, fname, 1);
206 if (ret == -1) {
207 tst_brkm(TBROK | TERRNO, cleanup,
208 "write(%d, %s, 1) failed", fd, fname);
209 }
210
211 /* close the file we have open */
212 if (close(fd) == -1)
213 tst_brkm(TBROK | TERRNO, cleanup, "close(%s) failed", fname);
214
215 fd_notify = myinotify_init();
216
217 if (fd_notify < 0) {
218 if (errno == ENOSYS)
219 tst_brkm(TCONF, cleanup,
220 "inotify is not configured in this kernel.");
221 else
222 tst_brkm(TBROK | TERRNO, cleanup,
223 "inotify_init failed");
224 }
225
226 wd = myinotify_add_watch(fd_notify, fname, IN_ALL_EVENTS);
227 if (wd < 0)
228 tst_brkm(TBROK | TERRNO, cleanup,
229 "inotify_add_watch (%d, %s, IN_ALL_EVENTS) failed.",
230 fd_notify, fname);
231 }
232
cleanup(void)233 static void cleanup(void)
234 {
235 if (fd_notify > 0 && close(fd_notify) == -1)
236 tst_resm(TWARN | TERRNO, "close(%d) failed", fd_notify);
237
238 if (mount_flag) {
239 TEST(tst_umount(mntpoint));
240 if (TEST_RETURN != 0)
241 tst_resm(TWARN | TTERRNO, "umount(%s) failed",
242 mntpoint);
243 }
244
245 tst_release_device(device);
246
247 tst_rmdir();
248 }
249
250 #else
251
main(void)252 int main(void)
253 {
254 tst_brkm(TCONF, NULL, "system doesn't have required inotify support");
255 }
256
257 #endif
258