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