xref: /third_party/toybox/toys/other/inotifyd.c (revision 0f66f451)
10f66f451Sopenharmony_ci/* inotifyd.c - inotify daemon.
20f66f451Sopenharmony_ci *
30f66f451Sopenharmony_ci * Copyright 2013 Ashwini Kumar <ak.ashwini1981@gmail.com>
40f66f451Sopenharmony_ci * Copyright 2013 Kyungwan Han <asura321@gmail.com>
50f66f451Sopenharmony_ci *
60f66f451Sopenharmony_ci * No Standard.
70f66f451Sopenharmony_ci
80f66f451Sopenharmony_ciUSE_INOTIFYD(NEWTOY(inotifyd, "<2", TOYFLAG_USR|TOYFLAG_BIN))
90f66f451Sopenharmony_ci
100f66f451Sopenharmony_ciconfig INOTIFYD
110f66f451Sopenharmony_ci  bool "inotifyd"
120f66f451Sopenharmony_ci  default y
130f66f451Sopenharmony_ci  help
140f66f451Sopenharmony_ci    usage: inotifyd PROG FILE[:MASK] ...
150f66f451Sopenharmony_ci
160f66f451Sopenharmony_ci    When a filesystem event matching MASK occurs to a FILE, run PROG as:
170f66f451Sopenharmony_ci
180f66f451Sopenharmony_ci      PROG EVENTS FILE [DIRFILE]
190f66f451Sopenharmony_ci
200f66f451Sopenharmony_ci    If PROG is "-" events are sent to stdout.
210f66f451Sopenharmony_ci
220f66f451Sopenharmony_ci    This file is:
230f66f451Sopenharmony_ci      a  accessed    c  modified    e  metadata change  w  closed (writable)
240f66f451Sopenharmony_ci      r  opened      D  deleted     M  moved            0  closed (unwritable)
250f66f451Sopenharmony_ci      u  unmounted   o  overflow    x  unwatchable
260f66f451Sopenharmony_ci
270f66f451Sopenharmony_ci    A file in this directory is:
280f66f451Sopenharmony_ci      m  moved in    y  moved out   n  created          d  deleted
290f66f451Sopenharmony_ci
300f66f451Sopenharmony_ci    When x event happens for all FILEs, inotifyd exits (after waiting for PROG).
310f66f451Sopenharmony_ci*/
320f66f451Sopenharmony_ci
330f66f451Sopenharmony_ci#define FOR_inotifyd
340f66f451Sopenharmony_ci#include "toys.h"
350f66f451Sopenharmony_ci#include <sys/inotify.h>
360f66f451Sopenharmony_ci
370f66f451Sopenharmony_civoid inotifyd_main(void)
380f66f451Sopenharmony_ci{
390f66f451Sopenharmony_ci  struct pollfd fds;
400f66f451Sopenharmony_ci  char *prog_args[5], **ss = toys.optargs;
410f66f451Sopenharmony_ci  char *masklist ="acew0rmyndDM uox";
420f66f451Sopenharmony_ci
430f66f451Sopenharmony_ci  fds.events = POLLIN;
440f66f451Sopenharmony_ci
450f66f451Sopenharmony_ci  *prog_args = *toys.optargs;
460f66f451Sopenharmony_ci  prog_args[4] = 0;
470f66f451Sopenharmony_ci  if ((fds.fd = inotify_init()) == -1) perror_exit(0);
480f66f451Sopenharmony_ci
490f66f451Sopenharmony_ci  // Track number of watched files. First one was program to run.
500f66f451Sopenharmony_ci  toys.optc--;
510f66f451Sopenharmony_ci
520f66f451Sopenharmony_ci  while (*++ss) {
530f66f451Sopenharmony_ci    char *path = *ss, *masks = strchr(*ss, ':');
540f66f451Sopenharmony_ci    int i, mask = 0;
550f66f451Sopenharmony_ci
560f66f451Sopenharmony_ci    if (!masks) mask = 0xfff; // default to all
570f66f451Sopenharmony_ci    else{
580f66f451Sopenharmony_ci      *masks++ = 0;
590f66f451Sopenharmony_ci      for (*masks++ = 0; *masks; masks++) {
600f66f451Sopenharmony_ci        i = stridx(masklist, *masks);;
610f66f451Sopenharmony_ci        if (i == -1) error_exit("bad mask '%c'", *masks);
620f66f451Sopenharmony_ci        mask |= 1<<i;
630f66f451Sopenharmony_ci      }
640f66f451Sopenharmony_ci    }
650f66f451Sopenharmony_ci
660f66f451Sopenharmony_ci    // This returns increasing numbers starting from 1, which coincidentally
670f66f451Sopenharmony_ci    // is the toys.optargs position of the file. (0 is program to run.)
680f66f451Sopenharmony_ci    if (inotify_add_watch(fds.fd, path, mask) < 0) perror_exit_raw(path);
690f66f451Sopenharmony_ci  }
700f66f451Sopenharmony_ci
710f66f451Sopenharmony_ci  for (;;) {
720f66f451Sopenharmony_ci    int ret = 0, len;
730f66f451Sopenharmony_ci    void *buf = 0;
740f66f451Sopenharmony_ci    struct inotify_event *event;
750f66f451Sopenharmony_ci
760f66f451Sopenharmony_ci    // Read next event(s)
770f66f451Sopenharmony_ci    ret = poll(&fds, 1, -1);
780f66f451Sopenharmony_ci    if (ret < 0 && errno == EINTR) continue;
790f66f451Sopenharmony_ci    if (ret <= 0) break;
800f66f451Sopenharmony_ci    xioctl(fds.fd, FIONREAD, &len);
810f66f451Sopenharmony_ci    event = buf = xmalloc(len);
820f66f451Sopenharmony_ci    len = readall(fds.fd, buf, len);
830f66f451Sopenharmony_ci
840f66f451Sopenharmony_ci    // Loop through set of events.
850f66f451Sopenharmony_ci    for (;;) {
860f66f451Sopenharmony_ci      int left = len - (((char *)event)-(char *)buf),
870f66f451Sopenharmony_ci          size = sizeof(struct inotify_event);
880f66f451Sopenharmony_ci
890f66f451Sopenharmony_ci      // Don't dereference event if ->len is off end of bufer
900f66f451Sopenharmony_ci      if (left >= size) size += event->len;
910f66f451Sopenharmony_ci      if (left < size) break;
920f66f451Sopenharmony_ci
930f66f451Sopenharmony_ci      if (event->mask) {
940f66f451Sopenharmony_ci        char *s = toybuf, *m;
950f66f451Sopenharmony_ci
960f66f451Sopenharmony_ci        for (m = masklist; *m; m++)
970f66f451Sopenharmony_ci          if (event->mask & (1<<(m-masklist))) *s++ = *m;
980f66f451Sopenharmony_ci        *s = 0;
990f66f451Sopenharmony_ci
1000f66f451Sopenharmony_ci        if (**prog_args == '-' && !prog_args[0][1]) {
1010f66f451Sopenharmony_ci          xprintf("%s\t%s\t%s\n" + 3*!event->len, toybuf,
1020f66f451Sopenharmony_ci              toys.optargs[event->wd], event->name);
1030f66f451Sopenharmony_ci        } else {
1040f66f451Sopenharmony_ci          prog_args[1] = toybuf;
1050f66f451Sopenharmony_ci          prog_args[2] = toys.optargs[event->wd];
1060f66f451Sopenharmony_ci          prog_args[3] = event->len ? event->name : 0;
1070f66f451Sopenharmony_ci          xrun(prog_args);
1080f66f451Sopenharmony_ci        }
1090f66f451Sopenharmony_ci
1100f66f451Sopenharmony_ci        if (event->mask & IN_IGNORED) {
1110f66f451Sopenharmony_ci          if (--toys.optc <= 0) {
1120f66f451Sopenharmony_ci            free(buf);
1130f66f451Sopenharmony_ci
1140f66f451Sopenharmony_ci            goto done;
1150f66f451Sopenharmony_ci          }
1160f66f451Sopenharmony_ci          inotify_rm_watch(fds.fd, event->wd);
1170f66f451Sopenharmony_ci        }
1180f66f451Sopenharmony_ci      }
1190f66f451Sopenharmony_ci      event = (void*)(size + (char*)event);
1200f66f451Sopenharmony_ci    }
1210f66f451Sopenharmony_ci    free(buf);
1220f66f451Sopenharmony_ci  }
1230f66f451Sopenharmony_ci
1240f66f451Sopenharmony_cidone:
1250f66f451Sopenharmony_ci  toys.exitval = !!toys.signal;
1260f66f451Sopenharmony_ci}
127