/* * $Id: upsd.c,v 2.0.1.6 1996/08/02 21:43:58 alexis Exp alexis $ * * UPS Daemon * The Wild Wind Communications, 1995, 1996 * * See file LICENSE for the distribution terms of this software. */ #include "upsd.h" #include "apc.h" /* * Actual UPS pre-initialized handler with reasonable defaults. * The initialization is *very* GNU CC specific. Sigh. */ static struct ups ups = { NULL, /* model */ {NULL, 0, {0, 0}, /* port */ {0, 0, 0, 0, {[0 ... NCCS-1] = 0}, 0, 0}, /* otty */ {0, 0, CS8 | CREAD | CLOCAL, 0, {[0 ... NCCS-1] = 0}, B2400, B2400}, /* ntty */ 1, {0, 0}, /* block size and delay */ {QUEUE_SIZE, NULL, NULL, NULL}}, /* queue */ NULL, /* status */ NULL /* events */ }; /* All supported UPS models. */ struct ups_model *upslist[] = { &apc_SmartUPS_230, &apc_SmartUPS_vs_420, NULL }; /* Signal list to handle. */ static int sig_handle_list[] = { SIGABRT, SIGBUS, SIGEMT, SIGFPE, SIGILL, SIGIO, SIGQUIT, SIGSEGV, SIGSYS, 0 }; /* Signal list to ignore. */ static int sig_ignore_list[] = { SIGALRM, SIGCHLD, SIGCONT, SIGHUP, SIGINFO, SIGINT, SIGPIPE, SIGPROF, SIGTERM, SIGTRAP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGUSR1, SIGUSR2, SIGVTALRM, SIGWINCH, SIGXCPU, SIGXFSZ, 0 }; static char *triggerb; struct ups *upsp = &ups; struct ups_trig *zero_trig; time_t current_time, next_time; /* * This is a daemon for monitoring an Uninterruptable Power Source * or as usually referenced UPS. The daemon is intended to support * several protocols but currently only APC SmartUPS protocol is * implemented. */ int main(argc, argv) int argc; char **argv; { extern char *optarg; extern int optind; register int *sp; register int c; struct sigaction act; struct timeval tv; /* Parse the command line first. */ while((c = getopt(argc, argv, "")) != EOF) { switch(c) { default: usage(); /* NOTREACHED */ } } argc -= optind; argv += optind; /* Set up the system log. */ openlog(NULL, LOG_CONS | LOG_PID, LOG_DAEMON); /* Configure the daemon. */ if(configure(_PATH_UPSD_CONF) == -1) { exit(1); } if((triggerb = xalloc(upsp->port.queue.size)) == NULL) { exit(1); } /* Set up signal handling. */ sigemptyset(&act.sa_mask); act.sa_handler = SIG_IGN; act.sa_flags = 0; for(sp = sig_ignore_list; *sp; sp++) { if(sigaction(*sp, &act, NULL) == -1) { syslog(LOG_ERR, "cannot install signal handler for signal %d: %m", *sp); exit(1); } } act.sa_handler = signal_handler; act.sa_flags = SA_RESTART; for(sp = sig_handle_list; *sp; sp++) { if(sigaction(*sp, &act, NULL) == -1) { syslog(LOG_ERR, "cannot install signal handler for signal %d: %m", *sp); exit(1); } } /* Detach and become a daemon. */ #ifndef DEBUG if(daemon(0, 1) == -1) { #else if(daemon(1, 1) == -1) { #endif syslog(LOG_ERR, "cannot become a daemon: %m"); exit(1); } /* Open the port. */ if(openport() == -1) { exit(1); } (void)mkpid(_PATH_UPSD_PID); /* Stamp the current time for top-level conditionless events. */ if(getcurrenttime()) { exit(1); } traverse2((struct chain *)upsp->eventv, (void *)trig, (void *)zero_trig); syslog(LOG_INFO, "ups daemon started"); /* The main loop. */ for(;;) { if(getcurrenttime()) { TERMINATE; /* XXX: Or continue? */ } next_time = 0; traverse((struct chain *)upsp->eventv, (void *)process); if(getcurrenttime()) { TERMINATE; /* XXX: Or continue? */ } if(next_time != 0) { tv.tv_sec = next_time - current_time; tv.tv_usec = 0; (void) select(0, NULL, NULL, NULL, &tv); } else { (void) select(0, NULL, NULL, NULL, NULL); } } /* NOTREACHED */ exit(1); } /* * Handles every signal received. */ void signal_handler(sig, code, scp) int sig; int code; struct sigcontext *scp; { register int s; register struct ups_trig *tp; if(sig == SIGIO || sig == SIGURG) { if(listenport() == -1) { exit(1); /* XXX: Wrong... */ } s = readport(triggerb, upsp->port.queue.size, 0); if(s > 0) { if((tp = checktrigger(triggerb, s))) { flushport(); /* XXX: Is it correct? */ traverse2((struct chain *)upsp->eventv, (void *)trig, tp); /* XXX: the trigger could be processed after all the */ /* XXX: actions currently executing... */ } } return; } syslog(LOG_ERR, "signal_handler: %s", sys_siglist[sig]); closeport(); (void)rmpid(_PATH_UPSD_PID); exit(1); } /* * Prints usage message and leaves the program with exit code * equal to 1. */ void usage(void) { fprintf(stderr, "usage: upsd\n"); exit(1); }