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