diff options
| -rw-r--r-- | docs/busybox.net/news.html | 4 | ||||
| -rw-r--r-- | include/applets.h | 1 | ||||
| -rw-r--r-- | include/usage.h | 17 | ||||
| -rw-r--r-- | util-linux/Config.in | 22 | ||||
| -rw-r--r-- | util-linux/Kbuild | 1 | ||||
| -rw-r--r-- | util-linux/acpid.c | 167 | 
6 files changed, 210 insertions, 2 deletions
diff --git a/docs/busybox.net/news.html b/docs/busybox.net/news.html index 3fccaae12..5c005fb0e 100644 --- a/docs/busybox.net/news.html +++ b/docs/busybox.net/news.html @@ -32,8 +32,8 @@      <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> -    <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 +    <p>Bug fix releases. 1.13.1 has fixes for ash, option parsing, id, init, +    inotifyd, klogd, line editing and modprobe. 1.12.3 has fixes      for option parsing and line editing.      </p>    </li> diff --git a/include/applets.h b/include/applets.h index fb904bb9f..ad3925577 100644 --- a/include/applets.h +++ b/include/applets.h @@ -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_ACPID(APPLET(acpid, _BB_DIR_SBIN, _BB_SUID_NEVER))  USE_ADDGROUP(APPLET(addgroup, _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)) diff --git a/include/usage.h b/include/usage.h index d35f8ae71..502fea7a0 100644 --- a/include/usage.h +++ b/include/usage.h @@ -16,6 +16,23 @@  #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 \         "[-g GID] " USE_FEATURE_ADDUSER_TO_GROUP("[user_name] ") "group_name" diff --git a/util-linux/Config.in b/util-linux/Config.in index 976507b68..3bba2e26d 100644 --- a/util-linux/Config.in +++ b/util-linux/Config.in @@ -5,6 +5,28 @@  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  	bool "blkid"  	default n diff --git a/util-linux/Kbuild b/util-linux/Kbuild index 2d0fc4928..842afb756 100644 --- a/util-linux/Kbuild +++ b/util-linux/Kbuild @@ -5,6 +5,7 @@  # Licensed under the GPL v2, see the file LICENSE in this tarball.  lib-y:= +lib-$(CONFIG_ACPID)             += acpid.o  lib-$(CONFIG_BLKID)             += blkid.o  lib-$(CONFIG_DMESG)             += dmesg.o  lib-$(CONFIG_FBSET)             += fbset.o diff --git a/util-linux/acpid.c b/util-linux/acpid.c new file mode 100644 index 000000000..ef4e54d5d --- /dev/null +++ b/util-linux/acpid.c @@ -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; +}  | 
