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