1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Copyright (c) 2020 CTERA Networks. All Rights Reserved. 4 * 5 * Started by Amir Goldstein <amir73il@gmail.com> 6 */ 7 8/*\ 9 * [Description] 10 * Check fanotify directory entry modification events, events on child and 11 * on self with group init flags: 12 * 13 * - FAN_REPORT_DFID_NAME (dir fid + name) 14 * - FAN_REPORT_DIR_FID (dir fid) 15 * - FAN_REPORT_DIR_FID | FAN_REPORT_FID (dir fid + child fid) 16 * - FAN_REPORT_DFID_NAME | FAN_REPORT_FID (dir fid + name + child fid) 17 * - FAN_REPORT_DFID_NAME_TARGET (dir fid + name + created/deleted file fid) 18 */ 19 20#define _GNU_SOURCE 21#include "config.h" 22 23#include <stdio.h> 24#include <sys/stat.h> 25#include <sys/types.h> 26#include <errno.h> 27#include <string.h> 28#include <sys/mount.h> 29#include <sys/syscall.h> 30#include "tst_test.h" 31 32#ifdef HAVE_SYS_FANOTIFY_H 33#include "fanotify.h" 34 35#define EVENT_MAX 20 36 37/* Size of the event structure, not including file handle */ 38#define EVENT_SIZE (sizeof(struct fanotify_event_metadata) + \ 39 sizeof(struct fanotify_event_info_fid)) 40 41/* Tripple events buffer size to account for file handles and names */ 42#define EVENT_BUF_LEN (EVENT_MAX * EVENT_SIZE * 3) 43 44#define BUF_SIZE 256 45 46#ifdef HAVE_NAME_TO_HANDLE_AT 47struct event_t { 48 unsigned long long mask; 49 struct fanotify_fid_t *fid; 50 struct fanotify_fid_t *child_fid; 51 char name[BUF_SIZE]; 52 char name2[BUF_SIZE]; 53 char *old_name; 54 char *new_name; 55}; 56 57static char fname1[BUF_SIZE + 11], fname2[BUF_SIZE + 11]; 58static char dname1[BUF_SIZE], dname2[BUF_SIZE], tmpdir[BUF_SIZE]; 59static int fd_notify; 60 61static struct event_t event_set[EVENT_MAX]; 62 63static char event_buf[EVENT_BUF_LEN]; 64 65#define DIR_NAME1 "test_dir1" 66#define DIR_NAME2 "test_dir2" 67#define FILE_NAME1 "test_file1" 68#define FILE_NAME2 "test_file2" 69#define MOUNT_PATH "fs_mnt" 70#define TEMP_DIR MOUNT_PATH "/temp_dir" 71 72static int fan_report_target_fid_unsupported; 73static int rename_events_unsupported; 74 75static struct test_case_t { 76 const char *tname; 77 struct fanotify_group_type group; 78 struct fanotify_mark_type mark; 79 unsigned long mask; 80 struct fanotify_mark_type sub_mark; 81 unsigned long sub_mask; 82 unsigned long tmpdir_ignored_mask; 83} test_cases[] = { 84 { 85 "FAN_REPORT_DFID_NAME monitor filesystem for create/delete/move/open/close", 86 INIT_FANOTIFY_GROUP_TYPE(REPORT_DFID_NAME), 87 INIT_FANOTIFY_MARK_TYPE(FILESYSTEM), 88 FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR, 89 /* Mount watch for events possible on children */ 90 INIT_FANOTIFY_MARK_TYPE(MOUNT), 91 FAN_OPEN | FAN_CLOSE | FAN_ONDIR, 92 0, 93 }, 94 { 95 "FAN_REPORT_DFID_NAME monitor directories for create/delete/move/open/close", 96 INIT_FANOTIFY_GROUP_TYPE(REPORT_DFID_NAME), 97 INIT_FANOTIFY_MARK_TYPE(INODE), 98 FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_ONDIR, 99 /* Watches for self events on subdir and events on subdir's children */ 100 INIT_FANOTIFY_MARK_TYPE(INODE), 101 FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR | 102 FAN_OPEN | FAN_CLOSE | FAN_EVENT_ON_CHILD, 103 0, 104 }, 105 { 106 "FAN_REPORT_DIR_FID monitor filesystem for create/delete/move/open/close", 107 INIT_FANOTIFY_GROUP_TYPE(REPORT_DIR_FID), 108 INIT_FANOTIFY_MARK_TYPE(FILESYSTEM), 109 FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR, 110 /* Mount watch for events possible on children */ 111 INIT_FANOTIFY_MARK_TYPE(MOUNT), 112 FAN_OPEN | FAN_CLOSE | FAN_ONDIR, 113 0, 114 }, 115 { 116 "FAN_REPORT_DIR_FID monitor directories for create/delete/move/open/close", 117 INIT_FANOTIFY_GROUP_TYPE(REPORT_DIR_FID), 118 INIT_FANOTIFY_MARK_TYPE(INODE), 119 FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_ONDIR, 120 /* Watches for self events on subdir and events on subdir's children */ 121 INIT_FANOTIFY_MARK_TYPE(INODE), 122 FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR | 123 FAN_OPEN | FAN_CLOSE | FAN_EVENT_ON_CHILD, 124 0, 125 }, 126 { 127 "FAN_REPORT_DFID_FID monitor filesystem for create/delete/move/open/close", 128 INIT_FANOTIFY_GROUP_TYPE(REPORT_DFID_FID), 129 INIT_FANOTIFY_MARK_TYPE(FILESYSTEM), 130 FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR, 131 /* Mount watch for events possible on children */ 132 INIT_FANOTIFY_MARK_TYPE(MOUNT), 133 FAN_OPEN | FAN_CLOSE | FAN_ONDIR, 134 0, 135 }, 136 { 137 "FAN_REPORT_DFID_FID monitor directories for create/delete/move/open/close", 138 INIT_FANOTIFY_GROUP_TYPE(REPORT_DFID_FID), 139 INIT_FANOTIFY_MARK_TYPE(INODE), 140 FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_ONDIR, 141 /* Watches for self events on subdir and events on subdir's children */ 142 INIT_FANOTIFY_MARK_TYPE(INODE), 143 FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR | 144 FAN_OPEN | FAN_CLOSE | FAN_EVENT_ON_CHILD, 145 0, 146 }, 147 { 148 "FAN_REPORT_DFID_NAME_FID monitor filesystem for create/delete/move/open/close", 149 INIT_FANOTIFY_GROUP_TYPE(REPORT_DFID_NAME_FID), 150 INIT_FANOTIFY_MARK_TYPE(FILESYSTEM), 151 FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR, 152 /* Mount watch for events possible on children */ 153 INIT_FANOTIFY_MARK_TYPE(MOUNT), 154 FAN_OPEN | FAN_CLOSE | FAN_ONDIR, 155 0, 156 }, 157 { 158 "FAN_REPORT_DFID_NAME_FID monitor directories for create/delete/move/open/close", 159 INIT_FANOTIFY_GROUP_TYPE(REPORT_DFID_NAME_FID), 160 INIT_FANOTIFY_MARK_TYPE(INODE), 161 FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_ONDIR, 162 /* Watches for self events on subdir and events on subdir's children */ 163 INIT_FANOTIFY_MARK_TYPE(INODE), 164 FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR | 165 FAN_OPEN | FAN_CLOSE | FAN_EVENT_ON_CHILD, 166 0, 167 }, 168 { 169 "FAN_REPORT_DFID_NAME_TARGET monitor filesystem for create/delete/move/open/close", 170 INIT_FANOTIFY_GROUP_TYPE(REPORT_DFID_NAME_TARGET), 171 INIT_FANOTIFY_MARK_TYPE(FILESYSTEM), 172 FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR, 173 /* Mount watch for events possible on children */ 174 INIT_FANOTIFY_MARK_TYPE(MOUNT), 175 FAN_OPEN | FAN_CLOSE | FAN_ONDIR, 176 0, 177 }, 178 { 179 "FAN_REPORT_DFID_NAME_TARGET monitor directories for create/delete/move/open/close", 180 INIT_FANOTIFY_GROUP_TYPE(REPORT_DFID_NAME_TARGET), 181 INIT_FANOTIFY_MARK_TYPE(INODE), 182 FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_ONDIR, 183 /* Watches for self events on subdir and events on subdir's children */ 184 INIT_FANOTIFY_MARK_TYPE(INODE), 185 FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR | 186 FAN_OPEN | FAN_CLOSE | FAN_EVENT_ON_CHILD, 187 0, 188 }, 189 { 190 "FAN_REPORT_DFID_NAME_FID monitor filesystem for create/delete/move/rename/open/close", 191 INIT_FANOTIFY_GROUP_TYPE(REPORT_DFID_NAME_FID), 192 INIT_FANOTIFY_MARK_TYPE(FILESYSTEM), 193 FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_RENAME | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR, 194 /* Mount watch for events possible on children */ 195 INIT_FANOTIFY_MARK_TYPE(MOUNT), 196 FAN_OPEN | FAN_CLOSE | FAN_ONDIR, 197 0, 198 }, 199 { 200 "FAN_REPORT_DFID_NAME_FID monitor directories for create/delete/move/rename/open/close", 201 INIT_FANOTIFY_GROUP_TYPE(REPORT_DFID_NAME_FID), 202 INIT_FANOTIFY_MARK_TYPE(INODE), 203 FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_RENAME | FAN_ONDIR, 204 /* Watches for self events on subdir and events on subdir's children */ 205 INIT_FANOTIFY_MARK_TYPE(INODE), 206 FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_RENAME | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR | 207 FAN_OPEN | FAN_CLOSE | FAN_EVENT_ON_CHILD, 208 0, 209 }, 210 { 211 "FAN_REPORT_DFID_NAME_TARGET monitor filesystem for create/delete/move/rename/open/close", 212 INIT_FANOTIFY_GROUP_TYPE(REPORT_DFID_NAME_TARGET), 213 INIT_FANOTIFY_MARK_TYPE(FILESYSTEM), 214 FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_RENAME | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR, 215 /* Mount watch for events possible on children */ 216 INIT_FANOTIFY_MARK_TYPE(MOUNT), 217 FAN_OPEN | FAN_CLOSE | FAN_ONDIR, 218 0, 219 }, 220 { 221 "FAN_REPORT_DFID_NAME_TARGET monitor directories for create/delete/move/rename/open/close", 222 INIT_FANOTIFY_GROUP_TYPE(REPORT_DFID_NAME_TARGET), 223 INIT_FANOTIFY_MARK_TYPE(INODE), 224 FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_RENAME | FAN_ONDIR, 225 /* Watches for self events on subdir and events on subdir's children */ 226 INIT_FANOTIFY_MARK_TYPE(INODE), 227 FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_RENAME | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR | 228 FAN_OPEN | FAN_CLOSE | FAN_EVENT_ON_CHILD, 229 0, 230 }, 231 { 232 "FAN_REPORT_DFID_NAME_FID monitor directories and ignore FAN_RENAME events to/from temp directory", 233 INIT_FANOTIFY_GROUP_TYPE(REPORT_DFID_NAME_FID), 234 INIT_FANOTIFY_MARK_TYPE(INODE), 235 FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_RENAME | FAN_ONDIR, 236 /* Watches for self events on subdir and events on subdir's children */ 237 INIT_FANOTIFY_MARK_TYPE(INODE), 238 FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_RENAME | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR | 239 FAN_OPEN | FAN_CLOSE | FAN_EVENT_ON_CHILD, 240 /* Ignore FAN_RENAME to/from tmpdir */ 241 FAN_MOVE | FAN_RENAME, 242 }, 243 { 244 "FAN_REPORT_DFID_NAME_FID monitor filesystem and ignore FAN_RENAME events to/from temp directory", 245 INIT_FANOTIFY_GROUP_TYPE(REPORT_DFID_NAME_FID), 246 INIT_FANOTIFY_MARK_TYPE(FILESYSTEM), 247 FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_RENAME | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR, 248 /* Mount watch for events possible on children */ 249 INIT_FANOTIFY_MARK_TYPE(MOUNT), 250 FAN_OPEN | FAN_CLOSE | FAN_ONDIR, 251 /* Ignore FAN_RENAME to/from tmpdir */ 252 FAN_MOVE | FAN_RENAME, 253 }, 254}; 255 256static void do_test(unsigned int number) 257{ 258 int fd, dirfd, len = 0, i = 0, test_num = 0, tst_count = 0; 259 struct test_case_t *tc = &test_cases[number]; 260 struct fanotify_group_type *group = &tc->group; 261 struct fanotify_mark_type *mark = &tc->mark; 262 struct fanotify_mark_type *sub_mark = &tc->sub_mark; 263 struct fanotify_fid_t root_fid, dir_fid, file_fid; 264 struct fanotify_fid_t *child_fid = NULL, *subdir_fid = NULL; 265 int report_name = (group->flag & FAN_REPORT_NAME); 266 int report_target_fid = (group->flag & FAN_REPORT_TARGET_FID); 267 int report_rename = (tc->mask & FAN_RENAME); 268 int fs_mark = (mark->flag == FAN_MARK_FILESYSTEM); 269 int rename_ignored = (tc->tmpdir_ignored_mask & FAN_RENAME); 270 271 tst_res(TINFO, "Test #%d: %s", number, tc->tname); 272 273 if (report_rename && rename_events_unsupported) { 274 tst_res(TCONF, "FAN_RENAME not supported in kernel?"); 275 return; 276 } 277 278 if (fan_report_target_fid_unsupported && report_target_fid) { 279 FANOTIFY_INIT_FLAGS_ERR_MSG(FAN_REPORT_TARGET_FID, 280 fan_report_target_fid_unsupported); 281 return; 282 } 283 284 fd_notify = SAFE_FANOTIFY_INIT(group->flag, 0); 285 286 /* 287 * Watch dir modify events with name in filesystem/dir 288 */ 289 SAFE_FANOTIFY_MARK(fd_notify, FAN_MARK_ADD | mark->flag, tc->mask, 290 AT_FDCWD, MOUNT_PATH); 291 292 /* Save the mount root fid */ 293 fanotify_save_fid(MOUNT_PATH, &root_fid); 294 295 /* 296 * Create subdir and watch open events "on children" with name. 297 * Make it a mount root. 298 */ 299 SAFE_MKDIR(dname1, 0755); 300 SAFE_MOUNT(dname1, dname1, "none", MS_BIND, NULL); 301 302 /* Save the subdir fid */ 303 fanotify_save_fid(dname1, &dir_fid); 304 /* With FAN_REPORT_TARGET_FID, report subdir fid also for dirent events */ 305 if (report_target_fid) 306 subdir_fid = &dir_fid; 307 308 if (tc->sub_mask) 309 SAFE_FANOTIFY_MARK(fd_notify, FAN_MARK_ADD | sub_mark->flag, 310 tc->sub_mask, AT_FDCWD, dname1); 311 /* 312 * ignore FAN_RENAME to/from tmpdir, so we won't get the FAN_RENAME events 313 * when subdir is moved via tmpdir. 314 * FAN_MOVE is also set in ignored mark of tmpdir, but it will have no effect 315 * and the MOVED_FROM/TO events will still be reported. 316 */ 317 if (tc->tmpdir_ignored_mask) 318 SAFE_FANOTIFY_MARK(fd_notify, FAN_MARK_ADD | 319 FAN_MARK_IGNORED_MASK | 320 FAN_MARK_IGNORED_SURV_MODIFY, 321 tc->tmpdir_ignored_mask, AT_FDCWD, TEMP_DIR); 322 323 memset(event_set, 0, sizeof(event_set)); 324 event_set[tst_count].mask = FAN_CREATE | FAN_ONDIR; 325 event_set[tst_count].fid = &root_fid; 326 event_set[tst_count].child_fid = subdir_fid; 327 strcpy(event_set[tst_count].name, DIR_NAME1); 328 tst_count++; 329 330 /* Generate modify events "on child" */ 331 fd = SAFE_CREAT(fname1, 0755); 332 333 /* Save the file fid */ 334 fanotify_save_fid(fname1, &file_fid); 335 /* With FAN_REPORT_TARGET_FID, report child fid also for dirent events */ 336 if (report_target_fid) 337 child_fid = &file_fid; 338 339 SAFE_WRITE(SAFE_WRITE_ALL, fd, "1", 1); 340 SAFE_RENAME(fname1, fname2); 341 342 SAFE_CLOSE(fd); 343 344 /* Generate delete events with fname2 */ 345 SAFE_UNLINK(fname2); 346 347 /* Read events on files in subdir */ 348 len += SAFE_READ(0, fd_notify, event_buf + len, EVENT_BUF_LEN - len); 349 350 /* 351 * FAN_CREATE|FAN_DELETE|FAN_MOVE events with the same name are merged. 352 */ 353 event_set[tst_count].mask = FAN_CREATE | FAN_MOVED_FROM; 354 event_set[tst_count].fid = &dir_fid; 355 event_set[tst_count].child_fid = child_fid; 356 strcpy(event_set[tst_count].name, FILE_NAME1); 357 tst_count++; 358 /* 359 * Event on non-dir child with the same name may be merged with the 360 * directory entry modification events above, unless FAN_REPORT_FID is 361 * set and child fid is reported. If FAN_REPORT_FID is set but 362 * FAN_REPORT_NAME is not set, then FAN_CREATE above is merged with 363 * FAN_DELETE below and FAN_OPEN will be merged with FAN_CLOSE. 364 */ 365 if (report_name) { 366 event_set[tst_count].mask = FAN_OPEN; 367 event_set[tst_count].fid = &dir_fid; 368 event_set[tst_count].child_fid = &file_fid; 369 strcpy(event_set[tst_count].name, FILE_NAME1); 370 tst_count++; 371 } 372 /* 373 * FAN_RENAME event is independent of MOVED_FROM/MOVED_TO and not merged 374 * with any other event because it has different info records. 375 */ 376 if (report_rename) { 377 event_set[tst_count].mask = FAN_RENAME; 378 event_set[tst_count].fid = &dir_fid; 379 event_set[tst_count].child_fid = child_fid; 380 strcpy(event_set[tst_count].name, FILE_NAME1); 381 strcpy(event_set[tst_count].name2, FILE_NAME2); 382 event_set[tst_count].old_name = event_set[tst_count].name; 383 event_set[tst_count].new_name = event_set[tst_count].name2; 384 tst_count++; 385 } 386 387 event_set[tst_count].mask = FAN_DELETE | FAN_MOVED_TO; 388 /* 389 * With FAN_REPORT_TARGET_FID, close of FILE_NAME2 is merged with 390 * moved_to and delete events, because they all have parent and 391 * child fid records. 392 */ 393 if (report_target_fid) 394 event_set[tst_count].mask |= FAN_CLOSE_WRITE; 395 event_set[tst_count].fid = &dir_fid; 396 event_set[tst_count].child_fid = child_fid; 397 strcpy(event_set[tst_count].name, FILE_NAME2); 398 tst_count++; 399 /* 400 * When not reporting name, open of FILE_NAME1 is merged 401 * with close of FILE_NAME2. 402 */ 403 if (!report_name) { 404 event_set[tst_count].mask = FAN_OPEN | FAN_CLOSE_WRITE; 405 event_set[tst_count].fid = &dir_fid; 406 event_set[tst_count].child_fid = &file_fid; 407 strcpy(event_set[tst_count].name, ""); 408 tst_count++; 409 } 410 /* 411 * Directory watch does not get self events on children. 412 * Filesystem watch gets self event w/o name info if FAN_REPORT_FID 413 * is set. 414 */ 415 if (fs_mark && (group->flag & FAN_REPORT_FID)) { 416 event_set[tst_count].mask = FAN_DELETE_SELF | FAN_MOVE_SELF; 417 event_set[tst_count].fid = &file_fid; 418 event_set[tst_count].child_fid = NULL; 419 strcpy(event_set[tst_count].name, ""); 420 tst_count++; 421 } 422 /* 423 * Without FAN_REPORT_TARGET_FID, close of FILE_NAME2 is not merged with 424 * open of FILE_NAME1 and it is received after the merged self events. 425 */ 426 if (report_name && !report_target_fid) { 427 event_set[tst_count].mask = FAN_CLOSE_WRITE; 428 event_set[tst_count].fid = &dir_fid; 429 event_set[tst_count].child_fid = &file_fid; 430 strcpy(event_set[tst_count].name, FILE_NAME2); 431 tst_count++; 432 } 433 434 dirfd = SAFE_OPEN(dname1, O_RDONLY | O_DIRECTORY); 435 SAFE_CLOSE(dirfd); 436 437 SAFE_UMOUNT(dname1); 438 439 /* 440 * Directory watch gets open/close events on itself and on its subdirs. 441 * Filesystem watch gets open/close event on all directories with name ".". 442 */ 443 event_set[tst_count].mask = FAN_OPEN | FAN_CLOSE_NOWRITE | FAN_ONDIR; 444 event_set[tst_count].fid = &dir_fid; 445 event_set[tst_count].child_fid = NULL; 446 strcpy(event_set[tst_count].name, "."); 447 tst_count++; 448 /* 449 * Directory watch gets self event on itself and filesystem watch gets 450 * self event on all directories with name ".". 451 */ 452 event_set[tst_count].mask = FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR; 453 event_set[tst_count].fid = &dir_fid; 454 event_set[tst_count].child_fid = NULL; 455 strcpy(event_set[tst_count].name, "."); 456 tst_count++; 457 458 /* 459 * If only root dir and subdir are watched, a rename via an unwatched tmpdir 460 * will observe the same MOVED_FROM/MOVED_TO events as a direct rename, 461 * but will observe 2 FAN_RENAME events with 1 info dir+name record each 462 * instead of 1 FAN_RENAME event with 2 dir+name info records. 463 * 464 * If tmpdir is ignoring FAN_RENAME, we will get the MOVED_FROM/MOVED_TO 465 * events and will not get the FAN_RENAME event for rename via tmpdir. 466 */ 467 if (!fs_mark || rename_ignored) { 468 SAFE_RENAME(dname1, tmpdir); 469 SAFE_RENAME(tmpdir, dname2); 470 } else { 471 SAFE_RENAME(dname1, dname2); 472 } 473 SAFE_RMDIR(dname2); 474 475 /* Read more events on dirs */ 476 len += SAFE_READ(0, fd_notify, event_buf + len, EVENT_BUF_LEN - len); 477 478 /* 479 * FAN_RENAME event is independent of MOVED_FROM/MOVED_TO and not merged 480 * with any other event because it has different info records. 481 * When renamed via an unwatched tmpdir, the 1st FAN_RENAME event has the 482 * info record of root_fid+DIR_NAME1 and the 2nd FAN_RENAME event has the 483 * info record of root_fid+DIR_NAME2. 484 * If tmpdir is ignoring FAN_RENAME, we get no FAN_RENAME events at all. 485 */ 486 if (report_rename && !rename_ignored) { 487 event_set[tst_count].mask = FAN_RENAME | FAN_ONDIR; 488 event_set[tst_count].fid = &root_fid; 489 event_set[tst_count].child_fid = subdir_fid; 490 strcpy(event_set[tst_count].name, DIR_NAME1); 491 event_set[tst_count].old_name = event_set[tst_count].name; 492 if (fs_mark) { 493 strcpy(event_set[tst_count].name2, DIR_NAME2); 494 event_set[tst_count].new_name = event_set[tst_count].name2; 495 } 496 tst_count++; 497 } 498 event_set[tst_count].mask = FAN_MOVED_FROM | FAN_ONDIR; 499 event_set[tst_count].fid = &root_fid; 500 event_set[tst_count].child_fid = subdir_fid; 501 strcpy(event_set[tst_count].name, DIR_NAME1); 502 tst_count++; 503 if (report_rename && !fs_mark && !rename_ignored) { 504 event_set[tst_count].mask = FAN_RENAME | FAN_ONDIR; 505 event_set[tst_count].fid = &root_fid; 506 event_set[tst_count].child_fid = subdir_fid; 507 strcpy(event_set[tst_count].name, DIR_NAME2); 508 event_set[tst_count].new_name = event_set[tst_count].name; 509 tst_count++; 510 } 511 event_set[tst_count].mask = FAN_DELETE | FAN_MOVED_TO | FAN_ONDIR; 512 event_set[tst_count].fid = &root_fid; 513 event_set[tst_count].child_fid = subdir_fid; 514 strcpy(event_set[tst_count].name, DIR_NAME2); 515 tst_count++; 516 /* Expect no more events */ 517 event_set[tst_count].mask = 0; 518 519 /* 520 * Cleanup the marks 521 */ 522 SAFE_CLOSE(fd_notify); 523 fd_notify = -1; 524 525 while (i < len) { 526 struct event_t *expected = &event_set[test_num]; 527 struct fanotify_event_metadata *event; 528 struct fanotify_event_info_fid *event_fid; 529 struct fanotify_event_info_fid *child_fid; 530 struct fanotify_fid_t *expected_fid = expected->fid; 531 struct fanotify_fid_t *expected_child_fid = expected->child_fid; 532 struct file_handle *file_handle; 533 unsigned int fhlen; 534 const char *filename; 535 int namelen, info_type, mask_match, info_id = 0; 536 537 event = (struct fanotify_event_metadata *)&event_buf[i]; 538 event_fid = (struct fanotify_event_info_fid *)(event + 1); 539 file_handle = (struct file_handle *)event_fid->handle; 540 fhlen = file_handle->handle_bytes; 541 filename = (char *)file_handle->f_handle + fhlen; 542 child_fid = (void *)((char *)event_fid + event_fid->hdr.len); 543 namelen = (char *)child_fid - (char *)filename; 544 /* End of event_fid could have name, zero padding, both or none */ 545 if (namelen > 0) { 546 namelen = strlen(filename); 547 } else { 548 filename = ""; 549 namelen = 0; 550 } 551 /* Is there a child fid after first fid record? */ 552 if (((char *)child_fid - (char *)event) >= event->event_len) 553 child_fid = NULL; 554 555 if (!(group->flag & FAN_REPORT_FID)) 556 expected_child_fid = NULL; 557 558 if (!report_name) 559 expected->name[0] = 0; 560 561 if (expected->mask & FAN_RENAME) { 562 /* If old name is not reported, first record is new name */ 563 info_type = expected->old_name ? 564 FAN_EVENT_INFO_TYPE_OLD_DFID_NAME : 565 FAN_EVENT_INFO_TYPE_NEW_DFID_NAME; 566 /* The 2nd fid is same as 1st becaue we rename in same parent */ 567 if (expected->name2[0]) 568 expected_child_fid = expected_fid; 569 } else if (expected->name[0]) { 570 info_type = FAN_EVENT_INFO_TYPE_DFID_NAME; 571 } else if (expected->mask & FAN_ONDIR) { 572 info_type = FAN_EVENT_INFO_TYPE_DFID; 573 } else if (expected->mask & (FAN_DELETE_SELF | FAN_MOVE_SELF)) { 574 /* Self event on non-dir has only child fid */ 575 info_type = FAN_EVENT_INFO_TYPE_FID; 576 } else { 577 info_type = FAN_EVENT_INFO_TYPE_DFID; 578 } 579 580 /* 581 * Event may contain more than the expected mask, but it must 582 * have all the bits in expected mask. 583 * Expected event on dir must not get event on non dir and the 584 * other way around. 585 */ 586 mask_match = ((event->mask & expected->mask) && 587 !(expected->mask & ~event->mask) && 588 !((event->mask ^ expected->mask) & FAN_ONDIR)); 589 590check_match: 591 if (test_num >= tst_count) { 592 tst_res(TFAIL, 593 "got unnecessary event: mask=%llx " 594 "pid=%u fd=%d name='%s' " 595 "len=%d info_type=%d info_len=%d fh_len=%d", 596 (unsigned long long)event->mask, 597 (unsigned int)event->pid, event->fd, filename, 598 event->event_len, event_fid->hdr.info_type, 599 event_fid->hdr.len, fhlen); 600 } else if (!fhlen || namelen < 0) { 601 tst_res(TFAIL, 602 "got event without fid: mask=%llx pid=%u fd=%d, " 603 "len=%d info_type=%d info_len=%d fh_len=%d", 604 (unsigned long long)event->mask, 605 (unsigned int)event->pid, event->fd, 606 event->event_len, event_fid->hdr.info_type, 607 event_fid->hdr.len, fhlen); 608 } else if (!mask_match) { 609 tst_res(TFAIL, 610 "got event: mask=%llx (expected %llx) " 611 "pid=%u fd=%d name='%s' " 612 "len=%d info_type=%d info_len=%d fh_len=%d", 613 (unsigned long long)event->mask, expected->mask, 614 (unsigned int)event->pid, event->fd, filename, 615 event->event_len, event_fid->hdr.info_type, 616 event_fid->hdr.len, fhlen); 617 } else if (info_type != event_fid->hdr.info_type) { 618 tst_res(TFAIL, 619 "got event: mask=%llx pid=%u fd=%d, " 620 "len=%d info_type=%d expected(%d) info_len=%d fh_len=%d", 621 (unsigned long long)event->mask, 622 (unsigned int)event->pid, event->fd, 623 event->event_len, event_fid->hdr.info_type, 624 info_type, event_fid->hdr.len, fhlen); 625 } else if (fhlen != expected_fid->handle.handle_bytes) { 626 tst_res(TFAIL, 627 "got event: mask=%llx pid=%u fd=%d name='%s' " 628 "len=%d info_type=%d info_len=%d fh_len=%d expected(%d) " 629 "fh_type=%d", 630 (unsigned long long)event->mask, 631 (unsigned int)event->pid, event->fd, filename, 632 event->event_len, info_type, 633 event_fid->hdr.len, fhlen, 634 expected_fid->handle.handle_bytes, 635 file_handle->handle_type); 636 } else if (file_handle->handle_type != 637 expected_fid->handle.handle_type) { 638 tst_res(TFAIL, 639 "got event: mask=%llx pid=%u fd=%d name='%s' " 640 "len=%d info_type=%d info_len=%d fh_len=%d " 641 "fh_type=%d expected(%x)", 642 (unsigned long long)event->mask, 643 (unsigned int)event->pid, event->fd, filename, 644 event->event_len, info_type, 645 event_fid->hdr.len, fhlen, 646 file_handle->handle_type, 647 expected_fid->handle.handle_type); 648 } else if (memcmp(file_handle->f_handle, 649 expected_fid->handle.f_handle, fhlen)) { 650 tst_res(TFAIL, 651 "got event: mask=%llx pid=%u fd=%d name='%s' " 652 "len=%d info_type=%d info_len=%d fh_len=%d " 653 "fh_type=%d unexpected file handle (%x...)", 654 (unsigned long long)event->mask, 655 (unsigned int)event->pid, event->fd, filename, 656 event->event_len, info_type, 657 event_fid->hdr.len, fhlen, 658 file_handle->handle_type, 659 *(int *)(file_handle->f_handle)); 660 } else if (memcmp(&event_fid->fsid, &expected_fid->fsid, 661 sizeof(event_fid->fsid)) != 0) { 662 tst_res(TFAIL, 663 "got event: mask=%llx pid=%u fd=%d name='%s' " 664 "len=%d info_type=%d info_len=%d fh_len=%d " 665 "fsid=%x.%x (expected %x.%x)", 666 (unsigned long long)event->mask, 667 (unsigned int)event->pid, event->fd, filename, 668 event->event_len, info_type, 669 event_fid->hdr.len, fhlen, 670 FSID_VAL_MEMBER(event_fid->fsid, 0), 671 FSID_VAL_MEMBER(event_fid->fsid, 1), 672 expected_fid->fsid.val[0], 673 expected_fid->fsid.val[1]); 674 } else if (strcmp(expected->name, filename)) { 675 tst_res(TFAIL, 676 "got event: mask=%llx " 677 "pid=%u fd=%d name='%s' expected('%s') " 678 "len=%d info_type=%d info_len=%d fh_len=%d", 679 (unsigned long long)event->mask, 680 (unsigned int)event->pid, event->fd, 681 filename, expected->name, 682 event->event_len, event_fid->hdr.info_type, 683 event_fid->hdr.len, fhlen); 684 } else if (event->pid != getpid()) { 685 tst_res(TFAIL, 686 "got event: mask=%llx pid=%u " 687 "(expected %u) fd=%d name='%s' " 688 "len=%d info_type=%d info_len=%d fh_len=%d", 689 (unsigned long long)event->mask, 690 (unsigned int)event->pid, 691 (unsigned int)getpid(), 692 event->fd, filename, 693 event->event_len, event_fid->hdr.info_type, 694 event_fid->hdr.len, fhlen); 695 } else if (!!child_fid != !!expected_child_fid) { 696 tst_res(TFAIL, 697 "got event: mask=%llx " 698 "pid=%u fd=%d name='%s' num_info=%d (expected %d) " 699 "len=%d info_type=%d info_len=%d fh_len=%d", 700 (unsigned long long)event->mask, 701 (unsigned int)event->pid, event->fd, 702 filename, 1 + !!child_fid, 1 + !!expected_child_fid, 703 event->event_len, event_fid->hdr.info_type, 704 event_fid->hdr.len, fhlen); 705 } else if (child_fid) { 706 tst_res(TINFO, 707 "got event #%d: info #%d: info_type=%d info_len=%d fh_len=%d", 708 test_num, info_id, event_fid->hdr.info_type, 709 event_fid->hdr.len, fhlen); 710 711 /* Recheck event_fid match with child_fid */ 712 event_fid = child_fid; 713 expected_fid = expected->child_fid; 714 info_id = 1; 715 info_type = FAN_EVENT_INFO_TYPE_FID; 716 /* 717 * With FAN_RENAME event, expect a second record of 718 * type NEW_DFID_NAME, which in our case 719 * has the same fid as the source dir in 1st record. 720 * TODO: check the 2nd name and the 3rd child fid record. 721 */ 722 if (event->mask & FAN_RENAME && expected->name2[0]) { 723 info_type = FAN_EVENT_INFO_TYPE_NEW_DFID_NAME; 724 expected_fid = expected->fid; 725 } 726 file_handle = (struct file_handle *)event_fid->handle; 727 fhlen = file_handle->handle_bytes; 728 child_fid = NULL; 729 expected_child_fid = NULL; 730 goto check_match; 731 } else { 732 tst_res(TPASS, 733 "got event #%d: mask=%llx pid=%u fd=%d name='%s' " 734 "len=%d; info #%d: info_type=%d info_len=%d fh_len=%d", 735 test_num, (unsigned long long)event->mask, 736 (unsigned int)event->pid, event->fd, filename, 737 event->event_len, info_id, event_fid->hdr.info_type, 738 event_fid->hdr.len, fhlen); 739 } 740 741 if (test_num < tst_count) 742 test_num++; 743 744 if (mask_match) { 745 /* In case of merged event match next expected mask */ 746 event->mask &= ~expected->mask | FAN_ONDIR; 747 if (event->mask & ~FAN_ONDIR) 748 continue; 749 } 750 751 i += event->event_len; 752 if (event->fd > 0) 753 SAFE_CLOSE(event->fd); 754 } 755 756 for (; test_num < tst_count; test_num++) { 757 tst_res(TFAIL, "didn't get event: mask=%llx, name='%s'", 758 event_set[test_num].mask, event_set[test_num].name); 759 760 } 761} 762 763static void setup(void) 764{ 765 REQUIRE_FANOTIFY_INIT_FLAGS_SUPPORTED_ON_FS(FAN_REPORT_DIR_FID, MOUNT_PATH); 766 fan_report_target_fid_unsupported = 767 fanotify_init_flags_supported_on_fs(FAN_REPORT_DFID_NAME_TARGET, MOUNT_PATH); 768 rename_events_unsupported = 769 fanotify_events_supported_by_kernel(FAN_RENAME, FAN_REPORT_DFID_NAME, 0); 770 771 SAFE_MKDIR(TEMP_DIR, 0755); 772 sprintf(dname1, "%s/%s", MOUNT_PATH, DIR_NAME1); 773 sprintf(dname2, "%s/%s", MOUNT_PATH, DIR_NAME2); 774 sprintf(tmpdir, "%s/%s", TEMP_DIR, DIR_NAME2); 775 sprintf(fname1, "%s/%s", dname1, FILE_NAME1); 776 sprintf(fname2, "%s/%s", dname1, FILE_NAME2); 777} 778 779static void cleanup(void) 780{ 781 if (fd_notify > 0) 782 SAFE_CLOSE(fd_notify); 783} 784 785static struct tst_test test = { 786 .test = do_test, 787 .tcnt = ARRAY_SIZE(test_cases), 788 .setup = setup, 789 .cleanup = cleanup, 790 .mount_device = 1, 791 .mntpoint = MOUNT_PATH, 792 .all_filesystems = 1, 793 .needs_root = 1 794}; 795 796#else 797 TST_TEST_TCONF("system does not have required name_to_handle_at() support"); 798#endif 799#else 800 TST_TEST_TCONF("system doesn't have required fanotify support"); 801#endif 802