xref: /freebsd/usr.sbin/apmd/apmd.c (revision d50a71bdd882717df3f41dadd84ffc28f3466a1a)
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[] =
32d50a71bdSMitsuru IWASAKI 	"$Id: apmd.c,v 1.1.3.13 1999/06/18 04:07:05 koie Exp $";
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;
59d50a71bdSMitsuru IWASAKI const char	*apmd_configfile = APMD_CONFIGFILE;
60d50a71bdSMitsuru IWASAKI const char	*apmd_pidfile = APMD_PIDFILE;
61d50a71bdSMitsuru IWASAKI int             apmctl_fd = -1;
62d50a71bdSMitsuru IWASAKI 
63d50a71bdSMitsuru IWASAKI /*
64d50a71bdSMitsuru IWASAKI  * table of event handlers
65d50a71bdSMitsuru IWASAKI  */
66d50a71bdSMitsuru IWASAKI #define EVENT_CONFIG_INITIALIZER(EV,R) { #EV, NULL, R },
67d50a71bdSMitsuru IWASAKI struct event_config events[EVENT_MAX] = {
68d50a71bdSMitsuru IWASAKI 	EVENT_CONFIG_INITIALIZER(NOEVENT, 0)
69d50a71bdSMitsuru IWASAKI 	EVENT_CONFIG_INITIALIZER(STANDBYREQ, 1)
70d50a71bdSMitsuru IWASAKI 	EVENT_CONFIG_INITIALIZER(SUSPENDREQ, 1)
71d50a71bdSMitsuru IWASAKI 	EVENT_CONFIG_INITIALIZER(NORMRESUME, 0)
72d50a71bdSMitsuru IWASAKI 	EVENT_CONFIG_INITIALIZER(CRITRESUME, 0)
73d50a71bdSMitsuru IWASAKI 	EVENT_CONFIG_INITIALIZER(BATTERYLOW, 0)
74d50a71bdSMitsuru IWASAKI 	EVENT_CONFIG_INITIALIZER(POWERSTATECHANGE, 0)
75d50a71bdSMitsuru IWASAKI 	EVENT_CONFIG_INITIALIZER(UPDATETIME, 0)
76d50a71bdSMitsuru IWASAKI 	EVENT_CONFIG_INITIALIZER(CRITSUSPEND, 1)
77d50a71bdSMitsuru IWASAKI 	EVENT_CONFIG_INITIALIZER(USERSTANDBYREQ, 1)
78d50a71bdSMitsuru IWASAKI 	EVENT_CONFIG_INITIALIZER(USERSUSPENDREQ, 1)
79d50a71bdSMitsuru IWASAKI 	EVENT_CONFIG_INITIALIZER(STANDBYRESUME, 0)
80d50a71bdSMitsuru IWASAKI 	EVENT_CONFIG_INITIALIZER(CAPABILITIESCHANGE, 0)
81d50a71bdSMitsuru IWASAKI };
82d50a71bdSMitsuru IWASAKI 
83d50a71bdSMitsuru IWASAKI /*
84d50a71bdSMitsuru IWASAKI  * default procedure
85d50a71bdSMitsuru IWASAKI  */
86d50a71bdSMitsuru IWASAKI struct event_cmd *
87d50a71bdSMitsuru IWASAKI event_cmd_default_clone(void *this)
88d50a71bdSMitsuru IWASAKI {
89d50a71bdSMitsuru IWASAKI 	struct event_cmd * oldone = this;
90d50a71bdSMitsuru IWASAKI 	struct event_cmd * newone = malloc(oldone->len);
91d50a71bdSMitsuru IWASAKI 
92d50a71bdSMitsuru IWASAKI 	newone->next = NULL;
93d50a71bdSMitsuru IWASAKI 	newone->len = oldone->len;
94d50a71bdSMitsuru IWASAKI 	newone->name = oldone->name;
95d50a71bdSMitsuru IWASAKI 	newone->op = oldone->op;
96d50a71bdSMitsuru IWASAKI 	return newone;
97d50a71bdSMitsuru IWASAKI }
98d50a71bdSMitsuru IWASAKI 
99d50a71bdSMitsuru IWASAKI /*
100d50a71bdSMitsuru IWASAKI  * exec command
101d50a71bdSMitsuru IWASAKI  */
102d50a71bdSMitsuru IWASAKI int
103d50a71bdSMitsuru IWASAKI event_cmd_exec_act(void *this)
104d50a71bdSMitsuru IWASAKI {
105d50a71bdSMitsuru IWASAKI 	struct event_cmd_exec * p = this;
106d50a71bdSMitsuru IWASAKI 	int status = -1;
107d50a71bdSMitsuru IWASAKI 	pid_t pid;
108d50a71bdSMitsuru IWASAKI 
109d50a71bdSMitsuru IWASAKI 	switch ((pid = fork())) {
110d50a71bdSMitsuru IWASAKI 	case -1:
111d50a71bdSMitsuru IWASAKI 		(void) warn("cannot fork");
112d50a71bdSMitsuru IWASAKI 		goto out;
113d50a71bdSMitsuru IWASAKI 	case 0:
114d50a71bdSMitsuru IWASAKI 		/* child process */
115d50a71bdSMitsuru IWASAKI 		execl(_PATH_BSHELL, "sh", "-c", p->line, (char *)NULL);
116d50a71bdSMitsuru IWASAKI 		_exit(127);
117d50a71bdSMitsuru IWASAKI 	default:
118d50a71bdSMitsuru IWASAKI 		/* parent process */
119d50a71bdSMitsuru IWASAKI 		do {
120d50a71bdSMitsuru IWASAKI 			pid = waitpid(pid, &status, 0);
121d50a71bdSMitsuru IWASAKI 		} while (pid == -1 && errno == EINTR);
122d50a71bdSMitsuru IWASAKI 		break;
123d50a71bdSMitsuru IWASAKI 	}
124d50a71bdSMitsuru IWASAKI  out:
125d50a71bdSMitsuru IWASAKI 	return status;
126d50a71bdSMitsuru IWASAKI }
127d50a71bdSMitsuru IWASAKI void
128d50a71bdSMitsuru IWASAKI event_cmd_exec_dump(void *this, FILE *fp)
129d50a71bdSMitsuru IWASAKI {
130d50a71bdSMitsuru IWASAKI 	fprintf(fp, " \"%s\"", ((struct event_cmd_exec *)this)->line);
131d50a71bdSMitsuru IWASAKI }
132d50a71bdSMitsuru IWASAKI struct event_cmd *
133d50a71bdSMitsuru IWASAKI event_cmd_exec_clone(void *this)
134d50a71bdSMitsuru IWASAKI {
135d50a71bdSMitsuru IWASAKI 	struct event_cmd_exec * newone = (struct event_cmd_exec *) event_cmd_default_clone(this);
136d50a71bdSMitsuru IWASAKI 	struct event_cmd_exec * oldone = this;
137d50a71bdSMitsuru IWASAKI 
138d50a71bdSMitsuru IWASAKI 	newone->evcmd.next = NULL;
139d50a71bdSMitsuru IWASAKI 	newone->evcmd.len = oldone->evcmd.len;
140d50a71bdSMitsuru IWASAKI 	newone->evcmd.name = oldone->evcmd.name;
141d50a71bdSMitsuru IWASAKI 	newone->evcmd.op = oldone->evcmd.op;
142d50a71bdSMitsuru IWASAKI 	newone->line = strdup(oldone->line);
143d50a71bdSMitsuru IWASAKI 	return (struct event_cmd *) newone;
144d50a71bdSMitsuru IWASAKI }
145d50a71bdSMitsuru IWASAKI void
146d50a71bdSMitsuru IWASAKI event_cmd_exec_free(void *this)
147d50a71bdSMitsuru IWASAKI {
148d50a71bdSMitsuru IWASAKI 	free(((struct event_cmd_exec *)this)->line);
149d50a71bdSMitsuru IWASAKI }
150d50a71bdSMitsuru IWASAKI struct event_cmd_op event_cmd_exec_ops = {
151d50a71bdSMitsuru IWASAKI 	event_cmd_exec_act,
152d50a71bdSMitsuru IWASAKI 	event_cmd_exec_dump,
153d50a71bdSMitsuru IWASAKI 	event_cmd_exec_clone,
154d50a71bdSMitsuru IWASAKI 	event_cmd_exec_free
155d50a71bdSMitsuru IWASAKI };
156d50a71bdSMitsuru IWASAKI 
157d50a71bdSMitsuru IWASAKI /*
158d50a71bdSMitsuru IWASAKI  * reject commad
159d50a71bdSMitsuru IWASAKI  */
160d50a71bdSMitsuru IWASAKI int
161d50a71bdSMitsuru IWASAKI event_cmd_reject_act(void *this)
162d50a71bdSMitsuru IWASAKI {
163d50a71bdSMitsuru IWASAKI 	int rc = -1;
164d50a71bdSMitsuru IWASAKI 
165d50a71bdSMitsuru IWASAKI 	if (ioctl(apmctl_fd, APMIO_REJECTLASTREQ, NULL)) {
166d50a71bdSMitsuru IWASAKI 		syslog(LOG_NOTICE, "fail to reject\n");
167d50a71bdSMitsuru IWASAKI 		goto out;
168d50a71bdSMitsuru IWASAKI 	}
169d50a71bdSMitsuru IWASAKI 	rc = 0;
170d50a71bdSMitsuru IWASAKI  out:
171d50a71bdSMitsuru IWASAKI 	return rc;
172d50a71bdSMitsuru IWASAKI }
173d50a71bdSMitsuru IWASAKI struct event_cmd_op event_cmd_reject_ops = {
174d50a71bdSMitsuru IWASAKI 	event_cmd_reject_act,
175d50a71bdSMitsuru IWASAKI 	NULL,
176d50a71bdSMitsuru IWASAKI 	event_cmd_default_clone,
177d50a71bdSMitsuru IWASAKI 	NULL
178d50a71bdSMitsuru IWASAKI };
179d50a71bdSMitsuru IWASAKI 
180d50a71bdSMitsuru IWASAKI /*
181d50a71bdSMitsuru IWASAKI  * manipulate event_config
182d50a71bdSMitsuru IWASAKI  */
183d50a71bdSMitsuru IWASAKI struct event_cmd *
184d50a71bdSMitsuru IWASAKI clone_event_cmd_list(struct event_cmd *p)
185d50a71bdSMitsuru IWASAKI {
186d50a71bdSMitsuru IWASAKI 	struct event_cmd dummy;
187d50a71bdSMitsuru IWASAKI 	struct event_cmd *q = &dummy;
188d50a71bdSMitsuru IWASAKI 	for ( ;p; p = p->next) {
189d50a71bdSMitsuru IWASAKI 		assert(p->op->clone);
190d50a71bdSMitsuru IWASAKI 		if ((q->next = p->op->clone(p)) == NULL)
191d50a71bdSMitsuru IWASAKI 			(void) err(1, "out of memory");
192d50a71bdSMitsuru IWASAKI 		q = q->next;
193d50a71bdSMitsuru IWASAKI 	}
194d50a71bdSMitsuru IWASAKI 	q->next = NULL;
195d50a71bdSMitsuru IWASAKI 	return dummy.next;
196d50a71bdSMitsuru IWASAKI }
197d50a71bdSMitsuru IWASAKI void
198d50a71bdSMitsuru IWASAKI free_event_cmd_list(struct event_cmd *p)
199d50a71bdSMitsuru IWASAKI {
200d50a71bdSMitsuru IWASAKI 	struct event_cmd * q;
201d50a71bdSMitsuru IWASAKI 	for ( ; p ; p = q) {
202d50a71bdSMitsuru IWASAKI 		q = p->next;
203d50a71bdSMitsuru IWASAKI 		if (p->op->free)
204d50a71bdSMitsuru IWASAKI 			p->op->free(p);
205d50a71bdSMitsuru IWASAKI 		free(p);
206d50a71bdSMitsuru IWASAKI 	}
207d50a71bdSMitsuru IWASAKI }
208d50a71bdSMitsuru IWASAKI int
209d50a71bdSMitsuru IWASAKI register_apm_event_handlers(
210d50a71bdSMitsuru IWASAKI 	bitstr_t bit_decl(evlist, EVENT_MAX),
211d50a71bdSMitsuru IWASAKI 	struct event_cmd *cmdlist)
212d50a71bdSMitsuru IWASAKI {
213d50a71bdSMitsuru IWASAKI 	if (cmdlist) {
214d50a71bdSMitsuru IWASAKI 		bitstr_t bit_decl(tmp, EVENT_MAX);
215d50a71bdSMitsuru IWASAKI 		memcpy(&tmp, evlist, bitstr_size(EVENT_MAX));
216d50a71bdSMitsuru IWASAKI 
217d50a71bdSMitsuru IWASAKI 		for (;;) {
218d50a71bdSMitsuru IWASAKI 			int n;
219d50a71bdSMitsuru IWASAKI 			struct event_cmd *p;
220d50a71bdSMitsuru IWASAKI 			struct event_cmd *q;
221d50a71bdSMitsuru IWASAKI 			bit_ffs(tmp, EVENT_MAX, &n);
222d50a71bdSMitsuru IWASAKI 			if (n < 0)
223d50a71bdSMitsuru IWASAKI 				break;
224d50a71bdSMitsuru IWASAKI 			p = events[n].cmdlist;
225d50a71bdSMitsuru IWASAKI 			if ((q = clone_event_cmd_list(cmdlist)) == NULL)
226d50a71bdSMitsuru IWASAKI 				(void) err(1, "out of memory");
227d50a71bdSMitsuru IWASAKI 			if (p) {
228d50a71bdSMitsuru IWASAKI 				while (p->next != NULL)
229d50a71bdSMitsuru IWASAKI 					p = p->next;
230d50a71bdSMitsuru IWASAKI 				p->next = q;
231d50a71bdSMitsuru IWASAKI 			} else {
232d50a71bdSMitsuru IWASAKI 				events[n].cmdlist = q;
233d50a71bdSMitsuru IWASAKI 			}
234d50a71bdSMitsuru IWASAKI 			bit_clear(tmp, n);
235d50a71bdSMitsuru IWASAKI 		}
236d50a71bdSMitsuru IWASAKI 	}
237d50a71bdSMitsuru IWASAKI 	return 0;
238d50a71bdSMitsuru IWASAKI }
239d50a71bdSMitsuru IWASAKI 
240d50a71bdSMitsuru IWASAKI /*
241d50a71bdSMitsuru IWASAKI  * execute command
242d50a71bdSMitsuru IWASAKI  */
243d50a71bdSMitsuru IWASAKI int
244d50a71bdSMitsuru IWASAKI exec_event_cmd(struct event_config *ev)
245d50a71bdSMitsuru IWASAKI {
246d50a71bdSMitsuru IWASAKI 	int status = 0;
247d50a71bdSMitsuru IWASAKI 
248d50a71bdSMitsuru IWASAKI 	struct event_cmd *p = ev->cmdlist;
249d50a71bdSMitsuru IWASAKI 	for (; p; p = p->next) {
250d50a71bdSMitsuru IWASAKI 		assert(p->op->act);
251d50a71bdSMitsuru IWASAKI 		if (verbose)
252d50a71bdSMitsuru IWASAKI 			syslog(LOG_INFO, "action: %s", p->name);
253d50a71bdSMitsuru IWASAKI 		status = p->op->act(p);
254d50a71bdSMitsuru IWASAKI 		if (status) {
255d50a71bdSMitsuru IWASAKI 			syslog(LOG_NOTICE, "command finished with %d\n", status);
256d50a71bdSMitsuru IWASAKI 			if (ev->rejectable) {
257d50a71bdSMitsuru IWASAKI 				syslog(LOG_ERR, "canceled");
258d50a71bdSMitsuru IWASAKI 				(void) event_cmd_reject_act(NULL);
259d50a71bdSMitsuru IWASAKI 			}
260d50a71bdSMitsuru IWASAKI 			break;
261d50a71bdSMitsuru IWASAKI 		}
262d50a71bdSMitsuru IWASAKI 	}
263d50a71bdSMitsuru IWASAKI 	return status;
264d50a71bdSMitsuru IWASAKI }
265d50a71bdSMitsuru IWASAKI 
266d50a71bdSMitsuru IWASAKI /*
267d50a71bdSMitsuru IWASAKI  * read config file
268d50a71bdSMitsuru IWASAKI  */
269d50a71bdSMitsuru IWASAKI extern FILE * yyin;
270d50a71bdSMitsuru IWASAKI extern int yydebug;
271d50a71bdSMitsuru IWASAKI 
272d50a71bdSMitsuru IWASAKI void
273d50a71bdSMitsuru IWASAKI read_config(void)
274d50a71bdSMitsuru IWASAKI {
275d50a71bdSMitsuru IWASAKI 	int i;
276d50a71bdSMitsuru IWASAKI 
277d50a71bdSMitsuru IWASAKI 	if ((yyin = fopen(apmd_configfile, "r")) == NULL) {
278d50a71bdSMitsuru IWASAKI 		(void) err(1, "cannot open config file");
279d50a71bdSMitsuru IWASAKI 	}
280d50a71bdSMitsuru IWASAKI 
281d50a71bdSMitsuru IWASAKI #ifdef DEBUG
282d50a71bdSMitsuru IWASAKI 	yydebug = debug_level;
283d50a71bdSMitsuru IWASAKI #endif
284d50a71bdSMitsuru IWASAKI 
285d50a71bdSMitsuru IWASAKI 	if (yyparse() != 0)
286d50a71bdSMitsuru IWASAKI 		(void) err(1, "cannot parse config file");
287d50a71bdSMitsuru IWASAKI 
288d50a71bdSMitsuru IWASAKI 	fclose(yyin);
289d50a71bdSMitsuru IWASAKI 
290d50a71bdSMitsuru IWASAKI 	/* enable events */
291d50a71bdSMitsuru IWASAKI 	for (i = 0; i < EVENT_MAX; i++) {
292d50a71bdSMitsuru IWASAKI 		if (events[i].cmdlist) {
293d50a71bdSMitsuru IWASAKI 			u_int event_type = i;
294d50a71bdSMitsuru IWASAKI 			if (write(apmctl_fd, &event_type, sizeof(u_int)) == -1) {
295d50a71bdSMitsuru IWASAKI 				(void) err(1, "cannot enable event 0x%x", event_type);
296d50a71bdSMitsuru IWASAKI 			}
297d50a71bdSMitsuru IWASAKI 		}
298d50a71bdSMitsuru IWASAKI 	}
299d50a71bdSMitsuru IWASAKI }
300d50a71bdSMitsuru IWASAKI 
301d50a71bdSMitsuru IWASAKI void
302d50a71bdSMitsuru IWASAKI dump_config()
303d50a71bdSMitsuru IWASAKI {
304d50a71bdSMitsuru IWASAKI 	int i;
305d50a71bdSMitsuru IWASAKI 
306d50a71bdSMitsuru IWASAKI 	for (i = 0; i < EVENT_MAX; i++) {
307d50a71bdSMitsuru IWASAKI 		struct event_cmd * p;
308d50a71bdSMitsuru IWASAKI 		if ((p = events[i].cmdlist)) {
309d50a71bdSMitsuru IWASAKI 			fprintf(stderr, "apm_event %s {\n", events[i].name);
310d50a71bdSMitsuru IWASAKI 			for ( ; p ; p = p->next) {
311d50a71bdSMitsuru IWASAKI 				fprintf(stderr, "\t%s", p->name);
312d50a71bdSMitsuru IWASAKI 				if (p->op->dump)
313d50a71bdSMitsuru IWASAKI 					p->op->dump(p, stderr);
314d50a71bdSMitsuru IWASAKI 				fprintf(stderr, ";\n");
315d50a71bdSMitsuru IWASAKI 			}
316d50a71bdSMitsuru IWASAKI 			fprintf(stderr, "}\n");
317d50a71bdSMitsuru IWASAKI 		}
318d50a71bdSMitsuru IWASAKI 	}
319d50a71bdSMitsuru IWASAKI }
320d50a71bdSMitsuru IWASAKI 
321d50a71bdSMitsuru IWASAKI void
322d50a71bdSMitsuru IWASAKI destroy_config()
323d50a71bdSMitsuru IWASAKI {
324d50a71bdSMitsuru IWASAKI 	int i;
325d50a71bdSMitsuru IWASAKI 
326d50a71bdSMitsuru IWASAKI 	/* disable events */
327d50a71bdSMitsuru IWASAKI 	for (i = 0; i < EVENT_MAX; i++) {
328d50a71bdSMitsuru IWASAKI 		if (events[i].cmdlist) {
329d50a71bdSMitsuru IWASAKI 			u_int event_type = i;
330d50a71bdSMitsuru IWASAKI 			if (write(apmctl_fd, &event_type, sizeof(u_int)) == -1) {
331d50a71bdSMitsuru IWASAKI 				(void) err(1, "cannot disable event 0x%x", event_type);
332d50a71bdSMitsuru IWASAKI 			}
333d50a71bdSMitsuru IWASAKI 		}
334d50a71bdSMitsuru IWASAKI 	}
335d50a71bdSMitsuru IWASAKI 
336d50a71bdSMitsuru IWASAKI 	for (i = 0; i < EVENT_MAX; i++) {
337d50a71bdSMitsuru IWASAKI 		struct event_cmd * p;
338d50a71bdSMitsuru IWASAKI 		if ((p = events[i].cmdlist))
339d50a71bdSMitsuru IWASAKI 			free_event_cmd_list(p);
340d50a71bdSMitsuru IWASAKI 		events[i].cmdlist = NULL;
341d50a71bdSMitsuru IWASAKI 	}
342d50a71bdSMitsuru IWASAKI }
343d50a71bdSMitsuru IWASAKI 
344d50a71bdSMitsuru IWASAKI void
345d50a71bdSMitsuru IWASAKI restart()
346d50a71bdSMitsuru IWASAKI {
347d50a71bdSMitsuru IWASAKI 	destroy_config();
348d50a71bdSMitsuru IWASAKI 	read_config();
349d50a71bdSMitsuru IWASAKI 	if (verbose)
350d50a71bdSMitsuru IWASAKI 		dump_config();
351d50a71bdSMitsuru IWASAKI }
352d50a71bdSMitsuru IWASAKI 
353d50a71bdSMitsuru IWASAKI /*
354d50a71bdSMitsuru IWASAKI  * write pid file
355d50a71bdSMitsuru IWASAKI  */
356d50a71bdSMitsuru IWASAKI static void
357d50a71bdSMitsuru IWASAKI write_pid()
358d50a71bdSMitsuru IWASAKI {
359d50a71bdSMitsuru IWASAKI 	FILE *fp = fopen(apmd_pidfile, "w");
360d50a71bdSMitsuru IWASAKI 
361d50a71bdSMitsuru IWASAKI 	if (fp) {
362d50a71bdSMitsuru IWASAKI 		fprintf(fp, "%d\n", getpid());
363d50a71bdSMitsuru IWASAKI 		fclose(fp);
364d50a71bdSMitsuru IWASAKI 	}
365d50a71bdSMitsuru IWASAKI }
366d50a71bdSMitsuru IWASAKI 
367d50a71bdSMitsuru IWASAKI /*
368d50a71bdSMitsuru IWASAKI  * handle signals
369d50a71bdSMitsuru IWASAKI  */
370d50a71bdSMitsuru IWASAKI static int signal_fd[2];
371d50a71bdSMitsuru IWASAKI 
372d50a71bdSMitsuru IWASAKI void
373d50a71bdSMitsuru IWASAKI enque_signal(int sig)
374d50a71bdSMitsuru IWASAKI {
375d50a71bdSMitsuru IWASAKI 	if (write(signal_fd[1], &sig, sizeof sig) != sizeof sig)
376d50a71bdSMitsuru IWASAKI 		(void) err(1, "cannot process signal.");
377d50a71bdSMitsuru IWASAKI }
378d50a71bdSMitsuru IWASAKI 
379d50a71bdSMitsuru IWASAKI void
380d50a71bdSMitsuru IWASAKI wait_child()
381d50a71bdSMitsuru IWASAKI {
382d50a71bdSMitsuru IWASAKI 	int status;
383d50a71bdSMitsuru IWASAKI 	while (waitpid(-1, &status, WNOHANG) > 0)
384d50a71bdSMitsuru IWASAKI 		;
385d50a71bdSMitsuru IWASAKI }
386d50a71bdSMitsuru IWASAKI 
387d50a71bdSMitsuru IWASAKI int
388d50a71bdSMitsuru IWASAKI proc_signal(int fd)
389d50a71bdSMitsuru IWASAKI {
390d50a71bdSMitsuru IWASAKI 	int rc = -1;
391d50a71bdSMitsuru IWASAKI 	int sig;
392d50a71bdSMitsuru IWASAKI 
393d50a71bdSMitsuru IWASAKI 	while (read(fd, &sig, sizeof sig) == sizeof sig) {
394d50a71bdSMitsuru IWASAKI 		syslog(LOG_INFO, "caught signal: %d", sig);
395d50a71bdSMitsuru IWASAKI 		switch (sig) {
396d50a71bdSMitsuru IWASAKI 		case SIGHUP:
397d50a71bdSMitsuru IWASAKI 			syslog(LOG_NOTICE, "restart by SIG");
398d50a71bdSMitsuru IWASAKI 			restart();
399d50a71bdSMitsuru IWASAKI 			break;
400d50a71bdSMitsuru IWASAKI 		case SIGTERM:
401d50a71bdSMitsuru IWASAKI 			syslog(LOG_NOTICE, "going down on signal %d", sig);
402d50a71bdSMitsuru IWASAKI 			rc = 1;
403d50a71bdSMitsuru IWASAKI 			goto out;
404d50a71bdSMitsuru IWASAKI 		case SIGCHLD:
405d50a71bdSMitsuru IWASAKI 			wait_child();
406d50a71bdSMitsuru IWASAKI 			break;
407d50a71bdSMitsuru IWASAKI 		default:
408d50a71bdSMitsuru IWASAKI 			(void) warn("unexpected signal(%d) received.", sig);
409d50a71bdSMitsuru IWASAKI 			break;
410d50a71bdSMitsuru IWASAKI 		}
411d50a71bdSMitsuru IWASAKI 	}
412d50a71bdSMitsuru IWASAKI 	rc = 0;
413d50a71bdSMitsuru IWASAKI  out:
414d50a71bdSMitsuru IWASAKI 	return rc;
415d50a71bdSMitsuru IWASAKI }
416d50a71bdSMitsuru IWASAKI void
417d50a71bdSMitsuru IWASAKI proc_apmevent(int fd)
418d50a71bdSMitsuru IWASAKI {
419d50a71bdSMitsuru IWASAKI 	struct apm_event_info apmevent;
420d50a71bdSMitsuru IWASAKI 
421d50a71bdSMitsuru IWASAKI 	while (ioctl(fd, APMIO_NEXTEVENT, &apmevent) == 0) {
422d50a71bdSMitsuru IWASAKI 		int status;
423d50a71bdSMitsuru IWASAKI 		syslog(LOG_NOTICE, "apmevent %04x index %d\n",
424d50a71bdSMitsuru IWASAKI 			apmevent.type, apmevent.index);
425d50a71bdSMitsuru IWASAKI 		syslog(LOG_INFO, "apm event: %s", events[apmevent.type].name);
426d50a71bdSMitsuru IWASAKI 		if (fork() == 0) {
427d50a71bdSMitsuru IWASAKI 			status = exec_event_cmd(&events[apmevent.type]);
428d50a71bdSMitsuru IWASAKI 			exit(status);
429d50a71bdSMitsuru IWASAKI 		}
430d50a71bdSMitsuru IWASAKI 	}
431d50a71bdSMitsuru IWASAKI }
432d50a71bdSMitsuru IWASAKI void
433d50a71bdSMitsuru IWASAKI event_loop(void)
434d50a71bdSMitsuru IWASAKI {
435d50a71bdSMitsuru IWASAKI 	int		fdmax = 0;
436d50a71bdSMitsuru IWASAKI 	struct sigaction nsa;
437d50a71bdSMitsuru IWASAKI 	fd_set          master_rfds;
438d50a71bdSMitsuru IWASAKI 	sigset_t	sigmask, osigmask;
439d50a71bdSMitsuru IWASAKI 
440d50a71bdSMitsuru IWASAKI 	FD_ZERO(&master_rfds);
441d50a71bdSMitsuru IWASAKI 	FD_SET(apmctl_fd, &master_rfds);
442d50a71bdSMitsuru IWASAKI 	fdmax = apmctl_fd > fdmax ? apmctl_fd : fdmax;
443d50a71bdSMitsuru IWASAKI 
444d50a71bdSMitsuru IWASAKI 	FD_SET(signal_fd[0], &master_rfds);
445d50a71bdSMitsuru IWASAKI 	fdmax = signal_fd[0] > fdmax ? signal_fd[0] : fdmax;
446d50a71bdSMitsuru IWASAKI 
447d50a71bdSMitsuru IWASAKI 	memset(&nsa, 0, sizeof nsa);
448d50a71bdSMitsuru IWASAKI 	nsa.sa_handler = enque_signal;
449d50a71bdSMitsuru IWASAKI 	sigfillset(&nsa.sa_mask);
450d50a71bdSMitsuru IWASAKI 	nsa.sa_flags = SA_RESTART;
451d50a71bdSMitsuru IWASAKI 	sigaction(SIGHUP, &nsa, NULL);
452d50a71bdSMitsuru IWASAKI 	sigaction(SIGCHLD, &nsa, NULL);
453d50a71bdSMitsuru IWASAKI 	sigaction(SIGTERM, &nsa, NULL);
454d50a71bdSMitsuru IWASAKI 
455d50a71bdSMitsuru IWASAKI 	sigemptyset(&sigmask);
456d50a71bdSMitsuru IWASAKI 	sigaddset(&sigmask, SIGHUP);
457d50a71bdSMitsuru IWASAKI 	sigaddset(&sigmask, SIGCHLD);
458d50a71bdSMitsuru IWASAKI 	sigaddset(&sigmask, SIGTERM);
459d50a71bdSMitsuru IWASAKI 	sigprocmask(SIG_SETMASK, &sigmask, &osigmask);
460d50a71bdSMitsuru IWASAKI 
461d50a71bdSMitsuru IWASAKI 	while (1) {
462d50a71bdSMitsuru IWASAKI 		fd_set rfds;
463d50a71bdSMitsuru IWASAKI 
464d50a71bdSMitsuru IWASAKI 		memcpy(&rfds, &master_rfds, sizeof rfds);
465d50a71bdSMitsuru IWASAKI 		sigprocmask(SIG_SETMASK, &osigmask, NULL);
466d50a71bdSMitsuru IWASAKI 		if (select(fdmax + 1, &rfds, 0, 0, 0) < 0) {
467d50a71bdSMitsuru IWASAKI 			if (errno != EINTR)
468d50a71bdSMitsuru IWASAKI 				(void) err(1, "select");
469d50a71bdSMitsuru IWASAKI 		}
470d50a71bdSMitsuru IWASAKI 		sigprocmask(SIG_SETMASK, &sigmask, NULL);
471d50a71bdSMitsuru IWASAKI 
472d50a71bdSMitsuru IWASAKI 		if (FD_ISSET(signal_fd[0], &rfds)) {
473d50a71bdSMitsuru IWASAKI 			if (proc_signal(signal_fd[0]) < 0)
474d50a71bdSMitsuru IWASAKI 				goto out;
475d50a71bdSMitsuru IWASAKI 		}
476d50a71bdSMitsuru IWASAKI 		if (FD_ISSET(apmctl_fd, &rfds))
477d50a71bdSMitsuru IWASAKI 			proc_apmevent(apmctl_fd);
478d50a71bdSMitsuru IWASAKI 	}
479d50a71bdSMitsuru IWASAKI out:
480d50a71bdSMitsuru IWASAKI 	return;
481d50a71bdSMitsuru IWASAKI }
482d50a71bdSMitsuru IWASAKI 
483d50a71bdSMitsuru IWASAKI void
484d50a71bdSMitsuru IWASAKI main(int ac, char* av[])
485d50a71bdSMitsuru IWASAKI {
486d50a71bdSMitsuru IWASAKI 	int	ch;
487d50a71bdSMitsuru IWASAKI 	int	daemonize = 1;
488d50a71bdSMitsuru IWASAKI 	char	*prog;
489d50a71bdSMitsuru IWASAKI 	int	logopt = LOG_NDELAY | LOG_PID;
490d50a71bdSMitsuru IWASAKI 
491d50a71bdSMitsuru IWASAKI 	while ((ch = getopt(ac, av, "df:v")) != EOF) {
492d50a71bdSMitsuru IWASAKI 		switch (ch) {
493d50a71bdSMitsuru IWASAKI 		case 'd':
494d50a71bdSMitsuru IWASAKI 			daemonize = 0;
495d50a71bdSMitsuru IWASAKI 			debug_level++;
496d50a71bdSMitsuru IWASAKI 			break;
497d50a71bdSMitsuru IWASAKI 		case 'f':
498d50a71bdSMitsuru IWASAKI 			apmd_configfile = optarg;
499d50a71bdSMitsuru IWASAKI 			break;
500d50a71bdSMitsuru IWASAKI 		case 'v':
501d50a71bdSMitsuru IWASAKI 			verbose = 1;
502d50a71bdSMitsuru IWASAKI 			break;
503d50a71bdSMitsuru IWASAKI 		default:
504d50a71bdSMitsuru IWASAKI 			(void) err(1, "unknown option `%c'", ch);
505d50a71bdSMitsuru IWASAKI 		}
506d50a71bdSMitsuru IWASAKI 	}
507d50a71bdSMitsuru IWASAKI 
508d50a71bdSMitsuru IWASAKI 	if (daemonize)
509d50a71bdSMitsuru IWASAKI 		daemon(0, 0);
510d50a71bdSMitsuru IWASAKI 
511d50a71bdSMitsuru IWASAKI #ifdef NICE_INCR
512d50a71bdSMitsuru IWASAKI 	(void) nice(NICE_INCR);
513d50a71bdSMitsuru IWASAKI #endif
514d50a71bdSMitsuru IWASAKI 
515d50a71bdSMitsuru IWASAKI 	if (!daemonize)
516d50a71bdSMitsuru IWASAKI 		logopt |= LOG_PERROR;
517d50a71bdSMitsuru IWASAKI 
518d50a71bdSMitsuru IWASAKI 	prog = strrchr(av[0], '/');
519d50a71bdSMitsuru IWASAKI 	openlog(prog ? prog+1 : av[0], logopt, LOG_DAEMON);
520d50a71bdSMitsuru IWASAKI 
521d50a71bdSMitsuru IWASAKI 	syslog(LOG_NOTICE, "start");
522d50a71bdSMitsuru IWASAKI 
523d50a71bdSMitsuru IWASAKI 	if (pipe(signal_fd) < 0)
524d50a71bdSMitsuru IWASAKI 		(void) err(1, "pipe");
525d50a71bdSMitsuru IWASAKI 	if (fcntl(signal_fd[0], F_SETFL, O_NONBLOCK) < 0)
526d50a71bdSMitsuru IWASAKI 		(void) err(1, "fcntl");
527d50a71bdSMitsuru IWASAKI 
528d50a71bdSMitsuru IWASAKI 	if ((apmctl_fd = open(APM_CTL_DEVICEFILE, O_RDWR)) == -1) {
529d50a71bdSMitsuru IWASAKI 		(void) err(1, "cannot open device file `%s'", APM_CTL_DEVICEFILE);
530d50a71bdSMitsuru IWASAKI 	}
531d50a71bdSMitsuru IWASAKI 
532d50a71bdSMitsuru IWASAKI 	restart();
533d50a71bdSMitsuru IWASAKI 	write_pid();
534d50a71bdSMitsuru IWASAKI 	event_loop();
535d50a71bdSMitsuru IWASAKI  	exit(EXIT_SUCCESS);
536d50a71bdSMitsuru IWASAKI }
537d50a71bdSMitsuru IWASAKI 
538