#include <dirent.h> #include <errno.h> #include <fcntl.h> #include <linux/limits.h> #include <poll.h> #include <stdbool.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/inotify.h> #include <sys/stat.h> #include <sys/types.h> #include <unistd.h> void join(char *abs, const char *p1, const char *p2) { bool ending_slash = p1[strlen(p1) - 1] == '/'; strncpy(abs, p1, strlen(p1)); if (!ending_slash) strncpy(abs + strlen(p1), "/", 1); strncpy(abs + strlen(p1) + (ending_slash ? 0 : 1), p2, strlen(p2)); } static void handle_events(int fd, int wd, char *dir) { char buf[4096] __attribute__((aligned(__alignof__(struct inotify_event)))); const struct inotify_event *event; ssize_t len; /* Loop while events can be read from inotify file descriptor. */ for (;;) { /* Read some events. */ len = read(fd, buf, sizeof(buf)); if (len == -1 && errno != EAGAIN) { perror("read"); exit(EXIT_FAILURE); } /* If the nonblocking read() found no events to read, then it returns -1 with errno set to EAGAIN. In that case, we exit the loop. */ if (len <= 0) break; /* Loop over all events in the buffer */ for (char *ptr = buf; ptr < buf + len; ptr += sizeof(struct inotify_event) + event->len) { event = (const struct inotify_event *)ptr; if (event->mask & IN_ISDIR) continue; /* Print the name of the watched directory */ char abs[PATH_MAX]; join(abs, dir, event->name); if (event->mask & IN_DELETE) { printf("- %s\n", abs); int fd = open(abs, O_CREAT, 0666); if (fd == -1) { perror("open"); exit(EXIT_FAILURE); } if (close(fd) == -1) { perror("close"); exit(EXIT_FAILURE); } } } } } int main(int argc, char *argv[]) { char buf; int fd, i, poll_num; int wd; nfds_t nfds; struct pollfd fds[2]; if (argc != 2) { printf("Usage: %s PATH\n", argv[0]); exit(EXIT_FAILURE); } printf("Press ENTER key to terminate.\n"); /* Create the file descriptor for accessing the inotify API */ fd = inotify_init1(IN_NONBLOCK); if (fd == -1) { perror("inotify_init1"); exit(EXIT_FAILURE); } wd = inotify_add_watch(fd, argv[1], IN_DELETE | IN_CLOSE); if (wd == -1) { fprintf(stderr, "Cannot watch '%s': %s\n", argv[1], strerror(errno)); exit(EXIT_FAILURE); } /* Prepare for polling */ nfds = 2; /* Console input */ fds[0].fd = STDIN_FILENO; fds[0].events = POLLIN; /* Inotify input */ fds[1].fd = fd; fds[1].events = POLLIN; /* Wait for events and/or terminal input */ printf("Listening for events.\n"); while (1) { poll_num = poll(fds, nfds, -1); if (poll_num == -1) { if (errno == EINTR) continue; perror("poll"); exit(EXIT_FAILURE); } if (poll_num <= 0) continue; 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) handle_events(fd, wd, argv[1]); } printf("Listening for events stopped.\n"); close(fd); exit(EXIT_SUCCESS); }