Created
February 8, 2024 21:18
-
-
Save giuliomoro/8b4c0625845502bd042eddc1e15efe19 to your computer and use it in GitHub Desktop.
inotify watcher
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
#include <errno.h> | |
#include <poll.h> | |
#include <unistd.h> | |
#include <string.h> | |
std::vector<InotifyPath> watchPaths(const std::vector<std::string>& paths, unsigned int timeoutMs, int flags) | |
{ | |
// largely taken from main inotify | |
std::vector<InotifyPath> files; | |
std::vector<int> wd; | |
// Create the file descriptor for accessing the inotify API | |
int fd = inotify_init1(IN_NONBLOCK); | |
if (fd == -1) { | |
perror("inotify_init1"); | |
return {}; | |
} | |
for(auto& p : paths) | |
{ | |
int w = inotify_add_watch(fd, p.c_str(), flags); | |
if(-1 == w) { | |
fprintf(stderr, "Cannot watch '%s': %s\n", | |
p.c_str(), strerror(errno)); | |
return {}; | |
} else { | |
wd.push_back(w); | |
} | |
} | |
// Prepare for polling | |
nfds_t nfds = 1; | |
struct pollfd fds[1]; | |
fds[0].fd = fd; | |
fds[0].events = POLLIN; | |
// Wait for events | |
int poll_num = poll(fds, nfds, timeoutMs); | |
if (poll_num == -1) { | |
if (errno == EINTR) | |
return {}; | |
perror("poll"); | |
} | |
if (poll_num <= 0) | |
return {}; | |
if (!(fds[0].revents & POLLIN)) | |
return {}; | |
{ | |
/* Read all available inotify events from the file descriptor 'fd'. | |
wd is the table of watch descriptors for the directories in argv. | |
argc is the length of wd and argv. | |
argv is the list of watched directories. | |
Entry 0 of wd and argv is unused. */ | |
/* Some systems cannot read integer variables if they are not | |
properly aligned. On other systems, incorrect alignment may | |
decrease performance. Hence, the buffer used for reading from | |
the inotify file descriptor should have the same alignment as | |
struct inotify_event. */ | |
__attribute__ ((aligned(__alignof__(struct inotify_event)))) | |
const struct inotify_event *event; | |
/* Loop while events can be read from inotify file descriptor. */ | |
while(1) { | |
/* Read some events. */ | |
char buf[4096]; | |
ssize_t len = read(fd, buf, sizeof(buf)); | |
if (len == -1 && errno != EAGAIN) { | |
perror("read"); | |
return {}; | |
} | |
/* 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; | |
files.push_back({std::string(event->name), event->mask}); | |
} | |
} | |
} | |
close(fd); | |
return files; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment