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 <fcntl.h>
40 #include <errno.h>
41 #include <string.h>
42 #include <sys/syscall.h>
43 #include <signal.h>
44 #include "tst_test.h"
45 #include "inotify.h"
46
47 #if defined(HAVE_SYS_INOTIFY_H)
48 #include <sys/inotify.h>
49
50 #define EVENT_MAX 1024
51 /* size of the event structure, not counting name */
52 #define EVENT_SIZE (sizeof(struct inotify_event))
53 /* reasonable guess as to size of 1024 events */
54 #define EVENT_BUF_LEN (EVENT_MAX * (EVENT_SIZE + 16))
55
56 #define BUF_SIZE 1024
57 static char fname[BUF_SIZE];
58 static int fd, fd_notify;
59 static int wd;
60
61 static unsigned int event_set[EVENT_MAX];
62
63 static char event_buf[EVENT_BUF_LEN];
64
65 #define DIR_MODE (S_IRWXU | S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP)
66
67 static char *mntpoint = "mntpoint";
68 static int mount_flag;
69
verify_inotify(void)70 void verify_inotify(void)
71 {
72 int ret;
73 int len, i, test_num;
74
75 int test_cnt = 0;
76
77 SAFE_MOUNT(tst_device->dev, mntpoint, tst_device->fs_type, 0, NULL);
78 mount_flag = 1;
79
80 wd = myinotify_add_watch(fd_notify, fname, IN_ALL_EVENTS);
81 if (wd < 0) {
82 tst_brk(TBROK | TERRNO,
83 "inotify_add_watch (%d, %s, IN_ALL_EVENTS) failed.",
84 fd_notify, fname);
85 }
86
87 event_set[test_cnt] = IN_UNMOUNT;
88 test_cnt++;
89 event_set[test_cnt] = IN_IGNORED;
90 test_cnt++;
91
92 /*check exit code from inotify_rm_watch */
93 test_cnt++;
94
95 tst_res(TINFO, "umount %s", tst_device->dev);
96 TEST(tst_umount(mntpoint));
97 if (TST_RET != 0) {
98 tst_brk(TBROK, "umount(2) Failed "
99 "while unmounting errno = %d : %s",
100 TST_ERR, strerror(TST_ERR));
101 }
102 mount_flag = 0;
103
104 len = read(fd_notify, event_buf, EVENT_BUF_LEN);
105 if (len < 0) {
106 tst_brk(TBROK | TERRNO,
107 "read(%d, buf, %zu) failed", fd_notify, EVENT_BUF_LEN);
108 }
109
110 /* check events */
111 test_num = 0;
112 i = 0;
113 while (i < len) {
114 struct inotify_event *event;
115 event = (struct inotify_event *)&event_buf[i];
116 if (test_num >= (test_cnt - 1)) {
117 tst_res(TFAIL,
118 "get unnecessary event: wd=%d mask=%x "
119 "cookie=%u len=%u",
120 event->wd, event->mask,
121 event->cookie, event->len);
122 } else if (event_set[test_num] == event->mask) {
123 tst_res(TPASS, "get event: wd=%d mask=%x"
124 " cookie=%u len=%u",
125 event->wd, event->mask,
126 event->cookie, event->len);
127
128 } else {
129 tst_res(TFAIL, "get event: wd=%d mask=%x "
130 "(expected %x) cookie=%u len=%u",
131 event->wd, event->mask,
132 event_set[test_num],
133 event->cookie, event->len);
134 }
135 test_num++;
136 i += EVENT_SIZE + event->len;
137 }
138 for (; test_num < test_cnt - 1; test_num++) {
139 tst_res(TFAIL, "don't get event: mask=%x ",
140 event_set[test_num]);
141
142 }
143 ret = myinotify_rm_watch(fd_notify, wd);
144 if (ret != -1 || errno != EINVAL)
145 tst_res(TFAIL | TERRNO,
146 "inotify_rm_watch (%d, %d) didn't return EINVAL",
147 fd_notify, wd);
148 else
149 tst_res(TPASS, "inotify_rm_watch (%d, %d) returned EINVAL",
150 fd_notify, wd);
151 }
152
setup(void)153 static void setup(void)
154 {
155 int ret;
156
157 SAFE_MKDIR(mntpoint, DIR_MODE);
158
159 SAFE_MOUNT(tst_device->dev, mntpoint, tst_device->fs_type, 0, NULL);
160 mount_flag = 1;
161
162 sprintf(fname, "%s/tfile_%d", mntpoint, getpid());
163 fd = SAFE_OPEN(fname, O_RDWR | O_CREAT, 0700);
164
165 ret = write(fd, fname, 1);
166 if (ret == -1) {
167 tst_brk(TBROK | TERRNO,
168 "write(%d, %s, 1) failed", fd, fname);
169 }
170
171 /* close the file we have open */
172 SAFE_CLOSE(fd);
173
174 fd_notify = myinotify_init();
175 if (fd_notify < 0) {
176 if (errno == ENOSYS)
177 tst_brk(TCONF,
178 "inotify is not configured in this kernel.");
179 else
180 tst_brk(TBROK | TERRNO,
181 "inotify_init failed");
182 }
183
184 tst_umount(mntpoint);
185 mount_flag = 0;
186 }
187
cleanup(void)188 static void cleanup(void)
189 {
190 if (fd_notify > 0)
191 SAFE_CLOSE(fd_notify);
192
193 if (mount_flag) {
194 TEST(tst_umount(mntpoint));
195 if (TST_RET != 0)
196 tst_res(TWARN | TTERRNO, "umount(%s) failed",
197 mntpoint);
198 }
199 }
200
201 static struct tst_test test = {
202 .needs_root = 1,
203 .needs_tmpdir = 1,
204 .format_device = 1,
205 .setup = setup,
206 .cleanup = cleanup,
207 .test_all = verify_inotify,
208 };
209
210 #else
211 TST_TEST_TCONF("system doesn't have required inotify support");
212 #endif
213