The Power Micro-Mini-HOWTO By Harvey J. Stein (hjstein@math.huji.ac.il) Version 1.0 (last edited Tue Aug 2 1994) Contents 1. Introduction 2. What you need to do (summary) 3. How it's supposed to work 4. Where to get the appropriate software 5. How to set things up 6. User Enhancements 7. How to make a cable 8. Serial port pin assignments 9. Ioctl bit numbers corresponding to RS232 control lines 10. Info on selected UPSs 10.1. Advice 1200 A 10.2. GPS 11. Reverse-engineering cables & hacking powerd.c 12. How to shutdown other machines on the same UPS 12.1. UPS status port method 12.2. Broadcast method 12.3. Dummy login method 1. Introduction This HOWTO covers connecting a UPS to a PC running Linux in such a way that Linux can shutdown cleanly when the power goes out. To a large extent it is reduntant, because all the basic info is contained in the powerd man page that comes with the SysVinit package. None the less, there seems to periodically be alot of discussion on the net regarding connecting Linux PCs to UPSs, (and the versions of Linux that I installed didn't come with a powerd man page). I figured having a HOWTO would be a good idea because: -A second source of information might help to understand how to connect Linux to a UPS, even if it's just the same information written differently. -The HOWTO can serve as a repository for UPS specific data. -The HOWTO contains additional details that aren't in the powerd man page. None the less, this does not replace the powerd man page. Hopefully, after reading both, people will be able to deal with UPSs. 2. What you need to do (summary) -Plug the PC into the UPS. -Connect the PC's serial port to the UPS with a special cable. -Run powerd on the PC. -Setup your initd to do something reasonable on powerfail & powerok events (like start a shutdown & kill any currently running shutdowns, respectively, for example). 3. How it's supposed to work UPS's job: When the power goes out, the UPS continues to power the PC & signals that the power went out by throwing a relay or turning on an opticoupler on it's control port. Cable's job: The cable is designed so that when the UPS throws said relay, this causes a particular serial port control line (typically DCD) to go high. Powerd's job: Powerd monitors the serial port. Keeps raised/lowered whatever serial port control lines the UPS needs to have raised/lowered (typically, DTR must be kept high & whatever line shuts off the UPS must be kept low). When powerd sees the UPS control line go high, it writes "FAIL" to /etc/powerfail & sends the initd process a SIGPWR signal. When the control line goes low again, it writes "OK" to /etc/powerfail & sends initd a SIGPWR signal. Initd's job (aside from everything else it does): When it receives a SIGPWR, it looks at /etc/powerfail. If it contains "FAIL" it runs the powerfail entry from /etc/inittab. If it contains "OK" it runs the powerokwait entry from inittab. 4. Where to get the appropriate software Pick up /pub/Linux/system/Daemons/SysVinit-2.50.tgz from sunsite.unc.edu or a mirror. It includes a copy of powerd.c, shutdown.c, an initd that understands what to do with SIGPWR, & can handle powerfail & powerokwait entries in the inittab file. 5. How to set things up -Edit /etc/inittab. Put in something like this: # What to do when power fails (Halt system & drain battery :): pf::powerfail:/etc/powerfailscript +5 # If power is back before shutdown, cancel the running shutdown. pg:0123456:powerokwait:/etc/powerokscript -Write scripts /etc/powerfailscript & /etc/powerokscript to shutdown in 5 minutes (or whatever's appropriate) & kill any existing shutdown, respectively. Depending on the version of shutdown that you're using, this will be either so trivial that you'll dispense with the scripts, or be a 1 line bash script, something along the lines of: kill `ps -aux | grep "shutdown" | grep -v grep | awk '{print $2}'` and you'll keep the scripts. -Tell initd to re-process the inittab file with the command: telinit q -Edit rc.local so that powerd gets run upon startup. The syntax is: powerd Replace with the serial port that the modem is connected, such as /dev/cua1. -Connect PC's serial port to UPS's serial port. DO NOT PLUG PC INTO UPS YET. -Plug a light into the UPS. -Turn on the UPS & the light. -Run powerd. -Test the setup: -Yank the UPS's plug. -Check that the light stays on. -Check that /etc/powerfailscript is running. -Check that shutdown is running. -Plug the UPS back in. -Check that the light stays on. -Check that /etc/powerfailscript is no longer running. -Check that shutdown is no longer running. -Yank the UPS's plug again. Leave it out & make sure that the PC shuts down properly in the proper amount of time. -After everything seems to be proper, powerdown the PC & plug it into the UPS. Run a script that sync's the hard disk every second or so. Simultaneously run a second script that keeps doing a find over your entire hard disk. The first is to make this a little safer & the second is to help draw lots of power. Now, pull the plug on the UPS, check again that shutdown is running & wait. Make sure that the PC shuts down cleanly before the battery on the UPS gives out. Congratulations! You now have a Linux PC that's protected by a UPS and will shutdown cleanly when the power goes out! 6. User Enhancements -Hack powerd.c to monitor the line indicating that the batteries are low. When the batteries get low, do an *immediate* shutdown. -Modify shutdown procedure so that if it's shutting down in a powerfail situation, then it turns off the UPS after doing everything necessary. 7. How to make a cable This section is just from messages I've seen on the net. I haven't done it so I can't write from experience. If anyone has, please write this section for me :). See also the message about the GPS1000 contained in section 10.2. >From miquels@caution.cistron.nl.mugnet.org Wed Jul 21 14:26:33 1993 Newsgroups: comp.os.linux Subject: Re: UPS interface for Linux? From: miquels@caution.cistron.nl.mugnet.org (Miquel van Smoorenburg) Date: Sat, 17 Jul 93 18:03:37 Distribution: world Organization: Cistron Electronics. In article <1993Jul15.184450.5193@excaliber.uucp> joel@rac1.wam.umd.edu (Joel M. Hoffman) writes: >I'm in the process of buying a UPS (Uninteruptable Power Supply), and >notice that some of them have interfaces for LAN's to signal the LAN >when the power fails. > >Is there such an interface for Linux? > >Thanks. > >-Joel >(joel@wam.umd.edu) > When I worked on the last versioon of SysVinit (Now version 2.4), I temporarily had a UPS on my computer, so I added support for it. You might have seen that in the latest header files there is a #define SIGPWR 30 now :-). Anyway, I did not have such a special interface but the output of most UPS's is just a relais that makes or breaks on power interrupt. I thought up a simple way to connect this to the DCD line of the serial port. In the SysVinit package there is a daemon called 'powerd' that keeps an eye on that serial line and sends SIGPWR to init when the status changes, so that init can do something (such as bringing the system down within 5 minutes). How to connect the UPS to the serial line is described in the source "powerd.c", but I will draw it here for explanation: +------------------------o DTR | +---+ | | resistor | | 10 kilo-Ohm | | +---+ To serial port. | +-----o-------+------------------------o DCD | | o UPS | \ relais | \ | | | +-----o-------+------------------------o GND Nice drawing eh? Hope this helps. SysVinit can be found on sunsite (and tsx-11 probably) as SysVinit2.4.tar.z Mike. -- Miquel van Smoorenburg, Ibmio.com: cannot open CONFIG.SYS: file handle broke off. >From danny@caution.cistron.nl.mugnet.org Wed Jul 21 14:27:04 1993 Newsgroups: comp.os.linux Subject: Re: UPS interface for Linux? From: danny@caution.cistron.nl.mugnet.org (Danny ter Haar) Date: Mon, 19 Jul 93 11:02:14 Distribution: world Organization: Cistron Electronics. In article <9307174330@caution.cistron.nl.mugnet.org> miquels@caution.cistron.nl.mugnet.org (Miquel van Smoorenburg) writes: >How to connect the UPS to the serial line is described in the source >"powerd.c", but I will draw it here for explanation: The drawing wasn't really clear, please use this one in stead ! > > +------------------------o DTR > | > +---+ > | | resistor > | | 10 kilo-Ohm > | | > +---+ To serial port. > | > +-----o-------+------------------------o DCD > | > o UPS > \ relais > \ > | > +-----o--------------------------------o GND > The DTR is kept high, when the UPS's power input is gone it will close the relais . The computer is monitoring the DCD input port to go LOW . When this happens it will start a shutdown sequence... _____ Danny -- <=====================================================================> Danny ter Haar or Robins law #103: 'a couple of lightyears can't part good friends' 8. Serial port pin assignments (The following is from David Tal's 'Frequently Used Cables and Connectors' document). Pin Assignment for the Serial Port (RS-232C), 25-pin and 9-pin -------------------------------------------------------------- DB-25 DB-9 Pin # Pin # Name EIA CCITT DTE-DCE Description ----- ----- ----- ----- ----- ------- ------------------- 1 FG AA 101 ---- Frame Ground/Chassis GND 2 3 TD BA 103 ---> Transmitted Data, TxD 3 2 RD BB 104 <--- Received Data, RxD 4 7 RTS CA 105 ---> Request To Send 5 8 CTS CB 106 <--- Clear To Send 6 6 DSR CC 107 <--- Data Set Ready 7 5 SG AB 102 ---- Signal Ground, GND 8 1 DCD CF 109 <--- Data Carrier Detect 9 -- -- - - Positive DC test voltage 10 -- -- - - Negative DC test voltage 11 QM -- - <--- Equalizer mode 12 SDCD SCF 122 <--- Secondary Data Carrier Detect 13 SCTS SCB 121 <--- Secondary Clear To Send 14 STD SBA 118 ---> Secondary Transmitted Data 15 TC DB 114 <--- Transmitter (signal) Clock 16 SRD SBB 119 <--- Secondary Receiver Clock 17 RC DD 115 ---> Receiver (signal) Clock 18 DCR -- - <--- Divided Clock Receiver 19 SRTS SCA 120 ---> Secondary Request To Send 20 4 DTR CD 108.2 ---> Data Terminal Ready 21 SQ CG 110 <--- Signal Quality Detect 22 9 RI CE 125 <--- Ring Indicator 23 -- CH 111 ---> Data rate selector 24 -- CI 112 <--- Data rate selector 25 TC DA 113 <--- Transmitted Clock 1 13 1 5 _______________________________ _______________ \ . . . . . . . . . . . . . / \ . . . . . / RS232-connectors \ . . . . . . . . . . . . / \ . . . . / seen from outside --------------------------- ----------- of computer. 14 25 6 9 DTE : Data Terminal Equipment (i.e. computer) DCE : Data Communications Equipment (i.e. modem) RxD : Data received; 1 is transmitted "low", 0 as "high" TxD : Data sent; 1 is transmitted "low", 0 as "high" DTR : DTE announces that it is powered up and ready to communicate DSR : DCE announces that it is ready to communicate; low=modem hangup RTS : DTE asks DCE for permission to send data CTS : DCE agrees on RTS RI : DCE signals the DTE that an establishment of a connection is attempted DCD : DCE announces that a connection is established 9. Ioctl bit numbers corresponding to RS232 control lines (taken from /usr/include/linux/termios.h) /* modem lines */ #define TIOCM_LE 0x001 #define TIOCM_DTR 0x002 #define TIOCM_RTS 0x004 #define TIOCM_ST 0x008 #define TIOCM_SR 0x010 #define TIOCM_CTS 0x020 #define TIOCM_CAR 0x040 #define TIOCM_RNG 0x080 #define TIOCM_DSR 0x100 #define TIOCM_CD TIOCM_CAR #define TIOCM_RI TIOCM_RNG Note that the 3rd column is in Hex. 10. Info on selected UPSs **** Please send them to me for inclusion here. **** 10.1. Advice 1200 A UPS from Advice Electronics, Tel Aviv Israel (they stick their own name on the things). UPS Control Port ---------------- 2 - Power Fail. 5 - Battery Low. 6 - Shut Down UPS. 4 - Common ground for pin 2, 5, 6. They also gave me the following picture which didn't help me, but may help you if you want to build a cable yourself: 2 ----------+ | \ \| |-------------- /| \/ (<--- The "\/" here indicates the type of | this transister. I forget what | denotes what, but this one points +-----+ away from the center line.) / / / 5 ----------+ | \ \| |-------------- /| \/ | | +-----+ / / / +------------- | / 10K |/ 6 --\/\/\/--| |\ \/ | | +-----+ / / / 4 ----------+ | | +-----+ / / / Cable supplied -------------- They first game me a cable that was part of a DOS UPS control package called RUPS. I used this for testing. When I was satisfied, they gave me a cable they use for Netware servers connected to UPSs. It functioned identically. Here are the details: DTR - Powers cable (keep high). CTS - Power out (stays high & goes low when power goes out). DSR - Battery low (stays high & goes low when battery does). RTS - Turns off UPS (keep low & set high to turn off UPS). (The powerd.c that comes with SysVinit set or left RTS high, causing the UPS to shut off immediately when powerd was started up!) 10.2. GPS1000 from ACCODATA >From hennus@sky.nl.mugnet.org Thu Mar 10 15:10:22 1994 Newsgroups: comp.os.linux.help Subject: Re: auto-shutdown with UPS From: hennus@sky.nl.mugnet.org (Hennus Bergman) Date: Tue, 1 Mar 1994 22:17:45 GMT Distribution: world Organization: The Organization For Removal Of On-Screen Logos In article , Colin Owen Rafferty wrote: >I am about to buy an Uninterruptable Power Supply for my machine, and >I would like to get one that has the "auto-shutdown" feature. > I just got one of those real cheap :-) It's a GPS1000 by ACCODATA. Anybody know how good the output signal of these things is? [Don't have a scope myself :-(] >I assume that these each have some kind of serial connection that >tells the system information about it. > I took it apart to find out how it worked. There were three optocouplers (two output, one input) connected to a 9 pin connector at the back. One turns on when the power fails, and goes off again when the power returns. While the power is off, you can use the `input' to shut the battery off. [It releases the power-relay.] The third one is some kind of feedback to tell that it did accepted the `shut-down command'. I think the interface for my UPS was designed to be connected to TTL-level signals, but with some resistors it could be connected to serial port. It's wired in such a way that using a RS-232 port you cannot use both output optocouplers; but the shutdown feedback is not necessary anyway, just use the important one. ;-) [Note that it is possible to blow the transistor part in optocouplers with RS-232 levels if you wire it the wrong way round ;-)] I was hoping I would be able to connect it to my unused game port, but that doesn't have an output, does it? I'll probably end up getting an extra printer port for this. Not all UPS' use optocouplers, some use simple relays, which are less critical to connect, but of course not as `nice'. >Has anyone written a package that watches the UPS and does a shutdown >(or something) when the power is off? SysVinit-2.4 (and probably 2.5 as well) has a `powerd' daemon that continually watches a serial port for presence of the CD (Carrier Detect) line and signals init when it drops. Init then activates shutdown with a time delay. If the power returns within a few minutes the shutdown is cancelled. Very Nice. The only problem I had with it is that it doesn't actually tell the UPS to turn off when the shutdown is complete. It just sits there with a root prompt. I'll probably write a small program to shut it down >from /etc/brc. RSN. > Colin Rafferty, Lehman Brothers Hennus Bergman 11. Reverse-engineering cables & hacking powerd.c Try to get documentation for the cables that your UPS seller supplies. In particular find out: -What lines need to be kept high. -What line(s) turn off the UPS. -What lines the UPS toggles to indicate that: -Power is out. -Battery is low. You then need to hack powerd.c appropriately. If you have trouble getting the above information (or just want to check it) the following program (upscheck.c) might help. It's a hacked version of powerd.c. It allows you to set the necessary port flags from the command line & then monitors the port, displaying the control lines every second. I used it as "upscheck /dev/cua1 2" (for example) to set the 2nd bit (DTR) & to clear the other bits. The number base 2 indicates which bits to set, so for example to set bits 1, 2 & 3, (& clear the others) use 7. See the code for details. Here's the (untested) upscheck.c program. It's untested because I edited the version I originally used to make it clearer, and can't test the new version at the moment. --------- Begin upscheck.c ------------------ /* * upscheck Check how UPS & computer communicate. * * Usage: upscheck * For example, upscheck /dev/cua4 4 to set bit 3 & * monitor /dev/cua4. * * Author: Harvey J. Stein * (but really just a minor modification of Miquel van * Smoorenburg's powerd.c * * Version: 1.0 19940802 * */ #include #include #include #include #include #include #include #include /* Main program. */ int main(int argc, char **argv) { int fd; /* These TIOCM_* parameters are defined in , which */ /* is indirectly included here. */ int dtr_bit = TIOCM_DTR; int rts_bit = TIOCM_RTS; int set_bits; int flags; int status, oldstat = -1; int count = 0; int pc; if (argc < 2) { fprintf(stderr, "Usage: upscheck \n"); exit(1); } /* Open monitor device. */ if ((fd = open(argv[1], O_RDWR | O_NDELAY)) < 0) { fprintf(stderr, "upscheck: %s: %s\n", argv[1], sys_errlist[errno]); exit(1);} /* Line is opened, so DTR is high. Force it anyway to be sure. */ /* ioctl(fd, TIOCMBIS, &dtr_bit); */ /* The above line was from the original powerd.c, but it turned off */ /* my UPS! So, I changed it to the line below which clears the DTR */ /* instead of setting the DTR bit & that worked for me. However, */ /* it might not work for you, so I commented it out too. */ /* ioctl(fd, TIOCMBIC, &dtr_bit); */ /* Get the bits to set from the command line. */ sscanf(argv[2], "%d", &set_bits); while (1) { /* Set the command line specified bits (& only the command line */ /* specified bits). */ ioctl(fd, TIOCMSET, &set_bits); fprintf(stderr, "Setting %o.\n", set_bits); sleep(1); /* Get the current line bits */ ioctl(fd, TIOCMGET, &flags); fprintf(stderr, "Flags are %o.\n", flags); /* Fiddle here by changing TIOCM_CTS to some other TIOCM until */ /* this program detects that the power goes out when you yank */ /* the plug on the UPS. Then you'll know how to modify powerd.c. */ if (flags & TIOCM_CTS) { pc = 0 ; fprintf(stderr, "power is up.\n"); } else { pc = pc + 1 ; fprintf(stderr, "power is down.\n"); } } close(fd); } ----------- End upscheck.c --------------------------- 12. How to shutdown other machines on the same UPS Some people (myself included) have several Linux PCs connected to one UPS. One PC monitors the UPS & needs to get the other PCs to shut down when the power goes out. There are a number of ways to do this, all are do-it-yourself currently, and most are just hypothetical. We assume the PCs can communicate over a network. Call the PC that monitors the UPS the master & the other PCs the slaves. 12.1. UPS status port method Set up a port on the master which, when connected to, either sends "OK", "FAIL", or "BATLOW", the first when the power is ok, the second when the power has failed, and the third when the battery is low. Model this on port 13 (the time port) which one can telnet to & receive the local time. Have the slaves run versions of powerd that look at this port instead of checking a serial line. The only down side I can see to this method is the network load due to checking this port. One would want to check this port often to quickly catch the BATLOW message & shut down before the battery dies. 12.2. Broadcast method Same as 12.1 except send an ethernet broadcast message that the power has just gone down. This might have security implications. 12.3. Dummy login method Set up dummy logins on the slaves with login names "powerok" & "powerfail", both with the same UID. Make /etc/powerokscript the shell of the powerok user, & make /etc/powerfailscript the shell of the powerfail user. On the master, have the /etc/powerokscript rlogin to each slave as user powerok, & have the /etc/powerfailscript rlogin to each slave as user powerfail. Put a .rhosts file on each slave in the home directory of powerok & powerfail to allow root from the master to login as user powerok & powerfail to each slave. This is the system I'm currently using. This might also have security implications. ---------- END UPS micro-mini HOWTO -------------------------