16958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma/* inotifyd.c - inotify daemon.
26958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma *
36958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma * Copyright 2013 Ashwini Kumar <ak.ashwini1981@gmail.com>
46958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma * Copyright 2013 Kyungwan Han <asura321@gmail.com>
56958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma *
66958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma * No Standard.
76958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma
86958429d84cff06fefdc898d837a71c239f1e214Ashwini SharmaUSE_INOTIFYD(NEWTOY(inotifyd, "<2", TOYFLAG_USR|TOYFLAG_BIN))
96958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma
106958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharmaconfig INOTIFYD
116958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma  bool "inotifyd"
12e70eea41eeed05e0ac938a6aceab27c918090fdeRob Landley  default y
136958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma  help
1401a806ff123aa091e0d41023432dfe2c0173a62dRob Landley    usage: inotifyd PROG FILE[:MASK] ...
156958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma
1601a806ff123aa091e0d41023432dfe2c0173a62dRob Landley    When a filesystem event matching MASK occurs to a FILE, run PROG as:
1701a806ff123aa091e0d41023432dfe2c0173a62dRob Landley
1801a806ff123aa091e0d41023432dfe2c0173a62dRob Landley      PROG EVENTS FILE [DIRFILE]
1901a806ff123aa091e0d41023432dfe2c0173a62dRob Landley
20eeb3541652110c35e9c434565a2c509687bb6697Rob Landley    If PROG is "-" events are sent to stdout.
21eeb3541652110c35e9c434565a2c509687bb6697Rob Landley
2201a806ff123aa091e0d41023432dfe2c0173a62dRob Landley    This file is:
2301a806ff123aa091e0d41023432dfe2c0173a62dRob Landley      a  accessed    c  modified    e  metadata change  w  closed (writable)
2401a806ff123aa091e0d41023432dfe2c0173a62dRob Landley      r  opened      D  deleted     M  moved            0  closed (unwritable)
2501a806ff123aa091e0d41023432dfe2c0173a62dRob Landley      u  unmounted   o  overflow    x  unwatchable
2601a806ff123aa091e0d41023432dfe2c0173a62dRob Landley
2701a806ff123aa091e0d41023432dfe2c0173a62dRob Landley    A file in this directory is:
2801a806ff123aa091e0d41023432dfe2c0173a62dRob Landley      m  moved in    y  moved out   n  created          d  deleted
296958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma
3001a806ff123aa091e0d41023432dfe2c0173a62dRob Landley    When x event happens for all FILEs, inotifyd exits (after waiting for PROG).
316958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma*/
3201a806ff123aa091e0d41023432dfe2c0173a62dRob Landley
336958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma#define FOR_inotifyd
346958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma#include "toys.h"
356958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma#include <sys/inotify.h>
366958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma
3701a806ff123aa091e0d41023432dfe2c0173a62dRob Landleyvoid inotifyd_main(void)
386958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma{
3901a806ff123aa091e0d41023432dfe2c0173a62dRob Landley  struct pollfd fds;
4001a806ff123aa091e0d41023432dfe2c0173a62dRob Landley  char *prog_args[5], **ss = toys.optargs;
4101a806ff123aa091e0d41023432dfe2c0173a62dRob Landley  char *masklist ="acew0rmyndDM uox";
426958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma
4301a806ff123aa091e0d41023432dfe2c0173a62dRob Landley  fds.events = POLLIN;
446958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma
4501a806ff123aa091e0d41023432dfe2c0173a62dRob Landley  *prog_args = *toys.optargs;
4601a806ff123aa091e0d41023432dfe2c0173a62dRob Landley  prog_args[4] = 0;
4701a806ff123aa091e0d41023432dfe2c0173a62dRob Landley  if ((fds.fd = inotify_init()) == -1) perror_exit(0);
486958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma
4901a806ff123aa091e0d41023432dfe2c0173a62dRob Landley  // Track number of watched files. First one was program to run.
5001a806ff123aa091e0d41023432dfe2c0173a62dRob Landley  toys.optc--;
5101a806ff123aa091e0d41023432dfe2c0173a62dRob Landley
5201a806ff123aa091e0d41023432dfe2c0173a62dRob Landley  while (*++ss) {
5301a806ff123aa091e0d41023432dfe2c0173a62dRob Landley    char *path = *ss, *masks = strchr(*ss, ':');
5401a806ff123aa091e0d41023432dfe2c0173a62dRob Landley    int i, mask = 0;
5501a806ff123aa091e0d41023432dfe2c0173a62dRob Landley
5601a806ff123aa091e0d41023432dfe2c0173a62dRob Landley    if (!masks) mask = 0xfff; // default to all
5701a806ff123aa091e0d41023432dfe2c0173a62dRob Landley    else{
5801a806ff123aa091e0d41023432dfe2c0173a62dRob Landley      *masks++ = 0;
5901a806ff123aa091e0d41023432dfe2c0173a62dRob Landley      for (*masks++ = 0; *masks; masks++) {
6001a806ff123aa091e0d41023432dfe2c0173a62dRob Landley        i = stridx(masklist, *masks);;
6101a806ff123aa091e0d41023432dfe2c0173a62dRob Landley        if (i == -1) error_exit("bad mask '%c'", *masks);
6201a806ff123aa091e0d41023432dfe2c0173a62dRob Landley        mask |= 1<<i;
636958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma      }
646958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma    }
6501a806ff123aa091e0d41023432dfe2c0173a62dRob Landley
6601a806ff123aa091e0d41023432dfe2c0173a62dRob Landley    // This returns increasing numbers starting from 1, which coincidentally
6701a806ff123aa091e0d41023432dfe2c0173a62dRob Landley    // is the toys.optargs position of the file. (0 is program to run.)
6801a806ff123aa091e0d41023432dfe2c0173a62dRob Landley    if (inotify_add_watch(fds.fd, path, mask) < 0) perror_exit("%s", path);
696958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma  }
706958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma
7101a806ff123aa091e0d41023432dfe2c0173a62dRob Landley  for (;;) {
7201a806ff123aa091e0d41023432dfe2c0173a62dRob Landley    int ret = 0, len;
7301a806ff123aa091e0d41023432dfe2c0173a62dRob Landley    void *buf = 0;
746958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma    struct inotify_event *event;
756958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma
7601a806ff123aa091e0d41023432dfe2c0173a62dRob Landley    // Read next event(s)
776958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma    ret = poll(&fds, 1, -1);
7801a806ff123aa091e0d41023432dfe2c0173a62dRob Landley    if (ret < 0 && errno == EINTR) continue;
796958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma    if (ret <= 0) break;
8001a806ff123aa091e0d41023432dfe2c0173a62dRob Landley    xioctl(fds.fd, FIONREAD, &len);
8101a806ff123aa091e0d41023432dfe2c0173a62dRob Landley    event = buf = xmalloc(len);
8201a806ff123aa091e0d41023432dfe2c0173a62dRob Landley    len = readall(fds.fd, buf, len);
8301a806ff123aa091e0d41023432dfe2c0173a62dRob Landley
8401a806ff123aa091e0d41023432dfe2c0173a62dRob Landley    // Loop through set of events.
8501a806ff123aa091e0d41023432dfe2c0173a62dRob Landley    for (;;) {
8601a806ff123aa091e0d41023432dfe2c0173a62dRob Landley      int left = len - (((char *)event)-(char *)buf),
8701a806ff123aa091e0d41023432dfe2c0173a62dRob Landley          size = sizeof(struct inotify_event);
8801a806ff123aa091e0d41023432dfe2c0173a62dRob Landley
8901a806ff123aa091e0d41023432dfe2c0173a62dRob Landley      // Don't dereference event if ->len is off end of bufer
9001a806ff123aa091e0d41023432dfe2c0173a62dRob Landley      if (left >= size) size += event->len;
9101a806ff123aa091e0d41023432dfe2c0173a62dRob Landley      if (left < size) break;
9201a806ff123aa091e0d41023432dfe2c0173a62dRob Landley
9301a806ff123aa091e0d41023432dfe2c0173a62dRob Landley      if (event->mask) {
9401a806ff123aa091e0d41023432dfe2c0173a62dRob Landley        char *s = toybuf, *m;
9501a806ff123aa091e0d41023432dfe2c0173a62dRob Landley
9601a806ff123aa091e0d41023432dfe2c0173a62dRob Landley        for (m = masklist; *m; m++)
9701a806ff123aa091e0d41023432dfe2c0173a62dRob Landley          if (event->mask & (1<<(m-masklist))) *s++ = *m;
9801a806ff123aa091e0d41023432dfe2c0173a62dRob Landley        *s = 0;
9901a806ff123aa091e0d41023432dfe2c0173a62dRob Landley
10001a806ff123aa091e0d41023432dfe2c0173a62dRob Landley        if (**prog_args == '-' && !prog_args[0][1]) {
10101a806ff123aa091e0d41023432dfe2c0173a62dRob Landley          xprintf("%s\t%s\t%s\n" + 3*!event->len, toybuf,
10201a806ff123aa091e0d41023432dfe2c0173a62dRob Landley              toys.optargs[event->wd], event->name);
1036958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma        } else {
10401a806ff123aa091e0d41023432dfe2c0173a62dRob Landley          prog_args[1] = toybuf;
10501a806ff123aa091e0d41023432dfe2c0173a62dRob Landley          prog_args[2] = toys.optargs[event->wd];
10601a806ff123aa091e0d41023432dfe2c0173a62dRob Landley          prog_args[3] = event->len ? event->name : 0;
107360d57f843f5435a75270e54583430dcb8f62546Rob Landley          xrun(prog_args);
1086958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma        }
10901a806ff123aa091e0d41023432dfe2c0173a62dRob Landley
1106958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma        if (event->mask & IN_IGNORED) {
1116958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma          if (--toys.optc <= 0) {
1126958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma            free(buf);
11301a806ff123aa091e0d41023432dfe2c0173a62dRob Landley
1146958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma            goto done;
1156958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma          }
1166958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma          inotify_rm_watch(fds.fd, event->wd);
1176958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma        }
1186958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma      }
11901a806ff123aa091e0d41023432dfe2c0173a62dRob Landley      event = (void*)(size + (char*)event);
1206958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma    }
1216958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma    free(buf);
1226958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma  }
12301a806ff123aa091e0d41023432dfe2c0173a62dRob Landley
1246958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharmadone:
12501a806ff123aa091e0d41023432dfe2c0173a62dRob Landley  toys.exitval = !!toys.signal;
1266958429d84cff06fefdc898d837a71c239f1e214Ashwini Sharma}
127