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