toybox/toys/other/inotifyd.c
<<
>>
Prefs
   1/* inotifyd.c - inotify daemon. 
   2 *
   3 * Copyright 2013 Ashwini Kumar <ak.ashwini1981@gmail.com>
   4 * Copyright 2013 Kyungwan Han <asura321@gmail.com>
   5 *
   6 * No Standard.
   7
   8USE_INOTIFYD(NEWTOY(inotifyd, "<2", TOYFLAG_USR|TOYFLAG_BIN))
   9
  10config 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
  37void 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
 124done:
 125  toys.exitval = !!toys.signal;
 126}
 127