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