xref: /openbsd-src/usr.sbin/ntpd/ntpd.c (revision 50b7afb2c2c0993b0894d4e34bf857cb13ed9c80)
1 /*	$OpenBSD: ntpd.c,v 1.79 2014/02/10 09:12:34 dtucker Exp $ */
2 
3 /*
4  * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
5  * Copyright (c) 2012 Mike Miller <mmiller@mgm51.com>
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
16  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
17  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include <sys/types.h>
21 #include <sys/resource.h>
22 #include <sys/socket.h>
23 #include <sys/wait.h>
24 #include <sys/un.h>
25 #include <netinet/in.h>
26 #include <errno.h>
27 #include <poll.h>
28 #include <pwd.h>
29 #include <signal.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <unistd.h>
34 #include <err.h>
35 
36 #include "ntpd.h"
37 
38 void		sighdlr(int);
39 __dead void	usage(void);
40 int		main(int, char *[]);
41 int		check_child(pid_t, const char *);
42 int		dispatch_imsg(struct ntpd_conf *);
43 int		dispatch_imsg_ctl(struct ntpd_conf *);
44 void		reset_adjtime(void);
45 int		ntpd_adjtime(double);
46 void		ntpd_adjfreq(double, int);
47 void		ntpd_settime(double);
48 void		readfreq(void);
49 int		writefreq(double);
50 void		ctl_main(int, char*[]);
51 const char     *ctl_lookup_option(char *, const char **);
52 void		show_status_msg(struct imsg *);
53 void		show_peer_msg(struct imsg *, int);
54 void		show_sensor_msg(struct imsg *, int);
55 
56 volatile sig_atomic_t	 quit = 0;
57 volatile sig_atomic_t	 reconfig = 0;
58 volatile sig_atomic_t	 sigchld = 0;
59 struct imsgbuf		*ibuf;
60 int			 debugsyslog = 0;
61 int			 timeout = INFTIM;
62 
63 const char		*showopt;
64 
65 static const char *ctl_showopt_list[] = {
66 	"peers", "Sensors", "status", "all", NULL
67 };
68 
69 void
70 sighdlr(int sig)
71 {
72 	switch (sig) {
73 	case SIGTERM:
74 	case SIGINT:
75 		quit = 1;
76 		break;
77 	case SIGCHLD:
78 		sigchld = 1;
79 		break;
80 	case SIGHUP:
81 		reconfig = 1;
82 		break;
83 	}
84 }
85 
86 __dead void
87 usage(void)
88 {
89 	extern char *__progname;
90 
91 	if (strcmp(__progname, "ntpctl") == 0)
92 		fprintf(stderr, "usage: ntpctl [-s all | peers | Sensors | status]\n");
93 	else
94 		fprintf(stderr, "usage: %s [-dnSsv] [-f file]\n",
95 		    __progname);
96 	exit(1);
97 }
98 
99 #define POLL_MAX		8
100 #define PFD_PIPE		0
101 
102 int
103 main(int argc, char *argv[])
104 {
105 	struct ntpd_conf	 lconf;
106 	struct pollfd		 pfd[POLL_MAX];
107 	pid_t			 chld_pid = 0, pid;
108 	const char		*conffile;
109 	int			 fd_ctl, ch, nfds;
110 	int			 pipe_chld[2];
111 	struct passwd		*pw;
112 	extern char 		*__progname;
113 
114 	if (strcmp(__progname, "ntpctl") == 0) {
115 		ctl_main (argc, argv);
116 		/* NOTREACHED */
117 	}
118 
119 	conffile = CONFFILE;
120 
121 	bzero(&lconf, sizeof(lconf));
122 
123 	log_init(1);		/* log to stderr until daemonized */
124 
125 	while ((ch = getopt(argc, argv, "df:nsSv")) != -1) {
126 		switch (ch) {
127 		case 'd':
128 			lconf.debug = 1;
129 			break;
130 		case 'f':
131 			conffile = optarg;
132 			break;
133 		case 'n':
134 			lconf.noaction = 1;
135 			break;
136 		case 's':
137 			lconf.settime = 1;
138 			break;
139 		case 'S':
140 			lconf.settime = 0;
141 			break;
142 		case 'v':
143 			debugsyslog = 1;
144 			break;
145 		default:
146 			usage();
147 			/* NOTREACHED */
148 		}
149 	}
150 
151 	argc -= optind;
152 	argv += optind;
153 	if (argc > 0)
154 		usage();
155 
156 	if (parse_config(conffile, &lconf))
157 		exit(1);
158 
159 	if (lconf.noaction) {
160 		fprintf(stderr, "configuration OK\n");
161 		exit(0);
162 	}
163 
164 	if (geteuid())
165 		errx(1, "need root privileges");
166 
167 	if ((pw = getpwnam(NTPD_USER)) == NULL)
168 		errx(1, "unknown user %s", NTPD_USER);
169 
170 	if (setpriority(PRIO_PROCESS, 0, -20) == -1)
171 		warn("can't set priority");
172 
173 	reset_adjtime();
174 	if (!lconf.settime) {
175 		log_init(lconf.debug);
176 		if (!lconf.debug)
177 			if (daemon(1, 0))
178 				fatal("daemon");
179 	} else
180 		timeout = SETTIME_TIMEOUT * 1000;
181 
182 	if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe_chld) == -1)
183 		fatal("socketpair");
184 
185 	if ((fd_ctl = control_init(CTLSOCKET)) == -1)
186 		fatalx("control socket init failed");
187 	if (control_listen(fd_ctl) == -1)
188 		fatalx("control socket listen failed");
189 
190 	signal(SIGCHLD, sighdlr);
191 	/* fork child process */
192 	chld_pid = ntp_main(pipe_chld, fd_ctl, &lconf, pw);
193 
194 	setproctitle("[priv]");
195 	readfreq();
196 
197 	signal(SIGTERM, sighdlr);
198 	signal(SIGINT, sighdlr);
199 	signal(SIGHUP, sighdlr);
200 
201 	close(pipe_chld[1]);
202 
203 	if ((ibuf = malloc(sizeof(struct imsgbuf))) == NULL)
204 		fatal(NULL);
205 	imsg_init(ibuf, pipe_chld[0]);
206 
207 	while (quit == 0) {
208 		pfd[PFD_PIPE].fd = ibuf->fd;
209 		pfd[PFD_PIPE].events = POLLIN;
210 		if (ibuf->w.queued)
211 			pfd[PFD_PIPE].events |= POLLOUT;
212 
213 		if ((nfds = poll(pfd, 1, timeout)) == -1)
214 			if (errno != EINTR) {
215 				log_warn("poll error");
216 				quit = 1;
217 			}
218 
219 		if (nfds == 0 && lconf.settime) {
220 			lconf.settime = 0;
221 			timeout = INFTIM;
222 			log_init(lconf.debug);
223 			log_debug("no reply received in time, skipping initial "
224 			    "time setting");
225 			if (!lconf.debug)
226 				if (daemon(1, 0))
227 					fatal("daemon");
228 		}
229 
230 		if (nfds > 0 && (pfd[PFD_PIPE].revents & POLLOUT))
231 			if (msgbuf_write(&ibuf->w) <= 0 && errno != EAGAIN) {
232 				log_warn("pipe write error (to child)");
233 				quit = 1;
234 			}
235 
236 		if (nfds > 0 && pfd[PFD_PIPE].revents & POLLIN) {
237 			nfds--;
238 			if (dispatch_imsg(&lconf) == -1)
239 				quit = 1;
240 		}
241 
242 		if (sigchld) {
243 			if (check_child(chld_pid, "child")) {
244 				quit = 1;
245 				chld_pid = 0;
246 			}
247 			sigchld = 0;
248 		}
249 
250 	}
251 
252 	signal(SIGCHLD, SIG_DFL);
253 
254 	if (chld_pid)
255 		kill(chld_pid, SIGTERM);
256 
257 	do {
258 		if ((pid = wait(NULL)) == -1 &&
259 		    errno != EINTR && errno != ECHILD)
260 			fatal("wait");
261 	} while (pid != -1 || (pid == -1 && errno == EINTR));
262 
263 	msgbuf_clear(&ibuf->w);
264 	free(ibuf);
265 	log_info("Terminating");
266 	return (0);
267 }
268 
269 int
270 check_child(pid_t pid, const char *pname)
271 {
272 	int	 status, sig;
273 	char	*signame;
274 
275 	if (waitpid(pid, &status, WNOHANG) > 0) {
276 		if (WIFEXITED(status)) {
277 			log_warnx("Lost child: %s exited", pname);
278 			return (1);
279 		}
280 		if (WIFSIGNALED(status)) {
281 			sig = WTERMSIG(status);
282 			signame = strsignal(sig) ? strsignal(sig) : "unknown";
283 			log_warnx("Lost child: %s terminated; signal %d (%s)",
284 			    pname, sig, signame);
285 			return (1);
286 		}
287 	}
288 
289 	return (0);
290 }
291 
292 int
293 dispatch_imsg(struct ntpd_conf *lconf)
294 {
295 	struct imsg		 imsg;
296 	int			 n, cnt;
297 	double			 d;
298 	char			*name;
299 	struct ntp_addr		*h, *hn;
300 	struct ibuf		*buf;
301 
302 	if ((n = imsg_read(ibuf)) == -1)
303 		return (-1);
304 
305 	if (n == 0) {	/* connection closed */
306 		log_warnx("dispatch_imsg in main: pipe closed");
307 		return (-1);
308 	}
309 
310 	for (;;) {
311 		if ((n = imsg_get(ibuf, &imsg)) == -1)
312 			return (-1);
313 
314 		if (n == 0)
315 			break;
316 
317 		switch (imsg.hdr.type) {
318 		case IMSG_ADJTIME:
319 			if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(d))
320 				fatalx("invalid IMSG_ADJTIME received");
321 			memcpy(&d, imsg.data, sizeof(d));
322 			n = ntpd_adjtime(d);
323 			imsg_compose(ibuf, IMSG_ADJTIME, 0, 0, -1,
324 			     &n, sizeof(n));
325 			break;
326 		case IMSG_ADJFREQ:
327 			if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(d))
328 				fatalx("invalid IMSG_ADJFREQ received");
329 			memcpy(&d, imsg.data, sizeof(d));
330 			ntpd_adjfreq(d, 1);
331 			break;
332 		case IMSG_SETTIME:
333 			if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(d))
334 				fatalx("invalid IMSG_SETTIME received");
335 			if (!lconf->settime)
336 				break;
337 			log_init(lconf->debug);
338 			memcpy(&d, imsg.data, sizeof(d));
339 			ntpd_settime(d);
340 			/* daemonize now */
341 			if (!lconf->debug)
342 				if (daemon(1, 0))
343 					fatal("daemon");
344 			lconf->settime = 0;
345 			timeout = INFTIM;
346 			break;
347 		case IMSG_HOST_DNS:
348 			name = imsg.data;
349 			if (imsg.hdr.len < 1 + IMSG_HEADER_SIZE)
350 				fatalx("invalid IMSG_HOST_DNS received");
351 			imsg.hdr.len -= 1 + IMSG_HEADER_SIZE;
352 			if (name[imsg.hdr.len] != '\0' ||
353 			    strlen(name) != imsg.hdr.len)
354 				fatalx("invalid IMSG_HOST_DNS received");
355 			if ((cnt = host_dns(name, &hn)) == -1)
356 				break;
357 			buf = imsg_create(ibuf, IMSG_HOST_DNS,
358 			    imsg.hdr.peerid, 0,
359 			    cnt * sizeof(struct sockaddr_storage));
360 			if (buf == NULL)
361 				break;
362 			if (cnt > 0)
363 				for (h = hn; h != NULL; h = h->next)
364 					imsg_add(buf, &h->ss, sizeof(h->ss));
365 
366 			imsg_close(ibuf, buf);
367 			break;
368 		default:
369 			break;
370 		}
371 		imsg_free(&imsg);
372 	}
373 	return (0);
374 }
375 
376 void
377 reset_adjtime(void)
378 {
379 	struct timeval	tv;
380 
381 	timerclear(&tv);
382 	if (adjtime(&tv, NULL) == -1)
383 		log_warn("reset adjtime failed");
384 }
385 
386 int
387 ntpd_adjtime(double d)
388 {
389 	struct timeval	tv, olddelta;
390 	int		synced = 0;
391 	static int	firstadj = 1;
392 
393 	d += getoffset();
394 	if (d >= (double)LOG_NEGLIGIBLE_ADJTIME / 1000 ||
395 	    d <= -1 * (double)LOG_NEGLIGIBLE_ADJTIME / 1000)
396 		log_info("adjusting local clock by %fs", d);
397 	else
398 		log_debug("adjusting local clock by %fs", d);
399 	d_to_tv(d, &tv);
400 	if (adjtime(&tv, &olddelta) == -1)
401 		log_warn("adjtime failed");
402 	else if (!firstadj && olddelta.tv_sec == 0 && olddelta.tv_usec == 0)
403 		synced = 1;
404 	firstadj = 0;
405 	return (synced);
406 }
407 
408 void
409 ntpd_adjfreq(double relfreq, int wrlog)
410 {
411 	int64_t curfreq;
412 	double ppmfreq;
413 	int r;
414 
415 	if (adjfreq(NULL, &curfreq) == -1) {
416 		log_warn("adjfreq failed");
417 		return;
418 	}
419 
420 	/*
421 	 * adjfreq's unit is ns/s shifted left 32; convert relfreq to
422 	 * that unit before adding. We log values in part per million.
423 	 */
424 	curfreq += relfreq * 1e9 * (1LL << 32);
425 	r = writefreq(curfreq / 1e9 / (1LL << 32));
426 	ppmfreq = relfreq * 1e6;
427 	if (wrlog) {
428 		if (ppmfreq >= LOG_NEGLIGIBLE_ADJFREQ ||
429 		    ppmfreq <= -LOG_NEGLIGIBLE_ADJFREQ)
430 			log_info("adjusting clock frequency by %f to %fppm%s",
431 			    ppmfreq, curfreq / 1e3 / (1LL << 32),
432 			    r ? "" : " (no drift file)");
433 		else
434 			log_debug("adjusting clock frequency by %f to %fppm%s",
435 			    ppmfreq, curfreq / 1e3 / (1LL << 32),
436 			    r ? "" : " (no drift file)");
437 	}
438 
439 	if (adjfreq(&curfreq, NULL) == -1)
440 		log_warn("adjfreq failed");
441 }
442 
443 void
444 ntpd_settime(double d)
445 {
446 	struct timeval	tv, curtime;
447 	char		buf[80];
448 	time_t		tval;
449 
450 	if (gettimeofday(&curtime, NULL) == -1) {
451 		log_warn("gettimeofday");
452 		return;
453 	}
454 	d_to_tv(d, &tv);
455 	curtime.tv_usec += tv.tv_usec + 1000000;
456 	curtime.tv_sec += tv.tv_sec - 1 + (curtime.tv_usec / 1000000);
457 	curtime.tv_usec %= 1000000;
458 
459 	if (settimeofday(&curtime, NULL) == -1) {
460 		log_warn("settimeofday");
461 		return;
462 	}
463 	tval = curtime.tv_sec;
464 	strftime(buf, sizeof(buf), "%a %b %e %H:%M:%S %Z %Y",
465 	    localtime(&tval));
466 	log_info("set local clock to %s (offset %fs)", buf, d);
467 }
468 
469 void
470 readfreq(void)
471 {
472 	FILE *fp;
473 	int64_t current;
474 	double d;
475 
476 	fp = fopen(DRIFTFILE, "r");
477 	if (fp == NULL) {
478 		/* if the drift file has been deleted by the user, reset */
479 		current = 0;
480 		if (adjfreq(&current, NULL) == -1)
481 			log_warn("adjfreq reset failed");
482 		return;
483 	}
484 
485 	/* if we're adjusting frequency already, don't override */
486 	if (adjfreq(NULL, &current) == -1)
487 		log_warn("adjfreq failed");
488 	else if (current == 0) {
489 		if (fscanf(fp, "%le", &d) == 1)
490 			ntpd_adjfreq(d, 0);
491 		else
492 			log_warnx("can't read %s", DRIFTFILE);
493 	}
494 	fclose(fp);
495 }
496 
497 int
498 writefreq(double d)
499 {
500 	int r;
501 	FILE *fp;
502 	static int warnonce = 1;
503 
504 	fp = fopen(DRIFTFILE, "w");
505 	if (fp == NULL) {
506 		if (warnonce) {
507 			log_warn("can't open %s", DRIFTFILE);
508 			warnonce = 0;
509 		}
510 		return 0;
511 	}
512 
513 	fprintf(fp, "%e\n", d);
514 	r = ferror(fp);
515 	if (fclose(fp) != 0 || r != 0) {
516 		if (warnonce) {
517 			log_warnx("can't write %s", DRIFTFILE);
518 			warnonce = 0;
519 		}
520 		unlink(DRIFTFILE);
521 		return 0;
522 	}
523 	return 1;
524 }
525 
526 void
527 ctl_main(int argc, char *argv[])
528 {
529 	struct sockaddr_un	 sun;
530 	struct imsg		 imsg;
531 	struct imsgbuf		*ibuf_ctl;
532 	int			 fd, n, done, ch, action;
533 	char			*sockname;
534 
535 	sockname = CTLSOCKET;
536 
537 	if (argc < 2) {
538 		usage();
539 		/* NOTREACHED */
540 	}
541 
542 	while ((ch = getopt(argc, argv, "s:")) != -1) {
543 		switch (ch) {
544 		case 's':
545 			showopt = ctl_lookup_option(optarg, ctl_showopt_list);
546 			if (showopt == NULL) {
547 				warnx("Unknown show modifier '%s'", optarg);
548 				usage();
549 			}
550 			break;
551 		default:
552 			usage();
553 			/* NOTREACHED */
554 		}
555 	}
556 
557 	action = -1;
558 	if (showopt != NULL) {
559 		switch (*showopt) {
560 		case 'p':
561 			action = CTL_SHOW_PEERS;
562 			break;
563 		case 's':
564 			action = CTL_SHOW_STATUS;
565 			break;
566 		case 'S':
567 			action = CTL_SHOW_SENSORS;
568 			break;
569 		case 'a':
570 			action = CTL_SHOW_ALL;
571 			break;
572 		default:
573 			usage();
574 			/* NOTREACHED */
575 		}
576 	} else
577 		usage();
578 
579 	if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
580 		err(1, "ntpctl: socket");
581 
582 	bzero(&sun, sizeof(sun));
583 	sun.sun_family = AF_UNIX;
584 	if (strlcpy(sun.sun_path, sockname, sizeof(sun.sun_path)) >=
585 	    sizeof(sun.sun_path))
586 		errx(1, "ctl socket name too long");
587 	if (connect(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1)
588 		err(1, "connect: %s", sockname);
589 
590 	if ((ibuf_ctl = malloc(sizeof(struct imsgbuf))) == NULL)
591 		err(1, NULL);
592 	imsg_init(ibuf_ctl, fd);
593 
594 	switch (action) {
595 	case CTL_SHOW_STATUS:
596 		imsg_compose(ibuf_ctl, IMSG_CTL_SHOW_STATUS,
597 		    0, 0, -1, NULL, 0);
598 		break;
599 	case CTL_SHOW_PEERS:
600 		imsg_compose(ibuf_ctl, IMSG_CTL_SHOW_PEERS,
601 		    0, 0, -1, NULL, 0);
602 		break;
603 	case CTL_SHOW_SENSORS:
604 		imsg_compose(ibuf_ctl, IMSG_CTL_SHOW_SENSORS,
605 		    0, 0, -1, NULL, 0);
606 		break;
607 	case CTL_SHOW_ALL:
608 		imsg_compose(ibuf_ctl, IMSG_CTL_SHOW_ALL,
609 		    0, 0, -1, NULL, 0);
610 		break;
611 	default:
612 		errx(1, "invalid action");
613 		break; /* NOTREACHED */
614 	}
615 
616 	while (ibuf_ctl->w.queued)
617 		if (msgbuf_write(&ibuf_ctl->w) <= 0 && errno != EAGAIN)
618 			err(1, "ibuf_ctl: msgbuf_write error");
619 
620 	done = 0;
621 	while (!done) {
622 		if ((n = imsg_read(ibuf_ctl)) == -1)
623 			err(1, "ibuf_ctl: imsg_read error");
624 		if (n == 0)
625 			errx(1, "ntpctl: pipe closed");
626 
627 		while (!done) {
628 			if ((n = imsg_get(ibuf_ctl, &imsg)) == -1)
629 				err(1, "ibuf_ctl: imsg_get error");
630 			if (n == 0)
631 				break;
632 
633 			switch (action) {
634 			case CTL_SHOW_STATUS:
635 				show_status_msg(&imsg);
636 				done = 1;
637 				break;
638 			case CTL_SHOW_PEERS:
639 				show_peer_msg(&imsg, 0);
640 				if (imsg.hdr.type ==
641 				    IMSG_CTL_SHOW_PEERS_END)
642 					done = 1;
643 				break;
644 			case CTL_SHOW_SENSORS:
645 				show_sensor_msg(&imsg, 0);
646 				if (imsg.hdr.type ==
647 				    IMSG_CTL_SHOW_SENSORS_END)
648 					done = 1;
649 				break;
650 			case CTL_SHOW_ALL:
651 				switch (imsg.hdr.type) {
652 				case IMSG_CTL_SHOW_STATUS:
653 					show_status_msg(&imsg);
654 					break;
655 				case IMSG_CTL_SHOW_PEERS:
656 					show_peer_msg(&imsg, 1);
657 					break;
658 				case IMSG_CTL_SHOW_SENSORS:
659 					show_sensor_msg(&imsg, 1);
660 					break;
661 				case IMSG_CTL_SHOW_PEERS_END:
662 				case IMSG_CTL_SHOW_SENSORS_END:
663 					/* do nothing */
664 					break;
665 				case IMSG_CTL_SHOW_ALL_END:
666 					done=1;
667 					break;
668 				default:
669 					/* no action taken */
670 					break;
671 				}
672 			default:
673 				/* no action taken */
674 				break;
675 			}
676 			imsg_free(&imsg);
677 		}
678 	}
679 	close(fd);
680 	free(ibuf_ctl);
681 	exit (0);
682 }
683 
684 const char *
685 ctl_lookup_option(char *cmd, const char **list)
686 {
687 	const char *item = NULL;
688 	if (cmd != NULL && *cmd)
689 		for (; *list; list++)
690 			if (!strncmp(cmd, *list, strlen(cmd))) {
691 				if (item == NULL)
692 					item = *list;
693 				else
694 					errx(1, "%s is ambiguous", cmd);
695 			}
696 	return (item);
697 }
698 
699 void
700 show_status_msg(struct imsg *imsg)
701 {
702 	struct ctl_show_status	*cstatus;
703 	double			 clock_offset;
704 
705 	if (imsg->hdr.len != IMSG_HEADER_SIZE + sizeof(struct ctl_show_status))
706 		fatalx("invalid IMSG_CTL_SHOW_STATUS received");
707 
708 	cstatus = (struct ctl_show_status *)imsg->data;
709 
710 	if (cstatus->peercnt > 0)
711 		printf("%d/%d peers valid, ",
712 		    cstatus->valid_peers, cstatus->peercnt);
713 
714 	if (cstatus->sensorcnt > 0)
715 		printf("%d/%d sensors valid, ",
716 		    cstatus->valid_sensors, cstatus->sensorcnt);
717 
718 	if (cstatus->peercnt + cstatus->sensorcnt == 0)
719 		printf("no peers and no sensors configured\n");
720 
721 	if (cstatus->synced == 1)
722 		printf("clock synced, stratum %u\n", cstatus->stratum);
723 	else {
724 		printf("clock unsynced");
725 		clock_offset = cstatus->clock_offset < 0 ?
726 		    -1.0 * cstatus->clock_offset : cstatus->clock_offset;
727 		if (clock_offset > 5e-7)
728 			printf(", clock offset is %.3fms\n",
729 			    cstatus->clock_offset);
730 		else
731 			printf("\n");
732 	}
733 }
734 
735 void
736 show_peer_msg(struct imsg *imsg, int calledfromshowall)
737 {
738 	struct ctl_show_peer	*cpeer;
739 	int			 cnt;
740 	char			 stratum[3];
741 	static int		 firsttime = 1;
742 
743 	if (imsg->hdr.type == IMSG_CTL_SHOW_PEERS_END) {
744 		if (imsg->hdr.len != IMSG_HEADER_SIZE + sizeof(cnt))
745 			fatalx("invalid IMSG_CTL_SHOW_PEERS_END received");
746 		memcpy(&cnt, imsg->data, sizeof(cnt));
747 		if (cnt == 0)
748 			printf("no peers configured\n");
749 		return;
750 	}
751 
752 	if (imsg->hdr.len != IMSG_HEADER_SIZE + sizeof(struct ctl_show_peer))
753 		fatalx("invalid IMSG_CTL_SHOW_PEERS received");
754 
755 	cpeer = (struct ctl_show_peer *)imsg->data;
756 
757 	if (strlen(cpeer->peer_desc) > MAX_DISPLAY_WIDTH - 1)
758 		fatalx("peer_desc is too long");
759 
760 	if (firsttime) {
761 		firsttime = 0;
762 		if (calledfromshowall)
763 			printf("\n");
764 		printf("peer\n   wt tl st  next  poll          "
765 		    "offset       delay      jitter\n");
766 	}
767 
768 	if (cpeer->stratum > 0)
769 		snprintf(stratum, sizeof(stratum), "%2u", cpeer->stratum);
770 	else
771 		strlcpy (stratum, " -", sizeof (stratum));
772 
773 	printf("%s\n %1s %2u %2u %2s %4llds %4llds",
774 	    cpeer->peer_desc, cpeer->syncedto == 1 ? "*" : " ",
775 	    cpeer->weight, cpeer->trustlevel, stratum,
776 	    (long long)cpeer->next, (long long)cpeer->poll);
777 
778 	if (cpeer->trustlevel >= TRUSTLEVEL_BADPEER)
779 		printf("  %12.3fms %9.3fms  %8.3fms\n", cpeer->offset,
780 		    cpeer->delay, cpeer->jitter);
781 	else
782 		printf("             ---- peer not valid ----\n");
783 
784 }
785 
786 void
787 show_sensor_msg(struct imsg *imsg, int calledfromshowall)
788 {
789 	struct ctl_show_sensor	*csensor;
790 	int			 cnt;
791 	static int		 firsttime = 1;
792 
793 	if (imsg->hdr.type == IMSG_CTL_SHOW_SENSORS_END) {
794 		if (imsg->hdr.len != IMSG_HEADER_SIZE + sizeof(cnt))
795 			fatalx("invalid IMSG_CTL_SHOW_SENSORS_END received");
796 		memcpy(&cnt, imsg->data, sizeof(cnt));
797 		if (cnt == 0)
798 			printf("no sensors configured\n");
799 		return;
800 	}
801 
802 	if (imsg->hdr.len != IMSG_HEADER_SIZE + sizeof(struct ctl_show_sensor))
803 		fatalx("invalid IMSG_CTL_SHOW_SENSORS received");
804 
805 	csensor = (struct ctl_show_sensor *)imsg->data;
806 
807 	if (strlen(csensor->sensor_desc) > MAX_DISPLAY_WIDTH - 1)
808 		fatalx("sensor_desc is too long");
809 
810 	if (firsttime) {
811 		firsttime = 0;
812 		if (calledfromshowall)
813 			printf("\n");
814 		printf("sensor\n   wt gd st  next  poll          "
815 		    "offset  correction\n");
816 	}
817 
818 	printf("%s\n %1s %2u %2u %2u %4llds %4llds",
819 	    csensor->sensor_desc, csensor->syncedto == 1 ? "*" : " ",
820 	    csensor->weight, csensor->good, csensor->stratum,
821 	    (long long)csensor->next, (long long)csensor->poll);
822 
823 	if (csensor->good == 1)
824 		printf("   %11.3fms %9.3fms\n",
825 		    csensor->offset, csensor->correction);
826 	else
827 		printf("         - sensor not valid -\n");
828 
829 }
830