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