Magellan Linux

Annotation of /trunk/mkinitrd-magellan/busybox/util-linux/acpid.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1123 - (hide annotations) (download)
Wed Aug 18 21:56:57 2010 UTC (13 years, 9 months ago) by niro
File MIME type: text/plain
File size: 4430 byte(s)
-updated to busybox-1.17.1
1 niro 984 /* 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 niro 1123 #ifndef EV_SW
13     # define EV_SW 0x05
14     #endif
15     #ifndef EV_KEY
16     # define EV_KEY 0x01
17     #endif
18     #ifndef SW_LID
19     # define SW_LID 0x00
20     #endif
21 niro 984 #ifndef SW_RFKILL_ALL
22 niro 1123 # define SW_RFKILL_ALL 0x03
23 niro 984 #endif
24 niro 1123 #ifndef KEY_POWER
25     # define KEY_POWER 116 /* SC System Power Down */
26     #endif
27     #ifndef KEY_SLEEP
28     # define KEY_SLEEP 142 /* SC System Sleep */
29     #endif
30 niro 984
31 niro 1123
32 niro 984 /*
33     * acpid listens to ACPI events coming either in textual form
34     * from /proc/acpi/event (though it is marked deprecated,
35     * it is still widely used and _is_ a standard) or in binary form
36     * from specified evdevs (just use /dev/input/event*).
37     * It parses the event to retrieve ACTION and a possible PARAMETER.
38     * It then spawns /etc/acpi/<ACTION>[/<PARAMETER>] either via run-parts
39     * (if the resulting path is a directory) or directly.
40     * If the resulting path does not exist it logs it via perror
41     * and continues listening.
42     */
43    
44     static void process_event(const char *event)
45     {
46     struct stat st;
47     char *handler = xasprintf("./%s", event);
48     const char *args[] = { "run-parts", handler, NULL };
49    
50     // debug info
51     if (option_mask32 & 8) { // -d
52     bb_error_msg("%s", event);
53     }
54    
55     // spawn handler
56     // N.B. run-parts would require scripts to have #!/bin/sh
57     // handler is directory? -> use run-parts
58     // handler is file? -> run it directly
59     if (0 == stat(event, &st))
60     spawn((char **)args + (0==(st.st_mode & S_IFDIR)));
61     else
62     bb_simple_perror_msg(event);
63     free(handler);
64     }
65    
66     /*
67     * acpid [-c conf_dir] [-l log_file] [-e proc_event_file] [evdev_event_file...]
68     */
69    
70     int acpid_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
71     int acpid_main(int argc, char **argv)
72     {
73     struct pollfd *pfd;
74     int i, nfd;
75     const char *opt_conf = "/etc/acpi";
76     const char *opt_input = "/proc/acpi/event";
77     const char *opt_logfile = "/var/log/acpid.log";
78    
79     getopt32(argv, "c:e:l:d"
80     IF_FEATURE_ACPID_COMPAT("g:m:s:S:v"),
81     &opt_conf, &opt_input, &opt_logfile
82     IF_FEATURE_ACPID_COMPAT(, NULL, NULL, NULL, NULL, NULL)
83     );
84    
85     // daemonize unless -d given
86     if (!(option_mask32 & 8)) { // ! -d
87     bb_daemonize_or_rexec(0, argv);
88     close(2);
89     xopen(opt_logfile, O_WRONLY | O_CREAT | O_TRUNC);
90     }
91    
92     argv += optind;
93     argc -= optind;
94    
95     // goto configuration directory
96     xchdir(opt_conf);
97    
98     // prevent zombies
99     signal(SIGCHLD, SIG_IGN);
100    
101     // no explicit evdev files given? -> use proc event interface
102     if (!*argv) {
103     // proc_event file is just a "config" :)
104     char *token[4];
105     parser_t *parser = config_open(opt_input);
106    
107     // dispatch events
108     while (config_read(parser, token, 4, 4, "\0 ", PARSE_NORMAL)) {
109     char *event = xasprintf("%s/%s", token[1], token[2]);
110     process_event(event);
111     free(event);
112     }
113    
114     if (ENABLE_FEATURE_CLEAN_UP)
115     config_close(parser);
116     return EXIT_SUCCESS;
117     }
118    
119     // evdev files given, use evdev interface
120    
121     // open event devices
122     pfd = xzalloc(sizeof(*pfd) * argc);
123     nfd = 0;
124     while (*argv) {
125     pfd[nfd].fd = open_or_warn(*argv++, O_RDONLY | O_NONBLOCK);
126     if (pfd[nfd].fd >= 0)
127     pfd[nfd++].events = POLLIN;
128     }
129    
130     // dispatch events
131     while (/* !bb_got_signal && */ poll(pfd, nfd, -1) > 0) {
132     for (i = 0; i < nfd; i++) {
133     const char *event;
134     struct input_event ev;
135    
136     if (!(pfd[i].revents & POLLIN))
137     continue;
138    
139     if (sizeof(ev) != full_read(pfd[i].fd, &ev, sizeof(ev)))
140     continue;
141     //bb_info_msg("%d: %d %d %4d", i, ev.type, ev.code, ev.value);
142    
143     // filter out unneeded events
144     if (ev.value != 1)
145     continue;
146    
147     event = NULL;
148    
149     // N.B. we will conform to /proc/acpi/event
150     // naming convention when assigning event names
151    
152     // TODO: do we want other events?
153    
154     // power and sleep buttons delivered as keys pressed
155     if (EV_KEY == ev.type) {
156     if (KEY_POWER == ev.code)
157     event = "PWRF/00000080";
158     else if (KEY_SLEEP == ev.code)
159     event = "SLPB/00000080";
160     }
161     // switches
162     else if (EV_SW == ev.type) {
163     if (SW_LID == ev.code)
164     event = "LID/00000080";
165     else if (SW_RFKILL_ALL == ev.code)
166     event = "RFKILL";
167     }
168     // filter out unneeded events
169     if (!event)
170     continue;
171    
172     // spawn event handler
173     process_event(event);
174     }
175     }
176    
177     if (ENABLE_FEATURE_CLEAN_UP) {
178     for (i = 0; i < nfd; i++)
179     close(pfd[i].fd);
180     free(pfd);
181     }
182    
183     return EXIT_SUCCESS;
184     }