# include # include # include # include # include # include # include # include # include # include /* generic definitions */ # define EOS ((char ) 0) # define NIL ((char *) 0) # define auto # define setbits(b,x) (x |= (b)) # define clrbits(b,x) (x &= ~(b)) /* program-specific definitions */ # define SHUTDOWNHOST "alexander" # define MAX_RETRY 6 # define CFFILE "/etc/upscheck.conf" # define BUFFSZ 128 # define OK 0 # define NOTOK 1 /* statuses returned by gupsstat() (see below) */ # define STA_NRML 0 /* normal state */ # define STA_INVR 1 /* "inverter on" state */ # define STA_SHDN 2 /* "shutting down" state */ # define STA_BITS 0x03 # define TIM_BITS (~0x03) # define getstat(s) ((s)&STA_BITS) # define gettime(s) (((s)&TIM_BITS)>>2) # define putstat(s,n) ((s)&=~STA_BITS);((s)|=((n)&STA_BITS)) # define puttime(s,t) ((s)&=~TIM_BITS);((s)|=((t)<<2)) /* Static data */ /* generic parameters */ static char * usernm = "root"; # ifndef TESTING static char * command = "/etc/shut_all.sh < /dev/null >& /dev/null & "; # endif # ifdef TESTING static char * command = "/tmp/shut_all.sh < /dev/null >& /dev/null & "; # endif static char * myname; /* my name, through argv[0] */ static char * cffile; /* the name of the CF file */ /* configuration parameters */ static int upsnum; /* number of UPS's */ static char ** upsnam; /* array of device names */ static int plint1; /* poll interval in normal state*/ static int plint2; /* poll interval in powerfail st*/ static int wttime; /* time from normal to powerfail*/ static int rntime; /* minimum remaining time */ static int * upsdsc; /* ups file descriptor array */ static int * upstat; /* ups status array */ int oldtemp[2]={-1,-1}; int newtemp; /* Function definitions (note: all functions are integer, and (with the ** exception of main()) return zero on success and non-zero on failure). */ int readcf (); /* reads the CF file, assigns values to statics */ int hextobin (); /* converts a hex digit into a number */ int readint (); /* reads an integer from a text buffer */ int ttsetup (); /* sets up a tty file for 1200-baud async IO */ int probeups (); /* probes the UPS until it responds with a promt*/ int gupsstat (); /* gets the current UPS status into a buffer */ int shut (); /* starts a shutdown procedure for hosts & UPSs */ main (argc, argv) int argc; char **argv; { register int i; /* general purpose */ register char * p; /* general purpose */ auto char buffer [BUFFSZ]; /* buffer for input */ auto int status; /* overall UPS status */ auto int mintim; /* minimum remaining tim*/ auto time_t invon; /* time inverter trnd on*/ auto int svdtim; /* saved rntime */ auto int retry; /* retry counter */ /* initialization: assign statics the correct values, then proceed with ** reading the configuration file. The function readcf() should assign ** all the correct values to the static data above. */ if (p = strrchr (argv [0], '/')) { myname = p + 1; } else { myname = argv [0]; } cffile = CFFILE; invon = 0; upsnum = 0; upsnam = (char **) 0; plint1 = 0; plint2 = 0; wttime = 0; rntime = 0; if (readcf ()) { fprintf (stderr, "%s(main): error in configuration file \"%s\". Exiting.\n", myname, cffile); exit (1); } /* setup the tty device(s) */ if (ttsetup ()) { fprintf (stderr, "%s(main): error during setup of tty device.\n"); exit (1); } /* setup some signals */ # ifndef TESTING signal (SIGINT, SIG_IGN); /* refuse to get killed by INT */ # endif signal (SIGSTOP, SIG_IGN); /* refuse to be stopped */ signal (SIGTSTP, SIG_IGN); /* refuse to be stopped by TSTP */ /* in the future, also: signal (SIGHUP, sighup);, to re-read CFFILE */ /* probe UPS(s) to see if they respond */ if (probeups ()) { fprintf (stderr, "%s(main): error while probing UPS(s).\n"); exit (1); } /* from now on, we are running as a daemon; use the syslogd(1m) interface */ openlog (myname, LOG_CONS, LOG_DAEMON); startover: /* main loop */ while (1) { /* for each UPS in turn, get its status, check if inverter is on, */ for (i = 0; i < upsnum; i++) { if (gupsstat (i, &upstat[i])) { syslog (LOG_ALERT, "error while getting status of UPS %s; retrying.", upsnam [i]); retry=1; do { if (gupsstat (i, &upstat[i])) { syslog (LOG_ALERT,"error while getting status of UPS %s; retry=%d", upsnam [i],retry); } else retry=MAX_RETRY+1; } while (retry++ < MAX_RETRY); if (retry == MAX_RETRY) { syslog (LOG_ALERT,"max retry limit reach. exiting."); exit (1); } } } /* for */ /* loop, and get the worse of all responses: the UPS with the highest ** status and with the minimum remaining time */ status = getstat (upstat [0]); mintim = gettime (upstat [0]); for (i = 1; i < upsnum; i++) { if (getstat (upstat [i]) > status) { status = getstat (upstat [i]); } else if (getstat (upstat [i]) == status) { mintim = (gettime (upstat [i]) < mintim)? gettime (upstat [i]) : mintim; } } /* depending on the worse status, take actions */ switch (getstat (status)) { case STA_NRML: /* everything is OK: reset invon and go on looping ** happily */ # ifdef TESTING printf ("looping happily (rntime=%d mins)\n", mintim/60); # endif invon = 0; sleep (plint1); continue; case STA_INVR: /* at least one UPS whose inverter is ON: check how ** long this has been happening (compared to wttime) */ # ifdef TESTING printf ("inverter on (rntime=%d mins)!\n", mintim/60); # endif if (!invon) { invon = time ((time_t *) 0); } else if (time ((time_t *) 0) - invon < wttime) { sleep (plint2); continue; } else /* slip through */; case STA_SHDN: /* at least one UPS whose inverter has been ON long ** enough to make sure this is a power failure, or ** one UPS with little remaining runtime: repeat ** polling the UPSs in tight loop, until either ** all inverters are off, or the remaining runtime ** gets smaller than the one configured. In this ** last case, perform the shutdown procedure. */ # ifdef TESTING printf ("inverter on, in shutdown state (rntime=%d mins)!\n", mintim/60); # endif syslog (LOG_ALERT, "inverter(s) permanently turned ON"); syslog (LOG_ALERT, "monitoring UPS(s) in tight loop..."); /* save the program's (not the UPS's) remaining run time */ svdtim = mintim - rntime; /* inner tight loop */ while (1) { for (i = 0; i < upsnum; i++) { if (gupsstat (i, &upstat[i])) { syslog (LOG_ALERT, "error getting status of UPS %s; retrying.", upsnam [i]); retry=1; do { if (gupsstat (i, &upstat[i])) { syslog (LOG_ALERT, "error while getting status of UPS %s; retry=%d", upsnam [i],retry); } else retry=MAX_RETRY+1; } while (retry++ < MAX_RETRY/2 ); if (retry == MAX_RETRY/2 ) { syslog (LOG_ALERT,"max retry limit reach. shutdown."); shut (); } } } /* for */ status = getstat (upstat [0]); mintim = gettime (upstat [0]); for (i = 1; i < upsnum; i++) { if (getstat (upstat [i]) > status) { status = getstat (upstat [i]); } else if (getstat (upstat [i]) == status) { mintim = (gettime (upstat [i]) < mintim)? gettime (upstat [i]) : mintim; } } if (status == STA_NRML) { /* we returned to normal status (pfeeww! unbelievable!) */ goto startover; } else if (mintim > rntime - 60) { # ifdef TESTING printf ("inverter on, in tight loop state (rntime=%d mins)!\n", mintim/60); # endif /* each minute, issue a new syslog entry (to make things ** look dramatic enough) */ if (svdtim >= mintim - rntime - 60) { svdtim = mintim - rntime; syslog (LOG_ALERT, "%d minutes remaining until shutdown.", svdtim / 60); } /* we do still have some time left, expect the better */ continue; } else { syslog (LOG_ALERT, "starting shutdown procedure NOW!"); syslog (LOG_EMERG, "starting shutdown procedure NOW!"); shut (); } } break; default: syslog (LOG_ALERT, "implementation error 2; exiting..."); exit (1); } /* switch */ } /* main loop */ } /* keyword names used by readcf() below */ static char * keynam [] = { "UPSNUM", "UPSNAM", "PLINT1", "PLINT2", "WTTIME", "RNTIME", NIL }; # define UPSNUM 0 # define UPSNAM 1 # define PLINT1 2 # define PLINT2 3 # define WTTIME 4 # define RNTIME 5 int readcf () { register int i; /* general purpose */ auto FILE * cf; /* stream for CF file */ auto char buffer [BUFFSZ]; /* buffer for input */ auto int line; /* number of lines read */ auto int nxtnam; /* the next name to be assgnd */ if (!(cf = fopen (cffile, "r"))) { sprintf (buffer, "%s(readcf): cannot open \"%s\"", myname, cffile); perror (buffer); return (NOTOK); } line = 0; while (1) { /* read one line from the configuration file */ if (!fgets (&buffer [0], BUFFSZ, cf)) { if (feof (cf)) { fclose (cf); break; } sprintf (buffer, "%s(readcf): fgets failed", myname); perror (buffer); return (NOTOK); } line++; /* skip over comment lines */ if (buffer [0] == '#') { continue; } /* strip the trailing newline */ buffer [strlen (buffer) - 1] = EOS; /* verify syntax correctness; all keywords are six-character long, ** and should be followed immediately by a '='. */ if (buffer [6] != '=') { fprintf (stderr, "%s(readcf): \"%s\", line %d: invalid syntax.\n", myname, cffile, line); return (NOTOK); } /* identify the current keyword */ for (i = 0; keynam [i]; i++) { if (!strncmp (keynam [i], &buffer [0], 6)) { break; } } if (!keynam [i]) { buffer [6] = EOS; fprintf (stderr, "%s(readcf): \"%s\", line %d: unknown keyword \"%s\".\n", myname, cffile, line, buffer); return (NOTOK); } /* sanity check: if UPSNUM has not been defined yet, do not allow any ** other keyword. */ if (!upsnum && i != UPSNUM) { fprintf (stderr, "%s(readcf): \"%s\", line %d: UPSNUM is not defined yet.\n", myname, cffile, line); return (NOTOK); } /* read the rest of the line into the respective variable */ switch (i) { case UPSNUM: /* check if UPSNUM has been redefined (just in case...) */ if (upsnum) { fprintf (stderr, "%s(readcf): \"%s\", line %d: UPSNUM redefined.\n", myname, cffile, line); return (NOTOK); } /* the number of UPS's should be an integer between 1 and 5. As ** soon as this is read in, the array of device names is malloc'ed, ** and the variable of the next name to be read in is set to 0. */ if (readint (&upsnum, &buffer [7], 1, 5)) { fprintf (stderr, "%s(readcf): \"%s\", line %d: illegal value \"%s\".\n", myname, cffile, line, &buffer [7]); return (NOTOK); } if (!(upsnam = (char **) malloc (upsnum * sizeof (char **)))) { sprintf (buffer, "%s(readcf): malloc failed", myname); perror (buffer); return (NOTOK); } nxtnam = 0; break; case UPSNAM: /* check how many names we already have */ if (nxtnam >= upsnum) { fprintf (stderr, "%s(readcf): \"%s\", line %d: too many UPSNAM definitions.\n", myname, cffile, line); return (NOTOK); } /* copy the specified device name into the next slot in name array */ if (!(upsnam [nxtnam++] = (char *) strdup (&buffer [7]))) { sprintf (buffer, "%s(readcf): malloc failed", myname); perror (buffer); return (NOTOK); } break; case PLINT1: if (plint1) { fprintf (stderr, "%s(readcf): \"%s\", line %d: PLINT1 redefined.\n", myname, cffile, line); return (NOTOK); } if (readint (&plint1, &buffer [7], 10, 300)) { fprintf (stderr, "%s(readcf): \"%s\", line %d: illegal value \"%s\".\n", myname, cffile, line, &buffer [7]); return (NOTOK); } break; case PLINT2: if (plint2) { fprintf (stderr, "%s(readcf): \"%s\", line %d: PLINT2 redefined.\n", myname, cffile, line); return (NOTOK); } if (readint (&plint2, &buffer [7], 5, 120)) { fprintf (stderr, "%s(readcf): \"%s\", line %d: illegal value \"%s\".\n", myname, cffile, line, &buffer [7]); return (NOTOK); } break; case WTTIME: if (wttime) { fprintf (stderr, "%s(readcf): \"%s\", line %d: WTTIME redefined.\n", myname, cffile, line); return (NOTOK); } if (readint (&wttime, &buffer [7], 5, 120)) { fprintf (stderr, "%s(readcf): \"%s\", line %d: illegal value \"%s\".\n", myname, cffile, line, &buffer [7]); return (NOTOK); } break; case RNTIME: if (rntime) { fprintf (stderr, "%s(readcf): \"%s\", line %d: RNTIME redefined.\n", myname, cffile, line); return (NOTOK); } if (readint (&rntime, &buffer [7], 600, 3600)) { fprintf (stderr, "%s(readcf): \"%s\", line %d: illegal value \"%s\".\n", myname, cffile, line, &buffer [7]); return (NOTOK); } break; default: fprintf (stderr, "%s(readcf): Implementation error 1\n", myname); exit (1); } } if (!upsnum) { fprintf (stderr, "%s(readcf): \"%s\", EOF: UPSNUM not defined.\n", myname, cffile); return (NOTOK); } if (nxtnam != upsnum) { fprintf (stderr, "%s(readcf): \"%s\", EOF: not enough UPSNAM lines.\n", myname, cffile); return (NOTOK); } if (!plint1) { fprintf (stderr, "%s(readcf): \"%s\", EOF: PLINT1 not defined.\n", myname, cffile); return (NOTOK); } if (!plint2) { fprintf (stderr, "%s(readcf): \"%s\", EOF: PLINT2 not defined.\n", myname, cffile); return (NOTOK); } if (!wttime) { fprintf (stderr, "%s(readcf): \"%s\", EOF: WTTIME not defined.\n", myname, cffile); return (NOTOK); } if (!rntime) { fprintf (stderr, "%s(readcf): \"%s\", EOF: RNTIME not defined.\n", myname, cffile); return (NOTOK); } /* allocate memory for the file descriptors */ if (!(upsdsc = (int *) malloc (upsnum * sizeof (int)))) { sprintf (buffer, "%s(readcf): malloc failed", myname); perror (buffer); return (NOTOK); } /* allocate memory for the UPS status array */ if (!(upstat = (int *) malloc (upsnum * sizeof (int)))) { sprintf (buffer, "%s(readcf): malloc failed", myname); perror (buffer); return (NOTOK); } # ifdef DEBUGCF printf ("Read from \"%s\":\n", cffile); printf ("\tUPSNUM=%d\n", upsnum); for (i = 0; i < upsnum; i++) { printf ("\tUPSNAM[%d]=%s\n", i, upsnam [i]); } printf ("\tPLINT1=%d\n", plint1); printf ("\tPLINT2=%d\n", plint2); printf ("\tWTTIME=%d\n", wttime); printf ("\tRNTIME=%d\n", rntime); # endif return (OK); } int hextobin (c) char c; { return ((int) (isdigit (c)? c - '0': toupper (c) - 'A' + 10)); } int readint (lhs, txt, minmum, maxmum) int * lhs; char *txt; int minmum; int maxmum; { register char * p; auto int ret; if (!isdigit (*txt)) { return (NOTOK); } for (ret = 0, p = txt; isdigit (*p); p++) { ret *= 10; ret += (int) (*p - '0'); } if (ret < minmum) { fprintf (stderr, "%s(readint): value %d less than min (%d assumed).\n", myname, ret, minmum); ret = minmum; } if (ret > maxmum) { fprintf (stderr, "%s(readint): value %d more than max (%d assumed).\n", myname, ret, maxmum); ret = maxmum; } *lhs = ret; return (OK); } int ttsetup () { register int i; /* general purpose */ auto char buffer [BUFFSZ]; /* buffer for input */ auto struct termios ttattr; /* termio to set tty ln */ /* open the ups file descriptors, adjust terminal line settings */ for (i = 0; i < upsnum; i++) { if ((upsdsc [i] = open (upsnam [i], O_RDWR)) < 0) { sprintf (buffer, "%s(ttsetup): cannot open %s", myname, upsnam [i]); perror (buffer); return (NOTOK); } # ifdef DEBUGTTY printf(" UPS file handler %d \n",upsdsc[i]); # endif if (tcgetattr (upsdsc [i], &ttattr) < 0) { sprintf (buffer, "%s(ttsetup): cannot get tty attrs for %s", myname, upsnam [i]); perror (buffer); return (NOTOK); } /* set tty to 'raw' mode: fix input modes, */ setbits ((IGNBRK|IGNPAR|IXON|IXOFF), ttattr.c_iflag); clrbits ((BRKINT|_IXANY|PARMRK|INPCK|INLCR|ICRNL|IUCLC), ttattr.c_iflag); /* fix output modes (no bits need to be set), */ clrbits ((OPOST|_OLCUC|_ONLCR|_OCRNL|_ONLRET|_OFILL|_OFDEL), ttattr.c_oflag); /* fix control modes, */ setbits ((HUPCL|CREAD|CS8), ttattr.c_cflag); clrbits ((CLOCAL|CSTOPB|PARENB|PARODD|LOBLK), ttattr.c_cflag); /* fix local modes, */ setbits ((IEXTEN), ttattr.c_lflag); clrbits ((ISIG|ICANON|_XCASE|ECHO|ECHOE|ECHOK|ECHONL|NOFLSH|TOSTOP), ttattr.c_lflag); /* fix MIN and TIME values, */ ttattr.c_cc [VMIN] = 1; ttattr.c_cc [VTIME] = 0; /* and fix input and output speed */ if (cfsetispeed (&ttattr, B1200) < 0 || cfsetospeed (&ttattr, B1200) < 0) { sprintf (buffer, "%s(ttsetup): cannot set tty ospeed to 1200 baud", myname); perror (buffer); return (NOTOK); } /* apply changes to tty */ if (tcsetattr (upsdsc [i], TCSANOW, &ttattr) < 0) { sprintf (buffer, "%s(ttsetup): cannot set tty attrs for %s", myname, upsnam [i]); perror (buffer); return (NOTOK); } # ifdef DEBUGTTY printf ("Terminal settings for %s (as returned by \"stty -a\"):\n", upsnam [i]); sprintf (buffer, "/bin/stty -a < %s", upsnam [i]); system (buffer); # endif } return (OK); } int probeups () { register int i, j; /* general-purpose */ auto char buffer [BUFFSZ]; /* buffer for input */ auto int count; /* ret. by select/read */ auto int rfds,wfds,efds; /* fdsc ready for I/O */ auto struct timeval tout; /* used for timeout */ /* for each UPS in turn, probe the UPS by sending a CR; the UPS is ** assumed to respond whatever ends in "=>"; if no response appears ** within ten seconds, the UPS is assumed defective or disconnected, ** and the program exits with a message. */ for (i = 0; i < upsnum; i++) { /* send a CR to the UPS */ if (write (upsdsc [i], "\r", 1) < 1) { sprintf (buffer, "%s(probeups): write to %s failed", myname, upsnam [i]); perror (buffer); return (NOTOK); } rfds = (1 << upsdsc [i]); wfds = 0; efds = 0; tout.tv_sec = 10; tout.tv_usec = 0; if ((count = select (upsdsc [i] + 1, &rfds, &wfds, &efds, &tout)) < 0) { sprintf (buffer, "%s(probeups): select to %s failed", myname, upsnam [i]); perror (buffer); return (NOTOK); } # ifdef DEBUGPROMPT printf ("Got count from select = %d\n", count); # endif if (count == 0) { fprintf (stderr, "%s(probeups): UPS at %s not responding.\n", myname, upsnam [i]); return (NOTOK); } /* give the 1200-baud RS232 of the UPS enough time to respond */ sleep (2); /* try now to see a '=>' prompt */ memset (buffer, 0, BUFFSZ); while (1) { if ((count = read (upsdsc [i], &buffer [0], BUFFSZ)) < 0) { sprintf (buffer, "%s(probeups): read from %s failed", myname, upsnam [i]); perror (buffer); return (NOTOK); } # ifdef DEBUGPROMPT printf ("UPS at %s responds:%s", upsnam [i], buffer); # endif for (j = 0; j < count; j++) { if (buffer [j] == '=') { if (j < count - 1) { if (buffer [j + 1] == '>') { # ifdef DEBUGPROMPT printf ("UPS at %s is now prompting for input.\n", upsnam [i]); # endif goto nextups; /* re-loop the "for" loop for the next UPS */ } } } } /* for j */ } /* while */ nextups: ; } /* for (each UPS) */ return (OK); } int gupsstat (i, stat) int i; /* index of the UPS to be queried about its status */ int *stat; /* where status is returned */ { register int j; /* general-purpose */ auto char buffer [BUFFSZ]; /* buffer for input */ auto int count; /* ret. by select/read */ auto int rfds,wfds,efds; /* fdsc ready for I/O */ auto struct timeval tout; /* used for timeout */ auto int rt; /* remaining time by UPS*/ auto char sendflag; /* send 'F' status flag */ /* drain the input stream, using a timeout of 2 seconds (this is ** necessary, because the UPS may issue unsolicited messages in ** an asynchronous manner). */ sendflag=1; while(sendflag) { while (1) { rfds = (1 << upsdsc [i]); wfds = 0; efds = 0; tout.tv_sec = 3; tout.tv_usec = 0; if ((count = select (upsdsc [i] + 1, &rfds, &wfds, &efds, &tout)) < 0) { syslog (LOG_ALERT, "(gupsstat): select to %s failed.", upsnam [i]); return (NOTOK); } /* count is zero if a timeout occured */ if (count == 0) { break; } /* otherwise, read (and ignore) whatever the UPS has to say, then retry */ (void) read (upsdsc [i], &buffer [0], BUFFSZ); } /* clear the buffer */ for(j=0;j<5;j++) buffer[j]=0; /* send an 'F' query to the UPS (followed by a CR) */ if (write (upsdsc [i], "F\r", 2) < 2) { syslog (LOG_ALERT, "(gupsstat): write to %s failed.", upsnam [i]); return (NOTOK); } /* read the command's echo: F\r\r\n = 4 chars */ memset (buffer, 0, BUFFSZ); for (j = 0; j < 4; j += count) { /* prepare a select, to see if UPS responds */ rfds = (1 << upsdsc [i]); wfds = 0; efds = 0; tout.tv_sec = 20; tout.tv_usec = 0; if ((count = select (upsdsc [i] + 1, &rfds, &wfds, &efds, &tout)) < 0) { syslog (LOG_ALERT, "(gupsstat): select to %s failed.", upsnam [i]); return (NOTOK); } if (count == 0) { /* old version syslog (LOG_ALERT, "(gupsstat): UPS at %s not responding.", upsnam [i]); return (NOTOK); */ break; } /* try now to read some character(s); expect 4 chars */ if ((count = read (upsdsc [i], &buffer [j], 4 - j)) <= 0) { syslog (LOG_ALERT, "(gupsstat): read from UPS at %s failed.", upsnam [i]); return (NOTOK); } } buffer[j]=0; if (strcmp(buffer,"F\r\r\n")==0) sendflag=0; # ifdef DEBUGGUPSSTAT else printf ("Got wrong echo from UPS %s:\n%s\n", upsnam [i], buffer); # endif } /* read the F-query output */ memset (buffer, 0, BUFFSZ); for (j = 0, count = 0; j < 84; j += count) { /* note: 'count' is returned from the last ** 'read' system call of the loop */ /* prepare a select, to see if UPS responds */ rfds = (1 << upsdsc [i]); wfds = 0; efds = 0; tout.tv_sec = 10; tout.tv_usec = 0; if ((count = select (upsdsc [i] + 1, &rfds, &wfds, &efds, &tout)) < 0) { syslog (LOG_ALERT, "(gupsstat): select to %s failed.", upsnam [i]); return (NOTOK); } if (count == 0) { syslog (LOG_ALERT, "(gupsstat): UPS at %s not responding.", upsnam [i]); return (NOTOK); } /* try now to read some character(s); expect 80 chars, plus CR/LF, ** plus the next prompt (2 chars), all together = 84 */ if ((count = read (upsdsc [i], &buffer [j], 84 - j)) <= 0) { syslog (LOG_ALERT, "(gupsstat): read from UPS at %s failed.", upsnam [i]); return (NOTOK); } } /* for */ buffer [80] = EOS; # ifdef TESTING printf ("Got buffer from UPS %s:\n%s\n", upsnam [i], buffer); # endif /* OK, we read the whole status string; check what we have to return */ /* note: '8 & hextobin(buffer[20])' is a flag about high temperature, ** which should probably be taken into account in the future */ /* get the remaining time from buffer [58..61] */ buffer [62] = EOS; /* terminate string at pos. 62 */ if (readint (&rt, &buffer [58], 0, 9999)) { syslog (LOG_ALERT, "(gupsstat): cannot convert time from UPS %s", upsnam [i]); return (NOTOK); } puttime (*stat, rt /* convert into seconds */ * 60); /* get alarm indications (explained below) */ if ((1 & hextobin (buffer [20])) /* low AC output */ ||(2 & hextobin (buffer [21])) /* near low battery */ ||(2 & hextobin (buffer [23]))) { /* user test alarm */ putstat (*stat, STA_SHDN); } else if (buffer [17] == '1') { putstat (*stat, STA_INVR); } else { putstat (*stat, STA_NRML); } /* added for temperture checking */ newtemp=(buffer[64]-'0')*10+buffer[65]-'0'; if (newtemp-oldtemp[i]>2 || newtemp-oldtemp[i]<-2) { oldtemp[i]=newtemp; syslog(LOG_WARNING,"Temperture changed at UPS %d. Now temp is %d", i,oldtemp[i]); } return (OK); } shut () { register int i; /* general purpose */ char *ahost[2]; struct servent *se; int s; syslog (LOG_INFO, "Emergency shutdown activated by checkups"); syslog (LOG_ALERT, "Emergency shutdown activated by checkups"); # ifdef TESTING printf ("WOW! I would have started a shutdown here!\n"); # endif # ifndef TESTING for (i = 0; i < upsnum; i++) { if (write (upsdsc [i], "PW377\rOFF 120\r", 14) != 14) { syslog (LOG_ALERT, "cannot shutdown UPS at %s!\n", upsnam [i]); } } #endif ahost[0]=(char *)strdup(SHUTDOWNHOST); ahost[1]=0; se = getservbyname ("shell", "tcp"); if (!se) { perror ("shell/tcp"); exit (1); } s = rcmd(ahost, se->s_port, usernm, usernm, command, 0); if (s < 0) { fprintf (stderr, "%s: Unable to execute the shut down script at alexander ",myname); perror ("rcmd failed"); syslog (LOG_ALERT, "cannot execute shutdown script at alexander"); exit (1); } close(s); exit (0); }