示例#1
0
int
main(int argc, char **argv)
{
    int             ups_fd, stat_fd, ch;
    int             flags;
    int             pstatus, poldstat = 1;
    int             bstatus, boldstat = 1;
    int             count = 0;
    int             bcount = 0;
    int             tries = 0;
    int             ikill = 0;
    int             ioctlbit;
    char           *self = argv[0];
    char            killchar = ' ';
    struct upsdef  *pups;

    while ((ch = getopt(argc, argv, "kc:d:r:s:t:")) != -1)
	switch (ch) {
	  case 'k':
	    ikill = 1;
	    break;
	  case 'c':
	    config_file = optarg;
	    break;
	  case 'd':
	    upsport = optarg;
	    break;
	  case 'r':
	    rcpowerfail = optarg;
	    break;
	  case 's':
	    upsstat = optarg;
	    break;
	  case 't':
	    upstype = optarg;
	    break;
	  case '?':
	  default:
	    usage(self);
	}
    argc -= optind;
    argv += optind;
    if (argc > 0)
	usage(self);

    parse_config(config_file);

    if (upsport == NULL || upstype == NULL || upsstat == NULL) {
	usage(self);
    }
    for (pups = ups; pups; pups = pups->next) {
	if (strcmp(pups->tag, upstype) == 0)
	    break;
    }
    if (!pups) {
	fprintf(stderr, "Error: %s: UPS <%s> unknown\n", self, argv[2]);
	exit(1);
    }
    /* Start syslog. */
    openlog(self, LOG_CONS | LOG_PERROR, LOG_DAEMON);

    if ((ups_fd = open(upsport, O_RDWR | O_NDELAY)) < 0) {
	syslog(LOG_ERR, "%s: %s", upsport, strerror(errno));
	closelog();
	exit(1);
    }
    /* Kill the inverter and close out if inverter kill was selected */
    if (ikill) {
	if (pups->killtime) {

	    /* Explicitly clear both DTR and RTS as soon as possible  */
	    ioctlbit = TIOCM_RTS;
	    ioctl(ups_fd, TIOCMBIC, &ioctlbit);
	    ioctlbit = TIOCM_DTR;
	    ioctl(ups_fd, TIOCMBIC, &ioctlbit);

	    /* clear killpower, apply cablepower to enable monitoring */
	    setlevel(ups_fd, pups->kill.line, !pups->kill.inverted);
	    setlevel(ups_fd, pups->cablepower.line, !pups->cablepower.inverted);

	    if (pups->kill.line == TIOCM_ST) {
		/* Send BREAK (TX high) to kill the UPS inverter. */
		tcsendbreak(ups_fd, 1000 * pups->killtime);
	    } else {
		/* Force high to send the UPS the inverter kill signal. */
		setlevel(ups_fd, pups->kill.line, pups->kill.inverted);
		sleep(pups->killtime);
	    }
	    ioctl(ups_fd, TIOCMGET, &flags);

	    /*
	     * Feb/05/2001 Added support for Tripplite Omnismart 450PNP, this
	     * UPS shutdowns inverter when data is sent over the Tx line
	     * (jhcaiced)
	     */
	    if (pups->flags & UPS_TXD_KILL_INVERTER) {
		sleep(2);
		write(ups_fd, &killchar, 1);
	    }
	    close(ups_fd);

	    /************************************************************/
	    /* We never should have gotten here.                        */
	    /* The inverter kill has failed for one reason or another.  */
	    /* If still in powerfail mode, exit with an error.          */
	    /* If power is ok (power has returned) let rc.0 finish the  */
	    /* reboot.                                                  */
	    /************************************************************/
	    if (getlevel(&pups->powerok, flags) == 0) {
		fprintf(stderr, "%s: UPS inverter kill failed.\n", self);
		exit(1);
	    }			/* if (getlevel(&pups->powerok,flags) == 0) */
	    /* Otherwise, exit normaly, power has returned. */
	    exit(0);
	} else {
	    fprintf(stderr, "Error: %s: UPS <%s> has no support for killing the inverter.\n",
		    self, pups->tag);
	    exit(1);
	}			/* if (pups->kill) */
    }				/* if (ikill) */
    /****************************************/
    /* If no kill signal, monitor the line. */
    /****************************************/
    /* Explicitly clear both DTR and RTS as soon as possible  */
    ioctl(ups_fd, TIOCMBIC, TIOCM_RTS);
    ioctl(ups_fd, TIOCMBIC, TIOCM_DTR);

    /* clear killpower, apply cablepower to enable monitoring */
    setlevel(ups_fd, pups->kill.line, !pups->kill.inverted);
    setlevel(ups_fd, pups->cablepower.line, !pups->cablepower.inverted);

    /* Daemonize. */
#ifdef DEBUG
    closelog();
    setsid();
#else
    switch (fork()) {
      case 0:			/* Child */
	closelog();
	setsid();
	break;
      case -1:			/* Error */
	syslog(LOG_ERR, "can't fork.");
	closelog();
	exit(1);
      default:			/* Parent */
	closelog();
	exit(0);
    }
#endif				/* switch(fork()) */

    /* Restart syslog. */
    openlog(self, LOG_CONS, LOG_DAEMON);

    /* Create an info file for powerfail scripts. */
    unlink(upsstat);
    if ((stat_fd = open(upsstat, O_CREAT | O_WRONLY, 0644)) >= 0) {
	write(stat_fd, "OK\n", 3);
	close(stat_fd);
    }
    /* Give the UPS a chance to reach a stable state. */
    sleep(2);

    /* Now sample the line. */
    while (1) {
	/* Get the status. */
	ioctl(ups_fd, TIOCMGET, &flags);

	/* Calculate present status. */
	pstatus = getlevel(&pups->powerok, flags);
	bstatus = getlevel(&pups->battok, flags);

	if (pups->cableok.line) {
	    /* Check the connection. */
	    tries = 0;
	    while (getlevel(&pups->cableok, flags) == 0) {
		/* Keep on trying, and warn every two minutes. */
		if ((tries % 60) == 0)
		    syslog(LOG_ALERT, "UPS connection error");
		sleep(2);
		tries++;
		ioctl(ups_fd, TIOCMGET, &flags);
	    }			/* while(getlevel(&pups->cableok,flags) */
	    if (tries > 0)
		syslog(LOG_ALERT, "UPS connection OK");
	} else {
	    /*
	     * Do pseudo-cable check, bad power on startup == possible bad
	     * cable
	     */
	    if (tries < 1) {
		tries++;

		/* Do startup failure check */
		if (!pstatus) {
		    /*
		     * Power is out: assume bad cable, but semi-scram to be
		     * safe
		     */
		    syslog(LOG_ALERT, "No power on startup; UPS connection error?");

		    /*
		     * Set status registers to prevent further processing
		     * until
		     */
		    /* the status of the cable is changed.                      */
		    poldstat = pstatus;
		    boldstat = bstatus;

		    powerfail(PFM_CABLE);
		}		/* if (!pstatus) */
	    }			/* if (tries < 1) */
	}			/* if (pups->cableok.line) */

	/* If anything has changed, process the change */
	if (pstatus != poldstat || bstatus != boldstat) {
	    count++;
	    if (count < 4) {
		/* Wait a little to ride out short brown-outs */
		sleep(1);
		continue;
	    }			/* if (count < 4) */
	    if (pstatus != poldstat) {
		if (pstatus) {
		    /* Power is OK */
		    syslog(LOG_ALERT, "Line power restored");
		    powerfail(PFM_OK);
		} else {
		    /* Power has FAILED */
		    if (bstatus) {
			/* Battery OK, normal shutdown */
			syslog(LOG_ALERT, "Line power has failed");
			powerfail(PFM_FAIL);
		    } else {
			/* Low Battery, SCRAM! */
			syslog(LOG_ALERT, "UPS battery power is low!");
			powerfail(PFM_SCRAM);
		    }		/* if (bstatus) */
		}		/* if (pstatus) */
	    }			/* if (pstatus != poldstat) */
	    if (bstatus != boldstat) {
		if (!bstatus && !pstatus) {
		    /* Power is out and Battery is now low, SCRAM! */
		    syslog(LOG_ALERT, "UPS battery power is low!");
		    powerfail(PFM_SCRAM);
		} else {
		    /* Battery status has changed */
		    if (bstatus) {
			/* Battery power is back */
			syslog(LOG_ALERT, "UPS battery power is now OK");
		    }		/* if (!bstatus) */
		}		/* if (!bstatus && !pstatus) */
	    }			/* if (bstatus != boldstat) */
	}			/* if (pstatus != poldstat || bstatus !=
				 * boldstat) */

	if (!bstatus && pstatus) {
	    /* Line power is OK and UPS signals battery is low */
	    /* Log a message to the syslog every 10 minutes */
	    if ((bcount % 300) == 0)
		syslog(LOG_ALERT, "UPS battery power is low!");
	    bcount++;
	} else {
	    /* Reset count */
	    bcount = 0;
	}			/* if (!bstatus && pstatus) */

	/* Reset count, remember status and sleep 2 seconds. */
	count = 0;
	poldstat = pstatus;
	boldstat = bstatus;
	sleep(2);
    }				/* while(1) */
    /* Never happens */
    return (0);
}
示例#2
0
/* Main program */
int main(int argc, char *argv[])
{
    int fd;
    int pkill = 0;
    int flags;
    int cntwait = 0;
    int cntstat = 0;
    int pstatus, poldstat = 1;  /* assume power is good to start */
    int bstatus, boldstat = 1;  /* assume battery is good to start */
    int wait = DEFAULT_WAIT;
    char *program = "tinyupsd";
    char *device = DEFAULT_DEVICE;
    char *cwait;
    FILE *fp;

    /* program = argv[0]; */

    /* Get any optional command line args */
    while(argc > 1) {
	if(!strcmp(argv[1], "-d")) { 
	    device = argv[2]; 
	}
	if(!strcmp(argv[1], "-w")) { 
	    cwait = argv[2]; 
	    wait = atoi(cwait);
	}
	if(!strcmp(argv[1], "-v")) { 
	    printf(version);
	    exit(0);
	}
	if(!strcmp(argv[1], "-h")) {
	    printf(usage);
	    exit(0);
	}
	if(!strcmp(argv[1], "-k")) {
	    pkill = 1;
	    argc -= 1; 
	    argv += 1;
	} else {
	    argc -= 2; 
	    argv += 2;
	}
    }

    /* Start syslog */
    openlog(program, LOG_CONS|LOG_PERROR, LOG_DAEMON);

    /* Open monitor device */
    if((fd = open(device, O_RDWR | O_NDELAY)) < 0) {
	syslog(LOG_ERR, "%s: %s", device, sys_errlist[errno]);
	closelog();
	exit(1);
    }

    /* We were asked to kill ups power */
    if(pkill) {
	/* We won't log to syslog, only to stderr */
	closelog();

	/* Kill power and exit (if the ups doesn't turn off */
        powerkill(fd);
	close(fd);
	exit(0);
    }

    /* See if we are already running */
    if(fp = fopen(PIDFILE, "r")) {
	syslog(LOG_ALERT, "fopen: %s: File already exists\n", PIDFILE);
	close(fd);
	closelog();
	exit(1);
    }

    /* Daemonize */
    switch(fork()) {
	case 0: /* Child */
	    closelog();
	    setsid();
	    break;
	case -1: /* Error */
	    syslog(LOG_ERR, "can't fork.");
	    closelog();
	    exit(1);
	default: /* Parent */
	    closelog();
	    exit(0);
    }

    /* Do some signal handling */
    signal(SIGQUIT, dodie);
    signal(SIGTERM, dodie);
    signal(SIGQUIT, dodie);

    /* Write our pid to file */
    unlink(PIDFILE);
    if((fp = fopen(PIDFILE, "w")) != 0) {
	fprintf(fp, "%d\n", getpid());
	fclose(fp);
    }
    
    /* Restart syslog */
    openlog(program, LOG_CONS, LOG_DAEMON);
    syslog(LOG_NOTICE, "started dev=%s wait=%i", device, wait);

    /* Adjust our timeout for the 2 second increment countdown */
    wait = wait / 2;
    
    /* Clear DTR and RTS */
    ioctl(fd, TIOCMBIC, TIOCM_RTS);
    ioctl(fd, TIOCMBIC, TIOCM_DTR);
    
    /* Apply power to our cable by setting DTR */
    ioctl(fd, TIOCMBIS, LINE_POWER);

    /* Begin our loop where we sample the line */
    while(1) {
        /* Get the status */
        ioctl(fd, TIOCMGET, &flags);

        /* Get ups condition */
        pstatus = !(flags & LINE_FAIL);   /* line high = power fail */
        bstatus = flags & LINE_SCRAM;     /* line low  = battery low */  

        /* Process the change if anything has changed */
        if(pstatus != poldstat || bstatus != boldstat) {
            /* Wait a little to ignore brownouts and false signals */
            cntstat++;
            if(cntstat < 4) {
                sleep(1);
                continue;
            }
	    
            #ifdef SYSV
	    /* See if we have a power condition */
	    if(pstatus != poldstat) {
		if(pstatus) {
		    /* Power has been restored */
		    syslog(LOG_ALERT, "power ok");
		    powerfail(0);
		} else {
		    /* Power has failed */
		    if(bstatus) {
			/* Battery is good */
			syslog(LOG_ALERT, "power has failed");
			powerfail(1);
		    } else {
			/* Battery is low */
			syslog(LOG_ALERT, 
			       "power has failed and battery is low");
			powerfail(2);
		    }
		}
	    }
	    #endif     
	}

        #ifndef SYSV
        if(!pstatus && !bstatus) {
            /* Low battery, shutting down now */
	    systemkill(fd);
		
        } else if(!pstatus) {
            /* No line power, count down now */
            if((cntwait == 0) || ((cntwait) % 30 == 0)) {
                /* Inform immediately and every minute */
                syslog(LOG_EMERG, 
		       "power failed, %d seconds to shutdown", 
		       ((wait-cntwait)*2));
            }
            if(cntwait > wait) {
                /* Timeout reached, shutting down */
                systemkill(fd);
            }
            cntwait++;
	
        } else {
            /* Power is ok, let everyone know, reset counter */
	    if(cntwait != 0) {
		syslog(LOG_EMERG, "power restored");
                cntwait = 0;
	    }
        }
	#endif     
	
	/* Reset count, remember status and sleep for 2 seconds */
	cntstat = 0;
	poldstat = pstatus;
	boldstat = bstatus;
        sleep(2);
    }

    
}