1 /* vi: set sw=4 ts=4: */
3 * simple ACPI events listener
5 * Copyright (C) 2008 by Vladimir Dronnikov <dronnikov@gmail.com>
7 * Licensed under GPLv2, see file LICENSE in this tarball for details.
11 #include <linux/input.h>
13 # define SW_RFKILL_ALL 3
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.
28 static void process_event(const char *event)
31 char *handler = xasprintf("./%s", event);
32 const char *args[] = { "run-parts", handler, NULL };
35 if (option_mask32 & 8) { // -d
36 bb_error_msg("%s", event);
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)));
46 bb_simple_perror_msg(event);
51 * acpid [-c conf_dir] [-l log_file] [-e proc_event_file] [evdev_event_file...]
54 int acpid_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
55 int acpid_main(int argc, char **argv)
59 const char *opt_conf = "/etc/acpi";
60 const char *opt_input = "/proc/acpi/event";
61 const char *opt_logfile = "/var/log/acpid.log";
63 getopt32(argv, "c:e:l:d"
64 IF_FEATURE_ACPID_COMPAT("g:m:s:S:v"),
65 &opt_conf, &opt_input, &opt_logfile
66 IF_FEATURE_ACPID_COMPAT(, NULL, NULL, NULL, NULL, NULL)
69 // daemonize unless -d given
70 if (!(option_mask32 & 8)) { // ! -d
71 bb_daemonize_or_rexec(0, argv);
73 xopen(opt_logfile, O_WRONLY | O_CREAT | O_TRUNC);
79 // goto configuration directory
83 signal(SIGCHLD, SIG_IGN);
85 // no explicit evdev files given? -> use proc event interface
87 // proc_event file is just a "config" :)
89 parser_t *parser = config_open(opt_input);
92 while (config_read(parser, token, 4, 4, "\0 ", PARSE_NORMAL)) {
93 char *event = xasprintf("%s/%s", token[1], token[2]);
98 if (ENABLE_FEATURE_CLEAN_UP)
103 // evdev files given, use evdev interface
105 // open event devices
106 pfd = xzalloc(sizeof(*pfd) * argc);
109 pfd[nfd].fd = open_or_warn(*argv++, O_RDONLY | O_NONBLOCK);
110 if (pfd[nfd].fd >= 0)
111 pfd[nfd++].events = POLLIN;
115 while (/* !bb_got_signal && */ poll(pfd, nfd, -1) > 0) {
116 for (i = 0; i < nfd; i++) {
118 struct input_event ev;
120 if (!(pfd[i].revents & POLLIN))
123 if (sizeof(ev) != full_read(pfd[i].fd, &ev, sizeof(ev)))
125 //bb_info_msg("%d: %d %d %4d", i, ev.type, ev.code, ev.value);
127 // filter out unneeded events
133 // N.B. we will conform to /proc/acpi/event
134 // naming convention when assigning event names
136 // TODO: do we want other events?
138 // power and sleep buttons delivered as keys pressed
139 if (EV_KEY == ev.type) {
140 if (KEY_POWER == ev.code)
141 event = "PWRF/00000080";
142 else if (KEY_SLEEP == ev.code)
143 event = "SLPB/00000080";
146 else if (EV_SW == ev.type) {
147 if (SW_LID == ev.code)
148 event = "LID/00000080";
149 else if (SW_RFKILL_ALL == ev.code)
152 // filter out unneeded events
156 // spawn event handler
157 process_event(event);
161 if (ENABLE_FEATURE_CLEAN_UP) {
162 for (i = 0; i < nfd; i++)