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