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