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