xref: /aosp_15_r20/external/toybox/toys/other/inotifyd.c (revision cf5a6c84e2b8763fc1a7db14496fd4742913b199)
1*cf5a6c84SAndroid Build Coastguard Worker /* inotifyd.c - inotify daemon.
2*cf5a6c84SAndroid Build Coastguard Worker  *
3*cf5a6c84SAndroid Build Coastguard Worker  * Copyright 2013 Ashwini Kumar <[email protected]>
4*cf5a6c84SAndroid Build Coastguard Worker  * Copyright 2013 Kyungwan Han <[email protected]>
5*cf5a6c84SAndroid Build Coastguard Worker  *
6*cf5a6c84SAndroid Build Coastguard Worker  * No Standard.
7*cf5a6c84SAndroid Build Coastguard Worker 
8*cf5a6c84SAndroid Build Coastguard Worker USE_INOTIFYD(NEWTOY(inotifyd, "<2", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_LINEBUF))
9*cf5a6c84SAndroid Build Coastguard Worker 
10*cf5a6c84SAndroid Build Coastguard Worker config INOTIFYD
11*cf5a6c84SAndroid Build Coastguard Worker   bool "inotifyd"
12*cf5a6c84SAndroid Build Coastguard Worker   default y
13*cf5a6c84SAndroid Build Coastguard Worker   help
14*cf5a6c84SAndroid Build Coastguard Worker     usage: inotifyd PROG FILE[:MASK] ...
15*cf5a6c84SAndroid Build Coastguard Worker 
16*cf5a6c84SAndroid Build Coastguard Worker     When a filesystem event matching MASK occurs to a FILE, run PROG as:
17*cf5a6c84SAndroid Build Coastguard Worker 
18*cf5a6c84SAndroid Build Coastguard Worker       PROG EVENTS FILE [DIRFILE]
19*cf5a6c84SAndroid Build Coastguard Worker 
20*cf5a6c84SAndroid Build Coastguard Worker     If PROG is "-" events are sent to stdout.
21*cf5a6c84SAndroid Build Coastguard Worker 
22*cf5a6c84SAndroid Build Coastguard Worker     This file is:
23*cf5a6c84SAndroid Build Coastguard Worker       a  accessed    c  modified    e  metadata change  w  closed (writable)
24*cf5a6c84SAndroid Build Coastguard Worker       r  opened      D  deleted     M  moved            0  closed (unwritable)
25*cf5a6c84SAndroid Build Coastguard Worker       u  unmounted   o  overflow    x  unwatchable
26*cf5a6c84SAndroid Build Coastguard Worker 
27*cf5a6c84SAndroid Build Coastguard Worker     A file in this directory is:
28*cf5a6c84SAndroid Build Coastguard Worker       m  moved in    y  moved out   n  created          d  deleted
29*cf5a6c84SAndroid Build Coastguard Worker 
30*cf5a6c84SAndroid Build Coastguard Worker     When x event happens for all FILEs, inotifyd exits (after waiting for PROG).
31*cf5a6c84SAndroid Build Coastguard Worker */
32*cf5a6c84SAndroid Build Coastguard Worker 
33*cf5a6c84SAndroid Build Coastguard Worker #define FOR_inotifyd
34*cf5a6c84SAndroid Build Coastguard Worker #include "toys.h"
35*cf5a6c84SAndroid Build Coastguard Worker #include <sys/inotify.h>
36*cf5a6c84SAndroid Build Coastguard Worker 
inotifyd_main(void)37*cf5a6c84SAndroid Build Coastguard Worker void inotifyd_main(void)
38*cf5a6c84SAndroid Build Coastguard Worker {
39*cf5a6c84SAndroid Build Coastguard Worker   struct pollfd fds;
40*cf5a6c84SAndroid Build Coastguard Worker   char *prog_args[5], **ss = toys.optargs;
41*cf5a6c84SAndroid Build Coastguard Worker   char *masklist ="acew0rmyndDM uox";
42*cf5a6c84SAndroid Build Coastguard Worker 
43*cf5a6c84SAndroid Build Coastguard Worker   fds.events = POLLIN;
44*cf5a6c84SAndroid Build Coastguard Worker 
45*cf5a6c84SAndroid Build Coastguard Worker   *prog_args = *toys.optargs;
46*cf5a6c84SAndroid Build Coastguard Worker   prog_args[4] = 0;
47*cf5a6c84SAndroid Build Coastguard Worker   if ((fds.fd = inotify_init()) == -1) perror_exit(0);
48*cf5a6c84SAndroid Build Coastguard Worker 
49*cf5a6c84SAndroid Build Coastguard Worker   // Track number of watched files. First one was program to run.
50*cf5a6c84SAndroid Build Coastguard Worker   toys.optc--;
51*cf5a6c84SAndroid Build Coastguard Worker 
52*cf5a6c84SAndroid Build Coastguard Worker   while (*++ss) {
53*cf5a6c84SAndroid Build Coastguard Worker     char *path = *ss, *masks = strchr(*ss, ':');
54*cf5a6c84SAndroid Build Coastguard Worker     int i, mask = 0;
55*cf5a6c84SAndroid Build Coastguard Worker 
56*cf5a6c84SAndroid Build Coastguard Worker     if (!masks) mask = 0xfff; // default to all
57*cf5a6c84SAndroid Build Coastguard Worker     else{
58*cf5a6c84SAndroid Build Coastguard Worker       for (*masks++ = 0; *masks; masks++) {
59*cf5a6c84SAndroid Build Coastguard Worker         i = stridx(masklist, *masks);;
60*cf5a6c84SAndroid Build Coastguard Worker         if (i == -1) error_exit("bad mask '%c'", *masks);
61*cf5a6c84SAndroid Build Coastguard Worker         mask |= 1<<i;
62*cf5a6c84SAndroid Build Coastguard Worker       }
63*cf5a6c84SAndroid Build Coastguard Worker     }
64*cf5a6c84SAndroid Build Coastguard Worker 
65*cf5a6c84SAndroid Build Coastguard Worker     // This returns increasing numbers starting from 1, which coincidentally
66*cf5a6c84SAndroid Build Coastguard Worker     // is the toys.optargs position of the file. (0 is program to run.)
67*cf5a6c84SAndroid Build Coastguard Worker     if (inotify_add_watch(fds.fd, path, mask) < 0) perror_exit_raw(path);
68*cf5a6c84SAndroid Build Coastguard Worker   }
69*cf5a6c84SAndroid Build Coastguard Worker 
70*cf5a6c84SAndroid Build Coastguard Worker   for (;;) {
71*cf5a6c84SAndroid Build Coastguard Worker     int ret = 0, len;
72*cf5a6c84SAndroid Build Coastguard Worker     void *buf = 0;
73*cf5a6c84SAndroid Build Coastguard Worker     struct inotify_event *event;
74*cf5a6c84SAndroid Build Coastguard Worker 
75*cf5a6c84SAndroid Build Coastguard Worker     // Read next event(s)
76*cf5a6c84SAndroid Build Coastguard Worker     ret = poll(&fds, 1, -1);
77*cf5a6c84SAndroid Build Coastguard Worker     if (ret < 0 && errno == EINTR) continue;
78*cf5a6c84SAndroid Build Coastguard Worker     if (ret <= 0) break;
79*cf5a6c84SAndroid Build Coastguard Worker     xioctl(fds.fd, FIONREAD, &len);
80*cf5a6c84SAndroid Build Coastguard Worker     event = buf = xmalloc(len);
81*cf5a6c84SAndroid Build Coastguard Worker     len = readall(fds.fd, buf, len);
82*cf5a6c84SAndroid Build Coastguard Worker 
83*cf5a6c84SAndroid Build Coastguard Worker     // Loop through set of events.
84*cf5a6c84SAndroid Build Coastguard Worker     for (;;) {
85*cf5a6c84SAndroid Build Coastguard Worker       int left = len - (((char *)event)-(char *)buf),
86*cf5a6c84SAndroid Build Coastguard Worker           size = sizeof(struct inotify_event);
87*cf5a6c84SAndroid Build Coastguard Worker 
88*cf5a6c84SAndroid Build Coastguard Worker       // Don't dereference event if ->len is off end of bufer
89*cf5a6c84SAndroid Build Coastguard Worker       if (left >= size) size += event->len;
90*cf5a6c84SAndroid Build Coastguard Worker       if (left < size) break;
91*cf5a6c84SAndroid Build Coastguard Worker 
92*cf5a6c84SAndroid Build Coastguard Worker       if (event->mask) {
93*cf5a6c84SAndroid Build Coastguard Worker         char *s = toybuf, *m;
94*cf5a6c84SAndroid Build Coastguard Worker 
95*cf5a6c84SAndroid Build Coastguard Worker         for (m = masklist; *m; m++)
96*cf5a6c84SAndroid Build Coastguard Worker           if (event->mask & (1<<(m-masklist))) *s++ = *m;
97*cf5a6c84SAndroid Build Coastguard Worker         *s = 0;
98*cf5a6c84SAndroid Build Coastguard Worker 
99*cf5a6c84SAndroid Build Coastguard Worker         if (**prog_args == '-' && !prog_args[0][1]) {
100*cf5a6c84SAndroid Build Coastguard Worker           xprintf("%s\t%s\t%s\n" + 3*!event->len, toybuf,
101*cf5a6c84SAndroid Build Coastguard Worker               toys.optargs[event->wd], event->name);
102*cf5a6c84SAndroid Build Coastguard Worker         } else {
103*cf5a6c84SAndroid Build Coastguard Worker           prog_args[1] = toybuf;
104*cf5a6c84SAndroid Build Coastguard Worker           prog_args[2] = toys.optargs[event->wd];
105*cf5a6c84SAndroid Build Coastguard Worker           prog_args[3] = event->len ? event->name : 0;
106*cf5a6c84SAndroid Build Coastguard Worker           xrun(prog_args);
107*cf5a6c84SAndroid Build Coastguard Worker         }
108*cf5a6c84SAndroid Build Coastguard Worker 
109*cf5a6c84SAndroid Build Coastguard Worker         if (event->mask & IN_IGNORED) {
110*cf5a6c84SAndroid Build Coastguard Worker           if (--toys.optc <= 0) {
111*cf5a6c84SAndroid Build Coastguard Worker             free(buf);
112*cf5a6c84SAndroid Build Coastguard Worker 
113*cf5a6c84SAndroid Build Coastguard Worker             goto done;
114*cf5a6c84SAndroid Build Coastguard Worker           }
115*cf5a6c84SAndroid Build Coastguard Worker           inotify_rm_watch(fds.fd, event->wd);
116*cf5a6c84SAndroid Build Coastguard Worker         }
117*cf5a6c84SAndroid Build Coastguard Worker       }
118*cf5a6c84SAndroid Build Coastguard Worker       event = (void*)(size + (char*)event);
119*cf5a6c84SAndroid Build Coastguard Worker     }
120*cf5a6c84SAndroid Build Coastguard Worker     free(buf);
121*cf5a6c84SAndroid Build Coastguard Worker   }
122*cf5a6c84SAndroid Build Coastguard Worker 
123*cf5a6c84SAndroid Build Coastguard Worker done:
124*cf5a6c84SAndroid Build Coastguard Worker   toys.exitval = !!toys.signal;
125*cf5a6c84SAndroid Build Coastguard Worker }
126