busybox/util-linux/acpid.c
<<
>>
Prefs
   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
  28static 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
  54int acpid_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
  55int 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                USE_FEATURE_ACPID_COMPAT("g:m:s:S:v"),
  65                &opt_conf, &opt_input, &opt_logfile
  66                USE_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
  78        // goto configuration directory
  79        xchdir(opt_conf);
  80
  81//      // setup signals
  82//      bb_signals(BB_FATAL_SIGS, record_signo);
  83
  84        // no explicit evdev files given? -> use proc event interface
  85        if (!*argv) {
  86                // proc_event file is just a "config" :)
  87                char *token[4];
  88                parser_t *parser = config_open(opt_input);
  89
  90                // dispatch events
  91                while (config_read(parser, token, 4, 4, "\0 ", PARSE_NORMAL)) {
  92                        char *event = xasprintf("%s/%s", token[1], token[2]);
  93                        process_event(event);
  94                        free(event);
  95                }
  96
  97                if (ENABLE_FEATURE_CLEAN_UP)
  98                        config_close(parser);
  99                return EXIT_SUCCESS;
 100        }
 101
 102        // evdev files given, use evdev interface
 103
 104        // open event devices
 105        pfd = xzalloc(sizeof(*pfd) * (argc - optind));
 106        nfd = 0;
 107        while (*argv) {
 108                pfd[nfd].fd = open_or_warn(*argv++, O_RDONLY | O_NONBLOCK);
 109                if (pfd[nfd].fd >= 0)
 110                        pfd[nfd++].events = POLLIN;
 111        }
 112
 113        // dispatch events
 114        while (/* !bb_got_signal && */ poll(pfd, nfd, -1) > 0) {
 115                for (i = 0; i < nfd; i++) {
 116                        const char *event;
 117                        struct input_event ev;
 118
 119                        if (!(pfd[i].revents & POLLIN))
 120                                continue;
 121
 122                        if (sizeof(ev) != full_read(pfd[i].fd, &ev, sizeof(ev)))
 123                                continue;
 124//bb_info_msg("%d: %d %d %4d", i, ev.type, ev.code, ev.value);
 125
 126                        // filter out unneeded events
 127                        if (ev.value != 1)
 128                                continue;
 129
 130                        event = NULL;
 131
 132                        // N.B. we will conform to /proc/acpi/event
 133                        // naming convention when assigning event names
 134
 135                        // TODO: do we want other events?
 136
 137                        // power and sleep buttons delivered as keys pressed
 138                        if (EV_KEY == ev.type) {
 139                                if (KEY_POWER == ev.code)
 140                                        event = "PWRF/00000080";
 141                                else if (KEY_SLEEP == ev.code)
 142                                        event = "SLPB/00000080";
 143                        }
 144                        // switches
 145                        else if (EV_SW == ev.type) {
 146                                if (SW_LID == ev.code)
 147                                        event = "LID/00000080";
 148                                else if (SW_RFKILL_ALL == ev.code)
 149                                        event = "RFKILL";
 150                        }
 151                        // filter out unneeded events
 152                        if (!event)
 153                                continue;
 154
 155                        // spawn event handler
 156                        process_event(event);
 157                }
 158        }
 159
 160        if (ENABLE_FEATURE_CLEAN_UP) {
 161                for (i = 0; i < nfd; i++)
 162                        close(pfd[i].fd);
 163                free(pfd);
 164        }
 165
 166        return EXIT_SUCCESS;
 167}
 168