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