xref: /freebsd/usr.sbin/apmd/apmd.c (revision 1de7b4b805ddbf2429da511c053686ac4591ed89)
1d50a71bdSMitsuru IWASAKI /*-
2*1de7b4b8SPedro F. Giffuni  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3*1de7b4b8SPedro F. Giffuni  *
4d50a71bdSMitsuru IWASAKI  * APM (Advanced Power Management) Event Dispatcher
5d50a71bdSMitsuru IWASAKI  *
6d50a71bdSMitsuru IWASAKI  * Copyright (c) 1999 Mitsuru IWASAKI <iwasaki@FreeBSD.org>
7d50a71bdSMitsuru IWASAKI  * Copyright (c) 1999 KOIE Hidetaka <koie@suri.co.jp>
8d50a71bdSMitsuru IWASAKI  * All rights reserved.
9d50a71bdSMitsuru IWASAKI  *
10d50a71bdSMitsuru IWASAKI  * Redistribution and use in source and binary forms, with or without
11d50a71bdSMitsuru IWASAKI  * modification, are permitted provided that the following conditions
12d50a71bdSMitsuru IWASAKI  * are met:
13d50a71bdSMitsuru IWASAKI  * 1. Redistributions of source code must retain the above copyright
14d50a71bdSMitsuru IWASAKI  *    notice, this list of conditions and the following disclaimer.
15d50a71bdSMitsuru IWASAKI  * 2. Redistributions in binary form must reproduce the above copyright
16d50a71bdSMitsuru IWASAKI  *    notice, this list of conditions and the following disclaimer in the
17d50a71bdSMitsuru IWASAKI  *    documentation and/or other materials provided with the distribution.
18d50a71bdSMitsuru IWASAKI  *
19d50a71bdSMitsuru IWASAKI  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20d50a71bdSMitsuru IWASAKI  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21d50a71bdSMitsuru IWASAKI  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22d50a71bdSMitsuru IWASAKI  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23d50a71bdSMitsuru IWASAKI  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24d50a71bdSMitsuru IWASAKI  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25d50a71bdSMitsuru IWASAKI  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26d50a71bdSMitsuru IWASAKI  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27d50a71bdSMitsuru IWASAKI  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28d50a71bdSMitsuru IWASAKI  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29d50a71bdSMitsuru IWASAKI  * SUCH DAMAGE.
30d50a71bdSMitsuru IWASAKI  */
31d50a71bdSMitsuru IWASAKI 
32d50a71bdSMitsuru IWASAKI #ifndef lint
33d50a71bdSMitsuru IWASAKI static const char rcsid[] =
3497d92980SPeter Wemm   "$FreeBSD$";
35d50a71bdSMitsuru IWASAKI #endif /* not lint */
36d50a71bdSMitsuru IWASAKI 
3700774f35SPeter Wemm #include <sys/types.h>
38d50a71bdSMitsuru IWASAKI #include <assert.h>
39d50a71bdSMitsuru IWASAKI #include <bitstring.h>
40d50a71bdSMitsuru IWASAKI #include <err.h>
41d50a71bdSMitsuru IWASAKI #include <errno.h>
42d50a71bdSMitsuru IWASAKI #include <fcntl.h>
43d50a71bdSMitsuru IWASAKI #include <paths.h>
44d50a71bdSMitsuru IWASAKI #include <signal.h>
45d50a71bdSMitsuru IWASAKI #include <stdio.h>
46d50a71bdSMitsuru IWASAKI #include <stdlib.h>
47d50a71bdSMitsuru IWASAKI #include <string.h>
48d50a71bdSMitsuru IWASAKI #include <syslog.h>
49d50a71bdSMitsuru IWASAKI #include <unistd.h>
50d50a71bdSMitsuru IWASAKI #include <sys/ioctl.h>
51d50a71bdSMitsuru IWASAKI #include <sys/time.h>
52d50a71bdSMitsuru IWASAKI #include <sys/wait.h>
53d50a71bdSMitsuru IWASAKI #include <machine/apm_bios.h>
54d50a71bdSMitsuru IWASAKI 
55d50a71bdSMitsuru IWASAKI #include "apmd.h"
56d50a71bdSMitsuru IWASAKI 
57d50a71bdSMitsuru IWASAKI int		debug_level = 0;
58d50a71bdSMitsuru IWASAKI int		verbose = 0;
59f90445cfSMatthew N. Dodd int		soft_power_state_change = 0;
60d50a71bdSMitsuru IWASAKI const char	*apmd_configfile = APMD_CONFIGFILE;
61d50a71bdSMitsuru IWASAKI const char	*apmd_pidfile = APMD_PIDFILE;
62719b9dc1SNick Sayer int             apmctl_fd = -1, apmnorm_fd = -1;
63d50a71bdSMitsuru IWASAKI 
64d50a71bdSMitsuru IWASAKI /*
65d50a71bdSMitsuru IWASAKI  * table of event handlers
66d50a71bdSMitsuru IWASAKI  */
67d50a71bdSMitsuru IWASAKI #define EVENT_CONFIG_INITIALIZER(EV,R) { #EV, NULL, R },
68d50a71bdSMitsuru IWASAKI struct event_config events[EVENT_MAX] = {
69d50a71bdSMitsuru IWASAKI 	EVENT_CONFIG_INITIALIZER(NOEVENT, 0)
70d50a71bdSMitsuru IWASAKI 	EVENT_CONFIG_INITIALIZER(STANDBYREQ, 1)
71d50a71bdSMitsuru IWASAKI 	EVENT_CONFIG_INITIALIZER(SUSPENDREQ, 1)
72d50a71bdSMitsuru IWASAKI 	EVENT_CONFIG_INITIALIZER(NORMRESUME, 0)
73d50a71bdSMitsuru IWASAKI 	EVENT_CONFIG_INITIALIZER(CRITRESUME, 0)
74d50a71bdSMitsuru IWASAKI 	EVENT_CONFIG_INITIALIZER(BATTERYLOW, 0)
7575b36243SMatthew N. Dodd 	EVENT_CONFIG_INITIALIZER(POWERSTATECHANGE, 0)
76d50a71bdSMitsuru IWASAKI 	EVENT_CONFIG_INITIALIZER(UPDATETIME, 0)
77d50a71bdSMitsuru IWASAKI 	EVENT_CONFIG_INITIALIZER(CRITSUSPEND, 1)
78d50a71bdSMitsuru IWASAKI 	EVENT_CONFIG_INITIALIZER(USERSTANDBYREQ, 1)
79d50a71bdSMitsuru IWASAKI 	EVENT_CONFIG_INITIALIZER(USERSUSPENDREQ, 1)
80d50a71bdSMitsuru IWASAKI 	EVENT_CONFIG_INITIALIZER(STANDBYRESUME, 0)
81d50a71bdSMitsuru IWASAKI 	EVENT_CONFIG_INITIALIZER(CAPABILITIESCHANGE, 0)
82d50a71bdSMitsuru IWASAKI };
83d50a71bdSMitsuru IWASAKI 
84d50a71bdSMitsuru IWASAKI /*
85719b9dc1SNick Sayer  * List of battery events
86719b9dc1SNick Sayer  */
87719b9dc1SNick Sayer struct battery_watch_event *battery_watch_list = NULL;
88719b9dc1SNick Sayer 
89719b9dc1SNick Sayer #define BATT_CHK_INTV 10 /* how many seconds between battery state checks? */
90719b9dc1SNick Sayer 
91719b9dc1SNick Sayer /*
92d50a71bdSMitsuru IWASAKI  * default procedure
93d50a71bdSMitsuru IWASAKI  */
94d50a71bdSMitsuru IWASAKI struct event_cmd *
95d50a71bdSMitsuru IWASAKI event_cmd_default_clone(void *this)
96d50a71bdSMitsuru IWASAKI {
97d50a71bdSMitsuru IWASAKI 	struct event_cmd * oldone = this;
98d50a71bdSMitsuru IWASAKI 	struct event_cmd * newone = malloc(oldone->len);
99d50a71bdSMitsuru IWASAKI 
100d50a71bdSMitsuru IWASAKI 	newone->next = NULL;
101d50a71bdSMitsuru IWASAKI 	newone->len = oldone->len;
102d50a71bdSMitsuru IWASAKI 	newone->name = oldone->name;
103d50a71bdSMitsuru IWASAKI 	newone->op = oldone->op;
104d50a71bdSMitsuru IWASAKI 	return newone;
105d50a71bdSMitsuru IWASAKI }
106d50a71bdSMitsuru IWASAKI 
107d50a71bdSMitsuru IWASAKI /*
108d50a71bdSMitsuru IWASAKI  * exec command
109d50a71bdSMitsuru IWASAKI  */
110d50a71bdSMitsuru IWASAKI int
111d50a71bdSMitsuru IWASAKI event_cmd_exec_act(void *this)
112d50a71bdSMitsuru IWASAKI {
113d50a71bdSMitsuru IWASAKI 	struct event_cmd_exec * p = this;
114d50a71bdSMitsuru IWASAKI 	int status = -1;
115d50a71bdSMitsuru IWASAKI 	pid_t pid;
116d50a71bdSMitsuru IWASAKI 
117d50a71bdSMitsuru IWASAKI 	switch ((pid = fork())) {
118d50a71bdSMitsuru IWASAKI 	case -1:
119103e4932SUlrich Spörlein 		warn("cannot fork");
120cd0788e1SUlrich Spörlein 		break;
121d50a71bdSMitsuru IWASAKI 	case 0:
122d50a71bdSMitsuru IWASAKI 		/* child process */
1239ad4f2d0SMatthew N. Dodd 		signal(SIGHUP, SIG_DFL);
1249ad4f2d0SMatthew N. Dodd 		signal(SIGCHLD, SIG_DFL);
1259ad4f2d0SMatthew N. Dodd 		signal(SIGTERM, SIG_DFL);
126cd0788e1SUlrich Spörlein 		execl(_PATH_BSHELL, "sh", "-c", p->line, (char *)NULL);
127d50a71bdSMitsuru IWASAKI 		_exit(127);
128d50a71bdSMitsuru IWASAKI 	default:
129d50a71bdSMitsuru IWASAKI 		/* parent process */
130d50a71bdSMitsuru IWASAKI 		do {
131d50a71bdSMitsuru IWASAKI 			pid = waitpid(pid, &status, 0);
132d50a71bdSMitsuru IWASAKI 		} while (pid == -1 && errno == EINTR);
133d50a71bdSMitsuru IWASAKI 		break;
134d50a71bdSMitsuru IWASAKI 	}
135d50a71bdSMitsuru IWASAKI 	return status;
136d50a71bdSMitsuru IWASAKI }
137d50a71bdSMitsuru IWASAKI void
138d50a71bdSMitsuru IWASAKI event_cmd_exec_dump(void *this, FILE *fp)
139d50a71bdSMitsuru IWASAKI {
140d50a71bdSMitsuru IWASAKI 	fprintf(fp, " \"%s\"", ((struct event_cmd_exec *)this)->line);
141d50a71bdSMitsuru IWASAKI }
142d50a71bdSMitsuru IWASAKI struct event_cmd *
143d50a71bdSMitsuru IWASAKI event_cmd_exec_clone(void *this)
144d50a71bdSMitsuru IWASAKI {
145d50a71bdSMitsuru IWASAKI 	struct event_cmd_exec * newone = (struct event_cmd_exec *) event_cmd_default_clone(this);
146d50a71bdSMitsuru IWASAKI 	struct event_cmd_exec * oldone = this;
147d50a71bdSMitsuru IWASAKI 
148d50a71bdSMitsuru IWASAKI 	newone->evcmd.next = NULL;
149d50a71bdSMitsuru IWASAKI 	newone->evcmd.len = oldone->evcmd.len;
150d50a71bdSMitsuru IWASAKI 	newone->evcmd.name = oldone->evcmd.name;
151d50a71bdSMitsuru IWASAKI 	newone->evcmd.op = oldone->evcmd.op;
152aecdf0ebSChris D. Faulhaber 	if ((newone->line = strdup(oldone->line)) == NULL)
153aecdf0ebSChris D. Faulhaber 		err(1, "out of memory");
154d50a71bdSMitsuru IWASAKI 	return (struct event_cmd *) newone;
155d50a71bdSMitsuru IWASAKI }
156d50a71bdSMitsuru IWASAKI void
157d50a71bdSMitsuru IWASAKI event_cmd_exec_free(void *this)
158d50a71bdSMitsuru IWASAKI {
159d50a71bdSMitsuru IWASAKI 	free(((struct event_cmd_exec *)this)->line);
160d50a71bdSMitsuru IWASAKI }
161d50a71bdSMitsuru IWASAKI struct event_cmd_op event_cmd_exec_ops = {
162d50a71bdSMitsuru IWASAKI 	event_cmd_exec_act,
163d50a71bdSMitsuru IWASAKI 	event_cmd_exec_dump,
164d50a71bdSMitsuru IWASAKI 	event_cmd_exec_clone,
165d50a71bdSMitsuru IWASAKI 	event_cmd_exec_free
166d50a71bdSMitsuru IWASAKI };
167d50a71bdSMitsuru IWASAKI 
168d50a71bdSMitsuru IWASAKI /*
169cd0788e1SUlrich Spörlein  * reject command
170d50a71bdSMitsuru IWASAKI  */
171d50a71bdSMitsuru IWASAKI int
172103e4932SUlrich Spörlein event_cmd_reject_act(void *this __unused)
173d50a71bdSMitsuru IWASAKI {
174cd0788e1SUlrich Spörlein 	int rc = 0;
175d50a71bdSMitsuru IWASAKI 
176d50a71bdSMitsuru IWASAKI 	if (ioctl(apmctl_fd, APMIO_REJECTLASTREQ, NULL)) {
177d50a71bdSMitsuru IWASAKI 		syslog(LOG_NOTICE, "fail to reject\n");
178cd0788e1SUlrich Spörlein 		rc = -1;
179d50a71bdSMitsuru IWASAKI 	}
180d50a71bdSMitsuru IWASAKI 	return rc;
181d50a71bdSMitsuru IWASAKI }
182d50a71bdSMitsuru IWASAKI struct event_cmd_op event_cmd_reject_ops = {
183d50a71bdSMitsuru IWASAKI 	event_cmd_reject_act,
184d50a71bdSMitsuru IWASAKI 	NULL,
185d50a71bdSMitsuru IWASAKI 	event_cmd_default_clone,
186d50a71bdSMitsuru IWASAKI 	NULL
187d50a71bdSMitsuru IWASAKI };
188d50a71bdSMitsuru IWASAKI 
189d50a71bdSMitsuru IWASAKI /*
190d50a71bdSMitsuru IWASAKI  * manipulate event_config
191d50a71bdSMitsuru IWASAKI  */
192d50a71bdSMitsuru IWASAKI struct event_cmd *
193d50a71bdSMitsuru IWASAKI clone_event_cmd_list(struct event_cmd *p)
194d50a71bdSMitsuru IWASAKI {
195d50a71bdSMitsuru IWASAKI 	struct event_cmd dummy;
196d50a71bdSMitsuru IWASAKI 	struct event_cmd *q = &dummy;
197d50a71bdSMitsuru IWASAKI 	for ( ;p; p = p->next) {
198d50a71bdSMitsuru IWASAKI 		assert(p->op->clone);
199d50a71bdSMitsuru IWASAKI 		if ((q->next = p->op->clone(p)) == NULL)
200103e4932SUlrich Spörlein 			err(1, "out of memory");
201d50a71bdSMitsuru IWASAKI 		q = q->next;
202d50a71bdSMitsuru IWASAKI 	}
203d50a71bdSMitsuru IWASAKI 	q->next = NULL;
204d50a71bdSMitsuru IWASAKI 	return dummy.next;
205d50a71bdSMitsuru IWASAKI }
206d50a71bdSMitsuru IWASAKI void
207d50a71bdSMitsuru IWASAKI free_event_cmd_list(struct event_cmd *p)
208d50a71bdSMitsuru IWASAKI {
209d50a71bdSMitsuru IWASAKI 	struct event_cmd * q;
210d50a71bdSMitsuru IWASAKI 	for ( ; p ; p = q) {
211d50a71bdSMitsuru IWASAKI 		q = p->next;
212d50a71bdSMitsuru IWASAKI 		if (p->op->free)
213d50a71bdSMitsuru IWASAKI 			p->op->free(p);
214d50a71bdSMitsuru IWASAKI 		free(p);
215d50a71bdSMitsuru IWASAKI 	}
216d50a71bdSMitsuru IWASAKI }
217d50a71bdSMitsuru IWASAKI int
218719b9dc1SNick Sayer register_battery_handlers(
219719b9dc1SNick Sayer 	int level, int direction,
220719b9dc1SNick Sayer 	struct event_cmd *cmdlist)
221719b9dc1SNick Sayer {
222719b9dc1SNick Sayer 	/*
223719b9dc1SNick Sayer 	 * level is negative if it's in "minutes", non-negative if
224719b9dc1SNick Sayer 	 * percentage.
225719b9dc1SNick Sayer 	 *
226719b9dc1SNick Sayer 	 * direction =1 means we care about this level when charging,
227719b9dc1SNick Sayer 	 * direction =-1 means we care about it when discharging.
228719b9dc1SNick Sayer 	 */
229719b9dc1SNick Sayer 	if (level>100) /* percentage > 100 */
230719b9dc1SNick Sayer 		return -1;
231719b9dc1SNick Sayer 	if (abs(direction) != 1) /* nonsense direction value */
232719b9dc1SNick Sayer 		return -1;
233719b9dc1SNick Sayer 
234719b9dc1SNick Sayer 	if (cmdlist) {
235719b9dc1SNick Sayer 		struct battery_watch_event *we;
236719b9dc1SNick Sayer 
237719b9dc1SNick Sayer 		if ((we = malloc(sizeof(struct battery_watch_event))) == NULL)
238103e4932SUlrich Spörlein 			err(1, "out of memory");
239719b9dc1SNick Sayer 
240719b9dc1SNick Sayer 		we->next = battery_watch_list; /* starts at NULL */
241719b9dc1SNick Sayer 		battery_watch_list = we;
242719b9dc1SNick Sayer 		we->level = abs(level);
243719b9dc1SNick Sayer 		we->type = (level<0)?BATTERY_MINUTES:BATTERY_PERCENT;
244719b9dc1SNick Sayer 		we->direction = (direction<0)?BATTERY_DISCHARGING:
245719b9dc1SNick Sayer 			BATTERY_CHARGING;
246719b9dc1SNick Sayer 		we->done = 0;
247719b9dc1SNick Sayer 		we->cmdlist = clone_event_cmd_list(cmdlist);
248719b9dc1SNick Sayer 	}
249719b9dc1SNick Sayer 	return 0;
250719b9dc1SNick Sayer }
251719b9dc1SNick Sayer int
252d50a71bdSMitsuru IWASAKI register_apm_event_handlers(
253d50a71bdSMitsuru IWASAKI 	bitstr_t bit_decl(evlist, EVENT_MAX),
254d50a71bdSMitsuru IWASAKI 	struct event_cmd *cmdlist)
255d50a71bdSMitsuru IWASAKI {
256d50a71bdSMitsuru IWASAKI 	if (cmdlist) {
257d50a71bdSMitsuru IWASAKI 		bitstr_t bit_decl(tmp, EVENT_MAX);
258d50a71bdSMitsuru IWASAKI 		memcpy(&tmp, evlist, bitstr_size(EVENT_MAX));
259d50a71bdSMitsuru IWASAKI 
260d50a71bdSMitsuru IWASAKI 		for (;;) {
261d50a71bdSMitsuru IWASAKI 			int n;
262d50a71bdSMitsuru IWASAKI 			struct event_cmd *p;
263d50a71bdSMitsuru IWASAKI 			struct event_cmd *q;
264d50a71bdSMitsuru IWASAKI 			bit_ffs(tmp, EVENT_MAX, &n);
265d50a71bdSMitsuru IWASAKI 			if (n < 0)
266d50a71bdSMitsuru IWASAKI 				break;
267d50a71bdSMitsuru IWASAKI 			p = events[n].cmdlist;
268d50a71bdSMitsuru IWASAKI 			if ((q = clone_event_cmd_list(cmdlist)) == NULL)
269103e4932SUlrich Spörlein 				err(1, "out of memory");
270d50a71bdSMitsuru IWASAKI 			if (p) {
271d50a71bdSMitsuru IWASAKI 				while (p->next != NULL)
272d50a71bdSMitsuru IWASAKI 					p = p->next;
273d50a71bdSMitsuru IWASAKI 				p->next = q;
274d50a71bdSMitsuru IWASAKI 			} else {
275d50a71bdSMitsuru IWASAKI 				events[n].cmdlist = q;
276d50a71bdSMitsuru IWASAKI 			}
277d50a71bdSMitsuru IWASAKI 			bit_clear(tmp, n);
278d50a71bdSMitsuru IWASAKI 		}
279d50a71bdSMitsuru IWASAKI 	}
280d50a71bdSMitsuru IWASAKI 	return 0;
281d50a71bdSMitsuru IWASAKI }
282d50a71bdSMitsuru IWASAKI 
283d50a71bdSMitsuru IWASAKI /*
284d50a71bdSMitsuru IWASAKI  * execute command
285d50a71bdSMitsuru IWASAKI  */
286d50a71bdSMitsuru IWASAKI int
287719b9dc1SNick Sayer exec_run_cmd(struct event_cmd *p)
288d50a71bdSMitsuru IWASAKI {
289d50a71bdSMitsuru IWASAKI 	int status = 0;
290d50a71bdSMitsuru IWASAKI 
291d50a71bdSMitsuru IWASAKI 	for (; p; p = p->next) {
292d50a71bdSMitsuru IWASAKI 		assert(p->op->act);
293d50a71bdSMitsuru IWASAKI 		if (verbose)
294d50a71bdSMitsuru IWASAKI 			syslog(LOG_INFO, "action: %s", p->name);
295d50a71bdSMitsuru IWASAKI 		status = p->op->act(p);
296d50a71bdSMitsuru IWASAKI 		if (status) {
297d50a71bdSMitsuru IWASAKI 			syslog(LOG_NOTICE, "command finished with %d\n", status);
298d50a71bdSMitsuru IWASAKI 			break;
299d50a71bdSMitsuru IWASAKI 		}
300d50a71bdSMitsuru IWASAKI 	}
301d50a71bdSMitsuru IWASAKI 	return status;
302d50a71bdSMitsuru IWASAKI }
303d50a71bdSMitsuru IWASAKI 
304d50a71bdSMitsuru IWASAKI /*
305719b9dc1SNick Sayer  * execute command -- the event version
306719b9dc1SNick Sayer  */
307719b9dc1SNick Sayer int
308719b9dc1SNick Sayer exec_event_cmd(struct event_config *ev)
309719b9dc1SNick Sayer {
310719b9dc1SNick Sayer 	int status = 0;
311719b9dc1SNick Sayer 
312719b9dc1SNick Sayer 	status = exec_run_cmd(ev->cmdlist);
313719b9dc1SNick Sayer 	if (status && ev->rejectable) {
314719b9dc1SNick Sayer 		syslog(LOG_ERR, "canceled");
315103e4932SUlrich Spörlein 		event_cmd_reject_act(NULL);
316719b9dc1SNick Sayer 	}
317719b9dc1SNick Sayer 	return status;
318719b9dc1SNick Sayer }
319719b9dc1SNick Sayer 
320719b9dc1SNick Sayer /*
321d50a71bdSMitsuru IWASAKI  * read config file
322d50a71bdSMitsuru IWASAKI  */
323d50a71bdSMitsuru IWASAKI extern FILE * yyin;
324d50a71bdSMitsuru IWASAKI extern int yydebug;
325d50a71bdSMitsuru IWASAKI 
326d50a71bdSMitsuru IWASAKI void
327d50a71bdSMitsuru IWASAKI read_config(void)
328d50a71bdSMitsuru IWASAKI {
329d50a71bdSMitsuru IWASAKI 	int i;
330d50a71bdSMitsuru IWASAKI 
331d50a71bdSMitsuru IWASAKI 	if ((yyin = fopen(apmd_configfile, "r")) == NULL) {
332103e4932SUlrich Spörlein 		err(1, "cannot open config file");
333d50a71bdSMitsuru IWASAKI 	}
334d50a71bdSMitsuru IWASAKI 
335d50a71bdSMitsuru IWASAKI #ifdef DEBUG
336d50a71bdSMitsuru IWASAKI 	yydebug = debug_level;
337d50a71bdSMitsuru IWASAKI #endif
338d50a71bdSMitsuru IWASAKI 
339d50a71bdSMitsuru IWASAKI 	if (yyparse() != 0)
340103e4932SUlrich Spörlein 		err(1, "cannot parse config file");
341d50a71bdSMitsuru IWASAKI 
342d50a71bdSMitsuru IWASAKI 	fclose(yyin);
343d50a71bdSMitsuru IWASAKI 
344d50a71bdSMitsuru IWASAKI 	/* enable events */
345d50a71bdSMitsuru IWASAKI 	for (i = 0; i < EVENT_MAX; i++) {
346d50a71bdSMitsuru IWASAKI 		if (events[i].cmdlist) {
347d50a71bdSMitsuru IWASAKI 			u_int event_type = i;
348d50a71bdSMitsuru IWASAKI 			if (write(apmctl_fd, &event_type, sizeof(u_int)) == -1) {
349103e4932SUlrich Spörlein 				err(1, "cannot enable event 0x%x", event_type);
350d50a71bdSMitsuru IWASAKI 			}
351d50a71bdSMitsuru IWASAKI 		}
352d50a71bdSMitsuru IWASAKI 	}
353d50a71bdSMitsuru IWASAKI }
354d50a71bdSMitsuru IWASAKI 
355d50a71bdSMitsuru IWASAKI void
356103e4932SUlrich Spörlein dump_config(void)
357d50a71bdSMitsuru IWASAKI {
358d50a71bdSMitsuru IWASAKI 	int i;
359719b9dc1SNick Sayer 	struct battery_watch_event *q;
360d50a71bdSMitsuru IWASAKI 
361d50a71bdSMitsuru IWASAKI 	for (i = 0; i < EVENT_MAX; i++) {
362d50a71bdSMitsuru IWASAKI 		struct event_cmd * p;
363d50a71bdSMitsuru IWASAKI 		if ((p = events[i].cmdlist)) {
364d50a71bdSMitsuru IWASAKI 			fprintf(stderr, "apm_event %s {\n", events[i].name);
365d50a71bdSMitsuru IWASAKI 			for ( ; p ; p = p->next) {
366d50a71bdSMitsuru IWASAKI 				fprintf(stderr, "\t%s", p->name);
367d50a71bdSMitsuru IWASAKI 				if (p->op->dump)
368d50a71bdSMitsuru IWASAKI 					p->op->dump(p, stderr);
369d50a71bdSMitsuru IWASAKI 				fprintf(stderr, ";\n");
370d50a71bdSMitsuru IWASAKI 			}
371d50a71bdSMitsuru IWASAKI 			fprintf(stderr, "}\n");
372d50a71bdSMitsuru IWASAKI 		}
373d50a71bdSMitsuru IWASAKI 	}
374719b9dc1SNick Sayer 	for (q = battery_watch_list ; q != NULL ; q = q -> next) {
375719b9dc1SNick Sayer 		struct event_cmd * p;
376719b9dc1SNick Sayer 		fprintf(stderr, "apm_battery %d%s %s {\n",
377719b9dc1SNick Sayer 			q -> level,
378719b9dc1SNick Sayer 			(q -> type == BATTERY_PERCENT)?"%":"m",
379719b9dc1SNick Sayer 			(q -> direction == BATTERY_CHARGING)?"charging":
380719b9dc1SNick Sayer 				"discharging");
381719b9dc1SNick Sayer 		for ( p = q -> cmdlist; p ; p = p->next) {
382719b9dc1SNick Sayer 			fprintf(stderr, "\t%s", p->name);
383719b9dc1SNick Sayer 			if (p->op->dump)
384719b9dc1SNick Sayer 				p->op->dump(p, stderr);
385719b9dc1SNick Sayer 			fprintf(stderr, ";\n");
386719b9dc1SNick Sayer 		}
387719b9dc1SNick Sayer 		fprintf(stderr, "}\n");
388719b9dc1SNick Sayer 	}
389d50a71bdSMitsuru IWASAKI }
390d50a71bdSMitsuru IWASAKI 
391d50a71bdSMitsuru IWASAKI void
392103e4932SUlrich Spörlein destroy_config(void)
393d50a71bdSMitsuru IWASAKI {
394d50a71bdSMitsuru IWASAKI 	int i;
395719b9dc1SNick Sayer 	struct battery_watch_event *q;
396d50a71bdSMitsuru IWASAKI 
397d50a71bdSMitsuru IWASAKI 	/* disable events */
398d50a71bdSMitsuru IWASAKI 	for (i = 0; i < EVENT_MAX; i++) {
399d50a71bdSMitsuru IWASAKI 		if (events[i].cmdlist) {
400d50a71bdSMitsuru IWASAKI 			u_int event_type = i;
401d50a71bdSMitsuru IWASAKI 			if (write(apmctl_fd, &event_type, sizeof(u_int)) == -1) {
402103e4932SUlrich Spörlein 				err(1, "cannot disable event 0x%x", event_type);
403d50a71bdSMitsuru IWASAKI 			}
404d50a71bdSMitsuru IWASAKI 		}
405d50a71bdSMitsuru IWASAKI 	}
406d50a71bdSMitsuru IWASAKI 
407d50a71bdSMitsuru IWASAKI 	for (i = 0; i < EVENT_MAX; i++) {
408d50a71bdSMitsuru IWASAKI 		struct event_cmd * p;
409d50a71bdSMitsuru IWASAKI 		if ((p = events[i].cmdlist))
410d50a71bdSMitsuru IWASAKI 			free_event_cmd_list(p);
411d50a71bdSMitsuru IWASAKI 		events[i].cmdlist = NULL;
412d50a71bdSMitsuru IWASAKI 	}
413719b9dc1SNick Sayer 
414719b9dc1SNick Sayer 	for( ; battery_watch_list; battery_watch_list = battery_watch_list -> next) {
415719b9dc1SNick Sayer 		free_event_cmd_list(battery_watch_list->cmdlist);
416719b9dc1SNick Sayer 		q = battery_watch_list->next;
417719b9dc1SNick Sayer 		free(battery_watch_list);
418719b9dc1SNick Sayer 		battery_watch_list = q;
419719b9dc1SNick Sayer 	}
420d50a71bdSMitsuru IWASAKI }
421d50a71bdSMitsuru IWASAKI 
422d50a71bdSMitsuru IWASAKI void
423103e4932SUlrich Spörlein restart(void)
424d50a71bdSMitsuru IWASAKI {
425d50a71bdSMitsuru IWASAKI 	destroy_config();
426d50a71bdSMitsuru IWASAKI 	read_config();
427d50a71bdSMitsuru IWASAKI 	if (verbose)
428d50a71bdSMitsuru IWASAKI 		dump_config();
429d50a71bdSMitsuru IWASAKI }
430d50a71bdSMitsuru IWASAKI 
431d50a71bdSMitsuru IWASAKI /*
432d50a71bdSMitsuru IWASAKI  * write pid file
433d50a71bdSMitsuru IWASAKI  */
434d50a71bdSMitsuru IWASAKI static void
435103e4932SUlrich Spörlein write_pid(void)
436d50a71bdSMitsuru IWASAKI {
437d50a71bdSMitsuru IWASAKI 	FILE *fp = fopen(apmd_pidfile, "w");
438d50a71bdSMitsuru IWASAKI 
439d50a71bdSMitsuru IWASAKI 	if (fp) {
44034759932SKevin Lo 		fprintf(fp, "%ld\n", (long)getpid());
441d50a71bdSMitsuru IWASAKI 		fclose(fp);
442d50a71bdSMitsuru IWASAKI 	}
443d50a71bdSMitsuru IWASAKI }
444d50a71bdSMitsuru IWASAKI 
445d50a71bdSMitsuru IWASAKI /*
446d50a71bdSMitsuru IWASAKI  * handle signals
447d50a71bdSMitsuru IWASAKI  */
448d50a71bdSMitsuru IWASAKI static int signal_fd[2];
449d50a71bdSMitsuru IWASAKI 
450d50a71bdSMitsuru IWASAKI void
451d50a71bdSMitsuru IWASAKI enque_signal(int sig)
452d50a71bdSMitsuru IWASAKI {
453d50a71bdSMitsuru IWASAKI 	if (write(signal_fd[1], &sig, sizeof sig) != sizeof sig)
454103e4932SUlrich Spörlein 		err(1, "cannot process signal.");
455d50a71bdSMitsuru IWASAKI }
456d50a71bdSMitsuru IWASAKI 
457d50a71bdSMitsuru IWASAKI void
458103e4932SUlrich Spörlein wait_child(void)
459d50a71bdSMitsuru IWASAKI {
460d50a71bdSMitsuru IWASAKI 	int status;
461d50a71bdSMitsuru IWASAKI 	while (waitpid(-1, &status, WNOHANG) > 0)
462d50a71bdSMitsuru IWASAKI 		;
463d50a71bdSMitsuru IWASAKI }
464d50a71bdSMitsuru IWASAKI 
465d50a71bdSMitsuru IWASAKI int
466d50a71bdSMitsuru IWASAKI proc_signal(int fd)
467d50a71bdSMitsuru IWASAKI {
468cd0788e1SUlrich Spörlein 	int rc = 0;
469d50a71bdSMitsuru IWASAKI 	int sig;
470d50a71bdSMitsuru IWASAKI 
471d50a71bdSMitsuru IWASAKI 	while (read(fd, &sig, sizeof sig) == sizeof sig) {
472d50a71bdSMitsuru IWASAKI 		syslog(LOG_INFO, "caught signal: %d", sig);
473d50a71bdSMitsuru IWASAKI 		switch (sig) {
474d50a71bdSMitsuru IWASAKI 		case SIGHUP:
475d50a71bdSMitsuru IWASAKI 			syslog(LOG_NOTICE, "restart by SIG");
476d50a71bdSMitsuru IWASAKI 			restart();
477d50a71bdSMitsuru IWASAKI 			break;
478d50a71bdSMitsuru IWASAKI 		case SIGTERM:
479d50a71bdSMitsuru IWASAKI 			syslog(LOG_NOTICE, "going down on signal %d", sig);
480f90445cfSMatthew N. Dodd 			rc = -1;
481cd0788e1SUlrich Spörlein 			return rc;
482d50a71bdSMitsuru IWASAKI 		case SIGCHLD:
483d50a71bdSMitsuru IWASAKI 			wait_child();
484d50a71bdSMitsuru IWASAKI 			break;
485d50a71bdSMitsuru IWASAKI 		default:
486103e4932SUlrich Spörlein 			warn("unexpected signal(%d) received.", sig);
487d50a71bdSMitsuru IWASAKI 			break;
488d50a71bdSMitsuru IWASAKI 		}
489d50a71bdSMitsuru IWASAKI 	}
490d50a71bdSMitsuru IWASAKI 	return rc;
491d50a71bdSMitsuru IWASAKI }
492d50a71bdSMitsuru IWASAKI void
493d50a71bdSMitsuru IWASAKI proc_apmevent(int fd)
494d50a71bdSMitsuru IWASAKI {
495d50a71bdSMitsuru IWASAKI 	struct apm_event_info apmevent;
496d50a71bdSMitsuru IWASAKI 
497d50a71bdSMitsuru IWASAKI 	while (ioctl(fd, APMIO_NEXTEVENT, &apmevent) == 0) {
498d50a71bdSMitsuru IWASAKI 		int status;
499d50a71bdSMitsuru IWASAKI 		syslog(LOG_NOTICE, "apmevent %04x index %d\n",
500d50a71bdSMitsuru IWASAKI 			apmevent.type, apmevent.index);
501d50a71bdSMitsuru IWASAKI 		syslog(LOG_INFO, "apm event: %s", events[apmevent.type].name);
502d50a71bdSMitsuru IWASAKI 		if (fork() == 0) {
503d50a71bdSMitsuru IWASAKI 			status = exec_event_cmd(&events[apmevent.type]);
504d50a71bdSMitsuru IWASAKI 			exit(status);
505d50a71bdSMitsuru IWASAKI 		}
506d50a71bdSMitsuru IWASAKI 	}
507d50a71bdSMitsuru IWASAKI }
508719b9dc1SNick Sayer 
509719b9dc1SNick Sayer #define AC_POWER_STATE ((pw_info.ai_acline == 1) ? BATTERY_CHARGING :\
510719b9dc1SNick Sayer 	BATTERY_DISCHARGING)
511719b9dc1SNick Sayer 
512719b9dc1SNick Sayer void
513103e4932SUlrich Spörlein check_battery(void)
514719b9dc1SNick Sayer {
515719b9dc1SNick Sayer 
516719b9dc1SNick Sayer 	static int first_time=1, last_state;
517f90445cfSMatthew N. Dodd 	int status;
518719b9dc1SNick Sayer 
519719b9dc1SNick Sayer 	struct apm_info pw_info;
520719b9dc1SNick Sayer 	struct battery_watch_event *p;
521719b9dc1SNick Sayer 
522719b9dc1SNick Sayer 	/* If we don't care, don't bother */
523719b9dc1SNick Sayer 	if (battery_watch_list == NULL)
524719b9dc1SNick Sayer 		return;
525719b9dc1SNick Sayer 
526719b9dc1SNick Sayer 	if (first_time) {
527719b9dc1SNick Sayer 		if ( ioctl(apmnorm_fd, APMIO_GETINFO, &pw_info) < 0)
528103e4932SUlrich Spörlein 			err(1, "cannot check battery state.");
529719b9dc1SNick Sayer /*
530719b9dc1SNick Sayer  * This next statement isn't entirely true. The spec does not tie AC
531719b9dc1SNick Sayer  * line state to battery charging or not, but this is a bit lazier to do.
532719b9dc1SNick Sayer  */
533719b9dc1SNick Sayer 		last_state = AC_POWER_STATE;
534719b9dc1SNick Sayer 		first_time = 0;
535719b9dc1SNick Sayer 		return; /* We can't process events, we have no baseline */
536719b9dc1SNick Sayer 	}
537719b9dc1SNick Sayer 
538719b9dc1SNick Sayer 	/*
539719b9dc1SNick Sayer 	 * XXX - should we do this a bunch of times and perform some sort
540719b9dc1SNick Sayer 	 * of smoothing or correction?
541719b9dc1SNick Sayer 	 */
542719b9dc1SNick Sayer 	if ( ioctl(apmnorm_fd, APMIO_GETINFO, &pw_info) < 0)
543103e4932SUlrich Spörlein 		err(1, "cannot check battery state.");
544719b9dc1SNick Sayer 
545719b9dc1SNick Sayer 	/*
546719b9dc1SNick Sayer 	 * If we're not in the state now that we were in last time,
547719b9dc1SNick Sayer 	 * then it's a transition, which means we must clean out
548719b9dc1SNick Sayer 	 * the event-caught state.
549719b9dc1SNick Sayer 	 */
550719b9dc1SNick Sayer 	if (last_state != AC_POWER_STATE) {
551f90445cfSMatthew N. Dodd 		if (soft_power_state_change && fork() == 0) {
552f90445cfSMatthew N. Dodd 			status = exec_event_cmd(&events[PMEV_POWERSTATECHANGE]);
553f90445cfSMatthew N. Dodd 			exit(status);
554f90445cfSMatthew N. Dodd 		}
555719b9dc1SNick Sayer 		last_state = AC_POWER_STATE;
556719b9dc1SNick Sayer 		for (p = battery_watch_list ; p!=NULL ; p = p -> next)
557719b9dc1SNick Sayer 			p->done = 0;
558719b9dc1SNick Sayer 	}
559719b9dc1SNick Sayer 	for (p = battery_watch_list ; p != NULL ; p = p -> next)
560719b9dc1SNick Sayer 		if (p -> direction == AC_POWER_STATE &&
561719b9dc1SNick Sayer 			!(p -> done) &&
562719b9dc1SNick Sayer 			((p -> type == BATTERY_PERCENT &&
563103e4932SUlrich Spörlein 				p -> level == (int)pw_info.ai_batt_life) ||
564719b9dc1SNick Sayer 			(p -> type == BATTERY_MINUTES &&
565719b9dc1SNick Sayer 				p -> level == (pw_info.ai_batt_time / 60)))) {
566719b9dc1SNick Sayer 			p -> done++;
567719b9dc1SNick Sayer 			if (verbose)
568719b9dc1SNick Sayer 				syslog(LOG_NOTICE, "Caught battery event: %s, %d%s",
569719b9dc1SNick Sayer 					(p -> direction == BATTERY_CHARGING)?"charging":"discharging",
570719b9dc1SNick Sayer 					p -> level,
571719b9dc1SNick Sayer 					(p -> type == BATTERY_PERCENT)?"%":" minutes");
572719b9dc1SNick Sayer 			if (fork() == 0) {
573719b9dc1SNick Sayer 				status = exec_run_cmd(p -> cmdlist);
574719b9dc1SNick Sayer 				exit(status);
575719b9dc1SNick Sayer 			}
576719b9dc1SNick Sayer 		}
577719b9dc1SNick Sayer }
578d50a71bdSMitsuru IWASAKI void
579d50a71bdSMitsuru IWASAKI event_loop(void)
580d50a71bdSMitsuru IWASAKI {
581d50a71bdSMitsuru IWASAKI 	int		fdmax = 0;
582d50a71bdSMitsuru IWASAKI 	struct sigaction nsa;
583d50a71bdSMitsuru IWASAKI 	fd_set          master_rfds;
584d50a71bdSMitsuru IWASAKI 	sigset_t	sigmask, osigmask;
585d50a71bdSMitsuru IWASAKI 
586d50a71bdSMitsuru IWASAKI 	FD_ZERO(&master_rfds);
587d50a71bdSMitsuru IWASAKI 	FD_SET(apmctl_fd, &master_rfds);
588d50a71bdSMitsuru IWASAKI 	fdmax = apmctl_fd > fdmax ? apmctl_fd : fdmax;
589d50a71bdSMitsuru IWASAKI 
590d50a71bdSMitsuru IWASAKI 	FD_SET(signal_fd[0], &master_rfds);
591d50a71bdSMitsuru IWASAKI 	fdmax = signal_fd[0] > fdmax ? signal_fd[0] : fdmax;
592d50a71bdSMitsuru IWASAKI 
593d50a71bdSMitsuru IWASAKI 	memset(&nsa, 0, sizeof nsa);
594d50a71bdSMitsuru IWASAKI 	nsa.sa_handler = enque_signal;
595d50a71bdSMitsuru IWASAKI 	sigfillset(&nsa.sa_mask);
596d50a71bdSMitsuru IWASAKI 	nsa.sa_flags = SA_RESTART;
597d50a71bdSMitsuru IWASAKI 	sigaction(SIGHUP, &nsa, NULL);
598d50a71bdSMitsuru IWASAKI 	sigaction(SIGCHLD, &nsa, NULL);
599d50a71bdSMitsuru IWASAKI 	sigaction(SIGTERM, &nsa, NULL);
600d50a71bdSMitsuru IWASAKI 
601d50a71bdSMitsuru IWASAKI 	sigemptyset(&sigmask);
602d50a71bdSMitsuru IWASAKI 	sigaddset(&sigmask, SIGHUP);
603d50a71bdSMitsuru IWASAKI 	sigaddset(&sigmask, SIGCHLD);
604d50a71bdSMitsuru IWASAKI 	sigaddset(&sigmask, SIGTERM);
605d50a71bdSMitsuru IWASAKI 	sigprocmask(SIG_SETMASK, &sigmask, &osigmask);
606d50a71bdSMitsuru IWASAKI 
607d50a71bdSMitsuru IWASAKI 	while (1) {
608d50a71bdSMitsuru IWASAKI 		fd_set rfds;
609719b9dc1SNick Sayer 		int res;
610719b9dc1SNick Sayer 		struct timeval to;
611719b9dc1SNick Sayer 
612719b9dc1SNick Sayer 		to.tv_sec = BATT_CHK_INTV;
613719b9dc1SNick Sayer 		to.tv_usec = 0;
614d50a71bdSMitsuru IWASAKI 
615d50a71bdSMitsuru IWASAKI 		memcpy(&rfds, &master_rfds, sizeof rfds);
616d50a71bdSMitsuru IWASAKI 		sigprocmask(SIG_SETMASK, &osigmask, NULL);
617719b9dc1SNick Sayer 		if ((res=select(fdmax + 1, &rfds, 0, 0, &to)) < 0) {
618d50a71bdSMitsuru IWASAKI 			if (errno != EINTR)
619103e4932SUlrich Spörlein 				err(1, "select");
620d50a71bdSMitsuru IWASAKI 		}
621d50a71bdSMitsuru IWASAKI 		sigprocmask(SIG_SETMASK, &sigmask, NULL);
622d50a71bdSMitsuru IWASAKI 
623719b9dc1SNick Sayer 		if (res == 0) { /* time to check the battery */
624719b9dc1SNick Sayer 			check_battery();
625719b9dc1SNick Sayer 			continue;
626719b9dc1SNick Sayer 		}
627719b9dc1SNick Sayer 
628d50a71bdSMitsuru IWASAKI 		if (FD_ISSET(signal_fd[0], &rfds)) {
629d50a71bdSMitsuru IWASAKI 			if (proc_signal(signal_fd[0]) < 0)
630cd0788e1SUlrich Spörlein 				return;
631d50a71bdSMitsuru IWASAKI 		}
632719b9dc1SNick Sayer 
633d50a71bdSMitsuru IWASAKI 		if (FD_ISSET(apmctl_fd, &rfds))
634d50a71bdSMitsuru IWASAKI 			proc_apmevent(apmctl_fd);
635d50a71bdSMitsuru IWASAKI 	}
636d50a71bdSMitsuru IWASAKI }
637d50a71bdSMitsuru IWASAKI 
638e46b89dcSPeter Wemm int
639d50a71bdSMitsuru IWASAKI main(int ac, char* av[])
640d50a71bdSMitsuru IWASAKI {
641d50a71bdSMitsuru IWASAKI 	int	ch;
642d50a71bdSMitsuru IWASAKI 	int	daemonize = 1;
643d50a71bdSMitsuru IWASAKI 	char	*prog;
644d50a71bdSMitsuru IWASAKI 	int	logopt = LOG_NDELAY | LOG_PID;
645d50a71bdSMitsuru IWASAKI 
6461c6adfcfSKevin Lo 	while ((ch = getopt(ac, av, "df:sv")) != -1) {
647d50a71bdSMitsuru IWASAKI 		switch (ch) {
648d50a71bdSMitsuru IWASAKI 		case 'd':
649d50a71bdSMitsuru IWASAKI 			daemonize = 0;
650d50a71bdSMitsuru IWASAKI 			debug_level++;
651d50a71bdSMitsuru IWASAKI 			break;
652d50a71bdSMitsuru IWASAKI 		case 'f':
653d50a71bdSMitsuru IWASAKI 			apmd_configfile = optarg;
654d50a71bdSMitsuru IWASAKI 			break;
655f90445cfSMatthew N. Dodd 		case 's':
656f90445cfSMatthew N. Dodd 			soft_power_state_change = 1;
657f90445cfSMatthew N. Dodd 			break;
658d50a71bdSMitsuru IWASAKI 		case 'v':
659d50a71bdSMitsuru IWASAKI 			verbose = 1;
660d50a71bdSMitsuru IWASAKI 			break;
661d50a71bdSMitsuru IWASAKI 		default:
662103e4932SUlrich Spörlein 			err(1, "unknown option `%c'", ch);
663d50a71bdSMitsuru IWASAKI 		}
664d50a71bdSMitsuru IWASAKI 	}
665d50a71bdSMitsuru IWASAKI 
666d50a71bdSMitsuru IWASAKI 	if (daemonize)
667d50a71bdSMitsuru IWASAKI 		daemon(0, 0);
668d50a71bdSMitsuru IWASAKI 
669d50a71bdSMitsuru IWASAKI #ifdef NICE_INCR
670103e4932SUlrich Spörlein 	nice(NICE_INCR);
671d50a71bdSMitsuru IWASAKI #endif
672d50a71bdSMitsuru IWASAKI 
673d50a71bdSMitsuru IWASAKI 	if (!daemonize)
674d50a71bdSMitsuru IWASAKI 		logopt |= LOG_PERROR;
675d50a71bdSMitsuru IWASAKI 
676d50a71bdSMitsuru IWASAKI 	prog = strrchr(av[0], '/');
677d50a71bdSMitsuru IWASAKI 	openlog(prog ? prog+1 : av[0], logopt, LOG_DAEMON);
678d50a71bdSMitsuru IWASAKI 
679d50a71bdSMitsuru IWASAKI 	syslog(LOG_NOTICE, "start");
680d50a71bdSMitsuru IWASAKI 
681d50a71bdSMitsuru IWASAKI 	if (pipe(signal_fd) < 0)
682103e4932SUlrich Spörlein 		err(1, "pipe");
683d50a71bdSMitsuru IWASAKI 	if (fcntl(signal_fd[0], F_SETFL, O_NONBLOCK) < 0)
684103e4932SUlrich Spörlein 		err(1, "fcntl");
685d50a71bdSMitsuru IWASAKI 
686719b9dc1SNick Sayer 	if ((apmnorm_fd = open(APM_NORM_DEVICEFILE, O_RDWR)) == -1) {
687103e4932SUlrich Spörlein 		err(1, "cannot open device file `%s'", APM_NORM_DEVICEFILE);
688719b9dc1SNick Sayer 	}
689719b9dc1SNick Sayer 
6909ad4f2d0SMatthew N. Dodd 	if (fcntl(apmnorm_fd, F_SETFD, 1) == -1) {
691103e4932SUlrich Spörlein 		err(1, "cannot set close-on-exec flag for device file '%s'", APM_NORM_DEVICEFILE);
6929ad4f2d0SMatthew N. Dodd 	}
6939ad4f2d0SMatthew N. Dodd 
694d50a71bdSMitsuru IWASAKI 	if ((apmctl_fd = open(APM_CTL_DEVICEFILE, O_RDWR)) == -1) {
695103e4932SUlrich Spörlein 		err(1, "cannot open device file `%s'", APM_CTL_DEVICEFILE);
696d50a71bdSMitsuru IWASAKI 	}
697d50a71bdSMitsuru IWASAKI 
6989ad4f2d0SMatthew N. Dodd 	if (fcntl(apmctl_fd, F_SETFD, 1) == -1) {
699103e4932SUlrich Spörlein 		err(1, "cannot set close-on-exec flag for device file '%s'", APM_CTL_DEVICEFILE);
7009ad4f2d0SMatthew N. Dodd 	}
7019ad4f2d0SMatthew N. Dodd 
702d50a71bdSMitsuru IWASAKI 	restart();
703d50a71bdSMitsuru IWASAKI 	write_pid();
704d50a71bdSMitsuru IWASAKI 	event_loop();
705d50a71bdSMitsuru IWASAKI 	exit(EXIT_SUCCESS);
706d50a71bdSMitsuru IWASAKI }
707d50a71bdSMitsuru IWASAKI 
708