diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2008-05-24 20:47:18 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2008-05-24 20:47:18 +0000 |
commit | 8e2c9e1518d42320ebd4b3ff09220d79a199e8ff (patch) | |
tree | ee565d0dbcbca18b33720aabc334d55ee39151da | |
parent | e94a87134d2c78d3a1df39605d1f30d928a592a5 (diff) | |
download | busybox-w32-8e2c9e1518d42320ebd4b3ff09220d79a199e8ff.tar.gz busybox-w32-8e2c9e1518d42320ebd4b3ff09220d79a199e8ff.tar.bz2 busybox-w32-8e2c9e1518d42320ebd4b3ff09220d79a199e8ff.zip |
inotify: new applet by Vladimir Dronnikov <dronnikov AT gmail.com>
function old new delta
inotifyd_main - 453 +453
packed_usage 24246 24450 +204
inotify_add_watch - 47 +47
inotify_init - 29 +29
mask_names - 13 +13
signal_handler 130 140 +10
applet_names 1859 1868 +9
applet_main 1132 1136 +4
applet_nameofs 566 568 +2
signalled 1 2 +1
-rw-r--r-- | include/applets.h | 1 | ||||
-rw-r--r-- | include/usage.h | 24 | ||||
-rw-r--r-- | miscutils/Config.in | 6 | ||||
-rw-r--r-- | miscutils/Kbuild | 1 | ||||
-rw-r--r-- | miscutils/inotifyd.c | 152 |
5 files changed, 184 insertions, 0 deletions
diff --git a/include/applets.h b/include/applets.h index 27c3a1b6f..4797e1dd5 100644 --- a/include/applets.h +++ b/include/applets.h | |||
@@ -185,6 +185,7 @@ USE_IFENSLAVE(APPLET(ifenslave, _BB_DIR_SBIN, _BB_SUID_NEVER)) | |||
185 | USE_IFUPDOWN(APPLET_ODDNAME(ifup, ifupdown, _BB_DIR_SBIN, _BB_SUID_NEVER, ifup)) | 185 | USE_IFUPDOWN(APPLET_ODDNAME(ifup, ifupdown, _BB_DIR_SBIN, _BB_SUID_NEVER, ifup)) |
186 | USE_INETD(APPLET(inetd, _BB_DIR_USR_SBIN, _BB_SUID_NEVER)) | 186 | USE_INETD(APPLET(inetd, _BB_DIR_USR_SBIN, _BB_SUID_NEVER)) |
187 | USE_INIT(APPLET(init, _BB_DIR_SBIN, _BB_SUID_NEVER)) | 187 | USE_INIT(APPLET(init, _BB_DIR_SBIN, _BB_SUID_NEVER)) |
188 | USE_INOTIFYD(APPLET(inotifyd, _BB_DIR_SBIN, _BB_SUID_NEVER)) | ||
188 | USE_INSMOD(APPLET(insmod, _BB_DIR_SBIN, _BB_SUID_NEVER)) | 189 | USE_INSMOD(APPLET(insmod, _BB_DIR_SBIN, _BB_SUID_NEVER)) |
189 | USE_INSTALL(APPLET(install, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) | 190 | USE_INSTALL(APPLET(install, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) |
190 | #if ENABLE_FEATURE_IP_ADDRESS \ | 191 | #if ENABLE_FEATURE_IP_ADDRESS \ |
diff --git a/include/usage.h b/include/usage.h index a1e489453..a4fe6a7e0 100644 --- a/include/usage.h +++ b/include/usage.h | |||
@@ -1833,6 +1833,30 @@ | |||
1833 | " ::shutdown:/bin/umount -a -r\n" \ | 1833 | " ::shutdown:/bin/umount -a -r\n" \ |
1834 | " ::shutdown:/sbin/swapoff -a\n" | 1834 | " ::shutdown:/sbin/swapoff -a\n" |
1835 | 1835 | ||
1836 | #define inotifyd_trivial_usage \ | ||
1837 | "/user/space/agent dir/or/file/being/watched[:mask] ..." | ||
1838 | #define inotifyd_full_usage "\n\n" \ | ||
1839 | "Spawn userspace agent on filesystem changes." \ | ||
1840 | "\nWhen a filesystem event matching the mask occurs" \ | ||
1841 | "\non specified file/directory an userspace agent is spawned" \ | ||
1842 | "\nwith the parameters:" \ | ||
1843 | "\n1. actual event(s)" \ | ||
1844 | "\n2. file/directory name" \ | ||
1845 | "\n3. name of subfile (if any), in case of watching a directory" \ | ||
1846 | "\n" \ | ||
1847 | "\n a File is accessed" \ | ||
1848 | "\n c File is modified" \ | ||
1849 | "\n e Metadata changed" \ | ||
1850 | "\n w Writtable file is closed" \ | ||
1851 | "\n 0 Unwrittable file is closed" \ | ||
1852 | "\n r File is opened" \ | ||
1853 | "\n m File is moved from X" \ | ||
1854 | "\n y File is moved to Y" \ | ||
1855 | "\n n Subfile is created" \ | ||
1856 | "\n d Subfile is deleted" \ | ||
1857 | "\n D Self is deleted" \ | ||
1858 | "\n M Self is moved" \ | ||
1859 | |||
1836 | #define insmod_trivial_usage \ | 1860 | #define insmod_trivial_usage \ |
1837 | USE_FEATURE_2_4_MODULES("[OPTION]... ") "MODULE [symbol=value]..." | 1861 | USE_FEATURE_2_4_MODULES("[OPTION]... ") "MODULE [symbol=value]..." |
1838 | #define insmod_full_usage "\n\n" \ | 1862 | #define insmod_full_usage "\n\n" \ |
diff --git a/miscutils/Config.in b/miscutils/Config.in index dffde34db..c7dbee899 100644 --- a/miscutils/Config.in +++ b/miscutils/Config.in | |||
@@ -222,6 +222,12 @@ config FBSPLASH | |||
222 | "NN" (ASCII decimal number) - percentage to show on progress bar | 222 | "NN" (ASCII decimal number) - percentage to show on progress bar |
223 | "exit" - well you guessed it | 223 | "exit" - well you guessed it |
224 | 224 | ||
225 | config INOTIFYD | ||
226 | bool "inotifyd" | ||
227 | default n | ||
228 | help | ||
229 | Simple inotify daemon. Reports filesystem changes. Requires kernel >= 2.6.13 | ||
230 | |||
225 | config LAST | 231 | config LAST |
226 | bool "last" | 232 | bool "last" |
227 | default n | 233 | default n |
diff --git a/miscutils/Kbuild b/miscutils/Kbuild index 96e754e1b..c12b12d42 100644 --- a/miscutils/Kbuild +++ b/miscutils/Kbuild | |||
@@ -16,6 +16,7 @@ lib-$(CONFIG_DEVFSD) += devfsd.o | |||
16 | lib-$(CONFIG_EJECT) += eject.o | 16 | lib-$(CONFIG_EJECT) += eject.o |
17 | lib-$(CONFIG_FBSPLASH) += fbsplash.o | 17 | lib-$(CONFIG_FBSPLASH) += fbsplash.o |
18 | lib-$(CONFIG_HDPARM) += hdparm.o | 18 | lib-$(CONFIG_HDPARM) += hdparm.o |
19 | lib-$(CONFIG_INOTIFYD) += inotifyd.o | ||
19 | lib-$(CONFIG_FEATURE_LAST_SMALL)+= last.o | 20 | lib-$(CONFIG_FEATURE_LAST_SMALL)+= last.o |
20 | lib-$(CONFIG_FEATURE_LAST_FANCY)+= last_fancy.o | 21 | lib-$(CONFIG_FEATURE_LAST_FANCY)+= last_fancy.o |
21 | lib-$(CONFIG_LESS) += less.o | 22 | lib-$(CONFIG_LESS) += less.o |
diff --git a/miscutils/inotifyd.c b/miscutils/inotifyd.c new file mode 100644 index 000000000..0d7ad2a9d --- /dev/null +++ b/miscutils/inotifyd.c | |||
@@ -0,0 +1,152 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | ||
2 | /* | ||
3 | * simple inotify daemon | ||
4 | * reports filesystem changes via userspace agent | ||
5 | * | ||
6 | * Copyright (C) 2008 by Vladimir Dronnikov <dronnikov@gmail.com> | ||
7 | * | ||
8 | * Licensed under GPLv2, see file LICENSE in this tarball for details. | ||
9 | */ | ||
10 | |||
11 | /* | ||
12 | * Use as follows: | ||
13 | * # inotifyd /user/space/agent dir/or/file/being/watched[:mask] ... | ||
14 | * | ||
15 | * When a filesystem event matching the specified mask is occured on specified file (or directory) | ||
16 | * a userspace agent is spawned and given the following parameters: | ||
17 | * $1. actual event(s) | ||
18 | * $2. file (or directory) name | ||
19 | * $3. name of subfile (if any), in case of watching a directory | ||
20 | * | ||
21 | * E.g. inotifyd ./dev-watcher /dev:n | ||
22 | * | ||
23 | * ./dev-watcher can be, say: | ||
24 | * #!/bin/sh | ||
25 | * echo "We have new device in here! Hello, $3!" | ||
26 | * | ||
27 | * See below for mask names explanation. | ||
28 | */ | ||
29 | |||
30 | #include "libbb.h" | ||
31 | #include <linux/inotify.h> | ||
32 | |||
33 | static volatile smallint signalled; | ||
34 | |||
35 | static void signal_handler(int signo) | ||
36 | { | ||
37 | signalled = signo; | ||
38 | } | ||
39 | |||
40 | static const char mask_names[] ALIGN1 = | ||
41 | "a" // 0x00000001 File was accessed | ||
42 | "c" // 0x00000002 File was modified | ||
43 | "e" // 0x00000004 Metadata changed | ||
44 | "w" // 0x00000008 Writtable file was closed | ||
45 | "0" // 0x00000010 Unwrittable file closed | ||
46 | "r" // 0x00000020 File was opened | ||
47 | "m" // 0x00000040 File was moved from X | ||
48 | "y" // 0x00000080 File was moved to Y | ||
49 | "n" // 0x00000100 Subfile was created | ||
50 | "d" // 0x00000200 Subfile was deleted | ||
51 | "D" // 0x00000400 Self was deleted | ||
52 | "M" // 0x00000800 Self was moved | ||
53 | ; | ||
54 | |||
55 | extern int inotify_init(void); | ||
56 | extern int inotify_add_watch(int fd, const char *path, uint32_t mask); | ||
57 | |||
58 | int inotifyd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | ||
59 | int inotifyd_main(int argc ATTRIBUTE_UNUSED, char **argv) | ||
60 | { | ||
61 | unsigned mask = IN_ALL_EVENTS; // assume we want all events | ||
62 | struct pollfd pfd; | ||
63 | char **watched = ++argv; // watched name list | ||
64 | const char *args[] = { *argv, NULL, NULL, NULL, NULL }; | ||
65 | |||
66 | // sanity check: agent and at least one watch must be given | ||
67 | if (!argv[1]) | ||
68 | bb_show_usage(); | ||
69 | |||
70 | // open inotify | ||
71 | pfd.fd = inotify_init(); | ||
72 | if (pfd.fd < 0) | ||
73 | bb_perror_msg_and_die("no kernel support"); | ||
74 | |||
75 | // setup watched | ||
76 | while (*++argv) { | ||
77 | char *path = *argv; | ||
78 | char *masks = strchr(path, ':'); | ||
79 | int wd; // watch descriptor | ||
80 | // if mask is specified -> | ||
81 | if (masks) { | ||
82 | *masks = '\0'; // split path and mask | ||
83 | // convert mask names to mask bitset | ||
84 | mask = 0; | ||
85 | while (*++masks) { | ||
86 | int i = strchr(mask_names, *masks) - mask_names; | ||
87 | if (i >= 0) { | ||
88 | mask |= (1 << i); | ||
89 | } | ||
90 | } | ||
91 | } | ||
92 | // add watch | ||
93 | wd = inotify_add_watch(pfd.fd, path, mask); | ||
94 | if (wd < 0) { | ||
95 | bb_perror_msg_and_die("add watch (%s) failed", path); | ||
96 | // } else { | ||
97 | // bb_error_msg("added %d [%s]:%4X", wd, path, mask); | ||
98 | } | ||
99 | } | ||
100 | |||
101 | // setup signals | ||
102 | bb_signals(0 | ||
103 | + (1 << SIGHUP) | ||
104 | + (1 << SIGINT) | ||
105 | + (1 << SIGTERM) | ||
106 | + (1 << SIGPIPE) | ||
107 | , signal_handler); | ||
108 | |||
109 | // do watch | ||
110 | |||
111 | // pfd.fd = fd; | ||
112 | pfd.events = POLLIN; | ||
113 | |||
114 | while (!signalled && poll(&pfd, 1, -1) > 0) { | ||
115 | ssize_t len; | ||
116 | void *buf; | ||
117 | struct inotify_event *ie; | ||
118 | |||
119 | // read out all pending events | ||
120 | xioctl(pfd.fd, FIONREAD, &len); | ||
121 | #define eventbuf bb_common_bufsiz1 | ||
122 | ie = buf = (len <= sizeof(eventbuf)) ? eventbuf : xmalloc(len); | ||
123 | len = full_read(pfd.fd, buf, len); | ||
124 | // process events. N.B. events may vary in length | ||
125 | while (len > 0) { | ||
126 | int i; | ||
127 | char events[12]; | ||
128 | char *s = events; | ||
129 | unsigned m = ie->mask; | ||
130 | |||
131 | for (i = 0; i < 12; ++i, m >>= 1) { | ||
132 | if (m & 1) { | ||
133 | *s++ = mask_names[i]; | ||
134 | } | ||
135 | } | ||
136 | *s = '\0'; | ||
137 | // bb_error_msg("exec %s %08X\t%s\t%s\t%s", agent, ie->mask, events, watched[ie->wd], ie->len ? ie->name : ""); | ||
138 | args[1] = events; | ||
139 | args[2] = watched[ie->wd]; | ||
140 | args[3] = ie->len ? ie->name : NULL; | ||
141 | xspawn((char **)args); | ||
142 | // next event | ||
143 | i = sizeof(struct inotify_event) + ie->len; | ||
144 | len -= i; | ||
145 | ie = (void*)((char*)ie + i); | ||
146 | } | ||
147 | if (eventbuf != buf) | ||
148 | free(buf); | ||
149 | } | ||
150 | |||
151 | return EXIT_SUCCESS; | ||
152 | } | ||