aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Ankarström <john@ankarstrom.se>2018-09-24 21:40:05 +0200
committerJohn Ankarström <john@ankarstrom.se>2018-09-24 23:13:02 +0200
commit0301256c7ae332979e3bca3d5a5e4010ba0b22eb (patch)
tree68bf3b77ece1ef4986281f8695b4b1d836ce915b
downloadwhen-0301256c7ae332979e3bca3d5a5e4010ba0b22eb.tar.gz
First commit
-rw-r--r--watch.c85
1 files changed, 85 insertions, 0 deletions
diff --git a/watch.c b/watch.c
new file mode 100644
index 0000000..d9e843e
--- /dev/null
+++ b/watch.c
@@ -0,0 +1,85 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/event.h>
+#include <sys/time.h>
+
+#define fail() exit(EXIT_FAILURE)
+#define fail_clean() do { status = EXIT_FAILURE; goto finally; } while (0)
+
+int main(int argc, char *argv[]) {
+ int status = EXIT_SUCCESS;
+ int fd, kq, n, i;
+ struct kevent event;
+
+ setbuf(stdout, NULL); // disable buffering even non-interactively
+
+ if (argc < 2) {
+ fprintf(stderr, "usage: %s file\n", argv[0]);
+ fail();
+ }
+
+ // 1. Open file
+ if ((fd = open(argv[1], O_RDONLY)) == -1) {
+ perror(argv[1]);
+ fail();
+ }
+
+ if ((kq = kqueue()) == -1) {
+ perror("kqueue");
+ fail_clean();
+ }
+
+ struct kevent change = { // event to watch for
+ .ident = fd,
+ .filter = EVFILT_VNODE,
+ .flags = EV_ADD | EV_CLEAR,
+ .fflags = NOTE_WRITE | NOTE_RENAME | NOTE_DELETE,
+ .data = 0,
+ .udata = NULL
+ };
+
+ // 2. Register event to watch for
+ if (kevent(kq, &change, 1, NULL, 0, NULL) == -1) {
+ perror("kevent");
+ fail_clean();
+ }
+ if (change.flags & EV_ERROR) {
+ fprintf(stderr, "Event error: %s", strerror(change.data));
+ fail_clean();
+ }
+
+ while (1) {
+ // 3. Wait for event
+ if ((n = kevent(kq, NULL, 0, &event, 1, NULL)) != 1) {
+ perror("kevent wait");
+ fail_clean();
+ } else if (n > 0) {
+ if (event.fflags & NOTE_WRITE) {
+ printf("%s\n", argv[1]);
+ }
+ if (event.fflags & NOTE_RENAME)
+ fprintf(stderr, "Note: file was renamed\n");
+ if (event.fflags & NOTE_DELETE) {
+ fprintf(stderr, "Error: file was deleted\n");
+ fail_clean();
+ }
+ }
+ }
+
+finally:
+ if (close(kq) == -1) {
+ perror("close");
+ fail();
+ }
+ if (close(fd) == -1) {
+ perror("close");
+ fail();
+ }
+
+ exit(status);
+}