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