• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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