mount: handle EDQUOT > 255 properly. closes bug 1579
[oweals/busybox.git] / util-linux / acpid.c
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                 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)
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         argc -= optind;
78
79         // goto configuration directory
80         xchdir(opt_conf);
81
82         // prevent zombies
83         signal(SIGCHLD, SIG_IGN);
84
85         // no explicit evdev files given? -> use proc event interface
86         if (!*argv) {
87                 // proc_event file is just a "config" :)
88                 char *token[4];
89                 parser_t *parser = config_open(opt_input);
90
91                 // dispatch events
92                 while (config_read(parser, token, 4, 4, "\0 ", PARSE_NORMAL)) {
93                         char *event = xasprintf("%s/%s", token[1], token[2]);
94                         process_event(event);
95                         free(event);
96                 }
97
98                 if (ENABLE_FEATURE_CLEAN_UP)
99                         config_close(parser);
100                 return EXIT_SUCCESS;
101         }
102
103         // evdev files given, use evdev interface
104
105         // open event devices
106         pfd = xzalloc(sizeof(*pfd) * argc);
107         nfd = 0;
108         while (*argv) {
109                 pfd[nfd].fd = open_or_warn(*argv++, O_RDONLY | O_NONBLOCK);
110                 if (pfd[nfd].fd >= 0)
111                         pfd[nfd++].events = POLLIN;
112         }
113
114         // dispatch events
115         while (/* !bb_got_signal && */ poll(pfd, nfd, -1) > 0) {
116                 for (i = 0; i < nfd; i++) {
117                         const char *event;
118                         struct input_event ev;
119
120                         if (!(pfd[i].revents & POLLIN))
121                                 continue;
122
123                         if (sizeof(ev) != full_read(pfd[i].fd, &ev, sizeof(ev)))
124                                 continue;
125 //bb_info_msg("%d: %d %d %4d", i, ev.type, ev.code, ev.value);
126
127                         // filter out unneeded events
128                         if (ev.value != 1)
129                                 continue;
130
131                         event = NULL;
132
133                         // N.B. we will conform to /proc/acpi/event
134                         // naming convention when assigning event names
135
136                         // TODO: do we want other events?
137
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";
144                         }
145                         // switches
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)
150                                         event = "RFKILL";
151                         }
152                         // filter out unneeded events
153                         if (!event)
154                                 continue;
155
156                         // spawn event handler
157                         process_event(event);
158                 }
159         }
160
161         if (ENABLE_FEATURE_CLEAN_UP) {
162                 for (i = 0; i < nfd; i++)
163                         close(pfd[i].fd);
164                 free(pfd);
165         }
166
167         return EXIT_SUCCESS;
168 }