1 /* inotifyd.c - inotify daemon.
2 *
3 * Copyright 2013 Ashwini Kumar <[email protected]>
4 * Copyright 2013 Kyungwan Han <[email protected]>
5 *
6 * No Standard.
7
8 USE_INOTIFYD(NEWTOY(inotifyd, "<2", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_LINEBUF))
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
inotifyd_main(void)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 for (*masks++ = 0; *masks; masks++) {
59 i = stridx(masklist, *masks);;
60 if (i == -1) error_exit("bad mask '%c'", *masks);
61 mask |= 1<<i;
62 }
63 }
64
65 // This returns increasing numbers starting from 1, which coincidentally
66 // is the toys.optargs position of the file. (0 is program to run.)
67 if (inotify_add_watch(fds.fd, path, mask) < 0) perror_exit_raw(path);
68 }
69
70 for (;;) {
71 int ret = 0, len;
72 void *buf = 0;
73 struct inotify_event *event;
74
75 // Read next event(s)
76 ret = poll(&fds, 1, -1);
77 if (ret < 0 && errno == EINTR) continue;
78 if (ret <= 0) break;
79 xioctl(fds.fd, FIONREAD, &len);
80 event = buf = xmalloc(len);
81 len = readall(fds.fd, buf, len);
82
83 // Loop through set of events.
84 for (;;) {
85 int left = len - (((char *)event)-(char *)buf),
86 size = sizeof(struct inotify_event);
87
88 // Don't dereference event if ->len is off end of bufer
89 if (left >= size) size += event->len;
90 if (left < size) break;
91
92 if (event->mask) {
93 char *s = toybuf, *m;
94
95 for (m = masklist; *m; m++)
96 if (event->mask & (1<<(m-masklist))) *s++ = *m;
97 *s = 0;
98
99 if (**prog_args == '-' && !prog_args[0][1]) {
100 xprintf("%s\t%s\t%s\n" + 3*!event->len, toybuf,
101 toys.optargs[event->wd], event->name);
102 } else {
103 prog_args[1] = toybuf;
104 prog_args[2] = toys.optargs[event->wd];
105 prog_args[3] = event->len ? event->name : 0;
106 xrun(prog_args);
107 }
108
109 if (event->mask & IN_IGNORED) {
110 if (--toys.optc <= 0) {
111 free(buf);
112
113 goto done;
114 }
115 inotify_rm_watch(fds.fd, event->wd);
116 }
117 }
118 event = (void*)(size + (char*)event);
119 }
120 free(buf);
121 }
122
123 done:
124 toys.exitval = !!toys.signal;
125 }
126