Home | History | Annotate | Download | only in other
      1 /* inotifyd.c - inotify daemon.
      2  *
      3  * Copyright 2013 Ashwini Kumar <ak.ashwini1981 (at) gmail.com>
      4  * Copyright 2013 Kyungwan Han <asura321 (at) gmail.com>
      5  *
      6  * No Standard.
      7 
      8 USE_INOTIFYD(NEWTOY(inotifyd, "<2", TOYFLAG_USR|TOYFLAG_BIN))
      9 
     10 config INOTIFYD
     11   bool "inotifyd"
     12   default y
     13   help
     14     usage: inotifyd PROG FILE[:MASK] ...
     15 
     16     When a filesystem event matching MASK occurs to a FILE, run PROG as:
     17 
     18       PROG EVENTS FILE [DIRFILE]
     19 
     20     If PROG is "-" events are sent to stdout.
     21 
     22     This file is:
     23       a  accessed    c  modified    e  metadata change  w  closed (writable)
     24       r  opened      D  deleted     M  moved            0  closed (unwritable)
     25       u  unmounted   o  overflow    x  unwatchable
     26 
     27     A file in this directory is:
     28       m  moved in    y  moved out   n  created          d  deleted
     29 
     30     When x event happens for all FILEs, inotifyd exits (after waiting for PROG).
     31 */
     32 
     33 #define FOR_inotifyd
     34 #include "toys.h"
     35 #include <sys/inotify.h>
     36 
     37 void inotifyd_main(void)
     38 {
     39   struct pollfd fds;
     40   char *prog_args[5], **ss = toys.optargs;
     41   char *masklist ="acew0rmyndDM uox";
     42 
     43   fds.events = POLLIN;
     44 
     45   *prog_args = *toys.optargs;
     46   prog_args[4] = 0;
     47   if ((fds.fd = inotify_init()) == -1) perror_exit(0);
     48 
     49   // Track number of watched files. First one was program to run.
     50   toys.optc--;
     51 
     52   while (*++ss) {
     53     char *path = *ss, *masks = strchr(*ss, ':');
     54     int i, mask = 0;
     55 
     56     if (!masks) mask = 0xfff; // default to all
     57     else{
     58       *masks++ = 0;
     59       for (*masks++ = 0; *masks; masks++) {
     60         i = stridx(masklist, *masks);;
     61         if (i == -1) error_exit("bad mask '%c'", *masks);
     62         mask |= 1<<i;
     63       }
     64     }
     65 
     66     // This returns increasing numbers starting from 1, which coincidentally
     67     // is the toys.optargs position of the file. (0 is program to run.)
     68     if (inotify_add_watch(fds.fd, path, mask) < 0) perror_exit_raw(path);
     69   }
     70 
     71   for (;;) {
     72     int ret = 0, len;
     73     void *buf = 0;
     74     struct inotify_event *event;
     75 
     76     // Read next event(s)
     77     ret = poll(&fds, 1, -1);
     78     if (ret < 0 && errno == EINTR) continue;
     79     if (ret <= 0) break;
     80     xioctl(fds.fd, FIONREAD, &len);
     81     event = buf = xmalloc(len);
     82     len = readall(fds.fd, buf, len);
     83 
     84     // Loop through set of events.
     85     for (;;) {
     86       int left = len - (((char *)event)-(char *)buf),
     87           size = sizeof(struct inotify_event);
     88 
     89       // Don't dereference event if ->len is off end of bufer
     90       if (left >= size) size += event->len;
     91       if (left < size) break;
     92 
     93       if (event->mask) {
     94         char *s = toybuf, *m;
     95 
     96         for (m = masklist; *m; m++)
     97           if (event->mask & (1<<(m-masklist))) *s++ = *m;
     98         *s = 0;
     99 
    100         if (**prog_args == '-' && !prog_args[0][1]) {
    101           xprintf("%s\t%s\t%s\n" + 3*!event->len, toybuf,
    102               toys.optargs[event->wd], event->name);
    103         } else {
    104           prog_args[1] = toybuf;
    105           prog_args[2] = toys.optargs[event->wd];
    106           prog_args[3] = event->len ? event->name : 0;
    107           xrun(prog_args);
    108         }
    109 
    110         if (event->mask & IN_IGNORED) {
    111           if (--toys.optc <= 0) {
    112             free(buf);
    113 
    114             goto done;
    115           }
    116           inotify_rm_watch(fds.fd, event->wd);
    117         }
    118       }
    119       event = (void*)(size + (char*)event);
    120     }
    121     free(buf);
    122   }
    123 
    124 done:
    125   toys.exitval = !!toys.signal;
    126 }
    127