1 /* upsmon - monitor power status over the 'net (talks to upsd via TCP)
2 
3    Copyright (C)
4      1998  Russell Kroll <rkroll@exploits.org>
5      2012  Arnaud Quette <arnaud.quette.free.fr>
6 
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11 
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16 
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20  */
21 
22 #include "common.h"
23 
24 #include <sys/stat.h>
25 #include <sys/wait.h>
26 #include <sys/socket.h>
27 #include <unistd.h>
28 #include <fcntl.h>
29 
30 #include "nut_stdint.h"
31 #include "upsclient.h"
32 #include "upsmon.h"
33 #include "parseconf.h"
34 #include "timehead.h"
35 
36 #ifdef HAVE_STDARG_H
37 #include <stdarg.h>
38 #endif
39 
40 static	char	*shutdowncmd = NULL, *notifycmd = NULL;
41 static	char	*powerdownflag = NULL, *configfile = NULL;
42 
43 static	unsigned int	minsupplies = 1, sleepval = 5;
44 
45 	/* sum of all power values from config file */
46 static	unsigned int	totalpv = 0;
47 
48 	/* default TTL of a device gone AWOL, 3 x polling interval = 15 sec */
49 static	int deadtime = 15;
50 
51 	/* default polling interval = 5 sec */
52 static	unsigned int	pollfreq = 5, pollfreqalert = 5;
53 
54 	/* secondary hosts are given 15 sec by default to logout from upsd */
55 static	int	hostsync = 15;
56 
57 	/* default replace battery warning interval (seconds) */
58 static	int	rbwarntime = 43200;
59 
60 	/* default "all communications down" warning interval (seconds) */
61 static	int	nocommwarntime = 300;
62 
63 	/* default interval between the shutdown warning and the shutdown */
64 static	unsigned int	finaldelay = 5;
65 
66 	/* set by SIGHUP handler, cleared after reload finishes */
67 static	int	reload_flag = 0;
68 
69 	/* set after SIGINT, SIGQUIT, or SIGTERM */
70 static	int	exit_flag = 0;
71 
72 	/* userid for unprivileged process when using fork mode */
73 static	char	*run_as_user = NULL;
74 
75 	/* SSL details - where to find certs, whether to use them */
76 static	char	*certpath = NULL;
77 static	char	*certname = NULL;
78 static	char	*certpasswd = NULL;
79 static	int	certverify = 0;		/* don't verify by default */
80 static	int	forcessl = 0;		/* don't require ssl by default */
81 
82 static	int	userfsd = 0, use_pipe = 1, pipefd[2];
83 
84 static	utype_t	*firstups = NULL;
85 
86 static int 	opt_af = AF_UNSPEC;
87 
88 	/* signal handling things */
89 static	struct sigaction sa;
90 static	sigset_t nut_upsmon_sigmask;
91 
setflag(int * val,int flag)92 static void setflag(int *val, int flag)
93 {
94 	*val |= flag;
95 }
96 
clearflag(int * val,int flag)97 static void clearflag(int *val, int flag)
98 {
99 	*val ^= (*val & flag);
100 }
101 
flag_isset(int num,int flag)102 static int flag_isset(int num, int flag)
103 {
104 	return ((num & flag) == flag);
105 }
106 
wall(const char * text)107 static void wall(const char *text)
108 {
109 	FILE	*wf;
110 
111 	wf = popen("wall", "w");
112 
113 	if (!wf) {
114 		upslog_with_errno(LOG_NOTICE, "Can't invoke wall");
115 		return;
116 	}
117 
118 	fprintf(wf, "%s\n", text);
119 	pclose(wf);
120 }
121 
notify(const char * notice,int flags,const char * ntype,const char * upsname)122 static void notify(const char *notice, int flags, const char *ntype,
123 			const char *upsname)
124 {
125 	char	exec[LARGEBUF];
126 	int	ret;
127 
128 	if (flag_isset(flags, NOTIFY_IGNORE))
129 		return;
130 
131 	if (flag_isset(flags, NOTIFY_SYSLOG))
132 		upslogx(LOG_NOTICE, "%s", notice);
133 
134 	/* fork here so upsmon doesn't get wedged if the notifier is slow */
135 	ret = fork();
136 
137 	if (ret < 0) {
138 		upslog_with_errno(LOG_ERR, "Can't fork to notify");
139 		return;
140 	}
141 
142 	if (ret != 0)	/* parent */
143 		return;
144 
145 	/* child continues and does all the work */
146 
147 	if (flag_isset(flags, NOTIFY_WALL))
148 		wall(notice);
149 
150 	if (flag_isset(flags, NOTIFY_EXEC)) {
151 		if (notifycmd != NULL) {
152 			snprintf(exec, sizeof(exec), "%s \"%s\"", notifycmd, notice);
153 
154 			if (upsname)
155 				setenv("UPSNAME", upsname, 1);
156 			else
157 				setenv("UPSNAME", "", 1);
158 
159 			setenv("NOTIFYTYPE", ntype, 1);
160 			if (system(exec) == -1) {
161 				upslog_with_errno(LOG_ERR, "%s", __func__);
162 			}
163 		}
164 	}
165 
166 	exit(EXIT_SUCCESS);
167 }
168 
do_notify(const utype_t * ups,int ntype)169 static void do_notify(const utype_t *ups, int ntype)
170 {
171 	int	i;
172 	char	msg[SMALLBUF], *upsname = NULL;
173 
174 	/* grab this for later */
175 	if (ups)
176 		upsname = ups->sys;
177 
178 	for (i = 0; notifylist[i].name != NULL; i++) {
179 		if (notifylist[i].type == ntype) {
180 			upsdebugx(2, "%s: ntype 0x%04x (%s)", __func__, ntype,
181 				notifylist[i].name);
182 #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL
183 #pragma GCC diagnostic push
184 #endif
185 #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL
186 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
187 #endif
188 #ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_SECURITY
189 #pragma GCC diagnostic ignored "-Wformat-security"
190 #endif
191 			snprintf(msg, sizeof(msg),
192 				notifylist[i].msg ? notifylist[i].msg : notifylist[i].stockmsg,
193 				ups ? ups->sys : "");
194 #ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_FORMAT_NONLITERAL
195 #pragma GCC diagnostic pop
196 #endif
197 			notify(msg, notifylist[i].flags, notifylist[i].name,
198 				upsname);
199 			return;
200 		}
201 	}
202 
203 	/* not found ?! */
204 }
205 
206 /* check if we need "primary" mode (managerial permissions)
207  * on the server for this ups, and apply for them then.
208  * Returns 0 in case of error, 1 otherwise (including when
209  * we do not need to try becoming a primary). This currently
210  * propagates further as the return value of do_upsd_auth().
211  */
apply_for_primary(utype_t * ups)212 static int apply_for_primary(utype_t *ups)
213 {
214 	char	buf[SMALLBUF];
215 
216 	/* don't bother if we're not configured as a primary for this ups */
217 	if (!flag_isset(ups->status, ST_PRIMARY))
218 		return 1;
219 
220 	/* this shouldn't happen (LOGIN checks it earlier) */
221 	if ((ups->upsname == NULL) || (strlen(ups->upsname) == 0)) {
222 		upslogx(LOG_ERR, "Set primary managerial mode on UPS [%s] failed: empty upsname",
223 			ups->sys);
224 		return 0;
225 	}
226 
227 	/* TODO: Use PRIMARY first but if talking to older server, retry with MASTER */
228 	snprintf(buf, sizeof(buf), "MASTER %s\n", ups->upsname);
229 
230 	if (upscli_sendline(&ups->conn, buf, strlen(buf)) < 0) {
231 		upslogx(LOG_ALERT, "Can't set primary managerial mode on UPS [%s] - %s",
232 			ups->sys, upscli_strerror(&ups->conn));
233 		return 0;
234 	}
235 
236 	if (upscli_readline(&ups->conn, buf, sizeof(buf)) == 0) {
237 		if (!strncmp(buf, "OK", 2))
238 			return 1;
239 
240 		/* not ERR, but not caught by readline either? */
241 
242 		upslogx(LOG_ALERT, "Primary managerial privileges unavailable on UPS [%s]",
243 			ups->sys);
244 		upslogx(LOG_ALERT, "Response: [%s]", buf);
245 	}
246 	else {	/* something caught by readraw's parsing call */
247 		upslogx(LOG_ALERT, "Primary managerial privileges unavailable on UPS [%s]",
248 			ups->sys);
249 		upslogx(LOG_ALERT, "Reason: %s", upscli_strerror(&ups->conn));
250 	}
251 
252 	return 0;
253 }
254 
255 /* authenticate to upsd, plus do LOGIN and MASTER if applicable */
256 /* TODO: API change pending to replace deprecated MASTER with PRIMARY
257  * and SLAVE with SECONDARY (and backwards-compatible alias handling)
258  */
do_upsd_auth(utype_t * ups)259 static int do_upsd_auth(utype_t *ups)
260 {
261 	char	buf[SMALLBUF];
262 
263 	if (!ups->un) {
264 		upslogx(LOG_ERR, "UPS [%s]: no username defined!", ups->sys);
265 		return 0;
266 	}
267 
268 	snprintf(buf, sizeof(buf), "USERNAME %s\n", ups->un);
269 	if (upscli_sendline(&ups->conn, buf, strlen(buf)) < 0) {
270 		upslogx(LOG_ERR, "Can't set username on [%s]: %s",
271 			ups->sys, upscli_strerror(&ups->conn));
272 			return 0;
273 	}
274 
275 	if (upscli_readline(&ups->conn, buf, sizeof(buf)) < 0) {
276 		upslogx(LOG_ERR, "Set username on [%s] failed: %s",
277 			ups->sys, upscli_strerror(&ups->conn));
278 		return 0;
279 	}
280 
281 	/* authenticate first */
282 	snprintf(buf, sizeof(buf), "PASSWORD %s\n", ups->pw);
283 
284 	if (upscli_sendline(&ups->conn, buf, strlen(buf)) < 0) {
285 		upslogx(LOG_ERR, "Can't set password on [%s]: %s",
286 			ups->sys, upscli_strerror(&ups->conn));
287 			return 0;
288 	}
289 
290 	if (upscli_readline(&ups->conn, buf, sizeof(buf)) < 0) {
291 		upslogx(LOG_ERR, "Set password on [%s] failed: %s",
292 			ups->sys, upscli_strerror(&ups->conn));
293 		return 0;
294 	}
295 
296 	/* catch insanity from the server - not ERR and not OK either */
297 	if (strncmp(buf, "OK", 2) != 0) {
298 		upslogx(LOG_ERR, "Set password on [%s] failed - got [%s]",
299 			ups->sys, buf);
300 		return 0;
301 	}
302 
303 	/* we require a upsname now */
304 	if ((ups->upsname == NULL) || (strlen(ups->upsname) == 0)) {
305 		upslogx(LOG_ERR, "Login to UPS [%s] failed: empty upsname",
306 			ups->sys);
307 		return 0;
308 	}
309 
310 	/* password is set, let's login */
311 	snprintf(buf, sizeof(buf), "LOGIN %s\n", ups->upsname);
312 
313 	if (upscli_sendline(&ups->conn, buf, strlen(buf)) < 0) {
314 		upslogx(LOG_ERR, "Login to UPS [%s] failed: %s",
315 			ups->sys, upscli_strerror(&ups->conn));
316 		return 0;
317 	}
318 
319 	if (upscli_readline(&ups->conn, buf, sizeof(buf)) < 0) {
320 		upslogx(LOG_ERR, "Can't login to UPS [%s]: %s",
321 			ups->sys, upscli_strerror(&ups->conn));
322 		return 0;
323 	}
324 
325 	/* catch insanity from the server - not ERR and not OK either */
326 	if (strncmp(buf, "OK", 2) != 0) {
327 		upslogx(LOG_ERR, "Login on UPS [%s] failed - got [%s]",
328 			ups->sys, buf);
329 		return 0;
330 	}
331 
332 	/* finally - everything is OK */
333 	upsdebugx(1, "Logged into UPS %s", ups->sys);
334 	setflag(&ups->status, ST_LOGIN);
335 
336 	/* now see if we also need to test primary managerial-mode permissions */
337 	return apply_for_primary(ups);
338 }
339 
340 /* set flags and make announcements when a UPS has been checked successfully */
ups_is_alive(utype_t * ups)341 static void ups_is_alive(utype_t *ups)
342 {
343 	time_t	now;
344 
345 	time(&now);
346 	ups->lastpoll = now;
347 
348 	if (ups->commstate == 1)		/* already known */
349 		return;
350 
351 	/* only notify for 0->1 transitions (to ignore the first connect) */
352 	if (ups->commstate == 0)
353 		do_notify(ups, NOTIFY_COMMOK);
354 
355 	ups->commstate = 1;
356 }
357 
358 /* handle all the notifications for a missing UPS in one place */
ups_is_gone(utype_t * ups)359 static void ups_is_gone(utype_t *ups)
360 {
361 	time_t	now;
362 
363 	/* first time: clear the flag and throw the first notifier */
364 	if (ups->commstate != 0) {
365 		ups->commstate = 0;
366 
367 		/* COMMBAD is the initial loss of communications */
368 		do_notify(ups, NOTIFY_COMMBAD);
369 		return;
370 	}
371 
372 	time(&now);
373 
374 	/* first only act if we're <nocommtime> seconds past the last poll */
375 	if ((now - ups->lastpoll) < nocommwarntime)
376 		return;
377 
378 	/* now only complain if we haven't lately */
379 	if ((now - ups->lastncwarn) > nocommwarntime) {
380 
381 		/* NOCOMM indicates a persistent condition */
382 		do_notify(ups, NOTIFY_NOCOMM);
383 		ups->lastncwarn = now;
384 	}
385 }
386 
ups_on_batt(utype_t * ups)387 static void ups_on_batt(utype_t *ups)
388 {
389 	if (flag_isset(ups->status, ST_ONBATT)) { 	/* no change */
390 		upsdebugx(4, "%s: %s (no change)", __func__, ups->sys);
391 		return;
392 	}
393 
394 	sleepval = pollfreqalert;	/* bump up polling frequency */
395 
396 	ups->linestate = 0;
397 
398 	upsdebugx(3, "%s: %s (first time)", __func__, ups->sys);
399 
400 	/* must have changed from OL to OB, so notify */
401 
402 	do_notify(ups, NOTIFY_ONBATT);
403 	setflag(&ups->status, ST_ONBATT);
404 	clearflag(&ups->status, ST_ONLINE);
405 }
406 
ups_on_line(utype_t * ups)407 static void ups_on_line(utype_t *ups)
408 {
409 	if (flag_isset(ups->status, ST_ONLINE)) { 	/* no change */
410 		upsdebugx(4, "%s: %s (no change)", __func__, ups->sys);
411 		return;
412 	}
413 
414 	sleepval = pollfreq;
415 
416 	upsdebugx(3, "%s: %s (first time)", __func__, ups->sys);
417 
418 	/* ignore the first OL at startup, otherwise send the notifier */
419 	if (ups->linestate != -1)
420 		do_notify(ups, NOTIFY_ONLINE);
421 
422 	ups->linestate = 1;
423 
424 	setflag(&ups->status, ST_ONLINE);
425 	clearflag(&ups->status, ST_ONBATT);
426 }
427 
428 /* create the flag file if necessary */
set_pdflag(void)429 static void set_pdflag(void)
430 {
431 	FILE	*pdf;
432 
433 	if (!powerdownflag)
434 		return;
435 
436 	pdf = fopen(powerdownflag, "w");
437 	if (!pdf) {
438 		upslogx(LOG_ERR, "Failed to create power down flag!");
439 		return;
440 	}
441 
442 	fprintf(pdf, "%s", SDMAGIC);
443 	fclose(pdf);
444 }
445 
446 /* the actual shutdown procedure */
447 static void doshutdown(void)
448 	__attribute__((noreturn));
449 
doshutdown(void)450 static void doshutdown(void)
451 {
452 	/* this should probably go away at some point */
453 	upslogx(LOG_CRIT, "Executing automatic power-fail shutdown");
454 	wall("Executing automatic power-fail shutdown\n");
455 
456 	do_notify(NULL, NOTIFY_SHUTDOWN);
457 
458 	sleep(finaldelay);
459 
460 	/* in the pipe model, we let the parent do this for us */
461 	if (use_pipe) {
462 		char	ch;
463 		ssize_t	wret;
464 
465 		ch = 1;
466 		wret = write(pipefd[1], &ch, 1);
467 
468 		if (wret < 1)
469 			upslogx(LOG_ERR, "Unable to call parent pipe for shutdown");
470 	} else {
471 		/* one process model = we do all the work here */
472 		int	sret;
473 
474 		if (geteuid() != 0)
475 			upslogx(LOG_WARNING, "Not root, shutdown may fail");
476 
477 		set_pdflag();
478 
479 		sret = system(shutdowncmd);
480 
481 		if (sret != 0)
482 			upslogx(LOG_ERR, "Unable to call shutdown command: %s",
483 				shutdowncmd);
484 	}
485 
486 	exit(EXIT_SUCCESS);
487 }
488 
489 /* set forced shutdown flag so other upsmons know what's going on here */
setfsd(utype_t * ups)490 static void setfsd(utype_t *ups)
491 {
492 	char	buf[SMALLBUF];
493 	ssize_t	ret;
494 
495 	/* this shouldn't happen */
496 	if (!ups->upsname) {
497 		upslogx(LOG_ERR, "setfsd: programming error: no UPS name set [%s]",
498 			ups->sys);
499 		return;
500 	}
501 
502 	upsdebugx(2, "Setting FSD on UPS %s", ups->sys);
503 
504 	snprintf(buf, sizeof(buf), "FSD %s\n", ups->upsname);
505 
506 	ret = upscli_sendline(&ups->conn, buf, strlen(buf));
507 
508 	if (ret < 0) {
509 		upslogx(LOG_ERR, "FSD set on UPS %s failed: %s", ups->sys,
510 			upscli_strerror(&ups->conn));
511 		return;
512 	}
513 
514 	ret = upscli_readline(&ups->conn, buf, sizeof(buf));
515 
516 	if (ret < 0) {
517 		upslogx(LOG_ERR, "FSD set on UPS %s failed: %s", ups->sys,
518 			upscli_strerror(&ups->conn));
519 		return;
520 	}
521 
522 	if (!strncmp(buf, "OK", 2))
523 		return;
524 
525 	/* protocol error: upsd said something other than "OK" */
526 	upslogx(LOG_ERR, "FSD set on UPS %s failed: %s", ups->sys, buf);
527 }
528 
set_alarm(void)529 static void set_alarm(void)
530 {
531 	alarm(NET_TIMEOUT);
532 }
533 
clear_alarm(void)534 static void clear_alarm(void)
535 {
536 #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_STRICT_PROTOTYPES)
537 # pragma GCC diagnostic push
538 # pragma GCC diagnostic ignored "-Wstrict-prototypes"
539 #endif
540 	signal(SIGALRM, SIG_IGN);
541 #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_STRICT_PROTOTYPES)
542 # pragma GCC diagnostic pop
543 #endif
544 	alarm(0);
545 }
546 
get_var(utype_t * ups,const char * var,char * buf,size_t bufsize)547 static int get_var(utype_t *ups, const char *var, char *buf, size_t bufsize)
548 {
549 	int	ret;
550 	size_t	numq, numa;
551 	const	char	*query[4];
552 	char	**answer;
553 
554 	/* this shouldn't happen */
555 	if (!ups->upsname) {
556 		upslogx(LOG_ERR, "get_var: programming error: no UPS name set [%s]",
557 			ups->sys);
558 		return -1;
559 	}
560 
561 	numq = 0;
562 
563 	if (!strcmp(var, "numlogins")) {
564 		query[0] = "NUMLOGINS";
565 		query[1] = ups->upsname;
566 		numq = 2;
567 	}
568 
569 	if (!strcmp(var, "status")) {
570 		query[0] = "VAR";
571 		query[1] = ups->upsname;
572 		query[2] = "ups.status";
573 		numq = 3;
574 	}
575 
576 	if (numq == 0) {
577 		upslogx(LOG_ERR, "get_var: programming error: var=%s", var);
578 		return -1;
579 	}
580 
581 	upsdebugx(3, "%s: %s / %s", __func__, ups->sys, var);
582 
583 	ret = upscli_get(&ups->conn, numq, query, &numa, &answer);
584 
585 	if (ret < 0) {
586 
587 		/* detect old upsd */
588 		if (upscli_upserror(&ups->conn) == UPSCLI_ERR_UNKCOMMAND) {
589 
590 			upslogx(LOG_ERR, "UPS [%s]: Too old to monitor",
591 				ups->sys);
592 			return -1;
593 		}
594 
595 		/* some other error */
596 		return -1;
597 	}
598 
599 	if (numa < numq) {
600 		upslogx(LOG_ERR, "%s: Error: insufficient data "
601 			"(got %zu args, need at least %zu)",
602 			var, numa, numq);
603 		return -1;
604 	}
605 
606 	snprintf(buf, bufsize, "%s", answer[numq]);
607 	return 0;
608 }
609 
610 /* Called by upsmon which is the primary on some UPS(es) to wait
611  * until all secondaries log out from it on the shared upsd server
612  * or the HOSTSYNC timeout expires
613  */
sync_secondaries(void)614 static void sync_secondaries(void)
615 {
616 	utype_t	*ups;
617 	char	temp[SMALLBUF];
618 	time_t	start, now;
619 	long	maxlogins, logins;
620 
621 	time(&start);
622 
623 	for (;;) {
624 		maxlogins = 0;
625 
626 		for (ups = firstups; ups != NULL; ups = ups->next) {
627 
628 			/* only check login count on devices we are the primary for */
629 			if (!flag_isset(ups->status, ST_PRIMARY))
630 				continue;
631 
632 			set_alarm();
633 
634 			if (get_var(ups, "numlogins", temp, sizeof(temp)) >= 0) {
635 				logins = strtol(temp, (char **)NULL, 10);
636 
637 				if (logins > maxlogins)
638 					maxlogins = logins;
639 			}
640 
641 			clear_alarm();
642 		}
643 
644 		/* if no UPS has more than 1 login (that would be us),
645 		 * then secondaries are all gone */
646 		/* TO THINK: how about redundant setups with several primary-mode
647 		 * clients managing an UPS, or possibly differend UPSes, with the
648 		 * same upsd? */
649 		if (maxlogins <= 1)
650 			return;
651 
652 		/* after HOSTSYNC seconds, assume secondaries are stuck - and bail */
653 		time(&now);
654 
655 		if ((now - start) > hostsync) {
656 			upslogx(LOG_INFO, "Host sync timer expired, forcing shutdown");
657 			return;
658 		}
659 
660 		usleep(250000);
661 	}
662 }
663 
664 static void forceshutdown(void)
665 	__attribute__((noreturn));
666 
forceshutdown(void)667 static void forceshutdown(void)
668 {
669 	utype_t	*ups;
670 	int	isaprimary = 0;
671 
672 	upsdebugx(1, "Shutting down any UPSes in PRIMARY mode...");
673 
674 	/* set FSD on any "primary" UPS entries (forced shutdown in progress) */
675 	for (ups = firstups; ups != NULL; ups = ups->next)
676 		if (flag_isset(ups->status, ST_PRIMARY)) {
677 			isaprimary = 1;
678 			setfsd(ups);
679 		}
680 
681 	/* if we're not a primary on anything, we should shut down now */
682 	if (!isaprimary)
683 		doshutdown();
684 
685 	/* we must be the primary now */
686 	upsdebugx(1, "This system is a primary... waiting for secondaries to logout...");
687 
688 	/* wait up to HOSTSYNC seconds for secondaries to logout */
689 	sync_secondaries();
690 
691 	/* time expired or all the secondaries are gone, so shutdown */
692 	doshutdown();
693 }
694 
is_ups_critical(utype_t * ups)695 static int is_ups_critical(utype_t *ups)
696 {
697 	time_t	now;
698 
699 	/* FSD = the primary is forcing a shutdown, or a driver forwarded the flag
700 	 * from a smarter UPS depending on vendor protocol, ability and settings
701 	 * (e.g. is charging but battery too low to guarantee safety to the load)
702 	 */
703 	if (flag_isset(ups->status, ST_FSD))
704 		return 1;
705 
706 	/* not OB or not LB = not critical yet */
707 	if ((!flag_isset(ups->status, ST_ONBATT)) ||
708 		(!flag_isset(ups->status, ST_LOWBATT)))
709 		return 0;
710 
711 	/* must be OB+LB now */
712 
713 	/* if UPS is calibrating, don't declare it critical */
714 	/* FIXME: Consider UPSes where we can know if they have other power
715 	 * circuits (bypass, etc.) and whether those do currently provide
716 	 * wall power to the host - and that we do not have both calibration
717 	 * and a real outage, when we still should shut down right now.
718 	 */
719 	if (flag_isset(ups->status, ST_CAL)) {
720 		upslogx(LOG_WARNING, "%s: seems that UPS [%s] is OB+LB now, but "
721 			"it is also calibrating - not declaring a critical state",
722 			  __func__, ups->upsname);
723 		return 0;
724 	}
725 
726 	/* if we're a primary, declare it critical so we set FSD on it */
727 	if (flag_isset(ups->status, ST_PRIMARY))
728 		return 1;
729 
730 	/* must be a secondary now */
731 
732 	/* FSD isn't set, so the primary hasn't seen it yet */
733 
734 	time(&now);
735 
736 	/* give the primary up to HOSTSYNC seconds before shutting down */
737 	if ((now - ups->lastnoncrit) > hostsync) {
738 		upslogx(LOG_WARNING, "Giving up on the primary for UPS [%s]",
739 			ups->sys);
740 		return 1;
741 	}
742 
743 	/* there's still time left, maybe OB+LB will go away next time we look? */
744 	return 0;
745 }
746 
747 /* recalculate the online power value and see if things are still OK */
recalc(void)748 static void recalc(void)
749 {
750 	utype_t	*ups;
751 	unsigned int	val_ol = 0;
752 	time_t	now;
753 
754 	time(&now);
755 	ups = firstups;
756 	while (ups != NULL) {
757 		/* promote dead UPSes that were last known OB to OB+LB */
758 		if ((now - ups->lastpoll) > deadtime)
759 			if (flag_isset(ups->status, ST_ONBATT)) {
760 				upsdebugx(1, "Promoting dead UPS: %s", ups->sys);
761 				setflag(&ups->status, ST_LOWBATT);
762 			}
763 
764 		/* note: we assume that a UPS that isn't critical must be OK *
765 		 *                                                           *
766 		 * this means a UPS we've never heard from is assumed OL     *
767 		 * whether this is really the best thing to do is undecided  */
768 
769 		/* crit = (FSD) || (OB & LB) > HOSTSYNC seconds */
770 		if (is_ups_critical(ups))
771 			upsdebugx(1, "Critical UPS: %s", ups->sys);
772 		else
773 			val_ol += ups->pv;
774 
775 		ups = ups->next;
776 	}
777 
778 	upsdebugx(3, "Current power value: %u", val_ol);
779 	upsdebugx(3, "Minimum power value: %u", minsupplies);
780 
781 	if (val_ol < minsupplies)
782 		forceshutdown();
783 }
784 
ups_low_batt(utype_t * ups)785 static void ups_low_batt(utype_t *ups)
786 {
787 	if (flag_isset(ups->status, ST_LOWBATT)) { 	/* no change */
788 		upsdebugx(4, "%s: %s (no change)", __func__, ups->sys);
789 		return;
790 	}
791 
792 	upsdebugx(3, "%s: %s (first time)", __func__, ups->sys);
793 
794 	/* must have changed from !LB to LB, so notify */
795 
796 	do_notify(ups, NOTIFY_LOWBATT);
797 	setflag(&ups->status, ST_LOWBATT);
798 }
799 
upsreplbatt(utype_t * ups)800 static void upsreplbatt(utype_t *ups)
801 {
802 	time_t	now;
803 
804 	time(&now);
805 
806 	if ((now - ups->lastrbwarn) > rbwarntime) {
807 		do_notify(ups, NOTIFY_REPLBATT);
808 		ups->lastrbwarn = now;
809 	}
810 }
811 
ups_cal(utype_t * ups)812 static void ups_cal(utype_t *ups)
813 {
814 	if (flag_isset(ups->status, ST_CAL)) { 	/* no change */
815 		upsdebugx(4, "%s: %s (no change)", __func__, ups->sys);
816 		return;
817 	}
818 
819 	upsdebugx(3, "%s: %s (first time)", __func__, ups->sys);
820 
821 	/* must have changed from !CAL to CAL, so notify */
822 
823 	do_notify(ups, NOTIFY_CAL);
824 	setflag(&ups->status, ST_CAL);
825 }
826 
ups_fsd(utype_t * ups)827 static void ups_fsd(utype_t *ups)
828 {
829 	if (flag_isset(ups->status, ST_FSD)) {		/* no change */
830 		upsdebugx(4, "%s: %s (no change)", __func__, ups->sys);
831 		return;
832 	}
833 
834 	upsdebugx(3, "%s: %s (first time)", __func__, ups->sys);
835 
836 	/* must have changed from !FSD to FSD, so notify */
837 
838 	do_notify(ups, NOTIFY_FSD);
839 	setflag(&ups->status, ST_FSD);
840 }
841 
842 /* cleanly close the connection to a given UPS */
drop_connection(utype_t * ups)843 static void drop_connection(utype_t *ups)
844 {
845 	upsdebugx(2, "Dropping connection to UPS [%s]", ups->sys);
846 
847 	ups->commstate = 0;
848 	ups->linestate = 0;
849 	clearflag(&ups->status, ST_LOGIN);
850 	clearflag(&ups->status, ST_CONNECTED);
851 
852 	upscli_disconnect(&ups->conn);
853 }
854 
855 /* change some UPS parameters during reloading */
redefine_ups(utype_t * ups,unsigned int pv,const char * un,const char * pw,const char * managerialOption)856 static void redefine_ups(utype_t *ups, unsigned int pv, const char *un,
857 		const char *pw, const char *managerialOption)
858 {
859 	ups->retain = 1;
860 
861 	if (ups->pv != pv) {
862 		upslogx(LOG_INFO, "UPS [%s]: redefined power value to %d",
863 			ups->sys, pv);
864 		ups->pv = pv;
865 	}
866 
867 	totalpv += ups->pv;
868 
869 	if (ups->un) {
870 		if (strcmp(ups->un, un) != 0) {
871 			upslogx(LOG_INFO, "UPS [%s]: redefined username",
872 				ups->sys);
873 
874 			free(ups->un);
875 
876 			ups->un = xstrdup(un);
877 
878 			/*
879 			 * if not logged in force a reconnection since this
880 			 * may have been redefined to make a login work
881 			 */
882 
883 			if (!flag_isset(ups->status, ST_LOGIN)) {
884 				upslogx(LOG_INFO, "UPS [%s]: retrying connection",
885 					ups->sys);
886 
887 				drop_connection(ups);
888 			}
889 
890 		}	/* if (strcmp(ups->un, un) != 0) { */
891 
892 	} else {
893 
894 		/* adding a username? (going to new style MONITOR line) */
895 
896 		if (un) {
897 			upslogx(LOG_INFO, "UPS [%s]: defined username",
898 				ups->sys);
899 
900 			ups->un = xstrdup(un);
901 
902 			/* possibly force reconnection - see above */
903 
904 			if (!flag_isset(ups->status, ST_LOGIN)) {
905 				upslogx(LOG_INFO, "UPS [%s]: retrying connection",
906 					ups->sys);
907 
908 				drop_connection(ups);
909 			}
910 
911 		}	/* if (un) */
912 	}
913 
914 	/* paranoia */
915 	if (!ups->pw)
916 		ups->pw = xstrdup("");	/* give it a bogus, but non-NULL one */
917 
918 	/* obviously don't put the new password in the syslog... */
919 	if (strcmp(ups->pw, pw) != 0) {
920 		upslogx(LOG_INFO, "UPS [%s]: redefined password", ups->sys);
921 
922 		free(ups->pw);
923 		ups->pw = xstrdup(pw);
924 
925 		/* possibly force reconnection - see above */
926 
927 		if (!flag_isset(ups->status, ST_LOGIN)) {
928 			upslogx(LOG_INFO, "UPS [%s]: retrying connection",
929 				ups->sys);
930 
931 			drop_connection(ups);
932 		}
933 	}
934 
935 	/* secondary|slave -> primary|master */
936 	if ( (   (!strcasecmp(managerialOption, "primary"))
937 	      || (!strcasecmp(managerialOption, "master"))  )
938 	     && (!flag_isset(ups->status, ST_PRIMARY)) ) {
939 		upslogx(LOG_INFO, "UPS [%s]: redefined as a primary", ups->sys);
940 		setflag(&ups->status, ST_PRIMARY);
941 
942 		/* reset connection to ensure primary mode gets checked */
943 		drop_connection(ups);
944 		return;
945 	}
946 
947 	/* primary|master -> secondary|slave */
948 	if ( (   (!strcasecmp(managerialOption, "secondary"))
949 	      || (!strcasecmp(managerialOption, "slave"))  )
950 	     && (flag_isset(ups->status, ST_PRIMARY)) ) {
951 		upslogx(LOG_INFO, "UPS [%s]: redefined as a secondary", ups->sys);
952 		clearflag(&ups->status, ST_PRIMARY);
953 		return;
954 	}
955 }
956 
addups(int reloading,const char * sys,const char * pvs,const char * un,const char * pw,const char * managerialOption)957 static void addups(int reloading, const char *sys, const char *pvs,
958 		const char *un, const char *pw, const char *managerialOption)
959 {
960 	unsigned int	pv;
961 	utype_t	*tmp, *last;
962 
963 	/* the username is now required - no more host-based auth */
964 
965 	if ((!sys) || (!pvs) || (!pw) || (!managerialOption) || (!un)) {
966 		upslogx(LOG_WARNING, "Ignoring invalid MONITOR line in %s!", configfile);
967 		upslogx(LOG_WARNING, "MONITOR configuration directives require five arguments.");
968 		return;
969 	}
970 
971 	long lpv = strtol(pvs, (char **) NULL, 10);
972 
973 	if (lpv < 0 || (sizeof(long) > sizeof(unsigned int) && lpv > (long)UINT_MAX)) {
974 		upslogx(LOG_WARNING, "UPS [%s]: ignoring invalid power value [%s]",
975 			sys, pvs);
976 		return;
977 	}
978 	pv = (unsigned int)lpv;
979 
980 	last = tmp = firstups;
981 
982 	while (tmp) {
983 		last = tmp;
984 
985 		/* check for duplicates */
986 		if (!strcmp(tmp->sys, sys)) {
987 			if (reloading)
988 				redefine_ups(tmp, pv, un, pw, managerialOption);
989 			else
990 				upslogx(LOG_WARNING, "Warning: ignoring duplicate"
991 					" UPS [%s]", sys);
992 			return;
993 		}
994 
995 		tmp = tmp->next;
996 	}
997 
998 	tmp = xmalloc(sizeof(utype_t));
999 	tmp->sys = xstrdup(sys);
1000 	tmp->pv = pv;
1001 
1002 	/* build this up so the user doesn't run with bad settings */
1003 	totalpv += tmp->pv;
1004 
1005 	tmp->un = xstrdup(un);
1006 
1007 	tmp->pw = xstrdup(pw);
1008 	tmp->status = 0;
1009 	tmp->retain = 1;
1010 
1011 	/* ignore initial COMMOK and ONLINE by default */
1012 	tmp->commstate = -1;
1013 	tmp->linestate = -1;
1014 
1015 	tmp->lastpoll = 0;
1016 	tmp->lastnoncrit = 0;
1017 	tmp->lastrbwarn = 0;
1018 	tmp->lastncwarn = 0;
1019 
1020 	if (   (!strcasecmp(managerialOption, "primary"))
1021 	    || (!strcasecmp(managerialOption, "master"))  ) {
1022 		setflag(&tmp->status, ST_PRIMARY);
1023 	}
1024 
1025 	tmp->next = NULL;
1026 
1027 	if (last)
1028 		last->next = tmp;
1029 	else
1030 		firstups = tmp;
1031 
1032 	if (tmp->pv)
1033 		upslogx(LOG_INFO, "UPS: %s (%s) (power value %d)", tmp->sys,
1034 			flag_isset(tmp->status, ST_PRIMARY) ? "primary" : "secondary",
1035 			tmp->pv);
1036 	else
1037 		upslogx(LOG_INFO, "UPS: %s (monitoring only)", tmp->sys);
1038 
1039 	tmp->upsname = tmp->hostname = NULL;
1040 
1041 	if (upscli_splitname(tmp->sys, &tmp->upsname, &tmp->hostname,
1042 		&tmp->port) != 0) {
1043 		upslogx(LOG_ERR, "Error: unable to split UPS name [%s]",
1044 			tmp->sys);
1045 	}
1046 
1047 	if (!tmp->upsname)
1048 		upslogx(LOG_WARNING, "Warning: UPS [%s]: no upsname set!",
1049 			tmp->sys);
1050 }
1051 
set_notifymsg(const char * name,const char * msg)1052 static void set_notifymsg(const char *name, const char *msg)
1053 {
1054 	int	i;
1055 
1056 	for (i = 0; notifylist[i].name != NULL; i++) {
1057 		if (!strcasecmp(notifylist[i].name, name)) {
1058 			free(notifylist[i].msg);
1059 			notifylist[i].msg = xstrdup(msg);
1060 			return;
1061 		}
1062 	}
1063 
1064 	upslogx(LOG_WARNING, "'%s' is not a valid notify event name", name);
1065 }
1066 
set_notifyflag(const char * ntype,char * flags)1067 static void set_notifyflag(const char *ntype, char *flags)
1068 {
1069 	int	i, pos;
1070 	char	*ptr, *tmp;
1071 
1072 	/* find ntype */
1073 
1074 	pos = -1;
1075 	for (i = 0; notifylist[i].name != NULL; i++) {
1076 		if (!strcasecmp(notifylist[i].name, ntype)) {
1077 			pos = i;
1078 			break;
1079 		}
1080 	}
1081 
1082 	if (pos == -1) {
1083 		upslogx(LOG_WARNING, "Warning: invalid notify type [%s]", ntype);
1084 		return;
1085 	}
1086 
1087 	ptr = flags;
1088 
1089 	/* zero existing flags */
1090 	notifylist[pos].flags = 0;
1091 
1092 	while (ptr) {
1093 		int	newflag;
1094 
1095 		tmp = strchr(ptr, '+');
1096 		if (tmp)
1097 			*tmp++ = '\0';
1098 
1099 		newflag = 0;
1100 
1101 		if (!strcmp(ptr, "SYSLOG"))
1102 			newflag = NOTIFY_SYSLOG;
1103 		if (!strcmp(ptr, "WALL"))
1104 			newflag = NOTIFY_WALL;
1105 		if (!strcmp(ptr, "EXEC"))
1106 			newflag = NOTIFY_EXEC;
1107 		if (!strcmp(ptr, "IGNORE"))
1108 			newflag = NOTIFY_IGNORE;
1109 
1110 		if (newflag)
1111 			notifylist[pos].flags |= newflag;
1112 		else
1113 			upslogx(LOG_WARNING, "Invalid notify flag: [%s]", ptr);
1114 
1115 		ptr = tmp;
1116 	}
1117 }
1118 
1119 /* in split mode, the parent doesn't hear about reloads */
checkmode(char * cfgentry,char * oldvalue,char * newvalue,int reloading)1120 static void checkmode(char *cfgentry, char *oldvalue, char *newvalue,
1121 			int reloading)
1122 {
1123 	/* nothing to do if in "all as root" mode */
1124 	if (use_pipe == 0)
1125 		return;
1126 
1127 	/* it's ok if we're not reloading yet */
1128 	if (reloading == 0)
1129 		return;
1130 
1131 	/* also nothing to do if it didn't change */
1132 	if ((oldvalue) && (newvalue)) {
1133 		if (!strcmp(oldvalue, newvalue))
1134 			return;
1135 	}
1136 
1137 	/* otherwise, yell at them */
1138 	upslogx(LOG_WARNING, "Warning: %s redefined in split-process mode!",
1139 		cfgentry);
1140 	upslogx(LOG_WARNING, "You must restart upsmon for this change to work");
1141 }
1142 
1143 /* returns 1 if used, 0 if not, so we can complain about bogus configs */
parse_conf_arg(size_t numargs,char ** arg)1144 static int parse_conf_arg(size_t numargs, char **arg)
1145 {
1146 	/* using up to arg[1] below */
1147 	if (numargs < 2)
1148 		return 0;
1149 
1150 	/* SHUTDOWNCMD <cmd> */
1151 	if (!strcmp(arg[0], "SHUTDOWNCMD")) {
1152 		checkmode(arg[0], shutdowncmd, arg[1], reload_flag);
1153 
1154 		free(shutdowncmd);
1155 		shutdowncmd = xstrdup(arg[1]);
1156 		return 1;
1157 	}
1158 
1159 	/* POWERDOWNFLAG <fn> */
1160 	if (!strcmp(arg[0], "POWERDOWNFLAG")) {
1161 		checkmode(arg[0], powerdownflag, arg[1], reload_flag);
1162 
1163 		free(powerdownflag);
1164 		powerdownflag = xstrdup(arg[1]);
1165 
1166 		if (!reload_flag)
1167 			upslogx(LOG_INFO, "Using power down flag file %s",
1168 				arg[1]);
1169 
1170 		return 1;
1171 	}
1172 
1173 	/* NOTIFYCMD <cmd> */
1174 	if (!strcmp(arg[0], "NOTIFYCMD")) {
1175 		free(notifycmd);
1176 		notifycmd = xstrdup(arg[1]);
1177 		return 1;
1178 	}
1179 
1180 	/* POLLFREQ <num> */
1181 	if (!strcmp(arg[0], "POLLFREQ")) {
1182 		int ipollfreq = atoi(arg[1]);
1183 		if (ipollfreq < 0) {
1184 			upsdebugx(0, "Ignoring invalid POLLFREQ value: %d", ipollfreq);
1185 		} else {
1186 			pollfreq = (unsigned int)ipollfreq;
1187 		}
1188 		return 1;
1189 	}
1190 
1191 	/* POLLFREQALERT <num> */
1192 	if (!strcmp(arg[0], "POLLFREQALERT")) {
1193 		int ipollfreqalert = atoi(arg[1]);
1194 		if (ipollfreqalert < 0) {
1195 			upsdebugx(0, "Ignoring invalid POLLFREQALERT value: %d", ipollfreqalert);
1196 		} else {
1197 			pollfreqalert = (unsigned int)ipollfreqalert;
1198 		}
1199 		return 1;
1200 	}
1201 
1202 	/* HOSTSYNC <num> */
1203 	if (!strcmp(arg[0], "HOSTSYNC")) {
1204 		hostsync = atoi(arg[1]);
1205 		return 1;
1206 	}
1207 
1208 	/* DEADTIME <num> */
1209 	if (!strcmp(arg[0], "DEADTIME")) {
1210 		deadtime = atoi(arg[1]);
1211 		return 1;
1212 	}
1213 
1214 	/* MINSUPPLIES <num> */
1215 	if (!strcmp(arg[0], "MINSUPPLIES")) {
1216 		int iminsupplies = atoi(arg[1]);
1217 		if (iminsupplies < 0) {
1218 			upsdebugx(0, "Ignoring invalid MINSUPPLIES value: %d", iminsupplies);
1219 		} else {
1220 			minsupplies = (unsigned int)iminsupplies;
1221 		}
1222 		return 1;
1223 	}
1224 
1225 	/* RBWARNTIME <num> */
1226 	if (!strcmp(arg[0], "RBWARNTIME")) {
1227 		rbwarntime = atoi(arg[1]);
1228 		return 1;
1229 	}
1230 
1231 	/* NOCOMMWARNTIME <num> */
1232 	if (!strcmp(arg[0], "NOCOMMWARNTIME")) {
1233 		nocommwarntime = atoi(arg[1]);
1234 		return 1;
1235 	}
1236 
1237 	/* FINALDELAY <num> */
1238 	if (!strcmp(arg[0], "FINALDELAY")) {
1239 		int ifinaldelay = atoi(arg[1]);
1240 		if (ifinaldelay < 0) {
1241 			upsdebugx(0, "Ignoring invalid FINALDELAY value: %d", ifinaldelay);
1242 		} else {
1243 			finaldelay = (unsigned int)ifinaldelay;
1244 		}
1245 		return 1;
1246 	}
1247 
1248 	/* RUN_AS_USER <userid> */
1249  	if (!strcmp(arg[0], "RUN_AS_USER")) {
1250 		free(run_as_user);
1251 		run_as_user = xstrdup(arg[1]);
1252 		return 1;
1253 	}
1254 
1255 	/* CERTPATH <path> */
1256 	if (!strcmp(arg[0], "CERTPATH")) {
1257 		free(certpath);
1258 		certpath = xstrdup(arg[1]);
1259 		return 1;
1260 	}
1261 
1262 	/* CERTVERIFY (0|1) */
1263 	if (!strcmp(arg[0], "CERTVERIFY")) {
1264 		certverify = atoi(arg[1]);
1265 		return 1;
1266 	}
1267 
1268 	/* FORCESSL (0|1) */
1269 	if (!strcmp(arg[0], "FORCESSL")) {
1270 		forcessl = atoi(arg[1]);
1271 		return 1;
1272 	}
1273 
1274 	/* using up to arg[2] below */
1275 	if (numargs < 3)
1276 		return 0;
1277 
1278 	/* NOTIFYMSG <notify type> <replacement message> */
1279 	if (!strcmp(arg[0], "NOTIFYMSG")) {
1280 		set_notifymsg(arg[1], arg[2]);
1281 		return 1;
1282 	}
1283 
1284 	/* NOTIFYFLAG <notify type> <flags> */
1285 	if (!strcmp(arg[0], "NOTIFYFLAG")) {
1286 		set_notifyflag(arg[1], arg[2]);
1287 		return 1;
1288 	}
1289 
1290 	/* CERTIDENT <name> <passwd> */
1291 	if (!strcmp(arg[0], "CERTIDENT")) {
1292 		free(certname);
1293 		certname = xstrdup(arg[1]);
1294 		free(certpasswd);
1295 		certpasswd = xstrdup(arg[2]);
1296 		return 1;
1297 	}
1298 
1299 	/* using up to arg[4] below */
1300 	if (numargs < 5)
1301 		return 0;
1302 
1303 	/* CERTHOST <hostname> <certname> (0|1) (0|1) */
1304 	if (!strcmp(arg[0], "CERTHOST")) {
1305 		upscli_add_host_cert(arg[1], arg[2], atoi(arg[3]), atoi(arg[4]));
1306 		return 1;
1307 	}
1308 
1309 	if (!strcmp(arg[0], "MONITOR")) {
1310 
1311 		/* original style: no username (only 5 args) */
1312 		if (numargs == 5) {
1313 			upslogx(LOG_ERR, "Unable to use old-style MONITOR line without a username");
1314 			upslogx(LOG_ERR, "Convert it and add a username to upsd.users - see the documentation");
1315 
1316 			fatalx(EXIT_FAILURE, "Fatal error: unusable configuration");
1317 		}
1318 
1319 		/* <sys> <pwrval> <user> <pw> ("primary"|"master" | "secondary"|"slave") */
1320 		addups(reload_flag, arg[1], arg[2], arg[3], arg[4], arg[5]);
1321 		return 1;
1322 	}
1323 
1324 	/* didn't parse it at all */
1325 	return 0;
1326 }
1327 
1328 /* called for fatal errors in parseconf like malloc failures */
upsmon_err(const char * errmsg)1329 static void upsmon_err(const char *errmsg)
1330 {
1331 	upslogx(LOG_ERR, "Fatal error in parseconf(%s): %s", configfile, errmsg);
1332 }
1333 
loadconfig(void)1334 static void loadconfig(void)
1335 {
1336 	PCONF_CTX_t	ctx;
1337 
1338 	pconf_init(&ctx, upsmon_err);
1339 
1340 	if (!pconf_file_begin(&ctx, configfile)) {
1341 		pconf_finish(&ctx);
1342 
1343 		if (reload_flag == 1) {
1344 			upslog_with_errno(LOG_ERR, "Reload failed: %s", ctx.errmsg);
1345 			return;
1346 		}
1347 
1348 		fatalx(EXIT_FAILURE, "%s", ctx.errmsg);
1349 	}
1350 
1351 	while (pconf_file_next(&ctx)) {
1352 		if (pconf_parse_error(&ctx)) {
1353 			upslogx(LOG_ERR, "Parse error: %s:%d: %s",
1354 				configfile, ctx.linenum, ctx.errmsg);
1355 			continue;
1356 		}
1357 
1358 		if (ctx.numargs < 1)
1359 			continue;
1360 
1361 		if (!parse_conf_arg(ctx.numargs, ctx.arglist)) {
1362 			unsigned int	i;
1363 			char	errmsg[SMALLBUF];
1364 
1365 			snprintf(errmsg, sizeof(errmsg),
1366 				"%s line %d: invalid directive",
1367 				configfile, ctx.linenum);
1368 
1369 			for (i = 0; i < ctx.numargs; i++)
1370 				snprintfcat(errmsg, sizeof(errmsg), " %s",
1371 					ctx.arglist[i]);
1372 
1373 			upslogx(LOG_WARNING, "%s", errmsg);
1374 		}
1375 	}
1376 
1377 	pconf_finish(&ctx);
1378 }
1379 
1380 /* SIGPIPE handler */
sigpipe(int sig)1381 static void sigpipe(int sig)
1382 {
1383 	upsdebugx(1, "SIGPIPE: dazed and confused, but continuing after signal %i...", sig);
1384 }
1385 
1386 /* SIGQUIT, SIGTERM handler */
set_exit_flag(int sig)1387 static void set_exit_flag(int sig)
1388 {
1389 	exit_flag = sig;
1390 }
1391 
ups_free(utype_t * ups)1392 static void ups_free(utype_t *ups)
1393 {
1394 	free(ups->sys);
1395 	free(ups->upsname);
1396 	free(ups->hostname);
1397 	free(ups->un);
1398 	free(ups->pw);
1399 	free(ups);
1400 }
1401 
upsmon_cleanup(void)1402 static void upsmon_cleanup(void)
1403 {
1404 	int	i;
1405 	utype_t	*utmp, *unext;
1406 
1407 	/* close all fds */
1408 	utmp = firstups;
1409 
1410 	while (utmp) {
1411 		unext = utmp->next;
1412 
1413 		drop_connection(utmp);
1414 		ups_free(utmp);
1415 
1416 		utmp = unext;
1417 	}
1418 
1419 	free(run_as_user);
1420 	free(shutdowncmd);
1421 	free(notifycmd);
1422 	free(powerdownflag);
1423 
1424 	for (i = 0; notifylist[i].name != NULL; i++) {
1425 		free(notifylist[i].msg);
1426 	}
1427 
1428 	upscli_cleanup();
1429 }
1430 
user_fsd(int sig)1431 static void user_fsd(int sig)
1432 {
1433 	upslogx(LOG_INFO, "Signal %d: User requested FSD", sig);
1434 	userfsd = 1;
1435 }
1436 
set_reload_flag(int sig)1437 static void set_reload_flag(int sig)
1438 {
1439 	NUT_UNUSED_VARIABLE(sig);
1440 
1441 	reload_flag = 1;
1442 }
1443 
1444 /* handler for alarm when getupsvarfd times out */
read_timeout(int sig)1445 static void read_timeout(int sig)
1446 {
1447 	NUT_UNUSED_VARIABLE(sig);
1448 
1449 	/* don't do anything here, just return */
1450 }
1451 
1452 /* install handlers for a few signals */
setup_signals(void)1453 static void setup_signals(void)
1454 {
1455 	sigemptyset(&nut_upsmon_sigmask);
1456 	sa.sa_mask = nut_upsmon_sigmask;
1457 	sa.sa_flags = 0;
1458 
1459 	sa.sa_handler = sigpipe;
1460 	sigaction(SIGPIPE, &sa, NULL);
1461 
1462 	sa.sa_handler = set_exit_flag;
1463 	sigaction(SIGINT, &sa, NULL);
1464 	sigaction(SIGQUIT, &sa, NULL);
1465 	sigaction(SIGTERM, &sa, NULL);
1466 
1467 	/* handle timeouts */
1468 
1469 	sa.sa_handler = read_timeout;
1470 	sigaction(SIGALRM, &sa, NULL);
1471 
1472 	/* deal with the ones from userspace as well */
1473 
1474 	sa.sa_handler = user_fsd;
1475 	sigaction(SIGCMD_FSD, &sa, NULL);
1476 
1477 	sa.sa_handler = set_reload_flag;
1478 	sigaction(SIGCMD_RELOAD, &sa, NULL);
1479 }
1480 
1481 /* remember the last time the ups was not critical (OB + LB) */
update_crittimer(utype_t * ups)1482 static void update_crittimer(utype_t *ups)
1483 {
1484 	/* if !OB, !LB, or CAL, then it's not critical, so log the time */
1485 	if ((!flag_isset(ups->status, ST_ONBATT))  ||
1486 		(!flag_isset(ups->status, ST_LOWBATT)) ||
1487 		(flag_isset(ups->status, ST_CAL))) {
1488 
1489 		time(&ups->lastnoncrit);
1490 		return;
1491 	}
1492 
1493 	/* fallthrough: let the timer age */
1494 }
1495 
1496 /* handle connecting to upsd, plus get SSL going too if possible */
try_connect(utype_t * ups)1497 static int try_connect(utype_t *ups)
1498 {
1499 	int	flags = 0, ret;
1500 
1501 	upsdebugx(1, "Trying to connect to UPS [%s]", ups->sys);
1502 
1503 	clearflag(&ups->status, ST_CONNECTED);
1504 
1505 	/* force it if configured that way, just try it otherwise */
1506 	if (forcessl == 1)
1507 		flags |= UPSCLI_CONN_REQSSL;
1508 	else
1509 		flags |= UPSCLI_CONN_TRYSSL;
1510 
1511 	if (opt_af == AF_INET)
1512 		flags |= UPSCLI_CONN_INET;
1513 
1514 	if (opt_af == AF_INET6)
1515 		flags |= UPSCLI_CONN_INET6;
1516 
1517 	if (!certpath) {
1518 		if (certverify == 1) {
1519 			upslogx(LOG_ERR, "Configuration error: "
1520 				"CERTVERIFY is set, but CERTPATH isn't");
1521 			upslogx(LOG_ERR, "UPS [%s]: Connection impossible, "
1522 				"dropping link", ups->sys);
1523 
1524 			ups_is_gone(ups);
1525 			drop_connection(ups);
1526 
1527 			return 0;	/* failed */
1528 		}
1529 	}
1530 
1531 	if (certverify == 1) {
1532 		flags |= UPSCLI_CONN_CERTVERIF;
1533 	}
1534 
1535 	ret = upscli_connect(&ups->conn, ups->hostname, ups->port, flags);
1536 
1537 	if (ret < 0) {
1538 		upslogx(LOG_ERR, "UPS [%s]: connect failed: %s",
1539 			ups->sys, upscli_strerror(&ups->conn));
1540 		ups_is_gone(ups);
1541 		return 0;
1542 	}
1543 
1544 	/* we're definitely connected now */
1545 	setflag(&ups->status, ST_CONNECTED);
1546 
1547 	/* prevent connection leaking to NOTIFYCMD */
1548 	fcntl(upscli_fd(&ups->conn), F_SETFD, FD_CLOEXEC);
1549 
1550 	/* now try to authenticate to upsd */
1551 
1552 	ret = do_upsd_auth(ups);
1553 
1554 	if (ret == 1)
1555 		return 1;		/* everything is happy */
1556 
1557 	/* something failed in the auth so we may not be completely logged in */
1558 
1559 	/* FUTURE: do something beyond the error msgs from do_upsd_auth? */
1560 
1561 	return 0;
1562 }
1563 
1564 /* deal with the contents of STATUS or ups.status for this ups */
parse_status(utype_t * ups,char * status)1565 static void parse_status(utype_t *ups, char *status)
1566 {
1567 	char	*statword, *ptr;
1568 
1569 	clear_alarm();
1570 
1571 	upsdebugx(2, "%s: [%s]", __func__, status);
1572 
1573 	/* empty response is the same as a dead ups */
1574 	if (status == NULL || status[0] == '\0') {
1575 		ups_is_gone(ups);
1576 		return;
1577 	}
1578 
1579 	ups_is_alive(ups);
1580 
1581 	/* clear these out early if they disappear */
1582 	if (!strstr(status, "LB"))
1583 		clearflag(&ups->status, ST_LOWBATT);
1584 	if (!strstr(status, "FSD"))
1585 		clearflag(&ups->status, ST_FSD);
1586 
1587 	statword = status;
1588 
1589 	/* split up the status words and parse each one separately */
1590 	while (statword != NULL) {
1591 		ptr = strchr(statword, ' ');
1592 		if (ptr)
1593 			*ptr++ = '\0';
1594 
1595 		upsdebugx(3, "parsing: [%s]", statword);
1596 
1597 		if (!strncasecmp(statword, "OL", 2))
1598 			ups_on_line(ups);
1599 		if (!strncasecmp(statword, "OB", 2))
1600 			ups_on_batt(ups);
1601 		if (!strncasecmp(statword, "LB", 2))
1602 			ups_low_batt(ups);
1603 		if (!strncasecmp(statword, "RB", 2))
1604 			upsreplbatt(ups);
1605 		if (!strncasecmp(statword, "CAL", 3))
1606 			ups_cal(ups);
1607 
1608 		/* do it last to override any possible OL */
1609 		if (!strncasecmp(statword, "FSD", 3))
1610 			ups_fsd(ups);
1611 
1612 		update_crittimer(ups);
1613 
1614 		statword = ptr;
1615 	}
1616 }
1617 
1618 /* see what the status of the UPS is and handle any changes */
pollups(utype_t * ups)1619 static void pollups(utype_t *ups)
1620 {
1621 	char	status[SMALLBUF];
1622 
1623 	/* try a reconnect here */
1624 	if (!flag_isset(ups->status, ST_CONNECTED))
1625 		if (try_connect(ups) != 1)
1626 			return;
1627 
1628 	if (upscli_ssl(&ups->conn) == 1)
1629 		upsdebugx(2, "%s: %s [SSL]", __func__, ups->sys);
1630 	else
1631 		upsdebugx(2, "%s: %s", __func__, ups->sys);
1632 
1633 	set_alarm();
1634 
1635 	if (get_var(ups, "status", status, sizeof(status)) == 0) {
1636 		clear_alarm();
1637 		parse_status(ups, status);
1638 		return;
1639 	}
1640 
1641 	/* fallthrough: no communications */
1642 	clear_alarm();
1643 
1644 	/* try to make some of these a little friendlier */
1645 
1646 	switch (upscli_upserror(&ups->conn)) {
1647 
1648 		case UPSCLI_ERR_UNKNOWNUPS:
1649 			upslogx(LOG_ERR, "Poll UPS [%s] failed - [%s] "
1650 			"does not exist on server %s",
1651 			ups->sys, ups->upsname,	ups->hostname);
1652 
1653 			break;
1654 		default:
1655 			upslogx(LOG_ERR, "Poll UPS [%s] failed - %s",
1656 				ups->sys, upscli_strerror(&ups->conn));
1657 			break;
1658 	}
1659 
1660 	/* throw COMMBAD or NOCOMM as conditions may warrant */
1661 	ups_is_gone(ups);
1662 
1663 	/* if upsclient lost the connection, clean up things on our side */
1664 	if (upscli_fd(&ups->conn) == -1) {
1665 		drop_connection(ups);
1666 		return;
1667 	}
1668 }
1669 
1670 /* see if the powerdownflag file is there and proper */
pdflag_status(void)1671 static int pdflag_status(void)
1672 {
1673 	FILE	*pdf;
1674 	char	buf[SMALLBUF];
1675 
1676 	if (!powerdownflag)
1677 		return 0;	/* unusable */
1678 
1679 	pdf = fopen(powerdownflag, "r");
1680 
1681 	if (pdf == NULL)
1682 		return 0;	/* not there */
1683 
1684 	/* if it exists, see if it has the right text in it */
1685 
1686 	if (fgets(buf, sizeof(buf), pdf) == NULL) {
1687 		upslog_with_errno(LOG_ERR, "'%s' exists, but we can't read from it", powerdownflag);
1688 	}
1689 	fclose(pdf);
1690 
1691 	/* reasoning: say upsmon.conf is world-writable (!) and some nasty
1692 	 * user puts something "important" as the power flag file.  This
1693 	 * keeps upsmon from utterly trashing it when starting up or powering
1694 	 * down at the expense of not shutting down the UPS.
1695 	 *
1696 	 * solution: don't let mere mortals edit that configuration file.
1697 	 */
1698 
1699 	if (!strncmp(buf, SDMAGIC, strlen(SDMAGIC)))
1700 		return 1;	/* exists and looks good */
1701 
1702 	return -1;	/* error: something else is in there */
1703 }
1704 
1705 /* only remove the flag file if it's actually from us */
clear_pdflag(void)1706 static void clear_pdflag(void)
1707 {
1708 	int	ret;
1709 
1710 	ret = pdflag_status();
1711 
1712 	if (ret == -1)  {
1713 		upslogx(LOG_ERR, "POWERDOWNFLAG (%s) does not contain"
1714 			"the upsmon magic string - disabling!", powerdownflag);
1715 		powerdownflag = NULL;
1716 		return;
1717 	}
1718 
1719 	/* it's from us, so we can remove it */
1720 	if (ret == 1)
1721 		unlink(powerdownflag);
1722 }
1723 
1724 /* exit with success only if it exists and is proper */
check_pdflag(void)1725 static int check_pdflag(void)
1726 {
1727 	int	ret;
1728 
1729 	ret = pdflag_status();
1730 
1731 	if (ret == -1) {
1732 		upslogx(LOG_ERR, "POWERDOWNFLAG (%s) does not contain "
1733 			"the upsmon magic string", powerdownflag);
1734 		return EXIT_FAILURE;
1735 	}
1736 
1737 	if (ret == 0) {
1738 		/* not there - this is not a shutdown event */
1739 		upslogx(LOG_ERR, "Power down flag is not set");
1740 		return EXIT_FAILURE;
1741 	}
1742 
1743 	if (ret != 1) {
1744 		upslogx(LOG_ERR, "Programming error: pdflag_status returned %d",
1745 			ret);
1746 		return EXIT_FAILURE;
1747 	}
1748 
1749 	/* only thing left - must be time for a shutdown */
1750 	upslogx(LOG_INFO, "Power down flag is set");
1751 	return EXIT_SUCCESS;
1752 }
1753 
1754 static void help(const char *arg_progname)
1755 	__attribute__((noreturn));
1756 
help(const char * arg_progname)1757 static void help(const char *arg_progname)
1758 {
1759 	printf("Monitors UPS servers and may initiate shutdown if necessary.\n\n");
1760 
1761 	printf("usage: %s [OPTIONS]\n\n", arg_progname);
1762 	printf("  -c <cmd>	send command to running process\n");
1763 	printf("		commands:\n");
1764 	printf("		 - fsd: shutdown all primary-mode UPSes (use with caution)\n");
1765 	printf("		 - reload: reread configuration\n");
1766 	printf("		 - stop: stop monitoring and exit\n");
1767 	printf("  -D		raise debugging level\n");
1768 	printf("  -h		display this help\n");
1769 	printf("  -K		checks POWERDOWNFLAG, sets exit code to 0 if set\n");
1770 	printf("  -p		always run privileged (disable privileged parent)\n");
1771 	printf("  -u <user>	run child as user <user> (ignored when using -p)\n");
1772 	printf("  -4		IPv4 only\n");
1773 	printf("  -6		IPv6 only\n");
1774 
1775 	exit(EXIT_SUCCESS);
1776 }
1777 
1778 static void runparent(int fd)
1779 	__attribute__((noreturn));
1780 
runparent(int fd)1781 static void runparent(int fd)
1782 {
1783 	ssize_t	ret;
1784 	int	sret;
1785 	char	ch;
1786 
1787 	/* handling signals is the child's job */
1788 #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_STRICT_PROTOTYPES)
1789 # pragma GCC diagnostic push
1790 # pragma GCC diagnostic ignored "-Wstrict-prototypes"
1791 #endif
1792 	signal(SIGHUP, SIG_IGN);
1793 	signal(SIGUSR1, SIG_IGN);
1794 	signal(SIGUSR2, SIG_IGN);
1795 #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_STRICT_PROTOTYPES)
1796 # pragma GCC diagnostic pop
1797 #endif
1798 
1799 	ret = read(fd, &ch, 1);
1800 
1801 	if (ret < 1) {
1802 		if (errno == ENOENT)
1803 			fatalx(EXIT_FAILURE, "upsmon parent: exiting (child exited)");
1804 
1805 		fatal_with_errno(EXIT_FAILURE, "upsmon parent: read");
1806 	}
1807 
1808 	if (ch != 1)
1809 		fatalx(EXIT_FAILURE, "upsmon parent: got bogus pipe command %c", ch);
1810 
1811 	/* have to do this here - child is unprivileged */
1812 	set_pdflag();
1813 
1814 	sret = system(shutdowncmd);
1815 
1816 	if (sret != 0)
1817 		upslogx(LOG_ERR, "parent: Unable to call shutdown command: %s",
1818 			shutdowncmd);
1819 
1820 	close(fd);
1821 	exit(EXIT_SUCCESS);
1822 }
1823 
1824 /* fire up the split parent/child scheme */
start_pipe(void)1825 static void start_pipe(void)
1826 {
1827 	int	ret;
1828 
1829 	ret = pipe(pipefd);
1830 
1831 	if (ret)
1832 		fatal_with_errno(EXIT_FAILURE, "pipe creation failed");
1833 
1834 	ret = fork();
1835 
1836 	if (ret < 0)
1837 		fatal_with_errno(EXIT_FAILURE, "fork failed");
1838 
1839 	/* start the privileged parent */
1840 	if (ret != 0) {
1841 		close(pipefd[1]);
1842 		runparent(pipefd[0]);
1843 
1844 #ifndef HAVE___ATTRIBUTE__NORETURN
1845 		exit(EXIT_FAILURE);	/* NOTREACHED */
1846 #endif
1847 	}
1848 
1849 	close(pipefd[0]);
1850 
1851 	/* prevent pipe leaking to NOTIFYCMD */
1852 	fcntl(pipefd[1], F_SETFD, FD_CLOEXEC);
1853 }
1854 
delete_ups(utype_t * target)1855 static void delete_ups(utype_t *target)
1856 {
1857 	utype_t	*ptr, *last;
1858 
1859 	if (!target)
1860 		return;
1861 
1862 	ptr = last = firstups;
1863 
1864 	while (ptr) {
1865 		if (ptr == target) {
1866 			upslogx(LOG_NOTICE, "No longer monitoring UPS [%s]",
1867 				target->sys);
1868 
1869 			/* disconnect cleanly */
1870 			drop_connection(ptr);
1871 
1872 			/* about to delete the first ups? */
1873 			if (ptr == last)
1874 				firstups = ptr->next;
1875 			else
1876 				last->next = ptr->next;
1877 
1878 			/* release memory */
1879 
1880 			ups_free(ptr);
1881 
1882 			return;
1883 		}
1884 
1885 		last = ptr;
1886 		ptr = ptr->next;
1887 	}
1888 
1889 	/* shouldn't happen */
1890 	upslogx(LOG_ERR, "delete_ups: UPS not found");
1891 }
1892 
1893 /* see if we can open a file */
check_file(const char * fn)1894 static int check_file(const char *fn)
1895 {
1896 	FILE	*f;
1897 
1898 	f = fopen(fn, "r");
1899 
1900 	if (!f) {
1901 		upslog_with_errno(LOG_ERR, "Reload failed: can't open %s", fn);
1902 		return 0;	/* failed */
1903 	}
1904 
1905 	fclose(f);
1906 	return 1;	/* OK */
1907 }
1908 
reload_conf(void)1909 static void reload_conf(void)
1910 {
1911 	utype_t	*tmp, *next;
1912 
1913 	upslogx(LOG_INFO, "Reloading configuration");
1914 
1915 	/* sanity check */
1916 	if (!check_file(configfile)) {
1917 		reload_flag = 0;
1918 		return;
1919 	}
1920 
1921 	/* flip through ups list, clear retain value */
1922 	tmp = firstups;
1923 
1924 	while (tmp) {
1925 		tmp->retain = 0;
1926 		tmp = tmp->next;
1927 	}
1928 
1929 	/* reset paranoia checker */
1930 	totalpv = 0;
1931 
1932 	/* reread upsmon.conf */
1933 	loadconfig();
1934 
1935 	/* go through the utype_t struct again */
1936 	tmp = firstups;
1937 
1938 	while (tmp) {
1939 		next = tmp->next;
1940 
1941 		/* !retain means it wasn't in the .conf this time around */
1942 		if (tmp->retain == 0)
1943 			delete_ups(tmp);
1944 
1945 		tmp = next;
1946 	}
1947 
1948 	/* see if the user just blew off a foot */
1949 	if (totalpv < minsupplies) {
1950 		upslogx(LOG_CRIT, "Fatal error: total power value (%d) less "
1951 			"than MINSUPPLIES (%d)", totalpv, minsupplies);
1952 
1953 		fatalx(EXIT_FAILURE, "Impossible power configuration, unable to continue");
1954 	}
1955 
1956 	/* finally clear the flag */
1957 	reload_flag = 0;
1958 }
1959 
1960 /* make sure the parent is still alive */
check_parent(void)1961 static void check_parent(void)
1962 {
1963 	int	ret;
1964 	fd_set	rfds;
1965 	struct	timeval	tv;
1966 	time_t	now;
1967 	static	time_t	lastwarn = 0;
1968 
1969 	FD_ZERO(&rfds);
1970 	FD_SET(pipefd[1], &rfds);
1971 
1972 	tv.tv_sec = 0;
1973 	tv.tv_usec = 0;
1974 
1975 	ret = select(pipefd[1] + 1, &rfds, NULL, NULL, &tv);
1976 
1977 	if (ret == 0)
1978 		return;
1979 
1980 	/* this should never happen, but we MUST KNOW if it ever does */
1981 
1982 	time(&now);
1983 
1984 	/* complain every 2 minutes */
1985 	if ((now - lastwarn) < 120)
1986 		return;
1987 
1988 	lastwarn = now;
1989 	do_notify(NULL, NOTIFY_NOPARENT);
1990 
1991 	/* also do this in case the notifier isn't being effective */
1992 	upslogx(LOG_ALERT, "Parent died - shutdown impossible");
1993 }
1994 
main(int argc,char * argv[])1995 int main(int argc, char *argv[])
1996 {
1997 	const char	*prog = xbasename(argv[0]);
1998 	int	i, cmd = 0, checking_flag = 0;
1999 
2000 	printf("Network UPS Tools %s %s\n", prog, UPS_VERSION);
2001 
2002 	/* if no configuration file is specified on the command line, use default */
2003 	configfile = xmalloc(SMALLBUF);
2004 	snprintf(configfile, SMALLBUF, "%s/upsmon.conf", confpath());
2005 	configfile = xrealloc(configfile, strlen(configfile) + 1);
2006 
2007 	run_as_user = xstrdup(RUN_AS_USER);
2008 
2009 	while ((i = getopt(argc, argv, "+Dhic:f:pu:VK46")) != -1) {
2010 		switch (i) {
2011 			case 'c':
2012 				if (!strncmp(optarg, "fsd", strlen(optarg)))
2013 					cmd = SIGCMD_FSD;
2014 				if (!strncmp(optarg, "stop", strlen(optarg)))
2015 					cmd = SIGCMD_STOP;
2016 				if (!strncmp(optarg, "reload", strlen(optarg)))
2017 					cmd = SIGCMD_RELOAD;
2018 
2019 				/* bad command name given */
2020 				if (cmd == 0)
2021 					help(argv[0]);
2022 				break;
2023 			case 'D':
2024 				nut_debug_level++;
2025 				break;
2026 			case 'f':
2027 				free(configfile);
2028 				configfile = xstrdup(optarg);
2029 				break;
2030 			case 'h':
2031 				help(argv[0]);
2032 #ifndef HAVE___ATTRIBUTE__NORETURN
2033 				break;
2034 #endif
2035 			case 'K':
2036 				checking_flag = 1;
2037 				break;
2038 			case 'p':
2039 				use_pipe = 0;
2040 				break;
2041 			case 'u':
2042 				free(run_as_user);
2043 				run_as_user = xstrdup(optarg);
2044 				break;
2045 			case 'V':
2046 				/* just show the banner */
2047 				exit(EXIT_SUCCESS);
2048 			case '4':
2049 				opt_af = AF_INET;
2050 				break;
2051 			case '6':
2052 				opt_af = AF_INET6;
2053 				break;
2054 			default:
2055 				help(argv[0]);
2056 #ifndef HAVE___ATTRIBUTE__NORETURN
2057 				break;
2058 #endif
2059 		}
2060 	}
2061 
2062 	if (cmd) {
2063 		sendsignal(prog, cmd);
2064 		exit(EXIT_SUCCESS);
2065 	}
2066 
2067 	/* otherwise, we are being asked to start.
2068 	 * so check if a previous instance is running by sending signal '0'
2069 	 * (Ie 'kill <pid> 0') */
2070 	if (sendsignal(prog, 0) == 0) {
2071 		printf("Fatal error: A previous upsmon instance is already running!\n");
2072 		printf("Either stop the previous instance first, or use the 'reload' command.\n");
2073 		exit(EXIT_FAILURE);
2074 	}
2075 
2076 	argc -= optind;
2077 	argv += optind;
2078 
2079 	open_syslog(prog);
2080 
2081 	loadconfig();
2082 
2083 	if (checking_flag)
2084 		exit(check_pdflag());
2085 
2086 	if (shutdowncmd == NULL)
2087 		printf("Warning: no shutdown command defined!\n");
2088 
2089 	/* we may need to get rid of a flag from a previous shutdown */
2090 	if (powerdownflag != NULL)
2091 		clear_pdflag();
2092 	/* FIXME (else): POWERDOWNFLAG is not defined!!
2093 	 * => fallback to a default value */
2094 
2095 	if (totalpv < minsupplies) {
2096 		printf("\nFatal error: insufficient power configured!\n\n");
2097 
2098 		printf("Sum of power values........: %d\n", totalpv);
2099 		printf("Minimum value (MINSUPPLIES): %d\n", minsupplies);
2100 
2101 		printf("\nEdit your upsmon.conf and change the values.\n");
2102 		exit(EXIT_FAILURE);
2103 	}
2104 
2105 	if (nut_debug_level < 1) {
2106 		background();
2107 	} else {
2108 		upsdebugx(1, "debug level is '%d'", nut_debug_level);
2109 	}
2110 
2111 	/* only do the pipe stuff if the user hasn't disabled it */
2112 	if (use_pipe) {
2113 		struct passwd	*new_uid = get_user_pwent(run_as_user);
2114 
2115 		/* === root parent and unprivileged child split here === */
2116 		start_pipe();
2117 
2118 		/* write the pid file now, as we will soon lose root */
2119 		writepid(prog);
2120 
2121 		become_user(new_uid);
2122 	} else {
2123 		upslogx(LOG_INFO, "Warning: running as one big root process by request (upsmon -p)");
2124 
2125 		writepid(prog);
2126 	}
2127 
2128 	if (upscli_init(certverify, certpath, certname, certpasswd) < 0) {
2129 		exit(EXIT_FAILURE);
2130 	}
2131 
2132 	/* prep our signal handlers */
2133 	setup_signals();
2134 
2135 	/* reopen the log for the child process */
2136 	closelog();
2137 	open_syslog(prog);
2138 
2139 	while (exit_flag == 0) {
2140 		utype_t	*ups;
2141 
2142 		/* check flags from signal handlers */
2143 		if (userfsd)
2144 			forceshutdown();
2145 
2146 		if (reload_flag)
2147 			reload_conf();
2148 
2149 		for (ups = firstups; ups != NULL; ups = ups->next)
2150 			pollups(ups);
2151 
2152 		recalc();
2153 
2154 		/* make sure the parent hasn't died */
2155 		if (use_pipe)
2156 			check_parent();
2157 
2158 		/* reap children that have exited */
2159 		waitpid(-1, NULL, WNOHANG);
2160 
2161 		sleep(sleepval);
2162 	}
2163 
2164 	upslogx(LOG_INFO, "Signal %d: exiting", exit_flag);
2165 	upsmon_cleanup();
2166 
2167 	exit(EXIT_SUCCESS);
2168 }
2169