aboutsummaryrefslogtreecommitdiff
path: root/toys/other/inotifyd.c
diff options
context:
space:
mode:
Diffstat (limited to 'toys/other/inotifyd.c')
-rw-r--r--toys/other/inotifyd.c126
1 files changed, 126 insertions, 0 deletions
diff --git a/toys/other/inotifyd.c b/toys/other/inotifyd.c
new file mode 100644
index 00000000..59c9a50c
--- /dev/null
+++ b/toys/other/inotifyd.c
@@ -0,0 +1,126 @@
+/* inotifyd.c - inotify daemon.
+ *
+ * Copyright 2013 Ashwini Kumar <ak.ashwini1981@gmail.com>
+ * Copyright 2013 Kyungwan Han <asura321@gmail.com>
+ *
+ * No Standard.
+
+USE_INOTIFYD(NEWTOY(inotifyd, "<2", TOYFLAG_USR|TOYFLAG_BIN))
+
+config INOTIFYD
+ bool "inotifyd"
+ default y
+ help
+ usage: inotifyd PROG FILE[:MASK] ...
+
+ When a filesystem event matching MASK occurs to a FILE, run PROG as:
+
+ PROG EVENTS FILE [DIRFILE]
+
+ If PROG is "-" events are sent to stdout.
+
+ This file is:
+ a accessed c modified e metadata change w closed (writable)
+ r opened D deleted M moved 0 closed (unwritable)
+ u unmounted o overflow x unwatchable
+
+ A file in this directory is:
+ m moved in y moved out n created d deleted
+
+ When x event happens for all FILEs, inotifyd exits (after waiting for PROG).
+*/
+
+#define FOR_inotifyd
+#include "toys.h"
+#include <sys/inotify.h>
+
+void inotifyd_main(void)
+{
+ struct pollfd fds;
+ char *prog_args[5], **ss = toys.optargs;
+ char *masklist ="acew0rmyndDM uox";
+
+ fds.events = POLLIN;
+
+ *prog_args = *toys.optargs;
+ prog_args[4] = 0;
+ if ((fds.fd = inotify_init()) == -1) perror_exit(0);
+
+ // Track number of watched files. First one was program to run.
+ toys.optc--;
+
+ while (*++ss) {
+ char *path = *ss, *masks = strchr(*ss, ':');
+ int i, mask = 0;
+
+ if (!masks) mask = 0xfff; // default to all
+ else{
+ *masks++ = 0;
+ for (*masks++ = 0; *masks; masks++) {
+ i = stridx(masklist, *masks);;
+ if (i == -1) error_exit("bad mask '%c'", *masks);
+ mask |= 1<<i;
+ }
+ }
+
+ // This returns increasing numbers starting from 1, which coincidentally
+ // is the toys.optargs position of the file. (0 is program to run.)
+ if (inotify_add_watch(fds.fd, path, mask) < 0) perror_exit("%s", path);
+ }
+
+ for (;;) {
+ int ret = 0, len;
+ void *buf = 0;
+ struct inotify_event *event;
+
+ // Read next event(s)
+ ret = poll(&fds, 1, -1);
+ if (ret < 0 && errno == EINTR) continue;
+ if (ret <= 0) break;
+ xioctl(fds.fd, FIONREAD, &len);
+ event = buf = xmalloc(len);
+ len = readall(fds.fd, buf, len);
+
+ // Loop through set of events.
+ for (;;) {
+ int left = len - (((char *)event)-(char *)buf),
+ size = sizeof(struct inotify_event);
+
+ // Don't dereference event if ->len is off end of bufer
+ if (left >= size) size += event->len;
+ if (left < size) break;
+
+ if (event->mask) {
+ char *s = toybuf, *m;
+
+ for (m = masklist; *m; m++)
+ if (event->mask & (1<<(m-masklist))) *s++ = *m;
+ *s = 0;
+
+ if (**prog_args == '-' && !prog_args[0][1]) {
+ xprintf("%s\t%s\t%s\n" + 3*!event->len, toybuf,
+ toys.optargs[event->wd], event->name);
+ } else {
+ prog_args[1] = toybuf;
+ prog_args[2] = toys.optargs[event->wd];
+ prog_args[3] = event->len ? event->name : 0;
+ xpclose(xpopen(prog_args, 0), 0);
+ }
+
+ if (event->mask & IN_IGNORED) {
+ if (--toys.optc <= 0) {
+ free(buf);
+
+ goto done;
+ }
+ inotify_rm_watch(fds.fd, event->wd);
+ }
+ }
+ event = (void*)(size + (char*)event);
+ }
+ free(buf);
+ }
+
+done:
+ toys.exitval = !!toys.signal;
+}