Patrick Welche <prlw1@cam.ac.uk>
[netbsd-mini2440.git] / external / bsd / ntp / dist / ntpq / ntpq-subs.c
blob1fb4d2a16f2b0fd1eacda7cc057be509d6fb9359
1 /* $NetBSD: ntpq-subs.c,v 1.1.1.1 2009/12/13 16:56:29 kardel Exp $ */
3 /*
4 * ntpq_ops.c - subroutines which are called to perform operations by ntpq
5 */
7 #include <stdio.h>
8 #include <ctype.h>
9 #include <sys/types.h>
10 #include <sys/time.h>
12 #include "ntp_stdlib.h"
13 #include "ntpq.h"
14 #include "ntpq-opts.h"
16 extern const char * chosts[];
17 extern char currenthost[];
18 extern int numhosts;
19 int maxhostlen;
22 * Declarations for command handlers in here
24 static int checkassocid (u_int32);
25 static struct varlist *findlistvar (struct varlist *, char *);
26 static void doaddvlist (struct varlist *, char *);
27 static void dormvlist (struct varlist *, char *);
28 static void doclearvlist (struct varlist *);
29 static void makequerydata (struct varlist *, int *, char *);
30 static int doquerylist (struct varlist *, int, int, int,
31 u_short *, int *, char **);
32 static void doprintvlist (struct varlist *, FILE *);
33 static void addvars (struct parse *, FILE *);
34 static void rmvars (struct parse *, FILE *);
35 static void clearvars (struct parse *, FILE *);
36 static void showvars (struct parse *, FILE *);
37 static int dolist (struct varlist *, int, int, int,
38 FILE *);
39 static void readlist (struct parse *, FILE *);
40 static void writelist (struct parse *, FILE *);
41 static void readvar (struct parse *, FILE *);
42 static void writevar (struct parse *, FILE *);
43 static void clocklist (struct parse *, FILE *);
44 static void clockvar (struct parse *, FILE *);
45 static int findassidrange (u_int32, u_int32, int *, int *);
46 static void mreadlist (struct parse *, FILE *);
47 static void mreadvar (struct parse *, FILE *);
48 static int dogetassoc (FILE *);
49 static void printassoc (int, FILE *);
50 static void associations (struct parse *, FILE *);
51 static void lassociations (struct parse *, FILE *);
52 static void passociations (struct parse *, FILE *);
53 static void lpassociations (struct parse *, FILE *);
55 #ifdef UNUSED
56 static void radiostatus (struct parse *, FILE *);
57 #endif /* UNUSED */
59 static void pstatus (struct parse *, FILE *);
60 static long when (l_fp *, l_fp *, l_fp *);
61 static char * prettyinterval (char *, long);
62 static int doprintpeers (struct varlist *, int, int, int, char *, FILE *, int);
63 static int dogetpeers (struct varlist *, int, FILE *, int);
64 static void dopeers (int, FILE *, int);
65 static void peers (struct parse *, FILE *);
66 static void lpeers (struct parse *, FILE *);
67 static void doopeers (int, FILE *, int);
68 static void opeers (struct parse *, FILE *);
69 static void lopeers (struct parse *, FILE *);
70 static void config (struct parse *, FILE *);
71 static void saveconfig (struct parse *, FILE *);
72 static void config_from_file(struct parse *, FILE *);
76 * Commands we understand. Ntpdc imports this.
78 struct xcmd opcmds[] = {
79 { "saveconfig", saveconfig, { NTP_STR, NO, NO, NO },
80 { "filename", "", "", ""},
81 "save ntpd configuration to file, . for current config file"},
82 { "associations", associations, { NO, NO, NO, NO },
83 { "", "", "", "" },
84 "print list of association ID's and statuses for the server's peers" },
85 { "passociations", passociations, { NO, NO, NO, NO },
86 { "", "", "", "" },
87 "print list of associations returned by last associations command" },
88 { "lassociations", lassociations, { NO, NO, NO, NO },
89 { "", "", "", "" },
90 "print list of associations including all client information" },
91 { "lpassociations", lpassociations, { NO, NO, NO, NO },
92 { "", "", "", "" },
93 "print last obtained list of associations, including client information" },
94 { "addvars", addvars, { NTP_STR, NO, NO, NO },
95 { "name[=value][,...]", "", "", "" },
96 "add variables to the variable list or change their values" },
97 { "rmvars", rmvars, { NTP_STR, NO, NO, NO },
98 { "name[,...]", "", "", "" },
99 "remove variables from the variable list" },
100 { "clearvars", clearvars, { NO, NO, NO, NO },
101 { "", "", "", "" },
102 "remove all variables from the variable list" },
103 { "showvars", showvars, { NO, NO, NO, NO },
104 { "", "", "", "" },
105 "print variables on the variable list" },
106 { "readlist", readlist, { OPT|NTP_UINT, NO, NO, NO },
107 { "assocID", "", "", "" },
108 "read the system or peer variables included in the variable list" },
109 { "rl", readlist, { OPT|NTP_UINT, NO, NO, NO },
110 { "assocID", "", "", "" },
111 "read the system or peer variables included in the variable list" },
112 { "writelist", writelist, { OPT|NTP_UINT, NO, NO, NO },
113 { "assocID", "", "", "" },
114 "write the system or peer variables included in the variable list" },
115 { "readvar", readvar, { OPT|NTP_UINT, OPT|NTP_STR, NO, NO },
116 { "assocID", "name=value[,...]", "", "" },
117 "read system or peer variables" },
118 { "rv", readvar, { OPT|NTP_UINT, OPT|NTP_STR, NO, NO },
119 { "assocID", "name=value[,...]", "", "" },
120 "read system or peer variables" },
121 { "writevar", writevar, { NTP_UINT, NTP_STR, NO, NO },
122 { "assocID", "name=value,[...]", "", "" },
123 "write system or peer variables" },
124 { "mreadlist", mreadlist, { NTP_UINT, NTP_UINT, NO, NO },
125 { "assocID", "assocID", "", "" },
126 "read the peer variables in the variable list for multiple peers" },
127 { "mrl", mreadlist, { NTP_UINT, NTP_UINT, NO, NO },
128 { "assocID", "assocID", "", "" },
129 "read the peer variables in the variable list for multiple peers" },
130 { "mreadvar", mreadvar, { NTP_UINT, NTP_UINT, OPT|NTP_STR, NO },
131 { "assocID", "assocID", "name=value[,...]", "" },
132 "read peer variables from multiple peers" },
133 { "mrv", mreadvar, { NTP_UINT, NTP_UINT, OPT|NTP_STR, NO },
134 { "assocID", "assocID", "name=value[,...]", "" },
135 "read peer variables from multiple peers" },
136 { "clocklist", clocklist, { OPT|NTP_UINT, NO, NO, NO },
137 { "assocID", "", "", "" },
138 "read the clock variables included in the variable list" },
139 { "cl", clocklist, { OPT|NTP_UINT, NO, NO, NO },
140 { "assocID", "", "", "" },
141 "read the clock variables included in the variable list" },
142 { "clockvar", clockvar, { OPT|NTP_UINT, OPT|NTP_STR, NO, NO },
143 { "assocID", "name=value[,...]", "", "" },
144 "read clock variables" },
145 { "cv", clockvar, { OPT|NTP_UINT, OPT|NTP_STR, NO, NO },
146 { "assocID", "name=value[,...]", "", "" },
147 "read clock variables" },
148 { "pstatus", pstatus, { NTP_UINT, NO, NO, NO },
149 { "assocID", "", "", "" },
150 "print status information returned for a peer" },
151 { "peers", peers, { OPT|IP_VERSION, NO, NO, NO },
152 { "-4|-6", "", "", "" },
153 "obtain and print a list of the server's peers [IP version]" },
154 { "lpeers", lpeers, { OPT|IP_VERSION, NO, NO, NO },
155 { "-4|-6", "", "", "" },
156 "obtain and print a list of all peers and clients [IP version]" },
157 { "opeers", opeers, { OPT|IP_VERSION, NO, NO, NO },
158 { "-4|-6", "", "", "" },
159 "print peer list the old way, with dstadr shown rather than refid [IP version]" },
160 { "lopeers", lopeers, { OPT|IP_VERSION, NO, NO, NO },
161 { "-4|-6", "", "", "" },
162 "obtain and print a list of all peers and clients showing dstadr [IP version]" },
163 { ":config", config, { NTP_STR, NO, NO, NO },
164 { "<configuration command line>", "", "", "" },
165 "send a remote configuration command to ntpd" },
166 { "config-from-file", config_from_file, { NTP_STR, NO, NO, NO },
167 { "<configuration filename>", "", "", "" },
168 "configure ntpd using the configuration filename" },
169 { 0, 0, { NO, NO, NO, NO },
170 { "-4|-6", "", "", "" }, "" }
175 * Variable list data space
177 #define MAXLINE 512 /* maximum length of a line */
178 #define MAXLIST 64 /* maximum number of variables in list */
179 #define LENHOSTNAME 256 /* host name is 256 characters long */
181 * Old CTL_PST defines for version 2.
183 #define OLD_CTL_PST_CONFIG 0x80
184 #define OLD_CTL_PST_AUTHENABLE 0x40
185 #define OLD_CTL_PST_AUTHENTIC 0x20
186 #define OLD_CTL_PST_REACH 0x10
187 #define OLD_CTL_PST_SANE 0x08
188 #define OLD_CTL_PST_DISP 0x04
190 #define OLD_CTL_PST_SEL_REJECT 0
191 #define OLD_CTL_PST_SEL_SELCAND 1
192 #define OLD_CTL_PST_SEL_SYNCCAND 2
193 #define OLD_CTL_PST_SEL_SYSPEER 3
195 char flash2[] = " .+* "; /* flash decode for version 2 */
196 char flash3[] = " x.-+#*o"; /* flash decode for peer status version 3 */
198 struct varlist {
199 char *name;
200 char *value;
201 } g_varlist[MAXLIST] = { { 0, 0 } };
204 * Imported from ntpq.c
206 extern int showhostnames;
207 extern int rawmode;
208 extern struct servent *server_entry;
209 extern struct association assoc_cache[];
210 extern int numassoc;
211 extern u_char pktversion;
212 extern struct ctl_var peer_var[];
215 * For quick string comparisons
217 #define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0)
221 * checkassocid - return the association ID, checking to see if it is valid
223 static int
224 checkassocid(
225 u_int32 value
228 if (value == 0 || value >= 65536) {
229 (void) fprintf(stderr, "***Invalid association ID specified\n");
230 return 0;
232 return (int)value;
237 * findlistvar - look for the named variable in a list and return if found
239 static struct varlist *
240 findlistvar(
241 struct varlist *list,
242 char *name
245 register struct varlist *vl;
247 for (vl = list; vl < list + MAXLIST && vl->name != 0; vl++)
248 if (STREQ(name, vl->name))
249 return vl;
250 if (vl < list + MAXLIST)
251 return vl;
252 return (struct varlist *)0;
257 * doaddvlist - add variable(s) to the variable list
259 static void
260 doaddvlist(
261 struct varlist *vlist,
262 char *vars
265 register struct varlist *vl;
266 int len;
267 char *name;
268 char *value;
270 len = strlen(vars);
271 while (nextvar(&len, &vars, &name, &value)) {
272 vl = findlistvar(vlist, name);
273 if (vl == 0) {
274 (void) fprintf(stderr, "Variable list full\n");
275 return;
278 if (vl->name == 0) {
279 vl->name = estrdup(name);
280 } else if (vl->value != 0) {
281 free(vl->value);
282 vl->value = 0;
285 if (value != 0)
286 vl->value = estrdup(value);
292 * dormvlist - remove variable(s) from the variable list
294 static void
295 dormvlist(
296 struct varlist *vlist,
297 char *vars
300 register struct varlist *vl;
301 int len;
302 char *name;
303 char *value;
305 len = strlen(vars);
306 while (nextvar(&len, &vars, &name, &value)) {
307 vl = findlistvar(vlist, name);
308 if (vl == 0 || vl->name == 0) {
309 (void) fprintf(stderr, "Variable `%s' not found\n",
310 name);
311 } else {
312 free((void *)vl->name);
313 if (vl->value != 0)
314 free(vl->value);
315 for ( ; (vl+1) < (g_varlist + MAXLIST)
316 && (vl+1)->name != 0; vl++) {
317 vl->name = (vl+1)->name;
318 vl->value = (vl+1)->value;
320 vl->name = vl->value = 0;
327 * doclearvlist - clear a variable list
329 static void
330 doclearvlist(
331 struct varlist *vlist
334 register struct varlist *vl;
336 for (vl = vlist; vl < vlist + MAXLIST && vl->name != 0; vl++) {
337 free((void *)vl->name);
338 vl->name = 0;
339 if (vl->value != 0) {
340 free(vl->value);
341 vl->value = 0;
348 * makequerydata - form a data buffer to be included with a query
350 static void
351 makequerydata(
352 struct varlist *vlist,
353 int *datalen,
354 char *data
357 register struct varlist *vl;
358 register char *cp, *cpend;
359 register int namelen, valuelen;
360 register int totallen;
362 cp = data;
363 cpend = data + *datalen;
365 for (vl = vlist; vl < vlist + MAXLIST && vl->name != 0; vl++) {
366 namelen = strlen(vl->name);
367 if (vl->value == 0)
368 valuelen = 0;
369 else
370 valuelen = strlen(vl->value);
371 totallen = namelen + valuelen + (valuelen != 0) + (cp != data);
372 if (cp + totallen > cpend)
373 break;
375 if (cp != data)
376 *cp++ = ',';
377 memmove(cp, vl->name, (unsigned)namelen);
378 cp += namelen;
379 if (valuelen != 0) {
380 *cp++ = '=';
381 memmove(cp, vl->value, (unsigned)valuelen);
382 cp += valuelen;
385 *datalen = cp - data;
390 * doquerylist - send a message including variables in a list
392 static int
393 doquerylist(
394 struct varlist *vlist,
395 int op,
396 int associd,
397 int auth,
398 u_short *rstatus,
399 int *dsize,
400 char **datap
403 char data[CTL_MAX_DATA_LEN];
404 int datalen;
406 datalen = sizeof(data);
407 makequerydata(vlist, &datalen, data);
409 return doquery(op, associd, auth, datalen, data, rstatus,
410 dsize, datap);
415 * doprintvlist - print the variables on a list
417 static void
418 doprintvlist(
419 struct varlist *vlist,
420 FILE *fp
423 register struct varlist *vl;
425 if (vlist->name == 0) {
426 (void) fprintf(fp, "No variables on list\n");
427 } else {
428 for (vl = vlist; vl < vlist + MAXLIST && vl->name != 0; vl++) {
429 if (vl->value == 0) {
430 (void) fprintf(fp, "%s\n", vl->name);
431 } else {
432 (void) fprintf(fp, "%s=%s\n",
433 vl->name, vl->value);
440 * addvars - add variables to the variable list
442 /*ARGSUSED*/
443 static void
444 addvars(
445 struct parse *pcmd,
446 FILE *fp
449 doaddvlist(g_varlist, pcmd->argval[0].string);
454 * rmvars - remove variables from the variable list
456 /*ARGSUSED*/
457 static void
458 rmvars(
459 struct parse *pcmd,
460 FILE *fp
463 dormvlist(g_varlist, pcmd->argval[0].string);
468 * clearvars - clear the variable list
470 /*ARGSUSED*/
471 static void
472 clearvars(
473 struct parse *pcmd,
474 FILE *fp
477 doclearvlist(g_varlist);
482 * showvars - show variables on the variable list
484 /*ARGSUSED*/
485 static void
486 showvars(
487 struct parse *pcmd,
488 FILE *fp
491 doprintvlist(g_varlist, fp);
496 * dolist - send a request with the given list of variables
498 static int
499 dolist(
500 struct varlist *vlist,
501 int associd,
502 int op,
503 int type,
504 FILE *fp
507 char *datap;
508 int res;
509 int dsize;
510 u_short rstatus;
511 int quiet;
514 * if we're asking for specific variables don't include the
515 * status header line in the output.
517 if (old_rv)
518 quiet = 0;
519 else
520 quiet = (vlist->name != NULL);
522 res = doquerylist(vlist, op, associd, 0, &rstatus, &dsize, &datap);
524 if (res != 0)
525 return 0;
527 if (numhosts > 1)
528 (void) fprintf(fp, "server=%s ", currenthost);
529 if (dsize == 0) {
530 if (associd == 0)
531 (void) fprintf(fp, "No system%s variables returned\n",
532 (type == TYPE_CLOCK) ? " clock" : "");
533 else
534 (void) fprintf(fp,
535 "No information returned for%s association %u\n",
536 (type == TYPE_CLOCK) ? " clock" : "", associd);
537 return 1;
540 if (!quiet)
541 fprintf(fp,"associd=%d ",associd);
542 printvars(dsize, datap, (int)rstatus, type, quiet, fp);
543 return 1;
548 * readlist - send a read variables request with the variables on the list
550 static void
551 readlist(
552 struct parse *pcmd,
553 FILE *fp
556 int associd;
558 if (pcmd->nargs == 0) {
559 associd = 0;
560 } else {
561 /* HMS: I think we want the u_int32 target here, not the u_long */
562 if (pcmd->argval[0].uval == 0)
563 associd = 0;
564 else if ((associd = checkassocid(pcmd->argval[0].uval)) == 0)
565 return;
568 (void) dolist(g_varlist, associd, CTL_OP_READVAR,
569 (associd == 0) ? TYPE_SYS : TYPE_PEER, fp);
574 * writelist - send a write variables request with the variables on the list
576 static void
577 writelist(
578 struct parse *pcmd,
579 FILE *fp
582 char *datap;
583 int res;
584 int associd;
585 int dsize;
586 u_short rstatus;
588 if (pcmd->nargs == 0) {
589 associd = 0;
590 } else {
591 /* HMS: Do we really want uval here? */
592 if (pcmd->argval[0].uval == 0)
593 associd = 0;
594 else if ((associd = checkassocid(pcmd->argval[0].uval)) == 0)
595 return;
598 res = doquerylist(g_varlist, CTL_OP_WRITEVAR, associd, 1, &rstatus,
599 &dsize, &datap);
601 if (res != 0)
602 return;
604 if (numhosts > 1)
605 (void) fprintf(fp, "server=%s ", currenthost);
606 if (dsize == 0)
607 (void) fprintf(fp, "done! (no data returned)\n");
608 else {
609 (void) fprintf(fp,"associd=%d ",associd);
610 printvars(dsize, datap, (int)rstatus,
611 (associd != 0) ? TYPE_PEER : TYPE_SYS, 0, fp);
613 return;
618 * readvar - send a read variables request with the specified variables
620 static void
621 readvar(
622 struct parse *pcmd,
623 FILE *fp
626 int associd;
627 struct varlist tmplist[MAXLIST];
629 /* HMS: uval? */
630 if (pcmd->nargs == 0 || pcmd->argval[0].uval == 0)
631 associd = 0;
632 else if ((associd = checkassocid(pcmd->argval[0].uval)) == 0)
633 return;
635 memset((char *)tmplist, 0, sizeof(tmplist));
636 if (pcmd->nargs >= 2)
637 doaddvlist(tmplist, pcmd->argval[1].string);
639 (void) dolist(tmplist, associd, CTL_OP_READVAR,
640 (associd == 0) ? TYPE_SYS : TYPE_PEER, fp);
642 doclearvlist(tmplist);
647 * writevar - send a write variables request with the specified variables
649 static void
650 writevar(
651 struct parse *pcmd,
652 FILE *fp
655 char *datap;
656 int res;
657 int associd;
658 int dsize;
659 u_short rstatus;
660 struct varlist tmplist[MAXLIST];
662 /* HMS: uval? */
663 if (pcmd->argval[0].uval == 0)
664 associd = 0;
665 else if ((associd = checkassocid(pcmd->argval[0].uval)) == 0)
666 return;
668 memset((char *)tmplist, 0, sizeof(tmplist));
669 doaddvlist(tmplist, pcmd->argval[1].string);
671 res = doquerylist(tmplist, CTL_OP_WRITEVAR, associd, 1, &rstatus,
672 &dsize, &datap);
674 doclearvlist(tmplist);
676 if (res != 0)
677 return;
679 if (numhosts > 1)
680 (void) fprintf(fp, "server=%s ", currenthost);
681 if (dsize == 0)
682 (void) fprintf(fp, "done! (no data returned)\n");
683 else {
684 (void) fprintf(fp,"associd=%d ",associd);
685 printvars(dsize, datap, (int)rstatus,
686 (associd != 0)
687 ? TYPE_PEER
688 : TYPE_SYS,
689 0, fp);
691 return;
696 * clocklist - send a clock variables request with the variables on the list
698 static void
699 clocklist(
700 struct parse *pcmd,
701 FILE *fp
704 int associd;
706 /* HMS: uval? */
707 if (pcmd->nargs == 0) {
708 associd = 0;
709 } else {
710 if (pcmd->argval[0].uval == 0)
711 associd = 0;
712 else if ((associd = checkassocid(pcmd->argval[0].uval)) == 0)
713 return;
716 (void) dolist(g_varlist, associd, CTL_OP_READCLOCK, TYPE_CLOCK, fp);
721 * clockvar - send a clock variables request with the specified variables
723 static void
724 clockvar(
725 struct parse *pcmd,
726 FILE *fp
729 int associd;
730 struct varlist tmplist[MAXLIST];
732 /* HMS: uval? */
733 if (pcmd->nargs == 0 || pcmd->argval[0].uval == 0)
734 associd = 0;
735 else if ((associd = checkassocid(pcmd->argval[0].uval)) == 0)
736 return;
738 memset((char *)tmplist, 0, sizeof(tmplist));
739 if (pcmd->nargs >= 2)
740 doaddvlist(tmplist, pcmd->argval[1].string);
742 (void) dolist(tmplist, associd, CTL_OP_READCLOCK, TYPE_CLOCK, fp);
744 doclearvlist(tmplist);
749 * findassidrange - verify a range of association ID's
751 static int
752 findassidrange(
753 u_int32 assid1,
754 u_int32 assid2,
755 int *from,
756 int *to
759 register int i;
760 int f, t;
762 if (assid1 == 0 || assid1 > 65535) {
763 (void) fprintf(stderr,
764 "***Invalid association ID %lu specified\n", (u_long)assid1);
765 return 0;
768 if (assid2 == 0 || assid2 > 65535) {
769 fprintf(stderr,
770 "***Invalid association ID %lu specified\n", (u_long)assid2);
771 return 0;
774 f = t = -1;
775 for (i = 0; i < numassoc; i++) {
776 if (assoc_cache[i].assid == assid1) {
777 f = i;
778 if (t != -1)
779 break;
781 if (assoc_cache[i].assid == assid2) {
782 t = i;
783 if (f != -1)
784 break;
788 if (f == -1 || t == -1) {
789 (void) fprintf(stderr,
790 "***Association ID %lu not found in list\n",
791 (f == -1) ? (u_long)assid1 : (u_long)assid2);
792 return 0;
795 if (f < t) {
796 *from = f;
797 *to = t;
798 } else {
799 *from = t;
800 *to = f;
802 return 1;
808 * mreadlist - send a read variables request for multiple associations
810 static void
811 mreadlist(
812 struct parse *pcmd,
813 FILE *fp
816 int i;
817 int from;
818 int to;
820 /* HMS: uval? */
821 if (!findassidrange(pcmd->argval[0].uval, pcmd->argval[1].uval,
822 &from, &to))
823 return;
825 for (i = from; i <= to; i++) {
826 if (i != from)
827 (void) fprintf(fp, "\n");
828 if (!dolist(g_varlist, (int)assoc_cache[i].assid,
829 CTL_OP_READVAR, TYPE_PEER, fp))
830 return;
832 return;
837 * mreadvar - send a read variables request for multiple associations
839 static void
840 mreadvar(
841 struct parse *pcmd,
842 FILE *fp
845 int i;
846 int from;
847 int to;
848 struct varlist tmplist[MAXLIST];
850 /* HMS: uval? */
851 if (!findassidrange(pcmd->argval[0].uval, pcmd->argval[1].uval,
852 &from, &to))
853 return;
855 memset((char *)tmplist, 0, sizeof(tmplist));
856 if (pcmd->nargs >= 3)
857 doaddvlist(tmplist, pcmd->argval[2].string);
859 for (i = from; i <= to; i++) {
860 if (i != from)
861 (void) fprintf(fp, "\n");
862 if (!dolist(g_varlist, (int)assoc_cache[i].assid,
863 CTL_OP_READVAR, TYPE_PEER, fp))
864 break;
866 doclearvlist(tmplist);
867 return;
872 * dogetassoc - query the host for its list of associations
874 static int
875 dogetassoc(
876 FILE *fp
879 char *datap;
880 int res;
881 int dsize;
882 u_short rstatus;
884 res = doquery(CTL_OP_READSTAT, 0, 0, 0, (char *)0, &rstatus,
885 &dsize, &datap);
887 if (res != 0)
888 return 0;
890 if (dsize == 0) {
891 if (numhosts > 1)
892 (void) fprintf(fp, "server=%s ", currenthost);
893 (void) fprintf(fp, "No association ID's returned\n");
894 return 0;
897 if (dsize & 0x3) {
898 if (numhosts > 1)
899 (void) fprintf(stderr, "server=%s ", currenthost);
900 (void) fprintf(stderr,
901 "***Server returned %d octets, should be multiple of 4\n",
902 dsize);
903 return 0;
906 numassoc = 0;
907 while (dsize > 0) {
908 assoc_cache[numassoc].assid = ntohs(*((u_short *)datap));
909 datap += sizeof(u_short);
910 assoc_cache[numassoc].status = ntohs(*((u_short *)datap));
911 datap += sizeof(u_short);
912 if (++numassoc >= MAXASSOC)
913 break;
914 dsize -= sizeof(u_short) + sizeof(u_short);
916 sortassoc();
917 return 1;
922 * printassoc - print the current list of associations
924 static void
925 printassoc(
926 int showall,
927 FILE *fp
930 register char *bp;
931 int i;
932 u_char statval;
933 int event;
934 u_long event_count;
935 const char *conf;
936 const char *reach;
937 const char *auth;
938 const char *condition = "";
939 const char *last_event;
940 const char *cnt;
941 char buf[128];
943 if (numassoc == 0) {
944 (void) fprintf(fp, "No association ID's in list\n");
945 return;
949 * Output a header
951 (void) fprintf(fp,
952 "\nind assid status conf reach auth condition last_event cnt\n");
953 (void) fprintf(fp,
954 "===========================================================\n");
955 for (i = 0; i < numassoc; i++) {
956 statval = (u_char) CTL_PEER_STATVAL(assoc_cache[i].status);
957 if (!showall && !(statval & (CTL_PST_CONFIG|CTL_PST_REACH)))
958 continue;
959 event = CTL_PEER_EVENT(assoc_cache[i].status);
960 event_count = CTL_PEER_NEVNT(assoc_cache[i].status);
961 if (statval & CTL_PST_CONFIG)
962 conf = "yes";
963 else
964 conf = "no";
965 if (statval & CTL_PST_BCAST) {
966 reach = "none";
967 if (statval & CTL_PST_AUTHENABLE)
968 auth = "yes";
969 else
970 auth = "none";
971 } else {
972 if (statval & CTL_PST_REACH)
973 reach = "yes";
974 else
975 reach = "no";
976 if (statval & CTL_PST_AUTHENABLE) {
977 if (statval & CTL_PST_AUTHENTIC)
978 auth = "ok ";
979 else
980 auth = "bad";
981 } else {
982 auth = "none";
985 if (pktversion > NTP_OLDVERSION) {
986 switch (statval & 0x7) {
988 case CTL_PST_SEL_REJECT:
989 condition = "reject";
990 break;
992 case CTL_PST_SEL_SANE:
993 condition = "falsetick";
994 break;
996 case CTL_PST_SEL_CORRECT:
997 condition = "excess";
998 break;
1000 case CTL_PST_SEL_SELCAND:
1001 condition = "outlyer";
1002 break;
1004 case CTL_PST_SEL_SYNCCAND:
1005 condition = "candidate";
1006 break;
1008 case CTL_PST_SEL_EXCESS:
1009 condition = "backup";
1010 break;
1012 case CTL_PST_SEL_SYSPEER:
1013 condition = "sys.peer";
1014 break;
1016 case CTL_PST_SEL_PPS:
1017 condition = "pps.peer";
1018 break;
1020 } else {
1021 switch (statval & 0x3) {
1023 case OLD_CTL_PST_SEL_REJECT:
1024 if (!(statval & OLD_CTL_PST_SANE))
1025 condition = "insane";
1026 else if (!(statval & OLD_CTL_PST_DISP))
1027 condition = "hi_disp";
1028 else
1029 condition = "";
1030 break;
1032 case OLD_CTL_PST_SEL_SELCAND:
1033 condition = "sel_cand";
1034 break;
1036 case OLD_CTL_PST_SEL_SYNCCAND:
1037 condition = "sync_cand";
1038 break;
1040 case OLD_CTL_PST_SEL_SYSPEER:
1041 condition = "sys_peer";
1042 break;
1045 switch (PEER_EVENT|event) {
1047 case PEVNT_MOBIL:
1048 last_event = "mobilize";
1049 break;
1051 case PEVNT_DEMOBIL:
1052 last_event = "demobilize";
1053 break;
1055 case PEVNT_REACH:
1056 last_event = "reachable";
1057 break;
1059 case PEVNT_UNREACH:
1060 last_event = "unreachable";
1061 break;
1063 case PEVNT_RESTART:
1064 last_event = "restart";
1065 break;
1067 case PEVNT_REPLY:
1068 last_event = "no_reply";
1069 break;
1071 case PEVNT_RATE:
1072 last_event = "rate_exceeded";
1073 break;
1075 case PEVNT_DENY:
1076 last_event = "access_denied";
1077 break;
1079 case PEVNT_ARMED:
1080 last_event = "leap_armed";
1081 break;
1083 case PEVNT_NEWPEER:
1084 last_event = "sys_peer";
1085 break;
1087 case PEVNT_CLOCK:
1088 last_event = "clock_alarm";
1089 break;
1091 default:
1092 last_event = "";
1093 break;
1095 cnt = uinttoa(event_count);
1096 sprintf(buf,
1097 "%3d %5u %04x %3.3s %4s %4.4s %9.9s %11s %2s",
1098 i + 1, assoc_cache[i].assid, assoc_cache[i].status,
1099 conf, reach, auth, condition, last_event, cnt);
1100 bp = &buf[strlen(buf)];
1101 while (bp > buf && *(bp-1) == ' ')
1102 *(--bp) = '\0';
1103 (void) fprintf(fp, "%s\n", buf);
1109 * associations - get, record and print a list of associations
1111 /*ARGSUSED*/
1112 static void
1113 associations(
1114 struct parse *pcmd,
1115 FILE *fp
1118 if (dogetassoc(fp))
1119 printassoc(0, fp);
1124 * lassociations - get, record and print a long list of associations
1126 /*ARGSUSED*/
1127 static void
1128 lassociations(
1129 struct parse *pcmd,
1130 FILE *fp
1133 if (dogetassoc(fp))
1134 printassoc(1, fp);
1139 * passociations - print the association list
1141 /*ARGSUSED*/
1142 static void
1143 passociations(
1144 struct parse *pcmd,
1145 FILE *fp
1148 printassoc(0, fp);
1153 * lpassociations - print the long association list
1155 /*ARGSUSED*/
1156 static void
1157 lpassociations(
1158 struct parse *pcmd,
1159 FILE *fp
1162 printassoc(1, fp);
1167 * saveconfig - dump ntp server configuration to server file
1169 static void
1170 saveconfig(
1171 struct parse *pcmd,
1172 FILE *fp
1175 char *datap;
1176 int res;
1177 int dsize;
1178 u_short rstatus;
1180 if (0 == pcmd->nargs)
1181 return;
1183 res = doquery(CTL_OP_SAVECONFIG, 0, 1,
1184 strlen(pcmd->argval[0].string),
1185 pcmd->argval[0].string, &rstatus, &dsize,
1186 &datap);
1188 if (res != 0)
1189 return;
1191 if (0 == dsize)
1192 fprintf(fp, "(no response message, curiously)");
1193 else {
1194 datap[dsize] = '\0';
1195 fprintf(fp, "%s", datap);
1200 #ifdef UNUSED
1202 * radiostatus - print the radio status returned by the server
1204 /*ARGSUSED*/
1205 static void
1206 radiostatus(
1207 struct parse *pcmd,
1208 FILE *fp
1211 char *datap;
1212 int res;
1213 int dsize;
1214 u_short rstatus;
1216 res = doquery(CTL_OP_READCLOCK, 0, 0, 0, (char *)0, &rstatus,
1217 &dsize, &datap);
1219 if (res != 0)
1220 return;
1222 if (numhosts > 1)
1223 (void) fprintf(fp, "server=%s ", currenthost);
1224 if (dsize == 0) {
1225 (void) fprintf(fp, "No radio status string returned\n");
1226 return;
1229 asciize(dsize, datap, fp);
1231 #endif /* UNUSED */
1234 * pstatus - print peer status returned by the server
1236 static void
1237 pstatus(
1238 struct parse *pcmd,
1239 FILE *fp
1242 char *datap;
1243 int res;
1244 int associd;
1245 int dsize;
1246 u_short rstatus;
1248 /* HMS: uval? */
1249 if ((associd = checkassocid(pcmd->argval[0].uval)) == 0)
1250 return;
1252 res = doquery(CTL_OP_READSTAT, associd, 0, 0, (char *)0, &rstatus,
1253 &dsize, &datap);
1255 if (res != 0)
1256 return;
1258 if (numhosts > 1)
1259 (void) fprintf(fp, "server=%s ", currenthost);
1260 if (dsize == 0) {
1261 (void) fprintf(fp,
1262 "No information returned for association %u\n",
1263 associd);
1264 return;
1267 (void) fprintf(fp,"associd=%d ",associd);
1268 printvars(dsize, datap, (int)rstatus, TYPE_PEER, 0, fp);
1273 * when - print how long its been since his last packet arrived
1275 static long
1276 when(
1277 l_fp *ts,
1278 l_fp *rec,
1279 l_fp *reftime
1282 l_fp *lasttime;
1284 if (rec->l_ui != 0)
1285 lasttime = rec;
1286 else if (reftime->l_ui != 0)
1287 lasttime = reftime;
1288 else
1289 return 0;
1291 return (ts->l_ui - lasttime->l_ui);
1296 * Pretty-print an interval into the given buffer, in a human-friendly format.
1298 static char *
1299 prettyinterval(
1300 char *buf,
1301 long diff
1304 if (diff <= 0) {
1305 buf[0] = '-';
1306 buf[1] = 0;
1307 return buf;
1310 if (diff <= 2048) {
1311 (void) sprintf(buf, "%ld", (long int)diff);
1312 return buf;
1315 diff = (diff + 29) / 60;
1316 if (diff <= 300) {
1317 (void) sprintf(buf, "%ldm", (long int)diff);
1318 return buf;
1321 diff = (diff + 29) / 60;
1322 if (diff <= 96) {
1323 (void) sprintf(buf, "%ldh", (long int)diff);
1324 return buf;
1327 diff = (diff + 11) / 24;
1328 (void) sprintf(buf, "%ldd", (long int)diff);
1329 return buf;
1332 static char
1333 decodeaddrtype(
1334 sockaddr_u *sock
1337 char ch = '-';
1338 u_int32 dummy;
1340 switch(AF(sock)) {
1341 case AF_INET:
1342 dummy = SRCADR(sock);
1343 ch = (char)(((dummy&0xf0000000)==0xe0000000) ? 'm' :
1344 ((dummy&0x000000ff)==0x000000ff) ? 'b' :
1345 ((dummy&0xffffffff)==0x7f000001) ? 'l' :
1346 ((dummy&0xffffffe0)==0x00000000) ? '-' :
1347 'u');
1348 break;
1349 case AF_INET6:
1350 if (IN6_IS_ADDR_MULTICAST(PSOCK_ADDR6(sock)))
1351 ch = 'm';
1352 else
1353 ch = 'u';
1354 break;
1355 default:
1356 ch = '-';
1357 break;
1359 return ch;
1363 * A list of variables required by the peers command
1365 struct varlist opeervarlist[] = {
1366 { "srcadr", 0 }, /* 0 */
1367 { "dstadr", 0 }, /* 1 */
1368 { "stratum", 0 }, /* 2 */
1369 { "hpoll", 0 }, /* 3 */
1370 { "ppoll", 0 }, /* 4 */
1371 { "reach", 0 }, /* 5 */
1372 { "delay", 0 }, /* 6 */
1373 { "offset", 0 }, /* 7 */
1374 { "jitter", 0 }, /* 8 */
1375 { "dispersion", 0 }, /* 9 */
1376 { "rec", 0 }, /* 10 */
1377 { "reftime", 0 }, /* 11 */
1378 { "srcport", 0 }, /* 12 */
1379 { 0, 0 }
1382 struct varlist peervarlist[] = {
1383 { "srcadr", 0 }, /* 0 */
1384 { "refid", 0 }, /* 1 */
1385 { "stratum", 0 }, /* 2 */
1386 { "hpoll", 0 }, /* 3 */
1387 { "ppoll", 0 }, /* 4 */
1388 { "reach", 0 }, /* 5 */
1389 { "delay", 0 }, /* 6 */
1390 { "offset", 0 }, /* 7 */
1391 { "jitter", 0 }, /* 8 */
1392 { "dispersion", 0 }, /* 9 */
1393 { "rec", 0 }, /* 10 */
1394 { "reftime", 0 }, /* 11 */
1395 { "srcport", 0 }, /* 12 */
1396 { 0, 0 }
1399 #define HAVE_SRCADR 0
1400 #define HAVE_DSTADR 1
1401 #define HAVE_REFID 1
1402 #define HAVE_STRATUM 2
1403 #define HAVE_HPOLL 3
1404 #define HAVE_PPOLL 4
1405 #define HAVE_REACH 5
1406 #define HAVE_DELAY 6
1407 #define HAVE_OFFSET 7
1408 #define HAVE_JITTER 8
1409 #define HAVE_DISPERSION 9
1410 #define HAVE_REC 10
1411 #define HAVE_REFTIME 11
1412 #define HAVE_SRCPORT 12
1413 #define MAXHAVE 13
1416 * Decode an incoming data buffer and print a line in the peer list
1418 static int
1419 doprintpeers(
1420 struct varlist *pvl,
1421 int associd,
1422 int rstatus,
1423 int datalen,
1424 char *data,
1425 FILE *fp,
1426 int af
1429 char *name;
1430 char *value = NULL;
1431 int i;
1432 int c;
1434 sockaddr_u srcadr;
1435 sockaddr_u dstadr;
1436 u_long srcport = 0;
1437 char *dstadr_refid = "0.0.0.0";
1438 u_long stratum = 0;
1439 long ppoll = 0;
1440 long hpoll = 0;
1441 u_long reach = 0;
1442 l_fp estoffset;
1443 l_fp estdelay;
1444 l_fp estjitter;
1445 l_fp estdisp;
1446 l_fp reftime;
1447 l_fp rec;
1448 l_fp ts;
1449 u_char havevar[MAXHAVE];
1450 u_long poll_sec;
1451 char type = '?';
1452 char refid_string[10];
1453 char whenbuf[8], pollbuf[8];
1454 char clock_name[LENHOSTNAME];
1456 memset((char *)havevar, 0, sizeof(havevar));
1457 get_systime(&ts);
1459 ZERO_SOCK(&srcadr);
1460 ZERO_SOCK(&dstadr);
1462 /* Initialize by zeroing out estimate variables */
1463 memset((char *)&estoffset, 0, sizeof(l_fp));
1464 memset((char *)&estdelay, 0, sizeof(l_fp));
1465 memset((char *)&estjitter, 0, sizeof(l_fp));
1466 memset((char *)&estdisp, 0, sizeof(l_fp));
1468 while (nextvar(&datalen, &data, &name, &value)) {
1469 sockaddr_u dum_store;
1471 i = findvar(name, peer_var, 1);
1472 if (i == 0)
1473 continue; /* don't know this one */
1474 switch (i) {
1475 case CP_SRCADR:
1476 if (decodenetnum(value, &srcadr)) {
1477 havevar[HAVE_SRCADR] = 1;
1479 break;
1480 case CP_DSTADR:
1481 if (decodenetnum(value, &dum_store)) {
1482 type = decodeaddrtype(&dum_store);
1483 if (pvl == opeervarlist) {
1484 havevar[HAVE_DSTADR] = 1;
1485 dstadr = dum_store;
1486 dstadr_refid = stoa(&dstadr);
1489 break;
1490 case CP_REFID:
1491 if (pvl == peervarlist) {
1492 havevar[HAVE_REFID] = 1;
1493 if (*value == '\0') {
1494 dstadr_refid = "0.0.0.0";
1495 } else if ((int)strlen(value) <= 4) {
1496 refid_string[0] = '.';
1497 (void) strcpy(&refid_string[1], value);
1498 i = strlen(refid_string);
1499 refid_string[i] = '.';
1500 refid_string[i+1] = '\0';
1501 dstadr_refid = refid_string;
1502 } else if (decodenetnum(value, &dstadr)) {
1503 if (SOCK_UNSPEC(&dstadr))
1504 dstadr_refid = "0.0.0.0";
1505 else if (ISREFCLOCKADR(&dstadr))
1506 dstadr_refid =
1507 refnumtoa(&dstadr);
1508 else
1509 dstadr_refid =
1510 stoa(&dstadr);
1511 } else {
1512 havevar[HAVE_REFID] = 0;
1515 break;
1516 case CP_STRATUM:
1517 if (decodeuint(value, &stratum))
1518 havevar[HAVE_STRATUM] = 1;
1519 break;
1520 case CP_HPOLL:
1521 if (decodeint(value, &hpoll)) {
1522 havevar[HAVE_HPOLL] = 1;
1523 if (hpoll < 0)
1524 hpoll = NTP_MINPOLL;
1526 break;
1527 case CP_PPOLL:
1528 if (decodeint(value, &ppoll)) {
1529 havevar[HAVE_PPOLL] = 1;
1530 if (ppoll < 0)
1531 ppoll = NTP_MINPOLL;
1533 break;
1534 case CP_REACH:
1535 if (decodeuint(value, &reach))
1536 havevar[HAVE_REACH] = 1;
1537 break;
1538 case CP_DELAY:
1539 if (decodetime(value, &estdelay))
1540 havevar[HAVE_DELAY] = 1;
1541 break;
1542 case CP_OFFSET:
1543 if (decodetime(value, &estoffset))
1544 havevar[HAVE_OFFSET] = 1;
1545 break;
1546 case CP_JITTER:
1547 if (pvl == peervarlist)
1548 if (decodetime(value, &estjitter))
1549 havevar[HAVE_JITTER] = 1;
1550 break;
1551 case CP_DISPERSION:
1552 if (decodetime(value, &estdisp))
1553 havevar[HAVE_DISPERSION] = 1;
1554 break;
1555 case CP_REC:
1556 if (decodets(value, &rec))
1557 havevar[HAVE_REC] = 1;
1558 break;
1559 case CP_SRCPORT:
1560 if (decodeuint(value, &srcport))
1561 havevar[HAVE_SRCPORT] = 1;
1562 break;
1563 case CP_REFTIME:
1564 havevar[HAVE_REFTIME] = 1;
1565 if (!decodets(value, &reftime))
1566 L_CLR(&reftime);
1567 break;
1568 default:
1569 break;
1574 * Check to see if the srcport is NTP's port. If not this probably
1575 * isn't a valid peer association.
1577 if (havevar[HAVE_SRCPORT] && srcport != NTP_PORT)
1578 return (1);
1581 * Got everything, format the line
1583 poll_sec = 1<<max(min3(ppoll, hpoll, NTP_MAXPOLL), NTP_MINPOLL);
1584 if (pktversion > NTP_OLDVERSION)
1585 c = flash3[CTL_PEER_STATVAL(rstatus) & 0x7];
1586 else
1587 c = flash2[CTL_PEER_STATVAL(rstatus) & 0x3];
1588 if (numhosts > 1)
1589 (void) fprintf(fp, "%-*s ", maxhostlen, currenthost);
1590 if (af == 0 || AF(&srcadr) == af) {
1591 strcpy(clock_name, nntohost(&srcadr));
1593 (void) fprintf(fp,
1594 "%c%-15.15s %-15.15s %2ld %c %4.4s %4.4s %3lo %7.7s %8.7s %7.7s\n",
1595 c, clock_name, dstadr_refid, stratum, type,
1596 prettyinterval(whenbuf, when(&ts, &rec, &reftime)),
1597 prettyinterval(pollbuf, (int)poll_sec), reach,
1598 lfptoms(&estdelay, 3), lfptoms(&estoffset, 3),
1599 havevar[HAVE_JITTER] ? lfptoms(&estjitter, 3) :
1600 lfptoms(&estdisp, 3));
1601 return (1);
1603 else
1604 return(1);
1607 #undef HAVE_SRCADR
1608 #undef HAVE_DSTADR
1609 #undef HAVE_STRATUM
1610 #undef HAVE_PPOLL
1611 #undef HAVE_HPOLL
1612 #undef HAVE_REACH
1613 #undef HAVE_ESTDELAY
1614 #undef HAVE_ESTOFFSET
1615 #undef HAVE_JITTER
1616 #undef HAVE_ESTDISP
1617 #undef HAVE_REFID
1618 #undef HAVE_REC
1619 #undef HAVE_SRCPORT
1620 #undef HAVE_REFTIME
1621 #undef MAXHAVE
1625 * dogetpeers - given an association ID, read and print the spreadsheet
1626 * peer variables.
1628 static int
1629 dogetpeers(
1630 struct varlist *pvl,
1631 int associd,
1632 FILE *fp,
1633 int af
1636 char *datap;
1637 int res;
1638 int dsize;
1639 u_short rstatus;
1641 #ifdef notdef
1642 res = doquerylist(pvl, CTL_OP_READVAR, associd, 0, &rstatus,
1643 &dsize, &datap);
1644 #else
1646 * Damn fuzzballs
1648 res = doquery(CTL_OP_READVAR, associd, 0, 0, (char *)0, &rstatus,
1649 &dsize, &datap);
1650 #endif
1652 if (res != 0)
1653 return 0;
1655 if (dsize == 0) {
1656 if (numhosts > 1)
1657 (void) fprintf(stderr, "server=%s ", currenthost);
1658 (void) fprintf(stderr,
1659 "***No information returned for association %d\n",
1660 associd);
1661 return 0;
1664 return doprintpeers(pvl, associd, (int)rstatus, dsize, datap, fp, af);
1669 * peers - print a peer spreadsheet
1671 static void
1672 dopeers(
1673 int showall,
1674 FILE *fp,
1675 int af
1678 register int i;
1679 char fullname[LENHOSTNAME];
1680 sockaddr_u netnum;
1682 if (!dogetassoc(fp))
1683 return;
1685 for (i = 0; i < numhosts; ++i) {
1686 if (getnetnum(chosts[i], &netnum, fullname, af))
1687 if ((int)strlen(fullname) > maxhostlen)
1688 maxhostlen = strlen(fullname);
1690 if (numhosts > 1)
1691 (void) fprintf(fp, "%-*.*s ", maxhostlen, maxhostlen, "server");
1692 (void) fprintf(fp,
1693 " remote refid st t when poll reach delay offset jitter\n");
1694 if (numhosts > 1)
1695 for (i = 0; i <= maxhostlen; ++i)
1696 (void) fprintf(fp, "=");
1697 (void) fprintf(fp,
1698 "==============================================================================\n");
1700 for (i = 0; i < numassoc; i++) {
1701 if (!showall &&
1702 !(CTL_PEER_STATVAL(assoc_cache[i].status)
1703 & (CTL_PST_CONFIG|CTL_PST_REACH)))
1704 continue;
1705 if (!dogetpeers(peervarlist, (int)assoc_cache[i].assid, fp, af)) {
1706 return;
1709 return;
1714 * peers - print a peer spreadsheet
1716 /*ARGSUSED*/
1717 static void
1718 peers(
1719 struct parse *pcmd,
1720 FILE *fp
1723 int af = 0;
1725 if (pcmd->nargs == 1) {
1726 if (pcmd->argval->ival == 6)
1727 af = AF_INET6;
1728 else
1729 af = AF_INET;
1731 dopeers(0, fp, af);
1736 * lpeers - print a peer spreadsheet including all fuzzball peers
1738 /*ARGSUSED*/
1739 static void
1740 lpeers(
1741 struct parse *pcmd,
1742 FILE *fp
1745 int af = 0;
1747 if (pcmd->nargs == 1) {
1748 if (pcmd->argval->ival == 6)
1749 af = AF_INET6;
1750 else
1751 af = AF_INET;
1753 dopeers(1, fp, af);
1758 * opeers - print a peer spreadsheet
1760 static void
1761 doopeers(
1762 int showall,
1763 FILE *fp,
1764 int af
1767 register int i;
1768 char fullname[LENHOSTNAME];
1769 sockaddr_u netnum;
1771 if (!dogetassoc(fp))
1772 return;
1774 for (i = 0; i < numhosts; ++i) {
1775 if (getnetnum(chosts[i], &netnum, fullname, af))
1776 if ((int)strlen(fullname) > maxhostlen)
1777 maxhostlen = strlen(fullname);
1779 if (numhosts > 1)
1780 (void) fprintf(fp, "%-*.*s ", maxhostlen, maxhostlen, "server");
1781 (void) fprintf(fp,
1782 " remote local st t when poll reach delay offset disp\n");
1783 if (numhosts > 1)
1784 for (i = 0; i <= maxhostlen; ++i)
1785 (void) fprintf(fp, "=");
1786 (void) fprintf(fp,
1787 "==============================================================================\n");
1789 for (i = 0; i < numassoc; i++) {
1790 if (!showall &&
1791 !(CTL_PEER_STATVAL(assoc_cache[i].status)
1792 & (CTL_PST_CONFIG|CTL_PST_REACH)))
1793 continue;
1794 if (!dogetpeers(opeervarlist, (int)assoc_cache[i].assid, fp, af)) {
1795 return;
1798 return;
1803 * opeers - print a peer spreadsheet the old way
1805 /*ARGSUSED*/
1806 static void
1807 opeers(
1808 struct parse *pcmd,
1809 FILE *fp
1812 int af = 0;
1814 if (pcmd->nargs == 1) {
1815 if (pcmd->argval->ival == 6)
1816 af = AF_INET6;
1817 else
1818 af = AF_INET;
1820 doopeers(0, fp, af);
1825 * lopeers - print a peer spreadsheet including all fuzzball peers
1827 /*ARGSUSED*/
1828 static void
1829 lopeers(
1830 struct parse *pcmd,
1831 FILE *fp
1834 int af = 0;
1836 if (pcmd->nargs == 1) {
1837 if (pcmd->argval->ival == 6)
1838 af = AF_INET6;
1839 else
1840 af = AF_INET;
1842 doopeers(1, fp, af);
1847 * config - send a configuration command to a remote host
1849 static void
1850 config (
1851 struct parse *pcmd,
1852 FILE *fp
1855 char *cfgcmd;
1856 u_short rstatus;
1857 int rsize;
1858 char *rdata;
1859 int res;
1860 int col;
1861 int i;
1863 cfgcmd = pcmd->argval[0].string;
1865 if (debug > 2) {
1866 printf("In Config\n");
1867 printf("Keyword = %s\n", pcmd->keyword);
1868 printf("Command = %s\n", cfgcmd);
1871 res = doquery(CTL_OP_CONFIGURE, 0, 1, strlen(cfgcmd), cfgcmd,
1872 &rstatus, &rsize, &rdata);
1874 if (res != 0)
1875 return;
1877 if (rsize > 0 && '\n' == rdata[rsize - 1])
1878 rsize--;
1879 rdata[rsize] = '\0';
1881 col = -1;
1882 if (1 == sscanf(rdata, "column %d syntax error", &col)
1883 && col >= 0 && (size_t)col <= strlen(cfgcmd) + 1) {
1884 if (interactive) {
1885 printf("______"); /* "ntpq> " */
1886 printf("________"); /* ":config " */
1887 } else
1888 printf("%s\n", cfgcmd);
1889 for (i = 1; i < col; i++)
1890 putchar('_');
1891 printf("^\n");
1893 printf("%s\n", rdata);
1898 * config_from_file - remotely configure an ntpd daemon using the
1899 * specified configuration file
1900 * SK: This function is a kludge at best and is full of bad design
1901 * bugs:
1902 * 1. ntpq uses UDP, which means that there is no guarantee of in-order,
1903 * error-free delivery.
1904 * 2. The maximum length of a packet is constrained, and as a result, the
1905 * maximum length of a line in a configuration file is constrained.
1906 * Longer lines will lead to unpredictable results.
1907 * 3. Since this function is sending a line at a time, we can't update
1908 * the control key through the configuration file (YUCK!!)
1910 static void
1911 config_from_file (
1912 struct parse *pcmd,
1913 FILE *fp
1916 u_short rstatus;
1917 int rsize;
1918 char *rdata;
1919 int res;
1920 FILE *config_fd;
1921 char config_cmd[MAXLINE];
1922 size_t config_len;
1923 int i;
1924 int retry_limit;
1926 if (debug > 2) {
1927 printf("In Config\n");
1928 printf("Keyword = %s\n", pcmd->keyword);
1929 printf("Filename = %s\n", pcmd->argval[0].string);
1932 config_fd = fopen(pcmd->argval[0].string, "r");
1933 if (NULL == config_fd) {
1934 printf("ERROR!! Couldn't open file: %s\n",
1935 pcmd->argval[0].string);
1936 return;
1939 printf("Sending configuration file, one line at a time.\n");
1940 i = 0;
1941 while (fgets(config_cmd, MAXLINE, config_fd) != NULL) {
1942 config_len = strlen(config_cmd);
1943 /* ensure even the last line has newline, if possible */
1944 if (config_len > 0 &&
1945 config_len + 2 < sizeof(config_cmd) &&
1946 '\n' != config_cmd[config_len - 1])
1947 config_cmd[config_len++] = '\n';
1948 ++i;
1949 retry_limit = 2;
1951 res = doquery(CTL_OP_CONFIGURE, 0, 1,
1952 strlen(config_cmd), config_cmd,
1953 &rstatus, &rsize, &rdata);
1954 while (res != 0 && retry_limit--);
1955 if (res != 0) {
1956 printf("Line No: %d query failed: %s", i,
1957 config_cmd);
1958 printf("Subsequent lines not sent.\n");
1959 fclose(config_fd);
1960 return;
1963 if (rsize > 0 && '\n' == rdata[rsize - 1])
1964 rsize--;
1965 if (rsize > 0 && '\r' == rdata[rsize - 1])
1966 rsize--;
1967 rdata[rsize] = '\0';
1968 printf("Line No: %d %s: %s", i, rdata, config_cmd);
1970 printf("Done sending file\n");
1971 fclose(config_fd);