aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2008-11-29 09:05:50 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2008-11-29 09:05:50 +0000
commitd16950ded91446a23a6ceef35fb3e100400301d9 (patch)
tree038faff9ea801e5d7f022b75256fc52e66186b75
parentf7d87f9b183aa28777ce09d40222fbe221d15c91 (diff)
downloadbusybox-d16950ded91446a23a6ceef35fb3e100400301d9.tar.gz
acpid: new applet by Vladimir. +737 bytes
-rw-r--r--docs/busybox.net/news.html4
-rw-r--r--include/applets.h1
-rw-r--r--include/usage.h17
-rw-r--r--util-linux/Config.in22
-rw-r--r--util-linux/Kbuild1
-rw-r--r--util-linux/acpid.c167
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 @@
<a href="http://busybox.net/downloads/fixes-1.12.3/">patches</a>,
<a href="http://busybox.net/fix.html">how to add a patch</a>)</p>
- <p>Bug-fix releases. 1.13.1 has fixes for ash, option parsing, id, init,
- inotify, klogd, line editing and modprobe. 1.12.3 has fixes
+ <p>Bug fix releases. 1.13.1 has fixes for ash, option parsing, id, init,
+ inotifyd, klogd, line editing and modprobe. 1.12.3 has fixes
for option parsing and line editing.
</p>
</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:
USE_TEST(APPLET_NOFORK([, test, _BB_DIR_USR_BIN, _BB_SUID_NEVER, test))
USE_TEST(APPLET_NOFORK([[, test, _BB_DIR_USR_BIN, _BB_SUID_NEVER, test))
+USE_ACPID(APPLET(acpid, _BB_DIR_SBIN, _BB_SUID_NEVER))
USE_ADDGROUP(APPLET(addgroup, _BB_DIR_BIN, _BB_SUID_NEVER))
USE_ADDUSER(APPLET(adduser, _BB_DIR_BIN, _BB_SUID_NEVER))
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 @@
#define NOUSAGE_STR "\b"
+#define acpid_trivial_usage \
+ "[-d] [-c CONFDIR] [-l LOGFILE] [-e PROC_EVENT_FILE] [EVDEV_EVENT_FILE...]"
+
+#define acpid_full_usage "\n\n" \
+ "Listen to ACPI events and spawn specific helpers on event arrival\n" \
+ "\nOptions:" \
+ "\n -d Do not daemonize and log to stderr" \
+ "\n -c DIR Config directory [/etc/acpi]" \
+ "\n -e FILE /proc event file [/proc/acpi/event]" \
+ "\n -l FILE Log file [/var/log/acpid]" \
+ USE_FEATURE_ACPID_COMPAT( \
+ "\n\nAccept and ignore compatibility options -g -m -s -S -v" \
+ )
+
+#define acpid_example_usage \
+ "# acpid -l /var/log/my-acpi-log\n" \
+ "# acpid -d /dev/input/event*\n"
#define addgroup_trivial_usage \
"[-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 @@
menu "Linux System Utilities"
+config ACPID
+ bool "acpid"
+ default n
+ help
+ acpid listens to ACPI events coming either in textual form from
+ /proc/acpi/event (though it is marked deprecated it is still widely
+ used and _is_ a standard) or in binary form from specified evdevs
+ (just use /dev/input/event*).
+
+ It parses the event to retrieve ACTION and a possible PARAMETER.
+ It then spawns /etc/acpi/<ACTION>[/<PARAMETER>] either via run-parts
+ (if the resulting path is a directory) or directly as an executable.
+
+ N.B. acpid relies on run-parts so have the latter installed.
+
+config FEATURE_ACPID_COMPAT
+ bool "Accept and ignore redundant options"
+ default n
+ depends on ACPID
+ help
+ Accept and ignore compatibility options -g -m -s -S -v.
+
config BLKID
bool "blkid"
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 @@
# Licensed under the GPL v2, see the file LICENSE in this tarball.
lib-y:=
+lib-$(CONFIG_ACPID) += acpid.o
lib-$(CONFIG_BLKID) += blkid.o
lib-$(CONFIG_DMESG) += dmesg.o
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 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * simple ACPI events listener
+ *
+ * Copyright (C) 2008 by Vladimir Dronnikov <dronnikov@gmail.com>
+ *
+ * Licensed under GPLv2, see file LICENSE in this tarball for details.
+ */
+#include "libbb.h"
+
+#include <linux/input.h>
+#ifndef SW_RFKILL_ALL
+# define SW_RFKILL_ALL 3
+#endif
+
+/*
+ * acpid listens to ACPI events coming either in textual form
+ * from /proc/acpi/event (though it is marked deprecated,
+ * it is still widely used and _is_ a standard) or in binary form
+ * from specified evdevs (just use /dev/input/event*).
+ * It parses the event to retrieve ACTION and a possible PARAMETER.
+ * It then spawns /etc/acpi/<ACTION>[/<PARAMETER>] either via run-parts
+ * (if the resulting path is a directory) or directly.
+ * If the resulting path does not exist it logs it via perror
+ * and continues listening.
+ */
+
+static void process_event(const char *event)
+{
+ struct stat st;
+ char *handler = xasprintf("./%s", event);
+ const char *args[] = { "run-parts", handler, NULL };
+
+ // debug info
+ if (option_mask32 & 8) { // -d
+ bb_error_msg("%s", event);
+ }
+
+ // spawn handler
+ // N.B. run-parts would require scripts to have #!/bin/sh
+ // handler is directory? -> use run-parts
+ // handler is file? -> run it directly
+ if (0 == stat(event, &st))
+ spawn((char **)args + (0==(st.st_mode & S_IFDIR)));
+ else
+ bb_simple_perror_msg(event);
+ free(handler);
+}
+
+/*
+ * acpid [-c conf_dir] [-l log_file] [-e proc_event_file] [evdev_event_file...]
+*/
+
+int acpid_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int acpid_main(int argc, char **argv)
+{
+ struct pollfd *pfd;
+ int i, nfd;
+ const char *opt_conf = "/etc/acpi";
+ const char *opt_input = "/proc/acpi/event";
+ const char *opt_logfile = "/var/log/acpid.log";
+
+ getopt32(argv, "c:e:l:d"
+ USE_FEATURE_ACPID_COMPAT("g:m:s:S:v"),
+ &opt_conf, &opt_input, &opt_logfile
+ USE_FEATURE_ACPID_COMPAT(, NULL, NULL, NULL, NULL, NULL)
+ );
+
+ // daemonize unless -d given
+ if (!(option_mask32 & 8)) { // ! -d
+ bb_daemonize_or_rexec(0, argv);
+ close(2);
+ xopen(opt_logfile, O_WRONLY | O_CREAT | O_TRUNC);
+ }
+
+ argv += optind;
+
+ // goto configuration directory
+ xchdir(opt_conf);
+
+// // setup signals
+// bb_signals(BB_FATAL_SIGS, record_signo);
+
+ // no explicit evdev files given? -> use proc event interface
+ if (!*argv) {
+ // proc_event file is just a "config" :)
+ char *token[4];
+ parser_t *parser = config_open(opt_input);
+
+ // dispatch events
+ while (config_read(parser, token, 4, 4, "\0 ", PARSE_NORMAL)) {
+ char *event = xasprintf("%s/%s", token[1], token[2]);
+ process_event(event);
+ free(event);
+ }
+
+ if (ENABLE_FEATURE_CLEAN_UP)
+ config_close(parser);
+ return EXIT_SUCCESS;
+ }
+
+ // evdev files given, use evdev interface
+
+ // open event devices
+ pfd = xzalloc(sizeof(*pfd) * (argc - optind));
+ nfd = 0;
+ while (*argv) {
+ pfd[nfd].fd = open_or_warn(*argv++, O_RDONLY | O_NONBLOCK);
+ if (pfd[nfd].fd >= 0)
+ pfd[nfd++].events = POLLIN;
+ }
+
+ // dispatch events
+ while (/* !bb_got_signal && */ poll(pfd, nfd, -1) > 0) {
+ for (i = 0; i < nfd; i++) {
+ const char *event;
+ struct input_event ev;
+
+ if (!(pfd[i].revents & POLLIN))
+ continue;
+
+ if (sizeof(ev) != full_read(pfd[i].fd, &ev, sizeof(ev)))
+ continue;
+//bb_info_msg("%d: %d %d %4d", i, ev.type, ev.code, ev.value);
+
+ // filter out unneeded events
+ if (ev.value != 1)
+ continue;
+
+ event = NULL;
+
+ // N.B. we will conform to /proc/acpi/event
+ // naming convention when assigning event names
+
+ // TODO: do we want other events?
+
+ // power and sleep buttons delivered as keys pressed
+ if (EV_KEY == ev.type) {
+ if (KEY_POWER == ev.code)
+ event = "PWRF/00000080";
+ else if (KEY_SLEEP == ev.code)
+ event = "SLPB/00000080";
+ }
+ // switches
+ else if (EV_SW == ev.type) {
+ if (SW_LID == ev.code)
+ event = "LID/00000080";
+ else if (SW_RFKILL_ALL == ev.code)
+ event = "RFKILL";
+ }
+ // filter out unneeded events
+ if (!event)
+ continue;
+
+ // spawn event handler
+ process_event(event);
+ }
+ }
+
+ if (ENABLE_FEATURE_CLEAN_UP) {
+ for (i = 0; i < nfd; i++)
+ close(pfd[i].fd);
+ free(pfd);
+ }
+
+ return EXIT_SUCCESS;
+}