diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2008-11-29 09:05:50 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2008-11-29 09:05:50 +0000 |
commit | d16950ded91446a23a6ceef35fb3e100400301d9 (patch) | |
tree | 038faff9ea801e5d7f022b75256fc52e66186b75 /util-linux | |
parent | f7d87f9b183aa28777ce09d40222fbe221d15c91 (diff) | |
download | busybox-d16950ded91446a23a6ceef35fb3e100400301d9.tar.gz |
acpid: new applet by Vladimir. +737 bytes
Diffstat (limited to 'util-linux')
-rw-r--r-- | util-linux/Config.in | 22 | ||||
-rw-r--r-- | util-linux/Kbuild | 1 | ||||
-rw-r--r-- | util-linux/acpid.c | 167 |
3 files changed, 190 insertions, 0 deletions
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; +} |