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