/* 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; xrun(prog_args); } 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; }