ntpq-subs.c revision 1.1.1.2 1 /* $NetBSD: ntpq-subs.c,v 1.1.1.2 2012/01/31 21:26:53 kardel Exp $ */
2
3 /*
4 * ntpq_ops.c - subroutines which are called to perform operations by ntpq
5 */
6
7 #include <stdio.h>
8 #include <ctype.h>
9 #include <sys/types.h>
10 #include <sys/time.h>
11
12 #include "ntp_stdlib.h"
13 #include "ntpq.h"
14 #include "ntpq-opts.h"
15
16 extern char * chosts[];
17 extern char currenthost[];
18 extern int currenthostisnum;
19 extern int numhosts;
20 int maxhostlen;
21
22 /*
23 * Declarations for command handlers in here
24 */
25 static associd_t checkassocid (u_int32);
26 static struct varlist *findlistvar (struct varlist *, char *);
27 static void doaddvlist (struct varlist *, const char *);
28 static void dormvlist (struct varlist *, const char *);
29 static void doclearvlist (struct varlist *);
30 static void makequerydata (struct varlist *, int *, char *);
31 static int doquerylist (struct varlist *, int, associd_t, int,
32 u_short *, int *, const char **);
33 static void doprintvlist (struct varlist *, FILE *);
34 static void addvars (struct parse *, FILE *);
35 static void rmvars (struct parse *, FILE *);
36 static void clearvars (struct parse *, FILE *);
37 static void showvars (struct parse *, FILE *);
38 static int dolist (struct varlist *, associd_t, int, int,
39 FILE *);
40 static void readlist (struct parse *, FILE *);
41 static void writelist (struct parse *, FILE *);
42 static void readvar (struct parse *, FILE *);
43 static void writevar (struct parse *, FILE *);
44 static void clocklist (struct parse *, FILE *);
45 static void clockvar (struct parse *, FILE *);
46 static int findassidrange (u_int32, u_int32, int *, int *);
47 static void mreadlist (struct parse *, FILE *);
48 static void mreadvar (struct parse *, FILE *);
49 static int dogetassoc (FILE *);
50 static void printassoc (int, FILE *);
51 static void associations (struct parse *, FILE *);
52 static void lassociations (struct parse *, FILE *);
53 static void passociations (struct parse *, FILE *);
54 static void lpassociations (struct parse *, FILE *);
55
56 #ifdef UNUSED
57 static void radiostatus (struct parse *, FILE *);
58 #endif /* UNUSED */
59
60 static void pstatus (struct parse *, FILE *);
61 static long when (l_fp *, l_fp *, l_fp *);
62 static char * prettyinterval (char *, size_t, long);
63 static int doprintpeers (struct varlist *, int, int, int, const char *, FILE *, int);
64 static int dogetpeers (struct varlist *, associd_t, FILE *, int);
65 static void dopeers (int, FILE *, int);
66 static void peers (struct parse *, FILE *);
67 static void lpeers (struct parse *, FILE *);
68 static void doopeers (int, FILE *, int);
69 static void opeers (struct parse *, FILE *);
70 static void lopeers (struct parse *, FILE *);
71 static void config (struct parse *, FILE *);
72 static void saveconfig (struct parse *, FILE *);
73 static void config_from_file(struct parse *, FILE *);
74
75
76 /*
77 * Commands we understand. Ntpdc imports this.
78 */
79 struct xcmd opcmds[] = {
80 { "saveconfig", saveconfig, { NTP_STR, NO, NO, NO },
81 { "filename", "", "", ""},
82 "save ntpd configuration to file, . for current config file"},
83 { "associations", associations, { NO, NO, NO, NO },
84 { "", "", "", "" },
85 "print list of association ID's and statuses for the server's peers" },
86 { "passociations", passociations, { NO, NO, NO, NO },
87 { "", "", "", "" },
88 "print list of associations returned by last associations command" },
89 { "lassociations", lassociations, { NO, NO, NO, NO },
90 { "", "", "", "" },
91 "print list of associations including all client information" },
92 { "lpassociations", lpassociations, { NO, NO, NO, NO },
93 { "", "", "", "" },
94 "print last obtained list of associations, including client information" },
95 { "addvars", addvars, { NTP_STR, NO, NO, NO },
96 { "name[=value][,...]", "", "", "" },
97 "add variables to the variable list or change their values" },
98 { "rmvars", rmvars, { NTP_STR, NO, NO, NO },
99 { "name[,...]", "", "", "" },
100 "remove variables from the variable list" },
101 { "clearvars", clearvars, { NO, NO, NO, NO },
102 { "", "", "", "" },
103 "remove all variables from the variable list" },
104 { "showvars", showvars, { NO, NO, NO, NO },
105 { "", "", "", "" },
106 "print variables on the variable list" },
107 { "readlist", readlist, { OPT|NTP_UINT, NO, NO, NO },
108 { "assocID", "", "", "" },
109 "read the system or peer variables included in the variable list" },
110 { "rl", readlist, { OPT|NTP_UINT, NO, NO, NO },
111 { "assocID", "", "", "" },
112 "read the system or peer variables included in the variable list" },
113 { "writelist", writelist, { OPT|NTP_UINT, NO, NO, NO },
114 { "assocID", "", "", "" },
115 "write the system or peer variables included in the variable list" },
116 { "readvar", readvar, { OPT|NTP_UINT, OPT|NTP_STR, NO, NO },
117 { "assocID", "name=value[,...]", "", "" },
118 "read system or peer variables" },
119 { "rv", readvar, { OPT|NTP_UINT, OPT|NTP_STR, NO, NO },
120 { "assocID", "name=value[,...]", "", "" },
121 "read system or peer variables" },
122 { "writevar", writevar, { NTP_UINT, NTP_STR, NO, NO },
123 { "assocID", "name=value,[...]", "", "" },
124 "write system or peer variables" },
125 { "mreadlist", mreadlist, { NTP_UINT, NTP_UINT, NO, NO },
126 { "assocID", "assocID", "", "" },
127 "read the peer variables in the variable list for multiple peers" },
128 { "mrl", mreadlist, { NTP_UINT, NTP_UINT, NO, NO },
129 { "assocID", "assocID", "", "" },
130 "read the peer variables in the variable list for multiple peers" },
131 { "mreadvar", mreadvar, { NTP_UINT, NTP_UINT, OPT|NTP_STR, NO },
132 { "assocID", "assocID", "name=value[,...]", "" },
133 "read peer variables from multiple peers" },
134 { "mrv", mreadvar, { NTP_UINT, NTP_UINT, OPT|NTP_STR, NO },
135 { "assocID", "assocID", "name=value[,...]", "" },
136 "read peer variables from multiple peers" },
137 { "clocklist", clocklist, { OPT|NTP_UINT, NO, NO, NO },
138 { "assocID", "", "", "" },
139 "read the clock variables included in the variable list" },
140 { "cl", clocklist, { OPT|NTP_UINT, NO, NO, NO },
141 { "assocID", "", "", "" },
142 "read the clock variables included in the variable list" },
143 { "clockvar", clockvar, { OPT|NTP_UINT, OPT|NTP_STR, NO, NO },
144 { "assocID", "name=value[,...]", "", "" },
145 "read clock variables" },
146 { "cv", clockvar, { OPT|NTP_UINT, OPT|NTP_STR, NO, NO },
147 { "assocID", "name=value[,...]", "", "" },
148 "read clock variables" },
149 { "pstatus", pstatus, { NTP_UINT, NO, NO, NO },
150 { "assocID", "", "", "" },
151 "print status information returned for a peer" },
152 { "peers", peers, { OPT|IP_VERSION, NO, NO, NO },
153 { "-4|-6", "", "", "" },
154 "obtain and print a list of the server's peers [IP version]" },
155 { "lpeers", lpeers, { OPT|IP_VERSION, NO, NO, NO },
156 { "-4|-6", "", "", "" },
157 "obtain and print a list of all peers and clients [IP version]" },
158 { "opeers", opeers, { OPT|IP_VERSION, NO, NO, NO },
159 { "-4|-6", "", "", "" },
160 "print peer list the old way, with dstadr shown rather than refid [IP version]" },
161 { "lopeers", lopeers, { OPT|IP_VERSION, NO, NO, NO },
162 { "-4|-6", "", "", "" },
163 "obtain and print a list of all peers and clients showing dstadr [IP version]" },
164 { ":config", config, { NTP_STR, NO, NO, NO },
165 { "<configuration command line>", "", "", "" },
166 "send a remote configuration command to ntpd" },
167 { "config-from-file", config_from_file, { NTP_STR, NO, NO, NO },
168 { "<configuration filename>", "", "", "" },
169 "configure ntpd using the configuration filename" },
170 { 0, 0, { NO, NO, NO, NO },
171 { "-4|-6", "", "", "" }, "" }
172 };
173
174
175 /*
176 * Variable list data space
177 */
178 #define MAXLINE 512 /* maximum length of a line */
179 #define MAXLIST 64 /* maximum number of variables in list */
180 #define LENHOSTNAME 256 /* host name is 256 characters long */
181 /*
182 * Old CTL_PST defines for version 2.
183 */
184 #define OLD_CTL_PST_CONFIG 0x80
185 #define OLD_CTL_PST_AUTHENABLE 0x40
186 #define OLD_CTL_PST_AUTHENTIC 0x20
187 #define OLD_CTL_PST_REACH 0x10
188 #define OLD_CTL_PST_SANE 0x08
189 #define OLD_CTL_PST_DISP 0x04
190
191 #define OLD_CTL_PST_SEL_REJECT 0
192 #define OLD_CTL_PST_SEL_SELCAND 1
193 #define OLD_CTL_PST_SEL_SYNCCAND 2
194 #define OLD_CTL_PST_SEL_SYSPEER 3
195
196 char flash2[] = " .+* "; /* flash decode for version 2 */
197 char flash3[] = " x.-+#*o"; /* flash decode for peer status version 3 */
198
199 struct varlist {
200 char *name;
201 char *value;
202 } g_varlist[MAXLIST] = { { 0, 0 } };
203
204 /*
205 * Imported from ntpq.c
206 */
207 extern int showhostnames;
208 extern int rawmode;
209 extern struct servent *server_entry;
210 extern struct association assoc_cache[];
211 extern int numassoc;
212 extern u_char pktversion;
213 extern struct ctl_var peer_var[];
214
215 /*
216 * For quick string comparisons
217 */
218 #define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0)
219
220
221 /*
222 * checkassocid - return the association ID, checking to see if it is valid
223 */
224 static associd_t
225 checkassocid(
226 u_int32 value
227 )
228 {
229 associd_t associd;
230 u_long ulvalue;
231
232 associd = (associd_t)value;
233 if (0 == associd || value != associd) {
234 ulvalue = value;
235 fprintf(stderr,
236 "***Invalid association ID %lu specified\n",
237 ulvalue);
238 return 0;
239 }
240
241 return associd;
242 }
243
244
245 /*
246 * findlistvar - look for the named variable in a list and return if found
247 */
248 static struct varlist *
249 findlistvar(
250 struct varlist *list,
251 char *name
252 )
253 {
254 register struct varlist *vl;
255
256 for (vl = list; vl < list + MAXLIST && vl->name != 0; vl++)
257 if (STREQ(name, vl->name))
258 return vl;
259 if (vl < list + MAXLIST)
260 return vl;
261 return (struct varlist *)0;
262 }
263
264
265 /*
266 * doaddvlist - add variable(s) to the variable list
267 */
268 static void
269 doaddvlist(
270 struct varlist *vlist,
271 const char *vars
272 )
273 {
274 register struct varlist *vl;
275 int len;
276 char *name;
277 char *value;
278
279 len = strlen(vars);
280 while (nextvar(&len, &vars, &name, &value)) {
281 vl = findlistvar(vlist, name);
282 if (vl == 0) {
283 (void) fprintf(stderr, "Variable list full\n");
284 return;
285 }
286
287 if (vl->name == 0) {
288 vl->name = estrdup(name);
289 } else if (vl->value != 0) {
290 free(vl->value);
291 vl->value = 0;
292 }
293
294 if (value != 0)
295 vl->value = estrdup(value);
296 }
297 }
298
299
300 /*
301 * dormvlist - remove variable(s) from the variable list
302 */
303 static void
304 dormvlist(
305 struct varlist *vlist,
306 const char *vars
307 )
308 {
309 register struct varlist *vl;
310 int len;
311 char *name;
312 char *value;
313
314 len = strlen(vars);
315 while (nextvar(&len, &vars, &name, &value)) {
316 vl = findlistvar(vlist, name);
317 if (vl == 0 || vl->name == 0) {
318 (void) fprintf(stderr, "Variable `%s' not found\n",
319 name);
320 } else {
321 free((void *)vl->name);
322 if (vl->value != 0)
323 free(vl->value);
324 for ( ; (vl+1) < (g_varlist + MAXLIST)
325 && (vl+1)->name != 0; vl++) {
326 vl->name = (vl+1)->name;
327 vl->value = (vl+1)->value;
328 }
329 vl->name = vl->value = 0;
330 }
331 }
332 }
333
334
335 /*
336 * doclearvlist - clear a variable list
337 */
338 static void
339 doclearvlist(
340 struct varlist *vlist
341 )
342 {
343 register struct varlist *vl;
344
345 for (vl = vlist; vl < vlist + MAXLIST && vl->name != 0; vl++) {
346 free((void *)vl->name);
347 vl->name = 0;
348 if (vl->value != 0) {
349 free(vl->value);
350 vl->value = 0;
351 }
352 }
353 }
354
355
356 /*
357 * makequerydata - form a data buffer to be included with a query
358 */
359 static void
360 makequerydata(
361 struct varlist *vlist,
362 int *datalen,
363 char *data
364 )
365 {
366 register struct varlist *vl;
367 register char *cp, *cpend;
368 register int namelen, valuelen;
369 register int totallen;
370
371 cp = data;
372 cpend = data + *datalen;
373
374 for (vl = vlist; vl < vlist + MAXLIST && vl->name != 0; vl++) {
375 namelen = strlen(vl->name);
376 if (vl->value == 0)
377 valuelen = 0;
378 else
379 valuelen = strlen(vl->value);
380 totallen = namelen + valuelen + (valuelen != 0) + (cp != data);
381 if (cp + totallen > cpend)
382 break;
383
384 if (cp != data)
385 *cp++ = ',';
386 memmove(cp, vl->name, (unsigned)namelen);
387 cp += namelen;
388 if (valuelen != 0) {
389 *cp++ = '=';
390 memmove(cp, vl->value, (unsigned)valuelen);
391 cp += valuelen;
392 }
393 }
394 *datalen = cp - data;
395 }
396
397
398 /*
399 * doquerylist - send a message including variables in a list
400 */
401 static int
402 doquerylist(
403 struct varlist *vlist,
404 int op,
405 associd_t associd,
406 int auth,
407 u_short *rstatus,
408 int *dsize,
409 const char **datap
410 )
411 {
412 char data[CTL_MAX_DATA_LEN];
413 int datalen;
414
415 datalen = sizeof(data);
416 makequerydata(vlist, &datalen, data);
417
418 return doquery(op, associd, auth, datalen, data, rstatus,
419 dsize, datap);
420 }
421
422
423 /*
424 * doprintvlist - print the variables on a list
425 */
426 static void
427 doprintvlist(
428 struct varlist *vlist,
429 FILE *fp
430 )
431 {
432 register struct varlist *vl;
433
434 if (vlist->name == 0) {
435 (void) fprintf(fp, "No variables on list\n");
436 } else {
437 for (vl = vlist; vl < vlist + MAXLIST && vl->name != 0; vl++) {
438 if (vl->value == 0) {
439 (void) fprintf(fp, "%s\n", vl->name);
440 } else {
441 (void) fprintf(fp, "%s=%s\n",
442 vl->name, vl->value);
443 }
444 }
445 }
446 }
447
448 /*
449 * addvars - add variables to the variable list
450 */
451 /*ARGSUSED*/
452 static void
453 addvars(
454 struct parse *pcmd,
455 FILE *fp
456 )
457 {
458 doaddvlist(g_varlist, pcmd->argval[0].string);
459 }
460
461
462 /*
463 * rmvars - remove variables from the variable list
464 */
465 /*ARGSUSED*/
466 static void
467 rmvars(
468 struct parse *pcmd,
469 FILE *fp
470 )
471 {
472 dormvlist(g_varlist, pcmd->argval[0].string);
473 }
474
475
476 /*
477 * clearvars - clear the variable list
478 */
479 /*ARGSUSED*/
480 static void
481 clearvars(
482 struct parse *pcmd,
483 FILE *fp
484 )
485 {
486 doclearvlist(g_varlist);
487 }
488
489
490 /*
491 * showvars - show variables on the variable list
492 */
493 /*ARGSUSED*/
494 static void
495 showvars(
496 struct parse *pcmd,
497 FILE *fp
498 )
499 {
500 doprintvlist(g_varlist, fp);
501 }
502
503
504 /*
505 * dolist - send a request with the given list of variables
506 */
507 static int
508 dolist(
509 struct varlist *vlist,
510 associd_t associd,
511 int op,
512 int type,
513 FILE *fp
514 )
515 {
516 const char *datap;
517 int res;
518 int dsize;
519 u_short rstatus;
520 int quiet;
521
522 /*
523 * if we're asking for specific variables don't include the
524 * status header line in the output.
525 */
526 if (old_rv)
527 quiet = 0;
528 else
529 quiet = (vlist->name != NULL);
530
531 res = doquerylist(vlist, op, associd, 0, &rstatus, &dsize, &datap);
532
533 if (res != 0)
534 return 0;
535
536 if (numhosts > 1)
537 (void) fprintf(fp, "server=%s ", currenthost);
538 if (dsize == 0) {
539 if (associd == 0)
540 (void) fprintf(fp, "No system%s variables returned\n",
541 (type == TYPE_CLOCK) ? " clock" : "");
542 else
543 (void) fprintf(fp,
544 "No information returned for%s association %u\n",
545 (type == TYPE_CLOCK) ? " clock" : "", associd);
546 return 1;
547 }
548
549 if (!quiet)
550 fprintf(fp,"associd=%d ",associd);
551 printvars(dsize, datap, (int)rstatus, type, quiet, fp);
552 return 1;
553 }
554
555
556 /*
557 * readlist - send a read variables request with the variables on the list
558 */
559 static void
560 readlist(
561 struct parse *pcmd,
562 FILE *fp
563 )
564 {
565 associd_t associd;
566 int type;
567
568 if (pcmd->nargs == 0) {
569 associd = 0;
570 } else {
571 /* HMS: I think we want the u_int32 target here, not the u_long */
572 if (pcmd->argval[0].uval == 0)
573 associd = 0;
574 else if ((associd = checkassocid(pcmd->argval[0].uval)) == 0)
575 return;
576 }
577
578 type = (0 == associd)
579 ? TYPE_SYS
580 : TYPE_PEER;
581 dolist(g_varlist, associd, CTL_OP_READVAR, type, fp);
582 }
583
584
585 /*
586 * writelist - send a write variables request with the variables on the list
587 */
588 static void
589 writelist(
590 struct parse *pcmd,
591 FILE *fp
592 )
593 {
594 const char *datap;
595 int res;
596 associd_t associd;
597 int dsize;
598 u_short rstatus;
599
600 if (pcmd->nargs == 0) {
601 associd = 0;
602 } else {
603 /* HMS: Do we really want uval here? */
604 if (pcmd->argval[0].uval == 0)
605 associd = 0;
606 else if ((associd = checkassocid(pcmd->argval[0].uval)) == 0)
607 return;
608 }
609
610 res = doquerylist(g_varlist, CTL_OP_WRITEVAR, associd, 1, &rstatus,
611 &dsize, &datap);
612
613 if (res != 0)
614 return;
615
616 if (numhosts > 1)
617 (void) fprintf(fp, "server=%s ", currenthost);
618 if (dsize == 0)
619 (void) fprintf(fp, "done! (no data returned)\n");
620 else {
621 (void) fprintf(fp,"associd=%d ",associd);
622 printvars(dsize, datap, (int)rstatus,
623 (associd != 0) ? TYPE_PEER : TYPE_SYS, 0, fp);
624 }
625 return;
626 }
627
628
629 /*
630 * readvar - send a read variables request with the specified variables
631 */
632 static void
633 readvar(
634 struct parse *pcmd,
635 FILE *fp
636 )
637 {
638 associd_t associd;
639 int type;
640 struct varlist tmplist[MAXLIST];
641
642
643 /* HMS: uval? */
644 if (pcmd->nargs == 0 || pcmd->argval[0].uval == 0)
645 associd = 0;
646 else if ((associd = checkassocid(pcmd->argval[0].uval)) == 0)
647 return;
648
649 memset(tmplist, 0, sizeof(tmplist));
650 if (pcmd->nargs >= 2)
651 doaddvlist(tmplist, pcmd->argval[1].string);
652
653 type = (0 == associd)
654 ? TYPE_SYS
655 : TYPE_PEER;
656 dolist(tmplist, associd, CTL_OP_READVAR, type, fp);
657
658 doclearvlist(tmplist);
659 }
660
661
662 /*
663 * writevar - send a write variables request with the specified variables
664 */
665 static void
666 writevar(
667 struct parse *pcmd,
668 FILE *fp
669 )
670 {
671 const char *datap;
672 int res;
673 associd_t associd;
674 int type;
675 int dsize;
676 u_short rstatus;
677 struct varlist tmplist[MAXLIST];
678
679 /* HMS: uval? */
680 if (pcmd->argval[0].uval == 0)
681 associd = 0;
682 else if ((associd = checkassocid(pcmd->argval[0].uval)) == 0)
683 return;
684
685 memset((char *)tmplist, 0, sizeof(tmplist));
686 doaddvlist(tmplist, pcmd->argval[1].string);
687
688 res = doquerylist(tmplist, CTL_OP_WRITEVAR, associd, 1, &rstatus,
689 &dsize, &datap);
690
691 doclearvlist(tmplist);
692
693 if (res != 0)
694 return;
695
696 if (numhosts > 1)
697 fprintf(fp, "server=%s ", currenthost);
698 if (dsize == 0)
699 fprintf(fp, "done! (no data returned)\n");
700 else {
701 fprintf(fp,"associd=%d ",associd);
702 type = (0 == associd)
703 ? TYPE_SYS
704 : TYPE_PEER;
705 printvars(dsize, datap, (int)rstatus, type, 0, fp);
706 }
707 return;
708 }
709
710
711 /*
712 * clocklist - send a clock variables request with the variables on the list
713 */
714 static void
715 clocklist(
716 struct parse *pcmd,
717 FILE *fp
718 )
719 {
720 associd_t associd;
721
722 /* HMS: uval? */
723 if (pcmd->nargs == 0) {
724 associd = 0;
725 } else {
726 if (pcmd->argval[0].uval == 0)
727 associd = 0;
728 else if ((associd = checkassocid(pcmd->argval[0].uval)) == 0)
729 return;
730 }
731
732 dolist(g_varlist, associd, CTL_OP_READCLOCK, TYPE_CLOCK, fp);
733 }
734
735
736 /*
737 * clockvar - send a clock variables request with the specified variables
738 */
739 static void
740 clockvar(
741 struct parse *pcmd,
742 FILE *fp
743 )
744 {
745 associd_t associd;
746 struct varlist tmplist[MAXLIST];
747
748 /* HMS: uval? */
749 if (pcmd->nargs == 0 || pcmd->argval[0].uval == 0)
750 associd = 0;
751 else if ((associd = checkassocid(pcmd->argval[0].uval)) == 0)
752 return;
753
754 memset(tmplist, 0, sizeof(tmplist));
755 if (pcmd->nargs >= 2)
756 doaddvlist(tmplist, pcmd->argval[1].string);
757
758 dolist(tmplist, associd, CTL_OP_READCLOCK, TYPE_CLOCK, fp);
759
760 doclearvlist(tmplist);
761 }
762
763
764 /*
765 * findassidrange - verify a range of association ID's
766 */
767 static int
768 findassidrange(
769 u_int32 assid1,
770 u_int32 assid2,
771 int *from,
772 int *to
773 )
774 {
775 associd_t assids[2];
776 int ind[COUNTOF(assids)];
777 int i;
778 size_t a;
779
780 assids[0] = checkassocid(assid1);
781 if (0 == assids[0])
782 return 0;
783 assids[1] = checkassocid(assid2);
784 if (0 == assids[1])
785 return 0;
786
787 for (a = 0; a < COUNTOF(assids); a++) {
788 ind[a] = -1;
789 for (i = 0; i < numassoc; i++)
790 if (assoc_cache[i].assid == assids[a])
791 ind[a] = i;
792 }
793 for (a = 0; a < COUNTOF(assids); a++)
794 if (-1 == ind[a]) {
795 fprintf(stderr,
796 "***Association ID %u not found in list\n",
797 assids[a]);
798 return 0;
799 }
800
801 if (ind[0] < ind[1]) {
802 *from = ind[0];
803 *to = ind[1];
804 } else {
805 *to = ind[0];
806 *from = ind[1];
807 }
808 return 1;
809 }
810
811
812
813 /*
814 * mreadlist - send a read variables request for multiple associations
815 */
816 static void
817 mreadlist(
818 struct parse *pcmd,
819 FILE *fp
820 )
821 {
822 int i;
823 int from;
824 int to;
825
826 /* HMS: uval? */
827 if (!findassidrange(pcmd->argval[0].uval, pcmd->argval[1].uval,
828 &from, &to))
829 return;
830
831 for (i = from; i <= to; i++) {
832 if (i != from)
833 (void) fprintf(fp, "\n");
834 if (!dolist(g_varlist, (int)assoc_cache[i].assid,
835 CTL_OP_READVAR, TYPE_PEER, fp))
836 return;
837 }
838 return;
839 }
840
841
842 /*
843 * mreadvar - send a read variables request for multiple associations
844 */
845 static void
846 mreadvar(
847 struct parse *pcmd,
848 FILE *fp
849 )
850 {
851 int i;
852 int from;
853 int to;
854 struct varlist tmplist[MAXLIST];
855 struct varlist *pvars;
856
857 /* HMS: uval? */
858 if (!findassidrange(pcmd->argval[0].uval, pcmd->argval[1].uval,
859 &from, &to))
860 return;
861
862 if (pcmd->nargs >= 3) {
863 memset(tmplist, 0, sizeof(tmplist));
864 doaddvlist(tmplist, pcmd->argval[2].string);
865 pvars = tmplist;
866 } else {
867 pvars = g_varlist;
868 }
869
870 for (i = from; i <= to; i++) {
871 if (i != from)
872 fprintf(fp, "\n");
873 if (!dolist(pvars, (int)assoc_cache[i].assid,
874 CTL_OP_READVAR, TYPE_PEER, fp))
875 break;
876 }
877 doclearvlist(tmplist);
878 return;
879 }
880
881
882 /*
883 * dogetassoc - query the host for its list of associations
884 */
885 static int
886 dogetassoc(
887 FILE *fp
888 )
889 {
890 const char *datap;
891 int res;
892 int dsize;
893 u_short rstatus;
894
895 res = doquery(CTL_OP_READSTAT, 0, 0, 0, (char *)0, &rstatus,
896 &dsize, &datap);
897
898 if (res != 0)
899 return 0;
900
901 if (dsize == 0) {
902 if (numhosts > 1)
903 (void) fprintf(fp, "server=%s ", currenthost);
904 (void) fprintf(fp, "No association ID's returned\n");
905 return 0;
906 }
907
908 if (dsize & 0x3) {
909 if (numhosts > 1)
910 (void) fprintf(stderr, "server=%s ", currenthost);
911 (void) fprintf(stderr,
912 "***Server returned %d octets, should be multiple of 4\n",
913 dsize);
914 return 0;
915 }
916
917 numassoc = 0;
918 while (dsize > 0) {
919 assoc_cache[numassoc].assid = ntohs(*((const u_short *)datap));
920 datap += sizeof(u_short);
921 assoc_cache[numassoc].status = ntohs(*((const u_short *)datap));
922 datap += sizeof(u_short);
923 if (++numassoc >= MAXASSOC)
924 break;
925 dsize -= sizeof(u_short) + sizeof(u_short);
926 }
927 sortassoc();
928 return 1;
929 }
930
931
932 /*
933 * printassoc - print the current list of associations
934 */
935 static void
936 printassoc(
937 int showall,
938 FILE *fp
939 )
940 {
941 register char *bp;
942 int i;
943 u_char statval;
944 int event;
945 u_long event_count;
946 const char *conf;
947 const char *reach;
948 const char *auth;
949 const char *condition = "";
950 const char *last_event;
951 const char *cnt;
952 char buf[128];
953
954 if (numassoc == 0) {
955 (void) fprintf(fp, "No association ID's in list\n");
956 return;
957 }
958
959 /*
960 * Output a header
961 */
962 (void) fprintf(fp,
963 "\nind assid status conf reach auth condition last_event cnt\n");
964 (void) fprintf(fp,
965 "===========================================================\n");
966 for (i = 0; i < numassoc; i++) {
967 statval = (u_char) CTL_PEER_STATVAL(assoc_cache[i].status);
968 if (!showall && !(statval & (CTL_PST_CONFIG|CTL_PST_REACH)))
969 continue;
970 event = CTL_PEER_EVENT(assoc_cache[i].status);
971 event_count = CTL_PEER_NEVNT(assoc_cache[i].status);
972 if (statval & CTL_PST_CONFIG)
973 conf = "yes";
974 else
975 conf = "no";
976 if (statval & CTL_PST_BCAST) {
977 reach = "none";
978 if (statval & CTL_PST_AUTHENABLE)
979 auth = "yes";
980 else
981 auth = "none";
982 } else {
983 if (statval & CTL_PST_REACH)
984 reach = "yes";
985 else
986 reach = "no";
987 if (statval & CTL_PST_AUTHENABLE) {
988 if (statval & CTL_PST_AUTHENTIC)
989 auth = "ok ";
990 else
991 auth = "bad";
992 } else {
993 auth = "none";
994 }
995 }
996 if (pktversion > NTP_OLDVERSION) {
997 switch (statval & 0x7) {
998
999 case CTL_PST_SEL_REJECT:
1000 condition = "reject";
1001 break;
1002
1003 case CTL_PST_SEL_SANE:
1004 condition = "falsetick";
1005 break;
1006
1007 case CTL_PST_SEL_CORRECT:
1008 condition = "excess";
1009 break;
1010
1011 case CTL_PST_SEL_SELCAND:
1012 condition = "outlyer";
1013 break;
1014
1015 case CTL_PST_SEL_SYNCCAND:
1016 condition = "candidate";
1017 break;
1018
1019 case CTL_PST_SEL_EXCESS:
1020 condition = "backup";
1021 break;
1022
1023 case CTL_PST_SEL_SYSPEER:
1024 condition = "sys.peer";
1025 break;
1026
1027 case CTL_PST_SEL_PPS:
1028 condition = "pps.peer";
1029 break;
1030 }
1031 } else {
1032 switch (statval & 0x3) {
1033
1034 case OLD_CTL_PST_SEL_REJECT:
1035 if (!(statval & OLD_CTL_PST_SANE))
1036 condition = "insane";
1037 else if (!(statval & OLD_CTL_PST_DISP))
1038 condition = "hi_disp";
1039 else
1040 condition = "";
1041 break;
1042
1043 case OLD_CTL_PST_SEL_SELCAND:
1044 condition = "sel_cand";
1045 break;
1046
1047 case OLD_CTL_PST_SEL_SYNCCAND:
1048 condition = "sync_cand";
1049 break;
1050
1051 case OLD_CTL_PST_SEL_SYSPEER:
1052 condition = "sys_peer";
1053 break;
1054 }
1055 }
1056 switch (PEER_EVENT|event) {
1057
1058 case PEVNT_MOBIL:
1059 last_event = "mobilize";
1060 break;
1061
1062 case PEVNT_DEMOBIL:
1063 last_event = "demobilize";
1064 break;
1065
1066 case PEVNT_REACH:
1067 last_event = "reachable";
1068 break;
1069
1070 case PEVNT_UNREACH:
1071 last_event = "unreachable";
1072 break;
1073
1074 case PEVNT_RESTART:
1075 last_event = "restart";
1076 break;
1077
1078 case PEVNT_REPLY:
1079 last_event = "no_reply";
1080 break;
1081
1082 case PEVNT_RATE:
1083 last_event = "rate_exceeded";
1084 break;
1085
1086 case PEVNT_DENY:
1087 last_event = "access_denied";
1088 break;
1089
1090 case PEVNT_ARMED:
1091 last_event = "leap_armed";
1092 break;
1093
1094 case PEVNT_NEWPEER:
1095 last_event = "sys_peer";
1096 break;
1097
1098 case PEVNT_CLOCK:
1099 last_event = "clock_alarm";
1100 break;
1101
1102 default:
1103 last_event = "";
1104 break;
1105 }
1106 cnt = uinttoa(event_count);
1107 snprintf(buf, sizeof(buf),
1108 "%3d %5u %04x %3.3s %4s %4.4s %9.9s %11s %2s",
1109 i + 1, assoc_cache[i].assid,
1110 assoc_cache[i].status, conf, reach, auth,
1111 condition, last_event, cnt);
1112 bp = buf + strlen(buf);
1113 while (bp > buf && ' ' == bp[-1])
1114 --bp;
1115 bp[0] = '\0';
1116 fprintf(fp, "%s\n", buf);
1117 }
1118 }
1119
1120
1121 /*
1122 * associations - get, record and print a list of associations
1123 */
1124 /*ARGSUSED*/
1125 static void
1126 associations(
1127 struct parse *pcmd,
1128 FILE *fp
1129 )
1130 {
1131 if (dogetassoc(fp))
1132 printassoc(0, fp);
1133 }
1134
1135
1136 /*
1137 * lassociations - get, record and print a long list of associations
1138 */
1139 /*ARGSUSED*/
1140 static void
1141 lassociations(
1142 struct parse *pcmd,
1143 FILE *fp
1144 )
1145 {
1146 if (dogetassoc(fp))
1147 printassoc(1, fp);
1148 }
1149
1150
1151 /*
1152 * passociations - print the association list
1153 */
1154 /*ARGSUSED*/
1155 static void
1156 passociations(
1157 struct parse *pcmd,
1158 FILE *fp
1159 )
1160 {
1161 printassoc(0, fp);
1162 }
1163
1164
1165 /*
1166 * lpassociations - print the long association list
1167 */
1168 /*ARGSUSED*/
1169 static void
1170 lpassociations(
1171 struct parse *pcmd,
1172 FILE *fp
1173 )
1174 {
1175 printassoc(1, fp);
1176 }
1177
1178
1179 /*
1180 * saveconfig - dump ntp server configuration to server file
1181 */
1182 static void
1183 saveconfig(
1184 struct parse *pcmd,
1185 FILE *fp
1186 )
1187 {
1188 const char *datap;
1189 int res;
1190 int dsize;
1191 u_short rstatus;
1192
1193 if (0 == pcmd->nargs)
1194 return;
1195
1196 res = doquery(CTL_OP_SAVECONFIG, 0, 1,
1197 strlen(pcmd->argval[0].string),
1198 pcmd->argval[0].string, &rstatus, &dsize,
1199 &datap);
1200
1201 if (res != 0)
1202 return;
1203
1204 if (0 == dsize)
1205 fprintf(fp, "(no response message, curiously)");
1206 else
1207 fprintf(fp, "%.*s", dsize, datap);
1208 }
1209
1210
1211 #ifdef UNUSED
1212 /*
1213 * radiostatus - print the radio status returned by the server
1214 */
1215 /*ARGSUSED*/
1216 static void
1217 radiostatus(
1218 struct parse *pcmd,
1219 FILE *fp
1220 )
1221 {
1222 char *datap;
1223 int res;
1224 int dsize;
1225 u_short rstatus;
1226
1227 res = doquery(CTL_OP_READCLOCK, 0, 0, 0, (char *)0, &rstatus,
1228 &dsize, &datap);
1229
1230 if (res != 0)
1231 return;
1232
1233 if (numhosts > 1)
1234 (void) fprintf(fp, "server=%s ", currenthost);
1235 if (dsize == 0) {
1236 (void) fprintf(fp, "No radio status string returned\n");
1237 return;
1238 }
1239
1240 asciize(dsize, datap, fp);
1241 }
1242 #endif /* UNUSED */
1243
1244 /*
1245 * pstatus - print peer status returned by the server
1246 */
1247 static void
1248 pstatus(
1249 struct parse *pcmd,
1250 FILE *fp
1251 )
1252 {
1253 const char *datap;
1254 int res;
1255 associd_t associd;
1256 int dsize;
1257 u_short rstatus;
1258
1259 /* HMS: uval? */
1260 if ((associd = checkassocid(pcmd->argval[0].uval)) == 0)
1261 return;
1262
1263 res = doquery(CTL_OP_READSTAT, associd, 0, 0, NULL, &rstatus,
1264 &dsize, &datap);
1265
1266 if (res != 0)
1267 return;
1268
1269 if (numhosts > 1)
1270 fprintf(fp, "server=%s ", currenthost);
1271 if (dsize == 0) {
1272 fprintf(fp,
1273 "No information returned for association %u\n",
1274 associd);
1275 return;
1276 }
1277
1278 fprintf(fp, "associd=%u ", associd);
1279 printvars(dsize, datap, (int)rstatus, TYPE_PEER, 0, fp);
1280 }
1281
1282
1283 /*
1284 * when - print how long its been since his last packet arrived
1285 */
1286 static long
1287 when(
1288 l_fp *ts,
1289 l_fp *rec,
1290 l_fp *reftime
1291 )
1292 {
1293 l_fp *lasttime;
1294
1295 if (rec->l_ui != 0)
1296 lasttime = rec;
1297 else if (reftime->l_ui != 0)
1298 lasttime = reftime;
1299 else
1300 return 0;
1301
1302 return (ts->l_ui - lasttime->l_ui);
1303 }
1304
1305
1306 /*
1307 * Pretty-print an interval into the given buffer, in a human-friendly format.
1308 */
1309 static char *
1310 prettyinterval(
1311 char *buf,
1312 size_t cb,
1313 long diff
1314 )
1315 {
1316 if (diff <= 0) {
1317 buf[0] = '-';
1318 buf[1] = 0;
1319 return buf;
1320 }
1321
1322 if (diff <= 2048) {
1323 snprintf(buf, cb, "%ld", diff);
1324 return buf;
1325 }
1326
1327 diff = (diff + 29) / 60;
1328 if (diff <= 300) {
1329 snprintf(buf, cb, "%ldm", diff);
1330 return buf;
1331 }
1332
1333 diff = (diff + 29) / 60;
1334 if (diff <= 96) {
1335 snprintf(buf, cb, "%ldh", diff);
1336 return buf;
1337 }
1338
1339 diff = (diff + 11) / 24;
1340 snprintf(buf, cb, "%ldd", diff);
1341 return buf;
1342 }
1343
1344 static char
1345 decodeaddrtype(
1346 sockaddr_u *sock
1347 )
1348 {
1349 char ch = '-';
1350 u_int32 dummy;
1351
1352 switch(AF(sock)) {
1353 case AF_INET:
1354 dummy = SRCADR(sock);
1355 ch = (char)(((dummy&0xf0000000)==0xe0000000) ? 'm' :
1356 ((dummy&0x000000ff)==0x000000ff) ? 'b' :
1357 ((dummy&0xffffffff)==0x7f000001) ? 'l' :
1358 ((dummy&0xffffffe0)==0x00000000) ? '-' :
1359 'u');
1360 break;
1361 case AF_INET6:
1362 if (IN6_IS_ADDR_MULTICAST(PSOCK_ADDR6(sock)))
1363 ch = 'm';
1364 else
1365 ch = 'u';
1366 break;
1367 default:
1368 ch = '-';
1369 break;
1370 }
1371 return ch;
1372 }
1373
1374 /*
1375 * A list of variables required by the peers command
1376 */
1377 struct varlist opeervarlist[] = {
1378 { "srcadr", 0 }, /* 0 */
1379 { "dstadr", 0 }, /* 1 */
1380 { "stratum", 0 }, /* 2 */
1381 { "hpoll", 0 }, /* 3 */
1382 { "ppoll", 0 }, /* 4 */
1383 { "reach", 0 }, /* 5 */
1384 { "delay", 0 }, /* 6 */
1385 { "offset", 0 }, /* 7 */
1386 { "jitter", 0 }, /* 8 */
1387 { "dispersion", 0 }, /* 9 */
1388 { "rec", 0 }, /* 10 */
1389 { "reftime", 0 }, /* 11 */
1390 { "srcport", 0 }, /* 12 */
1391 { 0, 0 }
1392 };
1393
1394 struct varlist peervarlist[] = {
1395 { "srcadr", 0 }, /* 0 */
1396 { "refid", 0 }, /* 1 */
1397 { "stratum", 0 }, /* 2 */
1398 { "hpoll", 0 }, /* 3 */
1399 { "ppoll", 0 }, /* 4 */
1400 { "reach", 0 }, /* 5 */
1401 { "delay", 0 }, /* 6 */
1402 { "offset", 0 }, /* 7 */
1403 { "jitter", 0 }, /* 8 */
1404 { "dispersion", 0 }, /* 9 */
1405 { "rec", 0 }, /* 10 */
1406 { "reftime", 0 }, /* 11 */
1407 { "srcport", 0 }, /* 12 */
1408 { 0, 0 }
1409 };
1410
1411 #define HAVE_SRCADR 0
1412 #define HAVE_DSTADR 1
1413 #define HAVE_REFID 1
1414 #define HAVE_STRATUM 2
1415 #define HAVE_HPOLL 3
1416 #define HAVE_PPOLL 4
1417 #define HAVE_REACH 5
1418 #define HAVE_DELAY 6
1419 #define HAVE_OFFSET 7
1420 #define HAVE_JITTER 8
1421 #define HAVE_DISPERSION 9
1422 #define HAVE_REC 10
1423 #define HAVE_REFTIME 11
1424 #define HAVE_SRCPORT 12
1425 #define MAXHAVE 13
1426
1427 /*
1428 * Decode an incoming data buffer and print a line in the peer list
1429 */
1430 static int
1431 doprintpeers(
1432 struct varlist *pvl,
1433 int associd,
1434 int rstatus,
1435 int datalen,
1436 const char *data,
1437 FILE *fp,
1438 int af
1439 )
1440 {
1441 char *name;
1442 char *value = NULL;
1443 int i;
1444 int c;
1445
1446 sockaddr_u srcadr;
1447 sockaddr_u dstadr;
1448 sockaddr_u refidadr;
1449 u_long srcport = 0;
1450 char *dstadr_refid = "0.0.0.0";
1451 char *serverlocal;
1452 size_t drlen;
1453 u_long stratum = 0;
1454 long ppoll = 0;
1455 long hpoll = 0;
1456 u_long reach = 0;
1457 l_fp estoffset;
1458 l_fp estdelay;
1459 l_fp estjitter;
1460 l_fp estdisp;
1461 l_fp reftime;
1462 l_fp rec;
1463 l_fp ts;
1464 u_char havevar[MAXHAVE];
1465 u_long poll_sec;
1466 char type = '?';
1467 char refid_string[10];
1468 char whenbuf[8], pollbuf[8];
1469 char clock_name[LENHOSTNAME];
1470
1471 memset((char *)havevar, 0, sizeof(havevar));
1472 get_systime(&ts);
1473
1474 ZERO_SOCK(&srcadr);
1475 ZERO_SOCK(&dstadr);
1476
1477 /* Initialize by zeroing out estimate variables */
1478 memset((char *)&estoffset, 0, sizeof(l_fp));
1479 memset((char *)&estdelay, 0, sizeof(l_fp));
1480 memset((char *)&estjitter, 0, sizeof(l_fp));
1481 memset((char *)&estdisp, 0, sizeof(l_fp));
1482
1483 while (nextvar(&datalen, &data, &name, &value)) {
1484 sockaddr_u dum_store;
1485
1486 i = findvar(name, peer_var, 1);
1487 if (i == 0)
1488 continue; /* don't know this one */
1489 switch (i) {
1490 case CP_SRCADR:
1491 if (decodenetnum(value, &srcadr)) {
1492 havevar[HAVE_SRCADR] = 1;
1493 }
1494 break;
1495 case CP_DSTADR:
1496 if (decodenetnum(value, &dum_store)) {
1497 type = decodeaddrtype(&dum_store);
1498 havevar[HAVE_DSTADR] = 1;
1499 dstadr = dum_store;
1500 if (pvl == opeervarlist) {
1501 dstadr_refid = trunc_left(stoa(&dstadr), 15);
1502 }
1503 }
1504 break;
1505 case CP_REFID:
1506 if (pvl == peervarlist) {
1507 havevar[HAVE_REFID] = 1;
1508 if (*value == '\0') {
1509 dstadr_refid = "";
1510 } else if (strlen(value) <= 4) {
1511 refid_string[0] = '.';
1512 (void) strcpy(&refid_string[1], value);
1513 i = strlen(refid_string);
1514 refid_string[i] = '.';
1515 refid_string[i+1] = '\0';
1516 dstadr_refid = refid_string;
1517 } else if (decodenetnum(value, &refidadr)) {
1518 if (SOCK_UNSPEC(&refidadr))
1519 dstadr_refid = "0.0.0.0";
1520 else if (ISREFCLOCKADR(&refidadr))
1521 dstadr_refid =
1522 refnumtoa(&refidadr);
1523 else
1524 dstadr_refid =
1525 stoa(&refidadr);
1526 } else {
1527 havevar[HAVE_REFID] = 0;
1528 }
1529 }
1530 break;
1531 case CP_STRATUM:
1532 if (decodeuint(value, &stratum))
1533 havevar[HAVE_STRATUM] = 1;
1534 break;
1535 case CP_HPOLL:
1536 if (decodeint(value, &hpoll)) {
1537 havevar[HAVE_HPOLL] = 1;
1538 if (hpoll < 0)
1539 hpoll = NTP_MINPOLL;
1540 }
1541 break;
1542 case CP_PPOLL:
1543 if (decodeint(value, &ppoll)) {
1544 havevar[HAVE_PPOLL] = 1;
1545 if (ppoll < 0)
1546 ppoll = NTP_MINPOLL;
1547 }
1548 break;
1549 case CP_REACH:
1550 if (decodeuint(value, &reach))
1551 havevar[HAVE_REACH] = 1;
1552 break;
1553 case CP_DELAY:
1554 if (decodetime(value, &estdelay))
1555 havevar[HAVE_DELAY] = 1;
1556 break;
1557 case CP_OFFSET:
1558 if (decodetime(value, &estoffset))
1559 havevar[HAVE_OFFSET] = 1;
1560 break;
1561 case CP_JITTER:
1562 if (pvl == peervarlist)
1563 if (decodetime(value, &estjitter))
1564 havevar[HAVE_JITTER] = 1;
1565 break;
1566 case CP_DISPERSION:
1567 if (decodetime(value, &estdisp))
1568 havevar[HAVE_DISPERSION] = 1;
1569 break;
1570 case CP_REC:
1571 if (decodets(value, &rec))
1572 havevar[HAVE_REC] = 1;
1573 break;
1574 case CP_SRCPORT:
1575 if (decodeuint(value, &srcport))
1576 havevar[HAVE_SRCPORT] = 1;
1577 break;
1578 case CP_REFTIME:
1579 havevar[HAVE_REFTIME] = 1;
1580 if (!decodets(value, &reftime))
1581 L_CLR(&reftime);
1582 break;
1583 default:
1584 break;
1585 }
1586 }
1587
1588 /*
1589 * Check to see if the srcport is NTP's port. If not this probably
1590 * isn't a valid peer association.
1591 */
1592 if (havevar[HAVE_SRCPORT] && srcport != NTP_PORT)
1593 return (1);
1594
1595 /*
1596 * Got everything, format the line
1597 */
1598 poll_sec = 1<<max(min3(ppoll, hpoll, NTP_MAXPOLL), NTP_MINPOLL);
1599 if (pktversion > NTP_OLDVERSION)
1600 c = flash3[CTL_PEER_STATVAL(rstatus) & 0x7];
1601 else
1602 c = flash2[CTL_PEER_STATVAL(rstatus) & 0x3];
1603 if (numhosts > 1) {
1604 if (peervarlist == pvl && havevar[HAVE_DSTADR]) {
1605 serverlocal = nntohost_col(&dstadr,
1606 (size_t)min(LIB_BUFLENGTH - 1, maxhostlen),
1607 TRUE);
1608 } else {
1609 if (currenthostisnum)
1610 serverlocal = trunc_left(currenthost,
1611 maxhostlen);
1612 else
1613 serverlocal = currenthost;
1614 }
1615 fprintf(fp, "%-*s ", maxhostlen, serverlocal);
1616 }
1617 if (AF_UNSPEC == af || AF(&srcadr) == af) {
1618 strncpy(clock_name, nntohost(&srcadr), sizeof(clock_name));
1619 fprintf(fp, "%c%-15.15s ", c, clock_name);
1620 drlen = strlen(dstadr_refid);
1621 makeascii(drlen, dstadr_refid, fp);
1622 while (drlen++ < 15)
1623 fputc(' ', fp);
1624 fprintf(fp,
1625 " %2ld %c %4.4s %4.4s %3lo %7.7s %8.7s %7.7s\n",
1626 stratum, type,
1627 prettyinterval(whenbuf, sizeof(whenbuf),
1628 when(&ts, &rec, &reftime)),
1629 prettyinterval(pollbuf, sizeof(pollbuf),
1630 (int)poll_sec),
1631 reach, lfptoms(&estdelay, 3),
1632 lfptoms(&estoffset, 3),
1633 (havevar[HAVE_JITTER])
1634 ? lfptoms(&estjitter, 3)
1635 : lfptoms(&estdisp, 3));
1636 return (1);
1637 }
1638 else
1639 return(1);
1640 }
1641
1642 #undef HAVE_SRCADR
1643 #undef HAVE_DSTADR
1644 #undef HAVE_STRATUM
1645 #undef HAVE_PPOLL
1646 #undef HAVE_HPOLL
1647 #undef HAVE_REACH
1648 #undef HAVE_ESTDELAY
1649 #undef HAVE_ESTOFFSET
1650 #undef HAVE_JITTER
1651 #undef HAVE_ESTDISP
1652 #undef HAVE_REFID
1653 #undef HAVE_REC
1654 #undef HAVE_SRCPORT
1655 #undef HAVE_REFTIME
1656 #undef MAXHAVE
1657
1658
1659 /*
1660 * dogetpeers - given an association ID, read and print the spreadsheet
1661 * peer variables.
1662 */
1663 static int
1664 dogetpeers(
1665 struct varlist *pvl,
1666 associd_t associd,
1667 FILE *fp,
1668 int af
1669 )
1670 {
1671 const char *datap;
1672 int res;
1673 int dsize;
1674 u_short rstatus;
1675
1676 #ifdef notdef
1677 res = doquerylist(pvl, CTL_OP_READVAR, associd, 0, &rstatus,
1678 &dsize, &datap);
1679 #else
1680 /*
1681 * Damn fuzzballs
1682 */
1683 res = doquery(CTL_OP_READVAR, associd, 0, 0, NULL, &rstatus,
1684 &dsize, &datap);
1685 #endif
1686
1687 if (res != 0)
1688 return 0;
1689
1690 if (dsize == 0) {
1691 if (numhosts > 1)
1692 fprintf(stderr, "server=%s ", currenthost);
1693 fprintf(stderr,
1694 "***No information returned for association %u\n",
1695 associd);
1696 return 0;
1697 }
1698
1699 return doprintpeers(pvl, associd, (int)rstatus, dsize, datap,
1700 fp, af);
1701 }
1702
1703
1704 /*
1705 * peers - print a peer spreadsheet
1706 */
1707 static void
1708 dopeers(
1709 int showall,
1710 FILE *fp,
1711 int af
1712 )
1713 {
1714 int i;
1715 char fullname[LENHOSTNAME];
1716 sockaddr_u netnum;
1717 char * name_or_num;
1718 size_t sl;
1719
1720 if (!dogetassoc(fp))
1721 return;
1722
1723 for (i = 0; i < numhosts; ++i) {
1724 if (getnetnum(chosts[i], &netnum, fullname, af)) {
1725 name_or_num = nntohost(&netnum);
1726 sl = strlen(name_or_num);
1727 maxhostlen = max(maxhostlen, (int)sl);
1728 }
1729 }
1730 if (numhosts > 1)
1731 fprintf(fp, "%-*.*s ", maxhostlen, maxhostlen,
1732 "server (local)");
1733 fprintf(fp,
1734 " remote refid st t when poll reach delay offset jitter\n");
1735 if (numhosts > 1)
1736 for (i = 0; i <= maxhostlen; ++i)
1737 fprintf(fp, "=");
1738 fprintf(fp,
1739 "==============================================================================\n");
1740
1741 for (i = 0; i < numassoc; i++) {
1742 if (!showall &&
1743 !(CTL_PEER_STATVAL(assoc_cache[i].status)
1744 & (CTL_PST_CONFIG|CTL_PST_REACH)))
1745 continue;
1746 if (!dogetpeers(peervarlist, (int)assoc_cache[i].assid, fp, af)) {
1747 return;
1748 }
1749 }
1750 return;
1751 }
1752
1753
1754 /*
1755 * peers - print a peer spreadsheet
1756 */
1757 /*ARGSUSED*/
1758 static void
1759 peers(
1760 struct parse *pcmd,
1761 FILE *fp
1762 )
1763 {
1764 int af = 0;
1765
1766 if (pcmd->nargs == 1) {
1767 if (pcmd->argval->ival == 6)
1768 af = AF_INET6;
1769 else
1770 af = AF_INET;
1771 }
1772 dopeers(0, fp, af);
1773 }
1774
1775
1776 /*
1777 * lpeers - print a peer spreadsheet including all fuzzball peers
1778 */
1779 /*ARGSUSED*/
1780 static void
1781 lpeers(
1782 struct parse *pcmd,
1783 FILE *fp
1784 )
1785 {
1786 int af = 0;
1787
1788 if (pcmd->nargs == 1) {
1789 if (pcmd->argval->ival == 6)
1790 af = AF_INET6;
1791 else
1792 af = AF_INET;
1793 }
1794 dopeers(1, fp, af);
1795 }
1796
1797
1798 /*
1799 * opeers - print a peer spreadsheet
1800 */
1801 static void
1802 doopeers(
1803 int showall,
1804 FILE *fp,
1805 int af
1806 )
1807 {
1808 register int i;
1809 char fullname[LENHOSTNAME];
1810 sockaddr_u netnum;
1811
1812 if (!dogetassoc(fp))
1813 return;
1814
1815 for (i = 0; i < numhosts; ++i) {
1816 if (getnetnum(chosts[i], &netnum, fullname, af))
1817 if ((int)strlen(fullname) > maxhostlen)
1818 maxhostlen = strlen(fullname);
1819 }
1820 if (numhosts > 1)
1821 (void) fprintf(fp, "%-*.*s ", maxhostlen, maxhostlen, "server");
1822 (void) fprintf(fp,
1823 " remote local st t when poll reach delay offset disp\n");
1824 if (numhosts > 1)
1825 for (i = 0; i <= maxhostlen; ++i)
1826 (void) fprintf(fp, "=");
1827 (void) fprintf(fp,
1828 "==============================================================================\n");
1829
1830 for (i = 0; i < numassoc; i++) {
1831 if (!showall &&
1832 !(CTL_PEER_STATVAL(assoc_cache[i].status)
1833 & (CTL_PST_CONFIG|CTL_PST_REACH)))
1834 continue;
1835 if (!dogetpeers(opeervarlist, (int)assoc_cache[i].assid, fp, af)) {
1836 return;
1837 }
1838 }
1839 return;
1840 }
1841
1842
1843 /*
1844 * opeers - print a peer spreadsheet the old way
1845 */
1846 /*ARGSUSED*/
1847 static void
1848 opeers(
1849 struct parse *pcmd,
1850 FILE *fp
1851 )
1852 {
1853 int af = 0;
1854
1855 if (pcmd->nargs == 1) {
1856 if (pcmd->argval->ival == 6)
1857 af = AF_INET6;
1858 else
1859 af = AF_INET;
1860 }
1861 doopeers(0, fp, af);
1862 }
1863
1864
1865 /*
1866 * lopeers - print a peer spreadsheet including all fuzzball peers
1867 */
1868 /*ARGSUSED*/
1869 static void
1870 lopeers(
1871 struct parse *pcmd,
1872 FILE *fp
1873 )
1874 {
1875 int af = 0;
1876
1877 if (pcmd->nargs == 1) {
1878 if (pcmd->argval->ival == 6)
1879 af = AF_INET6;
1880 else
1881 af = AF_INET;
1882 }
1883 doopeers(1, fp, af);
1884 }
1885
1886
1887 /*
1888 * config - send a configuration command to a remote host
1889 */
1890 static void
1891 config (
1892 struct parse *pcmd,
1893 FILE *fp
1894 )
1895 {
1896 char *cfgcmd;
1897 u_short rstatus;
1898 int rsize;
1899 const char *rdata;
1900 char *resp;
1901 int res;
1902 int col;
1903 int i;
1904
1905 cfgcmd = pcmd->argval[0].string;
1906
1907 if (debug > 2)
1908 fprintf(stderr,
1909 "In Config\n"
1910 "Keyword = %s\n"
1911 "Command = %s\n", pcmd->keyword, cfgcmd);
1912
1913 res = doquery(CTL_OP_CONFIGURE, 0, 1, strlen(cfgcmd), cfgcmd,
1914 &rstatus, &rsize, &rdata);
1915
1916 if (res != 0)
1917 return;
1918
1919 if (rsize > 0 && '\n' == rdata[rsize - 1])
1920 rsize--;
1921
1922 resp = emalloc(rsize + 1);
1923 memcpy(resp, rdata, rsize);
1924 resp[rsize] = '\0';
1925
1926 col = -1;
1927 if (1 == sscanf(resp, "column %d syntax error", &col)
1928 && col >= 0 && (size_t)col <= strlen(cfgcmd) + 1) {
1929 if (interactive) {
1930 printf("______"); /* "ntpq> " */
1931 printf("________"); /* ":config " */
1932 } else
1933 printf("%s\n", cfgcmd);
1934 for (i = 1; i < col; i++)
1935 putchar('_');
1936 printf("^\n");
1937 }
1938 printf("%s\n", resp);
1939 free(resp);
1940 }
1941
1942
1943 /*
1944 * config_from_file - remotely configure an ntpd daemon using the
1945 * specified configuration file
1946 * SK: This function is a kludge at best and is full of bad design
1947 * bugs:
1948 * 1. ntpq uses UDP, which means that there is no guarantee of in-order,
1949 * error-free delivery.
1950 * 2. The maximum length of a packet is constrained, and as a result, the
1951 * maximum length of a line in a configuration file is constrained.
1952 * Longer lines will lead to unpredictable results.
1953 * 3. Since this function is sending a line at a time, we can't update
1954 * the control key through the configuration file (YUCK!!)
1955 */
1956 static void
1957 config_from_file (
1958 struct parse *pcmd,
1959 FILE *fp
1960 )
1961 {
1962 u_short rstatus;
1963 int rsize;
1964 const char *rdata;
1965 int res;
1966 FILE *config_fd;
1967 char config_cmd[MAXLINE];
1968 size_t config_len;
1969 int i;
1970 int retry_limit;
1971
1972 if (debug > 2)
1973 fprintf(stderr,
1974 "In Config\n"
1975 "Keyword = %s\n"
1976 "Filename = %s\n", pcmd->keyword,
1977 pcmd->argval[0].string);
1978
1979 config_fd = fopen(pcmd->argval[0].string, "r");
1980 if (NULL == config_fd) {
1981 printf("ERROR!! Couldn't open file: %s\n",
1982 pcmd->argval[0].string);
1983 return;
1984 }
1985
1986 printf("Sending configuration file, one line at a time.\n");
1987 i = 0;
1988 while (fgets(config_cmd, MAXLINE, config_fd) != NULL) {
1989 config_len = strlen(config_cmd);
1990 /* ensure even the last line has newline, if possible */
1991 if (config_len > 0 &&
1992 config_len + 2 < sizeof(config_cmd) &&
1993 '\n' != config_cmd[config_len - 1])
1994 config_cmd[config_len++] = '\n';
1995 ++i;
1996 retry_limit = 2;
1997 do
1998 res = doquery(CTL_OP_CONFIGURE, 0, 1,
1999 strlen(config_cmd), config_cmd,
2000 &rstatus, &rsize, &rdata);
2001 while (res != 0 && retry_limit--);
2002 if (res != 0) {
2003 printf("Line No: %d query failed: %s", i,
2004 config_cmd);
2005 printf("Subsequent lines not sent.\n");
2006 fclose(config_fd);
2007 return;
2008 }
2009
2010 if (rsize > 0 && '\n' == rdata[rsize - 1])
2011 rsize--;
2012 if (rsize > 0 && '\r' == rdata[rsize - 1])
2013 rsize--;
2014 printf("Line No: %d %.*s: %s", i, rsize, rdata,
2015 config_cmd);
2016 }
2017 printf("Done sending file\n");
2018 fclose(config_fd);
2019 }
2020