/* bkpupsd - Simple UPS daemon for APC Back-UPS pro. series * Copyright (c) 1997, Yoshifumi Watanabe * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * Ver 1.0 A */ #include #include #include #include #include #include #include #include #include #include #include #include #define POWER_TIMEOUT 5*60 #define DEFAULT_PORT "/dev/cuaa1" #define _BKPUPSD_PID_PATH "/var/run/bkpupsd.pid" #define SH_SHUTDOWN "/usr/local/libexec/bkpupsd/bkpups.shutdown" #define SH_FAILED "/usr/local/libexec/bkpupsd/bkpups.failed" #define SH_RESTORED "/usr/local/libexec/bkpupsd/bkpups.restored" #define SH_BATTLOW "/usr/local/libexec/bkpupsd/bkpups.battlow" int makepid(char *s); void execomand(); int main(argc, argv) int argc; char **argv; { int fd; int lstatus; int rts_bit = TIOCM_RTS; int dtr_bit = TIOCM_DTR; int pfail = 0; int pfcount = 0; int prcount = 0; int blcount = 0; char *sh_shutdown = SH_SHUTDOWN; char *sh_failed = SH_FAILED; char *sh_restored = SH_RESTORED; char *sh_battlow = SH_BATTLOW; char *ups_port = DEFAULT_PORT; /* open ups port */ if(argc > 2) { errx(1,"Usage: bkpupsd : %s\n", strerror(errno)); } if(argc == 2) { ups_port = argv[1]; } if((fd = open(ups_port, O_RDWR | O_NDELAY)) < 0) { errx(1,"%s: %s", ups_port, strerror(errno)); } /* Initialize UPS */ ioctl(fd, TIOCMBIC, &rts_bit); ioctl(fd, TIOCMBIS, &dtr_bit); /* Detach and Become to a daemon process */ if(daemon(1,1) < 0) { syslog(LOG_ERR, "Cannot become a daemon: %m"); exit(1); } (void)makepid(_BKPUPSD_PID_PATH); /* Get line-status */ while(1) { ioctl(fd, TIOCMBIC, &rts_bit); ioctl(fd, TIOCMBIC, &dtr_bit); ioctl(fd, TIOCMBIS, &dtr_bit); ioctl(fd, TIOCMGET, &lstatus); if(lstatus & TIOCM_CAR) { ++blcount; if(blcount == 6) { syslog(LOG_ALERT, "Shutdown for Battery-Low."); /* Check line-failure */ ioctl(fd, TIOCMBIC, &dtr_bit); ioctl(fd, TIOCMBIS, &dtr_bit); ioctl(fd, TIOCMGET, &lstatus); if(lstatus & TIOCM_RNG) { /* BK-UPS Pro to Sleep. */ ioctl(fd, TIOCMBIC, &dtr_bit); ioctl(fd, TIOCMBIS, &dtr_bit); ioctl(fd, TIOCMBIS, &rts_bit); /* Emergency Shutdown Sequence */ execomand(sh_battlow); sleep(100); } } } else if(lstatus & TIOCM_RNG) { ++pfcount; prcount = 0; blcount = 0; if(pfcount == 3) { /* Powerfail */ syslog(LOG_WARNING, "Line Power is failing."); execomand(sh_failed); pfail = 1; } if(pfcount == POWER_TIMEOUT) { syslog(LOG_ALERT, "Shutdown for Powerfail."); /* BK-UPS Pro to Sleep */ ioctl(fd, TIOCMBIC, &dtr_bit); ioctl(fd, TIOCMBIS, &dtr_bit); ioctl(fd, TIOCMBIS, &rts_bit); /* Shutdown sequence */ execomand(sh_shutdown); sleep(100); } } else if(pfail == 1) { /* power recovery */ ++prcount; pfcount = 0; if(prcount == 3) { execomand(sh_restored); pfail = 0; blcount = 0; ioctl(fd, TIOCMBIC, &rts_bit); ioctl(fd, TIOCMBIC, &dtr_bit); ioctl(fd, TIOCMBIS, &dtr_bit); } /* Battery recovery */ else blcount = 0; } sleep(1); } } /* Subroutine to execute shell script command */ void execomand(shcommand) char *shcommand; { switch(fork()) { case 0: system(shcommand); exit(0); case -1: errx(1, "unable to execute shell command: %s", strerror(errno)); break; default: break; } } /* Subroutine to make bkpupsd.pid to /var/run/ directory. */ int makepid(s) char *s; { FILE *fp; pid_t pid; pid = getpid(); if((fp = fopen(s, "w")) == NULL) return -1; fprintf(fp, "%lu\n", (u_long)pid); fclose(fp); return 0; }