and SKIP_XXXX to IF_NOT_XXXX - the second one was especially badly named. It was not skipping anything!
		
			
				
	
	
		
			168 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			168 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/* 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"
 | 
						|
		IF_FEATURE_ACPID_COMPAT("g:m:s:S:v"),
 | 
						|
		&opt_conf, &opt_input, &opt_logfile
 | 
						|
		IF_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);
 | 
						|
 | 
						|
	// prevent zombies
 | 
						|
	signal(SIGCHLD, SIG_IGN);
 | 
						|
 | 
						|
	// 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;
 | 
						|
}
 |