acpid.c 4.0 KB

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