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