Bug Summary

File:src/usr.sbin/ntpd/ntpd.c
Warning:line 196, column 2
Value stored to 'argv' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

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