static void check_mark(char *file, unsigned long long flag, char *flagstr, int expect, void (*test_event)(char *)) { if (myfanotify_mark(fd_notify, FAN_MARK_ADD | flag, FAN_OPEN, AT_FDCWD, file) != expect) { tst_resm(TFAIL, "fanotify_mark (%d, FAN_MARK_ADD | %s, FAN_OPEN, AT_FDCWD, " "'%s') %s", fd_notify, flagstr, file, expect_str_fail(expect)); } else { tst_resm(TPASS, "fanotify_mark (%d, FAN_MARK_ADD | %s, FAN_OPEN, AT_FDCWD, " "'%s') %s", fd_notify, flagstr, file, expect_str_pass(expect)); /* If we expected failure there's nothing to clean up */ if (expect == -1) return; if (test_event) test_event(file); if (myfanotify_mark(fd_notify, FAN_MARK_REMOVE | flag, FAN_OPEN, AT_FDCWD, file) < 0) { tst_brkm(TBROK | TERRNO, cleanup, "fanotify_mark (%d, FAN_MARK_REMOVE | %s, " "FAN_OPEN, AT_FDCWD, '%s') failed", fd_notify, flagstr, file); } } }
int main(int ac, char **av) { int lc; const char *msg; if ((msg = parse_opts(ac, av, NULL, NULL)) != NULL) tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg); setup(); for (lc = 0; TEST_LOOPING(lc); lc++) { /* Check ONLYDIR on a directory */ CHECK_MARK(".", FAN_MARK_ONLYDIR, 0, NULL); /* Check ONLYDIR without a directory */ CHECK_MARK(fname, FAN_MARK_ONLYDIR, -1, NULL); /* Check DONT_FOLLOW for a symlink */ CHECK_MARK(sname, FAN_MARK_DONT_FOLLOW, 0, test_open_symlink); /* Check without DONT_FOLLOW for a symlink */ CHECK_MARK(sname, 0, 0, test_open_file); /* Verify FAN_MARK_FLUSH destroys all inode marks */ if (myfanotify_mark(fd_notify, FAN_MARK_ADD, FAN_OPEN, AT_FDCWD, fname) < 0) { tst_brkm(TBROK | TERRNO, cleanup, "fanotify_mark (%d, FAN_MARK_ADD, FAN_OPEN, " "AT_FDCWD, '%s') failed", fd_notify, fname); } if (myfanotify_mark(fd_notify, FAN_MARK_ADD, FAN_OPEN | FAN_ONDIR, AT_FDCWD, dir) < 0) { tst_brkm(TBROK | TERRNO, cleanup, "fanotify_mark (%d, FAN_MARK_ADD, FAN_OPEN | " "FAN_ONDIR, AT_FDCWD, '%s') failed", fd_notify, dir); } open_file(fname); verify_event(S_IFREG); open_dir(dir); verify_event(S_IFDIR); if (myfanotify_mark(fd_notify, FAN_MARK_FLUSH, 0, AT_FDCWD, ".") < 0) { tst_brkm(TBROK | TERRNO, cleanup, "fanotify_mark (%d, FAN_MARK_FLUSH, 0, " "AT_FDCWD, '.') failed", fd_notify); } open_dir(dir); verify_no_event(); } cleanup(); tst_exit(); }
static void setup(void) { int fd; tst_sig(FORK, DEF_HANDLER, cleanup); TEST_PAUSE; tst_tmpdir(); sprintf(fname, "fname_%d", getpid()); fd = SAFE_OPEN(cleanup, fname, O_CREAT | O_RDWR, 0644); SAFE_WRITE(cleanup, 1, fd, fname, 1); SAFE_CLOSE(cleanup, fd); if ((fd_notify = myfanotify_init(FAN_CLASS_CONTENT, O_RDONLY)) < 0) { if (errno == ENOSYS) { tst_brkm(TCONF, cleanup, "fanotify is not configured in this kernel."); } else { tst_brkm(TBROK | TERRNO, cleanup, "fanotify_init failed"); } } if (myfanotify_mark(fd_notify, FAN_MARK_ADD, FAN_ACCESS_PERM | FAN_OPEN_PERM, AT_FDCWD, fname) < 0) { tst_brkm(TBROK | TERRNO, cleanup, "fanotify_mark (%d, FAN_MARK_ADD, FAN_ACCESS_PERM | " "FAN_OPEN_PERM, AT_FDCWD, %s) failed. " "CONFIG_FANOTIFY_ACCESS_PERMISSIONS not " "configured in kernel?", fd_notify, fname); } }
static void setup(void) { tst_sig(NOFORK, DEF_HANDLER, cleanup); TEST_PAUSE; tst_tmpdir(); fd_notify = myfanotify_init(FAN_CLASS_NOTIF | FAN_NONBLOCK, O_RDONLY); if (fd_notify < 0) { if (errno == ENOSYS) { tst_brkm(TCONF, cleanup, "fanotify is not configured in this kernel."); } else { tst_brkm(TBROK | TERRNO, cleanup, "fanotify_init failed"); } } if (myfanotify_mark(fd_notify, FAN_MARK_MOUNT | FAN_MARK_ADD, FAN_OPEN, AT_FDCWD, ".") < 0) { tst_brkm(TBROK | TERRNO, cleanup, "fanotify_mark (%d, FAN_MARK_MOUNT | FAN_MARK_ADD, " "FAN_OPEN, AT_FDCWD, \".\") failed", fd_notify); } }
int main(int ac, char **av) { int lc; const char *msg; if ((msg = parse_opts(ac, av, NULL, NULL)) != NULL) tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg); setup(); for (lc = 0; TEST_LOOPING(lc); lc++) { int ret, len, i = 0, test_num = 0; tst_count = 0; if (myfanotify_mark(fd_notify, FAN_MARK_ADD, FAN_ACCESS | FAN_MODIFY | FAN_CLOSE | FAN_OPEN | FAN_EVENT_ON_CHILD, AT_FDCWD, ".") < 0) { tst_brkm(TBROK | TERRNO, cleanup, "fanotify_mark (%d, FAN_MARK_ADD, FAN_ACCESS | " "FAN_MODIFY | FAN_CLOSE | FAN_OPEN | " "FAN_EVENT_ON_CHILD, AT_FDCWD, '.') failed", fd_notify); } /* * generate sequence of events */ fd = SAFE_OPEN(cleanup, fname, O_RDWR | O_CREAT, 0700); event_set[tst_count] = FAN_OPEN; tst_count++; SAFE_WRITE(cleanup, 1, fd, fname, strlen(fname)); event_set[tst_count] = FAN_MODIFY; tst_count++; SAFE_CLOSE(cleanup, fd); event_set[tst_count] = FAN_CLOSE_WRITE; tst_count++; /* * Get list of events so far. We get events here to avoid * merging of following events with the previous ones. */ ret = SAFE_READ(cleanup, 0, fd_notify, event_buf, EVENT_BUF_LEN); len = ret; fd = SAFE_OPEN(cleanup, fname, O_RDONLY); event_set[tst_count] = FAN_OPEN; tst_count++; SAFE_READ(cleanup, 0, fd, buf, BUF_SIZE); event_set[tst_count] = FAN_ACCESS; tst_count++; SAFE_CLOSE(cleanup, fd); event_set[tst_count] = FAN_CLOSE_NOWRITE; tst_count++; /* * get next events */ ret = SAFE_READ(cleanup, 0, fd_notify, event_buf + len, EVENT_BUF_LEN - len); len += ret; /* * now remove child mark */ if (myfanotify_mark(fd_notify, FAN_MARK_REMOVE, FAN_EVENT_ON_CHILD, AT_FDCWD, ".") < 0) { tst_brkm(TBROK | TERRNO, cleanup, "fanotify_mark (%d, FAN_MARK REMOVE, " "FAN_EVENT_ON_CHILD, AT_FDCWD, '.') failed", fd_notify); } /* * Do something to verify events didn't get generated */ fd = SAFE_OPEN(cleanup, fname, O_RDONLY); SAFE_CLOSE(cleanup, fd); fd = SAFE_OPEN(cleanup, ".", O_RDONLY | O_DIRECTORY); event_set[tst_count] = FAN_OPEN; tst_count++; SAFE_CLOSE(cleanup, fd); event_set[tst_count] = FAN_CLOSE_NOWRITE; tst_count++; /* * Check events got generated only for the directory */ ret = SAFE_READ(cleanup, 0, fd_notify, event_buf + len, EVENT_BUF_LEN - len); len += ret; if (TST_TOTAL != tst_count) { tst_brkm(TBROK, cleanup, "TST_TOTAL and tst_count are not equal"); } tst_count = 0; /* * check events */ while (i < len) { struct fanotify_event_metadata *event; event = (struct fanotify_event_metadata *)&event_buf[i]; if (test_num >= TST_TOTAL) { tst_resm(TFAIL, "get unnecessary event: mask=%llx " "pid=%u fd=%u", (unsigned long long)event->mask, (unsigned)event->pid, event->fd); } else if (!(event->mask & event_set[test_num])) { tst_resm(TFAIL, "get event: mask=%llx (expected %llx) " "pid=%u fd=%u", (unsigned long long)event->mask, event_set[test_num], (unsigned)event->pid, event->fd); } else if (event->pid != getpid()) { tst_resm(TFAIL, "get event: mask=%llx pid=%u " "(expected %u) fd=%u", (unsigned long long)event->mask, (unsigned)event->pid, (unsigned)getpid(), event->fd); } else { tst_resm(TPASS, "get event: mask=%llx pid=%u fd=%u", (unsigned long long)event->mask, (unsigned)event->pid, event->fd); } event->mask &= ~event_set[test_num]; /* No events left in current mask? Go for next event */ if (event->mask == 0) { i += event->event_len; close(event->fd); } test_num++; } for (; test_num < TST_TOTAL; test_num++) { tst_resm(TFAIL, "didn't get event: mask=%llx", event_set[test_num]); } } cleanup(); tst_exit(); }
int main(int ac, char **av) { int lc; const char *msg; if ((msg = parse_opts(ac, av, NULL, NULL)) != NULL) tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg); setup(); for (lc = 0; TEST_LOOPING(lc); lc++) { int ret, len, i = 0, test_num = 0; tst_count = 0; if (myfanotify_mark(fd_notify, FAN_MARK_ADD, FAN_ACCESS | FAN_MODIFY | FAN_CLOSE | FAN_OPEN, AT_FDCWD, fname) < 0) { tst_brkm(TBROK | TERRNO, cleanup, "fanotify_mark (%d, FAN_MARK_ADD, FAN_ACCESS | " "FAN_MODIFY | FAN_CLOSE | FAN_OPEN, AT_FDCWD, %s) " "failed", fd_notify, fname); } /* * generate sequence of events */ fd = SAFE_OPEN(cleanup, fname, O_RDONLY); event_set[tst_count] = FAN_OPEN; tst_count++; SAFE_READ(cleanup, 0, fd, buf, BUF_SIZE); event_set[tst_count] = FAN_ACCESS; tst_count++; SAFE_CLOSE(cleanup, fd); event_set[tst_count] = FAN_CLOSE_NOWRITE; tst_count++; /* * Get list of events so far. We get events here to avoid * merging of following events with the previous ones. */ ret = SAFE_READ(cleanup, 0, fd_notify, event_buf, EVENT_BUF_LEN); len = ret; fd = SAFE_OPEN(cleanup, fname, O_RDWR | O_CREAT, 0700); event_set[tst_count] = FAN_OPEN; tst_count++; SAFE_WRITE(cleanup, 1, fd, fname, strlen(fname)); event_set[tst_count] = FAN_MODIFY; tst_count++; SAFE_CLOSE(cleanup, fd); event_set[tst_count] = FAN_CLOSE_WRITE; tst_count++; /* * get another list of events */ ret = SAFE_READ(cleanup, 0, fd_notify, event_buf + len, EVENT_BUF_LEN - len); len += ret; /* * Ignore mask testing */ /* Ignore access events */ if (myfanotify_mark(fd_notify, FAN_MARK_ADD | FAN_MARK_IGNORED_MASK, FAN_ACCESS, AT_FDCWD, fname) < 0) { tst_brkm(TBROK | TERRNO, cleanup, "fanotify_mark (%d, FAN_MARK_ADD | " "FAN_MARK_IGNORED_MASK, FAN_ACCESS, " "AT_FDCWD, %s) failed", fd_notify, fname); } fd = SAFE_OPEN(cleanup, fname, O_RDWR); event_set[tst_count] = FAN_OPEN; tst_count++; /* This event should be ignored */ SAFE_READ(cleanup, 0, fd, buf, BUF_SIZE); /* * get another list of events to verify the last one got ignored */ ret = SAFE_READ(cleanup, 0, fd_notify, event_buf + len, EVENT_BUF_LEN - len); len += ret; lseek(fd, 0, SEEK_SET); /* Generate modify event to clear ignore mask */ SAFE_WRITE(cleanup, 1, fd, fname, 1); event_set[tst_count] = FAN_MODIFY; tst_count++; /* * This event shouldn't be ignored because previous modification * should have removed the ignore mask */ SAFE_READ(cleanup, 0, fd, buf, BUF_SIZE); event_set[tst_count] = FAN_ACCESS; tst_count++; SAFE_CLOSE(cleanup, fd); event_set[tst_count] = FAN_CLOSE_WRITE; tst_count++; /* Read events to verify previous access was properly generated */ ret = SAFE_READ(cleanup, 0, fd_notify, event_buf + len, EVENT_BUF_LEN - len); len += ret; /* * Now ignore open & close events regardless of file * modifications */ if (myfanotify_mark(fd_notify, FAN_MARK_ADD | FAN_MARK_IGNORED_MASK | FAN_MARK_IGNORED_SURV_MODIFY, FAN_OPEN | FAN_CLOSE, AT_FDCWD, fname) < 0) { tst_brkm(TBROK | TERRNO, cleanup, "fanotify_mark (%d, FAN_MARK_ADD | " "FAN_MARK_IGNORED_MASK | " "FAN_MARK_IGNORED_SURV_MODIFY, FAN_OPEN | " "FAN_CLOSE, AT_FDCWD, %s) failed", fd_notify, fname); } /* This event should be ignored */ fd = SAFE_OPEN(cleanup, fname, O_RDWR); SAFE_WRITE(cleanup, 1, fd, fname, 1); event_set[tst_count] = FAN_MODIFY; tst_count++; /* This event should be still ignored */ SAFE_CLOSE(cleanup, fd); /* This event should still be ignored */ fd = SAFE_OPEN(cleanup, fname, O_RDWR); /* Read events to verify open & close were ignored */ ret = SAFE_READ(cleanup, 0, fd_notify, event_buf + len, EVENT_BUF_LEN - len); len += ret; /* Now remove open and close from ignored mask */ if (myfanotify_mark(fd_notify, FAN_MARK_REMOVE | FAN_MARK_IGNORED_MASK, FAN_OPEN | FAN_CLOSE, AT_FDCWD, fname) < 0) { tst_brkm(TBROK | TERRNO, cleanup, "fanotify_mark (%d, FAN_MARK_REMOVE | " "FAN_MARK_IGNORED_MASK, FAN_OPEN | " "FAN_CLOSE, AT_FDCWD, %s) failed", fd_notify, fname); } SAFE_CLOSE(cleanup, fd); event_set[tst_count] = FAN_CLOSE_WRITE; tst_count++; /* Read events to verify close was generated */ ret = SAFE_READ(cleanup, 0, fd_notify, event_buf + len, EVENT_BUF_LEN - len); len += ret; if (TST_TOTAL != tst_count) { tst_brkm(TBROK, cleanup, "TST_TOTAL (%d) and tst_count (%d) are not " "equal", TST_TOTAL, tst_count); } tst_count = 0; /* * check events */ while (i < len) { struct fanotify_event_metadata *event; event = (struct fanotify_event_metadata *)&event_buf[i]; if (test_num >= TST_TOTAL) { tst_resm(TFAIL, "get unnecessary event: mask=%llx " "pid=%u fd=%u", (unsigned long long)event->mask, (unsigned)event->pid, event->fd); } else if (!(event->mask & event_set[test_num])) { tst_resm(TFAIL, "get event: mask=%llx (expected %llx) " "pid=%u fd=%u", (unsigned long long)event->mask, event_set[test_num], (unsigned)event->pid, event->fd); } else if (event->pid != getpid()) { tst_resm(TFAIL, "get event: mask=%llx pid=%u " "(expected %u) fd=%u", (unsigned long long)event->mask, (unsigned)event->pid, (unsigned)getpid(), event->fd); } else { if (event->fd == -2) goto pass; ret = read(event->fd, buf, BUF_SIZE); if (ret != strlen(fname)) { tst_resm(TFAIL, "cannot read from returned fd " "of event: mask=%llx pid=%u " "fd=%u ret=%d (errno=%d)", (unsigned long long)event->mask, (unsigned)event->pid, event->fd, ret, errno); } else if (memcmp(buf, fname, strlen(fname))) { tst_resm(TFAIL, "wrong data read from returned fd " "of event: mask=%llx pid=%u " "fd=%u", (unsigned long long)event->mask, (unsigned)event->pid, event->fd); } else { pass: tst_resm(TPASS, "get event: mask=%llx pid=%u fd=%u", (unsigned long long)event->mask, (unsigned)event->pid, event->fd); } } /* * We have verified the data now so close fd and * invalidate it so that we don't check it again * unnecessarily */ close(event->fd); event->fd = -2; event->mask &= ~event_set[test_num]; /* No events left in current mask? Go for next event */ if (event->mask == 0) { i += event->event_len; } test_num++; } for (; test_num < TST_TOTAL; test_num++) { tst_resm(TFAIL, "didn't get event: mask=%llx", event_set[test_num]); } /* Remove mark to clear FAN_MARK_IGNORED_SURV_MODIFY */ if (myfanotify_mark(fd_notify, FAN_MARK_REMOVE, FAN_ACCESS | FAN_MODIFY | FAN_CLOSE | FAN_OPEN, AT_FDCWD, fname) < 0) { tst_brkm(TBROK | TERRNO, cleanup, "fanotify_mark (%d, FAN_MARK_REMOVE, FAN_ACCESS | " "FAN_MODIFY | FAN_CLOSE | FAN_OPEN, AT_FDCWD, %s) " "failed", fd_notify, fname); } } cleanup(); tst_exit(); }