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(¤t, 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, ¤t) == -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