| /* 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_raw(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; |
| } |