123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168 |
- /* 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"
- IF_FEATURE_ACPID_COMPAT("g:m:s:S:v"),
- &opt_conf, &opt_input, &opt_logfile
- IF_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;
- argc -= optind;
- // goto configuration directory
- xchdir(opt_conf);
- // prevent zombies
- signal(SIGCHLD, SIG_IGN);
- // 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);
- 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;
- }
|