1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Copyright (c) 2012 Linux Test Project. All Rights Reserved. 4 * Ngie Cooper, April 2012 5 * 6 * DESCRIPTION 7 * verify that IN_DELETE_SELF functions as expected 8 * 9 * ALGORITHM 10 * This testcase creates a temporary directory, then add watches to a 11 * predefined file and subdirectory, and delete the file and directory to 12 * ensure that the IN_DELETE_SELF event is captured properly. 13 * 14 * Because of how the inotify(7) API is designed, we also need to catch the 15 * IN_ATTRIB and IN_IGNORED events. 16 */ 17 18#include "config.h" 19 20#if defined(HAVE_SYS_INOTIFY_H) 21# include <sys/inotify.h> 22#endif 23#include <errno.h> 24#include <string.h> 25#include "tst_test.h" 26#include "inotify.h" 27 28#if defined(HAVE_SYS_INOTIFY_H) 29 30#define EVENT_MAX 1024 31/* size of the event structure, not counting name */ 32#define EVENT_SIZE (sizeof(struct inotify_event)) 33/* reasonable guess as to size of 1024 events */ 34#define EVENT_BUF_LEN (EVENT_MAX * (EVENT_SIZE + 16)) 35 36 37#define BUF_SIZE 256 38 39struct event_t { 40 char name[BUF_SIZE]; 41 unsigned int mask; 42}; 43 44#define TEST_DIR "test_dir" 45#define TEST_FILE "test_file" 46 47struct event_t event_set[EVENT_MAX]; 48 49char event_buf[EVENT_BUF_LEN]; 50 51int fd_notify, reap_wd_file, reap_wd_dir, wd_dir, wd_file; 52 53static void cleanup(void) 54{ 55 if (reap_wd_dir && myinotify_rm_watch(fd_notify, wd_dir) == -1) 56 tst_res(TWARN, 57 "inotify_rm_watch(%d, %d) [1] failed", fd_notify, 58 wd_dir); 59 60 if (reap_wd_file && myinotify_rm_watch(fd_notify, wd_file) == -1) 61 tst_res(TWARN, 62 "inotify_rm_watch(%d, %d) [2] failed", fd_notify, 63 wd_file); 64 65 if (fd_notify > 0) 66 SAFE_CLOSE(fd_notify); 67} 68 69static void setup(void) 70{ 71 fd_notify = SAFE_MYINOTIFY_INIT(); 72} 73 74void verify_inotify(void) 75{ 76 int i = 0, test_num = 0, len; 77 int test_cnt = 0; 78 79 SAFE_MKDIR(TEST_DIR, 00700); 80 close(SAFE_CREAT(TEST_FILE, 00600)); 81 82 wd_dir = SAFE_MYINOTIFY_ADD_WATCH(fd_notify, TEST_DIR, IN_ALL_EVENTS); 83 reap_wd_dir = 1; 84 85 wd_file = SAFE_MYINOTIFY_ADD_WATCH(fd_notify, TEST_FILE, IN_ALL_EVENTS); 86 reap_wd_file = 1; 87 88 SAFE_RMDIR(TEST_DIR); 89 reap_wd_dir = 0; 90 91 event_set[test_cnt].mask = IN_DELETE_SELF; 92 strcpy(event_set[test_cnt].name, ""); 93 test_cnt++; 94 event_set[test_cnt].mask = IN_IGNORED; 95 strcpy(event_set[test_cnt].name, ""); 96 test_cnt++; 97 98 SAFE_UNLINK(TEST_FILE); 99 reap_wd_file = 0; 100 101 /* 102 * When a file is unlinked, the link count is reduced by 1, and when it 103 * hits 0 the file is removed. 104 * 105 * This isn't well documented in inotify(7), but it's intuitive if you 106 * understand how Unix works. 107 */ 108 event_set[test_cnt].mask = IN_ATTRIB; 109 strcpy(event_set[test_cnt].name, ""); 110 test_cnt++; 111 112 event_set[test_cnt].mask = IN_DELETE_SELF; 113 strcpy(event_set[test_cnt].name, TEST_FILE); 114 test_cnt++; 115 event_set[test_cnt].mask = IN_IGNORED; 116 strcpy(event_set[test_cnt].name, ""); 117 test_cnt++; 118 119 len = read(fd_notify, event_buf, EVENT_BUF_LEN); 120 if (len == -1) 121 tst_brk(TBROK | TERRNO, "read failed"); 122 123 while (i < len) { 124 struct inotify_event *event; 125 event = (struct inotify_event *)&event_buf[i]; 126 if (test_num >= test_cnt) { 127 tst_res(TFAIL, 128 "got unnecessary event: " 129 "wd=%d mask=%04x cookie=%u len=%u " 130 "name=\"%.*s\"", event->wd, event->mask, 131 event->cookie, event->len, event->len, event->name); 132 133 } else if ((event_set[test_num].mask == event->mask) 134 && 135 (!strncmp 136 (event_set[test_num].name, event->name, 137 event->len))) { 138 tst_res(TPASS, 139 "got event: wd=%d mask=%04x " 140 "cookie=%u len=%u name=\"%.*s\"", 141 event->wd, event->mask, event->cookie, 142 event->len, event->len, event->name); 143 144 } else { 145 tst_res(TFAIL, "got event: wd=%d mask=%04x " 146 "(expected %x) cookie=%u len=%u " 147 "name=\"%.*s\" (expected \"%s\") %d", 148 event->wd, event->mask, 149 event_set[test_num].mask, 150 event->cookie, event->len, 151 event->len, event->name, 152 event_set[test_num].name, 153 strncmp(event_set[test_num].name, event->name, event->len)); 154 } 155 test_num++; 156 i += EVENT_SIZE + event->len; 157 } 158 159 for (; test_num < test_cnt; test_num++) { 160 tst_res(TFAIL, "didn't get event: mask=%04x ", 161 event_set[test_num].mask); 162 } 163 164} 165 166static struct tst_test test = { 167 .needs_tmpdir = 1, 168 .setup = setup, 169 .cleanup = cleanup, 170 .test_all = verify_inotify, 171}; 172 173#else 174 TST_TEST_TCONF("system doesn't have required inotify support"); 175#endif /* defined(HAVE_SYS_INOTIFY_H) */ 176