2 * ntpq_ops.c - subroutines which are called to perform operations by ntpq
12 #include "ntp_stdlib.h"
14 extern char * chosts[];
15 extern char currenthost[];
20 * Declarations for command handlers in here
22 static int checkassocid P((u_int32));
23 static char * strsave P((char *));
24 static struct varlist *findlistvar P((struct varlist *, char *));
25 static void doaddvlist P((struct varlist *, char *));
26 static void dormvlist P((struct varlist *, char *));
27 static void doclearvlist P((struct varlist *));
28 static void makequerydata P((struct varlist *, int *, char *));
29 static int doquerylist P((struct varlist *, int, int, int, u_short *, int *, char **));
30 static void doprintvlist P((struct varlist *, FILE *));
31 static void addvars P((struct parse *, FILE *));
32 static void rmvars P((struct parse *, FILE *));
33 static void clearvars P((struct parse *, FILE *));
34 static void showvars P((struct parse *, FILE *));
35 static int dolist P((struct varlist *, int, int, int, FILE *));
36 static void readlist P((struct parse *, FILE *));
37 static void writelist P((struct parse *, FILE *));
38 static void readvar P((struct parse *, FILE *));
39 static void writevar P((struct parse *, FILE *));
40 static void clocklist P((struct parse *, FILE *));
41 static void clockvar P((struct parse *, FILE *));
42 static int findassidrange P((u_int32, u_int32, int *, int *));
43 static void mreadlist P((struct parse *, FILE *));
44 static void mreadvar P((struct parse *, FILE *));
45 static int dogetassoc P((FILE *));
46 static void printassoc P((int, FILE *));
47 static void associations P((struct parse *, FILE *));
48 static void lassociations P((struct parse *, FILE *));
49 static void passociations P((struct parse *, FILE *));
50 static void lpassociations P((struct parse *, FILE *));
53 static void radiostatus P((struct parse *, FILE *));
56 static void pstatus P((struct parse *, FILE *));
57 static long when P((l_fp *, l_fp *, l_fp *));
58 static char * prettyinterval P((char *, long));
59 static int doprintpeers P((struct varlist *, int, int, int, char *, FILE *, int));
60 static int dogetpeers P((struct varlist *, int, FILE *, int));
61 static void dopeers P((int, FILE *, int));
62 static void peers P((struct parse *, FILE *));
63 static void lpeers P((struct parse *, FILE *));
64 static void doopeers P((int, FILE *, int));
65 static void opeers P((struct parse *, FILE *));
66 static void lopeers P((struct parse *, FILE *));
70 * Commands we understand. Ntpdc imports this.
72 struct xcmd opcmds[] = {
73 { "associations", associations, { NO, NO, NO, NO },
75 "print list of association ID's and statuses for the server's peers" },
76 { "passociations", passociations, { NO, NO, NO, NO },
78 "print list of associations returned by last associations command" },
79 { "lassociations", lassociations, { NO, NO, NO, NO },
81 "print list of associations including all client information" },
82 { "lpassociations", lpassociations, { NO, NO, NO, NO },
84 "print last obtained list of associations, including client information" },
85 { "addvars", addvars, { STR, NO, NO, NO },
86 { "name[=value][,...]", "", "", "" },
87 "add variables to the variable list or change their values" },
88 { "rmvars", rmvars, { STR, NO, NO, NO },
89 { "name[,...]", "", "", "" },
90 "remove variables from the variable list" },
91 { "clearvars", clearvars, { NO, NO, NO, NO },
93 "remove all variables from the variable list" },
94 { "showvars", showvars, { NO, NO, NO, NO },
96 "print variables on the variable list" },
97 { "readlist", readlist, { OPT|UINT, NO, NO, NO },
98 { "assocID", "", "", "" },
99 "read the system or peer variables included in the variable list" },
100 { "rl", readlist, { OPT|UINT, NO, NO, NO },
101 { "assocID", "", "", "" },
102 "read the system or peer variables included in the variable list" },
103 { "writelist", writelist, { OPT|UINT, NO, NO, NO },
104 { "assocID", "", "", "" },
105 "write the system or peer variables included in the variable list" },
106 { "readvar", readvar, { OPT|UINT, OPT|STR, NO, NO },
107 { "assocID", "name=value[,...]", "", "" },
108 "read system or peer variables" },
109 { "rv", readvar, { OPT|UINT, OPT|STR, NO, NO },
110 { "assocID", "name=value[,...]", "", "" },
111 "read system or peer variables" },
112 { "writevar", writevar, { UINT, STR, NO, NO },
113 { "assocID", "name=value,[...]", "", "" },
114 "write system or peer variables" },
115 { "mreadlist", mreadlist, { UINT, UINT, NO, NO },
116 { "assocID", "assocID", "", "" },
117 "read the peer variables in the variable list for multiple peers" },
118 { "mrl", mreadlist, { UINT, UINT, NO, NO },
119 { "assocID", "assocID", "", "" },
120 "read the peer variables in the variable list for multiple peers" },
121 { "mreadvar", mreadvar, { UINT, UINT, OPT|STR, NO },
122 { "assocID", "assocID", "name=value[,...]", "" },
123 "read peer variables from multiple peers" },
124 { "mrv", mreadvar, { UINT, UINT, OPT|STR, NO },
125 { "assocID", "assocID", "name=value[,...]", "" },
126 "read peer variables from multiple peers" },
127 { "clocklist", clocklist, { OPT|UINT, NO, NO, NO },
128 { "assocID", "", "", "" },
129 "read the clock variables included in the variable list" },
130 { "cl", clocklist, { OPT|UINT, NO, NO, NO },
131 { "assocID", "", "", "" },
132 "read the clock variables included in the variable list" },
133 { "clockvar", clockvar, { OPT|UINT, OPT|STR, NO, NO },
134 { "assocID", "name=value[,...]", "", "" },
135 "read clock variables" },
136 { "cv", clockvar, { OPT|UINT, OPT|STR, NO, NO },
137 { "assocID", "name=value[,...]", "", "" },
138 "read clock variables" },
139 { "pstatus", pstatus, { UINT, NO, NO, NO },
140 { "assocID", "", "", "" },
141 "print status information returned for a peer" },
142 { "peers", peers, { OPT|IP_VERSION, NO, NO, NO },
143 { "-4|-6", "", "", "" },
144 "obtain and print a list of the server's peers [IP version]" },
145 { "lpeers", lpeers, { OPT|IP_VERSION, NO, NO, NO },
146 { "-4|-6", "", "", "" },
147 "obtain and print a list of all peers and clients [IP version]" },
148 { "opeers", opeers, { OPT|IP_VERSION, NO, NO, NO },
149 { "-4|-6", "", "", "" },
150 "print peer list the old way, with dstadr shown rather than refid [IP version]" },
151 { "lopeers", lopeers, { OPT|IP_VERSION, NO, NO, NO },
152 { "-4|-6", "", "", "" },
153 "obtain and print a list of all peers and clients showing dstadr [IP version]" },
154 { 0, 0, { NO, NO, NO, NO },
155 { "-4|-6", "", "", "" }, "" }
160 * Variable list data space
162 #define MAXLIST 64 /* maximum number of variables in list */
163 #define LENHOSTNAME 256 /* host name is 256 characters long */
165 * Old CTL_PST defines for version 2.
167 #define OLD_CTL_PST_CONFIG 0x80
168 #define OLD_CTL_PST_AUTHENABLE 0x40
169 #define OLD_CTL_PST_AUTHENTIC 0x20
170 #define OLD_CTL_PST_REACH 0x10
171 #define OLD_CTL_PST_SANE 0x08
172 #define OLD_CTL_PST_DISP 0x04
173 #define OLD_CTL_PST_SEL_REJECT 0
174 #define OLD_CTL_PST_SEL_SELCAND 1
175 #define OLD_CTL_PST_SEL_SYNCCAND 2
176 #define OLD_CTL_PST_SEL_SYSPEER 3
179 char flash2[] = " .+* "; /* flash decode for version 2 */
180 char flash3[] = " x.-+#*o"; /* flash decode for peer status version 3 */
185 } varlist[MAXLIST] = { { 0, 0 } };
188 * Imported from ntpq.c
190 extern int showhostnames;
192 extern struct servent *server_entry;
193 extern struct association assoc_cache[];
195 extern u_char pktversion;
196 extern struct ctl_var peer_var[];
199 * For quick string comparisons
201 #define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0)
205 * checkassocid - return the association ID, checking to see if it is valid
212 if (value == 0 || value >= 65536) {
213 (void) fprintf(stderr, "***Invalid association ID specified\n");
221 * strsave - save a string
222 * XXX - should be in libntp.a
232 len = strlen(str) + 1;
233 if ((cp = (char *)malloc(len)) == NULL) {
234 (void) fprintf(stderr, "Malloc failed!!\n");
238 memmove(cp, str, len);
244 * findlistvar - look for the named variable in a list and return if found
246 static struct varlist *
248 struct varlist *list,
252 register struct varlist *vl;
254 for (vl = list; vl < list + MAXLIST && vl->name != 0; vl++)
255 if (STREQ(name, vl->name))
257 if (vl < list + MAXLIST)
259 return (struct varlist *)0;
264 * doaddvlist - add variable(s) to the variable list
268 struct varlist *vlist,
272 register struct varlist *vl;
278 while (nextvar(&len, &vars, &name, &value)) {
279 vl = findlistvar(vlist, name);
281 (void) fprintf(stderr, "Variable list full\n");
286 vl->name = strsave(name);
287 } else if (vl->value != 0) {
293 vl->value = strsave(value);
299 * dormvlist - remove variable(s) from the variable list
303 struct varlist *vlist,
307 register struct varlist *vl;
313 while (nextvar(&len, &vars, &name, &value)) {
314 vl = findlistvar(vlist, name);
315 if (vl == 0 || vl->name == 0) {
316 (void) fprintf(stderr, "Variable `%s' not found\n",
319 free((void *)vl->name);
322 for ( ; (vl+1) < (varlist+MAXLIST)
323 && (vl+1)->name != 0; vl++) {
324 vl->name = (vl+1)->name;
325 vl->value = (vl+1)->value;
327 vl->name = vl->value = 0;
334 * doclearvlist - clear a variable list
338 struct varlist *vlist
341 register struct varlist *vl;
343 for (vl = vlist; vl < vlist + MAXLIST && vl->name != 0; vl++) {
344 free((void *)vl->name);
346 if (vl->value != 0) {
355 * makequerydata - form a data buffer to be included with a query
359 struct varlist *vlist,
364 register struct varlist *vl;
365 register char *cp, *cpend;
366 register int namelen, valuelen;
367 register int totallen;
370 cpend = data + *datalen;
372 for (vl = vlist; vl < vlist + MAXLIST && vl->name != 0; vl++) {
373 namelen = strlen(vl->name);
377 valuelen = strlen(vl->value);
378 totallen = namelen + valuelen + (valuelen != 0) + (cp != data);
379 if (cp + totallen > cpend)
384 memmove(cp, vl->name, (unsigned)namelen);
388 memmove(cp, vl->value, (unsigned)valuelen);
392 *datalen = cp - data;
397 * doquerylist - send a message including variables in a list
401 struct varlist *vlist,
410 char data[CTL_MAX_DATA_LEN];
413 datalen = sizeof(data);
414 makequerydata(vlist, &datalen, data);
416 return doquery(op, associd, auth, datalen, data, rstatus,
422 * doprintvlist - print the variables on a list
426 struct varlist *vlist,
430 register struct varlist *vl;
432 if (vlist->name == 0) {
433 (void) fprintf(fp, "No variables on list\n");
435 for (vl = vlist; vl < vlist + MAXLIST && vl->name != 0; vl++) {
436 if (vl->value == 0) {
437 (void) fprintf(fp, "%s\n", vl->name);
439 (void) fprintf(fp, "%s=%s\n",
440 vl->name, vl->value);
448 * addvars - add variables to the variable list
457 doaddvlist(varlist, pcmd->argval[0].string);
462 * rmvars - remove variables from the variable list
471 dormvlist(varlist, pcmd->argval[0].string);
476 * clearvars - clear the variable list
485 doclearvlist(varlist);
490 * showvars - show variables on the variable list
499 doprintvlist(varlist, fp);
504 * dolist - send a request with the given list of variables
508 struct varlist *vlist,
520 res = doquerylist(vlist, op, associd, 0, &rstatus, &dsize, &datap);
527 (void) fprintf(fp, "No system%s variables returned\n",
528 (type == TYPE_CLOCK) ? " clock" : "");
531 "No information returned for%s association %u\n",
532 (type == TYPE_CLOCK) ? " clock" : "", associd);
536 printvars(dsize, datap, (int)rstatus, type, fp);
542 * readlist - send a read variables request with the variables on the list
552 if (pcmd->nargs == 0) {
555 /* HMS: I think we want the u_int32 target here, not the u_long */
556 if (pcmd->argval[0].uval == 0)
558 else if ((associd = checkassocid(pcmd->argval[0].uval)) == 0)
562 (void) dolist(varlist, associd, CTL_OP_READVAR,
563 (associd == 0) ? TYPE_SYS : TYPE_PEER, fp);
568 * writelist - send a write variables request with the variables on the list
582 if (pcmd->nargs == 0) {
585 /* HMS: Do we really want uval here? */
586 if (pcmd->argval[0].uval == 0)
588 else if ((associd = checkassocid(pcmd->argval[0].uval)) == 0)
592 res = doquerylist(varlist, CTL_OP_WRITEVAR, associd, 1, &rstatus,
599 (void) fprintf(fp, "done! (no data returned)\n");
601 printvars(dsize, datap, (int)rstatus,
602 (associd != 0) ? TYPE_PEER : TYPE_SYS, fp);
608 * readvar - send a read variables request with the specified variables
617 struct varlist tmplist[MAXLIST];
620 if (pcmd->nargs == 0 || pcmd->argval[0].uval == 0)
622 else if ((associd = checkassocid(pcmd->argval[0].uval)) == 0)
625 memset((char *)tmplist, 0, sizeof(tmplist));
626 if (pcmd->nargs >= 2)
627 doaddvlist(tmplist, pcmd->argval[1].string);
629 (void) dolist(tmplist, associd, CTL_OP_READVAR,
630 (associd == 0) ? TYPE_SYS : TYPE_PEER, fp);
632 doclearvlist(tmplist);
637 * writevar - send a write variables request with the specified variables
650 struct varlist tmplist[MAXLIST];
653 if (pcmd->argval[0].uval == 0)
655 else if ((associd = checkassocid(pcmd->argval[0].uval)) == 0)
658 memset((char *)tmplist, 0, sizeof(tmplist));
659 doaddvlist(tmplist, pcmd->argval[1].string);
661 res = doquerylist(tmplist, CTL_OP_WRITEVAR, associd, 1, &rstatus,
664 doclearvlist(tmplist);
670 (void) fprintf(fp, "done! (no data returned)\n");
672 printvars(dsize, datap, (int)rstatus,
673 (associd != 0) ? TYPE_PEER : TYPE_SYS, fp);
679 * clocklist - send a clock variables request with the variables on the list
690 if (pcmd->nargs == 0) {
693 if (pcmd->argval[0].uval == 0)
695 else if ((associd = checkassocid(pcmd->argval[0].uval)) == 0)
699 (void) dolist(varlist, associd, CTL_OP_READCLOCK, TYPE_CLOCK, fp);
704 * clockvar - send a clock variables request with the specified variables
713 struct varlist tmplist[MAXLIST];
716 if (pcmd->nargs == 0 || pcmd->argval[0].uval == 0)
718 else if ((associd = checkassocid(pcmd->argval[0].uval)) == 0)
721 memset((char *)tmplist, 0, sizeof(tmplist));
722 if (pcmd->nargs >= 2)
723 doaddvlist(tmplist, pcmd->argval[1].string);
725 (void) dolist(tmplist, associd, CTL_OP_READCLOCK, TYPE_CLOCK, fp);
727 doclearvlist(tmplist);
732 * findassidrange - verify a range of association ID's
745 if (assid1 == 0 || assid1 > 65535) {
746 (void) fprintf(stderr,
747 "***Invalid association ID %lu specified\n", (u_long)assid1);
751 if (assid2 == 0 || assid2 > 65535) {
752 (void) fprintf(stderr,
753 "***Invalid association ID %lu specified\n", (u_long)assid2);
758 for (i = 0; i < numassoc; i++) {
759 if (assoc_cache[i].assid == assid1) {
764 if (assoc_cache[i].assid == assid2) {
771 if (f == -1 || t == -1) {
772 (void) fprintf(stderr,
773 "***Association ID %lu not found in list\n",
774 (f == -1) ? (u_long)assid1 : (u_long)assid2);
791 * mreadlist - send a read variables request for multiple associations
804 if (!findassidrange(pcmd->argval[0].uval, pcmd->argval[1].uval,
808 for (i = from; i <= to; i++) {
810 (void) fprintf(fp, "\n");
811 if (!dolist(varlist, (int)assoc_cache[i].assid,
812 CTL_OP_READVAR, TYPE_PEER, fp))
820 * mreadvar - send a read variables request for multiple associations
831 struct varlist tmplist[MAXLIST];
834 if (!findassidrange(pcmd->argval[0].uval, pcmd->argval[1].uval,
838 memset((char *)tmplist, 0, sizeof(tmplist));
839 if (pcmd->nargs >= 3)
840 doaddvlist(tmplist, pcmd->argval[2].string);
842 for (i = from; i <= to; i++) {
844 (void) fprintf(fp, "\n");
845 if (!dolist(varlist, (int)assoc_cache[i].assid,
846 CTL_OP_READVAR, TYPE_PEER, fp))
849 doclearvlist(tmplist);
855 * dogetassoc - query the host for its list of associations
867 res = doquery(CTL_OP_READSTAT, 0, 0, 0, (char *)0, &rstatus,
868 &dsize, (void *)&datap);
874 (void) fprintf(fp, "No association ID's returned\n");
879 (void) fprintf(stderr,
880 "***Server returned %d octets, should be multiple of 4\n",
887 assoc_cache[numassoc].assid = ntohs(*datap);
889 assoc_cache[numassoc].status = ntohs(*datap);
891 if (++numassoc >= MAXASSOC)
893 dsize -= sizeof(u_short) + sizeof(u_short);
901 * printassoc - print the current list of associations
917 const char *condition = "";
918 const char *last_event;
923 (void) fprintf(fp, "No association ID's in list\n");
931 "ind assID status conf reach auth condition last_event cnt\n");
933 "===========================================================\n");
934 for (i = 0; i < numassoc; i++) {
935 statval = (u_char) CTL_PEER_STATVAL(assoc_cache[i].status);
936 if (!showall && !(statval & (CTL_PST_CONFIG|CTL_PST_REACH)))
938 event = CTL_PEER_EVENT(assoc_cache[i].status);
939 event_count = CTL_PEER_NEVNT(assoc_cache[i].status);
940 if (statval & CTL_PST_CONFIG)
944 if (statval & CTL_PST_REACH || 1) {
946 if (statval & CTL_PST_AUTHENABLE) {
947 if (statval & CTL_PST_AUTHENTIC)
954 if (pktversion > NTP_OLDVERSION)
955 switch (statval & 0x7) {
956 case CTL_PST_SEL_REJECT:
957 condition = "reject";
959 case CTL_PST_SEL_SANE:
960 condition = "falsetick";
962 case CTL_PST_SEL_CORRECT:
963 condition = "excess";
965 case CTL_PST_SEL_SELCAND:
966 condition = "outlyer";
968 case CTL_PST_SEL_SYNCCAND:
969 condition = "candidat";
971 case CTL_PST_SEL_DISTSYSPEER:
972 condition = "selected";
974 case CTL_PST_SEL_SYSPEER:
975 condition = "sys.peer";
977 case CTL_PST_SEL_PPS:
978 condition = "pps.peer";
982 switch (statval & 0x3) {
983 case OLD_CTL_PST_SEL_REJECT:
984 if (!(statval & OLD_CTL_PST_SANE))
985 condition = "insane";
986 else if (!(statval & OLD_CTL_PST_DISP))
987 condition = "hi_disp";
991 case OLD_CTL_PST_SEL_SELCAND:
992 condition = "sel_cand";
994 case OLD_CTL_PST_SEL_SYNCCAND:
995 condition = "sync_cand";
997 case OLD_CTL_PST_SEL_SYSPEER:
998 condition = "sys_peer";
1004 auth = condition = "";
1007 switch (PEER_EVENT|event) {
1008 case EVNT_PEERIPERR:
1009 last_event = "IP error";
1012 last_event = "auth fail";
1015 last_event = "lost reach";
1018 last_event = "reachable";
1020 case EVNT_PEERCLOCK:
1021 last_event = "clock expt";
1024 case EVNT_PEERSTRAT:
1025 last_event = "stratum chg";
1033 if (event_count != 0)
1034 cnt = uinttoa(event_count);
1038 "%3d %5u %04x %3.3s %4s %4.4s %9.9s %11s %2s",
1039 i+1, assoc_cache[i].assid, assoc_cache[i].status,
1040 conf, reach, auth, condition, last_event, cnt);
1041 bp = &buf[strlen(buf)];
1042 while (bp > buf && *(bp-1) == ' ')
1044 (void) fprintf(fp, "%s\n", buf);
1051 * associations - get, record and print a list of associations
1066 * lassociations - get, record and print a long list of associations
1081 * passociations - print the association list
1095 * lpassociations - print the long association list
1110 * radiostatus - print the radio status returned by the server
1124 res = doquery(CTL_OP_READCLOCK, 0, 0, 0, (char *)0, &rstatus,
1131 (void) fprintf(fp, "No radio status string returned\n");
1135 asciize(dsize, datap, fp);
1140 * pstatus - print peer status returned by the server
1155 if ((associd = checkassocid(pcmd->argval[0].uval)) == 0)
1158 res = doquery(CTL_OP_READSTAT, associd, 0, 0, (char *)0, &rstatus,
1166 "No information returned for association %u\n",
1171 printvars(dsize, datap, (int)rstatus, TYPE_PEER, fp);
1176 * when - print how long its been since his last packet arrived
1189 else if (reftime->l_ui != 0)
1194 return (ts->l_ui - lasttime->l_ui);
1199 * Pretty-print an interval into the given buffer, in a human-friendly format.
1214 (void) sprintf(buf, "%ld", (long int)diff);
1218 diff = (diff + 29) / 60;
1220 (void) sprintf(buf, "%ldm", (long int)diff);
1224 diff = (diff + 29) / 60;
1226 (void) sprintf(buf, "%ldh", (long int)diff);
1230 diff = (diff + 11) / 24;
1231 (void) sprintf(buf, "%ldd", (long int)diff);
1237 struct sockaddr_storage *sock
1242 struct sockaddr_in6 *sin6;
1244 switch(sock->ss_family) {
1246 dummy = ((struct sockaddr_in *)sock)->sin_addr.s_addr;
1247 dummy = ntohl(dummy);
1248 ch = (char)(((dummy&0xf0000000)==0xe0000000) ? 'm' :
1249 ((dummy&0x000000ff)==0x000000ff) ? 'b' :
1250 ((dummy&0xffffffff)==0x7f000001) ? 'l' :
1251 ((dummy&0xffffffe0)==0x00000000) ? '-' :
1255 sin6 = (struct sockaddr_in6 *)sock;
1256 if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
1269 * A list of variables required by the peers command
1271 struct varlist opeervarlist[] = {
1272 { "srcadr", 0 }, /* 0 */
1273 { "dstadr", 0 }, /* 1 */
1274 { "stratum", 0 }, /* 2 */
1275 { "hpoll", 0 }, /* 3 */
1276 { "ppoll", 0 }, /* 4 */
1277 { "reach", 0 }, /* 5 */
1278 { "delay", 0 }, /* 6 */
1279 { "offset", 0 }, /* 7 */
1280 { "jitter", 0 }, /* 8 */
1281 { "dispersion", 0 }, /* 9 */
1282 { "rec", 0 }, /* 10 */
1283 { "reftime", 0 }, /* 11 */
1284 { "srcport", 0 }, /* 12 */
1288 struct varlist peervarlist[] = {
1289 { "srcadr", 0 }, /* 0 */
1290 { "refid", 0 }, /* 1 */
1291 { "stratum", 0 }, /* 2 */
1292 { "hpoll", 0 }, /* 3 */
1293 { "ppoll", 0 }, /* 4 */
1294 { "reach", 0 }, /* 5 */
1295 { "delay", 0 }, /* 6 */
1296 { "offset", 0 }, /* 7 */
1297 { "jitter", 0 }, /* 8 */
1298 { "dispersion", 0 }, /* 9 */
1299 { "rec", 0 }, /* 10 */
1300 { "reftime", 0 }, /* 11 */
1301 { "srcport", 0 }, /* 12 */
1305 #define HAVE_SRCADR 0
1306 #define HAVE_DSTADR 1
1307 #define HAVE_REFID 1
1308 #define HAVE_STRATUM 2
1309 #define HAVE_HPOLL 3
1310 #define HAVE_PPOLL 4
1311 #define HAVE_REACH 5
1312 #define HAVE_DELAY 6
1313 #define HAVE_OFFSET 7
1314 #define HAVE_JITTER 8
1315 #define HAVE_DISPERSION 9
1317 #define HAVE_REFTIME 11
1318 #define HAVE_SRCPORT 12
1322 * Decode an incoming data buffer and print a line in the peer list
1326 struct varlist *pvl,
1340 struct sockaddr_storage srcadr;
1341 struct sockaddr_storage dstadr;
1343 char *dstadr_refid = "0.0.0.0";
1355 u_char havevar[MAXHAVE];
1358 char refid_string[10];
1359 char whenbuf[8], pollbuf[8];
1360 char clock_name[LENHOSTNAME];
1362 memset((char *)havevar, 0, sizeof(havevar));
1365 memset((char *)&srcadr, 0, sizeof(struct sockaddr_storage));
1366 memset((char *)&dstadr, 0, sizeof(struct sockaddr_storage));
1368 /* Initialize by zeroing out estimate variables */
1369 memset((char *)&estoffset, 0, sizeof(l_fp));
1370 memset((char *)&estdelay, 0, sizeof(l_fp));
1371 memset((char *)&estjitter, 0, sizeof(l_fp));
1372 memset((char *)&estdisp, 0, sizeof(l_fp));
1374 while (nextvar(&datalen, &data, &name, &value)) {
1375 struct sockaddr_storage dum_store;
1377 i = findvar(name, peer_var);
1379 continue; /* don't know this one */
1382 if (decodenetnum(value, &srcadr))
1383 havevar[HAVE_SRCADR] = 1;
1386 if (decodenetnum(value, &dum_store))
1387 type = decodeaddrtype(&dum_store);
1388 if (pvl == opeervarlist) {
1389 if (decodenetnum(value, &dstadr)) {
1390 havevar[HAVE_DSTADR] = 1;
1391 dstadr_refid = stoa(&dstadr);
1396 if (pvl == peervarlist) {
1397 havevar[HAVE_REFID] = 1;
1398 if (*value == '\0') {
1399 dstadr_refid = "0.0.0.0";
1400 } else if (decodenetnum(value, &dstadr)) {
1401 if (SOCKNUL(&dstadr))
1402 dstadr_refid = "0.0.0.0";
1403 else if ((dstadr.ss_family == AF_INET)
1404 && ISREFCLOCKADR(&dstadr))
1410 } else if ((int)strlen(value) <= 4) {
1411 refid_string[0] = '.';
1412 (void) strcpy(&refid_string[1], value);
1413 i = strlen(refid_string);
1414 refid_string[i] = '.';
1415 refid_string[i+1] = '\0';
1416 dstadr_refid = refid_string;
1418 havevar[HAVE_REFID] = 0;
1423 if (decodeuint(value, &stratum))
1424 havevar[HAVE_STRATUM] = 1;
1427 if (decodeint(value, &hpoll)) {
1428 havevar[HAVE_HPOLL] = 1;
1430 hpoll = NTP_MINPOLL;
1434 if (decodeint(value, &ppoll)) {
1435 havevar[HAVE_PPOLL] = 1;
1437 ppoll = NTP_MINPOLL;
1441 if (decodeuint(value, &reach))
1442 havevar[HAVE_REACH] = 1;
1445 if (decodetime(value, &estdelay))
1446 havevar[HAVE_DELAY] = 1;
1449 if (decodetime(value, &estoffset))
1450 havevar[HAVE_OFFSET] = 1;
1453 if (decodetime(value, &estjitter))
1454 havevar[HAVE_JITTER] = 1;
1457 if (decodetime(value, &estdisp))
1458 havevar[HAVE_DISPERSION] = 1;
1461 if (decodets(value, &rec))
1462 havevar[HAVE_REC] = 1;
1465 if (decodeuint(value, &srcport))
1466 havevar[HAVE_SRCPORT] = 1;
1469 havevar[HAVE_REFTIME] = 1;
1470 if (!decodets(value, &reftime))
1479 * Check to see if the srcport is NTP's port. If not this probably
1480 * isn't a valid peer association.
1482 if (havevar[HAVE_SRCPORT] && srcport != NTP_PORT)
1486 * Got everything, format the line
1488 poll_sec = 1<<max(min3(ppoll, hpoll, NTP_MAXPOLL), NTP_MINPOLL);
1489 if (pktversion > NTP_OLDVERSION)
1490 c = flash3[CTL_PEER_STATVAL(rstatus) & 0x7];
1492 c = flash2[CTL_PEER_STATVAL(rstatus) & 0x3];
1494 (void) fprintf(fp, "%-*s ", maxhostlen, currenthost);
1495 if (af == 0 || srcadr.ss_family == af){
1496 strcpy(clock_name, nntohost(&srcadr));
1499 "%c%-15.15s %-15.15s %2ld %c %4.4s %4.4s %3lo %7.7s %8.7s %7.7s\n",
1500 c, clock_name, dstadr_refid, stratum, type,
1501 prettyinterval(whenbuf, when(&ts, &rec, &reftime)),
1502 prettyinterval(pollbuf, (int)poll_sec), reach,
1503 lfptoms(&estdelay, 3), lfptoms(&estoffset, 3),
1504 havevar[HAVE_JITTER] ? lfptoms(&estjitter, 3) :
1505 lfptoms(&estdisp, 3));
1518 #undef HAVE_ESTDELAY
1519 #undef HAVE_ESTOFFSET
1530 * dogetpeers - given an association ID, read and print the spreadsheet
1535 struct varlist *pvl,
1547 res = doquerylist(pvl, CTL_OP_READVAR, associd, 0, &rstatus,
1553 res = doquery(CTL_OP_READVAR, associd, 0, 0, (char *)0, &rstatus,
1561 (void) fprintf(stderr,
1562 "***No information returned for association %d\n",
1567 return doprintpeers(pvl, associd, (int)rstatus, dsize, datap, fp, af);
1572 * peers - print a peer spreadsheet
1582 char fullname[LENHOSTNAME];
1583 struct sockaddr_storage netnum;
1585 if (!dogetassoc(fp))
1588 for (i = 0; i < numhosts; ++i) {
1589 if (getnetnum(chosts[i], &netnum, fullname, af))
1590 if ((int)strlen(fullname) > maxhostlen)
1591 maxhostlen = strlen(fullname);
1594 (void) fprintf(fp, "%-*.*s ", maxhostlen, maxhostlen, "host");
1596 " remote refid st t when poll reach delay offset jitter\n");
1598 for (i = 0; i <= maxhostlen; ++i)
1599 (void) fprintf(fp, "=");
1601 "==============================================================================\n");
1603 for (i = 0; i < numassoc; i++) {
1605 !(CTL_PEER_STATVAL(assoc_cache[i].status)
1606 & (CTL_PST_CONFIG|CTL_PST_REACH)))
1608 if (!dogetpeers(peervarlist, (int)assoc_cache[i].assid, fp, af)) {
1617 * peers - print a peer spreadsheet
1628 if (pcmd->nargs == 1) {
1629 if (pcmd->argval->ival == 6)
1639 * lpeers - print a peer spreadsheet including all fuzzball peers
1650 if (pcmd->nargs == 1) {
1651 if (pcmd->argval->ival == 6)
1661 * opeers - print a peer spreadsheet
1672 if (!dogetassoc(fp))
1676 " remote local st t when poll reach delay offset disp\n");
1678 "==============================================================================\n");
1680 for (i = 0; i < numassoc; i++) {
1682 !(CTL_PEER_STATVAL(assoc_cache[i].status)
1683 & (CTL_PST_CONFIG|CTL_PST_REACH)))
1685 if (!dogetpeers(opeervarlist, (int)assoc_cache[i].assid, fp, af)) {
1694 * opeers - print a peer spreadsheet the old way
1705 if (pcmd->nargs == 1) {
1706 if (pcmd->argval->ival == 6)
1711 doopeers(0, fp, af);
1716 * lopeers - print a peer spreadsheet including all fuzzball peers
1727 if (pcmd->nargs == 1) {
1728 if (pcmd->argval->ival == 6)
1733 doopeers(1, fp, af);