1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
|
/*
* powerd Monitor the DCD line of a serial port connected to
* an UPS. If the power goes down, notify init.
* If the power comes up again, notify init again.
* As long as the power is OK, the DCD line should be
* "HIGH". When the power fails, DCD should go "LOW".
* Powerd keeps DTR high so that you can connect
* DCD and DTR with a resistor of 10 Kilo Ohm and let the
* UPS or some relais pull the DCD line to ground.
* You also need to connect DTR and DSR together. This
* way, powerd can check now and then if DSR is high
* so it knows the UPS is connected!!
*
* Usage: powerd /dev/cua4 (or any other serial device).
*
* Author: Miquel van Smoorenburg, <miquels@drinkel.cistron.nl>.
*
* Version: 1.31, 29-Feb-1996.
*
* This program was originally written for my employer,
* ** Cistron Electronics **
* who has given kind permission to release this program
* for general puppose.
*
* Copyright 1991-1996 Cistron Electronics.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
/* Use the new way of communicating with init. */
#define NEWINIT
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <signal.h>
#include <syslog.h>
#include <string.h>
#include "paths.h"
#ifdef NEWINIT
#include "initreq.h"
#endif
#ifndef SIGPWR
# define SIGPWR SIGUSR1
#endif
#ifdef NEWINIT
void alrm_handler()
{
}
#endif
/* Tell init the power has either gone or is back. */
void powerfail(ok)
int ok;
{
int fd;
#ifdef NEWINIT
struct init_request req;
/* Fill out the request struct. */
memset(&req, 0, sizeof(req));
req.magic = INIT_MAGIC;
req.cmd = ok ? INIT_CMD_POWEROK : INIT_CMD_POWERFAIL;
/* Open the fifo (with timeout) */
signal(SIGALRM, alrm_handler);
alarm(3);
if ((fd = open(INIT_FIFO, O_WRONLY)) >= 0
&& write(fd, &req, sizeof(req)) == sizeof(req)) {
close(fd);
return;
}
/* Fall through to the old method.. */
#endif
/* Create an info file for init. */
unlink(PWRSTAT);
if ((fd = open(PWRSTAT, O_CREAT|O_WRONLY, 0644)) >= 0) {
if (ok)
write(fd, "OK\n", 3);
else
write(fd, "FAIL\n", 5);
close(fd);
}
kill(1, SIGPWR);
}
/* Main program. */
int main(int argc, char **argv)
{
int fd;
int dtr_bit = TIOCM_DTR;
int flags;
int status, oldstat = -1;
int count = 0;
int tries = 0;
if (argc < 2) {
fprintf(stderr, "Usage: powerd <device>\n");
exit(1);
}
/* Start syslog. */
openlog("powerd", LOG_CONS|LOG_PERROR, LOG_DAEMON);
/* Open monitor device. */
if ((fd = open(argv[1], O_RDWR | O_NDELAY)) < 0) {
syslog(LOG_ERR, "%s: %s", argv[1], sys_errlist[errno]);
closelog();
exit(1);
}
/* Line is opened, so DTR is high. Force it anyway to be sure. */
ioctl(fd, TIOCMBIS, &dtr_bit);
/* 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);
}
/* Restart syslog. */
openlog("powerd", LOG_CONS, LOG_DAEMON);
/* Now sample the DCD line. */
while(1) {
/* Get the status. */
ioctl(fd, TIOCMGET, &flags);
/* Check the connection: DSR should be high. */
tries = 0;
while((flags & TIOCM_DSR) == 0) {
/* Keep on trying, and warn every two minutes. */
if ((tries % 60) == 0)
syslog(LOG_ALERT, "UPS connection error");
sleep(2);
tries++;
ioctl(fd, TIOCMGET, &flags);
}
if (tries > 0)
syslog(LOG_ALERT, "UPS connection OK");
/* Calculate present status. */
status = (flags & TIOCM_CAR);
/* Did DCD drop to zero? Then the power has failed. */
if (oldstat != 0 && status == 0) {
count++;
if (count > 3)
powerfail(0);
else {
sleep(1);
continue;
}
}
/* Did DCD come up again? Then the power is back. */
if (oldstat == 0 && status > 0) {
count++;
if (count > 3)
powerfail(1);
else {
sleep(1);
continue;
}
}
/* Reset count, remember status and sleep 2 seconds. */
count = 0;
oldstat = status;
sleep(2);
}
/* Never happens */
return(0);
}
|