1 /* $OpenBSD: ntpd.c,v 1.112 2016/12/01 16:24:48 mestre 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 USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * 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 <syslog.h> 34 #include <time.h> 35 #include <unistd.h> 36 #include <fcntl.h> 37 #include <err.h> 38 39 #include "ntpd.h" 40 41 void sighdlr(int); 42 __dead void usage(void); 43 int main(int, char *[]); 44 void check_child(void); 45 int dispatch_imsg(struct ntpd_conf *, int, char **); 46 int dispatch_imsg_ctl(struct ntpd_conf *); 47 void reset_adjtime(void); 48 int ntpd_adjtime(double); 49 void ntpd_adjfreq(double, int); 50 void ntpd_settime(double); 51 void readfreq(void); 52 int writefreq(double); 53 void ctl_main(int, char*[]); 54 const char *ctl_lookup_option(char *, const char **); 55 void show_status_msg(struct imsg *); 56 void show_peer_msg(struct imsg *, int); 57 void show_sensor_msg(struct imsg *, int); 58 59 volatile sig_atomic_t quit = 0; 60 volatile sig_atomic_t reconfig = 0; 61 volatile sig_atomic_t sigchld = 0; 62 struct imsgbuf *ibuf; 63 int timeout = INFTIM; 64 65 extern u_int constraint_cnt; 66 67 const char *showopt; 68 69 static const char *ctl_showopt_list[] = { 70 "peers", "Sensors", "status", "all", NULL 71 }; 72 73 void 74 sighdlr(int sig) 75 { 76 switch (sig) { 77 case SIGTERM: 78 case SIGINT: 79 quit = 1; 80 break; 81 case SIGCHLD: 82 sigchld = 1; 83 break; 84 case SIGHUP: 85 reconfig = 1; 86 break; 87 } 88 } 89 90 __dead void 91 usage(void) 92 { 93 extern char *__progname; 94 95 if (strcmp(__progname, "ntpctl") == 0) 96 fprintf(stderr, 97 "usage: ntpctl -s all | peers | Sensors | status\n"); 98 else 99 fprintf(stderr, "usage: %s [-dnSsv] [-f file]\n", 100 __progname); 101 exit(1); 102 } 103 104 #define POLL_MAX 8 105 #define PFD_PIPE 0 106 #define PFD_MAX 1 107 108 int 109 main(int argc, char *argv[]) 110 { 111 struct ntpd_conf lconf; 112 struct pollfd *pfd = NULL; 113 pid_t pid; 114 const char *conffile; 115 int ch, nfds, i, j; 116 int pipe_chld[2]; 117 extern char *__progname; 118 u_int pfd_elms = 0, new_cnt; 119 struct constraint *cstr; 120 struct passwd *pw; 121 void *newp; 122 int argc0 = argc; 123 char **argv0 = argv; 124 char *pname = NULL; 125 126 if (strcmp(__progname, "ntpctl") == 0) { 127 ctl_main(argc, argv); 128 /* NOTREACHED */ 129 } 130 131 conffile = CONFFILE; 132 133 memset(&lconf, 0, sizeof(lconf)); 134 135 while ((ch = getopt(argc, argv, "df:nP:sSv")) != -1) { 136 switch (ch) { 137 case 'd': 138 lconf.debug = 2; 139 break; 140 case 'f': 141 conffile = optarg; 142 break; 143 case 'n': 144 lconf.debug = 2; 145 lconf.noaction = 1; 146 break; 147 case 'P': 148 pname = optarg; 149 break; 150 case 's': 151 lconf.settime = 1; 152 break; 153 case 'S': 154 lconf.settime = 0; 155 break; 156 case 'v': 157 lconf.verbose++; 158 break; 159 default: 160 usage(); 161 /* NOTREACHED */ 162 } 163 } 164 165 /* log to stderr until daemonized */ 166 log_init(lconf.debug ? lconf.debug : 1, LOG_DAEMON); 167 168 argc -= optind; 169 argv += optind; 170 if (argc > 0) 171 usage(); 172 173 if (parse_config(conffile, &lconf)) 174 exit(1); 175 176 if (lconf.noaction) { 177 fprintf(stderr, "configuration OK\n"); 178 exit(0); 179 } 180 181 if (geteuid()) 182 errx(1, "need root privileges"); 183 184 if ((pw = getpwnam(NTPD_USER)) == NULL) 185 errx(1, "unknown user %s", NTPD_USER); 186 187 if (pname != NULL) { 188 /* Remove our proc arguments, so child doesn't need to. */ 189 if (sanitize_argv(&argc0, &argv0) == -1) 190 fatalx("sanitize_argv"); 191 192 if (strcmp(NTP_PROC_NAME, pname) == 0) 193 ntp_main(&lconf, pw, argc0, argv0); 194 else if (strcmp(NTPDNS_PROC_NAME, pname) == 0) 195 ntp_dns(&lconf, pw); 196 else if (strcmp(CONSTRAINT_PROC_NAME, pname) == 0) 197 priv_constraint_child(pw->pw_dir, pw->pw_uid, 198 pw->pw_gid); 199 else 200 fatalx("%s: invalid process name '%s'", __func__, 201 pname); 202 203 fatalx("%s: process '%s' failed", __func__, pname); 204 } 205 206 if (setpriority(PRIO_PROCESS, 0, -20) == -1) 207 warn("can't set priority"); 208 209 reset_adjtime(); 210 if (!lconf.settime) { 211 log_init(lconf.debug, LOG_DAEMON); 212 log_verbose(lconf.verbose); 213 if (!lconf.debug) 214 if (daemon(1, 0)) 215 fatal("daemon"); 216 } else 217 timeout = SETTIME_TIMEOUT * 1000; 218 219 if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, PF_UNSPEC, 220 pipe_chld) == -1) 221 fatal("socketpair"); 222 223 signal(SIGCHLD, sighdlr); 224 225 /* fork child process */ 226 start_child(NTP_PROC_NAME, pipe_chld[1], argc0, argv0); 227 228 log_procinit("[priv]"); 229 readfreq(); 230 231 signal(SIGTERM, sighdlr); 232 signal(SIGINT, sighdlr); 233 signal(SIGHUP, sighdlr); 234 235 constraint_purge(); 236 237 if ((ibuf = malloc(sizeof(struct imsgbuf))) == NULL) 238 fatal(NULL); 239 imsg_init(ibuf, pipe_chld[0]); 240 241 constraint_cnt = 0; 242 243 /* 244 * Constraint processes are forked with certificates in memory, 245 * then privdrop into chroot before speaking to the outside world. 246 */ 247 if (pledge("stdio rpath inet settime proc exec id", NULL) == -1) 248 err(1, "pledge"); 249 250 while (quit == 0) { 251 new_cnt = PFD_MAX + constraint_cnt; 252 if (new_cnt > pfd_elms) { 253 if ((newp = reallocarray(pfd, new_cnt, 254 sizeof(*pfd))) == NULL) { 255 /* panic for now */ 256 log_warn("could not resize pfd from %u -> " 257 "%u entries", pfd_elms, new_cnt); 258 fatalx("exiting"); 259 } 260 pfd = newp; 261 pfd_elms = new_cnt; 262 } 263 264 memset(pfd, 0, sizeof(*pfd) * pfd_elms); 265 pfd[PFD_PIPE].fd = ibuf->fd; 266 pfd[PFD_PIPE].events = POLLIN; 267 if (ibuf->w.queued) 268 pfd[PFD_PIPE].events |= POLLOUT; 269 270 i = PFD_MAX; 271 TAILQ_FOREACH(cstr, &conf->constraints, entry) { 272 pfd[i].fd = cstr->fd; 273 pfd[i].events = POLLIN; 274 i++; 275 } 276 277 if ((nfds = poll(pfd, i, timeout)) == -1) 278 if (errno != EINTR) { 279 log_warn("poll error"); 280 quit = 1; 281 } 282 283 if (nfds == 0 && lconf.settime) { 284 lconf.settime = 0; 285 timeout = INFTIM; 286 log_init(lconf.debug, LOG_DAEMON); 287 log_verbose(lconf.verbose); 288 log_warnx("no reply received in time, skipping initial " 289 "time setting"); 290 if (!lconf.debug) 291 if (daemon(1, 0)) 292 fatal("daemon"); 293 } 294 295 if (nfds > 0 && (pfd[PFD_PIPE].revents & POLLOUT)) 296 if (msgbuf_write(&ibuf->w) <= 0 && errno != EAGAIN) { 297 log_warn("pipe write error (to child)"); 298 quit = 1; 299 } 300 301 if (nfds > 0 && pfd[PFD_PIPE].revents & POLLIN) { 302 nfds--; 303 if (dispatch_imsg(&lconf, argc0, argv0) == -1) 304 quit = 1; 305 } 306 307 for (j = PFD_MAX; nfds > 0 && j < i; j++) { 308 nfds -= priv_constraint_dispatch(&pfd[j]); 309 } 310 311 if (sigchld) { 312 check_child(); 313 sigchld = 0; 314 } 315 } 316 317 signal(SIGCHLD, SIG_DFL); 318 319 /* Close socket and start shutdown. */ 320 close(ibuf->fd); 321 322 do { 323 if ((pid = wait(NULL)) == -1 && 324 errno != EINTR && errno != ECHILD) 325 fatal("wait"); 326 } while (pid != -1 || (pid == -1 && errno == EINTR)); 327 328 msgbuf_clear(&ibuf->w); 329 free(ibuf); 330 log_info("Terminating"); 331 return (0); 332 } 333 334 void 335 check_child(void) 336 { 337 int status; 338 pid_t pid; 339 340 do { 341 pid = waitpid(WAIT_ANY, &status, WNOHANG); 342 if (pid <= 0) 343 continue; 344 345 priv_constraint_check_child(pid, status); 346 } while (pid > 0 || (pid == -1 && errno == EINTR)); 347 } 348 349 int 350 dispatch_imsg(struct ntpd_conf *lconf, int argc, char **argv) 351 { 352 struct imsg imsg; 353 int n; 354 double d; 355 356 if (((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) || n == 0) 357 return (-1); 358 359 for (;;) { 360 if ((n = imsg_get(ibuf, &imsg)) == -1) 361 return (-1); 362 363 if (n == 0) 364 break; 365 366 switch (imsg.hdr.type) { 367 case IMSG_ADJTIME: 368 if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(d)) 369 fatalx("invalid IMSG_ADJTIME received"); 370 memcpy(&d, imsg.data, sizeof(d)); 371 n = ntpd_adjtime(d); 372 imsg_compose(ibuf, IMSG_ADJTIME, 0, 0, -1, 373 &n, sizeof(n)); 374 break; 375 case IMSG_ADJFREQ: 376 if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(d)) 377 fatalx("invalid IMSG_ADJFREQ received"); 378 memcpy(&d, imsg.data, sizeof(d)); 379 ntpd_adjfreq(d, 1); 380 break; 381 case IMSG_SETTIME: 382 if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(d)) 383 fatalx("invalid IMSG_SETTIME received"); 384 if (!lconf->settime) 385 break; 386 log_init(lconf->debug, LOG_DAEMON); 387 log_verbose(lconf->verbose); 388 memcpy(&d, imsg.data, sizeof(d)); 389 ntpd_settime(d); 390 /* daemonize now */ 391 if (!lconf->debug) 392 if (daemon(1, 0)) 393 fatal("daemon"); 394 lconf->settime = 0; 395 timeout = INFTIM; 396 break; 397 case IMSG_CONSTRAINT_QUERY: 398 priv_constraint_msg(imsg.hdr.peerid, 399 imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE, 400 argc, argv); 401 break; 402 case IMSG_CONSTRAINT_KILL: 403 priv_constraint_kill(imsg.hdr.peerid); 404 break; 405 default: 406 break; 407 } 408 imsg_free(&imsg); 409 } 410 return (0); 411 } 412 413 void 414 reset_adjtime(void) 415 { 416 struct timeval tv; 417 418 timerclear(&tv); 419 if (adjtime(&tv, NULL) == -1) 420 log_warn("reset adjtime failed"); 421 } 422 423 int 424 ntpd_adjtime(double d) 425 { 426 struct timeval tv, olddelta; 427 int synced = 0; 428 static int firstadj = 1; 429 430 d += getoffset(); 431 if (d >= (double)LOG_NEGLIGIBLE_ADJTIME / 1000 || 432 d <= -1 * (double)LOG_NEGLIGIBLE_ADJTIME / 1000) 433 log_info("adjusting local clock by %fs", d); 434 else 435 log_debug("adjusting local clock by %fs", d); 436 d_to_tv(d, &tv); 437 if (adjtime(&tv, &olddelta) == -1) 438 log_warn("adjtime failed"); 439 else if (!firstadj && olddelta.tv_sec == 0 && olddelta.tv_usec == 0) 440 synced = 1; 441 firstadj = 0; 442 return (synced); 443 } 444 445 void 446 ntpd_adjfreq(double relfreq, int wrlog) 447 { 448 int64_t curfreq; 449 double ppmfreq; 450 int r; 451 452 if (adjfreq(NULL, &curfreq) == -1) { 453 log_warn("adjfreq failed"); 454 return; 455 } 456 457 /* 458 * adjfreq's unit is ns/s shifted left 32; convert relfreq to 459 * that unit before adding. We log values in part per million. 460 */ 461 curfreq += relfreq * 1e9 * (1LL << 32); 462 r = writefreq(curfreq / 1e9 / (1LL << 32)); 463 ppmfreq = relfreq * 1e6; 464 if (wrlog) { 465 if (ppmfreq >= LOG_NEGLIGIBLE_ADJFREQ || 466 ppmfreq <= -LOG_NEGLIGIBLE_ADJFREQ) 467 log_info("adjusting clock frequency by %f to %fppm%s", 468 ppmfreq, curfreq / 1e3 / (1LL << 32), 469 r ? "" : " (no drift file)"); 470 else 471 log_debug("adjusting clock frequency by %f to %fppm%s", 472 ppmfreq, curfreq / 1e3 / (1LL << 32), 473 r ? "" : " (no drift file)"); 474 } 475 476 if (adjfreq(&curfreq, NULL) == -1) 477 log_warn("adjfreq failed"); 478 } 479 480 void 481 ntpd_settime(double d) 482 { 483 struct timeval tv, curtime; 484 char buf[80]; 485 time_t tval; 486 487 if (gettimeofday(&curtime, NULL) == -1) { 488 log_warn("gettimeofday"); 489 return; 490 } 491 d_to_tv(d, &tv); 492 curtime.tv_usec += tv.tv_usec + 1000000; 493 curtime.tv_sec += tv.tv_sec - 1 + (curtime.tv_usec / 1000000); 494 curtime.tv_usec %= 1000000; 495 496 if (settimeofday(&curtime, NULL) == -1) { 497 log_warn("settimeofday"); 498 return; 499 } 500 tval = curtime.tv_sec; 501 strftime(buf, sizeof(buf), "%a %b %e %H:%M:%S %Z %Y", 502 localtime(&tval)); 503 log_info("set local clock to %s (offset %fs)", buf, d); 504 } 505 506 static FILE *freqfp; 507 508 void 509 readfreq(void) 510 { 511 int64_t current; 512 int fd; 513 double d; 514 515 fd = open(DRIFTFILE, O_RDWR); 516 if (fd == -1) { 517 log_warnx("creating new %s", DRIFTFILE); 518 current = 0; 519 if (adjfreq(¤t, NULL) == -1) 520 log_warn("adjfreq reset failed"); 521 freqfp = fopen(DRIFTFILE, "w"); 522 return; 523 } 524 525 freqfp = fdopen(fd, "r+"); 526 527 /* if we're adjusting frequency already, don't override */ 528 if (adjfreq(NULL, ¤t) == -1) 529 log_warn("adjfreq failed"); 530 else if (current == 0 && freqfp) { 531 if (fscanf(freqfp, "%lf", &d) == 1) { 532 d /= 1e6; /* scale from ppm */ 533 ntpd_adjfreq(d, 0); 534 } else 535 log_warnx("%s is empty", DRIFTFILE); 536 } 537 } 538 539 int 540 writefreq(double d) 541 { 542 int r; 543 static int warnonce = 1; 544 545 if (freqfp == NULL) 546 return 0; 547 rewind(freqfp); 548 r = fprintf(freqfp, "%.3f\n", d * 1e6); /* scale to ppm */ 549 if (r < 0 || fflush(freqfp) != 0) { 550 if (warnonce) { 551 log_warnx("can't write %s", DRIFTFILE); 552 warnonce = 0; 553 } 554 clearerr(freqfp); 555 return 0; 556 } 557 ftruncate(fileno(freqfp), ftello(freqfp)); 558 fsync(fileno(freqfp)); 559 return 1; 560 } 561 562 void 563 ctl_main(int argc, char *argv[]) 564 { 565 struct sockaddr_un sa; 566 struct imsg imsg; 567 struct imsgbuf *ibuf_ctl; 568 int fd, n, done, ch, action; 569 char *sockname; 570 571 sockname = CTLSOCKET; 572 573 if (argc < 2) { 574 usage(); 575 /* NOTREACHED */ 576 } 577 578 while ((ch = getopt(argc, argv, "s:")) != -1) { 579 switch (ch) { 580 case 's': 581 showopt = ctl_lookup_option(optarg, ctl_showopt_list); 582 if (showopt == NULL) { 583 warnx("Unknown show modifier '%s'", optarg); 584 usage(); 585 } 586 break; 587 default: 588 usage(); 589 /* NOTREACHED */ 590 } 591 } 592 593 action = -1; 594 if (showopt != NULL) { 595 switch (*showopt) { 596 case 'p': 597 action = CTL_SHOW_PEERS; 598 break; 599 case 's': 600 action = CTL_SHOW_STATUS; 601 break; 602 case 'S': 603 action = CTL_SHOW_SENSORS; 604 break; 605 case 'a': 606 action = CTL_SHOW_ALL; 607 break; 608 } 609 } 610 if (action == -1) 611 usage(); 612 /* NOTREACHED */ 613 614 if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) 615 err(1, "ntpctl: socket"); 616 617 memset(&sa, 0, sizeof(sa)); 618 sa.sun_family = AF_UNIX; 619 if (strlcpy(sa.sun_path, sockname, sizeof(sa.sun_path)) >= 620 sizeof(sa.sun_path)) 621 errx(1, "ctl socket name too long"); 622 if (connect(fd, (struct sockaddr *)&sa, sizeof(sa)) == -1) 623 err(1, "connect: %s", sockname); 624 625 if (pledge("stdio", NULL) == -1) 626 err(1, "pledge"); 627 628 if ((ibuf_ctl = malloc(sizeof(struct imsgbuf))) == NULL) 629 err(1, NULL); 630 imsg_init(ibuf_ctl, fd); 631 632 switch (action) { 633 case CTL_SHOW_STATUS: 634 imsg_compose(ibuf_ctl, IMSG_CTL_SHOW_STATUS, 635 0, 0, -1, NULL, 0); 636 break; 637 case CTL_SHOW_PEERS: 638 imsg_compose(ibuf_ctl, IMSG_CTL_SHOW_PEERS, 639 0, 0, -1, NULL, 0); 640 break; 641 case CTL_SHOW_SENSORS: 642 imsg_compose(ibuf_ctl, IMSG_CTL_SHOW_SENSORS, 643 0, 0, -1, NULL, 0); 644 break; 645 case CTL_SHOW_ALL: 646 imsg_compose(ibuf_ctl, IMSG_CTL_SHOW_ALL, 647 0, 0, -1, NULL, 0); 648 break; 649 default: 650 errx(1, "invalid action"); 651 break; /* NOTREACHED */ 652 } 653 654 while (ibuf_ctl->w.queued) 655 if (msgbuf_write(&ibuf_ctl->w) <= 0 && errno != EAGAIN) 656 err(1, "ibuf_ctl: msgbuf_write error"); 657 658 done = 0; 659 while (!done) { 660 if ((n = imsg_read(ibuf_ctl)) == -1 && errno != EAGAIN) 661 err(1, "ibuf_ctl: imsg_read error"); 662 if (n == 0) 663 errx(1, "ntpctl: pipe closed"); 664 665 while (!done) { 666 if ((n = imsg_get(ibuf_ctl, &imsg)) == -1) 667 err(1, "ibuf_ctl: imsg_get error"); 668 if (n == 0) 669 break; 670 671 switch (action) { 672 case CTL_SHOW_STATUS: 673 show_status_msg(&imsg); 674 done = 1; 675 break; 676 case CTL_SHOW_PEERS: 677 show_peer_msg(&imsg, 0); 678 if (imsg.hdr.type == 679 IMSG_CTL_SHOW_PEERS_END) 680 done = 1; 681 break; 682 case CTL_SHOW_SENSORS: 683 show_sensor_msg(&imsg, 0); 684 if (imsg.hdr.type == 685 IMSG_CTL_SHOW_SENSORS_END) 686 done = 1; 687 break; 688 case CTL_SHOW_ALL: 689 switch (imsg.hdr.type) { 690 case IMSG_CTL_SHOW_STATUS: 691 show_status_msg(&imsg); 692 break; 693 case IMSG_CTL_SHOW_PEERS: 694 show_peer_msg(&imsg, 1); 695 break; 696 case IMSG_CTL_SHOW_SENSORS: 697 show_sensor_msg(&imsg, 1); 698 break; 699 case IMSG_CTL_SHOW_PEERS_END: 700 case IMSG_CTL_SHOW_SENSORS_END: 701 /* do nothing */ 702 break; 703 case IMSG_CTL_SHOW_ALL_END: 704 done=1; 705 break; 706 default: 707 /* no action taken */ 708 break; 709 } 710 default: 711 /* no action taken */ 712 break; 713 } 714 imsg_free(&imsg); 715 } 716 } 717 close(fd); 718 free(ibuf_ctl); 719 exit(0); 720 } 721 722 const char * 723 ctl_lookup_option(char *cmd, const char **list) 724 { 725 const char *item = NULL; 726 if (cmd != NULL && *cmd) 727 for (; *list; list++) 728 if (!strncmp(cmd, *list, strlen(cmd))) { 729 if (item == NULL) 730 item = *list; 731 else 732 errx(1, "%s is ambiguous", cmd); 733 } 734 return (item); 735 } 736 737 void 738 show_status_msg(struct imsg *imsg) 739 { 740 struct ctl_show_status *cstatus; 741 double clock_offset; 742 struct timeval tv; 743 744 if (imsg->hdr.len != IMSG_HEADER_SIZE + sizeof(struct ctl_show_status)) 745 fatalx("invalid IMSG_CTL_SHOW_STATUS received"); 746 747 cstatus = (struct ctl_show_status *)imsg->data; 748 749 if (cstatus->peercnt > 0) 750 printf("%d/%d peers valid, ", 751 cstatus->valid_peers, cstatus->peercnt); 752 753 if (cstatus->sensorcnt > 0) 754 printf("%d/%d sensors valid, ", 755 cstatus->valid_sensors, cstatus->sensorcnt); 756 757 if (cstatus->constraint_median) { 758 tv.tv_sec = cstatus->constraint_median + 759 (getmonotime() - cstatus->constraint_last); 760 tv.tv_usec = 0; 761 d_to_tv(gettime_from_timeval(&tv) - gettime(), &tv); 762 printf("constraint offset %llds", (long long)tv.tv_sec); 763 if (cstatus->constraint_errors) 764 printf(" (%d errors)", 765 cstatus->constraint_errors); 766 printf(", "); 767 } 768 769 if (cstatus->peercnt + cstatus->sensorcnt == 0) 770 printf("no peers and no sensors configured\n"); 771 772 if (cstatus->synced == 1) 773 printf("clock synced, stratum %u\n", cstatus->stratum); 774 else { 775 printf("clock unsynced"); 776 clock_offset = cstatus->clock_offset < 0 ? 777 -1.0 * cstatus->clock_offset : cstatus->clock_offset; 778 if (clock_offset > 5e-7) 779 printf(", clock offset is %.3fms\n", 780 cstatus->clock_offset); 781 else 782 printf("\n"); 783 } 784 } 785 786 void 787 show_peer_msg(struct imsg *imsg, int calledfromshowall) 788 { 789 struct ctl_show_peer *cpeer; 790 int cnt; 791 char stratum[3]; 792 static int firsttime = 1; 793 794 if (imsg->hdr.type == IMSG_CTL_SHOW_PEERS_END) { 795 if (imsg->hdr.len != IMSG_HEADER_SIZE + sizeof(cnt)) 796 fatalx("invalid IMSG_CTL_SHOW_PEERS_END received"); 797 memcpy(&cnt, imsg->data, sizeof(cnt)); 798 if (cnt == 0) 799 printf("no peers configured\n"); 800 return; 801 } 802 803 if (imsg->hdr.len != IMSG_HEADER_SIZE + sizeof(struct ctl_show_peer)) 804 fatalx("invalid IMSG_CTL_SHOW_PEERS received"); 805 806 cpeer = (struct ctl_show_peer *)imsg->data; 807 808 if (strlen(cpeer->peer_desc) > MAX_DISPLAY_WIDTH - 1) 809 fatalx("peer_desc is too long"); 810 811 if (firsttime) { 812 firsttime = 0; 813 if (calledfromshowall) 814 printf("\n"); 815 printf("peer\n wt tl st next poll " 816 "offset delay jitter\n"); 817 } 818 819 if (cpeer->stratum > 0) 820 snprintf(stratum, sizeof(stratum), "%2u", cpeer->stratum); 821 else 822 strlcpy(stratum, " -", sizeof (stratum)); 823 824 printf("%s\n %1s %2u %2u %2s %4llds %4llds", 825 cpeer->peer_desc, cpeer->syncedto == 1 ? "*" : " ", 826 cpeer->weight, cpeer->trustlevel, stratum, 827 (long long)cpeer->next, (long long)cpeer->poll); 828 829 if (cpeer->trustlevel >= TRUSTLEVEL_BADPEER) 830 printf(" %12.3fms %9.3fms %8.3fms\n", cpeer->offset, 831 cpeer->delay, cpeer->jitter); 832 else 833 printf(" ---- peer not valid ----\n"); 834 835 } 836 837 void 838 show_sensor_msg(struct imsg *imsg, int calledfromshowall) 839 { 840 struct ctl_show_sensor *csensor; 841 int cnt; 842 static int firsttime = 1; 843 844 if (imsg->hdr.type == IMSG_CTL_SHOW_SENSORS_END) { 845 if (imsg->hdr.len != IMSG_HEADER_SIZE + sizeof(cnt)) 846 fatalx("invalid IMSG_CTL_SHOW_SENSORS_END received"); 847 memcpy(&cnt, imsg->data, sizeof(cnt)); 848 if (cnt == 0) 849 printf("no sensors configured\n"); 850 return; 851 } 852 853 if (imsg->hdr.len != IMSG_HEADER_SIZE + sizeof(struct ctl_show_sensor)) 854 fatalx("invalid IMSG_CTL_SHOW_SENSORS received"); 855 856 csensor = (struct ctl_show_sensor *)imsg->data; 857 858 if (strlen(csensor->sensor_desc) > MAX_DISPLAY_WIDTH - 1) 859 fatalx("sensor_desc is too long"); 860 861 if (firsttime) { 862 firsttime = 0; 863 if (calledfromshowall) 864 printf("\n"); 865 printf("sensor\n wt gd st next poll " 866 "offset correction\n"); 867 } 868 869 printf("%s\n %1s %2u %2u %2u %4llds %4llds", 870 csensor->sensor_desc, csensor->syncedto == 1 ? "*" : " ", 871 csensor->weight, csensor->good, csensor->stratum, 872 (long long)csensor->next, (long long)csensor->poll); 873 874 if (csensor->good == 1) 875 printf(" %11.3fms %9.3fms\n", 876 csensor->offset, csensor->correction); 877 else 878 printf(" - sensor not valid -\n"); 879 880 } 881