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