diff options
-rw-r--r-- | docs/busybox.net/news.html | 4 | ||||
-rw-r--r-- | include/applets.h | 1 | ||||
-rw-r--r-- | include/usage.h | 17 | ||||
-rw-r--r-- | util-linux/Config.in | 22 | ||||
-rw-r--r-- | util-linux/Kbuild | 1 | ||||
-rw-r--r-- | util-linux/acpid.c | 167 |
6 files changed, 210 insertions, 2 deletions
diff --git a/docs/busybox.net/news.html b/docs/busybox.net/news.html index 3fccaae12..5c005fb0e 100644 --- a/docs/busybox.net/news.html +++ b/docs/busybox.net/news.html | |||
@@ -32,8 +32,8 @@ | |||
32 | <a href="http://busybox.net/downloads/fixes-1.12.3/">patches</a>, | 32 | <a href="http://busybox.net/downloads/fixes-1.12.3/">patches</a>, |
33 | <a href="http://busybox.net/fix.html">how to add a patch</a>)</p> | 33 | <a href="http://busybox.net/fix.html">how to add a patch</a>)</p> |
34 | 34 | ||
35 | <p>Bug-fix releases. 1.13.1 has fixes for ash, option parsing, id, init, | 35 | <p>Bug fix releases. 1.13.1 has fixes for ash, option parsing, id, init, |
36 | inotify, klogd, line editing and modprobe. 1.12.3 has fixes | 36 | inotifyd, klogd, line editing and modprobe. 1.12.3 has fixes |
37 | for option parsing and line editing. | 37 | for option parsing and line editing. |
38 | </p> | 38 | </p> |
39 | </li> | 39 | </li> |
diff --git a/include/applets.h b/include/applets.h index fb904bb9f..ad3925577 100644 --- a/include/applets.h +++ b/include/applets.h | |||
@@ -69,6 +69,7 @@ s - suid type: | |||
69 | 69 | ||
70 | USE_TEST(APPLET_NOFORK([, test, _BB_DIR_USR_BIN, _BB_SUID_NEVER, test)) | 70 | USE_TEST(APPLET_NOFORK([, test, _BB_DIR_USR_BIN, _BB_SUID_NEVER, test)) |
71 | USE_TEST(APPLET_NOFORK([[, test, _BB_DIR_USR_BIN, _BB_SUID_NEVER, test)) | 71 | USE_TEST(APPLET_NOFORK([[, test, _BB_DIR_USR_BIN, _BB_SUID_NEVER, test)) |
72 | USE_ACPID(APPLET(acpid, _BB_DIR_SBIN, _BB_SUID_NEVER)) | ||
72 | USE_ADDGROUP(APPLET(addgroup, _BB_DIR_BIN, _BB_SUID_NEVER)) | 73 | USE_ADDGROUP(APPLET(addgroup, _BB_DIR_BIN, _BB_SUID_NEVER)) |
73 | USE_ADDUSER(APPLET(adduser, _BB_DIR_BIN, _BB_SUID_NEVER)) | 74 | USE_ADDUSER(APPLET(adduser, _BB_DIR_BIN, _BB_SUID_NEVER)) |
74 | USE_ADJTIMEX(APPLET(adjtimex, _BB_DIR_SBIN, _BB_SUID_NEVER)) | 75 | USE_ADJTIMEX(APPLET(adjtimex, _BB_DIR_SBIN, _BB_SUID_NEVER)) |
diff --git a/include/usage.h b/include/usage.h index d35f8ae71..502fea7a0 100644 --- a/include/usage.h +++ b/include/usage.h | |||
@@ -16,6 +16,23 @@ | |||
16 | 16 | ||
17 | #define NOUSAGE_STR "\b" | 17 | #define NOUSAGE_STR "\b" |
18 | 18 | ||
19 | #define acpid_trivial_usage \ | ||
20 | "[-d] [-c CONFDIR] [-l LOGFILE] [-e PROC_EVENT_FILE] [EVDEV_EVENT_FILE...]" | ||
21 | |||
22 | #define acpid_full_usage "\n\n" \ | ||
23 | "Listen to ACPI events and spawn specific helpers on event arrival\n" \ | ||
24 | "\nOptions:" \ | ||
25 | "\n -d Do not daemonize and log to stderr" \ | ||
26 | "\n -c DIR Config directory [/etc/acpi]" \ | ||
27 | "\n -e FILE /proc event file [/proc/acpi/event]" \ | ||
28 | "\n -l FILE Log file [/var/log/acpid]" \ | ||
29 | USE_FEATURE_ACPID_COMPAT( \ | ||
30 | "\n\nAccept and ignore compatibility options -g -m -s -S -v" \ | ||
31 | ) | ||
32 | |||
33 | #define acpid_example_usage \ | ||
34 | "# acpid -l /var/log/my-acpi-log\n" \ | ||
35 | "# acpid -d /dev/input/event*\n" | ||
19 | 36 | ||
20 | #define addgroup_trivial_usage \ | 37 | #define addgroup_trivial_usage \ |
21 | "[-g GID] " USE_FEATURE_ADDUSER_TO_GROUP("[user_name] ") "group_name" | 38 | "[-g GID] " USE_FEATURE_ADDUSER_TO_GROUP("[user_name] ") "group_name" |
diff --git a/util-linux/Config.in b/util-linux/Config.in index 976507b68..3bba2e26d 100644 --- a/util-linux/Config.in +++ b/util-linux/Config.in | |||
@@ -5,6 +5,28 @@ | |||
5 | 5 | ||
6 | menu "Linux System Utilities" | 6 | menu "Linux System Utilities" |
7 | 7 | ||
8 | config ACPID | ||
9 | bool "acpid" | ||
10 | default n | ||
11 | help | ||
12 | acpid listens to ACPI events coming either in textual form from | ||
13 | /proc/acpi/event (though it is marked deprecated it is still widely | ||
14 | used and _is_ a standard) or in binary form from specified evdevs | ||
15 | (just use /dev/input/event*). | ||
16 | |||
17 | It parses the event to retrieve ACTION and a possible PARAMETER. | ||
18 | It then spawns /etc/acpi/<ACTION>[/<PARAMETER>] either via run-parts | ||
19 | (if the resulting path is a directory) or directly as an executable. | ||
20 | |||
21 | N.B. acpid relies on run-parts so have the latter installed. | ||
22 | |||
23 | config FEATURE_ACPID_COMPAT | ||
24 | bool "Accept and ignore redundant options" | ||
25 | default n | ||
26 | depends on ACPID | ||
27 | help | ||
28 | Accept and ignore compatibility options -g -m -s -S -v. | ||
29 | |||
8 | config BLKID | 30 | config BLKID |
9 | bool "blkid" | 31 | bool "blkid" |
10 | default n | 32 | default n |
diff --git a/util-linux/Kbuild b/util-linux/Kbuild index 2d0fc4928..842afb756 100644 --- a/util-linux/Kbuild +++ b/util-linux/Kbuild | |||
@@ -5,6 +5,7 @@ | |||
5 | # Licensed under the GPL v2, see the file LICENSE in this tarball. | 5 | # Licensed under the GPL v2, see the file LICENSE in this tarball. |
6 | 6 | ||
7 | lib-y:= | 7 | lib-y:= |
8 | lib-$(CONFIG_ACPID) += acpid.o | ||
8 | lib-$(CONFIG_BLKID) += blkid.o | 9 | lib-$(CONFIG_BLKID) += blkid.o |
9 | lib-$(CONFIG_DMESG) += dmesg.o | 10 | lib-$(CONFIG_DMESG) += dmesg.o |
10 | lib-$(CONFIG_FBSET) += fbset.o | 11 | lib-$(CONFIG_FBSET) += fbset.o |
diff --git a/util-linux/acpid.c b/util-linux/acpid.c new file mode 100644 index 000000000..ef4e54d5d --- /dev/null +++ b/util-linux/acpid.c | |||
@@ -0,0 +1,167 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | ||
2 | /* | ||
3 | * simple ACPI events listener | ||
4 | * | ||
5 | * Copyright (C) 2008 by Vladimir Dronnikov <dronnikov@gmail.com> | ||
6 | * | ||
7 | * Licensed under GPLv2, see file LICENSE in this tarball for details. | ||
8 | */ | ||
9 | #include "libbb.h" | ||
10 | |||
11 | #include <linux/input.h> | ||
12 | #ifndef SW_RFKILL_ALL | ||
13 | # define SW_RFKILL_ALL 3 | ||
14 | #endif | ||
15 | |||
16 | /* | ||
17 | * acpid listens to ACPI events coming either in textual form | ||
18 | * from /proc/acpi/event (though it is marked deprecated, | ||
19 | * it is still widely used and _is_ a standard) or in binary form | ||
20 | * from specified evdevs (just use /dev/input/event*). | ||
21 | * It parses the event to retrieve ACTION and a possible PARAMETER. | ||
22 | * It then spawns /etc/acpi/<ACTION>[/<PARAMETER>] either via run-parts | ||
23 | * (if the resulting path is a directory) or directly. | ||
24 | * If the resulting path does not exist it logs it via perror | ||
25 | * and continues listening. | ||
26 | */ | ||
27 | |||
28 | static void process_event(const char *event) | ||
29 | { | ||
30 | struct stat st; | ||
31 | char *handler = xasprintf("./%s", event); | ||
32 | const char *args[] = { "run-parts", handler, NULL }; | ||
33 | |||
34 | // debug info | ||
35 | if (option_mask32 & 8) { // -d | ||
36 | bb_error_msg("%s", event); | ||
37 | } | ||
38 | |||
39 | // spawn handler | ||
40 | // N.B. run-parts would require scripts to have #!/bin/sh | ||
41 | // handler is directory? -> use run-parts | ||
42 | // handler is file? -> run it directly | ||
43 | if (0 == stat(event, &st)) | ||
44 | spawn((char **)args + (0==(st.st_mode & S_IFDIR))); | ||
45 | else | ||
46 | bb_simple_perror_msg(event); | ||
47 | free(handler); | ||
48 | } | ||
49 | |||
50 | /* | ||
51 | * acpid [-c conf_dir] [-l log_file] [-e proc_event_file] [evdev_event_file...] | ||
52 | */ | ||
53 | |||
54 | int acpid_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | ||
55 | int acpid_main(int argc, char **argv) | ||
56 | { | ||
57 | struct pollfd *pfd; | ||
58 | int i, nfd; | ||
59 | const char *opt_conf = "/etc/acpi"; | ||
60 | const char *opt_input = "/proc/acpi/event"; | ||
61 | const char *opt_logfile = "/var/log/acpid.log"; | ||
62 | |||
63 | getopt32(argv, "c:e:l:d" | ||
64 | USE_FEATURE_ACPID_COMPAT("g:m:s:S:v"), | ||
65 | &opt_conf, &opt_input, &opt_logfile | ||
66 | USE_FEATURE_ACPID_COMPAT(, NULL, NULL, NULL, NULL, NULL) | ||
67 | ); | ||
68 | |||
69 | // daemonize unless -d given | ||
70 | if (!(option_mask32 & 8)) { // ! -d | ||
71 | bb_daemonize_or_rexec(0, argv); | ||
72 | close(2); | ||
73 | xopen(opt_logfile, O_WRONLY | O_CREAT | O_TRUNC); | ||
74 | } | ||
75 | |||
76 | argv += optind; | ||
77 | |||
78 | // goto configuration directory | ||
79 | xchdir(opt_conf); | ||
80 | |||
81 | // // setup signals | ||
82 | // bb_signals(BB_FATAL_SIGS, record_signo); | ||
83 | |||
84 | // no explicit evdev files given? -> use proc event interface | ||
85 | if (!*argv) { | ||
86 | // proc_event file is just a "config" :) | ||
87 | char *token[4]; | ||
88 | parser_t *parser = config_open(opt_input); | ||
89 | |||
90 | // dispatch events | ||
91 | while (config_read(parser, token, 4, 4, "\0 ", PARSE_NORMAL)) { | ||
92 | char *event = xasprintf("%s/%s", token[1], token[2]); | ||
93 | process_event(event); | ||
94 | free(event); | ||
95 | } | ||
96 | |||
97 | if (ENABLE_FEATURE_CLEAN_UP) | ||
98 | config_close(parser); | ||
99 | return EXIT_SUCCESS; | ||
100 | } | ||
101 | |||
102 | // evdev files given, use evdev interface | ||
103 | |||
104 | // open event devices | ||
105 | pfd = xzalloc(sizeof(*pfd) * (argc - optind)); | ||
106 | nfd = 0; | ||
107 | while (*argv) { | ||
108 | pfd[nfd].fd = open_or_warn(*argv++, O_RDONLY | O_NONBLOCK); | ||
109 | if (pfd[nfd].fd >= 0) | ||
110 | pfd[nfd++].events = POLLIN; | ||
111 | } | ||
112 | |||
113 | // dispatch events | ||
114 | while (/* !bb_got_signal && */ poll(pfd, nfd, -1) > 0) { | ||
115 | for (i = 0; i < nfd; i++) { | ||
116 | const char *event; | ||
117 | struct input_event ev; | ||
118 | |||
119 | if (!(pfd[i].revents & POLLIN)) | ||
120 | continue; | ||
121 | |||
122 | if (sizeof(ev) != full_read(pfd[i].fd, &ev, sizeof(ev))) | ||
123 | continue; | ||
124 | //bb_info_msg("%d: %d %d %4d", i, ev.type, ev.code, ev.value); | ||
125 | |||
126 | // filter out unneeded events | ||
127 | if (ev.value != 1) | ||
128 | continue; | ||
129 | |||
130 | event = NULL; | ||
131 | |||
132 | // N.B. we will conform to /proc/acpi/event | ||
133 | // naming convention when assigning event names | ||
134 | |||
135 | // TODO: do we want other events? | ||
136 | |||
137 | // power and sleep buttons delivered as keys pressed | ||
138 | if (EV_KEY == ev.type) { | ||
139 | if (KEY_POWER == ev.code) | ||
140 | event = "PWRF/00000080"; | ||
141 | else if (KEY_SLEEP == ev.code) | ||
142 | event = "SLPB/00000080"; | ||
143 | } | ||
144 | // switches | ||
145 | else if (EV_SW == ev.type) { | ||
146 | if (SW_LID == ev.code) | ||
147 | event = "LID/00000080"; | ||
148 | else if (SW_RFKILL_ALL == ev.code) | ||
149 | event = "RFKILL"; | ||
150 | } | ||
151 | // filter out unneeded events | ||
152 | if (!event) | ||
153 | continue; | ||
154 | |||
155 | // spawn event handler | ||
156 | process_event(event); | ||
157 | } | ||
158 | } | ||
159 | |||
160 | if (ENABLE_FEATURE_CLEAN_UP) { | ||
161 | for (i = 0; i < nfd; i++) | ||
162 | close(pfd[i].fd); | ||
163 | free(pfd); | ||
164 | } | ||
165 | |||
166 | return EXIT_SUCCESS; | ||
167 | } | ||