1 /* 2 * Copyright (c) 2013 SUSE. 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 Jan Kara <jack@suse.cz> 24 * 25 * DESCRIPTION 26 * Check that fanotify work for children of a directory 27 */ 28 #define _GNU_SOURCE 29 #include "config.h" 30 31 #include <stdio.h> 32 #include <sys/stat.h> 33 #include <sys/types.h> 34 #include <fcntl.h> 35 #include <errno.h> 36 #include <string.h> 37 #include <sys/syscall.h> 38 #include "tst_test.h" 39 #include "fanotify.h" 40 41 #if defined(HAVE_SYS_FANOTIFY_H) 42 #include <sys/fanotify.h> 43 44 #define EVENT_MAX 1024 45 /* size of the event structure, not counting name */ 46 #define EVENT_SIZE (sizeof (struct fanotify_event_metadata)) 47 /* reasonable guess as to size of 1024 events */ 48 #define EVENT_BUF_LEN (EVENT_MAX * EVENT_SIZE) 49 50 #define BUF_SIZE 256 51 #define TST_TOTAL 8 52 53 static char fname[BUF_SIZE]; 54 static char buf[BUF_SIZE]; 55 static int fd, fd_notify; 56 57 static unsigned long long event_set[EVENT_MAX]; 58 59 static char event_buf[EVENT_BUF_LEN]; 60 61 void test01(void) 62 { 63 int ret, len, i = 0, test_num = 0; 64 65 int tst_count = 0; 66 67 if (fanotify_mark(fd_notify, FAN_MARK_ADD, FAN_ACCESS | 68 FAN_MODIFY | FAN_CLOSE | FAN_OPEN | 69 FAN_EVENT_ON_CHILD | FAN_ONDIR, AT_FDCWD, 70 ".") < 0) { 71 tst_brk(TBROK | TERRNO, 72 "fanotify_mark (%d, FAN_MARK_ADD, FAN_ACCESS | " 73 "FAN_MODIFY | FAN_CLOSE | FAN_OPEN | " 74 "FAN_EVENT_ON_CHILD | FAN_ONDIR, AT_FDCWD, '.') " 75 "failed", fd_notify); 76 } 77 78 /* 79 * generate sequence of events 80 */ 81 fd = SAFE_OPEN(fname, O_RDWR | O_CREAT, 0700); 82 event_set[tst_count] = FAN_OPEN; 83 tst_count++; 84 85 SAFE_WRITE(1, fd, fname, strlen(fname)); 86 event_set[tst_count] = FAN_MODIFY; 87 tst_count++; 88 89 SAFE_CLOSE(fd); 90 event_set[tst_count] = FAN_CLOSE_WRITE; 91 tst_count++; 92 93 /* 94 * Get list of events so far. We get events here to avoid 95 * merging of following events with the previous ones. 96 */ 97 ret = SAFE_READ(0, fd_notify, event_buf, 98 EVENT_BUF_LEN); 99 len = ret; 100 101 fd = SAFE_OPEN(fname, O_RDONLY); 102 event_set[tst_count] = FAN_OPEN; 103 tst_count++; 104 105 SAFE_READ(0, fd, buf, BUF_SIZE); 106 event_set[tst_count] = FAN_ACCESS; 107 tst_count++; 108 109 SAFE_CLOSE(fd); 110 event_set[tst_count] = FAN_CLOSE_NOWRITE; 111 tst_count++; 112 113 /* 114 * get next events 115 */ 116 ret = SAFE_READ(0, fd_notify, event_buf + len, 117 EVENT_BUF_LEN - len); 118 len += ret; 119 120 /* 121 * now remove child mark 122 */ 123 if (fanotify_mark(fd_notify, FAN_MARK_REMOVE, 124 FAN_EVENT_ON_CHILD, AT_FDCWD, ".") < 0) { 125 tst_brk(TBROK | TERRNO, 126 "fanotify_mark (%d, FAN_MARK REMOVE, " 127 "FAN_EVENT_ON_CHILD, AT_FDCWD, '.') failed", 128 fd_notify); 129 } 130 131 /* 132 * Do something to verify events didn't get generated 133 */ 134 fd = SAFE_OPEN(fname, O_RDONLY); 135 136 SAFE_CLOSE(fd); 137 138 fd = SAFE_OPEN(".", O_RDONLY | O_DIRECTORY); 139 event_set[tst_count] = FAN_OPEN; 140 tst_count++; 141 142 SAFE_CLOSE(fd); 143 event_set[tst_count] = FAN_CLOSE_NOWRITE; 144 tst_count++; 145 146 /* 147 * Check events got generated only for the directory 148 */ 149 ret = SAFE_READ(0, fd_notify, event_buf + len, 150 EVENT_BUF_LEN - len); 151 len += ret; 152 153 if (TST_TOTAL != tst_count) { 154 tst_brk(TBROK, 155 "TST_TOTAL and tst_count are not equal"); 156 } 157 tst_count = 0; 158 159 /* 160 * check events 161 */ 162 while (i < len) { 163 struct fanotify_event_metadata *event; 164 165 event = (struct fanotify_event_metadata *)&event_buf[i]; 166 if (test_num >= TST_TOTAL) { 167 tst_res(TFAIL, 168 "get unnecessary event: mask=%llx " 169 "pid=%u fd=%u", 170 (unsigned long long)event->mask, 171 (unsigned)event->pid, event->fd); 172 } else if (!(event->mask & event_set[test_num])) { 173 tst_res(TFAIL, 174 "get event: mask=%llx (expected %llx) " 175 "pid=%u fd=%u", 176 (unsigned long long)event->mask, 177 event_set[test_num], 178 (unsigned)event->pid, event->fd); 179 } else if (event->pid != getpid()) { 180 tst_res(TFAIL, 181 "get event: mask=%llx pid=%u " 182 "(expected %u) fd=%u", 183 (unsigned long long)event->mask, 184 (unsigned)event->pid, 185 (unsigned)getpid(), 186 event->fd); 187 } else { 188 tst_res(TPASS, 189 "get event: mask=%llx pid=%u fd=%u", 190 (unsigned long long)event->mask, 191 (unsigned)event->pid, event->fd); 192 } 193 event->mask &= ~event_set[test_num]; 194 /* No events left in current mask? Go for next event */ 195 if (event->mask == 0) { 196 i += event->event_len; 197 close(event->fd); 198 } 199 test_num++; 200 } 201 for (; test_num < TST_TOTAL; test_num++) { 202 tst_res(TFAIL, "didn't get event: mask=%llx", 203 event_set[test_num]); 204 205 } 206 } 207 208 static void setup(void) 209 { 210 sprintf(fname, "fname_%d", getpid()); 211 fd_notify = SAFE_FANOTIFY_INIT(FAN_CLASS_NOTIF, O_RDONLY); 212 } 213 214 static void cleanup(void) 215 { 216 if (fd_notify > 0) 217 SAFE_CLOSE(fd_notify); 218 } 219 220 static struct tst_test test = { 221 .test_all = test01, 222 .setup = setup, 223 .cleanup = cleanup, 224 .needs_tmpdir = 1, 225 .needs_root = 1 226 }; 227 228 #else 229 TST_TEST_TCONF("system doesn't have required fanotify support"); 230 #endif 231