Skip to content

Instantly share code, notes, and snippets.

@vegarsti
Created March 24, 2026 11:21
Show Gist options
  • Select an option

  • Save vegarsti/2fca3bc234839b1ccb3bc33ff03e535d to your computer and use it in GitHub Desktop.

Select an option

Save vegarsti/2fca3bc234839b1ccb3bc33ff03e535d to your computer and use it in GitHub Desktop.
#include <sys/event.h>
#include <sys/time.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
// Watches files for changes and prints which file changed
int main(int argc, char *argv[]) {
if (argc < 2) {
fprintf(stderr, "Usage: %s <file1> [file2] ...\n", argv[0]);
exit(1);
}
int nfiles = argc - 1;
// Create the kqueue
int kq = kqueue();
if (kq == -1) {
perror("kqueue");
exit(1);
}
// Open all files and set up change events
int *fds = malloc(nfiles * sizeof(int));
struct kevent *changes = malloc(nfiles * sizeof(struct kevent));
if (!fds || !changes) {
perror("malloc");
exit(1);
}
for (int i = 0; i < nfiles; i++) {
fds[i] = open(argv[i + 1], O_RDONLY | O_EVTONLY);
if (fds[i] == -1) {
fprintf(stderr, "open(%s): ", argv[i + 1]);
perror(NULL);
exit(1);
}
printf("Monitoring '%s' (fd %d)\n", argv[i + 1], fds[i]);
EV_SET(
&changes[i],
fds[i],
EVFILT_VNODE,
EV_ADD | EV_CLEAR,
NOTE_WRITE,
0,
// Store the filename as udata so we can identify it later
(void *)argv[i + 1]
);
}
// Register all events at once
if (kevent(kq, changes, nfiles, NULL, 0, NULL) == -1) {
perror("kevent register");
exit(1);
}
printf("Waiting for changes...\n");
struct kevent event;
while (1) {
// Wait for one event at a time
int n = kevent(kq, NULL, 0, &event, 1, NULL);
if (n == -1) {
perror("kevent wait");
break;
}
if (event.fflags & NOTE_WRITE) {
const char *name = (const char *)event.udata;
printf("[%s] written\n", name);
}
}
// Cleanup
for (int i = 0; i < nfiles; i++)
close(fds[i]);
free(fds);
free(changes);
close(kq);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment