Blame acpi_listen.c

Packit a94d48
/*
Packit a94d48
 *  acpi_listen.c - ACPI client for acpid's UNIX socket
Packit a94d48
 *
Packit a94d48
 *  Portions Copyright (C) 2003 Sun Microsystems (thockin@sun.com)
Packit a94d48
 *  Some parts (C) 2003 - Gismo / Luca Capello <luca.pca.it> http://luca.pca.it
Packit a94d48
 *  Copyright (C) 2004 Tim Hockin (thockin@hockin.org)
Packit a94d48
 *
Packit a94d48
 *  This program is free software; you can redistribute it and/or modify
Packit a94d48
 *  it under the terms of the GNU General Public License as published by
Packit a94d48
 *  the Free Software Foundation; either version 2 of the License, or
Packit a94d48
 *  (at your option) any later version.
Packit a94d48
 *
Packit a94d48
 *  This program is distributed in the hope that it will be useful,
Packit a94d48
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit a94d48
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit a94d48
 *  GNU General Public License for more details.
Packit a94d48
 *
Packit a94d48
 *  You should have received a copy of the GNU General Public License
Packit a94d48
 *  along with this program; if not, write to the Free Software
Packit a94d48
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
Packit a94d48
 */
Packit a94d48
Packit a94d48
#include <sys/types.h>
Packit a94d48
#include <sys/stat.h>
Packit a94d48
#include <fcntl.h>
Packit a94d48
#include <signal.h>
Packit a94d48
#include <unistd.h>
Packit a94d48
#include <stdio.h>
Packit a94d48
#include <stdlib.h>
Packit a94d48
#include <string.h>
Packit a94d48
#include <errno.h>
Packit a94d48
#include <ctype.h>
Packit a94d48
#include <getopt.h>
Packit a94d48
#include <time.h>
Packit a94d48
#include <poll.h>
Packit a94d48
#include <grp.h>
Packit a94d48
#include <signal.h>
Packit a94d48
Packit a94d48
#include "acpid.h"
Packit a94d48
#include "ud_socket.h"
Packit a94d48
Packit a94d48
#include "libc_compat.h"
Packit a94d48
Packit a94d48
static int handle_cmdline(int *argc, char ***argv);
Packit a94d48
static char *read_line(int fd);
Packit a94d48
Packit a94d48
const char *progname;
Packit a94d48
const char *socketfile = ACPID_SOCKETFILE;
Packit a94d48
static int max_events;
Packit a94d48
Packit a94d48
static void
Packit a94d48
time_expired(int signum __attribute__((unused)))
Packit a94d48
{
Packit a94d48
	exit(EXIT_SUCCESS);
Packit a94d48
}
Packit a94d48
Packit a94d48
int
Packit a94d48
main(int argc, char **argv)
Packit a94d48
{
Packit a94d48
	int sock_fd;
Packit a94d48
	int ret;
Packit a94d48
Packit a94d48
	/* handle an alarm */
Packit a94d48
	signal(SIGALRM, time_expired);
Packit a94d48
Packit a94d48
	/* learn who we really are */
Packit a94d48
	progname = (const char *)strrchr(argv[0], '/');
Packit a94d48
	progname = progname ? (progname + 1) : argv[0];
Packit a94d48
Packit a94d48
	/* handle the commandline  */
Packit a94d48
	handle_cmdline(&argc, &argv);
Packit a94d48
Packit a94d48
	/* open the socket */
Packit a94d48
	sock_fd = ud_connect(socketfile);
Packit a94d48
	if (sock_fd < 0) {
Packit a94d48
		fprintf(stderr, "%s: can't open socket %s: %s\n",
Packit a94d48
			progname, socketfile, strerror(errno));
Packit a94d48
		exit(EXIT_FAILURE);
Packit a94d48
	}
Packit a94d48
	/* set stdout to be line buffered */
Packit a94d48
	setvbuf(stdout, NULL, _IOLBF, 0);
Packit a94d48
Packit a94d48
	/* main loop */
Packit a94d48
	ret = 0;
Packit a94d48
	while (1) {
Packit a94d48
		char *event;
Packit a94d48
Packit a94d48
		/* read and handle an event */
Packit a94d48
		event = read_line(sock_fd);
Packit a94d48
		if (event) {
Packit a94d48
			fprintf(stdout, "%s\n", event);
Packit a94d48
		} else if (errno == EPIPE) {
Packit a94d48
			fprintf(stderr, "connection closed\n");
Packit a94d48
			break;
Packit a94d48
		} else {
Packit a94d48
			static int nerrs;
Packit a94d48
			if (++nerrs >= ACPID_MAX_ERRS) {
Packit a94d48
				fprintf(stderr, "too many errors - aborting\n");
Packit a94d48
				ret = 1;
Packit a94d48
				break;
Packit a94d48
			}
Packit a94d48
		}
Packit a94d48
Packit a94d48
		if (max_events > 0 && --max_events == 0) {
Packit a94d48
			break;
Packit a94d48
		}
Packit a94d48
	}
Packit a94d48
Packit a94d48
	return ret;
Packit a94d48
}
Packit a94d48
Packit a94d48
static struct option opts[] = {
Packit a94d48
	{"count", 0, 0, 'c'},
Packit a94d48
	{"socketfile", 1, 0, 's'},
Packit a94d48
	{"time", 0, 0, 't'},
Packit a94d48
	{"version", 0, 0, 'v'},
Packit a94d48
	{"help", 0, 0, 'h'},
Packit a94d48
	{NULL, 0, 0, 0},
Packit a94d48
};
Packit a94d48
static const char *opts_help[] = {
Packit a94d48
	"Set the maximum number of events.",	/* count */
Packit a94d48
	"Use the specified socket file.",	/* socketfile */
Packit a94d48
	"Listen for the specified time (in seconds).",/* time */
Packit a94d48
	"Print version information.",		/* version */
Packit a94d48
	"Print this message.",			/* help */
Packit a94d48
};
Packit a94d48
Packit a94d48
static void
Packit a94d48
usage(FILE *fp)
Packit a94d48
{
Packit a94d48
	struct option *opt;
Packit a94d48
	const char **hlp;
Packit a94d48
	int max, size;
Packit a94d48
Packit a94d48
	fprintf(fp, "Usage: %s [OPTIONS]\n", progname);
Packit a94d48
	max = 0;
Packit a94d48
	for (opt = opts; opt->name; opt++) {
Packit a94d48
		size = strlen(opt->name);
Packit a94d48
		if (size > max)
Packit a94d48
			max = size;
Packit a94d48
	}
Packit a94d48
	for (opt = opts, hlp = opts_help; opt->name; opt++, hlp++) {
Packit a94d48
		fprintf(fp, "  -%c, --%s", opt->val, opt->name);
Packit a94d48
		size = strlen(opt->name);
Packit a94d48
		for (; size < max; size++)
Packit a94d48
			fprintf(fp, " ");
Packit a94d48
		fprintf(fp, "  %s\n", *hlp);
Packit a94d48
	}
Packit a94d48
}
Packit a94d48
Packit a94d48
/*
Packit a94d48
 * Parse command line arguments
Packit a94d48
 */
Packit a94d48
static int
Packit a94d48
handle_cmdline(int *argc, char ***argv)
Packit a94d48
{
Packit a94d48
	for (;;) {
Packit a94d48
		int i;
Packit a94d48
		i = getopt_long(*argc, *argv, "c:s:t:vh", opts, NULL);
Packit a94d48
		if (i == -1) {
Packit a94d48
			break;
Packit a94d48
		}
Packit a94d48
		switch (i) {
Packit a94d48
		case 'c':
Packit a94d48
			if (!isdigit(optarg[0])) {
Packit a94d48
				usage(stderr);
Packit a94d48
				exit(EXIT_FAILURE);
Packit a94d48
			}
Packit a94d48
			max_events = atoi(optarg);
Packit a94d48
			break;
Packit a94d48
		case 's':
Packit a94d48
			socketfile = optarg;
Packit a94d48
			break;
Packit a94d48
		case 't':
Packit a94d48
			if (!isdigit(optarg[0])) {
Packit a94d48
				usage(stderr);
Packit a94d48
				exit(EXIT_FAILURE);
Packit a94d48
			}
Packit a94d48
			alarm(atoi(optarg));
Packit a94d48
			break;
Packit a94d48
		case 'v':
Packit a94d48
			printf(PACKAGE "-" VERSION "\n");
Packit a94d48
			exit(EXIT_SUCCESS);
Packit a94d48
		case 'h':
Packit a94d48
			usage(stdout);
Packit a94d48
			exit(EXIT_SUCCESS);
Packit a94d48
		default:
Packit a94d48
			usage(stderr);
Packit a94d48
			exit(EXIT_FAILURE);
Packit a94d48
			break;
Packit a94d48
		}
Packit a94d48
	}
Packit a94d48
Packit a94d48
	*argc -= optind;
Packit a94d48
	*argv += optind;
Packit a94d48
Packit a94d48
	return 0;
Packit a94d48
}
Packit a94d48
Packit a94d48
#define MAX_BUFLEN	1024
Packit a94d48
static char *
Packit a94d48
read_line(int fd)
Packit a94d48
{
Packit a94d48
	static char *buf;
Packit a94d48
	int buflen = 64;
Packit a94d48
	int i = 0;
Packit a94d48
	int r;
Packit a94d48
	int searching = 1;
Packit a94d48
Packit a94d48
	while (searching) {
Packit a94d48
		buf = realloc(buf, buflen);
Packit a94d48
		if (!buf) {
Packit a94d48
			fprintf(stderr, "ERR: malloc(%d): %s\n",
Packit a94d48
				buflen, strerror(errno));
Packit a94d48
			return NULL;
Packit a94d48
		}
Packit a94d48
		memset(buf+i, 0, buflen-i);
Packit a94d48
Packit a94d48
		while (i < buflen) {
Packit a94d48
			r = TEMP_FAILURE_RETRY (read(fd, buf+i, 1) );
Packit a94d48
			if (r < 0) {
Packit a94d48
				/* we should do something with the data */
Packit a94d48
				fprintf(stderr, "ERR: read(): %s\n",
Packit a94d48
					strerror(errno));
Packit a94d48
				return NULL;
Packit a94d48
			} else if (r == 0) {
Packit a94d48
				/* signal this in an almost standard way */
Packit a94d48
				errno = EPIPE;
Packit a94d48
				return NULL;
Packit a94d48
			} else if (r == 1) {
Packit a94d48
				/* scan for a newline */
Packit a94d48
				if (buf[i] == '\n') {
Packit a94d48
					searching = 0;
Packit a94d48
					buf[i] = '\0';
Packit a94d48
					break;
Packit a94d48
				}
Packit a94d48
				i++;
Packit a94d48
			}
Packit a94d48
		}
Packit a94d48
		if (buflen >= MAX_BUFLEN) {
Packit a94d48
			break;
Packit a94d48
		}
Packit a94d48
		buflen *= 2;
Packit a94d48
	}
Packit a94d48
Packit a94d48
	return buf;
Packit a94d48
}