inotify04.c revision fed9641096e27f79a0f2d9adfe9839dd8d11dc0f
1/* 2 * Copyright (c) 2012 Linux Test Project. 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 * Garrett Cooper, April 2012 24 */ 25 26/**************************************************************************** 27 * DESCRIPTION 28 * verify that IN_DELETE_SELF functions as expected 29 * 30 * ALGORITHM 31 * This testcase creates a temporary directory, then add watches to a 32 * predefined file and subdirectory, and delete the file and directory to 33 * ensure that the IN_DELETE_SELF event is captured properly. 34 * 35 * Because of how the inotify(7) API is designed, we also need to catch the 36 * IN_ATTRIB and IN_IGNORED events. 37 * 38 ****************************************************************************/ 39 40#include "config.h" 41 42#if defined(HAVE_SYS_INOTIFY_H) 43#include <sys/inotify.h> 44#endif 45#include <errno.h> 46#include <string.h> 47#include "test.h" 48#include "usctest.h" 49#include "linux_syscall_numbers.h" 50#include "inotify.h" 51#include "safe_macros.h" 52 53char *TCID = "inotify04"; 54 55#if defined(HAVE_SYS_INOTIFY_H) 56 57#define EVENT_MAX 1024 58/* size of the event structure, not counting name */ 59#define EVENT_SIZE (sizeof(struct inotify_event)) 60/* reasonable guess as to size of 1024 events */ 61#define EVENT_BUF_LEN (EVENT_MAX * (EVENT_SIZE + 16)) 62 63int TST_TOTAL = 4; 64 65#define BUF_SIZE 256 66 67struct event_t { 68 char name[BUF_SIZE]; 69 int mask; 70 size_t len; 71}; 72 73#define TEST_DIR "test_dir" 74#define TEST_FILE "test_file" 75 76struct event_t event_set[EVENT_MAX]; 77 78char event_buf[EVENT_BUF_LEN]; 79 80int fd_notify, reap_wd_file, reap_wd_dir, wd_dir, wd_file; 81 82static void cleanup(void) 83{ 84 85 if (reap_wd_dir && myinotify_rm_watch(fd_notify, wd_dir) == -1) 86 tst_resm(TWARN, 87 "inotify_rm_watch(%d, %d) [1] failed", fd_notify, wd_dir); 88 89 if (reap_wd_file && myinotify_rm_watch(fd_notify, wd_file) == -1) 90 tst_resm(TWARN, 91 "inotify_rm_watch(%d, %d) [2] failed", fd_notify, wd_file); 92 93 if (close(fd_notify) == -1) 94 tst_resm(TWARN, "close(%d) [1] failed", fd_notify); 95 96 if (close(wd_dir) == -1) 97 tst_resm(TWARN, "close(%d) [2] failed", wd_dir); 98 99 if (close(wd_file) == -1) 100 tst_resm(TWARN, "close(%d) [3] failed", wd_file); 101 102 TEST_CLEANUP; 103 104 tst_rmdir(); 105} 106 107static void setup(void) 108{ 109 110 tst_sig(NOFORK, DEF_HANDLER, cleanup); 111 112 TEST_PAUSE; 113 114 tst_tmpdir(); 115 116 fd_notify = myinotify_init(); 117 if (fd_notify == -1) 118 tst_brkm(TBROK|TERRNO, cleanup, "inotify_init() failed"); 119 120 SAFE_MKDIR(cleanup, TEST_DIR, 00700); 121 122 close(SAFE_CREAT(cleanup, TEST_FILE, 00600)); 123 124 wd_dir = myinotify_add_watch(fd_notify, TEST_DIR, IN_ALL_EVENTS); 125 if (wd_dir == -1) { 126 tst_brkm(TBROK|TERRNO, cleanup, 127 "inotify_add_watch(%d, \"%s\", IN_ALL_EVENTS) [1] failed", 128 fd_notify, TEST_DIR); 129 } 130 reap_wd_dir = 1; 131 132 wd_file = myinotify_add_watch(fd_notify, TEST_FILE, IN_ALL_EVENTS); 133 if (wd_file == -1) 134 tst_brkm(TBROK|TERRNO, cleanup, 135 "inotify_add_watch(%d, \"%s\", IN_ALL_EVENTS) [2] failed", 136 fd_notify, TEST_FILE); 137 reap_wd_file = 1; 138} 139 140int 141main(int argc, char **argv) 142{ 143 char *msg; 144 size_t len; 145 int i, test_num; 146 147 i = 0; 148 test_num = 0; 149 150 msg = parse_opts(argc, argv, NULL, NULL); 151 if (msg != NULL) 152 tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg); 153 154 setup(); 155 156 Tst_count = 0; 157 158 rmdir(TEST_DIR); 159 event_set[Tst_count].mask = IN_DELETE_SELF; 160 strcpy(event_set[Tst_count].name, ""); 161 Tst_count++; 162 event_set[Tst_count].mask = IN_IGNORED; 163 strcpy(event_set[Tst_count].name, ""); 164 Tst_count++; 165 166 unlink(TEST_FILE); 167 /* 168 * When a file is unlinked, the link count is reduced by 1, and when it 169 * hits 0 the file is removed. 170 * 171 * This isn't well documented in inotify(7), but it's intuitive if you 172 * understand how Unix works. 173 */ 174 if (0 <= tst_kvercmp(2, 6, 25)) { 175 event_set[Tst_count].mask = IN_ATTRIB; 176 strcpy(event_set[Tst_count].name, ""); 177 Tst_count++; 178 TST_TOTAL++; 179 } 180 event_set[Tst_count].mask = IN_DELETE_SELF; 181 strcpy(event_set[Tst_count].name, TEST_FILE); 182 Tst_count++; 183 event_set[Tst_count].mask = IN_IGNORED; 184 strcpy(event_set[Tst_count].name, ""); 185 Tst_count++; 186 187 if (Tst_count != TST_TOTAL) 188 tst_brkm(TBROK, cleanup, 189 "Tst_count and TST_TOTAL are not equal"); 190 191 Tst_count = 0; 192 193 len = read(fd_notify, event_buf, EVENT_BUF_LEN); 194 if (len == -1) 195 tst_brkm(TBROK|TERRNO, cleanup, "read failed"); 196 197 reap_wd_dir = 0; 198 reap_wd_file = 0; 199 200 while (i < len) { 201 struct inotify_event *event; 202 event = (struct inotify_event *)&event_buf[i]; 203 if (test_num >= TST_TOTAL) { 204 if (tst_kvercmp(2, 6, 25) < 0 205 && event_set[TST_TOTAL - 1].mask == 206 event->mask) 207 tst_resm(TWARN, 208 "This may be kernel bug. " 209 "Before kernel 2.6.25, a kernel bug " 210 "meant that the kernel code that was " 211 "intended to coalesce successive identical " 212 "events (i.e., the two most recent " 213 "events could potentially be coalesced " 214 "if the older had not yet been read) " 215 "instead checked if the most recent event " 216 "could be coalesced with the oldest " 217 "unread event. This has been fixed by commit" 218 "1c17d18e3775485bf1e0ce79575eb637a94494a2."); 219 tst_resm(TFAIL, 220 "got unnecessary event: " 221 "wd=%d mask=%x cookie=%u len=%u " 222 "name=\"%s\"", event->wd, event->mask, 223 event->cookie, event->len, 224 event->name); 225 226 } else if ((event_set[test_num].mask == event->mask) 227 && 228 (!strncmp 229 (event_set[test_num].name, event->name, 230 event->len))) { 231 tst_resm(TPASS, 232 "got event: wd=%d mask=%x " 233 "cookie=%u len=%u name=\"%s\"", 234 event->wd, event->mask, event->cookie, 235 event->len, event->name); 236 237 } else { 238 tst_resm(TFAIL, "got event: wd=%d mask=%x " 239 "(expected %x) cookie=%u len=%u " 240 "name=\"%s\" (expected \"%s\") %d", 241 event->wd, event->mask, 242 event_set[test_num].mask, 243 event->cookie, event->len, event->name, 244 event_set[test_num].name, 245 strcmp(event_set[test_num].name, 246 event->name)); 247 } 248 test_num++; 249 i += EVENT_SIZE + event->len; 250 } 251 252 for (; test_num < TST_TOTAL; test_num++) { 253 tst_resm(TFAIL, "didn't get event: mask=%x ", 254 event_set[test_num].mask); 255 } 256 257 cleanup(); 258 tst_exit(); 259} 260#else 261 262int TST_TOTAL; 263 264int main(void) 265{ 266 tst_brkm(TCONF, NULL, "system doesn't have required inotify support"); 267} 268#endif /* defined(HAVE_SYS_INOTIFY_H) */ 269