/*
* $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);
}
syntax highlighted by Code2HTML, v. 0.9.1