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