1 /* main.c - Network UPS Tools driver core
2 
3    Copyright (C)
4    1999			Russell Kroll <rkroll@exploits.org>
5    2005 - 2017	Arnaud Quette <arnaud.quette@free.fr>
6    2017 		Eaton (author: Emilien Kia <EmilienKia@Eaton.com>)
7 
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12 
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17 
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22 
23 #include "common.h"
24 #include "main.h"
25 #include "nut_stdint.h"
26 #include "dstate.h"
27 #include "attribute.h"
28 
29 /* data which may be useful to the drivers */
30 int		upsfd = -1;
31 char		*device_path = NULL;
32 const char	*progname = NULL, *upsname = NULL, *device_name = NULL;
33 
34 /* may be set by the driver to wake up while in dstate_poll_fds */
35 int	extrafd = -1;
36 
37 /* for ser_open */
38 int	do_lock_port = 1;
39 
40 /* for dstate->sock_connect, default to asynchronous */
41 int	do_synchronous = 0;
42 
43 /* for detecting -a values that don't match anything */
44 static	int	upsname_found = 0;
45 
46 static vartab_t	*vartab_h = NULL;
47 
48 /* variables possibly set by the global part of ups.conf */
49 time_t	poll_interval = 2;
50 static char	*chroot_path = NULL, *user = NULL;
51 
52 /* signal handling */
53 int	exit_flag = 0;
54 
55 /* everything else */
56 static char	*pidfn = NULL;
57 static int	dump_data = 0; /* Store the update_count requested */
58 
59 /* print the driver banner */
upsdrv_banner(void)60 void upsdrv_banner (void)
61 {
62 	int i;
63 
64 	printf("Network UPS Tools - %s %s (%s)\n", upsdrv_info.name, upsdrv_info.version, UPS_VERSION);
65 
66 	/* process sub driver(s) information */
67 	for (i = 0; upsdrv_info.subdrv_info[i]; i++) {
68 
69 		if (!upsdrv_info.subdrv_info[i]->name) {
70 			continue;
71 		}
72 
73 		if (!upsdrv_info.subdrv_info[i]->version) {
74 			continue;
75 		}
76 
77 		printf("%s %s\n", upsdrv_info.subdrv_info[i]->name,
78 			upsdrv_info.subdrv_info[i]->version);
79 	}
80 }
81 
82 /* power down the attached load immediately */
83 static void forceshutdown(void)
84 	__attribute__((noreturn));
85 
forceshutdown(void)86 static void forceshutdown(void)
87 {
88 	upslogx(LOG_NOTICE, "Initiating UPS shutdown");
89 
90 	/* the driver must not block in this function */
91 	upsdrv_shutdown();
92 	exit(EXIT_SUCCESS);
93 }
94 
95 /* this function only prints the usage message; it does not call exit() */
help_msg(void)96 static void help_msg(void)
97 {
98 	vartab_t	*tmp;
99 
100 	printf("\nusage: %s (-a <id>|-s <id>) [OPTIONS]\n", progname);
101 
102 	printf("  -a <id>        - autoconfig using ups.conf section <id>\n");
103 	printf("                 - note: -x after -a overrides ups.conf settings\n\n");
104 
105 	printf("  -s <id>        - configure directly from cmd line arguments\n");
106 	printf("                 - note: must specify all driver parameters with successive -x\n");
107 	printf("                 - note: at least 'port' variable should be set\n");
108 	printf("                 - note: to explore the current values on a device from an\n");
109 	printf("                   unprivileged user account (with sufficient media access in\n");
110 	printf("                   the OS - e.g. to query networked devices), you can specify\n");
111 	printf("                   '-d 1' argument and `export NUT_STATEPATH=/tmp` beforehand\n\n");
112 
113 	printf("  -V             - print version, then exit\n");
114 	printf("  -L             - print parseable list of driver variables\n");
115 	printf("  -D             - raise debugging level\n");
116 	printf("  -d <count>     - dump data to stdout after 'count' updates loop and exit\n");
117 	printf("  -q             - raise log level threshold\n");
118 	printf("  -h             - display this help\n");
119 	printf("  -k             - force shutdown\n");
120 	printf("  -i <int>       - poll interval\n");
121 	printf("  -r <dir>       - chroot to <dir>\n");
122 	printf("  -u <user>      - switch to <user> (if started as root)\n");
123 	printf("  -x <var>=<val> - set driver variable <var> to <val>\n");
124 	printf("                 - example: -x cable=940-0095B\n\n");
125 
126 	if (vartab_h) {
127 		tmp = vartab_h;
128 
129 		printf("Acceptable values for -x or ups.conf in this driver:\n\n");
130 
131 		while (tmp) {
132 			if (tmp->vartype == VAR_VALUE)
133 				printf("%40s : -x %s=<value>\n",
134 					tmp->desc, tmp->var);
135 			else
136 				printf("%40s : -x %s\n", tmp->desc, tmp->var);
137 			tmp = tmp->next;
138 		}
139 	}
140 
141 	upsdrv_help();
142 }
143 
144 /* store these in dstate as driver.(parameter|flag) */
dparam_setinfo(const char * var,const char * val)145 static void dparam_setinfo(const char *var, const char *val)
146 {
147 	char	vtmp[SMALLBUF];
148 
149 	/* store these in dstate for debugging and other help */
150 	if (val) {
151 		snprintf(vtmp, sizeof(vtmp), "driver.parameter.%s", var);
152 		dstate_setinfo(vtmp, "%s", val);
153 		return;
154 	}
155 
156 	/* no value = flag */
157 
158 	snprintf(vtmp, sizeof(vtmp), "driver.flag.%s", var);
159 	dstate_setinfo(vtmp, "enabled");
160 }
161 
162 /* cram var [= <val>] data into storage */
storeval(const char * var,char * val)163 static void storeval(const char *var, char *val)
164 {
165 	vartab_t	*tmp, *last;
166 
167 	if (!strncasecmp(var, "override.", 9)) {
168 		dstate_setinfo(var+9, "%s", val);
169 		dstate_setflags(var+9, ST_FLAG_IMMUTABLE);
170 		return;
171 	}
172 
173 	if (!strncasecmp(var, "default.", 8)) {
174 		dstate_setinfo(var+8, "%s", val);
175 		return;
176 	}
177 
178 	tmp = last = vartab_h;
179 
180 	while (tmp) {
181 		last = tmp;
182 
183 		/* sanity check */
184 		if (!tmp->var) {
185 			tmp = tmp->next;
186 			continue;
187 		}
188 
189 		/* later definitions overwrite earlier ones */
190 		if (!strcasecmp(tmp->var, var)) {
191 			free(tmp->val);
192 
193 			if (val)
194 				tmp->val = xstrdup(val);
195 
196 			/* don't keep things like SNMP community strings */
197 			if ((tmp->vartype & VAR_SENSITIVE) == 0)
198 				dparam_setinfo(var, val);
199 
200 			tmp->found = 1;
201 			return;
202 		}
203 
204 		tmp = tmp->next;
205 	}
206 
207 	/* try to help them out */
208 	printf("\nFatal error: '%s' is not a valid %s for this driver.\n", var,
209 		val ? "variable name" : "flag");
210 	printf("\n");
211 	printf("Look in the man page or call this driver with -h for a list of\n");
212 	printf("valid variable names and flags.\n");
213 
214 	exit(EXIT_SUCCESS);
215 }
216 
217 /* retrieve the value of variable <var> if possible */
getval(const char * var)218 char *getval(const char *var)
219 {
220 	vartab_t	*tmp = vartab_h;
221 
222 	while (tmp) {
223 		if (!strcasecmp(tmp->var, var))
224 			return(tmp->val);
225 		tmp = tmp->next;
226 	}
227 
228 	return NULL;
229 }
230 
231 /* see if <var> has been defined, even if no value has been given to it */
testvar(const char * var)232 int testvar(const char *var)
233 {
234 	vartab_t	*tmp = vartab_h;
235 
236 	while (tmp) {
237 		if (!strcasecmp(tmp->var, var))
238 			return tmp->found;
239 		tmp = tmp->next;
240 	}
241 
242 	return 0;	/* not found */
243 }
244 
245 /* callback from driver - create the table for -x/conf entries */
addvar(int vartype,const char * name,const char * desc)246 void addvar(int vartype, const char *name, const char *desc)
247 {
248 	vartab_t	*tmp, *last;
249 
250 	tmp = last = vartab_h;
251 
252 	while (tmp) {
253 		last = tmp;
254 		tmp = tmp->next;
255 	}
256 
257 	tmp = xmalloc(sizeof(vartab_t));
258 
259 	tmp->vartype = vartype;
260 	tmp->var = xstrdup(name);
261 	tmp->val = NULL;
262 	tmp->desc = xstrdup(desc);
263 	tmp->found = 0;
264 	tmp->next = NULL;
265 
266 	if (last)
267 		last->next = tmp;
268 	else
269 		vartab_h = tmp;
270 }
271 
272 /* handle -x / ups.conf config details that are for this part of the code */
main_arg(char * var,char * val)273 static int main_arg(char *var, char *val)
274 {
275 	/* flags for main */
276 
277 	if (!strcmp(var, "nolock")) {
278 		do_lock_port = 0;
279 		dstate_setinfo("driver.flag.nolock", "enabled");
280 		return 1;	/* handled */
281 	}
282 
283 	if (!strcmp(var, "ignorelb")) {
284 		dstate_setinfo("driver.flag.ignorelb", "enabled");
285 		return 1;	/* handled */
286 	}
287 
288 	/* any other flags are for the driver code */
289 	if (!val)
290 		return 0;
291 
292 	/* variables for main: port */
293 
294 	if (!strcmp(var, "port")) {
295 		device_path = xstrdup(val);
296 		device_name = xbasename(device_path);
297 		dstate_setinfo("driver.parameter.port", "%s", val);
298 		return 1;	/* handled */
299 	}
300 
301 	if (!strcmp(var, "sddelay")) {
302 		upslogx(LOG_INFO, "Obsolete value sddelay found in ups.conf");
303 		return 1;	/* handled */
304 	}
305 
306 	/* allow per-driver overrides of the global setting */
307 	if (!strcmp(var, "synchronous")) {
308 		if (!strncmp(val, "yes", 3))
309 			do_synchronous = 1;
310 		else
311 			do_synchronous = 0;
312 
313 		return 1;	/* handled */
314 	}
315 
316 	/* only for upsdrvctl - ignored here */
317 	if (!strcmp(var, "sdorder"))
318 		return 1;	/* handled */
319 
320 	/* only for upsd (at the moment) - ignored here */
321 	if (!strcmp(var, "desc"))
322 		return 1;	/* handled */
323 
324 	return 0;	/* unhandled, pass it through to the driver */
325 }
326 
do_global_args(const char * var,const char * val)327 static void do_global_args(const char *var, const char *val)
328 {
329 	if (!strcmp(var, "pollinterval")) {
330 		int ipv = atoi(val);
331 		if (ipv > 0) {
332 			poll_interval = (time_t)ipv;
333 		} else {
334 			fatalx(EXIT_FAILURE, "Error: invalid pollinterval: %d", ipv);
335 		}
336 		return;
337 	}
338 
339 	if (!strcmp(var, "chroot")) {
340 		free(chroot_path);
341 		chroot_path = xstrdup(val);
342 	}
343 
344 	if (!strcmp(var, "user")) {
345 		free(user);
346 		user = xstrdup(val);
347 	}
348 
349 	if (!strcmp(var, "synchronous")) {
350 		if (!strncmp(val, "yes", 3))
351 			do_synchronous = 1;
352 		else
353 			do_synchronous = 0;
354 	}
355 
356 
357 	/* unrecognized */
358 }
359 
do_upsconf_args(char * confupsname,char * var,char * val)360 void do_upsconf_args(char *confupsname, char *var, char *val)
361 {
362 	char	tmp[SMALLBUF];
363 
364 	/* handle global declarations */
365 	if (!confupsname) {
366 		do_global_args(var, val);
367 		return;
368 	}
369 
370 	/* no match = not for us */
371 	if (strcmp(confupsname, upsname) != 0)
372 		return;
373 
374 	upsname_found = 1;
375 
376 	if (main_arg(var, val))
377 		return;
378 
379 	/* flags (no =) now get passed to the driver-level stuff */
380 	if (!val) {
381 
382 		/* also store this, but it's a bit different */
383 		snprintf(tmp, sizeof(tmp), "driver.flag.%s", var);
384 		dstate_setinfo(tmp, "enabled");
385 
386 		storeval(var, NULL);
387 		return;
388 	}
389 
390 	/* don't let the user shoot themselves in the foot */
391 	if (!strcmp(var, "driver")) {
392 		if (strcmp(val, progname) != 0)
393 			fatalx(EXIT_FAILURE, "Error: UPS [%s] is for driver %s, but I'm %s!\n",
394 				confupsname, val, progname);
395 		return;
396 	}
397 
398 	/* allow per-driver overrides of the global setting */
399 	if (!strcmp(var, "pollinterval")) {
400 		int ipv = atoi(val);
401 		if (ipv > 0) {
402 			poll_interval = (time_t)ipv;
403 		} else {
404 			fatalx(EXIT_FAILURE, "Error: UPS [%s]: invalid pollinterval: %d",
405 				confupsname, ipv);
406 		}
407 		return;
408 	}
409 
410 	/* everything else must be for the driver */
411 	storeval(var, val);
412 }
413 
414 /* split -x foo=bar into 'foo' and 'bar' */
splitxarg(char * inbuf)415 static void splitxarg(char *inbuf)
416 {
417 	char	*eqptr, *val, *buf;
418 
419 	/* make our own copy - avoid changing argv */
420 	buf = xstrdup(inbuf);
421 
422 	eqptr = strchr(buf, '=');
423 
424 	if (!eqptr)
425 		val = NULL;
426 	else {
427 		*eqptr++ = '\0';
428 		val = eqptr;
429 	}
430 
431 	/* see if main handles this first */
432 	if (main_arg(buf, val))
433 		return;
434 
435 	/* otherwise store it for later */
436 	storeval(buf, val);
437 }
438 
439 /* dump the list from the vartable for external parsers */
listxarg(void)440 static void listxarg(void)
441 {
442 	vartab_t	*tmp;
443 
444 	tmp = vartab_h;
445 
446 	if (!tmp)
447 		return;
448 
449 	while (tmp) {
450 
451 		switch (tmp->vartype) {
452 			case VAR_VALUE: printf("VALUE"); break;
453 			case VAR_FLAG: printf("FLAG"); break;
454 			default: printf("UNKNOWN"); break;
455 		}
456 
457 		printf(" %s \"%s\"\n", tmp->var, tmp->desc);
458 
459 		tmp = tmp->next;
460 	}
461 }
462 
vartab_free(void)463 static void vartab_free(void)
464 {
465 	vartab_t	*tmp, *next;
466 
467 	tmp = vartab_h;
468 
469 	while (tmp) {
470 		next = tmp->next;
471 
472 		free(tmp->var);
473 		free(tmp->val);
474 		free(tmp->desc);
475 		free(tmp);
476 
477 		tmp = next;
478 	}
479 }
480 
exit_cleanup(void)481 static void exit_cleanup(void)
482 {
483 	free(chroot_path);
484 	free(device_path);
485 	free(user);
486 
487 	if (pidfn) {
488 		unlink(pidfn);
489 		free(pidfn);
490 	}
491 
492 	dstate_free();
493 	vartab_free();
494 }
495 
set_exit_flag(int sig)496 static void set_exit_flag(int sig)
497 {
498 	exit_flag = sig;
499 }
500 
setup_signals(void)501 static void setup_signals(void)
502 {
503 	struct sigaction	sa;
504 
505 	sigemptyset(&sa.sa_mask);
506 	sa.sa_flags = 0;
507 
508 	sa.sa_handler = set_exit_flag;
509 	sigaction(SIGTERM, &sa, NULL);
510 	sigaction(SIGINT, &sa, NULL);
511 	sigaction(SIGQUIT, &sa, NULL);
512 
513 #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_STRICT_PROTOTYPES)
514 # pragma GCC diagnostic push
515 # pragma GCC diagnostic ignored "-Wstrict-prototypes"
516 #endif
517 	sa.sa_handler = SIG_IGN;
518 #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_STRICT_PROTOTYPES)
519 # pragma GCC diagnostic pop
520 #endif
521 	sigaction(SIGHUP, &sa, NULL);
522 	sigaction(SIGPIPE, &sa, NULL);
523 }
524 
main(int argc,char ** argv)525 int main(int argc, char **argv)
526 {
527 	struct	passwd	*new_uid = NULL;
528 	int	i, do_forceshutdown = 0;
529 	int	update_count = 0;
530 
531 	atexit(exit_cleanup);
532 
533 	/* pick up a default from configure --with-user */
534 	user = xstrdup(RUN_AS_USER);	/* xstrdup: this gets freed at exit */
535 
536 	progname = xbasename(argv[0]);
537 	open_syslog(progname);
538 
539 	upsdrv_banner();
540 
541 	if (upsdrv_info.status == DRV_EXPERIMENTAL) {
542 		printf("Warning: This is an experimental driver.\n");
543 		printf("Some features may not function correctly.\n\n");
544 	}
545 
546 	/* build the driver's extra (-x) variable table */
547 	upsdrv_makevartable();
548 
549 	while ((i = getopt(argc, argv, "+a:s:kDd:hx:Lqr:u:Vi:")) != -1) {
550 		switch (i) {
551 			case 'a':
552 				upsname = optarg;
553 
554 				read_upsconf();
555 
556 				if (!upsname_found)
557 					fatalx(EXIT_FAILURE, "Error: Section %s not found in ups.conf",
558 						optarg);
559 				break;
560 			case 's':
561 				upsname = optarg;
562 				upsname_found = 1;
563 				break;
564 			case 'D':
565 				nut_debug_level++;
566 				break;
567 			case 'd':
568 				dump_data = atoi(optarg);
569 				break;
570 			case 'i': { // scope
571 					int ipv = atoi(optarg);
572 					if (ipv > 0) {
573 						poll_interval = (time_t)ipv;
574 					} else {
575 						fatalx(EXIT_FAILURE, "Error: command-line: invalid pollinterval: %d",
576 							ipv);
577 					}
578 				}
579 				break;
580 			case 'k':
581 				do_lock_port = 0;
582 				do_forceshutdown = 1;
583 				break;
584 			case 'L':
585 				listxarg();
586 				exit(EXIT_SUCCESS);
587 			case 'q':
588 				nut_log_level++;
589 				break;
590 			case 'r':
591 				chroot_path = xstrdup(optarg);
592 				break;
593 			case 'u':
594 				free(user);
595 				user = xstrdup(optarg);
596 				break;
597 			case 'V':
598 				/* already printed the banner, so exit */
599 				exit(EXIT_SUCCESS);
600 			case 'x':
601 				splitxarg(optarg);
602 				break;
603 			case 'h':
604 				help_msg();
605 				exit(EXIT_SUCCESS);
606 			default:
607 				fatalx(EXIT_FAILURE,
608 					"Error: unknown option -%c. Try -h for help.", i);
609 		}
610 	}
611 
612 	argc -= optind;
613 	argv += optind;
614 
615 	if (argc > 0) {
616 		fatalx(EXIT_FAILURE,
617 			"Error: too many non-option arguments. Try -h for help.");
618 	}
619 
620 	if (!upsname_found) {
621 		fatalx(EXIT_FAILURE,
622 			"Error: specifying '-a id' or '-s id' is now mandatory. Try -h for help.");
623 	}
624 
625 	/* we need to get the port from somewhere */
626 	if (!device_path) {
627 		fatalx(EXIT_FAILURE,
628 			"Error: you must specify a port name in ups.conf or in '-x port=...' argument.\n"
629 			"Try -h for help.");
630 	}
631 
632 	upsdebugx(1, "debug level is '%d'", nut_debug_level);
633 
634 	new_uid = get_user_pwent(user);
635 
636 	if (chroot_path)
637 		chroot_start(chroot_path);
638 
639 	become_user(new_uid);
640 
641 	/* Only switch to statepath if we're not powering off or just dumping data, for discovery */
642 	/* This avoid case where ie /var is umounted */
643 	if ((!do_forceshutdown) && (!dump_data) && (chdir(dflt_statepath())))
644 		fatal_with_errno(EXIT_FAILURE, "Can't chdir to %s", dflt_statepath());
645 
646 	/* Setup signals to communicate with driver once backgrounded. */
647 	if ((nut_debug_level == 0) && (!do_forceshutdown)) {
648 		char	buffer[SMALLBUF];
649 
650 		setup_signals();
651 
652 		snprintf(buffer, sizeof(buffer), "%s/%s-%s.pid", altpidpath(), progname, upsname);
653 
654 		/* Try to prevent that driver is started multiple times. If a PID file */
655 		/* already exists, send a TERM signal to the process and try if it goes */
656 		/* away. If not, retry a couple of times. */
657 		for (i = 0; i < 3; i++) {
658 			struct stat	st;
659 
660 			if (stat(buffer, &st) != 0) {
661 				/* PID file not found */
662 				break;
663 			}
664 
665 			if (sendsignalfn(buffer, SIGTERM) != 0) {
666 				/* Can't send signal to PID, assume invalid file */
667 				break;
668 			}
669 
670 			upslogx(LOG_WARNING, "Duplicate driver instance detected (PID file %s exists)! Terminating other driver!", buffer);
671 
672 			/* Allow driver some time to quit */
673 			sleep(5);
674 		}
675 
676 		/* Only write pid if we're not just dumping data, for discovery */
677 		if (!dump_data) {
678 			pidfn = xstrdup(buffer);
679 			writepid(pidfn);	/* before backgrounding */
680 		}
681 	}
682 
683 	/* clear out callback handler data */
684 	memset(&upsh, '\0', sizeof(upsh));
685 
686 	/* note: device.type is set early to be overridden by the driver
687 	 * when its a pdu! */
688 	dstate_setinfo("device.type", "ups");
689 
690 	upsdrv_initups();
691 
692 	/* UPS is detected now, cleanup upon exit */
693 	atexit(upsdrv_cleanup);
694 
695 	/* now see if things are very wrong out there */
696 	if (upsdrv_info.status == DRV_BROKEN) {
697 		fatalx(EXIT_FAILURE, "Fatal error: broken driver. It probably needs to be converted.\n");
698 	}
699 
700 	if (do_forceshutdown)
701 		forceshutdown();
702 
703 	/* publish the top-level data: version numbers, driver name */
704 	dstate_setinfo("driver.version", "%s", UPS_VERSION);
705 	dstate_setinfo("driver.version.internal", "%s", upsdrv_info.version);
706 	dstate_setinfo("driver.name", "%s", progname);
707 
708 	/*
709 	 * If we are not debugging, send the early startup logs generated by
710 	 * upsdrv_initinfo() and upsdrv_updateinfo() to syslog, not just stderr.
711 	 * Otherwise these logs are lost.
712 	 */
713 	if ((nut_debug_level == 0) && (!dump_data))
714 		syslogbit_set();
715 
716 	/* get the base data established before allowing connections */
717 	upsdrv_initinfo();
718 	upsdrv_updateinfo();
719 
720 	if (dstate_getinfo("driver.flag.ignorelb")) {
721 		int	have_lb_method = 0;
722 
723 		if (dstate_getinfo("battery.charge") && dstate_getinfo("battery.charge.low")) {
724 			upslogx(LOG_INFO, "using 'battery.charge' to set battery low state");
725 			have_lb_method++;
726 		}
727 
728 		if (dstate_getinfo("battery.runtime") && dstate_getinfo("battery.runtime.low")) {
729 			upslogx(LOG_INFO, "using 'battery.runtime' to set battery low state");
730 			have_lb_method++;
731 		}
732 
733 		if (!have_lb_method) {
734 			fatalx(EXIT_FAILURE,
735 				"The 'ignorelb' flag is set, but there is no way to determine the\n"
736 				"battery state of charge.\n\n"
737 				"Only set this flag if both 'battery.charge' and 'battery.charge.low'\n"
738 				"and/or 'battery.runtime' and 'battery.runtime.low' are available.\n");
739 		}
740 	}
741 
742 	/* now we can start servicing requests */
743 	/* Only write pid if we're not just dumping data, for discovery */
744 	if (!dump_data)
745 		dstate_init(progname, upsname);
746 
747 	/* The poll_interval may have been changed from the default */
748 	dstate_setinfo("driver.parameter.pollinterval", "%jd", (intmax_t)poll_interval);
749 
750 	/* The synchronous option may have been changed from the default */
751 	dstate_setinfo("driver.parameter.synchronous", "%s",
752 		(do_synchronous==1)?"yes":"no");
753 
754 	/* remap the device.* info from ups.* for the transition period */
755 	if (dstate_getinfo("ups.mfr") != NULL)
756 		dstate_setinfo("device.mfr", "%s", dstate_getinfo("ups.mfr"));
757 	if (dstate_getinfo("ups.model") != NULL)
758 		dstate_setinfo("device.model", "%s", dstate_getinfo("ups.model"));
759 	if (dstate_getinfo("ups.serial") != NULL)
760 		dstate_setinfo("device.serial", "%s", dstate_getinfo("ups.serial"));
761 
762 	if ( (nut_debug_level == 0) && (!dump_data) ) {
763 		background();
764 		writepid(pidfn);	/* PID changes when backgrounding */
765 	}
766 
767 	while (!exit_flag) {
768 
769 		struct timeval	timeout;
770 
771 		gettimeofday(&timeout, NULL);
772 		timeout.tv_sec += poll_interval;
773 
774 		upsdrv_updateinfo();
775 
776 		/* Dump the data tree (in upsc-like format) to stdout and exit */
777 		if (dump_data) {
778 			/* Wait for 'dump_data' update loops to ensure data completion */
779 			if (update_count == dump_data) {
780 				dstate_dump();
781 				exit_flag = 1;
782 			}
783 			else
784 				update_count++;
785 		}
786 		else {
787 			while (!dstate_poll_fds(timeout, extrafd) && !exit_flag) {
788 				/* repeat until time is up or extrafd has data */
789 			}
790 		}
791 	}
792 
793 	/* if we get here, the exit flag was set by a signal handler */
794 	/* however, avoid to "pollute" data dump output! */
795 	if (!dump_data)
796 		upslogx(LOG_INFO, "Signal %d: exiting", exit_flag);
797 
798 	exit(EXIT_SUCCESS);
799 }
800