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