Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 5 Feb 1997 19:21:54 +0000
From:      "Slavik Terletsky" <ts@polynet.lviv.ua>
To:        stevel@logues.rhn.orst.edu
Cc:        FreeBSD-hackers@FreeBSD.org
Subject:   Re: UPS daemon
Message-ID:  <199702051719.TAA18357@NetSurfer.lp.lviv.ua>

next in thread | raw e-mail | index | archive | help
Hello
I managed to hack upsd. As most of ppl who has APC Smart UPS I use
it in a dumb mode (I had no info on the cabling UPS to my box).
You may change it the way you want to get your UPS work,
it is written in C.
Wanna deep your knowledge in ups daemons ? Then drop a note to
Harvey J. Stein <hjstein@math.huji.ac.il>, he made a "UPS HOWTO".
(I don't remember the http URL for this).
So, here it is:

UPS daemon for FreeBSD (2.1.5 - tested).
Interacts with APC Smart-UPS 1400 in a dumb mode.

Connection scheme:

UPS (pin, signal name)		PC (pin, signal name)
----------------------		---------------------
1 Shutdown		>----------->	4 Data Terminal Ready
2 Line Failed		>----------->	8 Clear To Send
4 Common		>----------->	5 Ground
5 Battery Low		>--------+-->	1 Data Carrier Detector
8 Battery (+24V)	>--|10K|-+


UPSD DESCRIPTION

usage: upsd <device> [wait [script]]

device	- device name upsd interacts thru (e.g. /dev/cuaa1)
wait	- time (secs) to wait before running script, (default value 0 sec).
script	- system shutdown script (default /etc/rc.shutdown).

Actions:
upsd logs all the changes of UPS status (power {up,down}, battery {low,ok}).
When "power down" and "battery low" upsd activates UPS SHUTDOWN signal, waits
for a <wait> seconds, and then runs system shutdown script - <script>.

Script sample:

#!/bin/sh
# Script is executed when system is going down.

PATH=/sbin:/bin:/usr/sbin:/usr/bin

echo "System is going DOWN right NOW" | wall

reboot


Upsd source:
/* UPS daemon
 * Copyright 1997 Slavik Terletsky. All rights reserved.
 * Author: Slavik Terletsky <ts@polynet.lviv.ua>
 * System: FreeBSD
 */
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <syslog.h>
#include <unistd.h>
#include <varargs.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/uio.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/ttycom.h>

int status;
int wait = 0;
FILE *fd;
char *scr = "/etc/rc.shutdown";
char *idf = "/var/run/upsd.pid";

void upsterm();
void upsdown(int);

int main(int argc, char *argv[]) {
 int pd;
 int zero = 0;
 char d5, d6, d7;
 char low = 0;
 char pow = 1;

 /* check arguments */
 switch(argc) {
 case  4:
 scr = argv[3];
 case  3:
 wait = atoi(argv[2]);
 case  2:
 break;
 default:
 fprintf(stderr, "usage: %s <device> [wait [script]]\n", argv[0]);
 exit(1);
 }

 /* check if script exists */
 if(!(fd = fopen(scr, "r"))) {
 fprintf(stderr, "fopen: %s: %s\n", scr, sys_errlist[errno]);
 exit(1);
 }
 fclose(fd);

 /* check if upsd is already running */
 if(fd = fopen(idf, "r")) {
 fprintf(stderr, "fopen: %s: File already exists\n", idf);
 exit(1);
 }

 /* become a daemon */
 switch(fork()) {
 case -1:	/* error */
 fprintf(stderr, "fork: %s\n", sys_errlist[errno]);
 exit(1);
 case  0:	/* child */
 break;
 default:	/* parent */
 exit(0);
 }

 /* save the pid */
 if(!(fd = fopen(idf, "w"))) {
 fprintf(stderr, "fopen: %s: %s\n", idf, sys_errlist[errno]);
 exit(1);
 }
 fprintf(fd, "%d\n", (int)getpid());
 fclose(fd);

 /* open monitor device */
 if((pd = open(argv[1], O_RDWR | O_NDELAY)) < 0) {
 fprintf(stderr, "open: %s: %s\n", argv[1], sys_errlist[errno]);
 exit(1);
 }

 /* daemon is alive */
 openlog("upsd", LOG_PID, LOG_DAEMON);
 syslog(LOG_INFO, "daemon started");

 /* signal reaction */
 (void)signal(SIGTERM, upsterm);

 /* monitor device */
 while(1) {
 /* clear bits */
 if(ioctl(pd, TIOCMSET, &zero) < 0) {
  fprintf(stderr, "ioctl: %s\n", sys_errlist[errno]);
  exit(1);
 }

 /* get device status */
 if(ioctl(pd, TIOCMGET, &status) < 0) {
  fprintf(stderr, "ioctl: %s\n", sys_errlist[errno]);
  exit(1);
 }

 /* determin status */
 d5 = status & 0x20;
 d6 = status & 0x40;
 d7 = status & 0x80;

 /* power up */
 if(!(d7 + d5)) {
  if(!pow) {
   syslog(LOG_CRIT, "power up");
   pow = 1;
  }
 /* power down */
 } else {
  if(pow) {
   syslog(LOG_CRIT, "power down");
   pow = 0;
  }
 }

 /* battery low */
 if(!d6 && !low) {
  syslog(LOG_ALERT, "battery low");
  low = 1;

  /* down ups */
  if(!pow) {
   upsdown(pd);
  }
 }

 /* battery ok */
 if(d6 && low) {
  syslog(LOG_CRIT, "battery ok");
  low = 0;
 }

 sleep(1);
 }

 /* not reached */
 return 0;

}

void upsterm() {
 /* log termination message */
 syslog(LOG_INFO, "daemon terminated");

 /* remove pid file */
 unlink(idf);

 exit(0);
}

void upsdown(int pd) {
 /* log shutdown message */
 syslog(LOG_ALERT, "system is going down");

 /* remove pid file */
 unlink(idf);

 /* save our filesystem */
 system("/bin/sync");
 system("/bin/sync");
 system("/bin/sync");

 /* shutdown ups */
 status = TIOCM_DTR;
 if(ioctl(pd, TIOCMSET, &status) < 0) {
 fprintf(stderr, "ioctl: %s\n", sys_errlist[errno]);
 exit(1);
 }

 /* wait and then run script */
 sleep(wait);
 system(scr);
}


# Slavik Terletsky      # University "Lvivska Poytechnika" #
# Network Administrator # mailto:ts@polynet.lviv.ua        #



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199702051719.TAA18357>