34 |
"a" // 0x00000001 File was accessed |
"a" // 0x00000001 File was accessed |
35 |
"c" // 0x00000002 File was modified |
"c" // 0x00000002 File was modified |
36 |
"e" // 0x00000004 Metadata changed |
"e" // 0x00000004 Metadata changed |
37 |
"w" // 0x00000008 Writtable file was closed |
"w" // 0x00000008 Writable file was closed |
38 |
"0" // 0x00000010 Unwrittable file closed |
"0" // 0x00000010 Unwritable file closed |
39 |
"r" // 0x00000020 File was opened |
"r" // 0x00000020 File was opened |
40 |
"m" // 0x00000040 File was moved from X |
"m" // 0x00000040 File was moved from X |
41 |
"y" // 0x00000080 File was moved to Y |
"y" // 0x00000080 File was moved to Y |
43 |
"d" // 0x00000200 Subfile was deleted |
"d" // 0x00000200 Subfile was deleted |
44 |
"D" // 0x00000400 Self was deleted |
"D" // 0x00000400 Self was deleted |
45 |
"M" // 0x00000800 Self was moved |
"M" // 0x00000800 Self was moved |
46 |
|
"\0" // 0x00001000 (unused) |
47 |
|
// Kernel events, always reported: |
48 |
|
"u" // 0x00002000 Backing fs was unmounted |
49 |
|
"o" // 0x00004000 Event queued overflowed |
50 |
|
"x" // 0x00008000 File is no longer watched (usually deleted) |
51 |
; |
; |
52 |
|
enum { |
53 |
extern int inotify_init(void); |
MASK_BITS = sizeof(mask_names) - 1 |
54 |
extern int inotify_add_watch(int fd, const char *path, uint32_t mask); |
}; |
55 |
|
|
56 |
int inotifyd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
int inotifyd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
57 |
int inotifyd_main(int argc UNUSED_PARAM, char **argv) |
int inotifyd_main(int argc, char **argv) |
58 |
{ |
{ |
59 |
int n; |
int n; |
60 |
unsigned mask = IN_ALL_EVENTS; // assume we want all events |
unsigned mask; |
61 |
struct pollfd pfd; |
struct pollfd pfd; |
62 |
char **watched = ++argv; // watched name list |
char **watches; // names of files being watched |
63 |
const char *args[] = { *argv, NULL, NULL, NULL, NULL }; |
const char *args[5]; |
64 |
|
|
65 |
// sanity check: agent and at least one watch must be given |
// sanity check: agent and at least one watch must be given |
66 |
if (!argv[1]) |
if (!argv[1] || !argv[2]) |
67 |
bb_show_usage(); |
bb_show_usage(); |
68 |
|
|
69 |
|
argv++; |
70 |
|
// inotify_add_watch will number watched files |
71 |
|
// starting from 1, thus watches[0] is unimportant, |
72 |
|
// and 1st file name is watches[1]. |
73 |
|
watches = argv; |
74 |
|
args[0] = *argv; |
75 |
|
args[4] = NULL; |
76 |
|
argc -= 2; // number of files we watch |
77 |
|
|
78 |
// open inotify |
// open inotify |
79 |
pfd.fd = inotify_init(); |
pfd.fd = inotify_init(); |
80 |
if (pfd.fd < 0) |
if (pfd.fd < 0) |
81 |
bb_perror_msg_and_die("no kernel support"); |
bb_perror_msg_and_die("no kernel support"); |
82 |
|
|
83 |
// setup watched |
// setup watches |
84 |
while (*++argv) { |
while (*++argv) { |
85 |
char *path = *argv; |
char *path = *argv; |
86 |
char *masks = strchr(path, ':'); |
char *masks = strchr(path, ':'); |
87 |
|
|
88 |
|
mask = 0x0fff; // assuming we want all non-kernel events |
89 |
// if mask is specified -> |
// if mask is specified -> |
90 |
if (masks) { |
if (masks) { |
91 |
*masks = '\0'; // split path and mask |
*masks = '\0'; // split path and mask |
92 |
// convert mask names to mask bitset |
// convert mask names to mask bitset |
93 |
mask = 0; |
mask = 0; |
94 |
while (*++masks) { |
while (*++masks) { |
95 |
int i = strchr(mask_names, *masks) - mask_names; |
const char *found; |
96 |
if (i >= 0) { |
found = memchr(mask_names, *masks, MASK_BITS); |
97 |
mask |= (1 << i); |
if (found) |
98 |
} |
mask |= (1 << (found - mask_names)); |
99 |
} |
} |
100 |
} |
} |
101 |
// add watch |
// add watch |
111 |
// do watch |
// do watch |
112 |
pfd.events = POLLIN; |
pfd.events = POLLIN; |
113 |
while (1) { |
while (1) { |
114 |
ssize_t len; |
int len; |
115 |
void *buf; |
void *buf; |
116 |
struct inotify_event *ie; |
struct inotify_event *ie; |
|
|
|
117 |
again: |
again: |
118 |
if (bb_got_signal) |
if (bb_got_signal) |
119 |
break; |
break; |
120 |
n = poll(&pfd, 1, -1); |
n = poll(&pfd, 1, -1); |
121 |
/* Signal interrupted us? */ |
// Signal interrupted us? |
122 |
if (n < 0 && errno == EINTR) |
if (n < 0 && errno == EINTR) |
123 |
goto again; |
goto again; |
124 |
// Under Linux, above if() is not necessary. |
// Under Linux, above if() is not necessary. |
132 |
break; |
break; |
133 |
|
|
134 |
// read out all pending events |
// read out all pending events |
135 |
|
// (NB: len must be int, not ssize_t or long!) |
136 |
xioctl(pfd.fd, FIONREAD, &len); |
xioctl(pfd.fd, FIONREAD, &len); |
137 |
#define eventbuf bb_common_bufsiz1 |
#define eventbuf bb_common_bufsiz1 |
138 |
ie = buf = (len <= sizeof(eventbuf)) ? eventbuf : xmalloc(len); |
ie = buf = (len <= sizeof(eventbuf)) ? eventbuf : xmalloc(len); |
140 |
// process events. N.B. events may vary in length |
// process events. N.B. events may vary in length |
141 |
while (len > 0) { |
while (len > 0) { |
142 |
int i; |
int i; |
143 |
char events[sizeof(mask_names)]; |
// cache relevant events mask |
144 |
char *s = events; |
unsigned m = ie->mask & ((1 << MASK_BITS) - 1); |
145 |
unsigned m = ie->mask; |
if (m) { |
146 |
|
char events[MASK_BITS + 1]; |
147 |
for (i = 0; i < sizeof(mask_names)-1; ++i, m >>= 1) { |
char *s = events; |
148 |
if (m & 1) |
for (i = 0; i < MASK_BITS; ++i, m >>= 1) { |
149 |
*s++ = mask_names[i]; |
if ((m & 1) && (mask_names[i] != '\0')) |
150 |
|
*s++ = mask_names[i]; |
151 |
|
} |
152 |
|
*s = '\0'; |
153 |
|
// bb_error_msg("exec %s %08X\t%s\t%s\t%s", args[0], |
154 |
|
// ie->mask, events, watches[ie->wd], ie->len ? ie->name : ""); |
155 |
|
args[1] = events; |
156 |
|
args[2] = watches[ie->wd]; |
157 |
|
args[3] = ie->len ? ie->name : NULL; |
158 |
|
wait4pid(xspawn((char **)args)); |
159 |
|
// we are done if all files got final x event |
160 |
|
if (ie->mask & 0x8000) { |
161 |
|
if (--argc <= 0) |
162 |
|
goto done; |
163 |
|
inotify_rm_watch(pfd.fd, ie->wd); |
164 |
|
} |
165 |
} |
} |
|
*s = '\0'; |
|
|
//bb_error_msg("exec %s %08X\t%s\t%s\t%s", agent, |
|
|
// ie->mask, events, watched[ie->wd], ie->len ? ie->name : ""); |
|
|
args[1] = events; |
|
|
args[2] = watched[ie->wd]; |
|
|
args[3] = ie->len ? ie->name : NULL; |
|
|
wait4pid(xspawn((char **)args)); |
|
166 |
// next event |
// next event |
167 |
i = sizeof(struct inotify_event) + ie->len; |
i = sizeof(struct inotify_event) + ie->len; |
168 |
len -= i; |
len -= i; |
170 |
} |
} |
171 |
if (eventbuf != buf) |
if (eventbuf != buf) |
172 |
free(buf); |
free(buf); |
173 |
} |
} // while (1) |
174 |
|
done: |
175 |
return EXIT_SUCCESS; |
return bb_got_signal; |
176 |
} |
} |