acpid: new applet by Vladimir. +737 bytes

This commit is contained in:
Denis Vlasenko 2008-11-29 09:05:50 +00:00
parent f7d87f9b18
commit d16950ded9
6 changed files with 210 additions and 2 deletions

View File

@ -32,8 +32,8 @@
<a href="http://busybox.net/downloads/fixes-1.12.3/">patches</a>, <a href="http://busybox.net/downloads/fixes-1.12.3/">patches</a>,
<a href="http://busybox.net/fix.html">how to add a patch</a>)</p> <a href="http://busybox.net/fix.html">how to add a patch</a>)</p>
<p>Bug-fix releases. 1.13.1 has fixes for ash, option parsing, id, init, <p>Bug fix releases. 1.13.1 has fixes for ash, option parsing, id, init,
inotify, klogd, line editing and modprobe. 1.12.3 has fixes inotifyd, klogd, line editing and modprobe. 1.12.3 has fixes
for option parsing and line editing. for option parsing and line editing.
</p> </p>
</li> </li>

View File

@ -69,6 +69,7 @@ s - suid type:
USE_TEST(APPLET_NOFORK([, test, _BB_DIR_USR_BIN, _BB_SUID_NEVER, test)) USE_TEST(APPLET_NOFORK([, test, _BB_DIR_USR_BIN, _BB_SUID_NEVER, test))
USE_TEST(APPLET_NOFORK([[, test, _BB_DIR_USR_BIN, _BB_SUID_NEVER, test)) USE_TEST(APPLET_NOFORK([[, test, _BB_DIR_USR_BIN, _BB_SUID_NEVER, test))
USE_ACPID(APPLET(acpid, _BB_DIR_SBIN, _BB_SUID_NEVER))
USE_ADDGROUP(APPLET(addgroup, _BB_DIR_BIN, _BB_SUID_NEVER)) USE_ADDGROUP(APPLET(addgroup, _BB_DIR_BIN, _BB_SUID_NEVER))
USE_ADDUSER(APPLET(adduser, _BB_DIR_BIN, _BB_SUID_NEVER)) USE_ADDUSER(APPLET(adduser, _BB_DIR_BIN, _BB_SUID_NEVER))
USE_ADJTIMEX(APPLET(adjtimex, _BB_DIR_SBIN, _BB_SUID_NEVER)) USE_ADJTIMEX(APPLET(adjtimex, _BB_DIR_SBIN, _BB_SUID_NEVER))

View File

@ -16,6 +16,23 @@
#define NOUSAGE_STR "\b" #define NOUSAGE_STR "\b"
#define acpid_trivial_usage \
"[-d] [-c CONFDIR] [-l LOGFILE] [-e PROC_EVENT_FILE] [EVDEV_EVENT_FILE...]"
#define acpid_full_usage "\n\n" \
"Listen to ACPI events and spawn specific helpers on event arrival\n" \
"\nOptions:" \
"\n -d Do not daemonize and log to stderr" \
"\n -c DIR Config directory [/etc/acpi]" \
"\n -e FILE /proc event file [/proc/acpi/event]" \
"\n -l FILE Log file [/var/log/acpid]" \
USE_FEATURE_ACPID_COMPAT( \
"\n\nAccept and ignore compatibility options -g -m -s -S -v" \
)
#define acpid_example_usage \
"# acpid -l /var/log/my-acpi-log\n" \
"# acpid -d /dev/input/event*\n"
#define addgroup_trivial_usage \ #define addgroup_trivial_usage \
"[-g GID] " USE_FEATURE_ADDUSER_TO_GROUP("[user_name] ") "group_name" "[-g GID] " USE_FEATURE_ADDUSER_TO_GROUP("[user_name] ") "group_name"

View File

@ -5,6 +5,28 @@
menu "Linux System Utilities" menu "Linux System Utilities"
config ACPID
bool "acpid"
default n
help
acpid listens to ACPI events coming either in textual form from
/proc/acpi/event (though it is marked deprecated it is still widely
used and _is_ a standard) or in binary form from specified evdevs
(just use /dev/input/event*).
It parses the event to retrieve ACTION and a possible PARAMETER.
It then spawns /etc/acpi/<ACTION>[/<PARAMETER>] either via run-parts
(if the resulting path is a directory) or directly as an executable.
N.B. acpid relies on run-parts so have the latter installed.
config FEATURE_ACPID_COMPAT
bool "Accept and ignore redundant options"
default n
depends on ACPID
help
Accept and ignore compatibility options -g -m -s -S -v.
config BLKID config BLKID
bool "blkid" bool "blkid"
default n default n

View File

@ -5,6 +5,7 @@
# Licensed under the GPL v2, see the file LICENSE in this tarball. # Licensed under the GPL v2, see the file LICENSE in this tarball.
lib-y:= lib-y:=
lib-$(CONFIG_ACPID) += acpid.o
lib-$(CONFIG_BLKID) += blkid.o lib-$(CONFIG_BLKID) += blkid.o
lib-$(CONFIG_DMESG) += dmesg.o lib-$(CONFIG_DMESG) += dmesg.o
lib-$(CONFIG_FBSET) += fbset.o lib-$(CONFIG_FBSET) += fbset.o

167
util-linux/acpid.c Normal file
View File

@ -0,0 +1,167 @@
/* vi: set sw=4 ts=4: */
/*
* simple ACPI events listener
*
* Copyright (C) 2008 by Vladimir Dronnikov <dronnikov@gmail.com>
*
* Licensed under GPLv2, see file LICENSE in this tarball for details.
*/
#include "libbb.h"
#include <linux/input.h>
#ifndef SW_RFKILL_ALL
# define SW_RFKILL_ALL 3
#endif
/*
* acpid listens to ACPI events coming either in textual form
* from /proc/acpi/event (though it is marked deprecated,
* it is still widely used and _is_ a standard) or in binary form
* from specified evdevs (just use /dev/input/event*).
* It parses the event to retrieve ACTION and a possible PARAMETER.
* It then spawns /etc/acpi/<ACTION>[/<PARAMETER>] either via run-parts
* (if the resulting path is a directory) or directly.
* If the resulting path does not exist it logs it via perror
* and continues listening.
*/
static void process_event(const char *event)
{
struct stat st;
char *handler = xasprintf("./%s", event);
const char *args[] = { "run-parts", handler, NULL };
// debug info
if (option_mask32 & 8) { // -d
bb_error_msg("%s", event);
}
// spawn handler
// N.B. run-parts would require scripts to have #!/bin/sh
// handler is directory? -> use run-parts
// handler is file? -> run it directly
if (0 == stat(event, &st))
spawn((char **)args + (0==(st.st_mode & S_IFDIR)));
else
bb_simple_perror_msg(event);
free(handler);
}
/*
* acpid [-c conf_dir] [-l log_file] [-e proc_event_file] [evdev_event_file...]
*/
int acpid_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
int acpid_main(int argc, char **argv)
{
struct pollfd *pfd;
int i, nfd;
const char *opt_conf = "/etc/acpi";
const char *opt_input = "/proc/acpi/event";
const char *opt_logfile = "/var/log/acpid.log";
getopt32(argv, "c:e:l:d"
USE_FEATURE_ACPID_COMPAT("g:m:s:S:v"),
&opt_conf, &opt_input, &opt_logfile
USE_FEATURE_ACPID_COMPAT(, NULL, NULL, NULL, NULL, NULL)
);
// daemonize unless -d given
if (!(option_mask32 & 8)) { // ! -d
bb_daemonize_or_rexec(0, argv);
close(2);
xopen(opt_logfile, O_WRONLY | O_CREAT | O_TRUNC);
}
argv += optind;
// goto configuration directory
xchdir(opt_conf);
// // setup signals
// bb_signals(BB_FATAL_SIGS, record_signo);
// no explicit evdev files given? -> use proc event interface
if (!*argv) {
// proc_event file is just a "config" :)
char *token[4];
parser_t *parser = config_open(opt_input);
// dispatch events
while (config_read(parser, token, 4, 4, "\0 ", PARSE_NORMAL)) {
char *event = xasprintf("%s/%s", token[1], token[2]);
process_event(event);
free(event);
}
if (ENABLE_FEATURE_CLEAN_UP)
config_close(parser);
return EXIT_SUCCESS;
}
// evdev files given, use evdev interface
// open event devices
pfd = xzalloc(sizeof(*pfd) * (argc - optind));
nfd = 0;
while (*argv) {
pfd[nfd].fd = open_or_warn(*argv++, O_RDONLY | O_NONBLOCK);
if (pfd[nfd].fd >= 0)
pfd[nfd++].events = POLLIN;
}
// dispatch events
while (/* !bb_got_signal && */ poll(pfd, nfd, -1) > 0) {
for (i = 0; i < nfd; i++) {
const char *event;
struct input_event ev;
if (!(pfd[i].revents & POLLIN))
continue;
if (sizeof(ev) != full_read(pfd[i].fd, &ev, sizeof(ev)))
continue;
//bb_info_msg("%d: %d %d %4d", i, ev.type, ev.code, ev.value);
// filter out unneeded events
if (ev.value != 1)
continue;
event = NULL;
// N.B. we will conform to /proc/acpi/event
// naming convention when assigning event names
// TODO: do we want other events?
// power and sleep buttons delivered as keys pressed
if (EV_KEY == ev.type) {
if (KEY_POWER == ev.code)
event = "PWRF/00000080";
else if (KEY_SLEEP == ev.code)
event = "SLPB/00000080";
}
// switches
else if (EV_SW == ev.type) {
if (SW_LID == ev.code)
event = "LID/00000080";
else if (SW_RFKILL_ALL == ev.code)
event = "RFKILL";
}
// filter out unneeded events
if (!event)
continue;
// spawn event handler
process_event(event);
}
}
if (ENABLE_FEATURE_CLEAN_UP) {
for (i = 0; i < nfd; i++)
close(pfd[i].fd);
free(pfd);
}
return EXIT_SUCCESS;
}