1d50a71bdSMitsuru IWASAKI /*-
2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
31de7b4b8SPedro 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
3200774f35SPeter Wemm #include <sys/types.h>
33d50a71bdSMitsuru IWASAKI #include <assert.h>
34d50a71bdSMitsuru IWASAKI #include <bitstring.h>
35d50a71bdSMitsuru IWASAKI #include <err.h>
36d50a71bdSMitsuru IWASAKI #include <errno.h>
37d50a71bdSMitsuru IWASAKI #include <fcntl.h>
38d50a71bdSMitsuru IWASAKI #include <paths.h>
39d50a71bdSMitsuru IWASAKI #include <signal.h>
40d50a71bdSMitsuru IWASAKI #include <stdio.h>
41d50a71bdSMitsuru IWASAKI #include <stdlib.h>
42d50a71bdSMitsuru IWASAKI #include <string.h>
43d50a71bdSMitsuru IWASAKI #include <syslog.h>
44d50a71bdSMitsuru IWASAKI #include <unistd.h>
45d50a71bdSMitsuru IWASAKI #include <sys/ioctl.h>
46d50a71bdSMitsuru IWASAKI #include <sys/time.h>
47d50a71bdSMitsuru IWASAKI #include <sys/wait.h>
48d50a71bdSMitsuru IWASAKI #include <machine/apm_bios.h>
49d50a71bdSMitsuru IWASAKI
50d50a71bdSMitsuru IWASAKI #include "apmd.h"
51d50a71bdSMitsuru IWASAKI
52d50a71bdSMitsuru IWASAKI int debug_level = 0;
53d50a71bdSMitsuru IWASAKI int verbose = 0;
54f90445cfSMatthew N. Dodd int soft_power_state_change = 0;
55d50a71bdSMitsuru IWASAKI const char *apmd_configfile = APMD_CONFIGFILE;
56d50a71bdSMitsuru IWASAKI const char *apmd_pidfile = APMD_PIDFILE;
57719b9dc1SNick Sayer int apmctl_fd = -1, apmnorm_fd = -1;
58d50a71bdSMitsuru IWASAKI
59d50a71bdSMitsuru IWASAKI /*
60d50a71bdSMitsuru IWASAKI * table of event handlers
61d50a71bdSMitsuru IWASAKI */
62d50a71bdSMitsuru IWASAKI #define EVENT_CONFIG_INITIALIZER(EV,R) { #EV, NULL, R },
63d50a71bdSMitsuru IWASAKI struct event_config events[EVENT_MAX] = {
64d50a71bdSMitsuru IWASAKI EVENT_CONFIG_INITIALIZER(NOEVENT, 0)
65d50a71bdSMitsuru IWASAKI EVENT_CONFIG_INITIALIZER(STANDBYREQ, 1)
66d50a71bdSMitsuru IWASAKI EVENT_CONFIG_INITIALIZER(SUSPENDREQ, 1)
67d50a71bdSMitsuru IWASAKI EVENT_CONFIG_INITIALIZER(NORMRESUME, 0)
68d50a71bdSMitsuru IWASAKI EVENT_CONFIG_INITIALIZER(CRITRESUME, 0)
69d50a71bdSMitsuru IWASAKI EVENT_CONFIG_INITIALIZER(BATTERYLOW, 0)
7075b36243SMatthew N. Dodd EVENT_CONFIG_INITIALIZER(POWERSTATECHANGE, 0)
71d50a71bdSMitsuru IWASAKI EVENT_CONFIG_INITIALIZER(UPDATETIME, 0)
72d50a71bdSMitsuru IWASAKI EVENT_CONFIG_INITIALIZER(CRITSUSPEND, 1)
73d50a71bdSMitsuru IWASAKI EVENT_CONFIG_INITIALIZER(USERSTANDBYREQ, 1)
74d50a71bdSMitsuru IWASAKI EVENT_CONFIG_INITIALIZER(USERSUSPENDREQ, 1)
75d50a71bdSMitsuru IWASAKI EVENT_CONFIG_INITIALIZER(STANDBYRESUME, 0)
76d50a71bdSMitsuru IWASAKI EVENT_CONFIG_INITIALIZER(CAPABILITIESCHANGE, 0)
77d50a71bdSMitsuru IWASAKI };
78d50a71bdSMitsuru IWASAKI
79d50a71bdSMitsuru IWASAKI /*
80719b9dc1SNick Sayer * List of battery events
81719b9dc1SNick Sayer */
82719b9dc1SNick Sayer struct battery_watch_event *battery_watch_list = NULL;
83719b9dc1SNick Sayer
84719b9dc1SNick Sayer #define BATT_CHK_INTV 10 /* how many seconds between battery state checks? */
85719b9dc1SNick Sayer
86719b9dc1SNick Sayer /*
87d50a71bdSMitsuru IWASAKI * default procedure
88d50a71bdSMitsuru IWASAKI */
89d50a71bdSMitsuru IWASAKI struct event_cmd *
event_cmd_default_clone(void * this)90d50a71bdSMitsuru IWASAKI event_cmd_default_clone(void *this)
91d50a71bdSMitsuru IWASAKI {
92d50a71bdSMitsuru IWASAKI struct event_cmd * oldone = this;
93d50a71bdSMitsuru IWASAKI struct event_cmd * newone = malloc(oldone->len);
94d50a71bdSMitsuru IWASAKI
95d50a71bdSMitsuru IWASAKI newone->next = NULL;
96d50a71bdSMitsuru IWASAKI newone->len = oldone->len;
97d50a71bdSMitsuru IWASAKI newone->name = oldone->name;
98d50a71bdSMitsuru IWASAKI newone->op = oldone->op;
99d50a71bdSMitsuru IWASAKI return newone;
100d50a71bdSMitsuru IWASAKI }
101d50a71bdSMitsuru IWASAKI
102d50a71bdSMitsuru IWASAKI /*
103d50a71bdSMitsuru IWASAKI * exec command
104d50a71bdSMitsuru IWASAKI */
105d50a71bdSMitsuru IWASAKI int
event_cmd_exec_act(void * this)106d50a71bdSMitsuru IWASAKI event_cmd_exec_act(void *this)
107d50a71bdSMitsuru IWASAKI {
108d50a71bdSMitsuru IWASAKI struct event_cmd_exec * p = this;
109d50a71bdSMitsuru IWASAKI int status = -1;
110d50a71bdSMitsuru IWASAKI pid_t pid;
111d50a71bdSMitsuru IWASAKI
112d50a71bdSMitsuru IWASAKI switch ((pid = fork())) {
113d50a71bdSMitsuru IWASAKI case -1:
114103e4932SUlrich Spörlein warn("cannot fork");
115cd0788e1SUlrich Spörlein break;
116d50a71bdSMitsuru IWASAKI case 0:
117d50a71bdSMitsuru IWASAKI /* child process */
1189ad4f2d0SMatthew N. Dodd signal(SIGHUP, SIG_DFL);
1199ad4f2d0SMatthew N. Dodd signal(SIGCHLD, SIG_DFL);
1209ad4f2d0SMatthew N. Dodd signal(SIGTERM, SIG_DFL);
121cd0788e1SUlrich Spörlein execl(_PATH_BSHELL, "sh", "-c", p->line, (char *)NULL);
122d50a71bdSMitsuru IWASAKI _exit(127);
123d50a71bdSMitsuru IWASAKI default:
124d50a71bdSMitsuru IWASAKI /* parent process */
125d50a71bdSMitsuru IWASAKI do {
126d50a71bdSMitsuru IWASAKI pid = waitpid(pid, &status, 0);
127d50a71bdSMitsuru IWASAKI } while (pid == -1 && errno == EINTR);
128d50a71bdSMitsuru IWASAKI break;
129d50a71bdSMitsuru IWASAKI }
130d50a71bdSMitsuru IWASAKI return status;
131d50a71bdSMitsuru IWASAKI }
132d50a71bdSMitsuru IWASAKI void
event_cmd_exec_dump(void * this,FILE * fp)133d50a71bdSMitsuru IWASAKI event_cmd_exec_dump(void *this, FILE *fp)
134d50a71bdSMitsuru IWASAKI {
135d50a71bdSMitsuru IWASAKI fprintf(fp, " \"%s\"", ((struct event_cmd_exec *)this)->line);
136d50a71bdSMitsuru IWASAKI }
137d50a71bdSMitsuru IWASAKI struct event_cmd *
event_cmd_exec_clone(void * this)138d50a71bdSMitsuru IWASAKI event_cmd_exec_clone(void *this)
139d50a71bdSMitsuru IWASAKI {
140d50a71bdSMitsuru IWASAKI struct event_cmd_exec * newone = (struct event_cmd_exec *) event_cmd_default_clone(this);
141d50a71bdSMitsuru IWASAKI struct event_cmd_exec * oldone = this;
142d50a71bdSMitsuru IWASAKI
143d50a71bdSMitsuru IWASAKI newone->evcmd.next = NULL;
144d50a71bdSMitsuru IWASAKI newone->evcmd.len = oldone->evcmd.len;
145d50a71bdSMitsuru IWASAKI newone->evcmd.name = oldone->evcmd.name;
146d50a71bdSMitsuru IWASAKI newone->evcmd.op = oldone->evcmd.op;
147aecdf0ebSChris D. Faulhaber if ((newone->line = strdup(oldone->line)) == NULL)
148aecdf0ebSChris D. Faulhaber err(1, "out of memory");
149d50a71bdSMitsuru IWASAKI return (struct event_cmd *) newone;
150d50a71bdSMitsuru IWASAKI }
151d50a71bdSMitsuru IWASAKI void
event_cmd_exec_free(void * this)152d50a71bdSMitsuru IWASAKI event_cmd_exec_free(void *this)
153d50a71bdSMitsuru IWASAKI {
154d50a71bdSMitsuru IWASAKI free(((struct event_cmd_exec *)this)->line);
155d50a71bdSMitsuru IWASAKI }
156d50a71bdSMitsuru IWASAKI struct event_cmd_op event_cmd_exec_ops = {
157d50a71bdSMitsuru IWASAKI event_cmd_exec_act,
158d50a71bdSMitsuru IWASAKI event_cmd_exec_dump,
159d50a71bdSMitsuru IWASAKI event_cmd_exec_clone,
160d50a71bdSMitsuru IWASAKI event_cmd_exec_free
161d50a71bdSMitsuru IWASAKI };
162d50a71bdSMitsuru IWASAKI
163d50a71bdSMitsuru IWASAKI /*
164cd0788e1SUlrich Spörlein * reject command
165d50a71bdSMitsuru IWASAKI */
166d50a71bdSMitsuru IWASAKI int
event_cmd_reject_act(void * this __unused)167103e4932SUlrich Spörlein event_cmd_reject_act(void *this __unused)
168d50a71bdSMitsuru IWASAKI {
169cd0788e1SUlrich Spörlein int rc = 0;
170d50a71bdSMitsuru IWASAKI
171d50a71bdSMitsuru IWASAKI if (ioctl(apmctl_fd, APMIO_REJECTLASTREQ, NULL)) {
172d50a71bdSMitsuru IWASAKI syslog(LOG_NOTICE, "fail to reject\n");
173cd0788e1SUlrich Spörlein rc = -1;
174d50a71bdSMitsuru IWASAKI }
175d50a71bdSMitsuru IWASAKI return rc;
176d50a71bdSMitsuru IWASAKI }
177d50a71bdSMitsuru IWASAKI struct event_cmd_op event_cmd_reject_ops = {
178d50a71bdSMitsuru IWASAKI event_cmd_reject_act,
179d50a71bdSMitsuru IWASAKI NULL,
180d50a71bdSMitsuru IWASAKI event_cmd_default_clone,
181d50a71bdSMitsuru IWASAKI NULL
182d50a71bdSMitsuru IWASAKI };
183d50a71bdSMitsuru IWASAKI
184d50a71bdSMitsuru IWASAKI /*
185d50a71bdSMitsuru IWASAKI * manipulate event_config
186d50a71bdSMitsuru IWASAKI */
187d50a71bdSMitsuru IWASAKI struct event_cmd *
clone_event_cmd_list(struct event_cmd * p)188d50a71bdSMitsuru IWASAKI clone_event_cmd_list(struct event_cmd *p)
189d50a71bdSMitsuru IWASAKI {
190d50a71bdSMitsuru IWASAKI struct event_cmd dummy;
191d50a71bdSMitsuru IWASAKI struct event_cmd *q = &dummy;
192d50a71bdSMitsuru IWASAKI for ( ;p; p = p->next) {
193d50a71bdSMitsuru IWASAKI assert(p->op->clone);
194d50a71bdSMitsuru IWASAKI if ((q->next = p->op->clone(p)) == NULL)
195103e4932SUlrich Spörlein err(1, "out of memory");
196d50a71bdSMitsuru IWASAKI q = q->next;
197d50a71bdSMitsuru IWASAKI }
198d50a71bdSMitsuru IWASAKI q->next = NULL;
199d50a71bdSMitsuru IWASAKI return dummy.next;
200d50a71bdSMitsuru IWASAKI }
201d50a71bdSMitsuru IWASAKI void
free_event_cmd_list(struct event_cmd * p)202d50a71bdSMitsuru IWASAKI free_event_cmd_list(struct event_cmd *p)
203d50a71bdSMitsuru IWASAKI {
204d50a71bdSMitsuru IWASAKI struct event_cmd * q;
205d50a71bdSMitsuru IWASAKI for ( ; p ; p = q) {
206d50a71bdSMitsuru IWASAKI q = p->next;
207d50a71bdSMitsuru IWASAKI if (p->op->free)
208d50a71bdSMitsuru IWASAKI p->op->free(p);
209d50a71bdSMitsuru IWASAKI free(p);
210d50a71bdSMitsuru IWASAKI }
211d50a71bdSMitsuru IWASAKI }
212d50a71bdSMitsuru IWASAKI int
register_battery_handlers(int level,int direction,struct event_cmd * cmdlist)213719b9dc1SNick Sayer register_battery_handlers(
214719b9dc1SNick Sayer int level, int direction,
215719b9dc1SNick Sayer struct event_cmd *cmdlist)
216719b9dc1SNick Sayer {
217719b9dc1SNick Sayer /*
218719b9dc1SNick Sayer * level is negative if it's in "minutes", non-negative if
219719b9dc1SNick Sayer * percentage.
220719b9dc1SNick Sayer *
221719b9dc1SNick Sayer * direction =1 means we care about this level when charging,
222719b9dc1SNick Sayer * direction =-1 means we care about it when discharging.
223719b9dc1SNick Sayer */
224719b9dc1SNick Sayer if (level>100) /* percentage > 100 */
225719b9dc1SNick Sayer return -1;
226719b9dc1SNick Sayer if (abs(direction) != 1) /* nonsense direction value */
227719b9dc1SNick Sayer return -1;
228719b9dc1SNick Sayer
229719b9dc1SNick Sayer if (cmdlist) {
230719b9dc1SNick Sayer struct battery_watch_event *we;
231719b9dc1SNick Sayer
232719b9dc1SNick Sayer if ((we = malloc(sizeof(struct battery_watch_event))) == NULL)
233103e4932SUlrich Spörlein err(1, "out of memory");
234719b9dc1SNick Sayer
235719b9dc1SNick Sayer we->next = battery_watch_list; /* starts at NULL */
236719b9dc1SNick Sayer battery_watch_list = we;
237719b9dc1SNick Sayer we->level = abs(level);
238719b9dc1SNick Sayer we->type = (level<0)?BATTERY_MINUTES:BATTERY_PERCENT;
239719b9dc1SNick Sayer we->direction = (direction<0)?BATTERY_DISCHARGING:
240719b9dc1SNick Sayer BATTERY_CHARGING;
241719b9dc1SNick Sayer we->done = 0;
242719b9dc1SNick Sayer we->cmdlist = clone_event_cmd_list(cmdlist);
243719b9dc1SNick Sayer }
244719b9dc1SNick Sayer return 0;
245719b9dc1SNick Sayer }
246719b9dc1SNick Sayer int
register_apm_event_handlers(bitstr_t bit_decl (evlist,EVENT_MAX),struct event_cmd * cmdlist)247d50a71bdSMitsuru IWASAKI register_apm_event_handlers(
248d50a71bdSMitsuru IWASAKI bitstr_t bit_decl(evlist, EVENT_MAX),
249d50a71bdSMitsuru IWASAKI struct event_cmd *cmdlist)
250d50a71bdSMitsuru IWASAKI {
251d50a71bdSMitsuru IWASAKI if (cmdlist) {
252d50a71bdSMitsuru IWASAKI bitstr_t bit_decl(tmp, EVENT_MAX);
253d50a71bdSMitsuru IWASAKI memcpy(&tmp, evlist, bitstr_size(EVENT_MAX));
254d50a71bdSMitsuru IWASAKI
255d50a71bdSMitsuru IWASAKI for (;;) {
256d50a71bdSMitsuru IWASAKI int n;
257d50a71bdSMitsuru IWASAKI struct event_cmd *p;
258d50a71bdSMitsuru IWASAKI struct event_cmd *q;
259d50a71bdSMitsuru IWASAKI bit_ffs(tmp, EVENT_MAX, &n);
260d50a71bdSMitsuru IWASAKI if (n < 0)
261d50a71bdSMitsuru IWASAKI break;
262d50a71bdSMitsuru IWASAKI p = events[n].cmdlist;
263d50a71bdSMitsuru IWASAKI if ((q = clone_event_cmd_list(cmdlist)) == NULL)
264103e4932SUlrich Spörlein err(1, "out of memory");
265d50a71bdSMitsuru IWASAKI if (p) {
266d50a71bdSMitsuru IWASAKI while (p->next != NULL)
267d50a71bdSMitsuru IWASAKI p = p->next;
268d50a71bdSMitsuru IWASAKI p->next = q;
269d50a71bdSMitsuru IWASAKI } else {
270d50a71bdSMitsuru IWASAKI events[n].cmdlist = q;
271d50a71bdSMitsuru IWASAKI }
272d50a71bdSMitsuru IWASAKI bit_clear(tmp, n);
273d50a71bdSMitsuru IWASAKI }
274d50a71bdSMitsuru IWASAKI }
275d50a71bdSMitsuru IWASAKI return 0;
276d50a71bdSMitsuru IWASAKI }
277d50a71bdSMitsuru IWASAKI
278d50a71bdSMitsuru IWASAKI /*
279d50a71bdSMitsuru IWASAKI * execute command
280d50a71bdSMitsuru IWASAKI */
281d50a71bdSMitsuru IWASAKI int
exec_run_cmd(struct event_cmd * p)282719b9dc1SNick Sayer exec_run_cmd(struct event_cmd *p)
283d50a71bdSMitsuru IWASAKI {
284d50a71bdSMitsuru IWASAKI int status = 0;
285d50a71bdSMitsuru IWASAKI
286d50a71bdSMitsuru IWASAKI for (; p; p = p->next) {
287d50a71bdSMitsuru IWASAKI assert(p->op->act);
288d50a71bdSMitsuru IWASAKI if (verbose)
289d50a71bdSMitsuru IWASAKI syslog(LOG_INFO, "action: %s", p->name);
290d50a71bdSMitsuru IWASAKI status = p->op->act(p);
291d50a71bdSMitsuru IWASAKI if (status) {
292d50a71bdSMitsuru IWASAKI syslog(LOG_NOTICE, "command finished with %d\n", status);
293d50a71bdSMitsuru IWASAKI break;
294d50a71bdSMitsuru IWASAKI }
295d50a71bdSMitsuru IWASAKI }
296d50a71bdSMitsuru IWASAKI return status;
297d50a71bdSMitsuru IWASAKI }
298d50a71bdSMitsuru IWASAKI
299d50a71bdSMitsuru IWASAKI /*
300719b9dc1SNick Sayer * execute command -- the event version
301719b9dc1SNick Sayer */
302719b9dc1SNick Sayer int
exec_event_cmd(struct event_config * ev)303719b9dc1SNick Sayer exec_event_cmd(struct event_config *ev)
304719b9dc1SNick Sayer {
305719b9dc1SNick Sayer int status = 0;
306719b9dc1SNick Sayer
307719b9dc1SNick Sayer status = exec_run_cmd(ev->cmdlist);
308719b9dc1SNick Sayer if (status && ev->rejectable) {
309719b9dc1SNick Sayer syslog(LOG_ERR, "canceled");
310103e4932SUlrich Spörlein event_cmd_reject_act(NULL);
311719b9dc1SNick Sayer }
312719b9dc1SNick Sayer return status;
313719b9dc1SNick Sayer }
314719b9dc1SNick Sayer
315719b9dc1SNick Sayer /*
316d50a71bdSMitsuru IWASAKI * read config file
317d50a71bdSMitsuru IWASAKI */
318d50a71bdSMitsuru IWASAKI extern FILE * yyin;
319d50a71bdSMitsuru IWASAKI extern int yydebug;
320d50a71bdSMitsuru IWASAKI
321d50a71bdSMitsuru IWASAKI void
read_config(void)322d50a71bdSMitsuru IWASAKI read_config(void)
323d50a71bdSMitsuru IWASAKI {
324d50a71bdSMitsuru IWASAKI int i;
325d50a71bdSMitsuru IWASAKI
326d50a71bdSMitsuru IWASAKI if ((yyin = fopen(apmd_configfile, "r")) == NULL) {
327103e4932SUlrich Spörlein err(1, "cannot open config file");
328d50a71bdSMitsuru IWASAKI }
329d50a71bdSMitsuru IWASAKI
330d50a71bdSMitsuru IWASAKI #ifdef DEBUG
331d50a71bdSMitsuru IWASAKI yydebug = debug_level;
332d50a71bdSMitsuru IWASAKI #endif
333d50a71bdSMitsuru IWASAKI
334d50a71bdSMitsuru IWASAKI if (yyparse() != 0)
335103e4932SUlrich Spörlein err(1, "cannot parse config file");
336d50a71bdSMitsuru IWASAKI
337d50a71bdSMitsuru IWASAKI fclose(yyin);
338d50a71bdSMitsuru IWASAKI
339d50a71bdSMitsuru IWASAKI /* enable events */
340d50a71bdSMitsuru IWASAKI for (i = 0; i < EVENT_MAX; i++) {
341d50a71bdSMitsuru IWASAKI if (events[i].cmdlist) {
342d50a71bdSMitsuru IWASAKI u_int event_type = i;
343d50a71bdSMitsuru IWASAKI if (write(apmctl_fd, &event_type, sizeof(u_int)) == -1) {
344103e4932SUlrich Spörlein err(1, "cannot enable event 0x%x", event_type);
345d50a71bdSMitsuru IWASAKI }
346d50a71bdSMitsuru IWASAKI }
347d50a71bdSMitsuru IWASAKI }
348d50a71bdSMitsuru IWASAKI }
349d50a71bdSMitsuru IWASAKI
350d50a71bdSMitsuru IWASAKI void
dump_config(void)351103e4932SUlrich Spörlein dump_config(void)
352d50a71bdSMitsuru IWASAKI {
353d50a71bdSMitsuru IWASAKI int i;
354719b9dc1SNick Sayer struct battery_watch_event *q;
355d50a71bdSMitsuru IWASAKI
356d50a71bdSMitsuru IWASAKI for (i = 0; i < EVENT_MAX; i++) {
357d50a71bdSMitsuru IWASAKI struct event_cmd * p;
358d50a71bdSMitsuru IWASAKI if ((p = events[i].cmdlist)) {
359d50a71bdSMitsuru IWASAKI fprintf(stderr, "apm_event %s {\n", events[i].name);
360d50a71bdSMitsuru IWASAKI for ( ; p ; p = p->next) {
361d50a71bdSMitsuru IWASAKI fprintf(stderr, "\t%s", p->name);
362d50a71bdSMitsuru IWASAKI if (p->op->dump)
363d50a71bdSMitsuru IWASAKI p->op->dump(p, stderr);
364d50a71bdSMitsuru IWASAKI fprintf(stderr, ";\n");
365d50a71bdSMitsuru IWASAKI }
366d50a71bdSMitsuru IWASAKI fprintf(stderr, "}\n");
367d50a71bdSMitsuru IWASAKI }
368d50a71bdSMitsuru IWASAKI }
369719b9dc1SNick Sayer for (q = battery_watch_list ; q != NULL ; q = q -> next) {
370719b9dc1SNick Sayer struct event_cmd * p;
371719b9dc1SNick Sayer fprintf(stderr, "apm_battery %d%s %s {\n",
372719b9dc1SNick Sayer q -> level,
373719b9dc1SNick Sayer (q -> type == BATTERY_PERCENT)?"%":"m",
374719b9dc1SNick Sayer (q -> direction == BATTERY_CHARGING)?"charging":
375719b9dc1SNick Sayer "discharging");
376719b9dc1SNick Sayer for ( p = q -> cmdlist; p ; p = p->next) {
377719b9dc1SNick Sayer fprintf(stderr, "\t%s", p->name);
378719b9dc1SNick Sayer if (p->op->dump)
379719b9dc1SNick Sayer p->op->dump(p, stderr);
380719b9dc1SNick Sayer fprintf(stderr, ";\n");
381719b9dc1SNick Sayer }
382719b9dc1SNick Sayer fprintf(stderr, "}\n");
383719b9dc1SNick Sayer }
384d50a71bdSMitsuru IWASAKI }
385d50a71bdSMitsuru IWASAKI
386d50a71bdSMitsuru IWASAKI void
destroy_config(void)387103e4932SUlrich Spörlein destroy_config(void)
388d50a71bdSMitsuru IWASAKI {
389d50a71bdSMitsuru IWASAKI int i;
390719b9dc1SNick Sayer struct battery_watch_event *q;
391d50a71bdSMitsuru IWASAKI
392d50a71bdSMitsuru IWASAKI /* disable events */
393d50a71bdSMitsuru IWASAKI for (i = 0; i < EVENT_MAX; i++) {
394d50a71bdSMitsuru IWASAKI if (events[i].cmdlist) {
395d50a71bdSMitsuru IWASAKI u_int event_type = i;
396d50a71bdSMitsuru IWASAKI if (write(apmctl_fd, &event_type, sizeof(u_int)) == -1) {
397103e4932SUlrich Spörlein err(1, "cannot disable event 0x%x", event_type);
398d50a71bdSMitsuru IWASAKI }
399d50a71bdSMitsuru IWASAKI }
400d50a71bdSMitsuru IWASAKI }
401d50a71bdSMitsuru IWASAKI
402d50a71bdSMitsuru IWASAKI for (i = 0; i < EVENT_MAX; i++) {
403d50a71bdSMitsuru IWASAKI struct event_cmd * p;
404d50a71bdSMitsuru IWASAKI if ((p = events[i].cmdlist))
405d50a71bdSMitsuru IWASAKI free_event_cmd_list(p);
406d50a71bdSMitsuru IWASAKI events[i].cmdlist = NULL;
407d50a71bdSMitsuru IWASAKI }
408719b9dc1SNick Sayer
409719b9dc1SNick Sayer for( ; battery_watch_list; battery_watch_list = battery_watch_list -> next) {
410719b9dc1SNick Sayer free_event_cmd_list(battery_watch_list->cmdlist);
411719b9dc1SNick Sayer q = battery_watch_list->next;
412719b9dc1SNick Sayer free(battery_watch_list);
413719b9dc1SNick Sayer battery_watch_list = q;
414719b9dc1SNick Sayer }
415d50a71bdSMitsuru IWASAKI }
416d50a71bdSMitsuru IWASAKI
417d50a71bdSMitsuru IWASAKI void
restart(void)418103e4932SUlrich Spörlein restart(void)
419d50a71bdSMitsuru IWASAKI {
420d50a71bdSMitsuru IWASAKI destroy_config();
421d50a71bdSMitsuru IWASAKI read_config();
422d50a71bdSMitsuru IWASAKI if (verbose)
423d50a71bdSMitsuru IWASAKI dump_config();
424d50a71bdSMitsuru IWASAKI }
425d50a71bdSMitsuru IWASAKI
426d50a71bdSMitsuru IWASAKI /*
427d50a71bdSMitsuru IWASAKI * write pid file
428d50a71bdSMitsuru IWASAKI */
429d50a71bdSMitsuru IWASAKI static void
write_pid(void)430103e4932SUlrich Spörlein write_pid(void)
431d50a71bdSMitsuru IWASAKI {
432d50a71bdSMitsuru IWASAKI FILE *fp = fopen(apmd_pidfile, "w");
433d50a71bdSMitsuru IWASAKI
434d50a71bdSMitsuru IWASAKI if (fp) {
43534759932SKevin Lo fprintf(fp, "%ld\n", (long)getpid());
436d50a71bdSMitsuru IWASAKI fclose(fp);
437d50a71bdSMitsuru IWASAKI }
438d50a71bdSMitsuru IWASAKI }
439d50a71bdSMitsuru IWASAKI
440d50a71bdSMitsuru IWASAKI /*
441d50a71bdSMitsuru IWASAKI * handle signals
442d50a71bdSMitsuru IWASAKI */
443d50a71bdSMitsuru IWASAKI static int signal_fd[2];
444d50a71bdSMitsuru IWASAKI
445d50a71bdSMitsuru IWASAKI void
enque_signal(int sig)446d50a71bdSMitsuru IWASAKI enque_signal(int sig)
447d50a71bdSMitsuru IWASAKI {
448d50a71bdSMitsuru IWASAKI if (write(signal_fd[1], &sig, sizeof sig) != sizeof sig)
449103e4932SUlrich Spörlein err(1, "cannot process signal.");
450d50a71bdSMitsuru IWASAKI }
451d50a71bdSMitsuru IWASAKI
452d50a71bdSMitsuru IWASAKI void
wait_child(void)453103e4932SUlrich Spörlein wait_child(void)
454d50a71bdSMitsuru IWASAKI {
455d50a71bdSMitsuru IWASAKI int status;
456d50a71bdSMitsuru IWASAKI while (waitpid(-1, &status, WNOHANG) > 0)
457d50a71bdSMitsuru IWASAKI ;
458d50a71bdSMitsuru IWASAKI }
459d50a71bdSMitsuru IWASAKI
460d50a71bdSMitsuru IWASAKI int
proc_signal(int fd)461d50a71bdSMitsuru IWASAKI proc_signal(int fd)
462d50a71bdSMitsuru IWASAKI {
463cd0788e1SUlrich Spörlein int rc = 0;
464d50a71bdSMitsuru IWASAKI int sig;
465d50a71bdSMitsuru IWASAKI
466d50a71bdSMitsuru IWASAKI while (read(fd, &sig, sizeof sig) == sizeof sig) {
467d50a71bdSMitsuru IWASAKI syslog(LOG_INFO, "caught signal: %d", sig);
468d50a71bdSMitsuru IWASAKI switch (sig) {
469d50a71bdSMitsuru IWASAKI case SIGHUP:
470d50a71bdSMitsuru IWASAKI syslog(LOG_NOTICE, "restart by SIG");
471d50a71bdSMitsuru IWASAKI restart();
472d50a71bdSMitsuru IWASAKI break;
473d50a71bdSMitsuru IWASAKI case SIGTERM:
474d50a71bdSMitsuru IWASAKI syslog(LOG_NOTICE, "going down on signal %d", sig);
475f90445cfSMatthew N. Dodd rc = -1;
476cd0788e1SUlrich Spörlein return rc;
477d50a71bdSMitsuru IWASAKI case SIGCHLD:
478d50a71bdSMitsuru IWASAKI wait_child();
479d50a71bdSMitsuru IWASAKI break;
480d50a71bdSMitsuru IWASAKI default:
481103e4932SUlrich Spörlein warn("unexpected signal(%d) received.", sig);
482d50a71bdSMitsuru IWASAKI break;
483d50a71bdSMitsuru IWASAKI }
484d50a71bdSMitsuru IWASAKI }
485d50a71bdSMitsuru IWASAKI return rc;
486d50a71bdSMitsuru IWASAKI }
487d50a71bdSMitsuru IWASAKI void
proc_apmevent(int fd)488d50a71bdSMitsuru IWASAKI proc_apmevent(int fd)
489d50a71bdSMitsuru IWASAKI {
490d50a71bdSMitsuru IWASAKI struct apm_event_info apmevent;
491d50a71bdSMitsuru IWASAKI
492d50a71bdSMitsuru IWASAKI while (ioctl(fd, APMIO_NEXTEVENT, &apmevent) == 0) {
493d50a71bdSMitsuru IWASAKI int status;
494d50a71bdSMitsuru IWASAKI syslog(LOG_NOTICE, "apmevent %04x index %d\n",
495d50a71bdSMitsuru IWASAKI apmevent.type, apmevent.index);
496d50a71bdSMitsuru IWASAKI syslog(LOG_INFO, "apm event: %s", events[apmevent.type].name);
497d50a71bdSMitsuru IWASAKI if (fork() == 0) {
498d50a71bdSMitsuru IWASAKI status = exec_event_cmd(&events[apmevent.type]);
499d50a71bdSMitsuru IWASAKI exit(status);
500d50a71bdSMitsuru IWASAKI }
501d50a71bdSMitsuru IWASAKI }
502d50a71bdSMitsuru IWASAKI }
503719b9dc1SNick Sayer
504719b9dc1SNick Sayer #define AC_POWER_STATE ((pw_info.ai_acline == 1) ? BATTERY_CHARGING :\
505719b9dc1SNick Sayer BATTERY_DISCHARGING)
506719b9dc1SNick Sayer
507719b9dc1SNick Sayer void
check_battery(void)508103e4932SUlrich Spörlein check_battery(void)
509719b9dc1SNick Sayer {
510719b9dc1SNick Sayer
511719b9dc1SNick Sayer static int first_time=1, last_state;
512f90445cfSMatthew N. Dodd int status;
513719b9dc1SNick Sayer
514719b9dc1SNick Sayer struct apm_info pw_info;
515719b9dc1SNick Sayer struct battery_watch_event *p;
516719b9dc1SNick Sayer
517719b9dc1SNick Sayer /* If we don't care, don't bother */
518719b9dc1SNick Sayer if (battery_watch_list == NULL)
519719b9dc1SNick Sayer return;
520719b9dc1SNick Sayer
521719b9dc1SNick Sayer if (first_time) {
522719b9dc1SNick Sayer if ( ioctl(apmnorm_fd, APMIO_GETINFO, &pw_info) < 0)
523103e4932SUlrich Spörlein err(1, "cannot check battery state.");
524719b9dc1SNick Sayer /*
525719b9dc1SNick Sayer * This next statement isn't entirely true. The spec does not tie AC
526719b9dc1SNick Sayer * line state to battery charging or not, but this is a bit lazier to do.
527719b9dc1SNick Sayer */
528719b9dc1SNick Sayer last_state = AC_POWER_STATE;
529719b9dc1SNick Sayer first_time = 0;
530719b9dc1SNick Sayer return; /* We can't process events, we have no baseline */
531719b9dc1SNick Sayer }
532719b9dc1SNick Sayer
533719b9dc1SNick Sayer /*
534719b9dc1SNick Sayer * XXX - should we do this a bunch of times and perform some sort
535719b9dc1SNick Sayer * of smoothing or correction?
536719b9dc1SNick Sayer */
537719b9dc1SNick Sayer if ( ioctl(apmnorm_fd, APMIO_GETINFO, &pw_info) < 0)
538103e4932SUlrich Spörlein err(1, "cannot check battery state.");
539719b9dc1SNick Sayer
540719b9dc1SNick Sayer /*
541719b9dc1SNick Sayer * If we're not in the state now that we were in last time,
542719b9dc1SNick Sayer * then it's a transition, which means we must clean out
543719b9dc1SNick Sayer * the event-caught state.
544719b9dc1SNick Sayer */
545719b9dc1SNick Sayer if (last_state != AC_POWER_STATE) {
546f90445cfSMatthew N. Dodd if (soft_power_state_change && fork() == 0) {
547f90445cfSMatthew N. Dodd status = exec_event_cmd(&events[PMEV_POWERSTATECHANGE]);
548f90445cfSMatthew N. Dodd exit(status);
549f90445cfSMatthew N. Dodd }
550719b9dc1SNick Sayer last_state = AC_POWER_STATE;
551719b9dc1SNick Sayer for (p = battery_watch_list ; p!=NULL ; p = p -> next)
552719b9dc1SNick Sayer p->done = 0;
553719b9dc1SNick Sayer }
554719b9dc1SNick Sayer for (p = battery_watch_list ; p != NULL ; p = p -> next)
555719b9dc1SNick Sayer if (p -> direction == AC_POWER_STATE &&
556719b9dc1SNick Sayer !(p -> done) &&
557719b9dc1SNick Sayer ((p -> type == BATTERY_PERCENT &&
558103e4932SUlrich Spörlein p -> level == (int)pw_info.ai_batt_life) ||
559719b9dc1SNick Sayer (p -> type == BATTERY_MINUTES &&
560719b9dc1SNick Sayer p -> level == (pw_info.ai_batt_time / 60)))) {
561719b9dc1SNick Sayer p -> done++;
562719b9dc1SNick Sayer if (verbose)
563719b9dc1SNick Sayer syslog(LOG_NOTICE, "Caught battery event: %s, %d%s",
564719b9dc1SNick Sayer (p -> direction == BATTERY_CHARGING)?"charging":"discharging",
565719b9dc1SNick Sayer p -> level,
566719b9dc1SNick Sayer (p -> type == BATTERY_PERCENT)?"%":" minutes");
567719b9dc1SNick Sayer if (fork() == 0) {
568719b9dc1SNick Sayer status = exec_run_cmd(p -> cmdlist);
569719b9dc1SNick Sayer exit(status);
570719b9dc1SNick Sayer }
571719b9dc1SNick Sayer }
572719b9dc1SNick Sayer }
573d50a71bdSMitsuru IWASAKI void
event_loop(void)574d50a71bdSMitsuru IWASAKI event_loop(void)
575d50a71bdSMitsuru IWASAKI {
576d50a71bdSMitsuru IWASAKI int fdmax = 0;
577d50a71bdSMitsuru IWASAKI struct sigaction nsa;
578d50a71bdSMitsuru IWASAKI fd_set master_rfds;
579d50a71bdSMitsuru IWASAKI sigset_t sigmask, osigmask;
580d50a71bdSMitsuru IWASAKI
581d50a71bdSMitsuru IWASAKI FD_ZERO(&master_rfds);
582d50a71bdSMitsuru IWASAKI FD_SET(apmctl_fd, &master_rfds);
583d50a71bdSMitsuru IWASAKI fdmax = apmctl_fd > fdmax ? apmctl_fd : fdmax;
584d50a71bdSMitsuru IWASAKI
585d50a71bdSMitsuru IWASAKI FD_SET(signal_fd[0], &master_rfds);
586d50a71bdSMitsuru IWASAKI fdmax = signal_fd[0] > fdmax ? signal_fd[0] : fdmax;
587d50a71bdSMitsuru IWASAKI
588d50a71bdSMitsuru IWASAKI memset(&nsa, 0, sizeof nsa);
589d50a71bdSMitsuru IWASAKI nsa.sa_handler = enque_signal;
590d50a71bdSMitsuru IWASAKI sigfillset(&nsa.sa_mask);
591d50a71bdSMitsuru IWASAKI nsa.sa_flags = SA_RESTART;
592d50a71bdSMitsuru IWASAKI sigaction(SIGHUP, &nsa, NULL);
593d50a71bdSMitsuru IWASAKI sigaction(SIGCHLD, &nsa, NULL);
594d50a71bdSMitsuru IWASAKI sigaction(SIGTERM, &nsa, NULL);
595d50a71bdSMitsuru IWASAKI
596d50a71bdSMitsuru IWASAKI sigemptyset(&sigmask);
597d50a71bdSMitsuru IWASAKI sigaddset(&sigmask, SIGHUP);
598d50a71bdSMitsuru IWASAKI sigaddset(&sigmask, SIGCHLD);
599d50a71bdSMitsuru IWASAKI sigaddset(&sigmask, SIGTERM);
600d50a71bdSMitsuru IWASAKI sigprocmask(SIG_SETMASK, &sigmask, &osigmask);
601d50a71bdSMitsuru IWASAKI
602d50a71bdSMitsuru IWASAKI while (1) {
603d50a71bdSMitsuru IWASAKI fd_set rfds;
604719b9dc1SNick Sayer int res;
605719b9dc1SNick Sayer struct timeval to;
606719b9dc1SNick Sayer
607719b9dc1SNick Sayer to.tv_sec = BATT_CHK_INTV;
608719b9dc1SNick Sayer to.tv_usec = 0;
609d50a71bdSMitsuru IWASAKI
610d50a71bdSMitsuru IWASAKI memcpy(&rfds, &master_rfds, sizeof rfds);
611d50a71bdSMitsuru IWASAKI sigprocmask(SIG_SETMASK, &osigmask, NULL);
612719b9dc1SNick Sayer if ((res=select(fdmax + 1, &rfds, 0, 0, &to)) < 0) {
613d50a71bdSMitsuru IWASAKI if (errno != EINTR)
614103e4932SUlrich Spörlein err(1, "select");
615d50a71bdSMitsuru IWASAKI }
616d50a71bdSMitsuru IWASAKI sigprocmask(SIG_SETMASK, &sigmask, NULL);
617d50a71bdSMitsuru IWASAKI
618719b9dc1SNick Sayer if (res == 0) { /* time to check the battery */
619719b9dc1SNick Sayer check_battery();
620719b9dc1SNick Sayer continue;
621719b9dc1SNick Sayer }
622719b9dc1SNick Sayer
623d50a71bdSMitsuru IWASAKI if (FD_ISSET(signal_fd[0], &rfds)) {
624d50a71bdSMitsuru IWASAKI if (proc_signal(signal_fd[0]) < 0)
625cd0788e1SUlrich Spörlein return;
626d50a71bdSMitsuru IWASAKI }
627719b9dc1SNick Sayer
628d50a71bdSMitsuru IWASAKI if (FD_ISSET(apmctl_fd, &rfds))
629d50a71bdSMitsuru IWASAKI proc_apmevent(apmctl_fd);
630d50a71bdSMitsuru IWASAKI }
631d50a71bdSMitsuru IWASAKI }
632d50a71bdSMitsuru IWASAKI
633e46b89dcSPeter Wemm int
main(int ac,char * av[])634d50a71bdSMitsuru IWASAKI main(int ac, char* av[])
635d50a71bdSMitsuru IWASAKI {
636d50a71bdSMitsuru IWASAKI int ch;
637d50a71bdSMitsuru IWASAKI int daemonize = 1;
638d50a71bdSMitsuru IWASAKI char *prog;
639d50a71bdSMitsuru IWASAKI int logopt = LOG_NDELAY | LOG_PID;
640d50a71bdSMitsuru IWASAKI
6411c6adfcfSKevin Lo while ((ch = getopt(ac, av, "df:sv")) != -1) {
642d50a71bdSMitsuru IWASAKI switch (ch) {
643d50a71bdSMitsuru IWASAKI case 'd':
644d50a71bdSMitsuru IWASAKI daemonize = 0;
645d50a71bdSMitsuru IWASAKI debug_level++;
646d50a71bdSMitsuru IWASAKI break;
647d50a71bdSMitsuru IWASAKI case 'f':
648d50a71bdSMitsuru IWASAKI apmd_configfile = optarg;
649d50a71bdSMitsuru IWASAKI break;
650f90445cfSMatthew N. Dodd case 's':
651f90445cfSMatthew N. Dodd soft_power_state_change = 1;
652f90445cfSMatthew N. Dodd break;
653d50a71bdSMitsuru IWASAKI case 'v':
654d50a71bdSMitsuru IWASAKI verbose = 1;
655d50a71bdSMitsuru IWASAKI break;
656d50a71bdSMitsuru IWASAKI default:
657103e4932SUlrich Spörlein err(1, "unknown option `%c'", ch);
658d50a71bdSMitsuru IWASAKI }
659d50a71bdSMitsuru IWASAKI }
660d50a71bdSMitsuru IWASAKI
661d50a71bdSMitsuru IWASAKI if (daemonize)
662d50a71bdSMitsuru IWASAKI daemon(0, 0);
663d50a71bdSMitsuru IWASAKI
664d50a71bdSMitsuru IWASAKI #ifdef NICE_INCR
665103e4932SUlrich Spörlein nice(NICE_INCR);
666d50a71bdSMitsuru IWASAKI #endif
667d50a71bdSMitsuru IWASAKI
668d50a71bdSMitsuru IWASAKI if (!daemonize)
669d50a71bdSMitsuru IWASAKI logopt |= LOG_PERROR;
670d50a71bdSMitsuru IWASAKI
671d50a71bdSMitsuru IWASAKI prog = strrchr(av[0], '/');
672d50a71bdSMitsuru IWASAKI openlog(prog ? prog+1 : av[0], logopt, LOG_DAEMON);
673d50a71bdSMitsuru IWASAKI
674d50a71bdSMitsuru IWASAKI syslog(LOG_NOTICE, "start");
675d50a71bdSMitsuru IWASAKI
676d50a71bdSMitsuru IWASAKI if (pipe(signal_fd) < 0)
677103e4932SUlrich Spörlein err(1, "pipe");
678d50a71bdSMitsuru IWASAKI if (fcntl(signal_fd[0], F_SETFL, O_NONBLOCK) < 0)
679103e4932SUlrich Spörlein err(1, "fcntl");
680d50a71bdSMitsuru IWASAKI
681719b9dc1SNick Sayer if ((apmnorm_fd = open(APM_NORM_DEVICEFILE, O_RDWR)) == -1) {
682103e4932SUlrich Spörlein err(1, "cannot open device file `%s'", APM_NORM_DEVICEFILE);
683719b9dc1SNick Sayer }
684719b9dc1SNick Sayer
6859ad4f2d0SMatthew N. Dodd if (fcntl(apmnorm_fd, F_SETFD, 1) == -1) {
686103e4932SUlrich Spörlein err(1, "cannot set close-on-exec flag for device file '%s'", APM_NORM_DEVICEFILE);
6879ad4f2d0SMatthew N. Dodd }
6889ad4f2d0SMatthew N. Dodd
689d50a71bdSMitsuru IWASAKI if ((apmctl_fd = open(APM_CTL_DEVICEFILE, O_RDWR)) == -1) {
690103e4932SUlrich Spörlein err(1, "cannot open device file `%s'", APM_CTL_DEVICEFILE);
691d50a71bdSMitsuru IWASAKI }
692d50a71bdSMitsuru IWASAKI
6939ad4f2d0SMatthew N. Dodd if (fcntl(apmctl_fd, F_SETFD, 1) == -1) {
694103e4932SUlrich Spörlein err(1, "cannot set close-on-exec flag for device file '%s'", APM_CTL_DEVICEFILE);
6959ad4f2d0SMatthew N. Dodd }
6969ad4f2d0SMatthew N. Dodd
697d50a71bdSMitsuru IWASAKI restart();
698d50a71bdSMitsuru IWASAKI write_pid();
699d50a71bdSMitsuru IWASAKI event_loop();
700d50a71bdSMitsuru IWASAKI exit(EXIT_SUCCESS);
701d50a71bdSMitsuru IWASAKI }
702d50a71bdSMitsuru IWASAKI
703