-
-
Save cpu/b68e7bbdf60619c1cdf1ebc27b1e4ae5 to your computer and use it in GitHub Desktop.
Example `fanotify` API program source from `man 7 fanotify`, part of release 4.04 of the Linux man-pages project.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Lifted from `man 2 fanotify` on Linux 4.4.0-174-generic | |
*/ | |
#define _GNU_SOURCE /* Needed to get O_LARGEFILE definition */ | |
#include <errno.h> | |
#include <fcntl.h> | |
#include <limits.h> | |
#include <poll.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <sys/fanotify.h> | |
#include <unistd.h> | |
/* Read all available fanotify events from the file descriptor 'fd' */ | |
static void | |
handle_events(int fd) | |
{ | |
const struct fanotify_event_metadata *metadata; | |
struct fanotify_event_metadata buf[200]; | |
ssize_t len; | |
char path[PATH_MAX]; | |
ssize_t path_len; | |
char procfd_path[PATH_MAX]; | |
struct fanotify_response response; | |
/* Loop while events can be read from fanotify file descriptor */ | |
for(;;) { | |
/* Read some events */ | |
len = read(fd, (void *) &buf, sizeof(buf)); | |
if (len == -1 && errno != EAGAIN) { | |
perror("read"); | |
exit(EXIT_FAILURE); | |
} | |
/* Check if end of available data reached */ | |
if (len <= 0) | |
break; | |
/* Point to the first event in the buffer */ | |
metadata = buf; | |
/* Loop over all events in the buffer */ | |
while (FAN_EVENT_OK(metadata, len)) { | |
/* Check that run-time and compile-time structures match */ | |
if (metadata->vers != FANOTIFY_METADATA_VERSION) { | |
fprintf(stderr, | |
"Mismatch of fanotify metadata version.\n"); | |
exit(EXIT_FAILURE); | |
} | |
/* metadata->fd contains either FAN_NOFD, indicating a | |
queue overflow, or a file descriptor (a nonnegative | |
integer). Here, we simply ignore queue overflow. */ | |
if (metadata->fd >= 0) { | |
/* Handle open permission event */ | |
if (metadata->mask & FAN_OPEN_PERM) { | |
printf("FAN_OPEN_PERM: "); | |
/* Allow file to be opened */ | |
response.fd = metadata->fd; | |
response.response = FAN_ALLOW; | |
write(fd, &response, | |
sizeof(struct fanotify_response)); | |
} | |
/* Handle closing of writable file event */ | |
if (metadata->mask & FAN_CLOSE_WRITE) | |
printf("FAN_CLOSE_WRITE: "); | |
/* Retrieve and print pathname of the accessed file */ | |
snprintf(procfd_path, sizeof(procfd_path), | |
"/proc/self/fd/%d", metadata->fd); | |
path_len = readlink(procfd_path, path, | |
sizeof(path) - 1); | |
if (path_len == -1) { | |
perror("readlink"); | |
exit(EXIT_FAILURE); | |
} | |
path[path_len] = '\0'; | |
printf("File %s\n", path); | |
/* Close the file descriptor of the event */ | |
close(metadata->fd); | |
} | |
/* Advance to next event */ | |
metadata = FAN_EVENT_NEXT(metadata, len); | |
} | |
} | |
} | |
int | |
main(int argc, char *argv[]) | |
{ | |
char buf; | |
int fd, poll_num; | |
nfds_t nfds; | |
struct pollfd fds[2]; | |
/* Check mount point is supplied */ | |
if (argc != 2) { | |
fprintf(stderr, "Usage: %s MOUNT\n", argv[0]); | |
exit(EXIT_FAILURE); | |
} | |
printf("Press enter key to terminate.\n"); | |
/* Create the file descriptor for accessing the fanotify API */ | |
fd = fanotify_init(FAN_CLOEXEC | FAN_CLASS_CONTENT | FAN_NONBLOCK, | |
O_RDONLY | O_LARGEFILE); | |
if (fd == -1) { | |
perror("fanotify_init"); | |
exit(EXIT_FAILURE); | |
} | |
/* Mark the mount for: | |
- permission events before opening files | |
- notification events after closing a write-enabled | |
file descriptor */ | |
if (fanotify_mark(fd, FAN_MARK_ADD | FAN_MARK_MOUNT, | |
FAN_OPEN_PERM | FAN_CLOSE_WRITE, AT_FDCWD, | |
argv[1]) == -1) { | |
perror("fanotify_mark"); | |
exit(EXIT_FAILURE); | |
} | |
/* Prepare for polling */ | |
nfds = 2; | |
/* Console input */ | |
fds[0].fd = STDIN_FILENO; | |
fds[0].events = POLLIN; | |
/* Fanotify input */ | |
fds[1].fd = fd; | |
fds[1].events = POLLIN; | |
/* This is the loop to wait for incoming events */ | |
printf("Listening for events.\n"); | |
while (1) { | |
poll_num = poll(fds, nfds, -1); | |
if (poll_num == -1) { | |
if (errno == EINTR) /* Interrupted by a signal */ | |
continue; /* Restart poll() */ | |
perror("poll"); /* Unexpected error */ | |
exit(EXIT_FAILURE); | |
} | |
if (poll_num > 0) { | |
if (fds[0].revents & POLLIN) { | |
/* Console input is available: empty stdin and quit */ | |
while (read(STDIN_FILENO, &buf, 1) > 0 && buf != '\n') | |
continue; | |
break; | |
} | |
if (fds[1].revents & POLLIN) { | |
/* Fanotify events are available */ | |
handle_events(fd); | |
} | |
} | |
} | |
printf("Listening for events stopped.\n"); | |
exit(EXIT_SUCCESS); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment