1 /* $NetBSD: ntpq-subs.c,v 1.1.1.2 2007/06/24 15:50:25 kardel Exp $ */
4 * ntpq_ops.c - subroutines which are called to perform operations by ntpq
13 #include "ntp_stdlib.h"
15 extern const char * chosts
[];
16 extern char currenthost
[];
21 * Declarations for command handlers in here
23 static int checkassocid
P((u_int32
));
24 static char * strsave
P((char *));
25 static struct varlist
*findlistvar
P((struct varlist
*, char *));
26 static void doaddvlist
P((struct varlist
*, char *));
27 static void dormvlist
P((struct varlist
*, char *));
28 static void doclearvlist
P((struct varlist
*));
29 static void makequerydata
P((struct varlist
*, int *, char *));
30 static int doquerylist
P((struct varlist
*, int, int, int, u_short
*, int *, char **));
31 static void doprintvlist
P((struct varlist
*, FILE *));
32 static void addvars
P((struct parse
*, FILE *));
33 static void rmvars
P((struct parse
*, FILE *));
34 static void clearvars
P((struct parse
*, FILE *));
35 static void showvars
P((struct parse
*, FILE *));
36 static int dolist
P((struct varlist
*, int, int, int, FILE *));
37 static void readlist
P((struct parse
*, FILE *));
38 static void writelist
P((struct parse
*, FILE *));
39 static void readvar
P((struct parse
*, FILE *));
40 static void writevar
P((struct parse
*, FILE *));
41 static void clocklist
P((struct parse
*, FILE *));
42 static void clockvar
P((struct parse
*, FILE *));
43 static int findassidrange
P((u_int32
, u_int32
, int *, int *));
44 static void mreadlist
P((struct parse
*, FILE *));
45 static void mreadvar
P((struct parse
*, FILE *));
46 static int dogetassoc
P((FILE *));
47 static void printassoc
P((int, FILE *));
48 static void associations
P((struct parse
*, FILE *));
49 static void lassociations
P((struct parse
*, FILE *));
50 static void passociations
P((struct parse
*, FILE *));
51 static void lpassociations
P((struct parse
*, FILE *));
54 static void radiostatus
P((struct parse
*, FILE *));
57 static void pstatus
P((struct parse
*, FILE *));
58 static long when
P((l_fp
*, l_fp
*, l_fp
*));
59 static char * prettyinterval
P((char *, long));
60 static int doprintpeers
P((struct varlist
*, int, int, int, char *, FILE *, int));
61 static int dogetpeers
P((struct varlist
*, int, FILE *, int));
62 static void dopeers
P((int, FILE *, int));
63 static void peers
P((struct parse
*, FILE *));
64 static void lpeers
P((struct parse
*, FILE *));
65 static void doopeers
P((int, FILE *, int));
66 static void opeers
P((struct parse
*, FILE *));
67 static void lopeers
P((struct parse
*, FILE *));
71 * Commands we understand. Ntpdc imports this.
73 struct xcmd opcmds
[] = {
74 { "associations", associations
, { NO
, NO
, NO
, NO
},
76 "print list of association ID's and statuses for the server's peers" },
77 { "passociations", passociations
, { NO
, NO
, NO
, NO
},
79 "print list of associations returned by last associations command" },
80 { "lassociations", lassociations
, { NO
, NO
, NO
, NO
},
82 "print list of associations including all client information" },
83 { "lpassociations", lpassociations
, { NO
, NO
, NO
, NO
},
85 "print last obtained list of associations, including client information" },
86 { "addvars", addvars
, { NTP_STR
, NO
, NO
, NO
},
87 { "name[=value][,...]", "", "", "" },
88 "add variables to the variable list or change their values" },
89 { "rmvars", rmvars
, { NTP_STR
, NO
, NO
, NO
},
90 { "name[,...]", "", "", "" },
91 "remove variables from the variable list" },
92 { "clearvars", clearvars
, { NO
, NO
, NO
, NO
},
94 "remove all variables from the variable list" },
95 { "showvars", showvars
, { NO
, NO
, NO
, NO
},
97 "print variables on the variable list" },
98 { "readlist", readlist
, { OPT
|NTP_UINT
, NO
, NO
, NO
},
99 { "assocID", "", "", "" },
100 "read the system or peer variables included in the variable list" },
101 { "rl", readlist
, { OPT
|NTP_UINT
, NO
, NO
, NO
},
102 { "assocID", "", "", "" },
103 "read the system or peer variables included in the variable list" },
104 { "writelist", writelist
, { OPT
|NTP_UINT
, NO
, NO
, NO
},
105 { "assocID", "", "", "" },
106 "write the system or peer variables included in the variable list" },
107 { "readvar", readvar
, { OPT
|NTP_UINT
, OPT
|NTP_STR
, NO
, NO
},
108 { "assocID", "name=value[,...]", "", "" },
109 "read system or peer variables" },
110 { "rv", readvar
, { OPT
|NTP_UINT
, OPT
|NTP_STR
, NO
, NO
},
111 { "assocID", "name=value[,...]", "", "" },
112 "read system or peer variables" },
113 { "writevar", writevar
, { NTP_UINT
, NTP_STR
, NO
, NO
},
114 { "assocID", "name=value,[...]", "", "" },
115 "write system or peer variables" },
116 { "mreadlist", mreadlist
, { NTP_UINT
, NTP_UINT
, NO
, NO
},
117 { "assocID", "assocID", "", "" },
118 "read the peer variables in the variable list for multiple peers" },
119 { "mrl", mreadlist
, { NTP_UINT
, NTP_UINT
, NO
, NO
},
120 { "assocID", "assocID", "", "" },
121 "read the peer variables in the variable list for multiple peers" },
122 { "mreadvar", mreadvar
, { NTP_UINT
, NTP_UINT
, OPT
|NTP_STR
, NO
},
123 { "assocID", "assocID", "name=value[,...]", "" },
124 "read peer variables from multiple peers" },
125 { "mrv", mreadvar
, { NTP_UINT
, NTP_UINT
, OPT
|NTP_STR
, NO
},
126 { "assocID", "assocID", "name=value[,...]", "" },
127 "read peer variables from multiple peers" },
128 { "clocklist", clocklist
, { OPT
|NTP_UINT
, NO
, NO
, NO
},
129 { "assocID", "", "", "" },
130 "read the clock variables included in the variable list" },
131 { "cl", clocklist
, { OPT
|NTP_UINT
, NO
, NO
, NO
},
132 { "assocID", "", "", "" },
133 "read the clock variables included in the variable list" },
134 { "clockvar", clockvar
, { OPT
|NTP_UINT
, OPT
|NTP_STR
, NO
, NO
},
135 { "assocID", "name=value[,...]", "", "" },
136 "read clock variables" },
137 { "cv", clockvar
, { OPT
|NTP_UINT
, OPT
|NTP_STR
, NO
, NO
},
138 { "assocID", "name=value[,...]", "", "" },
139 "read clock variables" },
140 { "pstatus", pstatus
, { NTP_UINT
, NO
, NO
, NO
},
141 { "assocID", "", "", "" },
142 "print status information returned for a peer" },
143 { "peers", peers
, { OPT
|IP_VERSION
, NO
, NO
, NO
},
144 { "-4|-6", "", "", "" },
145 "obtain and print a list of the server's peers [IP version]" },
146 { "lpeers", lpeers
, { OPT
|IP_VERSION
, NO
, NO
, NO
},
147 { "-4|-6", "", "", "" },
148 "obtain and print a list of all peers and clients [IP version]" },
149 { "opeers", opeers
, { OPT
|IP_VERSION
, NO
, NO
, NO
},
150 { "-4|-6", "", "", "" },
151 "print peer list the old way, with dstadr shown rather than refid [IP version]" },
152 { "lopeers", lopeers
, { OPT
|IP_VERSION
, NO
, NO
, NO
},
153 { "-4|-6", "", "", "" },
154 "obtain and print a list of all peers and clients showing dstadr [IP version]" },
155 { 0, 0, { NO
, NO
, NO
, NO
},
156 { "-4|-6", "", "", "" }, "" }
161 * Variable list data space
163 #define MAXLIST 64 /* maximum number of variables in list */
164 #define LENHOSTNAME 256 /* host name is 256 characters long */
166 * Old CTL_PST defines for version 2.
168 #define OLD_CTL_PST_CONFIG 0x80
169 #define OLD_CTL_PST_AUTHENABLE 0x40
170 #define OLD_CTL_PST_AUTHENTIC 0x20
171 #define OLD_CTL_PST_REACH 0x10
172 #define OLD_CTL_PST_SANE 0x08
173 #define OLD_CTL_PST_DISP 0x04
174 #define OLD_CTL_PST_SEL_REJECT 0
175 #define OLD_CTL_PST_SEL_SELCAND 1
176 #define OLD_CTL_PST_SEL_SYNCCAND 2
177 #define OLD_CTL_PST_SEL_SYSPEER 3
180 char flash2
[] = " .+* "; /* flash decode for version 2 */
181 char flash3
[] = " x.-+#*o"; /* flash decode for peer status version 3 */
186 } varlist
[MAXLIST
] = { { 0, 0 } };
189 * Imported from ntpq.c
191 extern int showhostnames
;
193 extern struct servent
*server_entry
;
194 extern struct association assoc_cache
[];
196 extern u_char pktversion
;
197 extern struct ctl_var peer_var
[];
200 * For quick string comparisons
202 #define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0)
206 * checkassocid - return the association ID, checking to see if it is valid
213 if (value
== 0 || value
>= 65536) {
214 (void) fprintf(stderr
, "***Invalid association ID specified\n");
222 * strsave - save a string
223 * XXX - should be in libntp.a
233 len
= strlen(str
) + 1;
234 if ((cp
= (char *)malloc(len
)) == NULL
) {
235 (void) fprintf(stderr
, "Malloc failed!!\n");
239 memmove(cp
, str
, len
);
245 * findlistvar - look for the named variable in a list and return if found
247 static struct varlist
*
249 struct varlist
*list
,
253 register struct varlist
*vl
;
255 for (vl
= list
; vl
< list
+ MAXLIST
&& vl
->name
!= 0; vl
++)
256 if (STREQ(name
, vl
->name
))
258 if (vl
< list
+ MAXLIST
)
260 return (struct varlist
*)0;
265 * doaddvlist - add variable(s) to the variable list
269 struct varlist
*vlist
,
273 register struct varlist
*vl
;
279 while (nextvar(&len
, &vars
, &name
, &value
)) {
280 vl
= findlistvar(vlist
, name
);
282 (void) fprintf(stderr
, "Variable list full\n");
287 vl
->name
= strsave(name
);
288 } else if (vl
->value
!= 0) {
294 vl
->value
= strsave(value
);
300 * dormvlist - remove variable(s) from the variable list
304 struct varlist
*vlist
,
308 register struct varlist
*vl
;
314 while (nextvar(&len
, &vars
, &name
, &value
)) {
315 vl
= findlistvar(vlist
, name
);
316 if (vl
== 0 || vl
->name
== 0) {
317 (void) fprintf(stderr
, "Variable `%s' not found\n",
320 free((void *)vl
->name
);
323 for ( ; (vl
+1) < (varlist
+MAXLIST
)
324 && (vl
+1)->name
!= 0; vl
++) {
325 vl
->name
= (vl
+1)->name
;
326 vl
->value
= (vl
+1)->value
;
328 vl
->name
= vl
->value
= 0;
335 * doclearvlist - clear a variable list
339 struct varlist
*vlist
342 register struct varlist
*vl
;
344 for (vl
= vlist
; vl
< vlist
+ MAXLIST
&& vl
->name
!= 0; vl
++) {
345 free((void *)vl
->name
);
347 if (vl
->value
!= 0) {
356 * makequerydata - form a data buffer to be included with a query
360 struct varlist
*vlist
,
365 register struct varlist
*vl
;
366 register char *cp
, *cpend
;
367 register int namelen
, valuelen
;
368 register int totallen
;
371 cpend
= data
+ *datalen
;
373 for (vl
= vlist
; vl
< vlist
+ MAXLIST
&& vl
->name
!= 0; vl
++) {
374 namelen
= strlen(vl
->name
);
378 valuelen
= strlen(vl
->value
);
379 totallen
= namelen
+ valuelen
+ (valuelen
!= 0) + (cp
!= data
);
380 if (cp
+ totallen
> cpend
)
385 memmove(cp
, vl
->name
, (unsigned)namelen
);
389 memmove(cp
, vl
->value
, (unsigned)valuelen
);
393 *datalen
= cp
- data
;
398 * doquerylist - send a message including variables in a list
402 struct varlist
*vlist
,
411 char data
[CTL_MAX_DATA_LEN
];
414 datalen
= sizeof(data
);
415 makequerydata(vlist
, &datalen
, data
);
417 return doquery(op
, associd
, auth
, datalen
, data
, rstatus
,
423 * doprintvlist - print the variables on a list
427 struct varlist
*vlist
,
431 register struct varlist
*vl
;
433 if (vlist
->name
== 0) {
434 (void) fprintf(fp
, "No variables on list\n");
436 for (vl
= vlist
; vl
< vlist
+ MAXLIST
&& vl
->name
!= 0; vl
++) {
437 if (vl
->value
== 0) {
438 (void) fprintf(fp
, "%s\n", vl
->name
);
440 (void) fprintf(fp
, "%s=%s\n",
441 vl
->name
, vl
->value
);
449 * addvars - add variables to the variable list
458 doaddvlist(varlist
, pcmd
->argval
[0].string
);
463 * rmvars - remove variables from the variable list
472 dormvlist(varlist
, pcmd
->argval
[0].string
);
477 * clearvars - clear the variable list
486 doclearvlist(varlist
);
491 * showvars - show variables on the variable list
500 doprintvlist(varlist
, fp
);
505 * dolist - send a request with the given list of variables
509 struct varlist
*vlist
,
521 res
= doquerylist(vlist
, op
, associd
, 0, &rstatus
, &dsize
, &datap
);
527 (void) fprintf(fp
, "server=%s ", currenthost
);
530 (void) fprintf(fp
, "No system%s variables returned\n",
531 (type
== TYPE_CLOCK
) ? " clock" : "");
534 "No information returned for%s association %u\n",
535 (type
== TYPE_CLOCK
) ? " clock" : "", associd
);
539 (void) fprintf(fp
,"assID=%d ",associd
);
540 printvars(dsize
, datap
, (int)rstatus
, type
, fp
);
546 * readlist - send a read variables request with the variables on the list
556 if (pcmd
->nargs
== 0) {
559 /* HMS: I think we want the u_int32 target here, not the u_long */
560 if (pcmd
->argval
[0].uval
== 0)
562 else if ((associd
= checkassocid(pcmd
->argval
[0].uval
)) == 0)
566 (void) dolist(varlist
, associd
, CTL_OP_READVAR
,
567 (associd
== 0) ? TYPE_SYS
: TYPE_PEER
, fp
);
572 * writelist - send a write variables request with the variables on the list
586 if (pcmd
->nargs
== 0) {
589 /* HMS: Do we really want uval here? */
590 if (pcmd
->argval
[0].uval
== 0)
592 else if ((associd
= checkassocid(pcmd
->argval
[0].uval
)) == 0)
596 res
= doquerylist(varlist
, CTL_OP_WRITEVAR
, associd
, 1, &rstatus
,
603 (void) fprintf(fp
, "server=%s ", currenthost
);
605 (void) fprintf(fp
, "done! (no data returned)\n");
607 (void) fprintf(fp
,"assID=%d ",associd
);
608 printvars(dsize
, datap
, (int)rstatus
,
609 (associd
!= 0) ? TYPE_PEER
: TYPE_SYS
, fp
);
616 * readvar - send a read variables request with the specified variables
625 struct varlist tmplist
[MAXLIST
];
628 if (pcmd
->nargs
== 0 || pcmd
->argval
[0].uval
== 0)
630 else if ((associd
= checkassocid(pcmd
->argval
[0].uval
)) == 0)
633 memset((char *)tmplist
, 0, sizeof(tmplist
));
634 if (pcmd
->nargs
>= 2)
635 doaddvlist(tmplist
, pcmd
->argval
[1].string
);
637 (void) dolist(tmplist
, associd
, CTL_OP_READVAR
,
638 (associd
== 0) ? TYPE_SYS
: TYPE_PEER
, fp
);
640 doclearvlist(tmplist
);
645 * writevar - send a write variables request with the specified variables
658 struct varlist tmplist
[MAXLIST
];
661 if (pcmd
->argval
[0].uval
== 0)
663 else if ((associd
= checkassocid(pcmd
->argval
[0].uval
)) == 0)
666 memset((char *)tmplist
, 0, sizeof(tmplist
));
667 doaddvlist(tmplist
, pcmd
->argval
[1].string
);
669 res
= doquerylist(tmplist
, CTL_OP_WRITEVAR
, associd
, 1, &rstatus
,
672 doclearvlist(tmplist
);
678 (void) fprintf(fp
, "server=%s ", currenthost
);
680 (void) fprintf(fp
, "done! (no data returned)\n");
682 (void) fprintf(fp
,"assID=%d ",associd
);
683 printvars(dsize
, datap
, (int)rstatus
,
684 (associd
!= 0) ? TYPE_PEER
: TYPE_SYS
, fp
);
691 * clocklist - send a clock variables request with the variables on the list
702 if (pcmd
->nargs
== 0) {
705 if (pcmd
->argval
[0].uval
== 0)
707 else if ((associd
= checkassocid(pcmd
->argval
[0].uval
)) == 0)
711 (void) dolist(varlist
, associd
, CTL_OP_READCLOCK
, TYPE_CLOCK
, fp
);
716 * clockvar - send a clock variables request with the specified variables
725 struct varlist tmplist
[MAXLIST
];
728 if (pcmd
->nargs
== 0 || pcmd
->argval
[0].uval
== 0)
730 else if ((associd
= checkassocid(pcmd
->argval
[0].uval
)) == 0)
733 memset((char *)tmplist
, 0, sizeof(tmplist
));
734 if (pcmd
->nargs
>= 2)
735 doaddvlist(tmplist
, pcmd
->argval
[1].string
);
737 (void) dolist(tmplist
, associd
, CTL_OP_READCLOCK
, TYPE_CLOCK
, fp
);
739 doclearvlist(tmplist
);
744 * findassidrange - verify a range of association ID's
757 if (assid1
== 0 || assid1
> 65535) {
758 (void) fprintf(stderr
,
759 "***Invalid association ID %lu specified\n", (u_long
)assid1
);
763 if (assid2
== 0 || assid2
> 65535) {
764 (void) fprintf(stderr
,
765 "***Invalid association ID %lu specified\n", (u_long
)assid2
);
770 for (i
= 0; i
< numassoc
; i
++) {
771 if (assoc_cache
[i
].assid
== assid1
) {
776 if (assoc_cache
[i
].assid
== assid2
) {
783 if (f
== -1 || t
== -1) {
784 (void) fprintf(stderr
,
785 "***Association ID %lu not found in list\n",
786 (f
== -1) ? (u_long
)assid1
: (u_long
)assid2
);
803 * mreadlist - send a read variables request for multiple associations
816 if (!findassidrange(pcmd
->argval
[0].uval
, pcmd
->argval
[1].uval
,
820 for (i
= from
; i
<= to
; i
++) {
822 (void) fprintf(fp
, "\n");
823 if (!dolist(varlist
, (int)assoc_cache
[i
].assid
,
824 CTL_OP_READVAR
, TYPE_PEER
, fp
))
832 * mreadvar - send a read variables request for multiple associations
843 struct varlist tmplist
[MAXLIST
];
846 if (!findassidrange(pcmd
->argval
[0].uval
, pcmd
->argval
[1].uval
,
850 memset((char *)tmplist
, 0, sizeof(tmplist
));
851 if (pcmd
->nargs
>= 3)
852 doaddvlist(tmplist
, pcmd
->argval
[2].string
);
854 for (i
= from
; i
<= to
; i
++) {
856 (void) fprintf(fp
, "\n");
857 if (!dolist(varlist
, (int)assoc_cache
[i
].assid
,
858 CTL_OP_READVAR
, TYPE_PEER
, fp
))
861 doclearvlist(tmplist
);
867 * dogetassoc - query the host for its list of associations
879 res
= doquery(CTL_OP_READSTAT
, 0, 0, 0, (char *)0, &rstatus
,
887 (void) fprintf(fp
, "server=%s ", currenthost
);
888 (void) fprintf(fp
, "No association ID's returned\n");
894 (void) fprintf(stderr
, "server=%s ", currenthost
);
895 (void) fprintf(stderr
,
896 "***Server returned %d octets, should be multiple of 4\n",
903 assoc_cache
[numassoc
].assid
= ntohs(*((u_short
*)datap
));
904 datap
+= sizeof(u_short
);
905 assoc_cache
[numassoc
].status
= ntohs(*((u_short
*)datap
));
906 datap
+= sizeof(u_short
);
907 if (++numassoc
>= MAXASSOC
)
909 dsize
-= sizeof(u_short
) + sizeof(u_short
);
917 * printassoc - print the current list of associations
933 const char *condition
= "";
934 const char *last_event
;
939 (void) fprintf(fp
, "No association ID's in list\n");
947 "\nind assID status conf reach auth condition last_event cnt\n");
949 "===========================================================\n");
950 for (i
= 0; i
< numassoc
; i
++) {
951 statval
= (u_char
) CTL_PEER_STATVAL(assoc_cache
[i
].status
);
952 if (!showall
&& !(statval
& (CTL_PST_CONFIG
|CTL_PST_REACH
)))
954 event
= CTL_PEER_EVENT(assoc_cache
[i
].status
);
955 event_count
= CTL_PEER_NEVNT(assoc_cache
[i
].status
);
956 if (statval
& CTL_PST_CONFIG
)
960 if (statval
& CTL_PST_REACH
|| 1) {
962 if (statval
& CTL_PST_AUTHENABLE
) {
963 if (statval
& CTL_PST_AUTHENTIC
)
970 if (pktversion
> NTP_OLDVERSION
)
971 switch (statval
& 0x7) {
972 case CTL_PST_SEL_REJECT
:
973 condition
= "reject";
975 case CTL_PST_SEL_SANE
:
976 condition
= "falsetick";
978 case CTL_PST_SEL_CORRECT
:
979 condition
= "excess";
981 case CTL_PST_SEL_SELCAND
:
982 condition
= "outlyer";
984 case CTL_PST_SEL_SYNCCAND
:
985 condition
= "candidat";
987 case CTL_PST_SEL_DISTSYSPEER
:
988 condition
= "selected";
990 case CTL_PST_SEL_SYSPEER
:
991 condition
= "sys.peer";
993 case CTL_PST_SEL_PPS
:
994 condition
= "pps.peer";
998 switch (statval
& 0x3) {
999 case OLD_CTL_PST_SEL_REJECT
:
1000 if (!(statval
& OLD_CTL_PST_SANE
))
1001 condition
= "insane";
1002 else if (!(statval
& OLD_CTL_PST_DISP
))
1003 condition
= "hi_disp";
1007 case OLD_CTL_PST_SEL_SELCAND
:
1008 condition
= "sel_cand";
1010 case OLD_CTL_PST_SEL_SYNCCAND
:
1011 condition
= "sync_cand";
1013 case OLD_CTL_PST_SEL_SYSPEER
:
1014 condition
= "sys_peer";
1020 auth
= condition
= "";
1023 switch (PEER_EVENT
|event
) {
1024 case EVNT_PEERIPERR
:
1025 last_event
= "IP error";
1028 last_event
= "auth fail";
1031 last_event
= "lost reach";
1034 last_event
= "reachable";
1036 case EVNT_PEERCLOCK
:
1037 last_event
= "clock expt";
1040 case EVNT_PEERSTRAT
:
1041 last_event
= "stratum chg";
1049 if (event_count
!= 0)
1050 cnt
= uinttoa(event_count
);
1054 "%3d %5u %04x %3.3s %4s %4.4s %9.9s %11s %2s",
1055 i
+1, assoc_cache
[i
].assid
, assoc_cache
[i
].status
,
1056 conf
, reach
, auth
, condition
, last_event
, cnt
);
1057 bp
= &buf
[strlen(buf
)];
1058 while (bp
> buf
&& *(bp
-1) == ' ')
1060 (void) fprintf(fp
, "%s\n", buf
);
1067 * associations - get, record and print a list of associations
1082 * lassociations - get, record and print a long list of associations
1097 * passociations - print the association list
1111 * lpassociations - print the long association list
1126 * radiostatus - print the radio status returned by the server
1140 res
= doquery(CTL_OP_READCLOCK
, 0, 0, 0, (char *)0, &rstatus
,
1147 (void) fprintf(fp
, "server=%s ", currenthost
);
1149 (void) fprintf(fp
, "No radio status string returned\n");
1153 asciize(dsize
, datap
, fp
);
1158 * pstatus - print peer status returned by the server
1173 if ((associd
= checkassocid(pcmd
->argval
[0].uval
)) == 0)
1176 res
= doquery(CTL_OP_READSTAT
, associd
, 0, 0, (char *)0, &rstatus
,
1183 (void) fprintf(fp
, "server=%s ", currenthost
);
1186 "No information returned for association %u\n",
1191 (void) fprintf(fp
,"assID=%d ",associd
);
1192 printvars(dsize
, datap
, (int)rstatus
, TYPE_PEER
, fp
);
1197 * when - print how long its been since his last packet arrived
1210 else if (reftime
->l_ui
!= 0)
1215 return (ts
->l_ui
- lasttime
->l_ui
);
1220 * Pretty-print an interval into the given buffer, in a human-friendly format.
1235 (void) sprintf(buf
, "%ld", (long int)diff
);
1239 diff
= (diff
+ 29) / 60;
1241 (void) sprintf(buf
, "%ldm", (long int)diff
);
1245 diff
= (diff
+ 29) / 60;
1247 (void) sprintf(buf
, "%ldh", (long int)diff
);
1251 diff
= (diff
+ 11) / 24;
1252 (void) sprintf(buf
, "%ldd", (long int)diff
);
1258 struct sockaddr_storage
*sock
1263 struct sockaddr_in6
*sin6
;
1265 switch(sock
->ss_family
) {
1267 dummy
= ((struct sockaddr_in
*)sock
)->sin_addr
.s_addr
;
1268 dummy
= ntohl(dummy
);
1269 ch
= (char)(((dummy
&0xf0000000)==0xe0000000) ? 'm' :
1270 ((dummy
&0x000000ff)==0x000000ff) ? 'b' :
1271 ((dummy
&0xffffffff)==0x7f000001) ? 'l' :
1272 ((dummy
&0xffffffe0)==0x00000000) ? '-' :
1276 sin6
= (struct sockaddr_in6
*)sock
;
1277 if (IN6_IS_ADDR_MULTICAST(&sin6
->sin6_addr
))
1290 * A list of variables required by the peers command
1292 struct varlist opeervarlist
[] = {
1293 { "srcadr", 0 }, /* 0 */
1294 { "dstadr", 0 }, /* 1 */
1295 { "stratum", 0 }, /* 2 */
1296 { "hpoll", 0 }, /* 3 */
1297 { "ppoll", 0 }, /* 4 */
1298 { "reach", 0 }, /* 5 */
1299 { "delay", 0 }, /* 6 */
1300 { "offset", 0 }, /* 7 */
1301 { "jitter", 0 }, /* 8 */
1302 { "dispersion", 0 }, /* 9 */
1303 { "rec", 0 }, /* 10 */
1304 { "reftime", 0 }, /* 11 */
1305 { "srcport", 0 }, /* 12 */
1309 struct varlist peervarlist
[] = {
1310 { "srcadr", 0 }, /* 0 */
1311 { "refid", 0 }, /* 1 */
1312 { "stratum", 0 }, /* 2 */
1313 { "hpoll", 0 }, /* 3 */
1314 { "ppoll", 0 }, /* 4 */
1315 { "reach", 0 }, /* 5 */
1316 { "delay", 0 }, /* 6 */
1317 { "offset", 0 }, /* 7 */
1318 { "jitter", 0 }, /* 8 */
1319 { "dispersion", 0 }, /* 9 */
1320 { "rec", 0 }, /* 10 */
1321 { "reftime", 0 }, /* 11 */
1322 { "srcport", 0 }, /* 12 */
1326 #define HAVE_SRCADR 0
1327 #define HAVE_DSTADR 1
1328 #define HAVE_REFID 1
1329 #define HAVE_STRATUM 2
1330 #define HAVE_HPOLL 3
1331 #define HAVE_PPOLL 4
1332 #define HAVE_REACH 5
1333 #define HAVE_DELAY 6
1334 #define HAVE_OFFSET 7
1335 #define HAVE_JITTER 8
1336 #define HAVE_DISPERSION 9
1338 #define HAVE_REFTIME 11
1339 #define HAVE_SRCPORT 12
1343 * Decode an incoming data buffer and print a line in the peer list
1347 struct varlist
*pvl
,
1361 struct sockaddr_storage srcadr
;
1362 struct sockaddr_storage dstadr
;
1364 char *dstadr_refid
= "0.0.0.0";
1376 u_char havevar
[MAXHAVE
];
1379 char refid_string
[10];
1380 char whenbuf
[8], pollbuf
[8];
1381 char clock_name
[LENHOSTNAME
];
1383 memset((char *)havevar
, 0, sizeof(havevar
));
1386 memset((char *)&srcadr
, 0, sizeof(struct sockaddr_storage
));
1387 memset((char *)&dstadr
, 0, sizeof(struct sockaddr_storage
));
1389 /* Initialize by zeroing out estimate variables */
1390 memset((char *)&estoffset
, 0, sizeof(l_fp
));
1391 memset((char *)&estdelay
, 0, sizeof(l_fp
));
1392 memset((char *)&estjitter
, 0, sizeof(l_fp
));
1393 memset((char *)&estdisp
, 0, sizeof(l_fp
));
1395 while (nextvar(&datalen
, &data
, &name
, &value
)) {
1396 struct sockaddr_storage dum_store
;
1398 i
= findvar(name
, peer_var
, 1);
1400 continue; /* don't know this one */
1403 if (decodenetnum(value
, &srcadr
))
1404 havevar
[HAVE_SRCADR
] = 1;
1407 if (decodenetnum(value
, &dum_store
))
1408 type
= decodeaddrtype(&dum_store
);
1409 if (pvl
== opeervarlist
) {
1410 if (decodenetnum(value
, &dstadr
)) {
1411 havevar
[HAVE_DSTADR
] = 1;
1412 dstadr_refid
= stoa(&dstadr
);
1417 if (pvl
== peervarlist
) {
1418 havevar
[HAVE_REFID
] = 1;
1419 if (*value
== '\0') {
1420 dstadr_refid
= "0.0.0.0";
1421 } else if ((int)strlen(value
) <= 4) {
1422 refid_string
[0] = '.';
1423 (void) strcpy(&refid_string
[1], value
);
1424 i
= strlen(refid_string
);
1425 refid_string
[i
] = '.';
1426 refid_string
[i
+1] = '\0';
1427 dstadr_refid
= refid_string
;
1428 } else if (decodenetnum(value
, &dstadr
)) {
1429 if (SOCKNUL(&dstadr
))
1430 dstadr_refid
= "0.0.0.0";
1431 else if ((dstadr
.ss_family
== AF_INET
)
1432 && ISREFCLOCKADR(&dstadr
))
1439 havevar
[HAVE_REFID
] = 0;
1444 if (decodeuint(value
, &stratum
))
1445 havevar
[HAVE_STRATUM
] = 1;
1448 if (decodeint(value
, &hpoll
)) {
1449 havevar
[HAVE_HPOLL
] = 1;
1451 hpoll
= NTP_MINPOLL
;
1455 if (decodeint(value
, &ppoll
)) {
1456 havevar
[HAVE_PPOLL
] = 1;
1458 ppoll
= NTP_MINPOLL
;
1462 if (decodeuint(value
, &reach
))
1463 havevar
[HAVE_REACH
] = 1;
1466 if (decodetime(value
, &estdelay
))
1467 havevar
[HAVE_DELAY
] = 1;
1470 if (decodetime(value
, &estoffset
))
1471 havevar
[HAVE_OFFSET
] = 1;
1474 if (pvl
== peervarlist
)
1475 if (decodetime(value
, &estjitter
))
1476 havevar
[HAVE_JITTER
] = 1;
1479 if (decodetime(value
, &estdisp
))
1480 havevar
[HAVE_DISPERSION
] = 1;
1483 if (decodets(value
, &rec
))
1484 havevar
[HAVE_REC
] = 1;
1487 if (decodeuint(value
, &srcport
))
1488 havevar
[HAVE_SRCPORT
] = 1;
1491 havevar
[HAVE_REFTIME
] = 1;
1492 if (!decodets(value
, &reftime
))
1501 * Check to see if the srcport is NTP's port. If not this probably
1502 * isn't a valid peer association.
1504 if (havevar
[HAVE_SRCPORT
] && srcport
!= NTP_PORT
)
1508 * Got everything, format the line
1510 poll_sec
= 1<<max(min3(ppoll
, hpoll
, NTP_MAXPOLL
), NTP_MINPOLL
);
1511 if (pktversion
> NTP_OLDVERSION
)
1512 c
= flash3
[CTL_PEER_STATVAL(rstatus
) & 0x7];
1514 c
= flash2
[CTL_PEER_STATVAL(rstatus
) & 0x3];
1516 (void) fprintf(fp
, "%-*s ", maxhostlen
, currenthost
);
1517 if (af
== 0 || srcadr
.ss_family
== af
){
1518 strcpy(clock_name
, nntohost(&srcadr
));
1521 "%c%-15.15s %-15.15s %2ld %c %4.4s %4.4s %3lo %7.7s %8.7s %7.7s\n",
1522 c
, clock_name
, dstadr_refid
, stratum
, type
,
1523 prettyinterval(whenbuf
, when(&ts
, &rec
, &reftime
)),
1524 prettyinterval(pollbuf
, (int)poll_sec
), reach
,
1525 lfptoms(&estdelay
, 3), lfptoms(&estoffset
, 3),
1526 havevar
[HAVE_JITTER
] ? lfptoms(&estjitter
, 3) :
1527 lfptoms(&estdisp
, 3));
1540 #undef HAVE_ESTDELAY
1541 #undef HAVE_ESTOFFSET
1552 * dogetpeers - given an association ID, read and print the spreadsheet
1557 struct varlist
*pvl
,
1569 res
= doquerylist(pvl
, CTL_OP_READVAR
, associd
, 0, &rstatus
,
1575 res
= doquery(CTL_OP_READVAR
, associd
, 0, 0, (char *)0, &rstatus
,
1584 (void) fprintf(stderr
, "server=%s ", currenthost
);
1585 (void) fprintf(stderr
,
1586 "***No information returned for association %d\n",
1591 return doprintpeers(pvl
, associd
, (int)rstatus
, dsize
, datap
, fp
, af
);
1596 * peers - print a peer spreadsheet
1606 char fullname
[LENHOSTNAME
];
1607 struct sockaddr_storage netnum
;
1609 if (!dogetassoc(fp
))
1612 for (i
= 0; i
< numhosts
; ++i
) {
1613 if (getnetnum(chosts
[i
], &netnum
, fullname
, af
))
1614 if ((int)strlen(fullname
) > maxhostlen
)
1615 maxhostlen
= strlen(fullname
);
1618 (void) fprintf(fp
, "%-*.*s ", maxhostlen
, maxhostlen
, "server");
1620 " remote refid st t when poll reach delay offset jitter\n");
1622 for (i
= 0; i
<= maxhostlen
; ++i
)
1623 (void) fprintf(fp
, "=");
1625 "==============================================================================\n");
1627 for (i
= 0; i
< numassoc
; i
++) {
1629 !(CTL_PEER_STATVAL(assoc_cache
[i
].status
)
1630 & (CTL_PST_CONFIG
|CTL_PST_REACH
)))
1632 if (!dogetpeers(peervarlist
, (int)assoc_cache
[i
].assid
, fp
, af
)) {
1641 * peers - print a peer spreadsheet
1652 if (pcmd
->nargs
== 1) {
1653 if (pcmd
->argval
->ival
== 6)
1663 * lpeers - print a peer spreadsheet including all fuzzball peers
1674 if (pcmd
->nargs
== 1) {
1675 if (pcmd
->argval
->ival
== 6)
1685 * opeers - print a peer spreadsheet
1695 char fullname
[LENHOSTNAME
];
1696 struct sockaddr_storage netnum
;
1698 if (!dogetassoc(fp
))
1701 for (i
= 0; i
< numhosts
; ++i
) {
1702 if (getnetnum(chosts
[i
], &netnum
, fullname
, af
))
1703 if ((int)strlen(fullname
) > maxhostlen
)
1704 maxhostlen
= strlen(fullname
);
1707 (void) fprintf(fp
, "%-*.*s ", maxhostlen
, maxhostlen
, "server");
1709 " remote local st t when poll reach delay offset disp\n");
1711 for (i
= 0; i
<= maxhostlen
; ++i
)
1712 (void) fprintf(fp
, "=");
1714 "==============================================================================\n");
1716 for (i
= 0; i
< numassoc
; i
++) {
1718 !(CTL_PEER_STATVAL(assoc_cache
[i
].status
)
1719 & (CTL_PST_CONFIG
|CTL_PST_REACH
)))
1721 if (!dogetpeers(opeervarlist
, (int)assoc_cache
[i
].assid
, fp
, af
)) {
1730 * opeers - print a peer spreadsheet the old way
1741 if (pcmd
->nargs
== 1) {
1742 if (pcmd
->argval
->ival
== 6)
1747 doopeers(0, fp
, af
);
1752 * lopeers - print a peer spreadsheet including all fuzzball peers
1763 if (pcmd
->nargs
== 1) {
1764 if (pcmd
->argval
->ival
== 6)
1769 doopeers(1, fp
, af
);