2 * A simple tester of fanotify in the Linux kernel.
4 * This program is released in the Public Domain.
7 * $> gcc -o /tmp/fanotify-man fanotify-man.c
10 * $> /tmp/fanotify-example
12 #define _GNU_SOURCE /* Needed to get O_LARGEFILE definition */
19 #include <sys/fanotify.h>
22 /* Read all available fanotify events from the file descriptor 'fd'. */
27 const struct fanotify_event_metadata *metadata;
28 struct fanotify_event_metadata buf[200];
32 char procfd_path[PATH_MAX];
33 struct fanotify_response response;
35 /* Loop while events can be read from fanotify file descriptor. */
39 /* Read some events. */
41 len = read(fd, buf, sizeof(buf));
42 if (len == -1 && errno != EAGAIN) {
47 /* Check if end of available data reached. */
52 /* Point to the first event in the buffer. */
56 /* Loop over all events in the buffer. */
58 while (FAN_EVENT_OK(metadata, len)) {
60 /* Check that run-time and compile-time structures match. */
62 if (metadata->vers != FANOTIFY_METADATA_VERSION) {
64 "Mismatch of fanotify metadata version.\n");
68 /* metadata->fd contains either FAN_NOFD, indicating a
69 queue overflow, or a file descriptor (a nonnegative
70 integer). Here, we simply ignore queue overflow. */
72 if (metadata->fd >= 0) {
74 /* Handle open permission event. */
76 if (metadata->mask & FAN_OPEN_PERM) {
77 printf("FAN_OPEN_PERM: ");
79 /* Allow file to be opened. */
81 response.fd = metadata->fd;
82 response.response = FAN_ALLOW;
83 write(fd, &response, sizeof(response));
86 /* Handle closing of writable file event. */
88 if (metadata->mask & FAN_CLOSE_WRITE)
89 printf("FAN_CLOSE_WRITE: ");
91 /* Retrieve and print pathname of the accessed file. */
93 snprintf(procfd_path, sizeof(procfd_path),
94 "/proc/self/fd/%d", metadata->fd);
95 path_len = readlink(procfd_path, path,
102 path[path_len] = '\0';
103 printf("File %s\n", path);
105 /* Close the file descriptor of the event. */
110 /* Advance to next event. */
112 metadata = FAN_EVENT_NEXT(metadata, len);
118 main(int argc, char *argv[])
123 struct pollfd fds[2];
125 /* Check mount point is supplied. */
128 fprintf(stderr, "Usage: %s MOUNT\n", argv[0]);
132 printf("Press enter key to terminate.\n");
134 /* Create the file descriptor for accessing the fanotify API. */
136 fd = fanotify_init(FAN_CLOEXEC | FAN_CLASS_CONTENT | FAN_NONBLOCK,
137 O_RDONLY | O_LARGEFILE);
139 perror("fanotify_init");
143 /* Mark the mount for:
144 - permission events before opening files
145 - notification events after closing a write-enabled
148 if (fanotify_mark(fd, FAN_MARK_ADD | FAN_MARK_MOUNT,
149 FAN_OPEN_PERM | FAN_CLOSE_WRITE, AT_FDCWD,
151 perror("fanotify_mark");
155 /* Prepare for polling. */
159 fds[0].fd = STDIN_FILENO; /* Console input */
160 fds[0].events = POLLIN;
162 fds[1].fd = fd; /* Fanotify input */
163 fds[1].events = POLLIN;
165 /* This is the loop to wait for incoming events. */
167 printf("Listening for events.\n");
170 poll_num = poll(fds, nfds, -1);
171 if (poll_num == -1) {
172 if (errno == EINTR) /* Interrupted by a signal */
173 continue; /* Restart poll() */
175 perror("poll"); /* Unexpected error */
180 if (fds[0].revents & POLLIN) {
182 /* Console input is available: empty stdin and quit. */
184 while (read(STDIN_FILENO, &buf, 1) > 0 && buf != '\n')
189 if (fds[1].revents & POLLIN) {
191 /* Fanotify events are available. */
198 printf("Listening for events stopped.\n");