]>
Commit | Line | Data |
---|---|---|
a74aeac6 PR |
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 | } |