xref: /freebsd/usr.sbin/apmd/apmd.c (revision 75b36243d194b9a94e6f388753445331efa322cd)
1d50a71bdSMitsuru IWASAKI /*-
2d50a71bdSMitsuru IWASAKI  * APM (Advanced Power Management) Event Dispatcher
3d50a71bdSMitsuru IWASAKI  *
4d50a71bdSMitsuru IWASAKI  * Copyright (c) 1999 Mitsuru IWASAKI <iwasaki@FreeBSD.org>
5d50a71bdSMitsuru IWASAKI  * Copyright (c) 1999 KOIE Hidetaka <koie@suri.co.jp>
6d50a71bdSMitsuru IWASAKI  * All rights reserved.
7d50a71bdSMitsuru IWASAKI  *
8d50a71bdSMitsuru IWASAKI  * Redistribution and use in source and binary forms, with or without
9d50a71bdSMitsuru IWASAKI  * modification, are permitted provided that the following conditions
10d50a71bdSMitsuru IWASAKI  * are met:
11d50a71bdSMitsuru IWASAKI  * 1. Redistributions of source code must retain the above copyright
12d50a71bdSMitsuru IWASAKI  *    notice, this list of conditions and the following disclaimer.
13d50a71bdSMitsuru IWASAKI  * 2. Redistributions in binary form must reproduce the above copyright
14d50a71bdSMitsuru IWASAKI  *    notice, this list of conditions and the following disclaimer in the
15d50a71bdSMitsuru IWASAKI  *    documentation and/or other materials provided with the distribution.
16d50a71bdSMitsuru IWASAKI  *
17d50a71bdSMitsuru IWASAKI  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18d50a71bdSMitsuru IWASAKI  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19d50a71bdSMitsuru IWASAKI  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20d50a71bdSMitsuru IWASAKI  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21d50a71bdSMitsuru IWASAKI  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22d50a71bdSMitsuru IWASAKI  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23d50a71bdSMitsuru IWASAKI  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24d50a71bdSMitsuru IWASAKI  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25d50a71bdSMitsuru IWASAKI  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26d50a71bdSMitsuru IWASAKI  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27d50a71bdSMitsuru IWASAKI  * SUCH DAMAGE.
28d50a71bdSMitsuru IWASAKI  */
29d50a71bdSMitsuru IWASAKI 
30d50a71bdSMitsuru IWASAKI #ifndef lint
31d50a71bdSMitsuru IWASAKI static const char rcsid[] =
3297d92980SPeter Wemm   "$FreeBSD$";
33d50a71bdSMitsuru IWASAKI #endif /* not lint */
34d50a71bdSMitsuru IWASAKI 
35d50a71bdSMitsuru IWASAKI #include <assert.h>
36d50a71bdSMitsuru IWASAKI #include <bitstring.h>
37d50a71bdSMitsuru IWASAKI #include <err.h>
38d50a71bdSMitsuru IWASAKI #include <errno.h>
39d50a71bdSMitsuru IWASAKI #include <fcntl.h>
40d50a71bdSMitsuru IWASAKI #include <paths.h>
41d50a71bdSMitsuru IWASAKI #include <signal.h>
42d50a71bdSMitsuru IWASAKI #include <stdio.h>
43d50a71bdSMitsuru IWASAKI #include <stdlib.h>
44d50a71bdSMitsuru IWASAKI #include <string.h>
45d50a71bdSMitsuru IWASAKI #include <syslog.h>
46d50a71bdSMitsuru IWASAKI #include <unistd.h>
47d50a71bdSMitsuru IWASAKI #include <sys/ioctl.h>
48d50a71bdSMitsuru IWASAKI #include <sys/types.h>
49d50a71bdSMitsuru IWASAKI #include <sys/time.h>
50d50a71bdSMitsuru IWASAKI #include <sys/wait.h>
51d50a71bdSMitsuru IWASAKI #include <machine/apm_bios.h>
52d50a71bdSMitsuru IWASAKI 
53d50a71bdSMitsuru IWASAKI #include "apmd.h"
54d50a71bdSMitsuru IWASAKI 
55d50a71bdSMitsuru IWASAKI extern int	yyparse(void);
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:
119d50a71bdSMitsuru IWASAKI 		(void) warn("cannot fork");
120d50a71bdSMitsuru IWASAKI 		goto out;
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);
126d50a71bdSMitsuru IWASAKI 		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  out:
136d50a71bdSMitsuru IWASAKI 	return status;
137d50a71bdSMitsuru IWASAKI }
138d50a71bdSMitsuru IWASAKI void
139d50a71bdSMitsuru IWASAKI event_cmd_exec_dump(void *this, FILE *fp)
140d50a71bdSMitsuru IWASAKI {
141d50a71bdSMitsuru IWASAKI 	fprintf(fp, " \"%s\"", ((struct event_cmd_exec *)this)->line);
142d50a71bdSMitsuru IWASAKI }
143d50a71bdSMitsuru IWASAKI struct event_cmd *
144d50a71bdSMitsuru IWASAKI event_cmd_exec_clone(void *this)
145d50a71bdSMitsuru IWASAKI {
146d50a71bdSMitsuru IWASAKI 	struct event_cmd_exec * newone = (struct event_cmd_exec *) event_cmd_default_clone(this);
147d50a71bdSMitsuru IWASAKI 	struct event_cmd_exec * oldone = this;
148d50a71bdSMitsuru IWASAKI 
149d50a71bdSMitsuru IWASAKI 	newone->evcmd.next = NULL;
150d50a71bdSMitsuru IWASAKI 	newone->evcmd.len = oldone->evcmd.len;
151d50a71bdSMitsuru IWASAKI 	newone->evcmd.name = oldone->evcmd.name;
152d50a71bdSMitsuru IWASAKI 	newone->evcmd.op = oldone->evcmd.op;
153aecdf0ebSChris D. Faulhaber 	if ((newone->line = strdup(oldone->line)) == NULL)
154aecdf0ebSChris D. Faulhaber 		err(1, "out of memory");
155d50a71bdSMitsuru IWASAKI 	return (struct event_cmd *) newone;
156d50a71bdSMitsuru IWASAKI }
157d50a71bdSMitsuru IWASAKI void
158d50a71bdSMitsuru IWASAKI event_cmd_exec_free(void *this)
159d50a71bdSMitsuru IWASAKI {
160d50a71bdSMitsuru IWASAKI 	free(((struct event_cmd_exec *)this)->line);
161d50a71bdSMitsuru IWASAKI }
162d50a71bdSMitsuru IWASAKI struct event_cmd_op event_cmd_exec_ops = {
163d50a71bdSMitsuru IWASAKI 	event_cmd_exec_act,
164d50a71bdSMitsuru IWASAKI 	event_cmd_exec_dump,
165d50a71bdSMitsuru IWASAKI 	event_cmd_exec_clone,
166d50a71bdSMitsuru IWASAKI 	event_cmd_exec_free
167d50a71bdSMitsuru IWASAKI };
168d50a71bdSMitsuru IWASAKI 
169d50a71bdSMitsuru IWASAKI /*
170d50a71bdSMitsuru IWASAKI  * reject commad
171d50a71bdSMitsuru IWASAKI  */
172d50a71bdSMitsuru IWASAKI int
173d50a71bdSMitsuru IWASAKI event_cmd_reject_act(void *this)
174d50a71bdSMitsuru IWASAKI {
175d50a71bdSMitsuru IWASAKI 	int rc = -1;
176d50a71bdSMitsuru IWASAKI 
177d50a71bdSMitsuru IWASAKI 	if (ioctl(apmctl_fd, APMIO_REJECTLASTREQ, NULL)) {
178d50a71bdSMitsuru IWASAKI 		syslog(LOG_NOTICE, "fail to reject\n");
179d50a71bdSMitsuru IWASAKI 		goto out;
180d50a71bdSMitsuru IWASAKI 	}
181d50a71bdSMitsuru IWASAKI 	rc = 0;
182d50a71bdSMitsuru IWASAKI  out:
183d50a71bdSMitsuru IWASAKI 	return rc;
184d50a71bdSMitsuru IWASAKI }
185d50a71bdSMitsuru IWASAKI struct event_cmd_op event_cmd_reject_ops = {
186d50a71bdSMitsuru IWASAKI 	event_cmd_reject_act,
187d50a71bdSMitsuru IWASAKI 	NULL,
188d50a71bdSMitsuru IWASAKI 	event_cmd_default_clone,
189d50a71bdSMitsuru IWASAKI 	NULL
190d50a71bdSMitsuru IWASAKI };
191d50a71bdSMitsuru IWASAKI 
192d50a71bdSMitsuru IWASAKI /*
193d50a71bdSMitsuru IWASAKI  * manipulate event_config
194d50a71bdSMitsuru IWASAKI  */
195d50a71bdSMitsuru IWASAKI struct event_cmd *
196d50a71bdSMitsuru IWASAKI clone_event_cmd_list(struct event_cmd *p)
197d50a71bdSMitsuru IWASAKI {
198d50a71bdSMitsuru IWASAKI 	struct event_cmd dummy;
199d50a71bdSMitsuru IWASAKI 	struct event_cmd *q = &dummy;
200d50a71bdSMitsuru IWASAKI 	for ( ;p; p = p->next) {
201d50a71bdSMitsuru IWASAKI 		assert(p->op->clone);
202d50a71bdSMitsuru IWASAKI 		if ((q->next = p->op->clone(p)) == NULL)
203d50a71bdSMitsuru IWASAKI 			(void) err(1, "out of memory");
204d50a71bdSMitsuru IWASAKI 		q = q->next;
205d50a71bdSMitsuru IWASAKI 	}
206d50a71bdSMitsuru IWASAKI 	q->next = NULL;
207d50a71bdSMitsuru IWASAKI 	return dummy.next;
208d50a71bdSMitsuru IWASAKI }
209d50a71bdSMitsuru IWASAKI void
210d50a71bdSMitsuru IWASAKI free_event_cmd_list(struct event_cmd *p)
211d50a71bdSMitsuru IWASAKI {
212d50a71bdSMitsuru IWASAKI 	struct event_cmd * q;
213d50a71bdSMitsuru IWASAKI 	for ( ; p ; p = q) {
214d50a71bdSMitsuru IWASAKI 		q = p->next;
215d50a71bdSMitsuru IWASAKI 		if (p->op->free)
216d50a71bdSMitsuru IWASAKI 			p->op->free(p);
217d50a71bdSMitsuru IWASAKI 		free(p);
218d50a71bdSMitsuru IWASAKI 	}
219d50a71bdSMitsuru IWASAKI }
220d50a71bdSMitsuru IWASAKI int
221719b9dc1SNick Sayer register_battery_handlers(
222719b9dc1SNick Sayer 	int level, int direction,
223719b9dc1SNick Sayer 	struct event_cmd *cmdlist)
224719b9dc1SNick Sayer {
225719b9dc1SNick Sayer 	/*
226719b9dc1SNick Sayer 	 * level is negative if it's in "minutes", non-negative if
227719b9dc1SNick Sayer 	 * percentage.
228719b9dc1SNick Sayer 	 *
229719b9dc1SNick Sayer 	 * direction =1 means we care about this level when charging,
230719b9dc1SNick Sayer 	 * direction =-1 means we care about it when discharging.
231719b9dc1SNick Sayer 	 */
232719b9dc1SNick Sayer 	if (level>100) /* percentage > 100 */
233719b9dc1SNick Sayer 		return -1;
234719b9dc1SNick Sayer 	if (abs(direction) != 1) /* nonsense direction value */
235719b9dc1SNick Sayer 		return -1;
236719b9dc1SNick Sayer 
237719b9dc1SNick Sayer 	if (cmdlist) {
238719b9dc1SNick Sayer 		struct battery_watch_event *we;
239719b9dc1SNick Sayer 
240719b9dc1SNick Sayer 		if ((we = malloc(sizeof(struct battery_watch_event))) == NULL)
241719b9dc1SNick Sayer 			(void) err(1, "out of memory");
242719b9dc1SNick Sayer 
243719b9dc1SNick Sayer 		we->next = battery_watch_list; /* starts at NULL */
244719b9dc1SNick Sayer 		battery_watch_list = we;
245719b9dc1SNick Sayer 		we->level = abs(level);
246719b9dc1SNick Sayer 		we->type = (level<0)?BATTERY_MINUTES:BATTERY_PERCENT;
247719b9dc1SNick Sayer 		we->direction = (direction<0)?BATTERY_DISCHARGING:
248719b9dc1SNick Sayer 			BATTERY_CHARGING;
249719b9dc1SNick Sayer 		we->done = 0;
250719b9dc1SNick Sayer 		we->cmdlist = clone_event_cmd_list(cmdlist);
251719b9dc1SNick Sayer 	}
252719b9dc1SNick Sayer 	return 0;
253719b9dc1SNick Sayer }
254719b9dc1SNick Sayer int
255d50a71bdSMitsuru IWASAKI register_apm_event_handlers(
256d50a71bdSMitsuru IWASAKI 	bitstr_t bit_decl(evlist, EVENT_MAX),
257d50a71bdSMitsuru IWASAKI 	struct event_cmd *cmdlist)
258d50a71bdSMitsuru IWASAKI {
259d50a71bdSMitsuru IWASAKI 	if (cmdlist) {
260d50a71bdSMitsuru IWASAKI 		bitstr_t bit_decl(tmp, EVENT_MAX);
261d50a71bdSMitsuru IWASAKI 		memcpy(&tmp, evlist, bitstr_size(EVENT_MAX));
262d50a71bdSMitsuru IWASAKI 
263d50a71bdSMitsuru IWASAKI 		for (;;) {
264d50a71bdSMitsuru IWASAKI 			int n;
265d50a71bdSMitsuru IWASAKI 			struct event_cmd *p;
266d50a71bdSMitsuru IWASAKI 			struct event_cmd *q;
267d50a71bdSMitsuru IWASAKI 			bit_ffs(tmp, EVENT_MAX, &n);
268d50a71bdSMitsuru IWASAKI 			if (n < 0)
269d50a71bdSMitsuru IWASAKI 				break;
270d50a71bdSMitsuru IWASAKI 			p = events[n].cmdlist;
271d50a71bdSMitsuru IWASAKI 			if ((q = clone_event_cmd_list(cmdlist)) == NULL)
272d50a71bdSMitsuru IWASAKI 				(void) err(1, "out of memory");
273d50a71bdSMitsuru IWASAKI 			if (p) {
274d50a71bdSMitsuru IWASAKI 				while (p->next != NULL)
275d50a71bdSMitsuru IWASAKI 					p = p->next;
276d50a71bdSMitsuru IWASAKI 				p->next = q;
277d50a71bdSMitsuru IWASAKI 			} else {
278d50a71bdSMitsuru IWASAKI 				events[n].cmdlist = q;
279d50a71bdSMitsuru IWASAKI 			}
280d50a71bdSMitsuru IWASAKI 			bit_clear(tmp, n);
281d50a71bdSMitsuru IWASAKI 		}
282d50a71bdSMitsuru IWASAKI 	}
283d50a71bdSMitsuru IWASAKI 	return 0;
284d50a71bdSMitsuru IWASAKI }
285d50a71bdSMitsuru IWASAKI 
286d50a71bdSMitsuru IWASAKI /*
287d50a71bdSMitsuru IWASAKI  * execute command
288d50a71bdSMitsuru IWASAKI  */
289d50a71bdSMitsuru IWASAKI int
290719b9dc1SNick Sayer exec_run_cmd(struct event_cmd *p)
291d50a71bdSMitsuru IWASAKI {
292d50a71bdSMitsuru IWASAKI 	int status = 0;
293d50a71bdSMitsuru IWASAKI 
294d50a71bdSMitsuru IWASAKI 	for (; p; p = p->next) {
295d50a71bdSMitsuru IWASAKI 		assert(p->op->act);
296d50a71bdSMitsuru IWASAKI 		if (verbose)
297d50a71bdSMitsuru IWASAKI 			syslog(LOG_INFO, "action: %s", p->name);
298d50a71bdSMitsuru IWASAKI 		status = p->op->act(p);
299d50a71bdSMitsuru IWASAKI 		if (status) {
300d50a71bdSMitsuru IWASAKI 			syslog(LOG_NOTICE, "command finished with %d\n", status);
301d50a71bdSMitsuru IWASAKI 			break;
302d50a71bdSMitsuru IWASAKI 		}
303d50a71bdSMitsuru IWASAKI 	}
304d50a71bdSMitsuru IWASAKI 	return status;
305d50a71bdSMitsuru IWASAKI }
306d50a71bdSMitsuru IWASAKI 
307d50a71bdSMitsuru IWASAKI /*
308719b9dc1SNick Sayer  * execute command -- the event version
309719b9dc1SNick Sayer  */
310719b9dc1SNick Sayer int
311719b9dc1SNick Sayer exec_event_cmd(struct event_config *ev)
312719b9dc1SNick Sayer {
313719b9dc1SNick Sayer 	int status = 0;
314719b9dc1SNick Sayer 
315719b9dc1SNick Sayer 	status = exec_run_cmd(ev->cmdlist);
316719b9dc1SNick Sayer 	if (status && ev->rejectable) {
317719b9dc1SNick Sayer 		syslog(LOG_ERR, "canceled");
318719b9dc1SNick Sayer 		(void) event_cmd_reject_act(NULL);
319719b9dc1SNick Sayer 	}
320719b9dc1SNick Sayer 	return status;
321719b9dc1SNick Sayer }
322719b9dc1SNick Sayer 
323719b9dc1SNick Sayer /*
324d50a71bdSMitsuru IWASAKI  * read config file
325d50a71bdSMitsuru IWASAKI  */
326d50a71bdSMitsuru IWASAKI extern FILE * yyin;
327d50a71bdSMitsuru IWASAKI extern int yydebug;
328d50a71bdSMitsuru IWASAKI 
329d50a71bdSMitsuru IWASAKI void
330d50a71bdSMitsuru IWASAKI read_config(void)
331d50a71bdSMitsuru IWASAKI {
332d50a71bdSMitsuru IWASAKI 	int i;
333d50a71bdSMitsuru IWASAKI 
334d50a71bdSMitsuru IWASAKI 	if ((yyin = fopen(apmd_configfile, "r")) == NULL) {
335d50a71bdSMitsuru IWASAKI 		(void) err(1, "cannot open config file");
336d50a71bdSMitsuru IWASAKI 	}
337d50a71bdSMitsuru IWASAKI 
338d50a71bdSMitsuru IWASAKI #ifdef DEBUG
339d50a71bdSMitsuru IWASAKI 	yydebug = debug_level;
340d50a71bdSMitsuru IWASAKI #endif
341d50a71bdSMitsuru IWASAKI 
342d50a71bdSMitsuru IWASAKI 	if (yyparse() != 0)
343d50a71bdSMitsuru IWASAKI 		(void) err(1, "cannot parse config file");
344d50a71bdSMitsuru IWASAKI 
345d50a71bdSMitsuru IWASAKI 	fclose(yyin);
346d50a71bdSMitsuru IWASAKI 
347d50a71bdSMitsuru IWASAKI 	/* enable events */
348d50a71bdSMitsuru IWASAKI 	for (i = 0; i < EVENT_MAX; i++) {
349d50a71bdSMitsuru IWASAKI 		if (events[i].cmdlist) {
350d50a71bdSMitsuru IWASAKI 			u_int event_type = i;
351d50a71bdSMitsuru IWASAKI 			if (write(apmctl_fd, &event_type, sizeof(u_int)) == -1) {
352d50a71bdSMitsuru IWASAKI 				(void) err(1, "cannot enable event 0x%x", event_type);
353d50a71bdSMitsuru IWASAKI 			}
354d50a71bdSMitsuru IWASAKI 		}
355d50a71bdSMitsuru IWASAKI 	}
356d50a71bdSMitsuru IWASAKI }
357d50a71bdSMitsuru IWASAKI 
358d50a71bdSMitsuru IWASAKI void
359d50a71bdSMitsuru IWASAKI dump_config()
360d50a71bdSMitsuru IWASAKI {
361d50a71bdSMitsuru IWASAKI 	int i;
362719b9dc1SNick Sayer 	struct battery_watch_event *q;
363d50a71bdSMitsuru IWASAKI 
364d50a71bdSMitsuru IWASAKI 	for (i = 0; i < EVENT_MAX; i++) {
365d50a71bdSMitsuru IWASAKI 		struct event_cmd * p;
366d50a71bdSMitsuru IWASAKI 		if ((p = events[i].cmdlist)) {
367d50a71bdSMitsuru IWASAKI 			fprintf(stderr, "apm_event %s {\n", events[i].name);
368d50a71bdSMitsuru IWASAKI 			for ( ; p ; p = p->next) {
369d50a71bdSMitsuru IWASAKI 				fprintf(stderr, "\t%s", p->name);
370d50a71bdSMitsuru IWASAKI 				if (p->op->dump)
371d50a71bdSMitsuru IWASAKI 					p->op->dump(p, stderr);
372d50a71bdSMitsuru IWASAKI 				fprintf(stderr, ";\n");
373d50a71bdSMitsuru IWASAKI 			}
374d50a71bdSMitsuru IWASAKI 			fprintf(stderr, "}\n");
375d50a71bdSMitsuru IWASAKI 		}
376d50a71bdSMitsuru IWASAKI 	}
377719b9dc1SNick Sayer 	for (q = battery_watch_list ; q != NULL ; q = q -> next) {
378719b9dc1SNick Sayer 		struct event_cmd * p;
379719b9dc1SNick Sayer 		fprintf(stderr, "apm_battery %d%s %s {\n",
380719b9dc1SNick Sayer 			q -> level,
381719b9dc1SNick Sayer 			(q -> type == BATTERY_PERCENT)?"%":"m",
382719b9dc1SNick Sayer 			(q -> direction == BATTERY_CHARGING)?"charging":
383719b9dc1SNick Sayer 				"discharging");
384719b9dc1SNick Sayer 		for ( p = q -> cmdlist; p ; p = p->next) {
385719b9dc1SNick Sayer 			fprintf(stderr, "\t%s", p->name);
386719b9dc1SNick Sayer 			if (p->op->dump)
387719b9dc1SNick Sayer 				p->op->dump(p, stderr);
388719b9dc1SNick Sayer 			fprintf(stderr, ";\n");
389719b9dc1SNick Sayer 		}
390719b9dc1SNick Sayer 		fprintf(stderr, "}\n");
391719b9dc1SNick Sayer 	}
392d50a71bdSMitsuru IWASAKI }
393d50a71bdSMitsuru IWASAKI 
394d50a71bdSMitsuru IWASAKI void
395d50a71bdSMitsuru IWASAKI destroy_config()
396d50a71bdSMitsuru IWASAKI {
397d50a71bdSMitsuru IWASAKI 	int i;
398719b9dc1SNick Sayer 	struct battery_watch_event *q;
399d50a71bdSMitsuru IWASAKI 
400d50a71bdSMitsuru IWASAKI 	/* disable events */
401d50a71bdSMitsuru IWASAKI 	for (i = 0; i < EVENT_MAX; i++) {
402d50a71bdSMitsuru IWASAKI 		if (events[i].cmdlist) {
403d50a71bdSMitsuru IWASAKI 			u_int event_type = i;
404d50a71bdSMitsuru IWASAKI 			if (write(apmctl_fd, &event_type, sizeof(u_int)) == -1) {
405d50a71bdSMitsuru IWASAKI 				(void) err(1, "cannot disable event 0x%x", event_type);
406d50a71bdSMitsuru IWASAKI 			}
407d50a71bdSMitsuru IWASAKI 		}
408d50a71bdSMitsuru IWASAKI 	}
409d50a71bdSMitsuru IWASAKI 
410d50a71bdSMitsuru IWASAKI 	for (i = 0; i < EVENT_MAX; i++) {
411d50a71bdSMitsuru IWASAKI 		struct event_cmd * p;
412d50a71bdSMitsuru IWASAKI 		if ((p = events[i].cmdlist))
413d50a71bdSMitsuru IWASAKI 			free_event_cmd_list(p);
414d50a71bdSMitsuru IWASAKI 		events[i].cmdlist = NULL;
415d50a71bdSMitsuru IWASAKI 	}
416719b9dc1SNick Sayer 
417719b9dc1SNick Sayer 	for( ; battery_watch_list; battery_watch_list = battery_watch_list -> next) {
418719b9dc1SNick Sayer 		free_event_cmd_list(battery_watch_list->cmdlist);
419719b9dc1SNick Sayer 		q = battery_watch_list->next;
420719b9dc1SNick Sayer 		free(battery_watch_list);
421719b9dc1SNick Sayer 		battery_watch_list = q;
422719b9dc1SNick Sayer 	}
423d50a71bdSMitsuru IWASAKI }
424d50a71bdSMitsuru IWASAKI 
425d50a71bdSMitsuru IWASAKI void
426d50a71bdSMitsuru IWASAKI restart()
427d50a71bdSMitsuru IWASAKI {
428d50a71bdSMitsuru IWASAKI 	destroy_config();
429d50a71bdSMitsuru IWASAKI 	read_config();
430d50a71bdSMitsuru IWASAKI 	if (verbose)
431d50a71bdSMitsuru IWASAKI 		dump_config();
432d50a71bdSMitsuru IWASAKI }
433d50a71bdSMitsuru IWASAKI 
434d50a71bdSMitsuru IWASAKI /*
435d50a71bdSMitsuru IWASAKI  * write pid file
436d50a71bdSMitsuru IWASAKI  */
437d50a71bdSMitsuru IWASAKI static void
438d50a71bdSMitsuru IWASAKI write_pid()
439d50a71bdSMitsuru IWASAKI {
440d50a71bdSMitsuru IWASAKI 	FILE *fp = fopen(apmd_pidfile, "w");
441d50a71bdSMitsuru IWASAKI 
442d50a71bdSMitsuru IWASAKI 	if (fp) {
443d50a71bdSMitsuru IWASAKI 		fprintf(fp, "%d\n", getpid());
444d50a71bdSMitsuru IWASAKI 		fclose(fp);
445d50a71bdSMitsuru IWASAKI 	}
446d50a71bdSMitsuru IWASAKI }
447d50a71bdSMitsuru IWASAKI 
448d50a71bdSMitsuru IWASAKI /*
449d50a71bdSMitsuru IWASAKI  * handle signals
450d50a71bdSMitsuru IWASAKI  */
451d50a71bdSMitsuru IWASAKI static int signal_fd[2];
452d50a71bdSMitsuru IWASAKI 
453d50a71bdSMitsuru IWASAKI void
454d50a71bdSMitsuru IWASAKI enque_signal(int sig)
455d50a71bdSMitsuru IWASAKI {
456d50a71bdSMitsuru IWASAKI 	if (write(signal_fd[1], &sig, sizeof sig) != sizeof sig)
457d50a71bdSMitsuru IWASAKI 		(void) err(1, "cannot process signal.");
458d50a71bdSMitsuru IWASAKI }
459d50a71bdSMitsuru IWASAKI 
460d50a71bdSMitsuru IWASAKI void
461d50a71bdSMitsuru IWASAKI wait_child()
462d50a71bdSMitsuru IWASAKI {
463d50a71bdSMitsuru IWASAKI 	int status;
464d50a71bdSMitsuru IWASAKI 	while (waitpid(-1, &status, WNOHANG) > 0)
465d50a71bdSMitsuru IWASAKI 		;
466d50a71bdSMitsuru IWASAKI }
467d50a71bdSMitsuru IWASAKI 
468d50a71bdSMitsuru IWASAKI int
469d50a71bdSMitsuru IWASAKI proc_signal(int fd)
470d50a71bdSMitsuru IWASAKI {
471d50a71bdSMitsuru IWASAKI 	int rc = -1;
472d50a71bdSMitsuru IWASAKI 	int sig;
473d50a71bdSMitsuru IWASAKI 
474d50a71bdSMitsuru IWASAKI 	while (read(fd, &sig, sizeof sig) == sizeof sig) {
475d50a71bdSMitsuru IWASAKI 		syslog(LOG_INFO, "caught signal: %d", sig);
476d50a71bdSMitsuru IWASAKI 		switch (sig) {
477d50a71bdSMitsuru IWASAKI 		case SIGHUP:
478d50a71bdSMitsuru IWASAKI 			syslog(LOG_NOTICE, "restart by SIG");
479d50a71bdSMitsuru IWASAKI 			restart();
480d50a71bdSMitsuru IWASAKI 			break;
481d50a71bdSMitsuru IWASAKI 		case SIGTERM:
482d50a71bdSMitsuru IWASAKI 			syslog(LOG_NOTICE, "going down on signal %d", sig);
483f90445cfSMatthew N. Dodd 			rc = -1;
484d50a71bdSMitsuru IWASAKI 			goto out;
485d50a71bdSMitsuru IWASAKI 		case SIGCHLD:
486d50a71bdSMitsuru IWASAKI 			wait_child();
487d50a71bdSMitsuru IWASAKI 			break;
488d50a71bdSMitsuru IWASAKI 		default:
489d50a71bdSMitsuru IWASAKI 			(void) warn("unexpected signal(%d) received.", sig);
490d50a71bdSMitsuru IWASAKI 			break;
491d50a71bdSMitsuru IWASAKI 		}
492d50a71bdSMitsuru IWASAKI 	}
493d50a71bdSMitsuru IWASAKI 	rc = 0;
494d50a71bdSMitsuru IWASAKI  out:
495d50a71bdSMitsuru IWASAKI 	return rc;
496d50a71bdSMitsuru IWASAKI }
497d50a71bdSMitsuru IWASAKI void
498d50a71bdSMitsuru IWASAKI proc_apmevent(int fd)
499d50a71bdSMitsuru IWASAKI {
500d50a71bdSMitsuru IWASAKI 	struct apm_event_info apmevent;
501d50a71bdSMitsuru IWASAKI 
502d50a71bdSMitsuru IWASAKI 	while (ioctl(fd, APMIO_NEXTEVENT, &apmevent) == 0) {
503d50a71bdSMitsuru IWASAKI 		int status;
504d50a71bdSMitsuru IWASAKI 		syslog(LOG_NOTICE, "apmevent %04x index %d\n",
505d50a71bdSMitsuru IWASAKI 			apmevent.type, apmevent.index);
506d50a71bdSMitsuru IWASAKI 		syslog(LOG_INFO, "apm event: %s", events[apmevent.type].name);
507d50a71bdSMitsuru IWASAKI 		if (fork() == 0) {
508d50a71bdSMitsuru IWASAKI 			status = exec_event_cmd(&events[apmevent.type]);
509d50a71bdSMitsuru IWASAKI 			exit(status);
510d50a71bdSMitsuru IWASAKI 		}
511d50a71bdSMitsuru IWASAKI 	}
512d50a71bdSMitsuru IWASAKI }
513719b9dc1SNick Sayer 
514719b9dc1SNick Sayer #define AC_POWER_STATE ((pw_info.ai_acline == 1) ? BATTERY_CHARGING :\
515719b9dc1SNick Sayer 	BATTERY_DISCHARGING)
516719b9dc1SNick Sayer 
517719b9dc1SNick Sayer void
518719b9dc1SNick Sayer check_battery()
519719b9dc1SNick Sayer {
520719b9dc1SNick Sayer 
521719b9dc1SNick Sayer 	static int first_time=1, last_state;
522f90445cfSMatthew N. Dodd 	int status;
523719b9dc1SNick Sayer 
524719b9dc1SNick Sayer 	struct apm_info pw_info;
525719b9dc1SNick Sayer 	struct battery_watch_event *p;
526719b9dc1SNick Sayer 
527719b9dc1SNick Sayer 	/* If we don't care, don't bother */
528719b9dc1SNick Sayer 	if (battery_watch_list == NULL)
529719b9dc1SNick Sayer 		return;
530719b9dc1SNick Sayer 
531719b9dc1SNick Sayer 	if (first_time) {
532719b9dc1SNick Sayer 		if ( ioctl(apmnorm_fd, APMIO_GETINFO, &pw_info) < 0)
533719b9dc1SNick Sayer 			(void) err(1, "cannot check battery state.");
534719b9dc1SNick Sayer /*
535719b9dc1SNick Sayer  * This next statement isn't entirely true. The spec does not tie AC
536719b9dc1SNick Sayer  * line state to battery charging or not, but this is a bit lazier to do.
537719b9dc1SNick Sayer  */
538719b9dc1SNick Sayer 		last_state = AC_POWER_STATE;
539719b9dc1SNick Sayer 		first_time = 0;
540719b9dc1SNick Sayer 		return; /* We can't process events, we have no baseline */
541719b9dc1SNick Sayer 	}
542719b9dc1SNick Sayer 
543719b9dc1SNick Sayer 	/*
544719b9dc1SNick Sayer 	 * XXX - should we do this a bunch of times and perform some sort
545719b9dc1SNick Sayer 	 * of smoothing or correction?
546719b9dc1SNick Sayer 	 */
547719b9dc1SNick Sayer 	if ( ioctl(apmnorm_fd, APMIO_GETINFO, &pw_info) < 0)
548719b9dc1SNick Sayer 		(void) err(1, "cannot check battery state.");
549719b9dc1SNick Sayer 
550719b9dc1SNick Sayer 	/*
551719b9dc1SNick Sayer 	 * If we're not in the state now that we were in last time,
552719b9dc1SNick Sayer 	 * then it's a transition, which means we must clean out
553719b9dc1SNick Sayer 	 * the event-caught state.
554719b9dc1SNick Sayer 	 */
555719b9dc1SNick Sayer 	if (last_state != AC_POWER_STATE) {
556f90445cfSMatthew N. Dodd 		if (soft_power_state_change && fork() == 0) {
557f90445cfSMatthew N. Dodd 			status = exec_event_cmd(&events[PMEV_POWERSTATECHANGE]);
558f90445cfSMatthew N. Dodd 			exit(status);
559f90445cfSMatthew N. Dodd 		}
560719b9dc1SNick Sayer 		last_state = AC_POWER_STATE;
561719b9dc1SNick Sayer 		for (p = battery_watch_list ; p!=NULL ; p = p -> next)
562719b9dc1SNick Sayer 			p->done = 0;
563719b9dc1SNick Sayer 	}
564719b9dc1SNick Sayer 	for (p = battery_watch_list ; p != NULL ; p = p -> next)
565719b9dc1SNick Sayer 		if (p -> direction == AC_POWER_STATE &&
566719b9dc1SNick Sayer 			!(p -> done) &&
567719b9dc1SNick Sayer 			((p -> type == BATTERY_PERCENT &&
568719b9dc1SNick Sayer 				p -> level == pw_info.ai_batt_life) ||
569719b9dc1SNick Sayer 			(p -> type == BATTERY_MINUTES &&
570719b9dc1SNick Sayer 				p -> level == (pw_info.ai_batt_time / 60)))) {
571719b9dc1SNick Sayer 			p -> done++;
572719b9dc1SNick Sayer 			if (verbose)
573719b9dc1SNick Sayer 				syslog(LOG_NOTICE, "Caught battery event: %s, %d%s",
574719b9dc1SNick Sayer 					(p -> direction == BATTERY_CHARGING)?"charging":"discharging",
575719b9dc1SNick Sayer 					p -> level,
576719b9dc1SNick Sayer 					(p -> type == BATTERY_PERCENT)?"%":" minutes");
577719b9dc1SNick Sayer 			if (fork() == 0) {
578719b9dc1SNick Sayer 				status = exec_run_cmd(p -> cmdlist);
579719b9dc1SNick Sayer 				exit(status);
580719b9dc1SNick Sayer 			}
581719b9dc1SNick Sayer 		}
582719b9dc1SNick Sayer }
583d50a71bdSMitsuru IWASAKI void
584d50a71bdSMitsuru IWASAKI event_loop(void)
585d50a71bdSMitsuru IWASAKI {
586d50a71bdSMitsuru IWASAKI 	int		fdmax = 0;
587d50a71bdSMitsuru IWASAKI 	struct sigaction nsa;
588d50a71bdSMitsuru IWASAKI 	fd_set          master_rfds;
589d50a71bdSMitsuru IWASAKI 	sigset_t	sigmask, osigmask;
590d50a71bdSMitsuru IWASAKI 
591d50a71bdSMitsuru IWASAKI 	FD_ZERO(&master_rfds);
592d50a71bdSMitsuru IWASAKI 	FD_SET(apmctl_fd, &master_rfds);
593d50a71bdSMitsuru IWASAKI 	fdmax = apmctl_fd > fdmax ? apmctl_fd : fdmax;
594d50a71bdSMitsuru IWASAKI 
595d50a71bdSMitsuru IWASAKI 	FD_SET(signal_fd[0], &master_rfds);
596d50a71bdSMitsuru IWASAKI 	fdmax = signal_fd[0] > fdmax ? signal_fd[0] : fdmax;
597d50a71bdSMitsuru IWASAKI 
598d50a71bdSMitsuru IWASAKI 	memset(&nsa, 0, sizeof nsa);
599d50a71bdSMitsuru IWASAKI 	nsa.sa_handler = enque_signal;
600d50a71bdSMitsuru IWASAKI 	sigfillset(&nsa.sa_mask);
601d50a71bdSMitsuru IWASAKI 	nsa.sa_flags = SA_RESTART;
602d50a71bdSMitsuru IWASAKI 	sigaction(SIGHUP, &nsa, NULL);
603d50a71bdSMitsuru IWASAKI 	sigaction(SIGCHLD, &nsa, NULL);
604d50a71bdSMitsuru IWASAKI 	sigaction(SIGTERM, &nsa, NULL);
605d50a71bdSMitsuru IWASAKI 
606d50a71bdSMitsuru IWASAKI 	sigemptyset(&sigmask);
607d50a71bdSMitsuru IWASAKI 	sigaddset(&sigmask, SIGHUP);
608d50a71bdSMitsuru IWASAKI 	sigaddset(&sigmask, SIGCHLD);
609d50a71bdSMitsuru IWASAKI 	sigaddset(&sigmask, SIGTERM);
610d50a71bdSMitsuru IWASAKI 	sigprocmask(SIG_SETMASK, &sigmask, &osigmask);
611d50a71bdSMitsuru IWASAKI 
612d50a71bdSMitsuru IWASAKI 	while (1) {
613d50a71bdSMitsuru IWASAKI 		fd_set rfds;
614719b9dc1SNick Sayer 		int res;
615719b9dc1SNick Sayer 		struct timeval to;
616719b9dc1SNick Sayer 
617719b9dc1SNick Sayer 		to.tv_sec = BATT_CHK_INTV;
618719b9dc1SNick Sayer 		to.tv_usec = 0;
619d50a71bdSMitsuru IWASAKI 
620d50a71bdSMitsuru IWASAKI 		memcpy(&rfds, &master_rfds, sizeof rfds);
621d50a71bdSMitsuru IWASAKI 		sigprocmask(SIG_SETMASK, &osigmask, NULL);
622719b9dc1SNick Sayer 		if ((res=select(fdmax + 1, &rfds, 0, 0, &to)) < 0) {
623d50a71bdSMitsuru IWASAKI 			if (errno != EINTR)
624d50a71bdSMitsuru IWASAKI 				(void) err(1, "select");
625d50a71bdSMitsuru IWASAKI 		}
626d50a71bdSMitsuru IWASAKI 		sigprocmask(SIG_SETMASK, &sigmask, NULL);
627d50a71bdSMitsuru IWASAKI 
628719b9dc1SNick Sayer 		if (res == 0) { /* time to check the battery */
629719b9dc1SNick Sayer 			check_battery();
630719b9dc1SNick Sayer 			continue;
631719b9dc1SNick Sayer 		}
632719b9dc1SNick Sayer 
633d50a71bdSMitsuru IWASAKI 		if (FD_ISSET(signal_fd[0], &rfds)) {
634d50a71bdSMitsuru IWASAKI 			if (proc_signal(signal_fd[0]) < 0)
635d50a71bdSMitsuru IWASAKI 				goto out;
636d50a71bdSMitsuru IWASAKI 		}
637719b9dc1SNick Sayer 
638d50a71bdSMitsuru IWASAKI 		if (FD_ISSET(apmctl_fd, &rfds))
639d50a71bdSMitsuru IWASAKI 			proc_apmevent(apmctl_fd);
640d50a71bdSMitsuru IWASAKI 	}
641d50a71bdSMitsuru IWASAKI out:
642d50a71bdSMitsuru IWASAKI 	return;
643d50a71bdSMitsuru IWASAKI }
644d50a71bdSMitsuru IWASAKI 
645e46b89dcSPeter Wemm int
646d50a71bdSMitsuru IWASAKI main(int ac, char* av[])
647d50a71bdSMitsuru IWASAKI {
648d50a71bdSMitsuru IWASAKI 	int	ch;
649d50a71bdSMitsuru IWASAKI 	int	daemonize = 1;
650d50a71bdSMitsuru IWASAKI 	char	*prog;
651d50a71bdSMitsuru IWASAKI 	int	logopt = LOG_NDELAY | LOG_PID;
652d50a71bdSMitsuru IWASAKI 
653f90445cfSMatthew N. Dodd 	while ((ch = getopt(ac, av, "df:sv")) != EOF) {
654d50a71bdSMitsuru IWASAKI 		switch (ch) {
655d50a71bdSMitsuru IWASAKI 		case 'd':
656d50a71bdSMitsuru IWASAKI 			daemonize = 0;
657d50a71bdSMitsuru IWASAKI 			debug_level++;
658d50a71bdSMitsuru IWASAKI 			break;
659d50a71bdSMitsuru IWASAKI 		case 'f':
660d50a71bdSMitsuru IWASAKI 			apmd_configfile = optarg;
661d50a71bdSMitsuru IWASAKI 			break;
662f90445cfSMatthew N. Dodd 		case 's':
663f90445cfSMatthew N. Dodd 			soft_power_state_change = 1;
664f90445cfSMatthew N. Dodd 			break;
665d50a71bdSMitsuru IWASAKI 		case 'v':
666d50a71bdSMitsuru IWASAKI 			verbose = 1;
667d50a71bdSMitsuru IWASAKI 			break;
668d50a71bdSMitsuru IWASAKI 		default:
669d50a71bdSMitsuru IWASAKI 			(void) err(1, "unknown option `%c'", ch);
670d50a71bdSMitsuru IWASAKI 		}
671d50a71bdSMitsuru IWASAKI 	}
672d50a71bdSMitsuru IWASAKI 
673d50a71bdSMitsuru IWASAKI 	if (daemonize)
674d50a71bdSMitsuru IWASAKI 		daemon(0, 0);
675d50a71bdSMitsuru IWASAKI 
676d50a71bdSMitsuru IWASAKI #ifdef NICE_INCR
677d50a71bdSMitsuru IWASAKI 	(void) nice(NICE_INCR);
678d50a71bdSMitsuru IWASAKI #endif
679d50a71bdSMitsuru IWASAKI 
680d50a71bdSMitsuru IWASAKI 	if (!daemonize)
681d50a71bdSMitsuru IWASAKI 		logopt |= LOG_PERROR;
682d50a71bdSMitsuru IWASAKI 
683d50a71bdSMitsuru IWASAKI 	prog = strrchr(av[0], '/');
684d50a71bdSMitsuru IWASAKI 	openlog(prog ? prog+1 : av[0], logopt, LOG_DAEMON);
685d50a71bdSMitsuru IWASAKI 
686d50a71bdSMitsuru IWASAKI 	syslog(LOG_NOTICE, "start");
687d50a71bdSMitsuru IWASAKI 
688d50a71bdSMitsuru IWASAKI 	if (pipe(signal_fd) < 0)
689d50a71bdSMitsuru IWASAKI 		(void) err(1, "pipe");
690d50a71bdSMitsuru IWASAKI 	if (fcntl(signal_fd[0], F_SETFL, O_NONBLOCK) < 0)
691d50a71bdSMitsuru IWASAKI 		(void) err(1, "fcntl");
692d50a71bdSMitsuru IWASAKI 
693719b9dc1SNick Sayer 	if ((apmnorm_fd = open(APM_NORM_DEVICEFILE, O_RDWR)) == -1) {
694719b9dc1SNick Sayer 		(void) err(1, "cannot open device file `%s'", APM_NORM_DEVICEFILE);
695719b9dc1SNick Sayer 	}
696719b9dc1SNick Sayer 
6979ad4f2d0SMatthew N. Dodd 	if (fcntl(apmnorm_fd, F_SETFD, 1) == -1) {
6989ad4f2d0SMatthew N. Dodd 		(void) err(1, "cannot set close-on-exec flag for device file '%s'", APM_NORM_DEVICEFILE);
6999ad4f2d0SMatthew N. Dodd 	}
7009ad4f2d0SMatthew N. Dodd 
701d50a71bdSMitsuru IWASAKI 	if ((apmctl_fd = open(APM_CTL_DEVICEFILE, O_RDWR)) == -1) {
702d50a71bdSMitsuru IWASAKI 		(void) err(1, "cannot open device file `%s'", APM_CTL_DEVICEFILE);
703d50a71bdSMitsuru IWASAKI 	}
704d50a71bdSMitsuru IWASAKI 
7059ad4f2d0SMatthew N. Dodd 	if (fcntl(apmctl_fd, F_SETFD, 1) == -1) {
7069ad4f2d0SMatthew N. Dodd 		(void) err(1, "cannot set close-on-exec flag for device file '%s'", APM_CTL_DEVICEFILE);
7079ad4f2d0SMatthew N. Dodd  	}
7089ad4f2d0SMatthew N. Dodd 
709d50a71bdSMitsuru IWASAKI 	restart();
710d50a71bdSMitsuru IWASAKI 	write_pid();
711d50a71bdSMitsuru IWASAKI 	event_loop();
712d50a71bdSMitsuru IWASAKI  	exit(EXIT_SUCCESS);
713d50a71bdSMitsuru IWASAKI }
714d50a71bdSMitsuru IWASAKI 
715