xref: /src/contrib/ntp/ntpq/ntpq-subs.c (revision f5f40dd63bc7acbb5312b26ac1ea1103c12352a6)
1c0b746e5SOllivier Robert /*
2b5e14a13SCy Schubert  * ntpq-subs.c - subroutines which are called to perform ntpq commands.
3c0b746e5SOllivier Robert  */
4b5e14a13SCy Schubert #include <config.h>
5c0b746e5SOllivier Robert #include <stdio.h>
69c2daa00SOllivier Robert #include <ctype.h>
79c2daa00SOllivier Robert #include <sys/types.h>
89c2daa00SOllivier Robert #include <sys/time.h>
9c0b746e5SOllivier Robert 
102b45e011SOllivier Robert #include "ntpq.h"
112b45e011SOllivier Robert #include "ntpq-opts.h"
12c0b746e5SOllivier Robert 
13c0b746e5SOllivier Robert extern char	currenthost[];
142b45e011SOllivier Robert extern int	currenthostisnum;
15b5e14a13SCy Schubert size_t		maxhostlen;
16c0b746e5SOllivier Robert 
17c0b746e5SOllivier Robert /*
18c0b746e5SOllivier Robert  * Declarations for command handlers in here
19c0b746e5SOllivier Robert  */
202b45e011SOllivier Robert static	associd_t checkassocid	(u_int32);
212b45e011SOllivier Robert static	struct varlist *findlistvar (struct varlist *, char *);
222b45e011SOllivier Robert static	void	doaddvlist	(struct varlist *, const char *);
232b45e011SOllivier Robert static	void	dormvlist	(struct varlist *, const char *);
242b45e011SOllivier Robert static	void	doclearvlist	(struct varlist *);
25c373d928SXin LI static	void	makequerydata	(struct varlist *, size_t *, char *);
262b45e011SOllivier Robert static	int	doquerylist	(struct varlist *, int, associd_t, int,
27c373d928SXin LI 				 u_short *, size_t *, const char **);
282b45e011SOllivier Robert static	void	doprintvlist	(struct varlist *, FILE *);
292b45e011SOllivier Robert static	void	addvars 	(struct parse *, FILE *);
302b45e011SOllivier Robert static	void	rmvars		(struct parse *, FILE *);
312b45e011SOllivier Robert static	void	clearvars	(struct parse *, FILE *);
322b45e011SOllivier Robert static	void	showvars	(struct parse *, FILE *);
332b45e011SOllivier Robert static	int	dolist		(struct varlist *, associd_t, int, int,
342b45e011SOllivier Robert 				 FILE *);
352b45e011SOllivier Robert static	void	readlist	(struct parse *, FILE *);
362b45e011SOllivier Robert static	void	writelist	(struct parse *, FILE *);
372b45e011SOllivier Robert static	void	readvar 	(struct parse *, FILE *);
382b45e011SOllivier Robert static	void	writevar	(struct parse *, FILE *);
392b45e011SOllivier Robert static	void	clocklist	(struct parse *, FILE *);
402b45e011SOllivier Robert static	void	clockvar	(struct parse *, FILE *);
41b5e14a13SCy Schubert static	int	findassidrange	(u_int32, u_int32, int *, int *,
42b5e14a13SCy Schubert 				 FILE *);
432b45e011SOllivier Robert static	void	mreadlist	(struct parse *, FILE *);
442b45e011SOllivier Robert static	void	mreadvar	(struct parse *, FILE *);
452b45e011SOllivier Robert static	void	printassoc	(int, FILE *);
462b45e011SOllivier Robert static	void	associations	(struct parse *, FILE *);
472b45e011SOllivier Robert static	void	lassociations	(struct parse *, FILE *);
482b45e011SOllivier Robert static	void	passociations	(struct parse *, FILE *);
492b45e011SOllivier Robert static	void	lpassociations	(struct parse *, FILE *);
50c0b746e5SOllivier Robert 
51c0b746e5SOllivier Robert #ifdef	UNUSED
522b45e011SOllivier Robert static	void	radiostatus (struct parse *, FILE *);
53c0b746e5SOllivier Robert #endif	/* UNUSED */
54c0b746e5SOllivier Robert 
55b5e14a13SCy Schubert static	void	authinfo	(struct parse *, FILE *);
56b5e14a13SCy Schubert static	void	pstats	 	(struct parse *, FILE *);
572b45e011SOllivier Robert static	long	when		(l_fp *, l_fp *, l_fp *);
582b45e011SOllivier Robert static	char *	prettyinterval	(char *, size_t, long);
59c373d928SXin LI static	int	doprintpeers	(struct varlist *, int, int, size_t, const char *, FILE *, int);
602b45e011SOllivier Robert static	int	dogetpeers	(struct varlist *, associd_t, FILE *, int);
612b45e011SOllivier Robert static	void	dopeers 	(int, FILE *, int);
622b45e011SOllivier Robert static	void	peers		(struct parse *, FILE *);
63873997f3SCy Schubert static	void	doapeers 	(int, FILE *, int);
64873997f3SCy Schubert static	void	apeers		(struct parse *, FILE *);
652b45e011SOllivier Robert static	void	lpeers		(struct parse *, FILE *);
662b45e011SOllivier Robert static	void	doopeers	(int, FILE *, int);
672b45e011SOllivier Robert static	void	opeers		(struct parse *, FILE *);
682b45e011SOllivier Robert static	void	lopeers 	(struct parse *, FILE *);
692b45e011SOllivier Robert static	void	config		(struct parse *, FILE *);
702b45e011SOllivier Robert static	void	saveconfig	(struct parse *, FILE *);
712b45e011SOllivier Robert static	void	config_from_file(struct parse *, FILE *);
72b5e14a13SCy Schubert static	void	mrulist		(struct parse *, FILE *);
73b5e14a13SCy Schubert static	void	ifstats		(struct parse *, FILE *);
74b5e14a13SCy Schubert static	void	reslist		(struct parse *, FILE *);
75b5e14a13SCy Schubert static	void	sysstats	(struct parse *, FILE *);
76b5e14a13SCy Schubert static	void	sysinfo		(struct parse *, FILE *);
77b5e14a13SCy Schubert static	void	kerninfo	(struct parse *, FILE *);
78b5e14a13SCy Schubert static	void	monstats	(struct parse *, FILE *);
79b5e14a13SCy Schubert static	void	iostats		(struct parse *, FILE *);
80b5e14a13SCy Schubert static	void	timerstats	(struct parse *, FILE *);
81c0b746e5SOllivier Robert 
82c0b746e5SOllivier Robert /*
83c0b746e5SOllivier Robert  * Commands we understand.	Ntpdc imports this.
84c0b746e5SOllivier Robert  */
85c0b746e5SOllivier Robert struct xcmd opcmds[] = {
862b45e011SOllivier Robert 	{ "saveconfig", saveconfig, { NTP_STR, NO, NO, NO },
872b45e011SOllivier Robert 		{ "filename", "", "", ""},
882b45e011SOllivier Robert 		"save ntpd configuration to file, . for current config file"},
89c0b746e5SOllivier Robert 	{ "associations", associations, {  NO, NO, NO, NO },
90c0b746e5SOllivier Robert 	  { "", "", "", "" },
91c0b746e5SOllivier Robert 	  "print list of association ID's and statuses for the server's peers" },
92c0b746e5SOllivier Robert 	{ "passociations", passociations,   {  NO, NO, NO, NO },
93c0b746e5SOllivier Robert 	  { "", "", "", "" },
94c0b746e5SOllivier Robert 	  "print list of associations returned by last associations command" },
95c0b746e5SOllivier Robert 	{ "lassociations", lassociations,   {  NO, NO, NO, NO },
96c0b746e5SOllivier Robert 	  { "", "", "", "" },
97c0b746e5SOllivier Robert 	  "print list of associations including all client information" },
98c0b746e5SOllivier Robert 	{ "lpassociations", lpassociations, {  NO, NO, NO, NO },
99c0b746e5SOllivier Robert 	  { "", "", "", "" },
100c0b746e5SOllivier Robert 	  "print last obtained list of associations, including client information" },
101ff717da2SOllivier Robert 	{ "addvars",    addvars,    { NTP_STR, NO, NO, NO },
102c0b746e5SOllivier Robert 	  { "name[=value][,...]", "", "", "" },
103c0b746e5SOllivier Robert 	  "add variables to the variable list or change their values" },
104ff717da2SOllivier Robert 	{ "rmvars", rmvars,     { NTP_STR, NO, NO, NO },
105c0b746e5SOllivier Robert 	  { "name[,...]", "", "", "" },
106c0b746e5SOllivier Robert 	  "remove variables from the variable list" },
107c0b746e5SOllivier Robert 	{ "clearvars",  clearvars,  { NO, NO, NO, NO },
108c0b746e5SOllivier Robert 	  { "", "", "", "" },
109c0b746e5SOllivier Robert 	  "remove all variables from the variable list" },
110c0b746e5SOllivier Robert 	{ "showvars",   showvars,   { NO, NO, NO, NO },
111c0b746e5SOllivier Robert 	  { "", "", "", "" },
112c0b746e5SOllivier Robert 	  "print variables on the variable list" },
113ff717da2SOllivier Robert 	{ "readlist",   readlist,   { OPT|NTP_UINT, NO, NO, NO },
114c0b746e5SOllivier Robert 	  { "assocID", "", "", "" },
115c0b746e5SOllivier Robert 	  "read the system or peer variables included in the variable list" },
116ff717da2SOllivier Robert 	{ "rl",     readlist,   { OPT|NTP_UINT, NO, NO, NO },
117c0b746e5SOllivier Robert 	  { "assocID", "", "", "" },
118c0b746e5SOllivier Robert 	  "read the system or peer variables included in the variable list" },
119ff717da2SOllivier Robert 	{ "writelist",  writelist,  { OPT|NTP_UINT, NO, NO, NO },
120c0b746e5SOllivier Robert 	  { "assocID", "", "", "" },
121c0b746e5SOllivier Robert 	  "write the system or peer variables included in the variable list" },
122b5e14a13SCy Schubert 	{ "readvar", readvar,    { OPT|NTP_UINT, OPT|NTP_STR, OPT|NTP_STR, OPT|NTP_STR, },
123b5e14a13SCy Schubert 	  { "assocID", "varname1", "varname2", "varname3" },
124c0b746e5SOllivier Robert 	  "read system or peer variables" },
125b5e14a13SCy Schubert 	{ "rv",      readvar,    { OPT|NTP_UINT, OPT|NTP_STR, OPT|NTP_STR, OPT|NTP_STR, },
126b5e14a13SCy Schubert 	  { "assocID", "varname1", "varname2", "varname3" },
127c0b746e5SOllivier Robert 	  "read system or peer variables" },
128ff717da2SOllivier Robert 	{ "writevar",   writevar,   { NTP_UINT, NTP_STR, NO, NO },
129c0b746e5SOllivier Robert 	  { "assocID", "name=value,[...]", "", "" },
130c0b746e5SOllivier Robert 	  "write system or peer variables" },
131ff717da2SOllivier Robert 	{ "mreadlist",  mreadlist,  { NTP_UINT, NTP_UINT, NO, NO },
132b5e14a13SCy Schubert 	  { "assocIDlow", "assocIDhigh", "", "" },
133c0b746e5SOllivier Robert 	  "read the peer variables in the variable list for multiple peers" },
134ff717da2SOllivier Robert 	{ "mrl",    mreadlist,  { NTP_UINT, NTP_UINT, NO, NO },
135b5e14a13SCy Schubert 	  { "assocIDlow", "assocIDhigh", "", "" },
136c0b746e5SOllivier Robert 	  "read the peer variables in the variable list for multiple peers" },
137ff717da2SOllivier Robert 	{ "mreadvar",   mreadvar,   { NTP_UINT, NTP_UINT, OPT|NTP_STR, NO },
138b5e14a13SCy Schubert 	  { "assocIDlow", "assocIDhigh", "name=value[,...]", "" },
139c0b746e5SOllivier Robert 	  "read peer variables from multiple peers" },
140ff717da2SOllivier Robert 	{ "mrv",    mreadvar,   { NTP_UINT, NTP_UINT, OPT|NTP_STR, NO },
141b5e14a13SCy Schubert 	  { "assocIDlow", "assocIDhigh", "name=value[,...]", "" },
142c0b746e5SOllivier Robert 	  "read peer variables from multiple peers" },
143ff717da2SOllivier Robert 	{ "clocklist",  clocklist,  { OPT|NTP_UINT, NO, NO, NO },
144c0b746e5SOllivier Robert 	  { "assocID", "", "", "" },
145c0b746e5SOllivier Robert 	  "read the clock variables included in the variable list" },
146ff717da2SOllivier Robert 	{ "cl",     clocklist,  { OPT|NTP_UINT, NO, NO, NO },
147c0b746e5SOllivier Robert 	  { "assocID", "", "", "" },
148c0b746e5SOllivier Robert 	  "read the clock variables included in the variable list" },
149ff717da2SOllivier Robert 	{ "clockvar",   clockvar,   { OPT|NTP_UINT, OPT|NTP_STR, NO, NO },
150c0b746e5SOllivier Robert 	  { "assocID", "name=value[,...]", "", "" },
151c0b746e5SOllivier Robert 	  "read clock variables" },
152ff717da2SOllivier Robert 	{ "cv",     clockvar,   { OPT|NTP_UINT, OPT|NTP_STR, NO, NO },
153c0b746e5SOllivier Robert 	  { "assocID", "name=value[,...]", "", "" },
154c0b746e5SOllivier Robert 	  "read clock variables" },
155b5e14a13SCy Schubert 	{ "pstats",    pstats,    { NTP_UINT, NO, NO, NO },
156c0b746e5SOllivier Robert 	  { "assocID", "", "", "" },
157b5e14a13SCy Schubert 	  "show statistics for a peer" },
1589c2daa00SOllivier Robert 	{ "peers",  peers,      { OPT|IP_VERSION, NO, NO, NO },
1599c2daa00SOllivier Robert 	  { "-4|-6", "", "", "" },
1609c2daa00SOllivier Robert 	  "obtain and print a list of the server's peers [IP version]" },
161873997f3SCy Schubert 	{ "apeers",  apeers,      { OPT|IP_VERSION, NO, NO, NO },
162873997f3SCy Schubert 	  { "-4|-6", "", "", "" },
163873997f3SCy Schubert 	  "obtain and print a list of the server's peers and their assocIDs [IP version]" },
1649c2daa00SOllivier Robert 	{ "lpeers", lpeers,     { OPT|IP_VERSION, NO, NO, NO },
1659c2daa00SOllivier Robert 	  { "-4|-6", "", "", "" },
1669c2daa00SOllivier Robert 	  "obtain and print a list of all peers and clients [IP version]" },
1679c2daa00SOllivier Robert 	{ "opeers", opeers,     { OPT|IP_VERSION, NO, NO, NO },
1689c2daa00SOllivier Robert 	  { "-4|-6", "", "", "" },
1699c2daa00SOllivier Robert 	  "print peer list the old way, with dstadr shown rather than refid [IP version]" },
1709c2daa00SOllivier Robert 	{ "lopeers", lopeers,   { OPT|IP_VERSION, NO, NO, NO },
1719c2daa00SOllivier Robert 	  { "-4|-6", "", "", "" },
1729c2daa00SOllivier Robert 	  "obtain and print a list of all peers and clients showing dstadr [IP version]" },
1732b45e011SOllivier Robert 	{ ":config", config,   { NTP_STR, NO, NO, NO },
1742b45e011SOllivier Robert 	  { "<configuration command line>", "", "", "" },
1752b45e011SOllivier Robert 	  "send a remote configuration command to ntpd" },
1762b45e011SOllivier Robert 	{ "config-from-file", config_from_file, { NTP_STR, NO, NO, NO },
1772b45e011SOllivier Robert 	  { "<configuration filename>", "", "", "" },
1782b45e011SOllivier Robert 	  "configure ntpd using the configuration filename" },
179b5e14a13SCy Schubert 	{ "mrulist", mrulist, { OPT|NTP_STR, OPT|NTP_STR, OPT|NTP_STR, OPT|NTP_STR },
180b5e14a13SCy Schubert 	  { "tag=value", "tag=value", "tag=value", "tag=value" },
181b5e14a13SCy Schubert 	  "display the list of most recently seen source addresses, tags mincount=... resall=0x... resany=0x..." },
182b5e14a13SCy Schubert 	{ "ifstats", ifstats, { NO, NO, NO, NO },
183b5e14a13SCy Schubert 	  { "", "", "", "" },
184b5e14a13SCy Schubert 	  "show statistics for each local address ntpd is using" },
185b5e14a13SCy Schubert 	{ "reslist", reslist, { NO, NO, NO, NO },
186b5e14a13SCy Schubert 	  { "", "", "", "" },
187b5e14a13SCy Schubert 	  "show ntpd access control list" },
188b5e14a13SCy Schubert 	{ "sysinfo", sysinfo, { NO, NO, NO, NO },
189b5e14a13SCy Schubert 	  { "", "", "", "" },
190b5e14a13SCy Schubert 	  "display system summary" },
191b5e14a13SCy Schubert 	{ "kerninfo", kerninfo, { NO, NO, NO, NO },
192b5e14a13SCy Schubert 	  { "", "", "", "" },
193b5e14a13SCy Schubert 	  "display kernel loop and PPS statistics" },
194b5e14a13SCy Schubert 	{ "sysstats", sysstats, { NO, NO, NO, NO },
195b5e14a13SCy Schubert 	  { "", "", "", "" },
196b5e14a13SCy Schubert 	  "display system uptime and packet counts" },
197b5e14a13SCy Schubert 	{ "monstats", monstats, { NO, NO, NO, NO },
198b5e14a13SCy Schubert 	  { "", "", "", "" },
199b5e14a13SCy Schubert 	  "display monitor (mrulist) counters and limits" },
200b5e14a13SCy Schubert 	{ "authinfo", authinfo, { NO, NO, NO, NO },
201b5e14a13SCy Schubert 	  { "", "", "", "" },
202b5e14a13SCy Schubert 	  "display symmetric authentication counters" },
203b5e14a13SCy Schubert 	{ "iostats", iostats, { NO, NO, NO, NO },
204b5e14a13SCy Schubert 	  { "", "", "", "" },
205b5e14a13SCy Schubert 	  "display network input and output counters" },
206b5e14a13SCy Schubert 	{ "timerstats", timerstats, { NO, NO, NO, NO },
207b5e14a13SCy Schubert 	  { "", "", "", "" },
208b5e14a13SCy Schubert 	  "display interval timer counters" },
209c0b746e5SOllivier Robert 	{ 0,		0,		{ NO, NO, NO, NO },
2109c2daa00SOllivier Robert 	  { "-4|-6", "", "", "" }, "" }
211c0b746e5SOllivier Robert };
212c0b746e5SOllivier Robert 
213c0b746e5SOllivier Robert 
214c0b746e5SOllivier Robert /*
215c0b746e5SOllivier Robert  * Variable list data space
216c0b746e5SOllivier Robert  */
2172b45e011SOllivier Robert #define MAXLINE		512	/* maximum length of a line */
218b5e14a13SCy Schubert #define MAXLIST		128	/* maximum variables in list */
219b5e14a13SCy Schubert #define LENHOSTNAME	256	/* host name limit */
220b5e14a13SCy Schubert 
221b5e14a13SCy Schubert #define MRU_GOT_COUNT	0x1
222b5e14a13SCy Schubert #define MRU_GOT_LAST	0x2
223b5e14a13SCy Schubert #define MRU_GOT_FIRST	0x4
224b5e14a13SCy Schubert #define MRU_GOT_MV	0x8
225b5e14a13SCy Schubert #define MRU_GOT_RS	0x10
226b5e14a13SCy Schubert #define MRU_GOT_ADDR	0x20
227b5e14a13SCy Schubert #define MRU_GOT_ALL	(MRU_GOT_COUNT | MRU_GOT_LAST | MRU_GOT_FIRST \
228b5e14a13SCy Schubert 			 | MRU_GOT_MV | MRU_GOT_RS | MRU_GOT_ADDR)
229b5e14a13SCy Schubert 
230b5e14a13SCy Schubert /*
231b5e14a13SCy Schubert  * mrulist() depends on MRUSORT_DEF and MRUSORT_RDEF being the first two
232b5e14a13SCy Schubert  */
233b5e14a13SCy Schubert typedef enum mru_sort_order_tag {
234b5e14a13SCy Schubert 	MRUSORT_DEF = 0,	/* lstint ascending */
235b5e14a13SCy Schubert 	MRUSORT_R_DEF,		/* lstint descending */
236b5e14a13SCy Schubert 	MRUSORT_AVGINT,		/* avgint ascending */
237b5e14a13SCy Schubert 	MRUSORT_R_AVGINT,	/* avgint descending */
238b5e14a13SCy Schubert 	MRUSORT_ADDR,		/* IPv4 asc. then IPv6 asc. */
239b5e14a13SCy Schubert 	MRUSORT_R_ADDR,		/* IPv6 desc. then IPv4 desc. */
240b5e14a13SCy Schubert 	MRUSORT_COUNT,		/* hit count ascending */
241b5e14a13SCy Schubert 	MRUSORT_R_COUNT,	/* hit count descending */
242b5e14a13SCy Schubert 	MRUSORT_MAX,		/* special: count of this enum */
243b5e14a13SCy Schubert } mru_sort_order;
244b5e14a13SCy Schubert 
245b5e14a13SCy Schubert const char * const mru_sort_keywords[MRUSORT_MAX] = {
246b5e14a13SCy Schubert 	"lstint",		/* MRUSORT_DEF */
247b5e14a13SCy Schubert 	"-lstint",		/* MRUSORT_R_DEF */
248b5e14a13SCy Schubert 	"avgint",		/* MRUSORT_AVGINT */
249b5e14a13SCy Schubert 	"-avgint",		/* MRUSORT_R_AVGINT */
250b5e14a13SCy Schubert 	"addr",			/* MRUSORT_ADDR */
251b5e14a13SCy Schubert 	"-addr",		/* MRUSORT_R_ADDR */
252b5e14a13SCy Schubert 	"count",		/* MRUSORT_COUNT */
253b5e14a13SCy Schubert 	"-count",		/* MRUSORT_R_COUNT */
254b5e14a13SCy Schubert };
255b5e14a13SCy Schubert 
256b5e14a13SCy Schubert typedef int (*qsort_cmp)(const void *, const void *);
257b5e14a13SCy Schubert 
258c0b746e5SOllivier Robert /*
259c0b746e5SOllivier Robert  * Old CTL_PST defines for version 2.
260c0b746e5SOllivier Robert  */
261c0b746e5SOllivier Robert #define OLD_CTL_PST_CONFIG		0x80
262c0b746e5SOllivier Robert #define OLD_CTL_PST_AUTHENABLE		0x40
263c0b746e5SOllivier Robert #define OLD_CTL_PST_AUTHENTIC		0x20
264c0b746e5SOllivier Robert #define OLD_CTL_PST_REACH		0x10
265c0b746e5SOllivier Robert #define OLD_CTL_PST_SANE		0x08
266c0b746e5SOllivier Robert #define OLD_CTL_PST_DISP		0x04
2672b45e011SOllivier Robert 
268c0b746e5SOllivier Robert #define OLD_CTL_PST_SEL_REJECT		0
269c0b746e5SOllivier Robert #define OLD_CTL_PST_SEL_SELCAND 	1
270c0b746e5SOllivier Robert #define OLD_CTL_PST_SEL_SYNCCAND	2
271c0b746e5SOllivier Robert #define OLD_CTL_PST_SEL_SYSPEER 	3
272c0b746e5SOllivier Robert 
273c0b746e5SOllivier Robert char flash2[] = " .+*    "; /* flash decode for version 2 */
274c0b746e5SOllivier Robert char flash3[] = " x.-+#*o"; /* flash decode for peer status version 3 */
275c0b746e5SOllivier Robert 
276c0b746e5SOllivier Robert struct varlist {
277f7cba3a8SCy Schubert 	const char *name;
278c0b746e5SOllivier Robert 	char *value;
2792b45e011SOllivier Robert } g_varlist[MAXLIST] = { { 0, 0 } };
280c0b746e5SOllivier Robert 
281c0b746e5SOllivier Robert /*
282c0b746e5SOllivier Robert  * Imported from ntpq.c
283c0b746e5SOllivier Robert  */
284c0b746e5SOllivier Robert extern int showhostnames;
285b5e14a13SCy Schubert extern int wideremote;
286c0b746e5SOllivier Robert extern int rawmode;
287c0b746e5SOllivier Robert extern struct servent *server_entry;
288b5e14a13SCy Schubert extern struct association *assoc_cache;
289c0b746e5SOllivier Robert extern u_char pktversion;
290b5e14a13SCy Schubert 
291b5e14a13SCy Schubert typedef struct mru_tag mru;
292b5e14a13SCy Schubert struct mru_tag {
293b5e14a13SCy Schubert 	mru *		hlink;	/* next in hash table bucket */
294b5e14a13SCy Schubert 	DECL_DLIST_LINK(mru, mlink);
295b5e14a13SCy Schubert 	int		count;
296b5e14a13SCy Schubert 	l_fp		last;
297b5e14a13SCy Schubert 	l_fp		first;
298b5e14a13SCy Schubert 	u_char		mode;
299b5e14a13SCy Schubert 	u_char		ver;
300b5e14a13SCy Schubert 	u_short		rs;
301b5e14a13SCy Schubert 	sockaddr_u	addr;
302b5e14a13SCy Schubert };
303b5e14a13SCy Schubert 
304b5e14a13SCy Schubert typedef struct ifstats_row_tag {
305b5e14a13SCy Schubert 	u_int		ifnum;
306b5e14a13SCy Schubert 	sockaddr_u	addr;
307b5e14a13SCy Schubert 	sockaddr_u	bcast;
308b5e14a13SCy Schubert 	int		enabled;
309b5e14a13SCy Schubert 	u_int		flags;
310d14ac12fSXin LI 	u_int		mcast_count;
311b5e14a13SCy Schubert 	char		name[32];
312d14ac12fSXin LI 	u_int		peer_count;
313d14ac12fSXin LI 	u_int		received;
314d14ac12fSXin LI 	u_int		sent;
315d14ac12fSXin LI 	u_int		send_errors;
316b5e14a13SCy Schubert 	u_int		ttl;
317b5e14a13SCy Schubert 	u_int		uptime;
318b5e14a13SCy Schubert } ifstats_row;
319b5e14a13SCy Schubert 
320b5e14a13SCy Schubert typedef struct reslist_row_tag {
321b5e14a13SCy Schubert 	u_int		idx;
322b5e14a13SCy Schubert 	sockaddr_u	addr;
323b5e14a13SCy Schubert 	sockaddr_u	mask;
324b5e14a13SCy Schubert 	u_long		hits;
325b5e14a13SCy Schubert 	char		flagstr[128];
326b5e14a13SCy Schubert } reslist_row;
327b5e14a13SCy Schubert 
328b5e14a13SCy Schubert typedef struct var_display_collection_tag {
329b5e14a13SCy Schubert 	const char * const tag;		/* system variable */
330b5e14a13SCy Schubert 	const char * const display;	/* descriptive text */
331b5e14a13SCy Schubert 	u_char type;			/* NTP_STR, etc */
332b5e14a13SCy Schubert 	union {
333b5e14a13SCy Schubert 		char *		str;
334b5e14a13SCy Schubert 		sockaddr_u	sau;	/* NTP_ADD */
335b5e14a13SCy Schubert 		l_fp		lfp;	/* NTP_LFP */
336b5e14a13SCy Schubert 	} v;				/* retrieved value */
337b5e14a13SCy Schubert } vdc;
3384ba32eb5SCy Schubert #if !defined(MISSING_C99_STRUCT_INIT)
339f7cba3a8SCy Schubert # define VDC_INIT(a, b, c) { .tag = a, .display = b, .type = c }
340f7cba3a8SCy Schubert #else
341f7cba3a8SCy Schubert # define VDC_INIT(a, b, c) { a, b, c }
342f7cba3a8SCy Schubert #endif
343c0b746e5SOllivier Robert /*
344b5e14a13SCy Schubert  * other local function prototypes
345c0b746e5SOllivier Robert  */
346c373d928SXin LI static int	mrulist_ctrl_c_hook(void);
347b5e14a13SCy Schubert static mru *	add_mru(mru *);
348b5e14a13SCy Schubert static int	collect_mru_list(const char *, l_fp *);
349b5e14a13SCy Schubert static int	fetch_nonce(char *, size_t);
350b5e14a13SCy Schubert static int	qcmp_mru_avgint(const void *, const void *);
351b5e14a13SCy Schubert static int	qcmp_mru_r_avgint(const void *, const void *);
352b5e14a13SCy Schubert static int	qcmp_mru_addr(const void *, const void *);
353b5e14a13SCy Schubert static int	qcmp_mru_r_addr(const void *, const void *);
354b5e14a13SCy Schubert static int	qcmp_mru_count(const void *, const void *);
355b5e14a13SCy Schubert static int	qcmp_mru_r_count(const void *, const void *);
356b5e14a13SCy Schubert static void	validate_ifnum(FILE *, u_int, int *, ifstats_row *);
357b5e14a13SCy Schubert static void	another_ifstats_field(int *, ifstats_row *, FILE *);
358b5e14a13SCy Schubert static void	collect_display_vdc(associd_t as, vdc *table,
359b5e14a13SCy Schubert 				    int decodestatus, FILE *fp);
360c0b746e5SOllivier Robert 
3615171bc9bSCy Schubert static	int	xprintf(FILE *,	char const *, ...) NTP_PRINTF(2, 3);
3625171bc9bSCy Schubert static	int	xputs(char const *, FILE *);
3635171bc9bSCy Schubert static	int	xputc(int, FILE *);
3645171bc9bSCy Schubert 
365b5e14a13SCy Schubert /*
366b5e14a13SCy Schubert  * static globals
367b5e14a13SCy Schubert  */
368b5e14a13SCy Schubert static u_int	mru_count;
369b5e14a13SCy Schubert static u_int	mru_dupes;
370b5e14a13SCy Schubert volatile int	mrulist_interrupted;
371b5e14a13SCy Schubert static mru	mru_list;		/* listhead */
372b5e14a13SCy Schubert static mru **	hash_table;
373b5e14a13SCy Schubert 
374b5e14a13SCy Schubert /*
375b5e14a13SCy Schubert  * qsort comparison function table for mrulist().  The first two
376b5e14a13SCy Schubert  * entries are NULL because they are handled without qsort().
377b5e14a13SCy Schubert  */
378f7cba3a8SCy Schubert static const qsort_cmp mru_qcmp_table[MRUSORT_MAX] = {
379b5e14a13SCy Schubert 	NULL,			/* MRUSORT_DEF unused */
380b5e14a13SCy Schubert 	NULL,			/* MRUSORT_R_DEF unused */
381b5e14a13SCy Schubert 	&qcmp_mru_avgint,	/* MRUSORT_AVGINT */
382b5e14a13SCy Schubert 	&qcmp_mru_r_avgint,	/* MRUSORT_R_AVGINT */
383b5e14a13SCy Schubert 	&qcmp_mru_addr,		/* MRUSORT_ADDR */
384b5e14a13SCy Schubert 	&qcmp_mru_r_addr,	/* MRUSORT_R_ADDR */
385b5e14a13SCy Schubert 	&qcmp_mru_count,	/* MRUSORT_COUNT */
386b5e14a13SCy Schubert 	&qcmp_mru_r_count,	/* MRUSORT_R_COUNT */
387b5e14a13SCy Schubert };
388c0b746e5SOllivier Robert 
389c0b746e5SOllivier Robert /*
3905171bc9bSCy Schubert  * NULL-pointer safe FILE I/O: use stderr if no file supplied.
3915171bc9bSCy Schubert  */
3925171bc9bSCy Schubert static	int
xprintf(FILE * ofp,char const * fmt,...)3935171bc9bSCy Schubert xprintf(
3945171bc9bSCy Schubert 	FILE *		ofp,
3955171bc9bSCy Schubert 	char const *	fmt,
3965171bc9bSCy Schubert 	...
3975171bc9bSCy Schubert 	)
3985171bc9bSCy Schubert {
3995171bc9bSCy Schubert 	va_list	va;
4005171bc9bSCy Schubert 	int	rc;
4015171bc9bSCy Schubert 
4025171bc9bSCy Schubert 	va_start(va, fmt);
4035171bc9bSCy Schubert 	rc = vfprintf((ofp ? ofp : stderr), fmt, va);
4045171bc9bSCy Schubert 	va_end(va);
4055171bc9bSCy Schubert 	return rc;
4065171bc9bSCy Schubert }
4075171bc9bSCy Schubert 
4085171bc9bSCy Schubert static	int
xputs(char const * str,FILE * ofp)4095171bc9bSCy Schubert xputs(
4105171bc9bSCy Schubert 	char const *	str,
4115171bc9bSCy Schubert 	FILE *		ofp
4125171bc9bSCy Schubert 	)
4135171bc9bSCy Schubert {
4145171bc9bSCy Schubert 	return fputs(str, (ofp ? ofp : stderr));
4155171bc9bSCy Schubert }
4165171bc9bSCy Schubert 
4175171bc9bSCy Schubert static	int
xputc(int ch,FILE * ofp)4185171bc9bSCy Schubert xputc(
4195171bc9bSCy Schubert 	int	ch,
4205171bc9bSCy Schubert 	FILE *	ofp
4215171bc9bSCy Schubert 	)
4225171bc9bSCy Schubert {
4235171bc9bSCy Schubert 	return fputc(ch, (ofp ? ofp : stderr));
4245171bc9bSCy Schubert }
4255171bc9bSCy Schubert 
4265171bc9bSCy Schubert /*
427c0b746e5SOllivier Robert  * checkassocid - return the association ID, checking to see if it is valid
428c0b746e5SOllivier Robert  */
4292b45e011SOllivier Robert static associd_t
checkassocid(u_int32 value)430c0b746e5SOllivier Robert checkassocid(
431c0b746e5SOllivier Robert 	u_int32 value
432c0b746e5SOllivier Robert 	)
433c0b746e5SOllivier Robert {
4342b45e011SOllivier Robert 	associd_t	associd;
4352b45e011SOllivier Robert 	u_long		ulvalue;
4362b45e011SOllivier Robert 
4372b45e011SOllivier Robert 	associd = (associd_t)value;
4382b45e011SOllivier Robert 	if (0 == associd || value != associd) {
4392b45e011SOllivier Robert 		ulvalue = value;
4405171bc9bSCy Schubert 		xprintf(stderr,
4412b45e011SOllivier Robert 			"***Invalid association ID %lu specified\n",
4422b45e011SOllivier Robert 			ulvalue);
443c0b746e5SOllivier Robert 		return 0;
444c0b746e5SOllivier Robert 	}
445c0b746e5SOllivier Robert 
4462b45e011SOllivier Robert 	return associd;
447c0b746e5SOllivier Robert }
448c0b746e5SOllivier Robert 
449c0b746e5SOllivier Robert 
450c0b746e5SOllivier Robert /*
451b5e14a13SCy Schubert  * findlistvar - Look for the named variable in a varlist.  If found,
452b5e14a13SCy Schubert  *		 return a pointer to it.  Otherwise, if the list has
453b5e14a13SCy Schubert  *		 slots available, return the pointer to the first free
454b5e14a13SCy Schubert  *		 slot, or NULL if it's full.
455c0b746e5SOllivier Robert  */
456c0b746e5SOllivier Robert static struct varlist *
findlistvar(struct varlist * list,char * name)457c0b746e5SOllivier Robert findlistvar(
458c0b746e5SOllivier Robert 	struct varlist *list,
459c0b746e5SOllivier Robert 	char *name
460c0b746e5SOllivier Robert 	)
461c0b746e5SOllivier Robert {
462b5e14a13SCy Schubert 	struct varlist *vl;
463c0b746e5SOllivier Robert 
464b5e14a13SCy Schubert 	for (vl = list; vl < list + MAXLIST && vl->name != NULL; vl++)
465b5e14a13SCy Schubert 		if (!strcmp(name, vl->name))
466c0b746e5SOllivier Robert 			return vl;
467c0b746e5SOllivier Robert 	if (vl < list + MAXLIST)
468c0b746e5SOllivier Robert 		return vl;
469b5e14a13SCy Schubert 
470b5e14a13SCy Schubert 	return NULL;
471c0b746e5SOllivier Robert }
472c0b746e5SOllivier Robert 
473c0b746e5SOllivier Robert 
474c0b746e5SOllivier Robert /*
475c0b746e5SOllivier Robert  * doaddvlist - add variable(s) to the variable list
476c0b746e5SOllivier Robert  */
477c0b746e5SOllivier Robert static void
doaddvlist(struct varlist * vlist,const char * vars)478c0b746e5SOllivier Robert doaddvlist(
479c0b746e5SOllivier Robert 	struct varlist *vlist,
4802b45e011SOllivier Robert 	const char *vars
481c0b746e5SOllivier Robert 	)
482c0b746e5SOllivier Robert {
483b5e14a13SCy Schubert 	struct varlist *vl;
484c373d928SXin LI 	size_t len;
485c0b746e5SOllivier Robert 	char *name;
486c0b746e5SOllivier Robert 	char *value;
487c0b746e5SOllivier Robert 
488c0b746e5SOllivier Robert 	len = strlen(vars);
489c0b746e5SOllivier Robert 	while (nextvar(&len, &vars, &name, &value)) {
490c7f4d233SXin LI 		INSIST(name && value);
491c0b746e5SOllivier Robert 		vl = findlistvar(vlist, name);
492b5e14a13SCy Schubert 		if (NULL == vl) {
4935171bc9bSCy Schubert 			xprintf(stderr, "Variable list full\n");
494c0b746e5SOllivier Robert 			return;
495c0b746e5SOllivier Robert 		}
496c0b746e5SOllivier Robert 
497b5e14a13SCy Schubert 		if (NULL == vl->name) {
4982b45e011SOllivier Robert 			vl->name = estrdup(name);
499b5e14a13SCy Schubert 		} else if (vl->value != NULL) {
500c0b746e5SOllivier Robert 			free(vl->value);
501b5e14a13SCy Schubert 			vl->value = NULL;
502c0b746e5SOllivier Robert 		}
503c0b746e5SOllivier Robert 
504b5e14a13SCy Schubert 		if (value != NULL)
5052b45e011SOllivier Robert 			vl->value = estrdup(value);
506c0b746e5SOllivier Robert 	}
507c0b746e5SOllivier Robert }
508c0b746e5SOllivier Robert 
509c0b746e5SOllivier Robert 
510c0b746e5SOllivier Robert /*
511c0b746e5SOllivier Robert  * dormvlist - remove variable(s) from the variable list
512c0b746e5SOllivier Robert  */
513c0b746e5SOllivier Robert static void
dormvlist(struct varlist * vlist,const char * vars)514c0b746e5SOllivier Robert dormvlist(
515c0b746e5SOllivier Robert 	struct varlist *vlist,
5162b45e011SOllivier Robert 	const char *vars
517c0b746e5SOllivier Robert 	)
518c0b746e5SOllivier Robert {
519b5e14a13SCy Schubert 	struct varlist *vl;
520c373d928SXin LI 	size_t len;
521c0b746e5SOllivier Robert 	char *name;
522c0b746e5SOllivier Robert 	char *value;
523c0b746e5SOllivier Robert 
524c0b746e5SOllivier Robert 	len = strlen(vars);
525c0b746e5SOllivier Robert 	while (nextvar(&len, &vars, &name, &value)) {
526c7f4d233SXin LI 		INSIST(name && value);
527c0b746e5SOllivier Robert 		vl = findlistvar(vlist, name);
528c0b746e5SOllivier Robert 		if (vl == 0 || vl->name == 0) {
5295171bc9bSCy Schubert 			(void) xprintf(stderr, "Variable `%s' not found\n",
530c0b746e5SOllivier Robert 				       name);
531c0b746e5SOllivier Robert 		} else {
532f7cba3a8SCy Schubert 			free((void *)(intptr_t)vl->name);
533c0b746e5SOllivier Robert 			if (vl->value != 0)
534c0b746e5SOllivier Robert 			    free(vl->value);
5352b45e011SOllivier Robert 			for ( ; (vl+1) < (g_varlist + MAXLIST)
536c0b746e5SOllivier Robert 				      && (vl+1)->name != 0; vl++) {
537c0b746e5SOllivier Robert 				vl->name = (vl+1)->name;
538c0b746e5SOllivier Robert 				vl->value = (vl+1)->value;
539c0b746e5SOllivier Robert 			}
540c0b746e5SOllivier Robert 			vl->name = vl->value = 0;
541c0b746e5SOllivier Robert 		}
542c0b746e5SOllivier Robert 	}
543c0b746e5SOllivier Robert }
544c0b746e5SOllivier Robert 
545c0b746e5SOllivier Robert 
546c0b746e5SOllivier Robert /*
547c0b746e5SOllivier Robert  * doclearvlist - clear a variable list
548c0b746e5SOllivier Robert  */
549c0b746e5SOllivier Robert static void
doclearvlist(struct varlist * vlist)550c0b746e5SOllivier Robert doclearvlist(
551c0b746e5SOllivier Robert 	struct varlist *vlist
552c0b746e5SOllivier Robert 	)
553c0b746e5SOllivier Robert {
554c0b746e5SOllivier Robert 	register struct varlist *vl;
555c0b746e5SOllivier Robert 
556c0b746e5SOllivier Robert 	for (vl = vlist; vl < vlist + MAXLIST && vl->name != 0; vl++) {
557f7cba3a8SCy Schubert 		free((void *)(intptr_t)vl->name);
558c0b746e5SOllivier Robert 		vl->name = 0;
559c0b746e5SOllivier Robert 		if (vl->value != 0) {
560c0b746e5SOllivier Robert 			free(vl->value);
561c0b746e5SOllivier Robert 			vl->value = 0;
562c0b746e5SOllivier Robert 		}
563c0b746e5SOllivier Robert 	}
564c0b746e5SOllivier Robert }
565c0b746e5SOllivier Robert 
566c0b746e5SOllivier Robert 
567c0b746e5SOllivier Robert /*
568c0b746e5SOllivier Robert  * makequerydata - form a data buffer to be included with a query
569c0b746e5SOllivier Robert  */
570c0b746e5SOllivier Robert static void
makequerydata(struct varlist * vlist,size_t * datalen,char * data)571c0b746e5SOllivier Robert makequerydata(
572c0b746e5SOllivier Robert 	struct varlist *vlist,
573c373d928SXin LI 	size_t *datalen,
574c0b746e5SOllivier Robert 	char *data
575c0b746e5SOllivier Robert 	)
576c0b746e5SOllivier Robert {
577c0b746e5SOllivier Robert 	register struct varlist *vl;
578c0b746e5SOllivier Robert 	register char *cp, *cpend;
579c373d928SXin LI 	register size_t namelen, valuelen;
580c373d928SXin LI 	register size_t totallen;
581c0b746e5SOllivier Robert 
582c0b746e5SOllivier Robert 	cp = data;
583c0b746e5SOllivier Robert 	cpend = data + *datalen;
584c0b746e5SOllivier Robert 
585c0b746e5SOllivier Robert 	for (vl = vlist; vl < vlist + MAXLIST && vl->name != 0; vl++) {
586c0b746e5SOllivier Robert 		namelen = strlen(vl->name);
587c0b746e5SOllivier Robert 		if (vl->value == 0)
588c0b746e5SOllivier Robert 			valuelen = 0;
589c0b746e5SOllivier Robert 		else
590c0b746e5SOllivier Robert 			valuelen = strlen(vl->value);
591c0b746e5SOllivier Robert 		totallen = namelen + valuelen + (valuelen != 0) + (cp != data);
592b5e14a13SCy Schubert 		if (cp + totallen > cpend) {
5935171bc9bSCy Schubert 		    xprintf(stderr,
594b5e14a13SCy Schubert 			    "***Ignoring variables starting with `%s'\n",
595b5e14a13SCy Schubert 			    vl->name);
596c0b746e5SOllivier Robert 		    break;
597b5e14a13SCy Schubert 		}
598c0b746e5SOllivier Robert 
599c0b746e5SOllivier Robert 		if (cp != data)
600c0b746e5SOllivier Robert 			*cp++ = ',';
601b5e14a13SCy Schubert 		memcpy(cp, vl->name, (size_t)namelen);
602c0b746e5SOllivier Robert 		cp += namelen;
603c0b746e5SOllivier Robert 		if (valuelen != 0) {
604c0b746e5SOllivier Robert 			*cp++ = '=';
605b5e14a13SCy Schubert 			memcpy(cp, vl->value, (size_t)valuelen);
606c0b746e5SOllivier Robert 			cp += valuelen;
607c0b746e5SOllivier Robert 		}
608c0b746e5SOllivier Robert 	}
609c373d928SXin LI 	*datalen = (size_t)(cp - data);
610c0b746e5SOllivier Robert }
611c0b746e5SOllivier Robert 
612c0b746e5SOllivier Robert 
613c0b746e5SOllivier Robert /*
614c0b746e5SOllivier Robert  * doquerylist - send a message including variables in a list
615c0b746e5SOllivier Robert  */
616c0b746e5SOllivier Robert static int
doquerylist(struct varlist * vlist,int op,associd_t associd,int auth,u_short * rstatus,size_t * dsize,const char ** datap)617c0b746e5SOllivier Robert doquerylist(
618c0b746e5SOllivier Robert 	struct varlist *vlist,
619c0b746e5SOllivier Robert 	int op,
6202b45e011SOllivier Robert 	associd_t associd,
621c0b746e5SOllivier Robert 	int auth,
622c0b746e5SOllivier Robert 	u_short *rstatus,
623c373d928SXin LI 	size_t *dsize,
6242b45e011SOllivier Robert 	const char **datap
625c0b746e5SOllivier Robert 	)
626c0b746e5SOllivier Robert {
627c0b746e5SOllivier Robert 	char data[CTL_MAX_DATA_LEN];
628c373d928SXin LI 	size_t datalen;
629c0b746e5SOllivier Robert 
630c0b746e5SOllivier Robert 	datalen = sizeof(data);
631c0b746e5SOllivier Robert 	makequerydata(vlist, &datalen, data);
632c0b746e5SOllivier Robert 
633b5e14a13SCy Schubert 	return doquery(op, associd, auth, datalen, data, rstatus, dsize,
634b5e14a13SCy Schubert 		       datap);
635c0b746e5SOllivier Robert }
636c0b746e5SOllivier Robert 
637c0b746e5SOllivier Robert 
638c0b746e5SOllivier Robert /*
639c0b746e5SOllivier Robert  * doprintvlist - print the variables on a list
640c0b746e5SOllivier Robert  */
641c0b746e5SOllivier Robert static void
doprintvlist(struct varlist * vlist,FILE * fp)642c0b746e5SOllivier Robert doprintvlist(
643c0b746e5SOllivier Robert 	struct varlist *vlist,
644c0b746e5SOllivier Robert 	FILE *fp
645c0b746e5SOllivier Robert 	)
646c0b746e5SOllivier Robert {
647b5e14a13SCy Schubert 	size_t n;
648c0b746e5SOllivier Robert 
649b5e14a13SCy Schubert 	if (NULL == vlist->name) {
6505171bc9bSCy Schubert 		xprintf(fp, "No variables on list\n");
651b5e14a13SCy Schubert 		return;
652c0b746e5SOllivier Robert 	}
653b5e14a13SCy Schubert 	for (n = 0; n < MAXLIST && vlist[n].name != NULL; n++) {
654b5e14a13SCy Schubert 		if (NULL == vlist[n].value)
6555171bc9bSCy Schubert 			xprintf(fp, "%s\n", vlist[n].name);
656b5e14a13SCy Schubert 		else
6575171bc9bSCy Schubert 			xprintf(fp, "%s=%s\n", vlist[n].name,
658b5e14a13SCy Schubert 				vlist[n].value);
659c0b746e5SOllivier Robert 	}
660c0b746e5SOllivier Robert }
661c0b746e5SOllivier Robert 
662c0b746e5SOllivier Robert /*
663c0b746e5SOllivier Robert  * addvars - add variables to the variable list
664c0b746e5SOllivier Robert  */
665c0b746e5SOllivier Robert /*ARGSUSED*/
666c0b746e5SOllivier Robert static void
addvars(struct parse * pcmd,FILE * fp)667c0b746e5SOllivier Robert addvars(
668c0b746e5SOllivier Robert 	struct parse *pcmd,
669c0b746e5SOllivier Robert 	FILE *fp
670c0b746e5SOllivier Robert 	)
671c0b746e5SOllivier Robert {
6722b45e011SOllivier Robert 	doaddvlist(g_varlist, pcmd->argval[0].string);
673c0b746e5SOllivier Robert }
674c0b746e5SOllivier Robert 
675c0b746e5SOllivier Robert 
676c0b746e5SOllivier Robert /*
677c0b746e5SOllivier Robert  * rmvars - remove variables from the variable list
678c0b746e5SOllivier Robert  */
679c0b746e5SOllivier Robert /*ARGSUSED*/
680c0b746e5SOllivier Robert static void
rmvars(struct parse * pcmd,FILE * fp)681c0b746e5SOllivier Robert rmvars(
682c0b746e5SOllivier Robert 	struct parse *pcmd,
683c0b746e5SOllivier Robert 	FILE *fp
684c0b746e5SOllivier Robert 	)
685c0b746e5SOllivier Robert {
6862b45e011SOllivier Robert 	dormvlist(g_varlist, pcmd->argval[0].string);
687c0b746e5SOllivier Robert }
688c0b746e5SOllivier Robert 
689c0b746e5SOllivier Robert 
690c0b746e5SOllivier Robert /*
691c0b746e5SOllivier Robert  * clearvars - clear the variable list
692c0b746e5SOllivier Robert  */
693c0b746e5SOllivier Robert /*ARGSUSED*/
694c0b746e5SOllivier Robert static void
clearvars(struct parse * pcmd,FILE * fp)695c0b746e5SOllivier Robert clearvars(
696c0b746e5SOllivier Robert 	struct parse *pcmd,
697c0b746e5SOllivier Robert 	FILE *fp
698c0b746e5SOllivier Robert 	)
699c0b746e5SOllivier Robert {
7002b45e011SOllivier Robert 	doclearvlist(g_varlist);
701c0b746e5SOllivier Robert }
702c0b746e5SOllivier Robert 
703c0b746e5SOllivier Robert 
704c0b746e5SOllivier Robert /*
705c0b746e5SOllivier Robert  * showvars - show variables on the variable list
706c0b746e5SOllivier Robert  */
707c0b746e5SOllivier Robert /*ARGSUSED*/
708c0b746e5SOllivier Robert static void
showvars(struct parse * pcmd,FILE * fp)709c0b746e5SOllivier Robert showvars(
710c0b746e5SOllivier Robert 	struct parse *pcmd,
711c0b746e5SOllivier Robert 	FILE *fp
712c0b746e5SOllivier Robert 	)
713c0b746e5SOllivier Robert {
7142b45e011SOllivier Robert 	doprintvlist(g_varlist, fp);
715c0b746e5SOllivier Robert }
716c0b746e5SOllivier Robert 
717c0b746e5SOllivier Robert 
718c0b746e5SOllivier Robert /*
719c0b746e5SOllivier Robert  * dolist - send a request with the given list of variables
720c0b746e5SOllivier Robert  */
721c0b746e5SOllivier Robert static int
dolist(struct varlist * vlist,associd_t associd,int op,int type,FILE * fp)722c0b746e5SOllivier Robert dolist(
723c0b746e5SOllivier Robert 	struct varlist *vlist,
7242b45e011SOllivier Robert 	associd_t associd,
725c0b746e5SOllivier Robert 	int op,
726c0b746e5SOllivier Robert 	int type,
727c0b746e5SOllivier Robert 	FILE *fp
728c0b746e5SOllivier Robert 	)
729c0b746e5SOllivier Robert {
7302b45e011SOllivier Robert 	const char *datap;
731c0b746e5SOllivier Robert 	int res;
732c373d928SXin LI 	size_t dsize;
733c0b746e5SOllivier Robert 	u_short rstatus;
7342b45e011SOllivier Robert 	int quiet;
7352b45e011SOllivier Robert 
7362b45e011SOllivier Robert 	/*
7372b45e011SOllivier Robert 	 * if we're asking for specific variables don't include the
7382b45e011SOllivier Robert 	 * status header line in the output.
7392b45e011SOllivier Robert 	 */
7402b45e011SOllivier Robert 	if (old_rv)
7412b45e011SOllivier Robert 		quiet = 0;
7422b45e011SOllivier Robert 	else
7432b45e011SOllivier Robert 		quiet = (vlist->name != NULL);
744c0b746e5SOllivier Robert 
745c0b746e5SOllivier Robert 	res = doquerylist(vlist, op, associd, 0, &rstatus, &dsize, &datap);
746c0b746e5SOllivier Robert 
747c0b746e5SOllivier Robert 	if (res != 0)
748c0b746e5SOllivier Robert 		return 0;
749c0b746e5SOllivier Robert 
750ff717da2SOllivier Robert 	if (numhosts > 1)
7515171bc9bSCy Schubert 		xprintf(fp, "server=%s ", currenthost);
752c0b746e5SOllivier Robert 	if (dsize == 0) {
753c0b746e5SOllivier Robert 		if (associd == 0)
7545171bc9bSCy Schubert 			xprintf(fp, "No system%s variables returned\n",
755c0b746e5SOllivier Robert 				(type == TYPE_CLOCK) ? " clock" : "");
756c0b746e5SOllivier Robert 		else
7575171bc9bSCy Schubert 			xprintf(fp,
758c0b746e5SOllivier Robert 				"No information returned for%s association %u\n",
759b5e14a13SCy Schubert 				(type == TYPE_CLOCK) ? " clock" : "",
760b5e14a13SCy Schubert 				associd);
761c0b746e5SOllivier Robert 		return 1;
762c0b746e5SOllivier Robert 	}
763c0b746e5SOllivier Robert 
7642b45e011SOllivier Robert 	if (!quiet)
7655171bc9bSCy Schubert 		xprintf(fp, "associd=%u ", associd);
7662b45e011SOllivier Robert 	printvars(dsize, datap, (int)rstatus, type, quiet, fp);
767c0b746e5SOllivier Robert 	return 1;
768c0b746e5SOllivier Robert }
769c0b746e5SOllivier Robert 
770c0b746e5SOllivier Robert 
771c0b746e5SOllivier Robert /*
772c0b746e5SOllivier Robert  * readlist - send a read variables request with the variables on the list
773c0b746e5SOllivier Robert  */
774c0b746e5SOllivier Robert static void
readlist(struct parse * pcmd,FILE * fp)775c0b746e5SOllivier Robert readlist(
776c0b746e5SOllivier Robert 	struct parse *pcmd,
777c0b746e5SOllivier Robert 	FILE *fp
778c0b746e5SOllivier Robert 	)
779c0b746e5SOllivier Robert {
7802b45e011SOllivier Robert 	associd_t	associd;
7812b45e011SOllivier Robert 	int		type;
782c0b746e5SOllivier Robert 
783c0b746e5SOllivier Robert 	if (pcmd->nargs == 0) {
784c0b746e5SOllivier Robert 		associd = 0;
785c0b746e5SOllivier Robert 	} else {
786c0b746e5SOllivier Robert 	  /* HMS: I think we want the u_int32 target here, not the u_long */
787c0b746e5SOllivier Robert 		if (pcmd->argval[0].uval == 0)
788c0b746e5SOllivier Robert 			associd = 0;
789c0b746e5SOllivier Robert 		else if ((associd = checkassocid(pcmd->argval[0].uval)) == 0)
790c0b746e5SOllivier Robert 			return;
791c0b746e5SOllivier Robert 	}
792c0b746e5SOllivier Robert 
7932b45e011SOllivier Robert 	type = (0 == associd)
7942b45e011SOllivier Robert 		   ? TYPE_SYS
7952b45e011SOllivier Robert 		   : TYPE_PEER;
7962b45e011SOllivier Robert 	dolist(g_varlist, associd, CTL_OP_READVAR, type, fp);
797c0b746e5SOllivier Robert }
798c0b746e5SOllivier Robert 
799c0b746e5SOllivier Robert 
800c0b746e5SOllivier Robert /*
801c0b746e5SOllivier Robert  * writelist - send a write variables request with the variables on the list
802c0b746e5SOllivier Robert  */
803c0b746e5SOllivier Robert static void
writelist(struct parse * pcmd,FILE * fp)804c0b746e5SOllivier Robert writelist(
805c0b746e5SOllivier Robert 	struct parse *pcmd,
806c0b746e5SOllivier Robert 	FILE *fp
807c0b746e5SOllivier Robert 	)
808c0b746e5SOllivier Robert {
8092b45e011SOllivier Robert 	const char *datap;
810c0b746e5SOllivier Robert 	int res;
8112b45e011SOllivier Robert 	associd_t associd;
812c373d928SXin LI 	size_t dsize;
813c0b746e5SOllivier Robert 	u_short rstatus;
814c0b746e5SOllivier Robert 
815c0b746e5SOllivier Robert 	if (pcmd->nargs == 0) {
816c0b746e5SOllivier Robert 		associd = 0;
817c0b746e5SOllivier Robert 	} else {
818c0b746e5SOllivier Robert 		/* HMS: Do we really want uval here? */
819c0b746e5SOllivier Robert 		if (pcmd->argval[0].uval == 0)
820c0b746e5SOllivier Robert 			associd = 0;
821c0b746e5SOllivier Robert 		else if ((associd = checkassocid(pcmd->argval[0].uval)) == 0)
822c0b746e5SOllivier Robert 			return;
823c0b746e5SOllivier Robert 	}
824c0b746e5SOllivier Robert 
8252b45e011SOllivier Robert 	res = doquerylist(g_varlist, CTL_OP_WRITEVAR, associd, 1, &rstatus,
826c0b746e5SOllivier Robert 			  &dsize, &datap);
827c0b746e5SOllivier Robert 
828c0b746e5SOllivier Robert 	if (res != 0)
829c0b746e5SOllivier Robert 		return;
830c0b746e5SOllivier Robert 
831ff717da2SOllivier Robert 	if (numhosts > 1)
8325171bc9bSCy Schubert 		(void) xprintf(fp, "server=%s ", currenthost);
833c0b746e5SOllivier Robert 	if (dsize == 0)
8345171bc9bSCy Schubert 		(void) xprintf(fp, "done! (no data returned)\n");
835ff717da2SOllivier Robert 	else {
8365171bc9bSCy Schubert 		(void) xprintf(fp,"associd=%u ", associd);
837c0b746e5SOllivier Robert 		printvars(dsize, datap, (int)rstatus,
8382b45e011SOllivier Robert 			  (associd != 0) ? TYPE_PEER : TYPE_SYS, 0, fp);
839ff717da2SOllivier Robert 	}
840c0b746e5SOllivier Robert 	return;
841c0b746e5SOllivier Robert }
842c0b746e5SOllivier Robert 
843c0b746e5SOllivier Robert 
844c0b746e5SOllivier Robert /*
845c0b746e5SOllivier Robert  * readvar - send a read variables request with the specified variables
846c0b746e5SOllivier Robert  */
847c0b746e5SOllivier Robert static void
readvar(struct parse * pcmd,FILE * fp)848c0b746e5SOllivier Robert readvar(
849c0b746e5SOllivier Robert 	struct parse *pcmd,
850c0b746e5SOllivier Robert 	FILE *fp
851c0b746e5SOllivier Robert 	)
852c0b746e5SOllivier Robert {
8532b45e011SOllivier Robert 	associd_t	associd;
854c373d928SXin LI 	size_t		tmpcount;
855c373d928SXin LI 	size_t		u;
8562b45e011SOllivier Robert 	int		type;
857c0b746e5SOllivier Robert 	struct varlist	tmplist[MAXLIST];
858c0b746e5SOllivier Robert 
8592b45e011SOllivier Robert 
860c0b746e5SOllivier Robert 	/* HMS: uval? */
861c0b746e5SOllivier Robert 	if (pcmd->nargs == 0 || pcmd->argval[0].uval == 0)
862c0b746e5SOllivier Robert 		associd = 0;
863c0b746e5SOllivier Robert 	else if ((associd = checkassocid(pcmd->argval[0].uval)) == 0)
864c0b746e5SOllivier Robert 		return;
865c0b746e5SOllivier Robert 
866b5e14a13SCy Schubert 	ZERO(tmplist);
867b5e14a13SCy Schubert 	if (pcmd->nargs > 1) {
868b5e14a13SCy Schubert 		tmpcount = pcmd->nargs - 1;
869b5e14a13SCy Schubert 		for (u = 0; u < tmpcount; u++)
870b5e14a13SCy Schubert 			doaddvlist(tmplist, pcmd->argval[1 + u].string);
871b5e14a13SCy Schubert 	}
872c0b746e5SOllivier Robert 
8732b45e011SOllivier Robert 	type = (0 == associd)
8742b45e011SOllivier Robert 		   ? TYPE_SYS
8752b45e011SOllivier Robert 		   : TYPE_PEER;
8762b45e011SOllivier Robert 	dolist(tmplist, associd, CTL_OP_READVAR, type, fp);
877c0b746e5SOllivier Robert 
878c0b746e5SOllivier Robert 	doclearvlist(tmplist);
879c0b746e5SOllivier Robert }
880c0b746e5SOllivier Robert 
881c0b746e5SOllivier Robert 
882c0b746e5SOllivier Robert /*
883c0b746e5SOllivier Robert  * writevar - send a write variables request with the specified variables
884c0b746e5SOllivier Robert  */
885c0b746e5SOllivier Robert static void
writevar(struct parse * pcmd,FILE * fp)886c0b746e5SOllivier Robert writevar(
887c0b746e5SOllivier Robert 	struct parse *pcmd,
888c0b746e5SOllivier Robert 	FILE *fp
889c0b746e5SOllivier Robert 	)
890c0b746e5SOllivier Robert {
8912b45e011SOllivier Robert 	const char *datap;
892c0b746e5SOllivier Robert 	int res;
8932b45e011SOllivier Robert 	associd_t associd;
8942b45e011SOllivier Robert 	int type;
895c373d928SXin LI 	size_t dsize;
896c0b746e5SOllivier Robert 	u_short rstatus;
897c0b746e5SOllivier Robert 	struct varlist tmplist[MAXLIST];
898c0b746e5SOllivier Robert 
899c0b746e5SOllivier Robert 	/* HMS: uval? */
900c0b746e5SOllivier Robert 	if (pcmd->argval[0].uval == 0)
901c0b746e5SOllivier Robert 		associd = 0;
902c0b746e5SOllivier Robert 	else if ((associd = checkassocid(pcmd->argval[0].uval)) == 0)
903c0b746e5SOllivier Robert 		return;
904c0b746e5SOllivier Robert 
905b5e14a13SCy Schubert 	ZERO(tmplist);
906c0b746e5SOllivier Robert 	doaddvlist(tmplist, pcmd->argval[1].string);
907c0b746e5SOllivier Robert 
908c0b746e5SOllivier Robert 	res = doquerylist(tmplist, CTL_OP_WRITEVAR, associd, 1, &rstatus,
909c0b746e5SOllivier Robert 			  &dsize, &datap);
910c0b746e5SOllivier Robert 
911c0b746e5SOllivier Robert 	doclearvlist(tmplist);
912c0b746e5SOllivier Robert 
913c0b746e5SOllivier Robert 	if (res != 0)
914c0b746e5SOllivier Robert 		return;
915c0b746e5SOllivier Robert 
916ff717da2SOllivier Robert 	if (numhosts > 1)
9175171bc9bSCy Schubert 		xprintf(fp, "server=%s ", currenthost);
918c0b746e5SOllivier Robert 	if (dsize == 0)
9195171bc9bSCy Schubert 		xprintf(fp, "done! (no data returned)\n");
920ff717da2SOllivier Robert 	else {
9215171bc9bSCy Schubert 		xprintf(fp,"associd=%u ", associd);
9222b45e011SOllivier Robert 		type = (0 == associd)
9232b45e011SOllivier Robert 			   ? TYPE_SYS
9242b45e011SOllivier Robert 			   : TYPE_PEER;
9252b45e011SOllivier Robert 		printvars(dsize, datap, (int)rstatus, type, 0, fp);
926ff717da2SOllivier Robert 	}
927c0b746e5SOllivier Robert 	return;
928c0b746e5SOllivier Robert }
929c0b746e5SOllivier Robert 
930c0b746e5SOllivier Robert 
931c0b746e5SOllivier Robert /*
932c0b746e5SOllivier Robert  * clocklist - send a clock variables request with the variables on the list
933c0b746e5SOllivier Robert  */
934c0b746e5SOllivier Robert static void
clocklist(struct parse * pcmd,FILE * fp)935c0b746e5SOllivier Robert clocklist(
936c0b746e5SOllivier Robert 	struct parse *pcmd,
937c0b746e5SOllivier Robert 	FILE *fp
938c0b746e5SOllivier Robert 	)
939c0b746e5SOllivier Robert {
9402b45e011SOllivier Robert 	associd_t associd;
941c0b746e5SOllivier Robert 
942c0b746e5SOllivier Robert 	/* HMS: uval? */
943c0b746e5SOllivier Robert 	if (pcmd->nargs == 0) {
944c0b746e5SOllivier Robert 		associd = 0;
945c0b746e5SOllivier Robert 	} else {
946c0b746e5SOllivier Robert 		if (pcmd->argval[0].uval == 0)
947c0b746e5SOllivier Robert 			associd = 0;
948c0b746e5SOllivier Robert 		else if ((associd = checkassocid(pcmd->argval[0].uval)) == 0)
949c0b746e5SOllivier Robert 			return;
950c0b746e5SOllivier Robert 	}
951c0b746e5SOllivier Robert 
9522b45e011SOllivier Robert 	dolist(g_varlist, associd, CTL_OP_READCLOCK, TYPE_CLOCK, fp);
953c0b746e5SOllivier Robert }
954c0b746e5SOllivier Robert 
955c0b746e5SOllivier Robert 
956c0b746e5SOllivier Robert /*
957c0b746e5SOllivier Robert  * clockvar - send a clock variables request with the specified variables
958c0b746e5SOllivier Robert  */
959c0b746e5SOllivier Robert static void
clockvar(struct parse * pcmd,FILE * fp)960c0b746e5SOllivier Robert clockvar(
961c0b746e5SOllivier Robert 	struct parse *pcmd,
962c0b746e5SOllivier Robert 	FILE *fp
963c0b746e5SOllivier Robert 	)
964c0b746e5SOllivier Robert {
9652b45e011SOllivier Robert 	associd_t associd;
966c0b746e5SOllivier Robert 	struct varlist tmplist[MAXLIST];
967c0b746e5SOllivier Robert 
968c0b746e5SOllivier Robert 	/* HMS: uval? */
969c0b746e5SOllivier Robert 	if (pcmd->nargs == 0 || pcmd->argval[0].uval == 0)
970c0b746e5SOllivier Robert 		associd = 0;
971c0b746e5SOllivier Robert 	else if ((associd = checkassocid(pcmd->argval[0].uval)) == 0)
972c0b746e5SOllivier Robert 		return;
973c0b746e5SOllivier Robert 
974b5e14a13SCy Schubert 	ZERO(tmplist);
975c0b746e5SOllivier Robert 	if (pcmd->nargs >= 2)
976c0b746e5SOllivier Robert 		doaddvlist(tmplist, pcmd->argval[1].string);
977c0b746e5SOllivier Robert 
9782b45e011SOllivier Robert 	dolist(tmplist, associd, CTL_OP_READCLOCK, TYPE_CLOCK, fp);
979c0b746e5SOllivier Robert 
980c0b746e5SOllivier Robert 	doclearvlist(tmplist);
981c0b746e5SOllivier Robert }
982c0b746e5SOllivier Robert 
983c0b746e5SOllivier Robert 
984c0b746e5SOllivier Robert /*
985c0b746e5SOllivier Robert  * findassidrange - verify a range of association ID's
986c0b746e5SOllivier Robert  */
987c0b746e5SOllivier Robert static int
findassidrange(u_int32 assid1,u_int32 assid2,int * from,int * to,FILE * fp)988c0b746e5SOllivier Robert findassidrange(
989c0b746e5SOllivier Robert 	u_int32	assid1,
990c0b746e5SOllivier Robert 	u_int32	assid2,
991c0b746e5SOllivier Robert 	int *	from,
992b5e14a13SCy Schubert 	int *	to,
993b5e14a13SCy Schubert 	FILE *	fp
994c0b746e5SOllivier Robert 	)
995c0b746e5SOllivier Robert {
9962b45e011SOllivier Robert 	associd_t	assids[2];
9972b45e011SOllivier Robert 	int		ind[COUNTOF(assids)];
998b5e14a13SCy Schubert 	u_int		i;
9992b45e011SOllivier Robert 	size_t		a;
1000c0b746e5SOllivier Robert 
1001b5e14a13SCy Schubert 
1002b5e14a13SCy Schubert 	if (0 == numassoc)
1003b5e14a13SCy Schubert 		dogetassoc(fp);
1004b5e14a13SCy Schubert 
10052b45e011SOllivier Robert 	assids[0] = checkassocid(assid1);
10062b45e011SOllivier Robert 	if (0 == assids[0])
10072b45e011SOllivier Robert 		return 0;
10082b45e011SOllivier Robert 	assids[1] = checkassocid(assid2);
10092b45e011SOllivier Robert 	if (0 == assids[1])
10102b45e011SOllivier Robert 		return 0;
10112b45e011SOllivier Robert 
10122b45e011SOllivier Robert 	for (a = 0; a < COUNTOF(assids); a++) {
10132b45e011SOllivier Robert 		ind[a] = -1;
10142b45e011SOllivier Robert 		for (i = 0; i < numassoc; i++)
10152b45e011SOllivier Robert 			if (assoc_cache[i].assid == assids[a])
10162b45e011SOllivier Robert 				ind[a] = i;
10172b45e011SOllivier Robert 	}
10182b45e011SOllivier Robert 	for (a = 0; a < COUNTOF(assids); a++)
10192b45e011SOllivier Robert 		if (-1 == ind[a]) {
10205171bc9bSCy Schubert 			xprintf(stderr,
10212b45e011SOllivier Robert 				"***Association ID %u not found in list\n",
10222b45e011SOllivier Robert 				assids[a]);
1023c0b746e5SOllivier Robert 			return 0;
1024c0b746e5SOllivier Robert 		}
1025c0b746e5SOllivier Robert 
10262b45e011SOllivier Robert 	if (ind[0] < ind[1]) {
10272b45e011SOllivier Robert 		*from = ind[0];
10282b45e011SOllivier Robert 		*to = ind[1];
1029c0b746e5SOllivier Robert 	} else {
10302b45e011SOllivier Robert 		*to = ind[0];
10312b45e011SOllivier Robert 		*from = ind[1];
1032c0b746e5SOllivier Robert 	}
1033c0b746e5SOllivier Robert 	return 1;
1034c0b746e5SOllivier Robert }
1035c0b746e5SOllivier Robert 
1036c0b746e5SOllivier Robert 
1037c0b746e5SOllivier Robert 
1038c0b746e5SOllivier Robert /*
1039c0b746e5SOllivier Robert  * mreadlist - send a read variables request for multiple associations
1040c0b746e5SOllivier Robert  */
1041c0b746e5SOllivier Robert static void
mreadlist(struct parse * pcmd,FILE * fp)1042c0b746e5SOllivier Robert mreadlist(
1043c0b746e5SOllivier Robert 	struct parse *pcmd,
1044c0b746e5SOllivier Robert 	FILE *fp
1045c0b746e5SOllivier Robert 	)
1046c0b746e5SOllivier Robert {
1047c0b746e5SOllivier Robert 	int i;
1048c0b746e5SOllivier Robert 	int from;
1049c0b746e5SOllivier Robert 	int to;
1050c0b746e5SOllivier Robert 
1051c0b746e5SOllivier Robert 	if (!findassidrange(pcmd->argval[0].uval, pcmd->argval[1].uval,
1052b5e14a13SCy Schubert 			    &from, &to, fp))
1053c0b746e5SOllivier Robert 		return;
1054c0b746e5SOllivier Robert 
1055c0b746e5SOllivier Robert 	for (i = from; i <= to; i++) {
1056c0b746e5SOllivier Robert 		if (i != from)
10575171bc9bSCy Schubert 			xprintf(fp, "\n");
1058b5e14a13SCy Schubert 		if (!dolist(g_varlist, assoc_cache[i].assid,
1059c0b746e5SOllivier Robert 			    CTL_OP_READVAR, TYPE_PEER, fp))
1060c0b746e5SOllivier Robert 			return;
1061c0b746e5SOllivier Robert 	}
1062c0b746e5SOllivier Robert 	return;
1063c0b746e5SOllivier Robert }
1064c0b746e5SOllivier Robert 
1065c0b746e5SOllivier Robert 
1066c0b746e5SOllivier Robert /*
1067c0b746e5SOllivier Robert  * mreadvar - send a read variables request for multiple associations
1068c0b746e5SOllivier Robert  */
1069c0b746e5SOllivier Robert static void
mreadvar(struct parse * pcmd,FILE * fp)1070c0b746e5SOllivier Robert mreadvar(
1071c0b746e5SOllivier Robert 	struct parse *pcmd,
1072c0b746e5SOllivier Robert 	FILE *fp
1073c0b746e5SOllivier Robert 	)
1074c0b746e5SOllivier Robert {
1075c0b746e5SOllivier Robert 	int i;
1076c0b746e5SOllivier Robert 	int from;
1077c0b746e5SOllivier Robert 	int to;
1078c0b746e5SOllivier Robert 	struct varlist tmplist[MAXLIST];
10792b45e011SOllivier Robert 	struct varlist *pvars;
1080c0b746e5SOllivier Robert 
1081c0b746e5SOllivier Robert 	if (!findassidrange(pcmd->argval[0].uval, pcmd->argval[1].uval,
1082b5e14a13SCy Schubert 				&from, &to, fp))
1083c0b746e5SOllivier Robert 		return;
1084c0b746e5SOllivier Robert 
1085b5e14a13SCy Schubert 	ZERO(tmplist);
10862b45e011SOllivier Robert 	if (pcmd->nargs >= 3) {
1087c0b746e5SOllivier Robert 		doaddvlist(tmplist, pcmd->argval[2].string);
10882b45e011SOllivier Robert 		pvars = tmplist;
10892b45e011SOllivier Robert 	} else {
10902b45e011SOllivier Robert 		pvars = g_varlist;
10912b45e011SOllivier Robert 	}
1092c0b746e5SOllivier Robert 
1093c0b746e5SOllivier Robert 	for (i = from; i <= to; i++) {
1094b5e14a13SCy Schubert 		if (!dolist(pvars, assoc_cache[i].assid, CTL_OP_READVAR,
1095b5e14a13SCy Schubert 			    TYPE_PEER, fp))
1096c0b746e5SOllivier Robert 			break;
1097c0b746e5SOllivier Robert 	}
1098b5e14a13SCy Schubert 
1099b5e14a13SCy Schubert 	if (pvars == tmplist)
1100c0b746e5SOllivier Robert 		doclearvlist(tmplist);
1101b5e14a13SCy Schubert 
1102c0b746e5SOllivier Robert 	return;
1103c0b746e5SOllivier Robert }
1104c0b746e5SOllivier Robert 
1105c0b746e5SOllivier Robert 
1106c0b746e5SOllivier Robert /*
1107c0b746e5SOllivier Robert  * dogetassoc - query the host for its list of associations
1108c0b746e5SOllivier Robert  */
1109b5e14a13SCy Schubert int
dogetassoc(FILE * fp)1110c0b746e5SOllivier Robert dogetassoc(
1111c0b746e5SOllivier Robert 	FILE *fp
1112c0b746e5SOllivier Robert 	)
1113c0b746e5SOllivier Robert {
11142b45e011SOllivier Robert 	const char *datap;
1115b5e14a13SCy Schubert 	const u_short *pus;
1116c0b746e5SOllivier Robert 	int res;
1117c373d928SXin LI 	size_t dsize;
1118c0b746e5SOllivier Robert 	u_short rstatus;
1119c0b746e5SOllivier Robert 
1120c0b746e5SOllivier Robert 	res = doquery(CTL_OP_READSTAT, 0, 0, 0, (char *)0, &rstatus,
1121ff717da2SOllivier Robert 			  &dsize, &datap);
1122c0b746e5SOllivier Robert 
1123c0b746e5SOllivier Robert 	if (res != 0)
1124c0b746e5SOllivier Robert 		return 0;
1125c0b746e5SOllivier Robert 
1126c0b746e5SOllivier Robert 	if (dsize == 0) {
1127ff717da2SOllivier Robert 		if (numhosts > 1)
11285171bc9bSCy Schubert 			xprintf(fp, "server=%s ", currenthost);
11295171bc9bSCy Schubert 		xprintf(fp, "No association ID's returned\n");
1130c0b746e5SOllivier Robert 		return 0;
1131c0b746e5SOllivier Robert 	}
1132c0b746e5SOllivier Robert 
1133c0b746e5SOllivier Robert 	if (dsize & 0x3) {
1134ff717da2SOllivier Robert 		if (numhosts > 1)
11355171bc9bSCy Schubert 			xprintf(stderr, "server=%s ", currenthost);
11365171bc9bSCy Schubert 		xprintf(stderr,
1137c373d928SXin LI 			"***Server returned %zu octets, should be multiple of 4\n",
1138c0b746e5SOllivier Robert 			dsize);
1139c0b746e5SOllivier Robert 		return 0;
1140c0b746e5SOllivier Robert 	}
1141c0b746e5SOllivier Robert 
1142c0b746e5SOllivier Robert 	numassoc = 0;
1143b5e14a13SCy Schubert 
1144c0b746e5SOllivier Robert 	while (dsize > 0) {
1145b5e14a13SCy Schubert 		if (numassoc >= assoc_cache_slots) {
1146b5e14a13SCy Schubert 			grow_assoc_cache();
1147b5e14a13SCy Schubert 		}
1148b5e14a13SCy Schubert 		pus = (const void *)datap;
1149b5e14a13SCy Schubert 		assoc_cache[numassoc].assid = ntohs(*pus);
1150b5e14a13SCy Schubert 		datap += sizeof(*pus);
1151b5e14a13SCy Schubert 		pus = (const void *)datap;
1152b5e14a13SCy Schubert 		assoc_cache[numassoc].status = ntohs(*pus);
1153b5e14a13SCy Schubert 		datap += sizeof(*pus);
1154b5e14a13SCy Schubert 		dsize -= 2 * sizeof(*pus);
1155b5e14a13SCy Schubert 		if (debug) {
11565171bc9bSCy Schubert 			xprintf(stderr, "[%u] ",
1157b5e14a13SCy Schubert 				assoc_cache[numassoc].assid);
1158b5e14a13SCy Schubert 		}
1159b5e14a13SCy Schubert 		numassoc++;
1160b5e14a13SCy Schubert 	}
1161b5e14a13SCy Schubert 	if (debug) {
11625171bc9bSCy Schubert 		xprintf(stderr, "\n%d associations total\n", numassoc);
1163c0b746e5SOllivier Robert 	}
1164c0b746e5SOllivier Robert 	sortassoc();
1165c0b746e5SOllivier Robert 	return 1;
1166c0b746e5SOllivier Robert }
1167c0b746e5SOllivier Robert 
1168c0b746e5SOllivier Robert 
1169c0b746e5SOllivier Robert /*
1170c0b746e5SOllivier Robert  * printassoc - print the current list of associations
1171c0b746e5SOllivier Robert  */
1172c0b746e5SOllivier Robert static void
printassoc(int showall,FILE * fp)1173c0b746e5SOllivier Robert printassoc(
1174c0b746e5SOllivier Robert 	int showall,
1175c0b746e5SOllivier Robert 	FILE *fp
1176c0b746e5SOllivier Robert 	)
1177c0b746e5SOllivier Robert {
1178c0b746e5SOllivier Robert 	register char *bp;
1179b5e14a13SCy Schubert 	u_int i;
1180c0b746e5SOllivier Robert 	u_char statval;
1181c0b746e5SOllivier Robert 	int event;
1182c0b746e5SOllivier Robert 	u_long event_count;
1183c0b746e5SOllivier Robert 	const char *conf;
1184c0b746e5SOllivier Robert 	const char *reach;
1185c0b746e5SOllivier Robert 	const char *auth;
1186c0b746e5SOllivier Robert 	const char *condition = "";
1187c0b746e5SOllivier Robert 	const char *last_event;
1188c0b746e5SOllivier Robert 	char buf[128];
118926fd3d56SCy Schubert 	char numev[32];
1190c0b746e5SOllivier Robert 
1191c0b746e5SOllivier Robert 	if (numassoc == 0) {
11925171bc9bSCy Schubert 		(void) xprintf(fp, "No association ID's in list\n");
1193c0b746e5SOllivier Robert 		return;
1194c0b746e5SOllivier Robert 	}
1195c0b746e5SOllivier Robert 
1196c0b746e5SOllivier Robert 	/*
1197c0b746e5SOllivier Robert 	 * Output a header
1198c0b746e5SOllivier Robert 	 */
11995171bc9bSCy Schubert 	(void) xprintf(fp,
1200c7f4d233SXin LI 			   "ind assid status  conf reach auth condition  last_event cnt\n");
12015171bc9bSCy Schubert 	(void) xprintf(fp,
1202c0b746e5SOllivier Robert 			   "===========================================================\n");
1203c0b746e5SOllivier Robert 	for (i = 0; i < numassoc; i++) {
12049c2daa00SOllivier Robert 		statval = (u_char) CTL_PEER_STATVAL(assoc_cache[i].status);
1205c0b746e5SOllivier Robert 		if (!showall && !(statval & (CTL_PST_CONFIG|CTL_PST_REACH)))
1206c0b746e5SOllivier Robert 			continue;
1207c0b746e5SOllivier Robert 		event = CTL_PEER_EVENT(assoc_cache[i].status);
1208c0b746e5SOllivier Robert 		event_count = CTL_PEER_NEVNT(assoc_cache[i].status);
1209c0b746e5SOllivier Robert 		if (statval & CTL_PST_CONFIG)
1210c0b746e5SOllivier Robert 			conf = "yes";
1211c0b746e5SOllivier Robert 		else
1212c0b746e5SOllivier Robert 			conf = "no";
12132b45e011SOllivier Robert 		if (statval & CTL_PST_BCAST) {
12142b45e011SOllivier Robert 			reach = "none";
12152b45e011SOllivier Robert 			if (statval & CTL_PST_AUTHENABLE)
12162b45e011SOllivier Robert 				auth = "yes";
12172b45e011SOllivier Robert 			else
12182b45e011SOllivier Robert 				auth = "none";
12192b45e011SOllivier Robert 		} else {
12202b45e011SOllivier Robert 			if (statval & CTL_PST_REACH)
1221c0b746e5SOllivier Robert 				reach = "yes";
12222b45e011SOllivier Robert 			else
12232b45e011SOllivier Robert 				reach = "no";
1224c0b746e5SOllivier Robert 			if (statval & CTL_PST_AUTHENABLE) {
1225c0b746e5SOllivier Robert 				if (statval & CTL_PST_AUTHENTIC)
1226c0b746e5SOllivier Robert 					auth = "ok ";
1227c0b746e5SOllivier Robert 				else
1228c0b746e5SOllivier Robert 					auth = "bad";
12292b45e011SOllivier Robert 			} else {
1230c0b746e5SOllivier Robert 				auth = "none";
12312b45e011SOllivier Robert 			}
12322b45e011SOllivier Robert 		}
12332b45e011SOllivier Robert 		if (pktversion > NTP_OLDVERSION) {
1234c0b746e5SOllivier Robert 			switch (statval & 0x7) {
12352b45e011SOllivier Robert 
1236c0b746e5SOllivier Robert 			case CTL_PST_SEL_REJECT:
1237c0b746e5SOllivier Robert 				condition = "reject";
1238c0b746e5SOllivier Robert 				break;
12392b45e011SOllivier Robert 
1240c0b746e5SOllivier Robert 			case CTL_PST_SEL_SANE:
1241c0b746e5SOllivier Robert 				condition = "falsetick";
1242c0b746e5SOllivier Robert 				break;
12432b45e011SOllivier Robert 
1244c0b746e5SOllivier Robert 			case CTL_PST_SEL_CORRECT:
1245c0b746e5SOllivier Robert 				condition = "excess";
1246c0b746e5SOllivier Robert 				break;
12472b45e011SOllivier Robert 
1248c0b746e5SOllivier Robert 			case CTL_PST_SEL_SELCAND:
12490b0c40a7SGleb Smirnoff 				condition = "outlier";
1250c0b746e5SOllivier Robert 				break;
12512b45e011SOllivier Robert 
1252c0b746e5SOllivier Robert 			case CTL_PST_SEL_SYNCCAND:
12532b45e011SOllivier Robert 				condition = "candidate";
1254c0b746e5SOllivier Robert 				break;
12552b45e011SOllivier Robert 
12562b45e011SOllivier Robert 			case CTL_PST_SEL_EXCESS:
12572b45e011SOllivier Robert 				condition = "backup";
1258c0b746e5SOllivier Robert 				break;
12592b45e011SOllivier Robert 
1260c0b746e5SOllivier Robert 			case CTL_PST_SEL_SYSPEER:
1261c0b746e5SOllivier Robert 				condition = "sys.peer";
1262c0b746e5SOllivier Robert 				break;
12632b45e011SOllivier Robert 
1264c0b746e5SOllivier Robert 			case CTL_PST_SEL_PPS:
1265c0b746e5SOllivier Robert 				condition = "pps.peer";
1266c0b746e5SOllivier Robert 				break;
1267c0b746e5SOllivier Robert 			}
12682b45e011SOllivier Robert 		} else {
1269c0b746e5SOllivier Robert 			switch (statval & 0x3) {
12702b45e011SOllivier Robert 
1271c0b746e5SOllivier Robert 			case OLD_CTL_PST_SEL_REJECT:
1272c0b746e5SOllivier Robert 				if (!(statval & OLD_CTL_PST_SANE))
1273c0b746e5SOllivier Robert 					condition = "insane";
1274c0b746e5SOllivier Robert 				else if (!(statval & OLD_CTL_PST_DISP))
1275c0b746e5SOllivier Robert 					condition = "hi_disp";
1276c0b746e5SOllivier Robert 				else
1277c0b746e5SOllivier Robert 					condition = "";
1278c0b746e5SOllivier Robert 				break;
12792b45e011SOllivier Robert 
1280c0b746e5SOllivier Robert 			case OLD_CTL_PST_SEL_SELCAND:
1281c0b746e5SOllivier Robert 				condition = "sel_cand";
1282c0b746e5SOllivier Robert 				break;
12832b45e011SOllivier Robert 
1284c0b746e5SOllivier Robert 			case OLD_CTL_PST_SEL_SYNCCAND:
1285c0b746e5SOllivier Robert 				condition = "sync_cand";
1286c0b746e5SOllivier Robert 				break;
12872b45e011SOllivier Robert 
1288c0b746e5SOllivier Robert 			case OLD_CTL_PST_SEL_SYSPEER:
1289c0b746e5SOllivier Robert 				condition = "sys_peer";
1290c0b746e5SOllivier Robert 				break;
1291c0b746e5SOllivier Robert 			}
1292c0b746e5SOllivier Robert 		}
1293c0b746e5SOllivier Robert 		switch (PEER_EVENT|event) {
12942b45e011SOllivier Robert 
12952b45e011SOllivier Robert 		case PEVNT_MOBIL:
12962b45e011SOllivier Robert 			last_event = "mobilize";
1297c0b746e5SOllivier Robert 			break;
12982b45e011SOllivier Robert 
12992b45e011SOllivier Robert 		case PEVNT_DEMOBIL:
13002b45e011SOllivier Robert 			last_event = "demobilize";
1301c0b746e5SOllivier Robert 			break;
13022b45e011SOllivier Robert 
13032b45e011SOllivier Robert 		case PEVNT_REACH:
1304c0b746e5SOllivier Robert 			last_event = "reachable";
1305c0b746e5SOllivier Robert 			break;
13062b45e011SOllivier Robert 
13072b45e011SOllivier Robert 		case PEVNT_UNREACH:
13082b45e011SOllivier Robert 			last_event = "unreachable";
1309c0b746e5SOllivier Robert 			break;
13102b45e011SOllivier Robert 
13112b45e011SOllivier Robert 		case PEVNT_RESTART:
13122b45e011SOllivier Robert 			last_event = "restart";
1313c0b746e5SOllivier Robert 			break;
13142b45e011SOllivier Robert 
13152b45e011SOllivier Robert 		case PEVNT_REPLY:
13162b45e011SOllivier Robert 			last_event = "no_reply";
13172b45e011SOllivier Robert 			break;
13182b45e011SOllivier Robert 
13192b45e011SOllivier Robert 		case PEVNT_RATE:
13202b45e011SOllivier Robert 			last_event = "rate_exceeded";
13212b45e011SOllivier Robert 			break;
13222b45e011SOllivier Robert 
13232b45e011SOllivier Robert 		case PEVNT_DENY:
13242b45e011SOllivier Robert 			last_event = "access_denied";
13252b45e011SOllivier Robert 			break;
13262b45e011SOllivier Robert 
13272b45e011SOllivier Robert 		case PEVNT_ARMED:
13282b45e011SOllivier Robert 			last_event = "leap_armed";
13292b45e011SOllivier Robert 			break;
13302b45e011SOllivier Robert 
13312b45e011SOllivier Robert 		case PEVNT_NEWPEER:
13322b45e011SOllivier Robert 			last_event = "sys_peer";
13332b45e011SOllivier Robert 			break;
13342b45e011SOllivier Robert 
13352b45e011SOllivier Robert 		case PEVNT_CLOCK:
13362b45e011SOllivier Robert 			last_event = "clock_alarm";
13372b45e011SOllivier Robert 			break;
13382b45e011SOllivier Robert 
133926fd3d56SCy Schubert 		case PEVNT_AUTH:
134026fd3d56SCy Schubert 			last_event = "bad_auth";
134126fd3d56SCy Schubert 			break;
134226fd3d56SCy Schubert 
134326fd3d56SCy Schubert 		case PEVNT_POPCORN:
134426fd3d56SCy Schubert 			last_event = "popcorn";
134526fd3d56SCy Schubert 			break;
134626fd3d56SCy Schubert 
134726fd3d56SCy Schubert 		case PEVNT_XLEAVE:
134826fd3d56SCy Schubert 			last_event = "interleave";
134926fd3d56SCy Schubert 			break;
135026fd3d56SCy Schubert 
135126fd3d56SCy Schubert 		case PEVNT_XERR:
135226fd3d56SCy Schubert 			last_event = "xleave_err";
135326fd3d56SCy Schubert 			break;
135426fd3d56SCy Schubert 
1355c0b746e5SOllivier Robert 		default:
135626fd3d56SCy Schubert 			snprintf(numev, sizeof(numev), "<?%x?>", event);
135726fd3d56SCy Schubert 			last_event = numev;
1358c0b746e5SOllivier Robert 			break;
1359c0b746e5SOllivier Robert 		}
13602b45e011SOllivier Robert 		snprintf(buf, sizeof(buf),
1361b5e14a13SCy Schubert 			 "%3d %5u  %04x   %3.3s  %4s  %4.4s %9.9s %11s %2lu",
13622b45e011SOllivier Robert 			 i + 1, assoc_cache[i].assid,
13632b45e011SOllivier Robert 			 assoc_cache[i].status, conf, reach, auth,
1364b5e14a13SCy Schubert 			 condition, last_event, event_count);
13652b45e011SOllivier Robert 		bp = buf + strlen(buf);
13662b45e011SOllivier Robert 		while (bp > buf && ' ' == bp[-1])
13672b45e011SOllivier Robert 			--bp;
13682b45e011SOllivier Robert 		bp[0] = '\0';
13695171bc9bSCy Schubert 		xprintf(fp, "%s\n", buf);
1370c0b746e5SOllivier Robert 	}
1371c0b746e5SOllivier Robert }
1372c0b746e5SOllivier Robert 
1373c0b746e5SOllivier Robert 
1374c0b746e5SOllivier Robert /*
1375c0b746e5SOllivier Robert  * associations - get, record and print a list of associations
1376c0b746e5SOllivier Robert  */
1377c0b746e5SOllivier Robert /*ARGSUSED*/
1378c0b746e5SOllivier Robert static void
associations(struct parse * pcmd,FILE * fp)1379c0b746e5SOllivier Robert associations(
1380c0b746e5SOllivier Robert 	struct parse *pcmd,
1381c0b746e5SOllivier Robert 	FILE *fp
1382c0b746e5SOllivier Robert 	)
1383c0b746e5SOllivier Robert {
1384c0b746e5SOllivier Robert 	if (dogetassoc(fp))
1385c0b746e5SOllivier Robert 		printassoc(0, fp);
1386c0b746e5SOllivier Robert }
1387c0b746e5SOllivier Robert 
1388c0b746e5SOllivier Robert 
1389c0b746e5SOllivier Robert /*
1390c0b746e5SOllivier Robert  * lassociations - get, record and print a long list of associations
1391c0b746e5SOllivier Robert  */
1392c0b746e5SOllivier Robert /*ARGSUSED*/
1393c0b746e5SOllivier Robert static void
lassociations(struct parse * pcmd,FILE * fp)1394c0b746e5SOllivier Robert lassociations(
1395c0b746e5SOllivier Robert 	struct parse *pcmd,
1396c0b746e5SOllivier Robert 	FILE *fp
1397c0b746e5SOllivier Robert 	)
1398c0b746e5SOllivier Robert {
1399c0b746e5SOllivier Robert 	if (dogetassoc(fp))
1400c0b746e5SOllivier Robert 		printassoc(1, fp);
1401c0b746e5SOllivier Robert }
1402c0b746e5SOllivier Robert 
1403c0b746e5SOllivier Robert 
1404c0b746e5SOllivier Robert /*
1405c0b746e5SOllivier Robert  * passociations - print the association list
1406c0b746e5SOllivier Robert  */
1407c0b746e5SOllivier Robert /*ARGSUSED*/
1408c0b746e5SOllivier Robert static void
passociations(struct parse * pcmd,FILE * fp)1409c0b746e5SOllivier Robert passociations(
1410c0b746e5SOllivier Robert 	struct parse *pcmd,
1411c0b746e5SOllivier Robert 	FILE *fp
1412c0b746e5SOllivier Robert 	)
1413c0b746e5SOllivier Robert {
1414c0b746e5SOllivier Robert 	printassoc(0, fp);
1415c0b746e5SOllivier Robert }
1416c0b746e5SOllivier Robert 
1417c0b746e5SOllivier Robert 
1418c0b746e5SOllivier Robert /*
1419c0b746e5SOllivier Robert  * lpassociations - print the long association list
1420c0b746e5SOllivier Robert  */
1421c0b746e5SOllivier Robert /*ARGSUSED*/
1422c0b746e5SOllivier Robert static void
lpassociations(struct parse * pcmd,FILE * fp)1423c0b746e5SOllivier Robert lpassociations(
1424c0b746e5SOllivier Robert 	struct parse *pcmd,
1425c0b746e5SOllivier Robert 	FILE *fp
1426c0b746e5SOllivier Robert 	)
1427c0b746e5SOllivier Robert {
1428c0b746e5SOllivier Robert 	printassoc(1, fp);
1429c0b746e5SOllivier Robert }
1430c0b746e5SOllivier Robert 
1431c0b746e5SOllivier Robert 
14322b45e011SOllivier Robert /*
14332b45e011SOllivier Robert  *  saveconfig - dump ntp server configuration to server file
14342b45e011SOllivier Robert  */
14352b45e011SOllivier Robert static void
saveconfig(struct parse * pcmd,FILE * fp)14362b45e011SOllivier Robert saveconfig(
14372b45e011SOllivier Robert 	struct parse *pcmd,
14382b45e011SOllivier Robert 	FILE *fp
14392b45e011SOllivier Robert 	)
14402b45e011SOllivier Robert {
14412b45e011SOllivier Robert 	const char *datap;
14422b45e011SOllivier Robert 	int res;
1443c373d928SXin LI 	size_t dsize;
14442b45e011SOllivier Robert 	u_short rstatus;
14452b45e011SOllivier Robert 
14462b45e011SOllivier Robert 	if (0 == pcmd->nargs)
14472b45e011SOllivier Robert 		return;
14482b45e011SOllivier Robert 
14492b45e011SOllivier Robert 	res = doquery(CTL_OP_SAVECONFIG, 0, 1,
14502b45e011SOllivier Robert 		      strlen(pcmd->argval[0].string),
14512b45e011SOllivier Robert 		      pcmd->argval[0].string, &rstatus, &dsize,
14522b45e011SOllivier Robert 		      &datap);
14532b45e011SOllivier Robert 
14542b45e011SOllivier Robert 	if (res != 0)
14552b45e011SOllivier Robert 		return;
14562b45e011SOllivier Robert 
14572b45e011SOllivier Robert 	if (0 == dsize)
14585171bc9bSCy Schubert 		xprintf(fp, "(no response message, curiously)");
14592b45e011SOllivier Robert 	else
14605171bc9bSCy Schubert 		xprintf(fp, "%.*s", (int)dsize, datap); /* cast is wobbly */
14612b45e011SOllivier Robert }
14622b45e011SOllivier Robert 
14632b45e011SOllivier Robert 
1464c0b746e5SOllivier Robert #ifdef	UNUSED
1465c0b746e5SOllivier Robert /*
1466c0b746e5SOllivier Robert  * radiostatus - print the radio status returned by the server
1467c0b746e5SOllivier Robert  */
1468c0b746e5SOllivier Robert /*ARGSUSED*/
1469c0b746e5SOllivier Robert static void
radiostatus(struct parse * pcmd,FILE * fp)1470c0b746e5SOllivier Robert radiostatus(
1471c0b746e5SOllivier Robert 	struct parse *pcmd,
1472c0b746e5SOllivier Robert 	FILE *fp
1473c0b746e5SOllivier Robert 	)
1474c0b746e5SOllivier Robert {
1475c0b746e5SOllivier Robert 	char *datap;
1476c0b746e5SOllivier Robert 	int res;
1477c0b746e5SOllivier Robert 	int dsize;
1478c0b746e5SOllivier Robert 	u_short rstatus;
1479c0b746e5SOllivier Robert 
1480c0b746e5SOllivier Robert 	res = doquery(CTL_OP_READCLOCK, 0, 0, 0, (char *)0, &rstatus,
1481c0b746e5SOllivier Robert 			  &dsize, &datap);
1482c0b746e5SOllivier Robert 
1483c0b746e5SOllivier Robert 	if (res != 0)
1484c0b746e5SOllivier Robert 		return;
1485c0b746e5SOllivier Robert 
1486ff717da2SOllivier Robert 	if (numhosts > 1)
14875171bc9bSCy Schubert 		(void) xprintf(fp, "server=%s ", currenthost);
1488c0b746e5SOllivier Robert 	if (dsize == 0) {
14895171bc9bSCy Schubert 		(void) xprintf(fp, "No radio status string returned\n");
1490c0b746e5SOllivier Robert 		return;
1491c0b746e5SOllivier Robert 	}
1492c0b746e5SOllivier Robert 
1493c0b746e5SOllivier Robert 	asciize(dsize, datap, fp);
1494c0b746e5SOllivier Robert }
1495c0b746e5SOllivier Robert #endif	/* UNUSED */
1496c0b746e5SOllivier Robert 
1497c0b746e5SOllivier Robert /*
14981f833b3fSCy Schubert  * when - return how long its been since his last packet arrived
1499c0b746e5SOllivier Robert  */
1500c0b746e5SOllivier Robert static long
when(l_fp * ts,l_fp * rec,l_fp * reftime)1501c0b746e5SOllivier Robert when(
1502c0b746e5SOllivier Robert 	l_fp *ts,
1503c0b746e5SOllivier Robert 	l_fp *rec,
1504c0b746e5SOllivier Robert 	l_fp *reftime
1505c0b746e5SOllivier Robert 	)
1506c0b746e5SOllivier Robert {
1507c0b746e5SOllivier Robert 	l_fp *lasttime;
1508c0b746e5SOllivier Robert 
1509c0b746e5SOllivier Robert 	if (rec->l_ui != 0)
1510c0b746e5SOllivier Robert 		lasttime = rec;
1511c0b746e5SOllivier Robert 	else if (reftime->l_ui != 0)
1512c0b746e5SOllivier Robert 		lasttime = reftime;
1513c0b746e5SOllivier Robert 	else
1514c0b746e5SOllivier Robert 		return 0;
1515c0b746e5SOllivier Robert 
1516d14ac12fSXin LI 	if (ts->l_ui < lasttime->l_ui)
1517d14ac12fSXin LI 		return -1;
1518c0b746e5SOllivier Robert 	return (ts->l_ui - lasttime->l_ui);
1519c0b746e5SOllivier Robert }
1520c0b746e5SOllivier Robert 
1521c0b746e5SOllivier Robert 
1522c0b746e5SOllivier Robert /*
1523c0b746e5SOllivier Robert  * Pretty-print an interval into the given buffer, in a human-friendly format.
1524c0b746e5SOllivier Robert  */
1525c0b746e5SOllivier Robert static char *
prettyinterval(char * buf,size_t cb,long diff)1526c0b746e5SOllivier Robert prettyinterval(
1527c0b746e5SOllivier Robert 	char *buf,
15282b45e011SOllivier Robert 	size_t cb,
1529c0b746e5SOllivier Robert 	long diff
1530c0b746e5SOllivier Robert 	)
1531c0b746e5SOllivier Robert {
1532c0b746e5SOllivier Robert 	if (diff <= 0) {
1533c0b746e5SOllivier Robert 		buf[0] = '-';
1534c0b746e5SOllivier Robert 		buf[1] = 0;
1535c0b746e5SOllivier Robert 		return buf;
1536c0b746e5SOllivier Robert 	}
1537c0b746e5SOllivier Robert 
1538c0b746e5SOllivier Robert 	if (diff <= 2048) {
1539c7f4d233SXin LI 		snprintf(buf, cb, "%u", (unsigned int)diff);
1540c0b746e5SOllivier Robert 		return buf;
1541c0b746e5SOllivier Robert 	}
1542c0b746e5SOllivier Robert 
1543c0b746e5SOllivier Robert 	diff = (diff + 29) / 60;
1544c0b746e5SOllivier Robert 	if (diff <= 300) {
1545c7f4d233SXin LI 		snprintf(buf, cb, "%um", (unsigned int)diff);
1546c0b746e5SOllivier Robert 		return buf;
1547c0b746e5SOllivier Robert 	}
1548c0b746e5SOllivier Robert 
1549c0b746e5SOllivier Robert 	diff = (diff + 29) / 60;
1550c0b746e5SOllivier Robert 	if (diff <= 96) {
1551c7f4d233SXin LI 		snprintf(buf, cb, "%uh", (unsigned int)diff);
1552c0b746e5SOllivier Robert 		return buf;
1553c0b746e5SOllivier Robert 	}
1554c0b746e5SOllivier Robert 
1555c0b746e5SOllivier Robert 	diff = (diff + 11) / 24;
1556d14ac12fSXin LI 	if (diff <= 999) {
1557c7f4d233SXin LI 		snprintf(buf, cb, "%ud", (unsigned int)diff);
1558c0b746e5SOllivier Robert 		return buf;
1559c0b746e5SOllivier Robert 	}
1560c0b746e5SOllivier Robert 
1561d14ac12fSXin LI 	/* years are only approximated... */
1562d14ac12fSXin LI 	diff = (long)floor(diff / 365.25 + 0.5);
1563c7f4d233SXin LI 	if (diff <= 999) {
1564c7f4d233SXin LI 		snprintf(buf, cb, "%uy", (unsigned int)diff);
1565c7f4d233SXin LI 		return buf;
1566c7f4d233SXin LI 	}
1567c7f4d233SXin LI 	/* Ok, this amounts to infinity... */
1568c7f4d233SXin LI 	strlcpy(buf, "INF", cb);
1569d14ac12fSXin LI 	return buf;
1570d14ac12fSXin LI }
1571d14ac12fSXin LI 
15729c2daa00SOllivier Robert static char
decodeaddrtype(sockaddr_u * sock)15739c2daa00SOllivier Robert decodeaddrtype(
15742b45e011SOllivier Robert 	sockaddr_u *sock
15759c2daa00SOllivier Robert 	)
15769c2daa00SOllivier Robert {
15779c2daa00SOllivier Robert 	char ch = '-';
15789c2daa00SOllivier Robert 	u_int32 dummy;
15799c2daa00SOllivier Robert 
15802b45e011SOllivier Robert 	switch(AF(sock)) {
15819c2daa00SOllivier Robert 	case AF_INET:
15822b45e011SOllivier Robert 		dummy = SRCADR(sock);
15839c2daa00SOllivier Robert 		ch = (char)(((dummy&0xf0000000)==0xe0000000) ? 'm' :
15849c2daa00SOllivier Robert 			((dummy&0x000000ff)==0x000000ff) ? 'b' :
15859c2daa00SOllivier Robert 			((dummy&0xffffffff)==0x7f000001) ? 'l' :
15869c2daa00SOllivier Robert 			((dummy&0xffffffe0)==0x00000000) ? '-' :
15879c2daa00SOllivier Robert 			'u');
15889c2daa00SOllivier Robert 		break;
15899c2daa00SOllivier Robert 	case AF_INET6:
15902b45e011SOllivier Robert 		if (IN6_IS_ADDR_MULTICAST(PSOCK_ADDR6(sock)))
15919c2daa00SOllivier Robert 			ch = 'm';
15929c2daa00SOllivier Robert 		else
15939c2daa00SOllivier Robert 			ch = 'u';
15949c2daa00SOllivier Robert 		break;
15959c2daa00SOllivier Robert 	default:
15969c2daa00SOllivier Robert 		ch = '-';
15979c2daa00SOllivier Robert 		break;
15989c2daa00SOllivier Robert 	}
15999c2daa00SOllivier Robert 	return ch;
16009c2daa00SOllivier Robert }
1601c0b746e5SOllivier Robert 
1602c0b746e5SOllivier Robert /*
1603c0b746e5SOllivier Robert  * A list of variables required by the peers command
1604c0b746e5SOllivier Robert  */
1605c0b746e5SOllivier Robert struct varlist opeervarlist[] = {
1606c0b746e5SOllivier Robert 	{ "srcadr",	0 },	/* 0 */
1607c0b746e5SOllivier Robert 	{ "dstadr",	0 },	/* 1 */
1608c0b746e5SOllivier Robert 	{ "stratum",	0 },	/* 2 */
1609c0b746e5SOllivier Robert 	{ "hpoll",	0 },	/* 3 */
1610c0b746e5SOllivier Robert 	{ "ppoll",	0 },	/* 4 */
1611c0b746e5SOllivier Robert 	{ "reach",	0 },	/* 5 */
1612c0b746e5SOllivier Robert 	{ "delay",	0 },	/* 6 */
1613c0b746e5SOllivier Robert 	{ "offset",	0 },	/* 7 */
1614c0b746e5SOllivier Robert 	{ "jitter",	0 },	/* 8 */
1615c0b746e5SOllivier Robert 	{ "dispersion", 0 },	/* 9 */
1616c0b746e5SOllivier Robert 	{ "rec",	0 },	/* 10 */
1617c0b746e5SOllivier Robert 	{ "reftime",	0 },	/* 11 */
1618c0b746e5SOllivier Robert 	{ "srcport",	0 },	/* 12 */
1619b5e14a13SCy Schubert 	{ "hmode",	0 },	/* 13 */
1620c0b746e5SOllivier Robert 	{ 0,		0 }
1621c0b746e5SOllivier Robert };
1622c0b746e5SOllivier Robert 
1623c0b746e5SOllivier Robert struct varlist peervarlist[] = {
1624c0b746e5SOllivier Robert 	{ "srcadr",	0 },	/* 0 */
1625c0b746e5SOllivier Robert 	{ "refid",	0 },	/* 1 */
1626c0b746e5SOllivier Robert 	{ "stratum",	0 },	/* 2 */
1627c0b746e5SOllivier Robert 	{ "hpoll",	0 },	/* 3 */
1628c0b746e5SOllivier Robert 	{ "ppoll",	0 },	/* 4 */
1629c0b746e5SOllivier Robert 	{ "reach",	0 },	/* 5 */
1630c0b746e5SOllivier Robert 	{ "delay",	0 },	/* 6 */
1631c0b746e5SOllivier Robert 	{ "offset",	0 },	/* 7 */
1632c0b746e5SOllivier Robert 	{ "jitter",	0 },	/* 8 */
1633c0b746e5SOllivier Robert 	{ "dispersion", 0 },	/* 9 */
1634c0b746e5SOllivier Robert 	{ "rec",	0 },	/* 10 */
1635c0b746e5SOllivier Robert 	{ "reftime",	0 },	/* 11 */
1636c0b746e5SOllivier Robert 	{ "srcport",	0 },	/* 12 */
1637b5e14a13SCy Schubert 	{ "hmode",	0 },	/* 13 */
1638b5e14a13SCy Schubert 	{ "srchost",	0 },	/* 14 */
1639c0b746e5SOllivier Robert 	{ 0,		0 }
1640c0b746e5SOllivier Robert };
1641c0b746e5SOllivier Robert 
1642873997f3SCy Schubert struct varlist apeervarlist[] = {
1643873997f3SCy Schubert 	{ "srcadr",	0 },	/* 0 */
1644873997f3SCy Schubert 	{ "refid",	0 },	/* 1 */
1645873997f3SCy Schubert 	{ "assid",	0 },	/* 2 */
1646873997f3SCy Schubert 	{ "stratum",	0 },	/* 3 */
1647873997f3SCy Schubert 	{ "hpoll",	0 },	/* 4 */
1648873997f3SCy Schubert 	{ "ppoll",	0 },	/* 5 */
1649873997f3SCy Schubert 	{ "reach",	0 },	/* 6 */
1650873997f3SCy Schubert 	{ "delay",	0 },	/* 7 */
1651873997f3SCy Schubert 	{ "offset",	0 },	/* 8 */
1652873997f3SCy Schubert 	{ "jitter",	0 },	/* 9 */
1653873997f3SCy Schubert 	{ "dispersion", 0 },	/* 10 */
1654873997f3SCy Schubert 	{ "rec",	0 },	/* 11 */
1655873997f3SCy Schubert 	{ "reftime",	0 },	/* 12 */
1656873997f3SCy Schubert 	{ "srcport",	0 },	/* 13 */
1657873997f3SCy Schubert 	{ "hmode",	0 },	/* 14 */
1658873997f3SCy Schubert 	{ "srchost",	0 },	/* 15 */
1659873997f3SCy Schubert 	{ 0,		0 }
1660873997f3SCy Schubert };
1661873997f3SCy Schubert 
1662c0b746e5SOllivier Robert 
1663c0b746e5SOllivier Robert /*
1664c0b746e5SOllivier Robert  * Decode an incoming data buffer and print a line in the peer list
1665c0b746e5SOllivier Robert  */
1666c0b746e5SOllivier Robert static int
doprintpeers(struct varlist * pvl,int associd,int rstatus,size_t datalen,const char * data,FILE * fp,int af)1667c0b746e5SOllivier Robert doprintpeers(
1668c0b746e5SOllivier Robert 	struct varlist *pvl,
1669c0b746e5SOllivier Robert 	int associd,
1670c0b746e5SOllivier Robert 	int rstatus,
1671c373d928SXin LI 	size_t datalen,
16722b45e011SOllivier Robert 	const char *data,
16739c2daa00SOllivier Robert 	FILE *fp,
16749c2daa00SOllivier Robert 	int af
1675c0b746e5SOllivier Robert 	)
1676c0b746e5SOllivier Robert {
1677c0b746e5SOllivier Robert 	char *name;
16789c2daa00SOllivier Robert 	char *value = NULL;
1679c0b746e5SOllivier Robert 	int c;
1680c373d928SXin LI 	size_t len;
1681b5e14a13SCy Schubert 	int have_srchost;
1682b5e14a13SCy Schubert 	int have_dstadr;
1683b5e14a13SCy Schubert 	int have_da_rid;
1684b5e14a13SCy Schubert 	int have_jitter;
16852b45e011SOllivier Robert 	sockaddr_u srcadr;
16862b45e011SOllivier Robert 	sockaddr_u dstadr;
1687b5e14a13SCy Schubert 	sockaddr_u dum_store;
16882b45e011SOllivier Robert 	sockaddr_u refidadr;
1689b5e14a13SCy Schubert 	long hmode = 0;
16909c2daa00SOllivier Robert 	u_long srcport = 0;
1691b5e14a13SCy Schubert 	u_int32 u32;
1692b5e14a13SCy Schubert 	const char *dstadr_refid = "0.0.0.0";
1693b5e14a13SCy Schubert 	const char *serverlocal;
16941f833b3fSCy Schubert 	char *drbuf = NULL;
16952b45e011SOllivier Robert 	size_t drlen;
16969c2daa00SOllivier Robert 	u_long stratum = 0;
16979c2daa00SOllivier Robert 	long ppoll = 0;
16989c2daa00SOllivier Robert 	long hpoll = 0;
16999c2daa00SOllivier Robert 	u_long reach = 0;
1700c0b746e5SOllivier Robert 	l_fp estoffset;
1701c0b746e5SOllivier Robert 	l_fp estdelay;
1702c0b746e5SOllivier Robert 	l_fp estjitter;
1703c0b746e5SOllivier Robert 	l_fp estdisp;
1704c0b746e5SOllivier Robert 	l_fp reftime;
1705c0b746e5SOllivier Robert 	l_fp rec;
1706c0b746e5SOllivier Robert 	l_fp ts;
1707a151a66cSOllivier Robert 	u_long poll_sec;
1708c7f4d233SXin LI 	u_long flash = 0;
1709c0b746e5SOllivier Robert 	char type = '?';
17109c2daa00SOllivier Robert 	char clock_name[LENHOSTNAME];
1711c7f4d233SXin LI 	char whenbuf[12], pollbuf[12];
1712c7f4d233SXin LI 	/* [Bug 3482] formally whenbuf & pollbuf should be able to hold
1713c7f4d233SXin LI 	 * a full signed int. Not that we would use that much string
1714c7f4d233SXin LI 	 * data for it...
1715c7f4d233SXin LI 	 */
1716c0b746e5SOllivier Robert 	get_systime(&ts);
1717c0b746e5SOllivier Robert 
1718b5e14a13SCy Schubert 	have_srchost = FALSE;
1719b5e14a13SCy Schubert 	have_dstadr = FALSE;
1720b5e14a13SCy Schubert 	have_da_rid = FALSE;
1721b5e14a13SCy Schubert 	have_jitter = FALSE;
17222b45e011SOllivier Robert 	ZERO_SOCK(&srcadr);
17232b45e011SOllivier Robert 	ZERO_SOCK(&dstadr);
1724b5e14a13SCy Schubert 	clock_name[0] = '\0';
1725b5e14a13SCy Schubert 	ZERO(estoffset);
1726b5e14a13SCy Schubert 	ZERO(estdelay);
1727b5e14a13SCy Schubert 	ZERO(estjitter);
1728b5e14a13SCy Schubert 	ZERO(estdisp);
17299c2daa00SOllivier Robert 
1730c0b746e5SOllivier Robert 	while (nextvar(&datalen, &data, &name, &value)) {
1731c7f4d233SXin LI 		INSIST(name && value);
1732b5e14a13SCy Schubert 		if (!strcmp("srcadr", name) ||
1733b5e14a13SCy Schubert 		    !strcmp("peeradr", name)) {
1734b5e14a13SCy Schubert 			if (!decodenetnum(value, &srcadr))
17355171bc9bSCy Schubert 				xprintf(stderr, "malformed %s=%s\n",
1736b5e14a13SCy Schubert 					name, value);
1737b5e14a13SCy Schubert 		} else if (!strcmp("srchost", name)) {
1738873997f3SCy Schubert 			if (pvl == peervarlist || pvl == apeervarlist) {
1739b5e14a13SCy Schubert 				len = strlen(value);
1740b5e14a13SCy Schubert 				if (2 < len &&
1741b5e14a13SCy Schubert 				    (size_t)len < sizeof(clock_name)) {
1742b5e14a13SCy Schubert 					/* strip quotes */
1743b5e14a13SCy Schubert 					value++;
1744b5e14a13SCy Schubert 					len -= 2;
1745b5e14a13SCy Schubert 					memcpy(clock_name, value, len);
1746b5e14a13SCy Schubert 					clock_name[len] = '\0';
1747b5e14a13SCy Schubert 					have_srchost = TRUE;
17482b45e011SOllivier Robert 				}
1749b5e14a13SCy Schubert 			}
1750b5e14a13SCy Schubert 		} else if (!strcmp("dstadr", name)) {
17512b45e011SOllivier Robert 			if (decodenetnum(value, &dum_store)) {
17529c2daa00SOllivier Robert 				type = decodeaddrtype(&dum_store);
1753b5e14a13SCy Schubert 				have_dstadr = TRUE;
17542b45e011SOllivier Robert 				dstadr = dum_store;
17552b45e011SOllivier Robert 				if (pvl == opeervarlist) {
1756b5e14a13SCy Schubert 					have_da_rid = TRUE;
17572b45e011SOllivier Robert 					dstadr_refid = trunc_left(stoa(&dstadr), 15);
1758c0b746e5SOllivier Robert 				}
1759c0b746e5SOllivier Robert 			}
1760b5e14a13SCy Schubert 		} else if (!strcmp("hmode", name)) {
1761b5e14a13SCy Schubert 			decodeint(value, &hmode);
1762b5e14a13SCy Schubert 		} else if (!strcmp("refid", name)) {
1763c1950318SXin LI 			if (   (pvl == peervarlist)
1764c1950318SXin LI 			    && (drefid == REFID_IPV4)) {
1765b5e14a13SCy Schubert 				have_da_rid = TRUE;
1766b5e14a13SCy Schubert 				drlen = strlen(value);
1767b5e14a13SCy Schubert 				if (0 == drlen) {
17682b45e011SOllivier Robert 					dstadr_refid = "";
1769b5e14a13SCy Schubert 				} else if (drlen <= 4) {
1770b5e14a13SCy Schubert 					ZERO(u32);
1771b5e14a13SCy Schubert 					memcpy(&u32, value, drlen);
1772b5e14a13SCy Schubert 					dstadr_refid = refid_str(u32, 1);
17732b45e011SOllivier Robert 				} else if (decodenetnum(value, &refidadr)) {
17742b45e011SOllivier Robert 					if (SOCK_UNSPEC(&refidadr))
1775c0b746e5SOllivier Robert 						dstadr_refid = "0.0.0.0";
17761f833b3fSCy Schubert 					else if (ISREFCLOCKADR(&refidadr)) {
17779c2daa00SOllivier Robert 						dstadr_refid =
17782b45e011SOllivier Robert 						    refnumtoa(&refidadr);
17791f833b3fSCy Schubert 					} else {
17809c2daa00SOllivier Robert 						dstadr_refid =
17812b45e011SOllivier Robert 						    stoa(&refidadr);
17821f833b3fSCy Schubert 					}
1783c0b746e5SOllivier Robert 				} else {
1784b5e14a13SCy Schubert 					have_da_rid = FALSE;
1785c0b746e5SOllivier Robert 				}
1786c1950318SXin LI 			} else if (   (pvl == apeervarlist)
1787c1950318SXin LI 				   || (pvl == peervarlist)) {
1788c1950318SXin LI 				/* no need to check drefid == REFID_HASH */
1789873997f3SCy Schubert 				have_da_rid = TRUE;
1790873997f3SCy Schubert 				drlen = strlen(value);
1791873997f3SCy Schubert 				if (0 == drlen) {
1792873997f3SCy Schubert 					dstadr_refid = "";
1793873997f3SCy Schubert 				} else if (drlen <= 4) {
1794873997f3SCy Schubert 					ZERO(u32);
1795873997f3SCy Schubert 					memcpy(&u32, value, drlen);
1796873997f3SCy Schubert 					dstadr_refid = refid_str(u32, 1);
17975171bc9bSCy Schubert 					//xprintf(stderr, "apeervarlist S1 refid: value=<%s>\n", value);
1798873997f3SCy Schubert 				} else if (decodenetnum(value, &refidadr)) {
1799873997f3SCy Schubert 					if (SOCK_UNSPEC(&refidadr))
1800873997f3SCy Schubert 						dstadr_refid = "0.0.0.0";
18011f833b3fSCy Schubert 					else if (ISREFCLOCKADR(&refidadr)) {
1802873997f3SCy Schubert 						dstadr_refid =
1803873997f3SCy Schubert 							refnumtoa(&refidadr);
18041f833b3fSCy Schubert 						if (pvl == apeervarlist) {
18051f833b3fSCy Schubert 							/*
18061f833b3fSCy Schubert 							 * restrict refid to
18071f833b3fSCy Schubert 							 * 8 chars [Bug 3850]
18081f833b3fSCy Schubert 							 */
18091f833b3fSCy Schubert 							dstadr_refid =
18101f833b3fSCy Schubert 								trunc_right(
18111f833b3fSCy Schubert 									dstadr_refid,
18121f833b3fSCy Schubert 									8);
1813873997f3SCy Schubert 						}
18141f833b3fSCy Schubert 					} else {
18151f833b3fSCy Schubert 						drbuf = emalloc(10);
18161f833b3fSCy Schubert 						snprintf(drbuf, 10, "%0x",
18171f833b3fSCy Schubert 							 SRCADR(&refidadr));
18181f833b3fSCy Schubert 						dstadr_refid = drbuf;
18191f833b3fSCy Schubert 					}
1820873997f3SCy Schubert 				} else {
1821873997f3SCy Schubert 					have_da_rid = FALSE;
1822873997f3SCy Schubert 				}
1823c0b746e5SOllivier Robert 			}
1824b5e14a13SCy Schubert 		} else if (!strcmp("stratum", name)) {
1825b5e14a13SCy Schubert 			decodeuint(value, &stratum);
1826b5e14a13SCy Schubert 		} else if (!strcmp("hpoll", name)) {
1827b5e14a13SCy Schubert 			if (decodeint(value, &hpoll) && hpoll < 0)
1828c0b746e5SOllivier Robert 				hpoll = NTP_MINPOLL;
1829b5e14a13SCy Schubert 		} else if (!strcmp("ppoll", name)) {
1830b5e14a13SCy Schubert 			if (decodeint(value, &ppoll) && ppoll < 0)
1831c0b746e5SOllivier Robert 				ppoll = NTP_MINPOLL;
1832b5e14a13SCy Schubert 		} else if (!strcmp("reach", name)) {
1833b5e14a13SCy Schubert 			decodeuint(value, &reach);
1834b5e14a13SCy Schubert 		} else if (!strcmp("delay", name)) {
1835b5e14a13SCy Schubert 			decodetime(value, &estdelay);
1836b5e14a13SCy Schubert 		} else if (!strcmp("offset", name)) {
1837b5e14a13SCy Schubert 			decodetime(value, &estoffset);
1838b5e14a13SCy Schubert 		} else if (!strcmp("jitter", name)) {
1839873997f3SCy Schubert 			if ((pvl == peervarlist || pvl == apeervarlist)
1840873997f3SCy Schubert 			    && decodetime(value, &estjitter))
1841b5e14a13SCy Schubert 				have_jitter = 1;
1842b5e14a13SCy Schubert 		} else if (!strcmp("rootdisp", name) ||
1843b5e14a13SCy Schubert 			   !strcmp("dispersion", name)) {
1844b5e14a13SCy Schubert 			decodetime(value, &estdisp);
1845b5e14a13SCy Schubert 		} else if (!strcmp("rec", name)) {
1846b5e14a13SCy Schubert 			decodets(value, &rec);
1847b5e14a13SCy Schubert 		} else if (!strcmp("srcport", name) ||
1848b5e14a13SCy Schubert 			   !strcmp("peerport", name)) {
1849b5e14a13SCy Schubert 			decodeuint(value, &srcport);
1850b5e14a13SCy Schubert 		} else if (!strcmp("reftime", name)) {
1851c0b746e5SOllivier Robert 			if (!decodets(value, &reftime))
1852c0b746e5SOllivier Robert 				L_CLR(&reftime);
1853c7f4d233SXin LI 		} else if (!strcmp("flash", name)) {
1854c7f4d233SXin LI 			decodeuint(value, &flash);
1855873997f3SCy Schubert 		} else {
18565171bc9bSCy Schubert 			// xprintf(stderr, "UNRECOGNIZED name=%s ", name);
1857c0b746e5SOllivier Robert 		}
1858c0b746e5SOllivier Robert 	}
1859c0b746e5SOllivier Robert 
1860c0b746e5SOllivier Robert 	/*
1861b5e14a13SCy Schubert 	 * hmode gives the best guidance for the t column.  If the response
1862b5e14a13SCy Schubert 	 * did not include hmode we'll use the old decodeaddrtype() result.
1863c0b746e5SOllivier Robert 	 */
1864b5e14a13SCy Schubert 	switch (hmode) {
1865b5e14a13SCy Schubert 
1866b5e14a13SCy Schubert 	case MODE_BCLIENT:
1867b5e14a13SCy Schubert 		/* broadcastclient or multicastclient */
1868b5e14a13SCy Schubert 		type = 'b';
1869b5e14a13SCy Schubert 		break;
1870b5e14a13SCy Schubert 
1871b5e14a13SCy Schubert 	case MODE_BROADCAST:
1872b5e14a13SCy Schubert 		/* broadcast or multicast server */
1873b5e14a13SCy Schubert 		if (IS_MCAST(&srcadr))
1874b5e14a13SCy Schubert 			type = 'M';
1875b5e14a13SCy Schubert 		else
1876b5e14a13SCy Schubert 			type = 'B';
1877b5e14a13SCy Schubert 		break;
1878b5e14a13SCy Schubert 
1879b5e14a13SCy Schubert 	case MODE_CLIENT:
1880b5e14a13SCy Schubert 		if (ISREFCLOCKADR(&srcadr))
1881b5e14a13SCy Schubert 			type = 'l';	/* local refclock*/
1882b5e14a13SCy Schubert 		else if (SOCK_UNSPEC(&srcadr))
1883b5e14a13SCy Schubert 			type = 'p';	/* pool */
1884b5e14a13SCy Schubert 		else if (IS_MCAST(&srcadr))
1885b5e14a13SCy Schubert 			type = 'a';	/* manycastclient */
1886b5e14a13SCy Schubert 		else
1887b5e14a13SCy Schubert 			type = 'u';	/* unicast */
1888b5e14a13SCy Schubert 		break;
1889b5e14a13SCy Schubert 
1890b5e14a13SCy Schubert 	case MODE_ACTIVE:
1891b5e14a13SCy Schubert 		type = 's';		/* symmetric active */
1892b5e14a13SCy Schubert 		break;			/* configured */
1893b5e14a13SCy Schubert 
1894b5e14a13SCy Schubert 	case MODE_PASSIVE:
1895b5e14a13SCy Schubert 		type = 'S';		/* symmetric passive */
1896b5e14a13SCy Schubert 		break;			/* ephemeral */
1897b5e14a13SCy Schubert 	}
1898c0b746e5SOllivier Robert 
1899c0b746e5SOllivier Robert 	/*
1900c0b746e5SOllivier Robert 	 * Got everything, format the line
1901c0b746e5SOllivier Robert 	 */
1902b5e14a13SCy Schubert 	poll_sec = 1 << min(ppoll, hpoll);
1903c0b746e5SOllivier Robert 	if (pktversion > NTP_OLDVERSION)
1904c0b746e5SOllivier Robert 		c = flash3[CTL_PEER_STATVAL(rstatus) & 0x7];
1905c0b746e5SOllivier Robert 	else
1906c0b746e5SOllivier Robert 		c = flash2[CTL_PEER_STATVAL(rstatus) & 0x3];
19072b45e011SOllivier Robert 	if (numhosts > 1) {
1908873997f3SCy Schubert 		if ((pvl == peervarlist || pvl == apeervarlist)
1909873997f3SCy Schubert 		    && have_dstadr) {
19102b45e011SOllivier Robert 			serverlocal = nntohost_col(&dstadr,
19112b45e011SOllivier Robert 			    (size_t)min(LIB_BUFLENGTH - 1, maxhostlen),
19122b45e011SOllivier Robert 			    TRUE);
19132b45e011SOllivier Robert 		} else {
19142b45e011SOllivier Robert 			if (currenthostisnum)
19152b45e011SOllivier Robert 				serverlocal = trunc_left(currenthost,
19162b45e011SOllivier Robert 							 maxhostlen);
19172b45e011SOllivier Robert 			else
19182b45e011SOllivier Robert 				serverlocal = currenthost;
19192b45e011SOllivier Robert 		}
19205171bc9bSCy Schubert 		xprintf(fp, "%-*s ", (int)maxhostlen, serverlocal);
19212b45e011SOllivier Robert 	}
19222b45e011SOllivier Robert 	if (AF_UNSPEC == af || AF(&srcadr) == af) {
1923b5e14a13SCy Schubert 		if (!have_srchost)
1924b5e14a13SCy Schubert 			strlcpy(clock_name, nntohost(&srcadr),
1925b5e14a13SCy Schubert 				sizeof(clock_name));
1926d14ac12fSXin LI 		/* wide and long source - space over on next line */
1927d14ac12fSXin LI 		/* allow for host + sp if > 1 and regular tally + source + sp */
1928b5e14a13SCy Schubert 		if (wideremote && 15 < strlen(clock_name))
19295171bc9bSCy Schubert 			xprintf(fp, "%c%s\n%*s", c, clock_name,
1930d14ac12fSXin LI 				((numhosts > 1) ? (int)maxhostlen + 1 : 0)
1931d14ac12fSXin LI 							+ 1 + 15 + 1, "");
1932b5e14a13SCy Schubert 		else
19335171bc9bSCy Schubert 			xprintf(fp, "%c%-15.15s ", c, clock_name);
1934c7f4d233SXin LI 		if ((flash & TEST12) && (pvl != opeervarlist)) {
19355171bc9bSCy Schubert 			drlen = xprintf(fp, "(loop)");
1936c7f4d233SXin LI 		} else if (!have_da_rid) {
1937b5e14a13SCy Schubert 			drlen = 0;
1938b5e14a13SCy Schubert 		} else {
19392b45e011SOllivier Robert 			drlen = strlen(dstadr_refid);
19402b45e011SOllivier Robert 			makeascii(drlen, dstadr_refid, fp);
1941b5e14a13SCy Schubert 		}
19421f833b3fSCy Schubert 		free(drbuf);
1943873997f3SCy Schubert 		if (pvl == apeervarlist) {
1944873997f3SCy Schubert 			while (drlen++ < 9)
19455171bc9bSCy Schubert 				xputc(' ', fp);
19465171bc9bSCy Schubert 			xprintf(fp, "%-6d", associd);
1947873997f3SCy Schubert 		} else {
19482b45e011SOllivier Robert 			while (drlen++ < 15)
19495171bc9bSCy Schubert 				xputc(' ', fp);
1950873997f3SCy Schubert 		}
19515171bc9bSCy Schubert 		xprintf(fp,
19522b45e011SOllivier Robert 			" %2ld %c %4.4s %4.4s  %3lo  %7.7s %8.7s %7.7s\n",
19532b45e011SOllivier Robert 			stratum, type,
19542b45e011SOllivier Robert 			prettyinterval(whenbuf, sizeof(whenbuf),
19552b45e011SOllivier Robert 				       when(&ts, &rec, &reftime)),
19562b45e011SOllivier Robert 			prettyinterval(pollbuf, sizeof(pollbuf),
19572b45e011SOllivier Robert 				       (int)poll_sec),
19585171bc9bSCy Schubert 			reach, ulfptoms(&estdelay, 3),
19592b45e011SOllivier Robert 			lfptoms(&estoffset, 3),
1960b5e14a13SCy Schubert 			(have_jitter)
19615171bc9bSCy Schubert 			    ? ulfptoms(&estjitter, 3)
19625171bc9bSCy Schubert 			    : ulfptoms(&estdisp, 3));
1963c0b746e5SOllivier Robert 		return (1);
1964c0b746e5SOllivier Robert 	}
19659c2daa00SOllivier Robert 	else
19669c2daa00SOllivier Robert 		return(1);
19679c2daa00SOllivier Robert }
1968c0b746e5SOllivier Robert 
1969c0b746e5SOllivier Robert 
1970c0b746e5SOllivier Robert /*
1971c0b746e5SOllivier Robert  * dogetpeers - given an association ID, read and print the spreadsheet
1972c0b746e5SOllivier Robert  *		peer variables.
1973c0b746e5SOllivier Robert  */
1974c0b746e5SOllivier Robert static int
dogetpeers(struct varlist * pvl,associd_t associd,FILE * fp,int af)1975c0b746e5SOllivier Robert dogetpeers(
1976c0b746e5SOllivier Robert 	struct varlist *pvl,
19772b45e011SOllivier Robert 	associd_t associd,
19789c2daa00SOllivier Robert 	FILE *fp,
19799c2daa00SOllivier Robert 	int af
1980c0b746e5SOllivier Robert 	)
1981c0b746e5SOllivier Robert {
19822b45e011SOllivier Robert 	const char *datap;
1983c0b746e5SOllivier Robert 	int res;
1984c373d928SXin LI 	size_t dsize;
1985c0b746e5SOllivier Robert 	u_short rstatus;
1986c0b746e5SOllivier Robert 
1987c0b746e5SOllivier Robert #ifdef notdef
1988c0b746e5SOllivier Robert 	res = doquerylist(pvl, CTL_OP_READVAR, associd, 0, &rstatus,
1989c0b746e5SOllivier Robert 			  &dsize, &datap);
1990c0b746e5SOllivier Robert #else
1991c0b746e5SOllivier Robert 	/*
1992c0b746e5SOllivier Robert 	 * Damn fuzzballs
1993c0b746e5SOllivier Robert 	 */
19942b45e011SOllivier Robert 	res = doquery(CTL_OP_READVAR, associd, 0, 0, NULL, &rstatus,
1995c0b746e5SOllivier Robert 			  &dsize, &datap);
1996c0b746e5SOllivier Robert #endif
1997c0b746e5SOllivier Robert 
1998c0b746e5SOllivier Robert 	if (res != 0)
1999c0b746e5SOllivier Robert 		return 0;
2000c0b746e5SOllivier Robert 
2001c0b746e5SOllivier Robert 	if (dsize == 0) {
2002ff717da2SOllivier Robert 		if (numhosts > 1)
20035171bc9bSCy Schubert 			xprintf(stderr, "server=%s ", currenthost);
20045171bc9bSCy Schubert 		xprintf(stderr,
20052b45e011SOllivier Robert 			"***No information returned for association %u\n",
2006c0b746e5SOllivier Robert 			associd);
2007c0b746e5SOllivier Robert 		return 0;
2008c0b746e5SOllivier Robert 	}
2009c0b746e5SOllivier Robert 
20102b45e011SOllivier Robert 	return doprintpeers(pvl, associd, (int)rstatus, dsize, datap,
20112b45e011SOllivier Robert 			    fp, af);
2012c0b746e5SOllivier Robert }
2013c0b746e5SOllivier Robert 
2014c0b746e5SOllivier Robert 
2015c0b746e5SOllivier Robert /*
2016c0b746e5SOllivier Robert  * peers - print a peer spreadsheet
2017c0b746e5SOllivier Robert  */
2018c0b746e5SOllivier Robert static void
dopeers(int showall,FILE * fp,int af)2019c0b746e5SOllivier Robert dopeers(
2020c0b746e5SOllivier Robert 	int showall,
20219c2daa00SOllivier Robert 	FILE *fp,
20229c2daa00SOllivier Robert 	int af
2023c0b746e5SOllivier Robert 	)
2024c0b746e5SOllivier Robert {
2025b5e14a13SCy Schubert 	u_int		u;
2026c0b746e5SOllivier Robert 	char		fullname[LENHOSTNAME];
20272b45e011SOllivier Robert 	sockaddr_u	netnum;
2028b5e14a13SCy Schubert 	const char *	name_or_num;
20292b45e011SOllivier Robert 	size_t		sl;
2030c0b746e5SOllivier Robert 
2031c0b746e5SOllivier Robert 	if (!dogetassoc(fp))
2032c0b746e5SOllivier Robert 		return;
2033c0b746e5SOllivier Robert 
203426fd3d56SCy Schubert 	if (numhosts > 1) {
2035b5e14a13SCy Schubert 		for (u = 0; u < numhosts; u++) {
2036b5e14a13SCy Schubert 			if (getnetnum(chosts[u].name, &netnum, fullname, af)) {
20372b45e011SOllivier Robert 				name_or_num = nntohost(&netnum);
20382b45e011SOllivier Robert 				sl = strlen(name_or_num);
2039b5e14a13SCy Schubert 				maxhostlen = max(maxhostlen, sl);
20402b45e011SOllivier Robert 			}
2041c0b746e5SOllivier Robert 		}
20425171bc9bSCy Schubert 		xprintf(fp, "%-*.*s ", (int)maxhostlen, (int)maxhostlen,
20432b45e011SOllivier Robert 			"server (local)");
204426fd3d56SCy Schubert 	}
20455171bc9bSCy Schubert 	xprintf(fp,
2046c0b746e5SOllivier Robert 		"     remote           refid      st t when poll reach   delay   offset  jitter\n");
2047c0b746e5SOllivier Robert 	if (numhosts > 1)
2048b5e14a13SCy Schubert 		for (u = 0; u <= maxhostlen; u++)
20495171bc9bSCy Schubert 			xprintf(fp, "=");
20505171bc9bSCy Schubert 	xprintf(fp,
2051c0b746e5SOllivier Robert 		"==============================================================================\n");
2052c0b746e5SOllivier Robert 
2053b5e14a13SCy Schubert 	for (u = 0; u < numassoc; u++) {
2054c0b746e5SOllivier Robert 		if (!showall &&
2055b5e14a13SCy Schubert 		    !(CTL_PEER_STATVAL(assoc_cache[u].status)
2056b5e14a13SCy Schubert 		      & (CTL_PST_CONFIG|CTL_PST_REACH))) {
2057b5e14a13SCy Schubert 			if (debug)
20585171bc9bSCy Schubert 				xprintf(stderr, "eliding [%d]\n",
2059b5e14a13SCy Schubert 					(int)assoc_cache[u].assid);
2060c0b746e5SOllivier Robert 			continue;
2061c0b746e5SOllivier Robert 		}
2062b5e14a13SCy Schubert 		if (!dogetpeers(peervarlist, (int)assoc_cache[u].assid,
2063b5e14a13SCy Schubert 				fp, af))
2064b5e14a13SCy Schubert 			return;
2065c0b746e5SOllivier Robert 	}
2066c0b746e5SOllivier Robert 	return;
2067c0b746e5SOllivier Robert }
2068c0b746e5SOllivier Robert 
2069c0b746e5SOllivier Robert 
2070c0b746e5SOllivier Robert /*
2071873997f3SCy Schubert  * doapeers - print a peer spreadsheet with assocIDs
2072873997f3SCy Schubert  */
2073873997f3SCy Schubert static void
doapeers(int showall,FILE * fp,int af)2074873997f3SCy Schubert doapeers(
2075873997f3SCy Schubert 	int showall,
2076873997f3SCy Schubert 	FILE *fp,
2077873997f3SCy Schubert 	int af
2078873997f3SCy Schubert 	)
2079873997f3SCy Schubert {
2080873997f3SCy Schubert 	u_int		u;
2081873997f3SCy Schubert 	char		fullname[LENHOSTNAME];
2082873997f3SCy Schubert 	sockaddr_u	netnum;
2083873997f3SCy Schubert 	const char *	name_or_num;
2084873997f3SCy Schubert 	size_t		sl;
2085873997f3SCy Schubert 
2086873997f3SCy Schubert 	if (!dogetassoc(fp))
2087873997f3SCy Schubert 		return;
2088873997f3SCy Schubert 
208926fd3d56SCy Schubert 	if (numhosts > 1) {
2090873997f3SCy Schubert 		for (u = 0; u < numhosts; u++) {
2091873997f3SCy Schubert 			if (getnetnum(chosts[u].name, &netnum, fullname, af)) {
2092873997f3SCy Schubert 				name_or_num = nntohost(&netnum);
2093873997f3SCy Schubert 				sl = strlen(name_or_num);
2094873997f3SCy Schubert 				maxhostlen = max(maxhostlen, sl);
2095873997f3SCy Schubert 			}
2096873997f3SCy Schubert 		}
20975171bc9bSCy Schubert 		xprintf(fp, "%-*.*s ", (int)maxhostlen, (int)maxhostlen,
2098873997f3SCy Schubert 			"server (local)");
209926fd3d56SCy Schubert 	}
21005171bc9bSCy Schubert 	xprintf(fp,
2101873997f3SCy Schubert 		"     remote       refid   assid  st t when poll reach   delay   offset  jitter\n");
2102873997f3SCy Schubert 	if (numhosts > 1)
2103873997f3SCy Schubert 		for (u = 0; u <= maxhostlen; u++)
21045171bc9bSCy Schubert 			xprintf(fp, "=");
21055171bc9bSCy Schubert 	xprintf(fp,
2106873997f3SCy Schubert 		"==============================================================================\n");
2107873997f3SCy Schubert 
2108873997f3SCy Schubert 	for (u = 0; u < numassoc; u++) {
2109873997f3SCy Schubert 		if (!showall &&
2110873997f3SCy Schubert 		    !(CTL_PEER_STATVAL(assoc_cache[u].status)
2111873997f3SCy Schubert 		      & (CTL_PST_CONFIG|CTL_PST_REACH))) {
2112873997f3SCy Schubert 			if (debug)
21135171bc9bSCy Schubert 				xprintf(stderr, "eliding [%d]\n",
2114873997f3SCy Schubert 					(int)assoc_cache[u].assid);
2115873997f3SCy Schubert 			continue;
2116873997f3SCy Schubert 		}
2117873997f3SCy Schubert 		if (!dogetpeers(apeervarlist, (int)assoc_cache[u].assid,
2118873997f3SCy Schubert 				fp, af))
2119873997f3SCy Schubert 			return;
2120873997f3SCy Schubert 	}
2121873997f3SCy Schubert 	return;
2122873997f3SCy Schubert }
2123873997f3SCy Schubert 
2124873997f3SCy Schubert 
2125873997f3SCy Schubert /*
2126c0b746e5SOllivier Robert  * peers - print a peer spreadsheet
2127c0b746e5SOllivier Robert  */
2128c0b746e5SOllivier Robert /*ARGSUSED*/
2129c0b746e5SOllivier Robert static void
peers(struct parse * pcmd,FILE * fp)2130c0b746e5SOllivier Robert peers(
2131c0b746e5SOllivier Robert 	struct parse *pcmd,
2132c0b746e5SOllivier Robert 	FILE *fp
2133c0b746e5SOllivier Robert 	)
2134c0b746e5SOllivier Robert {
2135c1950318SXin LI 	if (drefid == REFID_HASH) {
2136c1950318SXin LI 		apeers(pcmd, fp);
2137c1950318SXin LI 	} else {
21389c2daa00SOllivier Robert 		int af = 0;
21399c2daa00SOllivier Robert 
21409c2daa00SOllivier Robert 		if (pcmd->nargs == 1) {
21419c2daa00SOllivier Robert 			if (pcmd->argval->ival == 6)
21429c2daa00SOllivier Robert 				af = AF_INET6;
21439c2daa00SOllivier Robert 			else
21449c2daa00SOllivier Robert 				af = AF_INET;
21459c2daa00SOllivier Robert 		}
21469c2daa00SOllivier Robert 		dopeers(0, fp, af);
2147c0b746e5SOllivier Robert 	}
2148c1950318SXin LI }
2149c0b746e5SOllivier Robert 
2150c0b746e5SOllivier Robert 
2151c0b746e5SOllivier Robert /*
2152873997f3SCy Schubert  * apeers - print a peer spreadsheet, with assocIDs
2153873997f3SCy Schubert  */
2154873997f3SCy Schubert /*ARGSUSED*/
2155873997f3SCy Schubert static void
apeers(struct parse * pcmd,FILE * fp)2156873997f3SCy Schubert apeers(
2157873997f3SCy Schubert 	struct parse *pcmd,
2158873997f3SCy Schubert 	FILE *fp
2159873997f3SCy Schubert 	)
2160873997f3SCy Schubert {
2161873997f3SCy Schubert 	int af = 0;
2162873997f3SCy Schubert 
2163873997f3SCy Schubert 	if (pcmd->nargs == 1) {
2164873997f3SCy Schubert 		if (pcmd->argval->ival == 6)
2165873997f3SCy Schubert 			af = AF_INET6;
2166873997f3SCy Schubert 		else
2167873997f3SCy Schubert 			af = AF_INET;
2168873997f3SCy Schubert 	}
2169873997f3SCy Schubert 	doapeers(0, fp, af);
2170873997f3SCy Schubert }
2171873997f3SCy Schubert 
2172873997f3SCy Schubert 
2173873997f3SCy Schubert /*
2174c0b746e5SOllivier Robert  * lpeers - print a peer spreadsheet including all fuzzball peers
2175c0b746e5SOllivier Robert  */
2176c0b746e5SOllivier Robert /*ARGSUSED*/
2177c0b746e5SOllivier Robert static void
lpeers(struct parse * pcmd,FILE * fp)2178c0b746e5SOllivier Robert lpeers(
2179c0b746e5SOllivier Robert 	struct parse *pcmd,
2180c0b746e5SOllivier Robert 	FILE *fp
2181c0b746e5SOllivier Robert 	)
2182c0b746e5SOllivier Robert {
21839c2daa00SOllivier Robert 	int af = 0;
21849c2daa00SOllivier Robert 
21859c2daa00SOllivier Robert 	if (pcmd->nargs == 1) {
21869c2daa00SOllivier Robert 		if (pcmd->argval->ival == 6)
21879c2daa00SOllivier Robert 			af = AF_INET6;
21889c2daa00SOllivier Robert 		else
21899c2daa00SOllivier Robert 			af = AF_INET;
21909c2daa00SOllivier Robert 	}
21919c2daa00SOllivier Robert 	dopeers(1, fp, af);
2192c0b746e5SOllivier Robert }
2193c0b746e5SOllivier Robert 
2194c0b746e5SOllivier Robert 
2195c0b746e5SOllivier Robert /*
2196c0b746e5SOllivier Robert  * opeers - print a peer spreadsheet
2197c0b746e5SOllivier Robert  */
2198c0b746e5SOllivier Robert static void
doopeers(int showall,FILE * fp,int af)2199c0b746e5SOllivier Robert doopeers(
2200c0b746e5SOllivier Robert 	int showall,
22019c2daa00SOllivier Robert 	FILE *fp,
22029c2daa00SOllivier Robert 	int af
2203c0b746e5SOllivier Robert 	)
2204c0b746e5SOllivier Robert {
2205b5e14a13SCy Schubert 	u_int i;
2206ff717da2SOllivier Robert 	char fullname[LENHOSTNAME];
22072b45e011SOllivier Robert 	sockaddr_u netnum;
2208c0b746e5SOllivier Robert 
2209c0b746e5SOllivier Robert 	if (!dogetassoc(fp))
2210c0b746e5SOllivier Robert 		return;
2211c0b746e5SOllivier Robert 
221226fd3d56SCy Schubert 	if (numhosts > 1) {
2213ff717da2SOllivier Robert 		for (i = 0; i < numhosts; ++i) {
221426fd3d56SCy Schubert 			if (getnetnum(chosts[i].name, &netnum, fullname, af)) {
221526fd3d56SCy Schubert 				maxhostlen = max(maxhostlen, strlen(fullname));
2216ff717da2SOllivier Robert 			}
22175171bc9bSCy Schubert 			xprintf(fp, "%-*.*s ", (int)maxhostlen, (int)maxhostlen,
2218b5e14a13SCy Schubert 				"server");
221926fd3d56SCy Schubert 		}
222026fd3d56SCy Schubert 	}
22215171bc9bSCy Schubert 	xprintf(fp,
2222c0b746e5SOllivier Robert 	    "     remote           local      st t when poll reach   delay   offset    disp\n");
2223ff717da2SOllivier Robert 	if (numhosts > 1)
2224ff717da2SOllivier Robert 		for (i = 0; i <= maxhostlen; ++i)
22255171bc9bSCy Schubert 			xprintf(fp, "=");
22265171bc9bSCy Schubert 	xprintf(fp,
2227c0b746e5SOllivier Robert 	    "==============================================================================\n");
2228c0b746e5SOllivier Robert 
2229c0b746e5SOllivier Robert 	for (i = 0; i < numassoc; i++) {
2230c0b746e5SOllivier Robert 		if (!showall &&
2231b5e14a13SCy Schubert 		    !(CTL_PEER_STATVAL(assoc_cache[i].status) &
2232b5e14a13SCy Schubert 		      (CTL_PST_CONFIG | CTL_PST_REACH)))
2233c0b746e5SOllivier Robert 			continue;
2234b5e14a13SCy Schubert 		if (!dogetpeers(opeervarlist, assoc_cache[i].assid, fp, af))
2235c0b746e5SOllivier Robert 			return;
2236c0b746e5SOllivier Robert 	}
2237c0b746e5SOllivier Robert 	return;
2238c0b746e5SOllivier Robert }
2239c0b746e5SOllivier Robert 
2240c0b746e5SOllivier Robert 
2241c0b746e5SOllivier Robert /*
2242c0b746e5SOllivier Robert  * opeers - print a peer spreadsheet the old way
2243c0b746e5SOllivier Robert  */
2244c0b746e5SOllivier Robert /*ARGSUSED*/
2245c0b746e5SOllivier Robert static void
opeers(struct parse * pcmd,FILE * fp)2246c0b746e5SOllivier Robert opeers(
2247c0b746e5SOllivier Robert 	struct parse *pcmd,
2248c0b746e5SOllivier Robert 	FILE *fp
2249c0b746e5SOllivier Robert 	)
2250c0b746e5SOllivier Robert {
22519c2daa00SOllivier Robert 	int af = 0;
22529c2daa00SOllivier Robert 
22539c2daa00SOllivier Robert 	if (pcmd->nargs == 1) {
22549c2daa00SOllivier Robert 		if (pcmd->argval->ival == 6)
22559c2daa00SOllivier Robert 			af = AF_INET6;
22569c2daa00SOllivier Robert 		else
22579c2daa00SOllivier Robert 			af = AF_INET;
22589c2daa00SOllivier Robert 	}
22599c2daa00SOllivier Robert 	doopeers(0, fp, af);
2260c0b746e5SOllivier Robert }
2261c0b746e5SOllivier Robert 
2262c0b746e5SOllivier Robert 
2263c0b746e5SOllivier Robert /*
2264c0b746e5SOllivier Robert  * lopeers - print a peer spreadsheet including all fuzzball peers
2265c0b746e5SOllivier Robert  */
2266c0b746e5SOllivier Robert /*ARGSUSED*/
2267c0b746e5SOllivier Robert static void
lopeers(struct parse * pcmd,FILE * fp)2268c0b746e5SOllivier Robert lopeers(
2269c0b746e5SOllivier Robert 	struct parse *pcmd,
2270c0b746e5SOllivier Robert 	FILE *fp
2271c0b746e5SOllivier Robert 	)
2272c0b746e5SOllivier Robert {
22739c2daa00SOllivier Robert 	int af = 0;
22749c2daa00SOllivier Robert 
22759c2daa00SOllivier Robert 	if (pcmd->nargs == 1) {
22769c2daa00SOllivier Robert 		if (pcmd->argval->ival == 6)
22779c2daa00SOllivier Robert 			af = AF_INET6;
22789c2daa00SOllivier Robert 		else
22799c2daa00SOllivier Robert 			af = AF_INET;
22809c2daa00SOllivier Robert 	}
22819c2daa00SOllivier Robert 	doopeers(1, fp, af);
2282c0b746e5SOllivier Robert }
22832b45e011SOllivier Robert 
22842b45e011SOllivier Robert 
22852b45e011SOllivier Robert /*
22862b45e011SOllivier Robert  * config - send a configuration command to a remote host
22872b45e011SOllivier Robert  */
22882b45e011SOllivier Robert static void
config(struct parse * pcmd,FILE * fp)22892b45e011SOllivier Robert config (
22902b45e011SOllivier Robert 	struct parse *pcmd,
22912b45e011SOllivier Robert 	FILE *fp
22922b45e011SOllivier Robert 	)
22932b45e011SOllivier Robert {
2294b5e14a13SCy Schubert 	const char *cfgcmd;
22952b45e011SOllivier Robert 	u_short rstatus;
2296c373d928SXin LI 	size_t rsize;
22972b45e011SOllivier Robert 	const char *rdata;
22982b45e011SOllivier Robert 	char *resp;
22992b45e011SOllivier Robert 	int res;
23002b45e011SOllivier Robert 	int col;
23012b45e011SOllivier Robert 	int i;
23022b45e011SOllivier Robert 
23032b45e011SOllivier Robert 	cfgcmd = pcmd->argval[0].string;
23042b45e011SOllivier Robert 
23052b45e011SOllivier Robert 	if (debug > 2)
23065171bc9bSCy Schubert 		xprintf(stderr,
23072b45e011SOllivier Robert 			"In Config\n"
23082b45e011SOllivier Robert 			"Keyword = %s\n"
23092b45e011SOllivier Robert 			"Command = %s\n", pcmd->keyword, cfgcmd);
23102b45e011SOllivier Robert 
2311c373d928SXin LI 	res = doquery(CTL_OP_CONFIGURE, 0, 1,
2312c373d928SXin LI 		      strlen(cfgcmd), cfgcmd,
23132b45e011SOllivier Robert 		      &rstatus, &rsize, &rdata);
23142b45e011SOllivier Robert 
23152b45e011SOllivier Robert 	if (res != 0)
23162b45e011SOllivier Robert 		return;
23172b45e011SOllivier Robert 
23182b45e011SOllivier Robert 	if (rsize > 0 && '\n' == rdata[rsize - 1])
23192b45e011SOllivier Robert 		rsize--;
23202b45e011SOllivier Robert 
23212b45e011SOllivier Robert 	resp = emalloc(rsize + 1);
23222b45e011SOllivier Robert 	memcpy(resp, rdata, rsize);
23232b45e011SOllivier Robert 	resp[rsize] = '\0';
23242b45e011SOllivier Robert 
23252b45e011SOllivier Robert 	col = -1;
23262b45e011SOllivier Robert 	if (1 == sscanf(resp, "column %d syntax error", &col)
23272b45e011SOllivier Robert 	    && col >= 0 && (size_t)col <= strlen(cfgcmd) + 1) {
2328d14ac12fSXin LI 		if (interactive)
23295171bc9bSCy Schubert 			xputs("             *", stdout); /* "ntpq> :config " */
2330d14ac12fSXin LI 		else
23312b45e011SOllivier Robert 			printf("%s\n", cfgcmd);
2332d14ac12fSXin LI 		for (i = 0; i < col; i++)
23335171bc9bSCy Schubert 			xputc('_', stdout);
23345171bc9bSCy Schubert 		xputs("^\n", stdout);
23352b45e011SOllivier Robert 	}
23362b45e011SOllivier Robert 	printf("%s\n", resp);
23372b45e011SOllivier Robert 	free(resp);
23382b45e011SOllivier Robert }
23392b45e011SOllivier Robert 
23402b45e011SOllivier Robert 
23412b45e011SOllivier Robert /*
23422b45e011SOllivier Robert  * config_from_file - remotely configure an ntpd daemon using the
23432b45e011SOllivier Robert  * specified configuration file
23442b45e011SOllivier Robert  * SK: This function is a kludge at best and is full of bad design
23452b45e011SOllivier Robert  * bugs:
23462b45e011SOllivier Robert  * 1. ntpq uses UDP, which means that there is no guarantee of in-order,
23472b45e011SOllivier Robert  *    error-free delivery.
23482b45e011SOllivier Robert  * 2. The maximum length of a packet is constrained, and as a result, the
23492b45e011SOllivier Robert  *    maximum length of a line in a configuration file is constrained.
23502b45e011SOllivier Robert  *    Longer lines will lead to unpredictable results.
23512b45e011SOllivier Robert  * 3. Since this function is sending a line at a time, we can't update
23522b45e011SOllivier Robert  *    the control key through the configuration file (YUCK!!)
2353c1950318SXin LI  *
2354c1950318SXin LI  * Pearly: There are a few places where 'size_t' is cast to 'int' based
2355c1950318SXin LI  * on the assumption that 'int' can hold the size of the involved
2356c1950318SXin LI  * buffers without overflow.
23572b45e011SOllivier Robert  */
23582b45e011SOllivier Robert static void
config_from_file(struct parse * pcmd,FILE * fp)23592b45e011SOllivier Robert config_from_file (
23602b45e011SOllivier Robert 	struct parse *pcmd,
23612b45e011SOllivier Robert 	FILE *fp
23622b45e011SOllivier Robert 	)
23632b45e011SOllivier Robert {
23642b45e011SOllivier Robert 	u_short rstatus;
2365c373d928SXin LI 	size_t rsize;
23662b45e011SOllivier Robert 	const char *rdata;
2367c1950318SXin LI 	char * cp;
23682b45e011SOllivier Robert 	int res;
23692b45e011SOllivier Robert 	FILE *config_fd;
23702b45e011SOllivier Robert 	char config_cmd[MAXLINE];
23712b45e011SOllivier Robert 	size_t config_len;
23722b45e011SOllivier Robert 	int i;
23732b45e011SOllivier Robert 	int retry_limit;
23742b45e011SOllivier Robert 
23752b45e011SOllivier Robert 	if (debug > 2)
23765171bc9bSCy Schubert 		xprintf(stderr,
23772b45e011SOllivier Robert 			"In Config\n"
23782b45e011SOllivier Robert 			"Keyword = %s\n"
23792b45e011SOllivier Robert 			"Filename = %s\n", pcmd->keyword,
23802b45e011SOllivier Robert 			pcmd->argval[0].string);
23812b45e011SOllivier Robert 
23822b45e011SOllivier Robert 	config_fd = fopen(pcmd->argval[0].string, "r");
23832b45e011SOllivier Robert 	if (NULL == config_fd) {
23842b45e011SOllivier Robert 		printf("ERROR!! Couldn't open file: %s\n",
23852b45e011SOllivier Robert 		       pcmd->argval[0].string);
23862b45e011SOllivier Robert 		return;
23872b45e011SOllivier Robert 	}
23882b45e011SOllivier Robert 
23892b45e011SOllivier Robert 	printf("Sending configuration file, one line at a time.\n");
23902b45e011SOllivier Robert 	i = 0;
23912b45e011SOllivier Robert 	while (fgets(config_cmd, MAXLINE, config_fd) != NULL) {
2392c1950318SXin LI 		/* Eliminate comments first. */
2393c1950318SXin LI 		cp = strchr(config_cmd, '#');
2394c1950318SXin LI 		config_len = (NULL != cp)
2395c1950318SXin LI 		    ? (size_t)(cp - config_cmd)
2396c1950318SXin LI 		    : strlen(config_cmd);
2397c1950318SXin LI 
2398c1950318SXin LI 		/* [Bug 3015] make sure there's no trailing whitespace;
2399c1950318SXin LI 		 * the fix for [Bug 2853] on the server side forbids
2400c1950318SXin LI 		 * those. And don't transmit empty lines, as this would
2401c1950318SXin LI 		 * just be waste.
2402c1950318SXin LI 		 */
2403c1950318SXin LI 		while (config_len != 0 &&
2404c1950318SXin LI 		       (u_char)config_cmd[config_len-1] <= ' ')
2405c1950318SXin LI 			--config_len;
2406c1950318SXin LI 		config_cmd[config_len] = '\0';
2407c1950318SXin LI 
24082b45e011SOllivier Robert 		++i;
2409c1950318SXin LI 		if (0 == config_len)
2410c1950318SXin LI 			continue;
2411c1950318SXin LI 
24122b45e011SOllivier Robert 		retry_limit = 2;
24132b45e011SOllivier Robert 		do
24142b45e011SOllivier Robert 			res = doquery(CTL_OP_CONFIGURE, 0, 1,
2415c1950318SXin LI 				      config_len, config_cmd,
24162b45e011SOllivier Robert 				      &rstatus, &rsize, &rdata);
24172b45e011SOllivier Robert 		while (res != 0 && retry_limit--);
24182b45e011SOllivier Robert 		if (res != 0) {
2419c1950318SXin LI 			printf("Line No: %d query failed: %.*s\n"
2420c1950318SXin LI 			       "Subsequent lines not sent.\n",
2421c1950318SXin LI 			       i, (int)config_len, config_cmd);
24222b45e011SOllivier Robert 			fclose(config_fd);
24232b45e011SOllivier Robert 			return;
24242b45e011SOllivier Robert 		}
24252b45e011SOllivier Robert 
2426c1950318SXin LI 		/* Right-strip the result code string, then output the
2427c1950318SXin LI 		 * last line executed, with result code. */
2428c1950318SXin LI 		while (rsize != 0 && (u_char)rdata[rsize - 1] <= ' ')
2429c1950318SXin LI 			--rsize;
2430c1950318SXin LI 		printf("Line No: %d %.*s: %.*s\n", i,
2431c1950318SXin LI 		       (int)rsize, rdata,
2432c1950318SXin LI 		       (int)config_len, config_cmd);
24332b45e011SOllivier Robert 	}
24342b45e011SOllivier Robert 	printf("Done sending file\n");
24352b45e011SOllivier Robert 	fclose(config_fd);
24362b45e011SOllivier Robert }
2437b5e14a13SCy Schubert 
2438b5e14a13SCy Schubert 
2439b5e14a13SCy Schubert static int
fetch_nonce(char * nonce,size_t cb_nonce)2440b5e14a13SCy Schubert fetch_nonce(
2441b5e14a13SCy Schubert 	char *	nonce,
2442b5e14a13SCy Schubert 	size_t	cb_nonce
2443b5e14a13SCy Schubert 	)
2444b5e14a13SCy Schubert {
2445b5e14a13SCy Schubert 	const char	nonce_eq[] = "nonce=";
2446b5e14a13SCy Schubert 	int		qres;
2447b5e14a13SCy Schubert 	u_short		rstatus;
2448c373d928SXin LI 	size_t		rsize;
2449b5e14a13SCy Schubert 	const char *	rdata;
2450c373d928SXin LI 	size_t		chars;
2451b5e14a13SCy Schubert 
2452b5e14a13SCy Schubert 	/*
2453b5e14a13SCy Schubert 	 * Retrieve a nonce specific to this client to demonstrate to
2454b5e14a13SCy Schubert 	 * ntpd that we're capable of receiving responses to our source
2455b5e14a13SCy Schubert 	 * IP address, and thereby unlikely to be forging the source.
2456b5e14a13SCy Schubert 	 */
2457b5e14a13SCy Schubert 	qres = doquery(CTL_OP_REQ_NONCE, 0, 0, 0, NULL, &rstatus,
2458b5e14a13SCy Schubert 		       &rsize, &rdata);
2459b5e14a13SCy Schubert 	if (qres) {
24605171bc9bSCy Schubert 		xprintf(stderr, "nonce request failed\n");
2461b5e14a13SCy Schubert 		return FALSE;
2462b5e14a13SCy Schubert 	}
2463b5e14a13SCy Schubert 
24641f833b3fSCy Schubert 	if (rsize <= sizeof(nonce_eq) - 1 ||
2465b5e14a13SCy Schubert 	    strncmp(rdata, nonce_eq, sizeof(nonce_eq) - 1)) {
24665171bc9bSCy Schubert 		xprintf(stderr, "unexpected nonce response format: %.*s\n",
2467c373d928SXin LI 			(int)rsize, rdata); /* cast is wobbly */
2468b5e14a13SCy Schubert 		return FALSE;
2469b5e14a13SCy Schubert 	}
2470b5e14a13SCy Schubert 	chars = rsize - (sizeof(nonce_eq) - 1);
2471c7f4d233SXin LI 	if (chars >= cb_nonce)
2472b5e14a13SCy Schubert 		return FALSE;
2473b5e14a13SCy Schubert 	memcpy(nonce, rdata + sizeof(nonce_eq) - 1, chars);
2474b5e14a13SCy Schubert 	nonce[chars] = '\0';
2475b5e14a13SCy Schubert 	while (chars > 0 &&
2476b5e14a13SCy Schubert 	       ('\r' == nonce[chars - 1] || '\n' == nonce[chars - 1])) {
2477b5e14a13SCy Schubert 		chars--;
2478b5e14a13SCy Schubert 		nonce[chars] = '\0';
2479b5e14a13SCy Schubert 	}
2480b5e14a13SCy Schubert 
2481b5e14a13SCy Schubert 	return TRUE;
2482b5e14a13SCy Schubert }
2483b5e14a13SCy Schubert 
2484b5e14a13SCy Schubert 
2485b5e14a13SCy Schubert /*
2486b5e14a13SCy Schubert  * add_mru	Add and entry to mru list, hash table, and allocate
2487b5e14a13SCy Schubert  *		and return a replacement.
2488b5e14a13SCy Schubert  *		This is a helper for collect_mru_list().
2489b5e14a13SCy Schubert  */
2490b5e14a13SCy Schubert static mru *
add_mru(mru * add)2491b5e14a13SCy Schubert add_mru(
2492b5e14a13SCy Schubert 	mru *add
2493b5e14a13SCy Schubert 	)
2494b5e14a13SCy Schubert {
2495b5e14a13SCy Schubert 	u_short hash;
2496b5e14a13SCy Schubert 	mru *mon;
2497b5e14a13SCy Schubert 	mru *unlinked;
2498b5e14a13SCy Schubert 
2499b5e14a13SCy Schubert 
2500b5e14a13SCy Schubert 	hash = NTP_HASH_ADDR(&add->addr);
2501b5e14a13SCy Schubert 	/* see if we have it among previously received entries */
2502b5e14a13SCy Schubert 	for (mon = hash_table[hash]; mon != NULL; mon = mon->hlink)
2503b5e14a13SCy Schubert 		if (SOCK_EQ(&mon->addr, &add->addr))
2504b5e14a13SCy Schubert 			break;
2505b5e14a13SCy Schubert 	if (mon != NULL) {
2506b5e14a13SCy Schubert 		if (!L_ISGEQ(&add->first, &mon->first)) {
25075171bc9bSCy Schubert 			xprintf(stderr,
2508b5e14a13SCy Schubert 				"add_mru duplicate %s new first ts %08x.%08x precedes prior %08x.%08x\n",
2509b5e14a13SCy Schubert 				sptoa(&add->addr), add->last.l_ui,
2510b5e14a13SCy Schubert 				add->last.l_uf, mon->last.l_ui,
2511b5e14a13SCy Schubert 				mon->last.l_uf);
2512b5e14a13SCy Schubert 			exit(1);
2513b5e14a13SCy Schubert 		}
2514b5e14a13SCy Schubert 		UNLINK_DLIST(mon, mlink);
2515b5e14a13SCy Schubert 		UNLINK_SLIST(unlinked, hash_table[hash], mon, hlink, mru);
25160b0c40a7SGleb Smirnoff 		INSIST(unlinked == mon);
2517b5e14a13SCy Schubert 		mru_dupes++;
2518b5e14a13SCy Schubert 		TRACE(2, ("(updated from %08x.%08x) ", mon->last.l_ui,
2519b5e14a13SCy Schubert 		      mon->last.l_uf));
2520b5e14a13SCy Schubert 	}
2521b5e14a13SCy Schubert 	LINK_DLIST(mru_list, add, mlink);
2522b5e14a13SCy Schubert 	LINK_SLIST(hash_table[hash], add, hlink);
2523b5e14a13SCy Schubert 	TRACE(2, ("add_mru %08x.%08x c %d m %d v %d rest %x first %08x.%08x %s\n",
2524b5e14a13SCy Schubert 	      add->last.l_ui, add->last.l_uf, add->count,
2525b5e14a13SCy Schubert 	      (int)add->mode, (int)add->ver, (u_int)add->rs,
2526b5e14a13SCy Schubert 	      add->first.l_ui, add->first.l_uf, sptoa(&add->addr)));
2527b5e14a13SCy Schubert 	/* if we didn't update an existing entry, alloc replacement */
2528b5e14a13SCy Schubert 	if (NULL == mon) {
2529b5e14a13SCy Schubert 		mon = emalloc(sizeof(*mon));
2530b5e14a13SCy Schubert 		mru_count++;
2531b5e14a13SCy Schubert 	}
2532b5e14a13SCy Schubert 	ZERO(*mon);
2533b5e14a13SCy Schubert 
2534b5e14a13SCy Schubert 	return mon;
2535b5e14a13SCy Schubert }
2536b5e14a13SCy Schubert 
2537b5e14a13SCy Schubert 
2538b5e14a13SCy Schubert /* MGOT macro is specific to collect_mru_list() */
2539b5e14a13SCy Schubert #define MGOT(bit)				\
2540b5e14a13SCy Schubert 	do {					\
2541b5e14a13SCy Schubert 		got |= (bit);			\
2542b5e14a13SCy Schubert 		if (MRU_GOT_ALL == got) {	\
2543b5e14a13SCy Schubert 			got = 0;		\
2544b5e14a13SCy Schubert 			mon = add_mru(mon);	\
2545b5e14a13SCy Schubert 			ci++;			\
2546b5e14a13SCy Schubert 		}				\
2547b5e14a13SCy Schubert 	} while (0)
2548b5e14a13SCy Schubert 
2549b5e14a13SCy Schubert 
2550c373d928SXin LI int
mrulist_ctrl_c_hook(void)2551b5e14a13SCy Schubert mrulist_ctrl_c_hook(void)
2552b5e14a13SCy Schubert {
2553b5e14a13SCy Schubert 	mrulist_interrupted = TRUE;
2554c373d928SXin LI 	return TRUE;
2555b5e14a13SCy Schubert }
2556b5e14a13SCy Schubert 
2557b5e14a13SCy Schubert 
2558b5e14a13SCy Schubert static int
collect_mru_list(const char * parms,l_fp * pnow)2559b5e14a13SCy Schubert collect_mru_list(
2560b5e14a13SCy Schubert 	const char *	parms,
2561b5e14a13SCy Schubert 	l_fp *		pnow
2562b5e14a13SCy Schubert 	)
2563b5e14a13SCy Schubert {
2564b5e14a13SCy Schubert 	const u_int sleep_msecs = 5;
2565b5e14a13SCy Schubert 	static int ntpd_row_limit = MRU_ROW_LIMIT;
2566b5e14a13SCy Schubert 	int c_mru_l_rc;		/* this function's return code */
2567b5e14a13SCy Schubert 	u_char got;		/* MRU_GOT_* bits */
2568b5e14a13SCy Schubert 	time_t next_report;
2569b5e14a13SCy Schubert 	size_t cb;
2570b5e14a13SCy Schubert 	mru *mon;
2571b5e14a13SCy Schubert 	mru *head;
2572b5e14a13SCy Schubert 	mru *recent;
2573b5e14a13SCy Schubert 	int list_complete;
2574b5e14a13SCy Schubert 	char nonce[128];
2575b5e14a13SCy Schubert 	char buf[128];
2576b5e14a13SCy Schubert 	char req_buf[CTL_MAX_DATA_LEN];
2577b5e14a13SCy Schubert 	char *req;
2578b5e14a13SCy Schubert 	char *req_end;
2579c373d928SXin LI 	size_t chars;
2580b5e14a13SCy Schubert 	int qres;
2581b5e14a13SCy Schubert 	u_short rstatus;
2582c373d928SXin LI 	size_t rsize;
2583b5e14a13SCy Schubert 	const char *rdata;
2584b5e14a13SCy Schubert 	int limit;
2585b5e14a13SCy Schubert 	int frags;
2586b5e14a13SCy Schubert 	int cap_frags;
2587b5e14a13SCy Schubert 	char *tag;
2588b5e14a13SCy Schubert 	char *val;
2589b5e14a13SCy Schubert 	int si;		/* server index in response */
2590b5e14a13SCy Schubert 	int ci;		/* client (our) index for validation */
2591b5e14a13SCy Schubert 	int ri;		/* request index (.# suffix) */
2592b5e14a13SCy Schubert 	int mv;
2593b5e14a13SCy Schubert 	l_fp newest;
2594b5e14a13SCy Schubert 	l_fp last_older;
2595b5e14a13SCy Schubert 	sockaddr_u addr_older;
2596b5e14a13SCy Schubert 	int have_now;
2597b5e14a13SCy Schubert 	int have_addr_older;
2598b5e14a13SCy Schubert 	int have_last_older;
2599b5e14a13SCy Schubert 	u_int restarted_count;
2600b5e14a13SCy Schubert 	u_int nonce_uses;
2601b5e14a13SCy Schubert 	u_short hash;
2602b5e14a13SCy Schubert 	mru *unlinked;
2603b5e14a13SCy Schubert 
2604b5e14a13SCy Schubert 	if (!fetch_nonce(nonce, sizeof(nonce)))
2605b5e14a13SCy Schubert 		return FALSE;
2606b5e14a13SCy Schubert 
2607b5e14a13SCy Schubert 	nonce_uses = 0;
2608b5e14a13SCy Schubert 	restarted_count = 0;
2609b5e14a13SCy Schubert 	mru_count = 0;
2610b5e14a13SCy Schubert 	INIT_DLIST(mru_list, mlink);
2611b5e14a13SCy Schubert 	cb = NTP_HASH_SIZE * sizeof(*hash_table);
26120b0c40a7SGleb Smirnoff 	INSIST(NULL == hash_table);
2613b5e14a13SCy Schubert 	hash_table = emalloc_zero(cb);
2614b5e14a13SCy Schubert 
2615b5e14a13SCy Schubert 	c_mru_l_rc = FALSE;
2616b5e14a13SCy Schubert 	list_complete = FALSE;
2617b5e14a13SCy Schubert 	have_now = FALSE;
2618b5e14a13SCy Schubert 	cap_frags = TRUE;
2619b5e14a13SCy Schubert 	got = 0;
2620b5e14a13SCy Schubert 	ri = 0;
2621b5e14a13SCy Schubert 	cb = sizeof(*mon);
2622b5e14a13SCy Schubert 	mon = emalloc_zero(cb);
2623b5e14a13SCy Schubert 	ZERO(*pnow);
2624b5e14a13SCy Schubert 	ZERO(last_older);
2625b5e14a13SCy Schubert 	next_report = time(NULL) + MRU_REPORT_SECS;
2626b5e14a13SCy Schubert 
2627b5e14a13SCy Schubert 	limit = min(3 * MAXFRAGS, ntpd_row_limit);
2628b5e14a13SCy Schubert 	frags = MAXFRAGS;
2629b5e14a13SCy Schubert 	snprintf(req_buf, sizeof(req_buf), "nonce=%s, frags=%d%s",
2630b5e14a13SCy Schubert 		 nonce, frags, parms);
2631b5e14a13SCy Schubert 	nonce_uses++;
2632b5e14a13SCy Schubert 
2633b5e14a13SCy Schubert 	while (TRUE) {
2634b5e14a13SCy Schubert 		if (debug)
26355171bc9bSCy Schubert 			xprintf(stderr, "READ_MRU parms: %s\n", req_buf);
2636b5e14a13SCy Schubert 
2637c373d928SXin LI 		qres = doqueryex(CTL_OP_READ_MRU, 0, 0,
2638c373d928SXin LI 				 strlen(req_buf), req_buf,
2639c373d928SXin LI 				 &rstatus, &rsize, &rdata, TRUE);
2640b5e14a13SCy Schubert 
2641b5e14a13SCy Schubert 		if (CERR_UNKNOWNVAR == qres && ri > 0) {
2642b5e14a13SCy Schubert 			/*
2643b5e14a13SCy Schubert 			 * None of the supplied prior entries match, so
2644b5e14a13SCy Schubert 			 * toss them from our list and try again.
2645b5e14a13SCy Schubert 			 */
2646b5e14a13SCy Schubert 			if (debug)
26475171bc9bSCy Schubert 				xprintf(stderr,
2648b5e14a13SCy Schubert 					"no overlap between %d prior entries and server MRU list\n",
2649b5e14a13SCy Schubert 					ri);
2650b5e14a13SCy Schubert 			while (ri--) {
2651b5e14a13SCy Schubert 				recent = HEAD_DLIST(mru_list, mlink);
26520b0c40a7SGleb Smirnoff 				INSIST(recent != NULL);
2653b5e14a13SCy Schubert 				if (debug)
26545171bc9bSCy Schubert 					xprintf(stderr,
2655b5e14a13SCy Schubert 						"tossing prior entry %s to resync\n",
2656b5e14a13SCy Schubert 						sptoa(&recent->addr));
2657b5e14a13SCy Schubert 				UNLINK_DLIST(recent, mlink);
2658b5e14a13SCy Schubert 				hash = NTP_HASH_ADDR(&recent->addr);
2659b5e14a13SCy Schubert 				UNLINK_SLIST(unlinked, hash_table[hash],
2660b5e14a13SCy Schubert 					     recent, hlink, mru);
26610b0c40a7SGleb Smirnoff 				INSIST(unlinked == recent);
2662b5e14a13SCy Schubert 				free(recent);
2663b5e14a13SCy Schubert 				mru_count--;
2664b5e14a13SCy Schubert 			}
2665b5e14a13SCy Schubert 			if (NULL == HEAD_DLIST(mru_list, mlink)) {
2666b5e14a13SCy Schubert 				restarted_count++;
2667b5e14a13SCy Schubert 				if (restarted_count > 8) {
26685171bc9bSCy Schubert 					xprintf(stderr,
2669b5e14a13SCy Schubert 						"Giving up after 8 restarts from the beginning.\n"
2670b5e14a13SCy Schubert 						"With high-traffic NTP servers, this can occur if the\n"
2671b5e14a13SCy Schubert 						"MRU list is limited to less than about 16 seconds' of\n"
2672b5e14a13SCy Schubert 						"entries.  See the 'mru' ntp.conf directive to adjust.\n");
2673b5e14a13SCy Schubert 					goto cleanup_return;
2674b5e14a13SCy Schubert 				}
2675b5e14a13SCy Schubert 				if (debug)
26765171bc9bSCy Schubert 					xprintf(stderr,
2677b5e14a13SCy Schubert 						"--->   Restarting from the beginning, retry #%u\n",
2678b5e14a13SCy Schubert 						restarted_count);
2679b5e14a13SCy Schubert 			}
2680b5e14a13SCy Schubert 		} else if (CERR_UNKNOWNVAR == qres) {
26815171bc9bSCy Schubert 			xprintf(stderr,
2682b5e14a13SCy Schubert 				"CERR_UNKNOWNVAR from ntpd but no priors given.\n");
2683b5e14a13SCy Schubert 			goto cleanup_return;
2684b5e14a13SCy Schubert 		} else if (CERR_BADVALUE == qres) {
2685b5e14a13SCy Schubert 			if (cap_frags) {
2686b5e14a13SCy Schubert 				cap_frags = FALSE;
2687b5e14a13SCy Schubert 				if (debug)
26885171bc9bSCy Schubert 					xprintf(stderr,
2689b5e14a13SCy Schubert 						"Reverted to row limit from fragments limit.\n");
2690b5e14a13SCy Schubert 			} else {
2691b5e14a13SCy Schubert 				/* ntpd has lower cap on row limit */
2692b5e14a13SCy Schubert 				ntpd_row_limit--;
2693b5e14a13SCy Schubert 				limit = min(limit, ntpd_row_limit);
2694b5e14a13SCy Schubert 				if (debug)
26955171bc9bSCy Schubert 					xprintf(stderr,
2696b5e14a13SCy Schubert 						"Row limit reduced to %d following CERR_BADVALUE.\n",
2697b5e14a13SCy Schubert 						limit);
2698b5e14a13SCy Schubert 			}
2699b5e14a13SCy Schubert 		} else if (ERR_INCOMPLETE == qres ||
2700b5e14a13SCy Schubert 			   ERR_TIMEOUT == qres) {
2701b5e14a13SCy Schubert 			/*
2702b5e14a13SCy Schubert 			 * Reduce the number of rows/frags requested by
2703b5e14a13SCy Schubert 			 * half to recover from lost response fragments.
2704b5e14a13SCy Schubert 			 */
2705b5e14a13SCy Schubert 			if (cap_frags) {
2706b5e14a13SCy Schubert 				frags = max(2, frags / 2);
2707b5e14a13SCy Schubert 				if (debug)
27085171bc9bSCy Schubert 					xprintf(stderr,
2709b5e14a13SCy Schubert 						"Frag limit reduced to %d following incomplete response.\n",
2710b5e14a13SCy Schubert 						frags);
2711b5e14a13SCy Schubert 			} else {
2712b5e14a13SCy Schubert 				limit = max(2, limit / 2);
2713b5e14a13SCy Schubert 				if (debug)
27145171bc9bSCy Schubert 					xprintf(stderr,
2715b5e14a13SCy Schubert 						"Row limit reduced to %d following incomplete response.\n",
2716b5e14a13SCy Schubert 						limit);
2717b5e14a13SCy Schubert 			}
2718b5e14a13SCy Schubert 		} else if (qres) {
2719b5e14a13SCy Schubert 			show_error_msg(qres, 0);
2720b5e14a13SCy Schubert 			goto cleanup_return;
2721b5e14a13SCy Schubert 		}
2722b5e14a13SCy Schubert 		/*
2723b5e14a13SCy Schubert 		 * This is a cheap cop-out implementation of rawmode
2724b5e14a13SCy Schubert 		 * output for mrulist.  A better approach would be to
2725b5e14a13SCy Schubert 		 * dump similar output after the list is collected by
2726b5e14a13SCy Schubert 		 * ntpq with a continuous sequence of indexes.  This
2727b5e14a13SCy Schubert 		 * cheap approach has indexes resetting to zero for
2728b5e14a13SCy Schubert 		 * each query/response, and duplicates are not
2729b5e14a13SCy Schubert 		 * coalesced.
2730b5e14a13SCy Schubert 		 */
2731b5e14a13SCy Schubert 		if (!qres && rawmode)
2732b5e14a13SCy Schubert 			printvars(rsize, rdata, rstatus, TYPE_SYS, 1, stdout);
2733b5e14a13SCy Schubert 		ci = 0;
2734b5e14a13SCy Schubert 		have_addr_older = FALSE;
2735b5e14a13SCy Schubert 		have_last_older = FALSE;
2736b5e14a13SCy Schubert 		while (!qres && nextvar(&rsize, &rdata, &tag, &val)) {
2737c7f4d233SXin LI 			INSIST(tag && val);
2738b5e14a13SCy Schubert 			if (debug > 1)
27395171bc9bSCy Schubert 				xprintf(stderr, "nextvar gave: %s = %s\n",
2740b5e14a13SCy Schubert 					tag, val);
2741b5e14a13SCy Schubert 			switch(tag[0]) {
2742b5e14a13SCy Schubert 
2743b5e14a13SCy Schubert 			case 'a':
2744b5e14a13SCy Schubert 				if (!strcmp(tag, "addr.older")) {
2745b5e14a13SCy Schubert 					if (!have_last_older) {
27465171bc9bSCy Schubert 						xprintf(stderr,
2747b5e14a13SCy Schubert 							"addr.older %s before last.older\n",
2748b5e14a13SCy Schubert 							val);
2749b5e14a13SCy Schubert 						goto cleanup_return;
2750b5e14a13SCy Schubert 					}
2751b5e14a13SCy Schubert 					if (!decodenetnum(val, &addr_older)) {
27525171bc9bSCy Schubert 						xprintf(stderr,
2753b5e14a13SCy Schubert 							"addr.older %s garbled\n",
2754b5e14a13SCy Schubert 							val);
2755b5e14a13SCy Schubert 						goto cleanup_return;
2756b5e14a13SCy Schubert 					}
2757b5e14a13SCy Schubert 					hash = NTP_HASH_ADDR(&addr_older);
2758b5e14a13SCy Schubert 					for (recent = hash_table[hash];
2759b5e14a13SCy Schubert 					     recent != NULL;
2760b5e14a13SCy Schubert 					     recent = recent->hlink)
2761b5e14a13SCy Schubert 						if (ADDR_PORT_EQ(
2762b5e14a13SCy Schubert 						      &addr_older,
2763b5e14a13SCy Schubert 						      &recent->addr))
2764b5e14a13SCy Schubert 							break;
2765b5e14a13SCy Schubert 					if (NULL == recent) {
27665171bc9bSCy Schubert 						xprintf(stderr,
2767b5e14a13SCy Schubert 							"addr.older %s not in hash table\n",
2768b5e14a13SCy Schubert 							val);
2769b5e14a13SCy Schubert 						goto cleanup_return;
2770b5e14a13SCy Schubert 					}
2771b5e14a13SCy Schubert 					if (!L_ISEQU(&last_older,
2772b5e14a13SCy Schubert 						     &recent->last)) {
27735171bc9bSCy Schubert 						xprintf(stderr,
2774b5e14a13SCy Schubert 							"last.older %08x.%08x mismatches %08x.%08x expected.\n",
2775b5e14a13SCy Schubert 							last_older.l_ui,
2776b5e14a13SCy Schubert 							last_older.l_uf,
2777b5e14a13SCy Schubert 							recent->last.l_ui,
2778b5e14a13SCy Schubert 							recent->last.l_uf);
2779b5e14a13SCy Schubert 						goto cleanup_return;
2780b5e14a13SCy Schubert 					}
2781b5e14a13SCy Schubert 					have_addr_older = TRUE;
2782b5e14a13SCy Schubert 				} else if (1 != sscanf(tag, "addr.%d", &si)
2783b5e14a13SCy Schubert 					   || si != ci)
2784b5e14a13SCy Schubert 					goto nomatch;
2785b5e14a13SCy Schubert 				else if (decodenetnum(val, &mon->addr))
2786b5e14a13SCy Schubert 					MGOT(MRU_GOT_ADDR);
2787b5e14a13SCy Schubert 				break;
2788b5e14a13SCy Schubert 
2789b5e14a13SCy Schubert 			case 'l':
2790b5e14a13SCy Schubert 				if (!strcmp(tag, "last.older")) {
2791b5e14a13SCy Schubert 					if ('0' != val[0] ||
2792b5e14a13SCy Schubert 					    'x' != val[1] ||
2793b5e14a13SCy Schubert 					    !hextolfp(val + 2, &last_older)) {
27945171bc9bSCy Schubert 						xprintf(stderr,
2795b5e14a13SCy Schubert 							"last.older %s garbled\n",
2796b5e14a13SCy Schubert 							val);
2797b5e14a13SCy Schubert 						goto cleanup_return;
2798b5e14a13SCy Schubert 					}
2799b5e14a13SCy Schubert 					have_last_older = TRUE;
2800b5e14a13SCy Schubert 				} else if (!strcmp(tag, "last.newest")) {
2801b5e14a13SCy Schubert 					if (0 != got) {
28025171bc9bSCy Schubert 						xprintf(stderr,
2803b5e14a13SCy Schubert 							"last.newest %s before complete row, got = 0x%x\n",
2804b5e14a13SCy Schubert 							val, (u_int)got);
2805b5e14a13SCy Schubert 						goto cleanup_return;
2806b5e14a13SCy Schubert 					}
2807b5e14a13SCy Schubert 					if (!have_now) {
28085171bc9bSCy Schubert 						xprintf(stderr,
2809b5e14a13SCy Schubert 							"last.newest %s before now=\n",
2810b5e14a13SCy Schubert 							val);
2811b5e14a13SCy Schubert 						goto cleanup_return;
2812b5e14a13SCy Schubert 					}
2813b5e14a13SCy Schubert 					head = HEAD_DLIST(mru_list, mlink);
2814b5e14a13SCy Schubert 					if (NULL != head) {
2815b5e14a13SCy Schubert 						if ('0' != val[0] ||
2816b5e14a13SCy Schubert 						    'x' != val[1] ||
2817b5e14a13SCy Schubert 						    !hextolfp(val + 2, &newest) ||
2818b5e14a13SCy Schubert 						    !L_ISEQU(&newest,
2819b5e14a13SCy Schubert 							     &head->last)) {
28205171bc9bSCy Schubert 							xprintf(stderr,
2821b5e14a13SCy Schubert 								"last.newest %s mismatches %08x.%08x",
2822b5e14a13SCy Schubert 								val,
2823b5e14a13SCy Schubert 								head->last.l_ui,
2824b5e14a13SCy Schubert 								head->last.l_uf);
2825b5e14a13SCy Schubert 							goto cleanup_return;
2826b5e14a13SCy Schubert 						}
2827b5e14a13SCy Schubert 					}
2828b5e14a13SCy Schubert 					list_complete = TRUE;
2829b5e14a13SCy Schubert 				} else if (1 != sscanf(tag, "last.%d", &si) ||
2830b5e14a13SCy Schubert 					   si != ci || '0' != val[0] ||
2831b5e14a13SCy Schubert 					   'x' != val[1] ||
2832b5e14a13SCy Schubert 					   !hextolfp(val + 2, &mon->last)) {
2833b5e14a13SCy Schubert 					goto nomatch;
2834b5e14a13SCy Schubert 				} else {
2835b5e14a13SCy Schubert 					MGOT(MRU_GOT_LAST);
2836b5e14a13SCy Schubert 					/*
2837b5e14a13SCy Schubert 					 * allow interrupted retrieval,
2838b5e14a13SCy Schubert 					 * using most recent retrieved
2839b5e14a13SCy Schubert 					 * entry's last seen timestamp
2840b5e14a13SCy Schubert 					 * as the end of operation.
2841b5e14a13SCy Schubert 					 */
2842b5e14a13SCy Schubert 					*pnow = mon->last;
2843b5e14a13SCy Schubert 				}
2844b5e14a13SCy Schubert 				break;
2845b5e14a13SCy Schubert 
2846b5e14a13SCy Schubert 			case 'f':
2847b5e14a13SCy Schubert 				if (1 != sscanf(tag, "first.%d", &si) ||
2848b5e14a13SCy Schubert 				    si != ci || '0' != val[0] ||
2849b5e14a13SCy Schubert 				    'x' != val[1] ||
2850b5e14a13SCy Schubert 				    !hextolfp(val + 2, &mon->first))
2851b5e14a13SCy Schubert 					goto nomatch;
2852b5e14a13SCy Schubert 				MGOT(MRU_GOT_FIRST);
2853b5e14a13SCy Schubert 				break;
2854b5e14a13SCy Schubert 
2855b5e14a13SCy Schubert 			case 'n':
2856b5e14a13SCy Schubert 				if (!strcmp(tag, "nonce")) {
2857b5e14a13SCy Schubert 					strlcpy(nonce, val, sizeof(nonce));
2858b5e14a13SCy Schubert 					nonce_uses = 0;
2859b5e14a13SCy Schubert 					break; /* case */
2860b5e14a13SCy Schubert 				} else if (strcmp(tag, "now") ||
2861b5e14a13SCy Schubert 					   '0' != val[0] ||
2862b5e14a13SCy Schubert 					   'x' != val[1] ||
2863b5e14a13SCy Schubert 					    !hextolfp(val + 2, pnow))
2864b5e14a13SCy Schubert 					goto nomatch;
2865b5e14a13SCy Schubert 				have_now = TRUE;
2866b5e14a13SCy Schubert 				break;
2867b5e14a13SCy Schubert 
2868b5e14a13SCy Schubert 			case 'c':
2869b5e14a13SCy Schubert 				if (1 != sscanf(tag, "ct.%d", &si) ||
2870b5e14a13SCy Schubert 				    si != ci ||
2871b5e14a13SCy Schubert 				    1 != sscanf(val, "%d", &mon->count)
2872b5e14a13SCy Schubert 				    || mon->count < 1)
2873b5e14a13SCy Schubert 					goto nomatch;
2874b5e14a13SCy Schubert 				MGOT(MRU_GOT_COUNT);
2875b5e14a13SCy Schubert 				break;
2876b5e14a13SCy Schubert 
2877b5e14a13SCy Schubert 			case 'm':
2878b5e14a13SCy Schubert 				if (1 != sscanf(tag, "mv.%d", &si) ||
2879b5e14a13SCy Schubert 				    si != ci ||
2880b5e14a13SCy Schubert 				    1 != sscanf(val, "%d", &mv))
2881b5e14a13SCy Schubert 					goto nomatch;
2882b5e14a13SCy Schubert 				mon->mode = PKT_MODE(mv);
2883b5e14a13SCy Schubert 				mon->ver = PKT_VERSION(mv);
2884b5e14a13SCy Schubert 				MGOT(MRU_GOT_MV);
2885b5e14a13SCy Schubert 				break;
2886b5e14a13SCy Schubert 
2887b5e14a13SCy Schubert 			case 'r':
2888b5e14a13SCy Schubert 				if (1 != sscanf(tag, "rs.%d", &si) ||
2889b5e14a13SCy Schubert 				    si != ci ||
2890b5e14a13SCy Schubert 				    1 != sscanf(val, "0x%hx", &mon->rs))
2891b5e14a13SCy Schubert 					goto nomatch;
2892b5e14a13SCy Schubert 				MGOT(MRU_GOT_RS);
2893b5e14a13SCy Schubert 				break;
2894b5e14a13SCy Schubert 
2895b5e14a13SCy Schubert 			default:
2896b5e14a13SCy Schubert 			nomatch:
2897b5e14a13SCy Schubert 				/* empty stmt */ ;
2898b5e14a13SCy Schubert 				/* ignore unknown tags */
2899b5e14a13SCy Schubert 			}
2900b5e14a13SCy Schubert 		}
2901b5e14a13SCy Schubert 		if (have_now)
2902b5e14a13SCy Schubert 			list_complete = TRUE;
2903b5e14a13SCy Schubert 		if (list_complete) {
29040b0c40a7SGleb Smirnoff 			INSIST(0 == ri || have_addr_older);
2905b5e14a13SCy Schubert 		}
2906b5e14a13SCy Schubert 		if (mrulist_interrupted) {
2907b5e14a13SCy Schubert 			printf("mrulist retrieval interrupted by operator.\n"
2908b5e14a13SCy Schubert 			       "Displaying partial client list.\n");
2909b5e14a13SCy Schubert 			fflush(stdout);
2910b5e14a13SCy Schubert 		}
2911b5e14a13SCy Schubert 		if (list_complete || mrulist_interrupted) {
29125171bc9bSCy Schubert 			xprintf(stderr,
2913b5e14a13SCy Schubert 				"\rRetrieved %u unique MRU entries and %u updates.\n",
2914b5e14a13SCy Schubert 				mru_count, mru_dupes);
2915b5e14a13SCy Schubert 			fflush(stderr);
2916b5e14a13SCy Schubert 			break;
2917b5e14a13SCy Schubert 		}
2918b5e14a13SCy Schubert 		if (time(NULL) >= next_report) {
2919b5e14a13SCy Schubert 			next_report += MRU_REPORT_SECS;
29205171bc9bSCy Schubert 			xprintf(stderr, "\r%u (%u updates) ", mru_count,
2921b5e14a13SCy Schubert 				mru_dupes);
2922b5e14a13SCy Schubert 			fflush(stderr);
2923b5e14a13SCy Schubert 		}
2924b5e14a13SCy Schubert 
2925b5e14a13SCy Schubert 		/*
2926b5e14a13SCy Schubert 		 * Snooze for a bit between queries to let ntpd catch
2927b5e14a13SCy Schubert 		 * up with other duties.
2928b5e14a13SCy Schubert 		 */
2929b5e14a13SCy Schubert #ifdef SYS_WINNT
2930b5e14a13SCy Schubert 		Sleep(sleep_msecs);
2931b5e14a13SCy Schubert #elif !defined(HAVE_NANOSLEEP)
2932b5e14a13SCy Schubert 		sleep((sleep_msecs / 1000) + 1);
2933b5e14a13SCy Schubert #else
2934b5e14a13SCy Schubert 		{
2935b5e14a13SCy Schubert 			struct timespec interv = { 0,
2936b5e14a13SCy Schubert 						   1000 * sleep_msecs };
2937b5e14a13SCy Schubert 			nanosleep(&interv, NULL);
2938b5e14a13SCy Schubert 		}
2939b5e14a13SCy Schubert #endif
2940b5e14a13SCy Schubert 		/*
2941b5e14a13SCy Schubert 		 * If there were no errors, increase the number of rows
2942b5e14a13SCy Schubert 		 * to a maximum of 3 * MAXFRAGS (the most packets ntpq
2943b5e14a13SCy Schubert 		 * can handle in one response), on the assumption that
2944b5e14a13SCy Schubert 		 * no less than 3 rows fit in each packet, capped at
2945b5e14a13SCy Schubert 		 * our best guess at the server's row limit.
2946b5e14a13SCy Schubert 		 */
2947b5e14a13SCy Schubert 		if (!qres) {
2948b5e14a13SCy Schubert 			if (cap_frags) {
2949b5e14a13SCy Schubert 				frags = min(MAXFRAGS, frags + 1);
2950b5e14a13SCy Schubert 			} else {
2951b5e14a13SCy Schubert 				limit = min3(3 * MAXFRAGS,
2952b5e14a13SCy Schubert 					     ntpd_row_limit,
2953b5e14a13SCy Schubert 					     max(limit + 1,
2954b5e14a13SCy Schubert 					         limit * 33 / 32));
2955b5e14a13SCy Schubert 			}
2956b5e14a13SCy Schubert 		}
2957b5e14a13SCy Schubert 		/*
2958b5e14a13SCy Schubert 		 * prepare next query with as many address and last-seen
2959b5e14a13SCy Schubert 		 * timestamps as will fit in a single packet.
2960b5e14a13SCy Schubert 		 */
2961b5e14a13SCy Schubert 		req = req_buf;
2962b5e14a13SCy Schubert 		req_end = req_buf + sizeof(req_buf);
2963b5e14a13SCy Schubert #define REQ_ROOM	(req_end - req)
2964b5e14a13SCy Schubert 		snprintf(req, REQ_ROOM, "nonce=%s, %s=%d%s", nonce,
2965b5e14a13SCy Schubert 			 (cap_frags)
2966b5e14a13SCy Schubert 			     ? "frags"
2967b5e14a13SCy Schubert 			     : "limit",
2968b5e14a13SCy Schubert 			 (cap_frags)
2969b5e14a13SCy Schubert 			     ? frags
2970b5e14a13SCy Schubert 			     : limit,
2971b5e14a13SCy Schubert 			 parms);
2972b5e14a13SCy Schubert 		req += strlen(req);
2973b5e14a13SCy Schubert 		nonce_uses++;
2974b5e14a13SCy Schubert 		if (nonce_uses >= 4) {
2975b5e14a13SCy Schubert 			if (!fetch_nonce(nonce, sizeof(nonce)))
2976b5e14a13SCy Schubert 				goto cleanup_return;
2977b5e14a13SCy Schubert 			nonce_uses = 0;
2978b5e14a13SCy Schubert 		}
2979b5e14a13SCy Schubert 
2980b5e14a13SCy Schubert 
2981b5e14a13SCy Schubert 		for (ri = 0, recent = HEAD_DLIST(mru_list, mlink);
2982b5e14a13SCy Schubert 		     recent != NULL;
2983b5e14a13SCy Schubert 		     ri++, recent = NEXT_DLIST(mru_list, recent, mlink)) {
2984b5e14a13SCy Schubert 
2985b5e14a13SCy Schubert 			snprintf(buf, sizeof(buf),
2986b5e14a13SCy Schubert 				 ", addr.%d=%s, last.%d=0x%08x.%08x",
2987b5e14a13SCy Schubert 				 ri, sptoa(&recent->addr), ri,
2988b5e14a13SCy Schubert 				 recent->last.l_ui, recent->last.l_uf);
2989b5e14a13SCy Schubert 			chars = strlen(buf);
2990cbb26d1bSXin LI 			if ((size_t)REQ_ROOM <= chars)
2991b5e14a13SCy Schubert 				break;
2992b5e14a13SCy Schubert 			memcpy(req, buf, chars + 1);
2993b5e14a13SCy Schubert 			req += chars;
2994b5e14a13SCy Schubert 		}
2995b5e14a13SCy Schubert 	}
2996b5e14a13SCy Schubert 
2997b5e14a13SCy Schubert 	c_mru_l_rc = TRUE;
2998b5e14a13SCy Schubert 	goto retain_hash_table;
2999b5e14a13SCy Schubert 
3000b5e14a13SCy Schubert cleanup_return:
3001b5e14a13SCy Schubert 	free(hash_table);
3002b5e14a13SCy Schubert 	hash_table = NULL;
3003b5e14a13SCy Schubert 
3004b5e14a13SCy Schubert retain_hash_table:
3005b5e14a13SCy Schubert 	if (mon != NULL)
3006b5e14a13SCy Schubert 		free(mon);
3007b5e14a13SCy Schubert 
3008b5e14a13SCy Schubert 	return c_mru_l_rc;
3009b5e14a13SCy Schubert }
3010b5e14a13SCy Schubert 
3011b5e14a13SCy Schubert 
3012b5e14a13SCy Schubert /*
3013b5e14a13SCy Schubert  * qcmp_mru_addr - sort MRU entries by remote address.
3014b5e14a13SCy Schubert  *
3015b5e14a13SCy Schubert  * All IPv4 addresses sort before any IPv6, addresses are sorted by
3016b5e14a13SCy Schubert  * value within address family.
3017b5e14a13SCy Schubert  */
3018b5e14a13SCy Schubert static int
qcmp_mru_addr(const void * v1,const void * v2)3019b5e14a13SCy Schubert qcmp_mru_addr(
3020b5e14a13SCy Schubert 	const void *v1,
3021b5e14a13SCy Schubert 	const void *v2
3022b5e14a13SCy Schubert 	)
3023b5e14a13SCy Schubert {
3024b5e14a13SCy Schubert 	const mru * const *	ppm1 = v1;
3025b5e14a13SCy Schubert 	const mru * const *	ppm2 = v2;
3026b5e14a13SCy Schubert 	const mru *		pm1;
3027b5e14a13SCy Schubert 	const mru *		pm2;
3028b5e14a13SCy Schubert 	u_short			af1;
3029b5e14a13SCy Schubert 	u_short			af2;
3030b5e14a13SCy Schubert 	size_t			cmplen;
3031b5e14a13SCy Schubert 	size_t			addr_off;
3032b5e14a13SCy Schubert 
3033b5e14a13SCy Schubert 	pm1 = *ppm1;
3034b5e14a13SCy Schubert 	pm2 = *ppm2;
3035b5e14a13SCy Schubert 
3036b5e14a13SCy Schubert 	af1 = AF(&pm1->addr);
3037b5e14a13SCy Schubert 	af2 = AF(&pm2->addr);
3038b5e14a13SCy Schubert 
3039b5e14a13SCy Schubert 	if (af1 != af2)
3040b5e14a13SCy Schubert 		return (AF_INET == af1)
3041b5e14a13SCy Schubert 			   ? -1
3042b5e14a13SCy Schubert 			   : 1;
3043b5e14a13SCy Schubert 
3044b5e14a13SCy Schubert 	cmplen = SIZEOF_INADDR(af1);
3045b5e14a13SCy Schubert 	addr_off = (AF_INET == af1)
3046b5e14a13SCy Schubert 		      ? offsetof(struct sockaddr_in, sin_addr)
3047b5e14a13SCy Schubert 		      : offsetof(struct sockaddr_in6, sin6_addr);
3048b5e14a13SCy Schubert 
3049b5e14a13SCy Schubert 	return memcmp((const char *)&pm1->addr + addr_off,
3050b5e14a13SCy Schubert 		      (const char *)&pm2->addr + addr_off,
3051b5e14a13SCy Schubert 		      cmplen);
3052b5e14a13SCy Schubert }
3053b5e14a13SCy Schubert 
3054b5e14a13SCy Schubert 
3055b5e14a13SCy Schubert static int
qcmp_mru_r_addr(const void * v1,const void * v2)3056b5e14a13SCy Schubert qcmp_mru_r_addr(
3057b5e14a13SCy Schubert 	const void *v1,
3058b5e14a13SCy Schubert 	const void *v2
3059b5e14a13SCy Schubert 	)
3060b5e14a13SCy Schubert {
3061b5e14a13SCy Schubert 	return -qcmp_mru_addr(v1, v2);
3062b5e14a13SCy Schubert }
3063b5e14a13SCy Schubert 
3064b5e14a13SCy Schubert 
3065b5e14a13SCy Schubert /*
3066b5e14a13SCy Schubert  * qcmp_mru_count - sort MRU entries by times seen (hit count).
3067b5e14a13SCy Schubert  */
3068b5e14a13SCy Schubert static int
qcmp_mru_count(const void * v1,const void * v2)3069b5e14a13SCy Schubert qcmp_mru_count(
3070b5e14a13SCy Schubert 	const void *v1,
3071b5e14a13SCy Schubert 	const void *v2
3072b5e14a13SCy Schubert 	)
3073b5e14a13SCy Schubert {
3074b5e14a13SCy Schubert 	const mru * const *	ppm1 = v1;
3075b5e14a13SCy Schubert 	const mru * const *	ppm2 = v2;
3076b5e14a13SCy Schubert 	const mru *		pm1;
3077b5e14a13SCy Schubert 	const mru *		pm2;
3078b5e14a13SCy Schubert 
3079b5e14a13SCy Schubert 	pm1 = *ppm1;
3080b5e14a13SCy Schubert 	pm2 = *ppm2;
3081b5e14a13SCy Schubert 
3082b5e14a13SCy Schubert 	return (pm1->count < pm2->count)
3083b5e14a13SCy Schubert 		   ? -1
3084b5e14a13SCy Schubert 		   : ((pm1->count == pm2->count)
3085b5e14a13SCy Schubert 			  ? 0
3086b5e14a13SCy Schubert 			  : 1);
3087b5e14a13SCy Schubert }
3088b5e14a13SCy Schubert 
3089b5e14a13SCy Schubert 
3090b5e14a13SCy Schubert static int
qcmp_mru_r_count(const void * v1,const void * v2)3091b5e14a13SCy Schubert qcmp_mru_r_count(
3092b5e14a13SCy Schubert 	const void *v1,
3093b5e14a13SCy Schubert 	const void *v2
3094b5e14a13SCy Schubert 	)
3095b5e14a13SCy Schubert {
3096b5e14a13SCy Schubert 	return -qcmp_mru_count(v1, v2);
3097b5e14a13SCy Schubert }
3098b5e14a13SCy Schubert 
3099b5e14a13SCy Schubert 
3100b5e14a13SCy Schubert /*
3101b5e14a13SCy Schubert  * qcmp_mru_avgint - sort MRU entries by average interval.
3102b5e14a13SCy Schubert  */
3103b5e14a13SCy Schubert static int
qcmp_mru_avgint(const void * v1,const void * v2)3104b5e14a13SCy Schubert qcmp_mru_avgint(
3105b5e14a13SCy Schubert 	const void *v1,
3106b5e14a13SCy Schubert 	const void *v2
3107b5e14a13SCy Schubert 	)
3108b5e14a13SCy Schubert {
3109b5e14a13SCy Schubert 	const mru * const *	ppm1 = v1;
3110b5e14a13SCy Schubert 	const mru * const *	ppm2 = v2;
3111b5e14a13SCy Schubert 	const mru *		pm1;
3112b5e14a13SCy Schubert 	const mru *		pm2;
3113b5e14a13SCy Schubert 	l_fp			interval;
3114b5e14a13SCy Schubert 	double			avg1;
3115b5e14a13SCy Schubert 	double			avg2;
3116b5e14a13SCy Schubert 
3117b5e14a13SCy Schubert 	pm1 = *ppm1;
3118b5e14a13SCy Schubert 	pm2 = *ppm2;
3119b5e14a13SCy Schubert 
3120b5e14a13SCy Schubert 	interval = pm1->last;
3121b5e14a13SCy Schubert 	L_SUB(&interval, &pm1->first);
3122b5e14a13SCy Schubert 	LFPTOD(&interval, avg1);
3123b5e14a13SCy Schubert 	avg1 /= pm1->count;
3124b5e14a13SCy Schubert 
3125b5e14a13SCy Schubert 	interval = pm2->last;
3126b5e14a13SCy Schubert 	L_SUB(&interval, &pm2->first);
3127b5e14a13SCy Schubert 	LFPTOD(&interval, avg2);
3128b5e14a13SCy Schubert 	avg2 /= pm2->count;
3129b5e14a13SCy Schubert 
3130b5e14a13SCy Schubert 	if (avg1 < avg2)
3131b5e14a13SCy Schubert 		return -1;
3132b5e14a13SCy Schubert 	else if (avg1 > avg2)
3133b5e14a13SCy Schubert 		return 1;
3134b5e14a13SCy Schubert 
3135b5e14a13SCy Schubert 	/* secondary sort on lstint - rarely tested */
3136b5e14a13SCy Schubert 	if (L_ISEQU(&pm1->last, &pm2->last))
3137b5e14a13SCy Schubert 		return 0;
3138b5e14a13SCy Schubert 	else if (L_ISGEQ(&pm1->last, &pm2->last))
3139b5e14a13SCy Schubert 		return -1;
3140b5e14a13SCy Schubert 	else
3141b5e14a13SCy Schubert 		return 1;
3142b5e14a13SCy Schubert }
3143b5e14a13SCy Schubert 
3144b5e14a13SCy Schubert 
3145b5e14a13SCy Schubert static int
qcmp_mru_r_avgint(const void * v1,const void * v2)3146b5e14a13SCy Schubert qcmp_mru_r_avgint(
3147b5e14a13SCy Schubert 	const void *v1,
3148b5e14a13SCy Schubert 	const void *v2
3149b5e14a13SCy Schubert 	)
3150b5e14a13SCy Schubert {
3151b5e14a13SCy Schubert 	return -qcmp_mru_avgint(v1, v2);
3152b5e14a13SCy Schubert }
3153b5e14a13SCy Schubert 
3154b5e14a13SCy Schubert 
3155b5e14a13SCy Schubert /*
3156b5e14a13SCy Schubert  * mrulist - ntpq's mrulist command to fetch an arbitrarily large Most
3157b5e14a13SCy Schubert  *	     Recently Used (seen) remote address list from ntpd.
3158b5e14a13SCy Schubert  *
3159b5e14a13SCy Schubert  * Similar to ntpdc's monlist command, but not limited to a single
3160b5e14a13SCy Schubert  * request/response, and thereby not limited to a few hundred remote
3161b5e14a13SCy Schubert  * addresses.
3162b5e14a13SCy Schubert  *
3163b5e14a13SCy Schubert  * See ntpd/ntp_control.c read_mru_list() for comments on the way
3164b5e14a13SCy Schubert  * CTL_OP_READ_MRU is designed to be used.
3165b5e14a13SCy Schubert  *
3166b5e14a13SCy Schubert  * mrulist intentionally differs from monlist in the way the avgint
3167b5e14a13SCy Schubert  * column is calculated.  monlist includes the time after the last
3168b5e14a13SCy Schubert  * packet from the client until the monlist query time in the average,
3169b5e14a13SCy Schubert  * while mrulist excludes it.  That is, monlist's average interval grows
3170b5e14a13SCy Schubert  * over time for remote addresses not heard from in some time, while it
3171b5e14a13SCy Schubert  * remains unchanged in mrulist.  This also affects the avgint value for
3172b5e14a13SCy Schubert  * entries representing a single packet, with identical first and last
3173b5e14a13SCy Schubert  * timestamps.  mrulist shows 0 avgint, monlist shows a value identical
3174b5e14a13SCy Schubert  * to lstint.
3175b5e14a13SCy Schubert  */
3176b5e14a13SCy Schubert static void
mrulist(struct parse * pcmd,FILE * fp)3177b5e14a13SCy Schubert mrulist(
3178b5e14a13SCy Schubert 	struct parse *	pcmd,
3179b5e14a13SCy Schubert 	FILE *		fp
3180b5e14a13SCy Schubert 	)
3181b5e14a13SCy Schubert {
3182b5e14a13SCy Schubert 	const char mincount_eq[] =	"mincount=";
3183b5e14a13SCy Schubert 	const char resall_eq[] =	"resall=";
3184b5e14a13SCy Schubert 	const char resany_eq[] =	"resany=";
3185b5e14a13SCy Schubert 	const char maxlstint_eq[] =	"maxlstint=";
3186b5e14a13SCy Schubert 	const char laddr_eq[] =		"laddr=";
3187b5e14a13SCy Schubert 	const char sort_eq[] =		"sort=";
3188b5e14a13SCy Schubert 	mru_sort_order order;
3189b5e14a13SCy Schubert 	size_t n;
3190b5e14a13SCy Schubert 	char parms_buf[128];
3191b5e14a13SCy Schubert 	char buf[24];
3192b5e14a13SCy Schubert 	char *parms;
3193b5e14a13SCy Schubert 	const char *arg;
3194b5e14a13SCy Schubert 	size_t cb;
3195b5e14a13SCy Schubert 	mru **sorted;
3196b5e14a13SCy Schubert 	mru **ppentry;
3197b5e14a13SCy Schubert 	mru *recent;
3198b5e14a13SCy Schubert 	l_fp now;
3199b5e14a13SCy Schubert 	l_fp interval;
3200b5e14a13SCy Schubert 	double favgint;
3201b5e14a13SCy Schubert 	double flstint;
3202b5e14a13SCy Schubert 	int avgint;
3203b5e14a13SCy Schubert 	int lstint;
3204f7cba3a8SCy Schubert 	size_t i;
3205b5e14a13SCy Schubert 
3206c373d928SXin LI 	mrulist_interrupted = FALSE;
3207c373d928SXin LI 	push_ctrl_c_handler(&mrulist_ctrl_c_hook);
32085171bc9bSCy Schubert 	xprintf(stderr,
3209c373d928SXin LI 		"Ctrl-C will stop MRU retrieval and display partial results.\n");
3210c373d928SXin LI 	fflush(stderr);
3211c373d928SXin LI 
3212b5e14a13SCy Schubert 	order = MRUSORT_DEF;
3213b5e14a13SCy Schubert 	parms_buf[0] = '\0';
3214b5e14a13SCy Schubert 	parms = parms_buf;
3215b5e14a13SCy Schubert 	for (i = 0; i < pcmd->nargs; i++) {
3216b5e14a13SCy Schubert 		arg = pcmd->argval[i].string;
3217b5e14a13SCy Schubert 		if (arg != NULL) {
3218b5e14a13SCy Schubert 			cb = strlen(arg) + 1;
3219b5e14a13SCy Schubert 			if ((!strncmp(resall_eq, arg, sizeof(resall_eq)
3220b5e14a13SCy Schubert 			    - 1) || !strncmp(resany_eq, arg,
3221b5e14a13SCy Schubert 			    sizeof(resany_eq) - 1) || !strncmp(
3222b5e14a13SCy Schubert 			    mincount_eq, arg, sizeof(mincount_eq) - 1)
3223b5e14a13SCy Schubert 			    || !strncmp(laddr_eq, arg, sizeof(laddr_eq)
3224b5e14a13SCy Schubert 			    - 1) || !strncmp(maxlstint_eq, arg,
3225b5e14a13SCy Schubert 			    sizeof(laddr_eq) - 1)) && parms + cb + 2 <=
3226b5e14a13SCy Schubert 			    parms_buf + sizeof(parms_buf)) {
3227b5e14a13SCy Schubert 				/* these are passed intact to ntpd */
3228b5e14a13SCy Schubert 				memcpy(parms, ", ", 2);
3229b5e14a13SCy Schubert 				parms += 2;
3230b5e14a13SCy Schubert 				memcpy(parms, arg, cb);
3231b5e14a13SCy Schubert 				parms += cb - 1;
3232b5e14a13SCy Schubert 			} else if (!strncmp(sort_eq, arg,
3233b5e14a13SCy Schubert 					    sizeof(sort_eq) - 1)) {
3234b5e14a13SCy Schubert 				arg += sizeof(sort_eq) - 1;
3235b5e14a13SCy Schubert 				for (n = 0;
3236b5e14a13SCy Schubert 				     n < COUNTOF(mru_sort_keywords);
3237b5e14a13SCy Schubert 				     n++)
3238b5e14a13SCy Schubert 					if (!strcmp(mru_sort_keywords[n],
3239b5e14a13SCy Schubert 						    arg))
3240b5e14a13SCy Schubert 						break;
3241b5e14a13SCy Schubert 				if (n < COUNTOF(mru_sort_keywords))
3242b5e14a13SCy Schubert 					order = n;
3243b5e14a13SCy Schubert 			} else if (!strcmp("limited", arg) ||
3244b5e14a13SCy Schubert 				   !strcmp("kod", arg)) {
3245b5e14a13SCy Schubert 				/* transform to resany=... */
3246b5e14a13SCy Schubert 				snprintf(buf, sizeof(buf),
3247b5e14a13SCy Schubert 					 ", resany=0x%x",
3248b5e14a13SCy Schubert 					 ('k' == arg[0])
3249b5e14a13SCy Schubert 					     ? RES_KOD
3250b5e14a13SCy Schubert 					     : RES_LIMITED);
3251b5e14a13SCy Schubert 				cb = 1 + strlen(buf);
3252b5e14a13SCy Schubert 				if (parms + cb <
3253b5e14a13SCy Schubert 					parms_buf + sizeof(parms_buf)) {
3254b5e14a13SCy Schubert 					memcpy(parms, buf, cb);
3255b5e14a13SCy Schubert 					parms += cb - 1;
3256b5e14a13SCy Schubert 				}
3257b5e14a13SCy Schubert 			} else
32585171bc9bSCy Schubert 				xprintf(stderr,
3259b5e14a13SCy Schubert 					"ignoring unrecognized mrulist parameter: %s\n",
3260b5e14a13SCy Schubert 					arg);
3261b5e14a13SCy Schubert 		}
3262b5e14a13SCy Schubert 	}
3263b5e14a13SCy Schubert 	parms = parms_buf;
3264b5e14a13SCy Schubert 
3265b5e14a13SCy Schubert 	if (!collect_mru_list(parms, &now))
3266b5e14a13SCy Schubert 		return;
3267b5e14a13SCy Schubert 
3268b5e14a13SCy Schubert 	/* display the results */
3269b5e14a13SCy Schubert 	if (rawmode)
3270b5e14a13SCy Schubert 		goto cleanup_return;
3271b5e14a13SCy Schubert 
3272b5e14a13SCy Schubert 	/* construct an array of entry pointers in default order */
3273873997f3SCy Schubert 	sorted = eallocarray(mru_count, sizeof(*sorted));
3274b5e14a13SCy Schubert 	ppentry = sorted;
3275b5e14a13SCy Schubert 	if (MRUSORT_R_DEF != order) {
3276b5e14a13SCy Schubert 		ITER_DLIST_BEGIN(mru_list, recent, mlink, mru)
32770b0c40a7SGleb Smirnoff 			INSIST(ppentry < sorted + mru_count);
3278b5e14a13SCy Schubert 			*ppentry = recent;
3279b5e14a13SCy Schubert 			ppentry++;
3280b5e14a13SCy Schubert 		ITER_DLIST_END()
3281b5e14a13SCy Schubert 	} else {
3282b5e14a13SCy Schubert 		REV_ITER_DLIST_BEGIN(mru_list, recent, mlink, mru)
32830b0c40a7SGleb Smirnoff 			INSIST(ppentry < sorted + mru_count);
3284b5e14a13SCy Schubert 			*ppentry = recent;
3285b5e14a13SCy Schubert 			ppentry++;
3286b5e14a13SCy Schubert 		REV_ITER_DLIST_END()
3287b5e14a13SCy Schubert 	}
3288b5e14a13SCy Schubert 
3289b5e14a13SCy Schubert 	if (ppentry - sorted != (int)mru_count) {
32905171bc9bSCy Schubert 		xprintf(stderr,
3291b5e14a13SCy Schubert 			"mru_count %u should match MRU list depth %ld.\n",
3292b5e14a13SCy Schubert 			mru_count, (long)(ppentry - sorted));
3293b5e14a13SCy Schubert 		free(sorted);
3294b5e14a13SCy Schubert 		goto cleanup_return;
3295b5e14a13SCy Schubert 	}
3296b5e14a13SCy Schubert 
3297b5e14a13SCy Schubert 	/* re-sort sorted[] if not default or reverse default */
3298b5e14a13SCy Schubert 	if (MRUSORT_R_DEF < order)
3299b5e14a13SCy Schubert 		qsort(sorted, mru_count, sizeof(sorted[0]),
3300b5e14a13SCy Schubert 		      mru_qcmp_table[order]);
3301b5e14a13SCy Schubert 
3302cbb26d1bSXin LI 	mrulist_interrupted = FALSE;
3303b5e14a13SCy Schubert 	printf(	"lstint avgint rstr r m v  count rport remote address\n"
3304b5e14a13SCy Schubert 		"==============================================================================\n");
3305b5e14a13SCy Schubert 		/* '=' x 78 */
3306b5e14a13SCy Schubert 	for (ppentry = sorted; ppentry < sorted + mru_count; ppentry++) {
3307b5e14a13SCy Schubert 		recent = *ppentry;
3308b5e14a13SCy Schubert 		interval = now;
3309b5e14a13SCy Schubert 		L_SUB(&interval, &recent->last);
3310b5e14a13SCy Schubert 		LFPTOD(&interval, flstint);
3311b5e14a13SCy Schubert 		lstint = (int)(flstint + 0.5);
3312b5e14a13SCy Schubert 		interval = recent->last;
3313b5e14a13SCy Schubert 		L_SUB(&interval, &recent->first);
3314b5e14a13SCy Schubert 		LFPTOD(&interval, favgint);
3315b5e14a13SCy Schubert 		favgint /= recent->count;
3316b5e14a13SCy Schubert 		avgint = (int)(favgint + 0.5);
33175171bc9bSCy Schubert 		xprintf(fp, "%6d %6d %4hx %c %d %d %6d %5u %s\n",
3318b5e14a13SCy Schubert 			lstint, avgint, recent->rs,
3319b5e14a13SCy Schubert 			(RES_KOD & recent->rs)
3320b5e14a13SCy Schubert 			    ? 'K'
3321b5e14a13SCy Schubert 			    : (RES_LIMITED & recent->rs)
3322b5e14a13SCy Schubert 				  ? 'L'
3323b5e14a13SCy Schubert 				  : '.',
3324b5e14a13SCy Schubert 			(int)recent->mode, (int)recent->ver,
3325b5e14a13SCy Schubert 			recent->count, SRCPORT(&recent->addr),
3326b5e14a13SCy Schubert 			nntohost(&recent->addr));
3327b5e14a13SCy Schubert 		if (showhostnames)
3328b5e14a13SCy Schubert 			fflush(fp);
3329cbb26d1bSXin LI 		if (mrulist_interrupted) {
33305171bc9bSCy Schubert 			xputs("\n --interrupted--\n", fp);
3331cbb26d1bSXin LI 			fflush(fp);
3332cbb26d1bSXin LI 			break;
3333cbb26d1bSXin LI 		}
3334b5e14a13SCy Schubert 	}
3335b5e14a13SCy Schubert 	fflush(fp);
3336b5e14a13SCy Schubert 	if (debug) {
33375171bc9bSCy Schubert 		xprintf(stderr,
3338b5e14a13SCy Schubert 			"--- completed, freeing sorted[] pointers\n");
3339b5e14a13SCy Schubert 		fflush(stderr);
3340b5e14a13SCy Schubert 	}
3341b5e14a13SCy Schubert 	free(sorted);
3342b5e14a13SCy Schubert 
3343b5e14a13SCy Schubert cleanup_return:
3344b5e14a13SCy Schubert 	if (debug) {
33455171bc9bSCy Schubert 		xprintf(stderr, "... freeing MRU entries\n");
3346b5e14a13SCy Schubert 		fflush(stderr);
3347b5e14a13SCy Schubert 	}
3348b5e14a13SCy Schubert 	ITER_DLIST_BEGIN(mru_list, recent, mlink, mru)
3349b5e14a13SCy Schubert 		free(recent);
3350b5e14a13SCy Schubert 	ITER_DLIST_END()
3351b5e14a13SCy Schubert 	if (debug) {
33525171bc9bSCy Schubert 		xprintf(stderr, "... freeing hash_table[]\n");
3353b5e14a13SCy Schubert 		fflush(stderr);
3354b5e14a13SCy Schubert 	}
3355b5e14a13SCy Schubert 	free(hash_table);
3356b5e14a13SCy Schubert 	hash_table = NULL;
3357b5e14a13SCy Schubert 	INIT_DLIST(mru_list, mlink);
3358c373d928SXin LI 
3359c373d928SXin LI 	pop_ctrl_c_handler(&mrulist_ctrl_c_hook);
3360b5e14a13SCy Schubert }
3361b5e14a13SCy Schubert 
3362b5e14a13SCy Schubert 
3363b5e14a13SCy Schubert /*
3364b5e14a13SCy Schubert  * validate_ifnum - helper for ifstats()
3365b5e14a13SCy Schubert  *
3366b5e14a13SCy Schubert  * Ensures rows are received in order and complete.
3367b5e14a13SCy Schubert  */
3368b5e14a13SCy Schubert static void
validate_ifnum(FILE * fp,u_int ifnum,int * pfields,ifstats_row * prow)3369b5e14a13SCy Schubert validate_ifnum(
3370b5e14a13SCy Schubert 	FILE *		fp,
3371b5e14a13SCy Schubert 	u_int		ifnum,
3372b5e14a13SCy Schubert 	int *		pfields,
3373b5e14a13SCy Schubert 	ifstats_row *	prow
3374b5e14a13SCy Schubert 	)
3375b5e14a13SCy Schubert {
3376b5e14a13SCy Schubert 	if (prow->ifnum == ifnum)
3377b5e14a13SCy Schubert 		return;
3378873997f3SCy Schubert 	if (prow->ifnum + 1 <= ifnum) {
3379b5e14a13SCy Schubert 		if (*pfields < IFSTATS_FIELDS)
33805171bc9bSCy Schubert 			xprintf(fp, "Warning: incomplete row with %d (of %d) fields\n",
3381b5e14a13SCy Schubert 				*pfields, IFSTATS_FIELDS);
3382b5e14a13SCy Schubert 		*pfields = 0;
3383b5e14a13SCy Schubert 		prow->ifnum = ifnum;
3384b5e14a13SCy Schubert 		return;
3385b5e14a13SCy Schubert 	}
33865171bc9bSCy Schubert 	xprintf(stderr,
3387b5e14a13SCy Schubert 		"received if index %u, have %d of %d fields for index %u, aborting.\n",
3388b5e14a13SCy Schubert 		ifnum, *pfields, IFSTATS_FIELDS, prow->ifnum);
3389b5e14a13SCy Schubert 	exit(1);
3390b5e14a13SCy Schubert }
3391b5e14a13SCy Schubert 
3392b5e14a13SCy Schubert 
3393b5e14a13SCy Schubert /*
3394b5e14a13SCy Schubert  * another_ifstats_field - helper for ifstats()
3395b5e14a13SCy Schubert  *
3396b5e14a13SCy Schubert  * If all fields for the row have been received, print it.
3397b5e14a13SCy Schubert  */
3398b5e14a13SCy Schubert static void
another_ifstats_field(int * pfields,ifstats_row * prow,FILE * fp)3399b5e14a13SCy Schubert another_ifstats_field(
3400b5e14a13SCy Schubert 	int *		pfields,
3401b5e14a13SCy Schubert 	ifstats_row *	prow,
3402b5e14a13SCy Schubert 	FILE *		fp
3403b5e14a13SCy Schubert 	)
3404b5e14a13SCy Schubert {
3405b5e14a13SCy Schubert 	u_int ifnum;
3406b5e14a13SCy Schubert 
3407b5e14a13SCy Schubert 	(*pfields)++;
3408b5e14a13SCy Schubert 	/* we understand 12 tags */
3409b5e14a13SCy Schubert 	if (IFSTATS_FIELDS > *pfields)
3410b5e14a13SCy Schubert 		return;
3411b5e14a13SCy Schubert 	/*
3412b5e14a13SCy Schubert 	"    interface name                                        send\n"
3413b5e14a13SCy Schubert 	" #  address/broadcast     drop flag ttl mc received sent failed peers   uptime\n"
3414b5e14a13SCy Schubert 	"==============================================================================\n");
3415b5e14a13SCy Schubert 	 */
34165171bc9bSCy Schubert 	xprintf(fp,
3417d14ac12fSXin LI 		"%3u %-24.24s %c %4x %3u %2u %6u %6u %6u %5u %8d\n"
3418b5e14a13SCy Schubert 		"    %s\n",
3419b5e14a13SCy Schubert 		prow->ifnum, prow->name,
3420b5e14a13SCy Schubert 		(prow->enabled)
3421b5e14a13SCy Schubert 		    ? '.'
3422b5e14a13SCy Schubert 		    : 'D',
3423b5e14a13SCy Schubert 		prow->flags, prow->ttl, prow->mcast_count,
3424b5e14a13SCy Schubert 		prow->received, prow->sent, prow->send_errors,
3425b5e14a13SCy Schubert 		prow->peer_count, prow->uptime, sptoa(&prow->addr));
3426b5e14a13SCy Schubert 	if (!SOCK_UNSPEC(&prow->bcast))
34275171bc9bSCy Schubert 		xprintf(fp, "    %s\n", sptoa(&prow->bcast));
3428b5e14a13SCy Schubert 	ifnum = prow->ifnum;
3429b5e14a13SCy Schubert 	ZERO(*prow);
3430b5e14a13SCy Schubert 	prow->ifnum = ifnum;
3431b5e14a13SCy Schubert }
3432b5e14a13SCy Schubert 
3433b5e14a13SCy Schubert 
3434b5e14a13SCy Schubert /*
3435b5e14a13SCy Schubert  * ifstats - ntpq -c ifstats modeled on ntpdc -c ifstats.
3436b5e14a13SCy Schubert  */
3437b5e14a13SCy Schubert static void
ifstats(struct parse * pcmd,FILE * fp)3438b5e14a13SCy Schubert ifstats(
3439b5e14a13SCy Schubert 	struct parse *	pcmd,
3440b5e14a13SCy Schubert 	FILE *		fp
3441b5e14a13SCy Schubert 	)
3442b5e14a13SCy Schubert {
3443b5e14a13SCy Schubert 	const char	addr_fmt[] =	"addr.%u";
3444b5e14a13SCy Schubert 	const char	bcast_fmt[] =	"bcast.%u";
3445b5e14a13SCy Schubert 	const char	en_fmt[] =	"en.%u";	/* enabled */
3446b5e14a13SCy Schubert 	const char	flags_fmt[] =	"flags.%u";
3447b5e14a13SCy Schubert 	const char	mc_fmt[] =	"mc.%u";	/* mcast count */
3448b5e14a13SCy Schubert 	const char	name_fmt[] =	"name.%u";
3449b5e14a13SCy Schubert 	const char	pc_fmt[] =	"pc.%u";	/* peer count */
3450b5e14a13SCy Schubert 	const char	rx_fmt[] =	"rx.%u";
3451b5e14a13SCy Schubert 	const char	tl_fmt[] =	"tl.%u";	/* ttl */
3452b5e14a13SCy Schubert 	const char	tx_fmt[] =	"tx.%u";
3453b5e14a13SCy Schubert 	const char	txerr_fmt[] =	"txerr.%u";
3454b5e14a13SCy Schubert 	const char	up_fmt[] =	"up.%u";	/* uptime */
3455b5e14a13SCy Schubert 	const char *	datap;
3456b5e14a13SCy Schubert 	int		qres;
3457c373d928SXin LI 	size_t		dsize;
3458b5e14a13SCy Schubert 	u_short		rstatus;
3459b5e14a13SCy Schubert 	char *		tag;
3460b5e14a13SCy Schubert 	char *		val;
3461b5e14a13SCy Schubert 	int		fields;
3462b5e14a13SCy Schubert 	u_int		ui;
3463b5e14a13SCy Schubert 	ifstats_row	row;
3464b5e14a13SCy Schubert 	int		comprende;
3465b5e14a13SCy Schubert 	size_t		len;
3466b5e14a13SCy Schubert 
3467b5e14a13SCy Schubert 	qres = doquery(CTL_OP_READ_ORDLIST_A, 0, TRUE, 0, NULL, &rstatus,
3468b5e14a13SCy Schubert 		       &dsize, &datap);
3469b5e14a13SCy Schubert 	if (qres)	/* message already displayed */
3470b5e14a13SCy Schubert 		return;
3471b5e14a13SCy Schubert 
34725171bc9bSCy Schubert 	xprintf(fp,
3473b5e14a13SCy Schubert 		"    interface name                                        send\n"
3474b5e14a13SCy Schubert 		" #  address/broadcast     drop flag ttl mc received sent failed peers   uptime\n"
3475b5e14a13SCy Schubert 		"==============================================================================\n");
3476b5e14a13SCy Schubert 		/* '=' x 78 */
3477b5e14a13SCy Schubert 
3478b5e14a13SCy Schubert 	ZERO(row);
3479b5e14a13SCy Schubert 	fields = 0;
3480b5e14a13SCy Schubert 	ui = 0;
3481b5e14a13SCy Schubert 	while (nextvar(&dsize, &datap, &tag, &val)) {
3482c7f4d233SXin LI 		INSIST(tag && val);
3483b5e14a13SCy Schubert 		if (debug > 1)
34845171bc9bSCy Schubert 		    xprintf(stderr, "nextvar gave: %s = %s\n", tag, val);
3485b5e14a13SCy Schubert 		comprende = FALSE;
3486b5e14a13SCy Schubert 		switch(tag[0]) {
3487b5e14a13SCy Schubert 
3488b5e14a13SCy Schubert 		case 'a':
3489b5e14a13SCy Schubert 			if (1 == sscanf(tag, addr_fmt, &ui) &&
3490b5e14a13SCy Schubert 			    decodenetnum(val, &row.addr))
3491b5e14a13SCy Schubert 				comprende = TRUE;
3492b5e14a13SCy Schubert 			break;
3493b5e14a13SCy Schubert 
3494b5e14a13SCy Schubert 		case 'b':
3495b5e14a13SCy Schubert 			if (1 == sscanf(tag, bcast_fmt, &ui) &&
3496c7f4d233SXin LI 			    ('\0' == *val ||
3497b5e14a13SCy Schubert 			     decodenetnum(val, &row.bcast)))
3498b5e14a13SCy Schubert 				comprende = TRUE;
3499b5e14a13SCy Schubert 			break;
3500b5e14a13SCy Schubert 
3501b5e14a13SCy Schubert 		case 'e':
3502b5e14a13SCy Schubert 			if (1 == sscanf(tag, en_fmt, &ui) &&
3503b5e14a13SCy Schubert 			    1 == sscanf(val, "%d", &row.enabled))
3504b5e14a13SCy Schubert 				comprende = TRUE;
3505b5e14a13SCy Schubert 			break;
3506b5e14a13SCy Schubert 
3507b5e14a13SCy Schubert 		case 'f':
3508b5e14a13SCy Schubert 			if (1 == sscanf(tag, flags_fmt, &ui) &&
3509b5e14a13SCy Schubert 			    1 == sscanf(val, "0x%x", &row.flags))
3510b5e14a13SCy Schubert 				comprende = TRUE;
3511b5e14a13SCy Schubert 			break;
3512b5e14a13SCy Schubert 
3513b5e14a13SCy Schubert 		case 'm':
3514b5e14a13SCy Schubert 			if (1 == sscanf(tag, mc_fmt, &ui) &&
3515d14ac12fSXin LI 			    1 == sscanf(val, "%u", &row.mcast_count))
3516b5e14a13SCy Schubert 				comprende = TRUE;
3517b5e14a13SCy Schubert 			break;
3518b5e14a13SCy Schubert 
3519b5e14a13SCy Schubert 		case 'n':
3520b5e14a13SCy Schubert 			if (1 == sscanf(tag, name_fmt, &ui)) {
3521b5e14a13SCy Schubert 				/* strip quotes */
3522b5e14a13SCy Schubert 				len = strlen(val);
3523b5e14a13SCy Schubert 				if (len >= 2 &&
3524b5e14a13SCy Schubert 				    len - 2 < sizeof(row.name)) {
3525b5e14a13SCy Schubert 					len -= 2;
3526b5e14a13SCy Schubert 					memcpy(row.name, val + 1, len);
3527b5e14a13SCy Schubert 					row.name[len] = '\0';
3528b5e14a13SCy Schubert 					comprende = TRUE;
3529b5e14a13SCy Schubert 				}
3530b5e14a13SCy Schubert 			}
3531b5e14a13SCy Schubert 			break;
3532b5e14a13SCy Schubert 
3533b5e14a13SCy Schubert 		case 'p':
3534b5e14a13SCy Schubert 			if (1 == sscanf(tag, pc_fmt, &ui) &&
3535d14ac12fSXin LI 			    1 == sscanf(val, "%u", &row.peer_count))
3536b5e14a13SCy Schubert 				comprende = TRUE;
3537b5e14a13SCy Schubert 			break;
3538b5e14a13SCy Schubert 
3539b5e14a13SCy Schubert 		case 'r':
3540b5e14a13SCy Schubert 			if (1 == sscanf(tag, rx_fmt, &ui) &&
3541d14ac12fSXin LI 			    1 == sscanf(val, "%u", &row.received))
3542b5e14a13SCy Schubert 				comprende = TRUE;
3543b5e14a13SCy Schubert 			break;
3544b5e14a13SCy Schubert 
3545b5e14a13SCy Schubert 		case 't':
3546b5e14a13SCy Schubert 			if (1 == sscanf(tag, tl_fmt, &ui) &&
3547d14ac12fSXin LI 			    1 == sscanf(val, "%u", &row.ttl))
3548b5e14a13SCy Schubert 				comprende = TRUE;
3549b5e14a13SCy Schubert 			else if (1 == sscanf(tag, tx_fmt, &ui) &&
3550d14ac12fSXin LI 				 1 == sscanf(val, "%u", &row.sent))
3551b5e14a13SCy Schubert 				comprende = TRUE;
3552b5e14a13SCy Schubert 			else if (1 == sscanf(tag, txerr_fmt, &ui) &&
3553d14ac12fSXin LI 				 1 == sscanf(val, "%u", &row.send_errors))
3554b5e14a13SCy Schubert 				comprende = TRUE;
3555b5e14a13SCy Schubert 			break;
3556b5e14a13SCy Schubert 
3557b5e14a13SCy Schubert 		case 'u':
3558b5e14a13SCy Schubert 			if (1 == sscanf(tag, up_fmt, &ui) &&
3559d14ac12fSXin LI 			    1 == sscanf(val, "%u", &row.uptime))
3560b5e14a13SCy Schubert 				comprende = TRUE;
3561b5e14a13SCy Schubert 			break;
3562b5e14a13SCy Schubert 		}
3563b5e14a13SCy Schubert 
3564b5e14a13SCy Schubert 		if (comprende) {
3565b5e14a13SCy Schubert 			/* error out if rows out of order */
3566b5e14a13SCy Schubert 			validate_ifnum(fp, ui, &fields, &row);
3567b5e14a13SCy Schubert 			/* if the row is complete, print it */
3568b5e14a13SCy Schubert 			another_ifstats_field(&fields, &row, fp);
3569b5e14a13SCy Schubert 		}
3570b5e14a13SCy Schubert 	}
3571b5e14a13SCy Schubert 	if (fields != IFSTATS_FIELDS)
35725171bc9bSCy Schubert 		xprintf(fp, "Warning: incomplete row with %d (of %d) fields\n",
3573b5e14a13SCy Schubert 			fields, IFSTATS_FIELDS);
3574b5e14a13SCy Schubert 
3575b5e14a13SCy Schubert 	fflush(fp);
3576b5e14a13SCy Schubert }
3577b5e14a13SCy Schubert 
3578b5e14a13SCy Schubert 
3579b5e14a13SCy Schubert /*
3580b5e14a13SCy Schubert  * validate_reslist_idx - helper for reslist()
3581b5e14a13SCy Schubert  *
3582b5e14a13SCy Schubert  * Ensures rows are received in order and complete.
3583b5e14a13SCy Schubert  */
3584b5e14a13SCy Schubert static void
validate_reslist_idx(FILE * fp,u_int idx,int * pfields,reslist_row * prow)3585b5e14a13SCy Schubert validate_reslist_idx(
3586b5e14a13SCy Schubert 	FILE *		fp,
3587b5e14a13SCy Schubert 	u_int		idx,
3588b5e14a13SCy Schubert 	int *		pfields,
3589b5e14a13SCy Schubert 	reslist_row *	prow
3590b5e14a13SCy Schubert 	)
3591b5e14a13SCy Schubert {
3592b5e14a13SCy Schubert 	if (prow->idx == idx)
3593b5e14a13SCy Schubert 		return;
3594b5e14a13SCy Schubert 	if (prow->idx + 1 == idx) {
3595b5e14a13SCy Schubert 		if (*pfields < RESLIST_FIELDS)
35965171bc9bSCy Schubert 			xprintf(fp, "Warning: incomplete row with %d (of %d) fields",
3597b5e14a13SCy Schubert 				*pfields, RESLIST_FIELDS);
3598b5e14a13SCy Schubert 		*pfields = 0;
3599b5e14a13SCy Schubert 		prow->idx = idx;
3600b5e14a13SCy Schubert 		return;
3601b5e14a13SCy Schubert 	}
36025171bc9bSCy Schubert 	xprintf(stderr,
3603b5e14a13SCy Schubert 		"received reslist index %u, have %d of %d fields for index %u, aborting.\n",
3604b5e14a13SCy Schubert 		idx, *pfields, RESLIST_FIELDS, prow->idx);
3605b5e14a13SCy Schubert 	exit(1);
3606b5e14a13SCy Schubert }
3607b5e14a13SCy Schubert 
3608b5e14a13SCy Schubert 
3609b5e14a13SCy Schubert /*
3610b5e14a13SCy Schubert  * another_reslist_field - helper for reslist()
3611b5e14a13SCy Schubert  *
3612b5e14a13SCy Schubert  * If all fields for the row have been received, print it.
3613b5e14a13SCy Schubert  */
3614b5e14a13SCy Schubert static void
another_reslist_field(int * pfields,reslist_row * prow,FILE * fp)3615b5e14a13SCy Schubert another_reslist_field(
3616b5e14a13SCy Schubert 	int *		pfields,
3617b5e14a13SCy Schubert 	reslist_row *	prow,
3618b5e14a13SCy Schubert 	FILE *		fp
3619b5e14a13SCy Schubert 	)
3620b5e14a13SCy Schubert {
3621b5e14a13SCy Schubert 	char	addrmaskstr[128];
3622b5e14a13SCy Schubert 	int	prefix;	/* subnet mask as prefix bits count */
3623b5e14a13SCy Schubert 	u_int	idx;
3624b5e14a13SCy Schubert 
3625b5e14a13SCy Schubert 	(*pfields)++;
3626b5e14a13SCy Schubert 	/* we understand 4 tags */
3627b5e14a13SCy Schubert 	if (RESLIST_FIELDS > *pfields)
3628b5e14a13SCy Schubert 		return;
3629b5e14a13SCy Schubert 
3630b5e14a13SCy Schubert 	prefix = sockaddr_masktoprefixlen(&prow->mask);
3631b5e14a13SCy Schubert 	if (prefix >= 0)
3632b5e14a13SCy Schubert 		snprintf(addrmaskstr, sizeof(addrmaskstr), "%s/%d",
3633b5e14a13SCy Schubert 			 stoa(&prow->addr), prefix);
3634b5e14a13SCy Schubert 	else
3635b5e14a13SCy Schubert 		snprintf(addrmaskstr, sizeof(addrmaskstr), "%s %s",
3636b5e14a13SCy Schubert 			 stoa(&prow->addr), stoa(&prow->mask));
3637b5e14a13SCy Schubert 
3638b5e14a13SCy Schubert 	/*
3639b5e14a13SCy Schubert 	"   hits    addr/prefix or addr mask\n"
3640b5e14a13SCy Schubert 	"           restrictions\n"
3641b5e14a13SCy Schubert 	"==============================================================================\n");
3642b5e14a13SCy Schubert 	 */
36435171bc9bSCy Schubert 	xprintf(fp,
3644b5e14a13SCy Schubert 		"%10lu %s\n"
3645b5e14a13SCy Schubert 		"           %s\n",
3646b5e14a13SCy Schubert 		prow->hits, addrmaskstr, prow->flagstr);
3647b5e14a13SCy Schubert 	idx = prow->idx;
3648b5e14a13SCy Schubert 	ZERO(*prow);
3649b5e14a13SCy Schubert 	prow->idx = idx;
3650b5e14a13SCy Schubert }
3651b5e14a13SCy Schubert 
3652b5e14a13SCy Schubert 
3653b5e14a13SCy Schubert /*
3654b5e14a13SCy Schubert  * reslist - ntpq -c reslist modeled on ntpdc -c reslist.
3655b5e14a13SCy Schubert  */
3656b5e14a13SCy Schubert static void
reslist(struct parse * pcmd,FILE * fp)3657b5e14a13SCy Schubert reslist(
3658b5e14a13SCy Schubert 	struct parse *	pcmd,
3659b5e14a13SCy Schubert 	FILE *		fp
3660b5e14a13SCy Schubert 	)
3661b5e14a13SCy Schubert {
3662b5e14a13SCy Schubert 	const char addr_fmtu[] =	"addr.%u";
3663b5e14a13SCy Schubert 	const char mask_fmtu[] =	"mask.%u";
3664b5e14a13SCy Schubert 	const char hits_fmt[] =		"hits.%u";
3665b5e14a13SCy Schubert 	const char flags_fmt[] =	"flags.%u";
3666b5e14a13SCy Schubert 	const char qdata[] =		"addr_restrictions";
3667b5e14a13SCy Schubert 	const int qdata_chars =		COUNTOF(qdata) - 1;
3668b5e14a13SCy Schubert 	const char *	datap;
3669b5e14a13SCy Schubert 	int		qres;
3670c373d928SXin LI 	size_t		dsize;
3671b5e14a13SCy Schubert 	u_short		rstatus;
3672b5e14a13SCy Schubert 	char *		tag;
3673b5e14a13SCy Schubert 	char *		val;
3674b5e14a13SCy Schubert 	int		fields;
3675b5e14a13SCy Schubert 	u_int		ui;
3676b5e14a13SCy Schubert 	reslist_row	row;
3677b5e14a13SCy Schubert 	int		comprende;
3678b5e14a13SCy Schubert 	size_t		len;
3679b5e14a13SCy Schubert 
3680b5e14a13SCy Schubert 	qres = doquery(CTL_OP_READ_ORDLIST_A, 0, TRUE, qdata_chars,
3681b5e14a13SCy Schubert 		       qdata, &rstatus, &dsize, &datap);
3682b5e14a13SCy Schubert 	if (qres)	/* message already displayed */
3683b5e14a13SCy Schubert 		return;
3684b5e14a13SCy Schubert 
36855171bc9bSCy Schubert 	xprintf(fp,
3686b5e14a13SCy Schubert 		"   hits    addr/prefix or addr mask\n"
3687b5e14a13SCy Schubert 		"           restrictions\n"
3688b5e14a13SCy Schubert 		"==============================================================================\n");
3689b5e14a13SCy Schubert 		/* '=' x 78 */
3690b5e14a13SCy Schubert 
3691b5e14a13SCy Schubert 	ZERO(row);
3692b5e14a13SCy Schubert 	fields = 0;
3693b5e14a13SCy Schubert 	ui = 0;
3694b5e14a13SCy Schubert 	while (nextvar(&dsize, &datap, &tag, &val)) {
3695c7f4d233SXin LI 		INSIST(tag && val);
3696b5e14a13SCy Schubert 		if (debug > 1)
36975171bc9bSCy Schubert 			xprintf(stderr, "nextvar gave: %s = %s\n", tag, val);
3698b5e14a13SCy Schubert 		comprende = FALSE;
3699b5e14a13SCy Schubert 		switch(tag[0]) {
3700b5e14a13SCy Schubert 
3701b5e14a13SCy Schubert 		case 'a':
3702b5e14a13SCy Schubert 			if (1 == sscanf(tag, addr_fmtu, &ui) &&
3703b5e14a13SCy Schubert 			    decodenetnum(val, &row.addr))
3704b5e14a13SCy Schubert 				comprende = TRUE;
3705b5e14a13SCy Schubert 			break;
3706b5e14a13SCy Schubert 
3707b5e14a13SCy Schubert 		case 'f':
3708b5e14a13SCy Schubert 			if (1 == sscanf(tag, flags_fmt, &ui)) {
3709b5e14a13SCy Schubert 				if (NULL == val) {
3710b5e14a13SCy Schubert 					row.flagstr[0] = '\0';
3711b5e14a13SCy Schubert 					comprende = TRUE;
371207ac48c3SXin LI 				} else if ((len = strlen(val)) < sizeof(row.flagstr)) {
3713b5e14a13SCy Schubert 					memcpy(row.flagstr, val, len);
3714b5e14a13SCy Schubert 					row.flagstr[len] = '\0';
3715b5e14a13SCy Schubert 					comprende = TRUE;
371607ac48c3SXin LI 				} else {
371707ac48c3SXin LI 					 /* no flags, and still !comprende */
371807ac48c3SXin LI 					row.flagstr[0] = '\0';
3719b5e14a13SCy Schubert 				}
3720b5e14a13SCy Schubert 			}
3721b5e14a13SCy Schubert 			break;
3722b5e14a13SCy Schubert 
3723b5e14a13SCy Schubert 		case 'h':
3724b5e14a13SCy Schubert 			if (1 == sscanf(tag, hits_fmt, &ui) &&
3725b5e14a13SCy Schubert 			    1 == sscanf(val, "%lu", &row.hits))
3726b5e14a13SCy Schubert 				comprende = TRUE;
3727b5e14a13SCy Schubert 			break;
3728b5e14a13SCy Schubert 
3729b5e14a13SCy Schubert 		case 'm':
3730b5e14a13SCy Schubert 			if (1 == sscanf(tag, mask_fmtu, &ui) &&
3731b5e14a13SCy Schubert 			    decodenetnum(val, &row.mask))
3732b5e14a13SCy Schubert 				comprende = TRUE;
3733b5e14a13SCy Schubert 			break;
3734b5e14a13SCy Schubert 		}
3735b5e14a13SCy Schubert 
3736b5e14a13SCy Schubert 		if (comprende) {
3737b5e14a13SCy Schubert 			/* error out if rows out of order */
3738b5e14a13SCy Schubert 			validate_reslist_idx(fp, ui, &fields, &row);
3739b5e14a13SCy Schubert 			/* if the row is complete, print it */
3740b5e14a13SCy Schubert 			another_reslist_field(&fields, &row, fp);
3741b5e14a13SCy Schubert 		}
3742b5e14a13SCy Schubert 	}
3743b5e14a13SCy Schubert 	if (fields != RESLIST_FIELDS)
37445171bc9bSCy Schubert 		xprintf(fp, "Warning: incomplete row with %d (of %d) fields",
3745b5e14a13SCy Schubert 			fields, RESLIST_FIELDS);
3746b5e14a13SCy Schubert 
3747b5e14a13SCy Schubert 	fflush(fp);
3748b5e14a13SCy Schubert }
3749b5e14a13SCy Schubert 
3750b5e14a13SCy Schubert 
3751b5e14a13SCy Schubert /*
3752b5e14a13SCy Schubert  * collect_display_vdc
3753b5e14a13SCy Schubert  */
3754b5e14a13SCy Schubert static void
collect_display_vdc(associd_t as,vdc * table,int decodestatus,FILE * fp)3755b5e14a13SCy Schubert collect_display_vdc(
3756b5e14a13SCy Schubert 	associd_t	as,
3757b5e14a13SCy Schubert 	vdc *		table,
3758b5e14a13SCy Schubert 	int		decodestatus,
3759b5e14a13SCy Schubert 	FILE *		fp
3760b5e14a13SCy Schubert 	)
3761b5e14a13SCy Schubert {
3762b5e14a13SCy Schubert 	static const char * const suf[2] = { "adr", "port" };
3763b5e14a13SCy Schubert 	static const char * const leapbits[4] = { "00", "01",
3764b5e14a13SCy Schubert 						  "10", "11" };
3765b5e14a13SCy Schubert 	struct varlist vl[MAXLIST];
3766b5e14a13SCy Schubert 	char tagbuf[32];
3767b5e14a13SCy Schubert 	vdc *pvdc;
3768b5e14a13SCy Schubert 	u_short rstatus;
3769c373d928SXin LI 	size_t rsize;
3770b5e14a13SCy Schubert 	const char *rdata;
3771b5e14a13SCy Schubert 	int qres;
3772b5e14a13SCy Schubert 	char *tag;
3773b5e14a13SCy Schubert 	char *val;
3774b5e14a13SCy Schubert 	u_int n;
3775b5e14a13SCy Schubert 	size_t len;
3776b5e14a13SCy Schubert 	int match;
3777b5e14a13SCy Schubert 	u_long ul;
3778b5e14a13SCy Schubert 	int vtype;
37795171bc9bSCy Schubert 	sockaddr_u sau;
3780b5e14a13SCy Schubert 
3781b5e14a13SCy Schubert 	ZERO(vl);
3782b5e14a13SCy Schubert 	for (pvdc = table; pvdc->tag != NULL; pvdc++) {
3783b5e14a13SCy Schubert 		ZERO(pvdc->v);
3784b5e14a13SCy Schubert 		if (NTP_ADD != pvdc->type) {
3785b5e14a13SCy Schubert 			doaddvlist(vl, pvdc->tag);
3786b5e14a13SCy Schubert 		} else {
3787b5e14a13SCy Schubert 			for (n = 0; n < COUNTOF(suf); n++) {
3788b5e14a13SCy Schubert 				snprintf(tagbuf, sizeof(tagbuf), "%s%s",
3789b5e14a13SCy Schubert 					 pvdc->tag, suf[n]);
3790b5e14a13SCy Schubert 				doaddvlist(vl, tagbuf);
3791b5e14a13SCy Schubert 			}
3792b5e14a13SCy Schubert 		}
3793b5e14a13SCy Schubert 	}
3794b5e14a13SCy Schubert 	qres = doquerylist(vl, CTL_OP_READVAR, as, 0, &rstatus, &rsize,
3795b5e14a13SCy Schubert 			   &rdata);
3796b5e14a13SCy Schubert 	doclearvlist(vl);
3797b5e14a13SCy Schubert 	if (qres)
3798b5e14a13SCy Schubert 		return;		/* error msg already displayed */
3799b5e14a13SCy Schubert 
3800b5e14a13SCy Schubert 	/*
3801b5e14a13SCy Schubert 	 * iterate over the response variables filling vdc_table with
3802b5e14a13SCy Schubert 	 * the retrieved values.
3803b5e14a13SCy Schubert 	 */
3804b5e14a13SCy Schubert 	while (nextvar(&rsize, &rdata, &tag, &val)) {
3805c7f4d233SXin LI 		INSIST(tag && val);
3806b5e14a13SCy Schubert 		n = 0;
3807b5e14a13SCy Schubert 		for (pvdc = table; pvdc->tag != NULL; pvdc++) {
3808b5e14a13SCy Schubert 			len = strlen(pvdc->tag);
3809b5e14a13SCy Schubert 			if (strncmp(tag, pvdc->tag, len))
3810b5e14a13SCy Schubert 				continue;
3811b5e14a13SCy Schubert 			if (NTP_ADD != pvdc->type) {
3812b5e14a13SCy Schubert 				if ('\0' != tag[len])
3813b5e14a13SCy Schubert 					continue;
3814b5e14a13SCy Schubert 				break;
3815b5e14a13SCy Schubert 			}
3816b5e14a13SCy Schubert 			match = FALSE;
3817b5e14a13SCy Schubert 			for (n = 0; n < COUNTOF(suf); n++) {
3818b5e14a13SCy Schubert 				if (strcmp(tag + len, suf[n]))
3819b5e14a13SCy Schubert 					continue;
3820b5e14a13SCy Schubert 				match = TRUE;
3821b5e14a13SCy Schubert 				break;
3822b5e14a13SCy Schubert 			}
3823b5e14a13SCy Schubert 			if (match)
3824b5e14a13SCy Schubert 				break;
3825b5e14a13SCy Schubert 		}
3826b5e14a13SCy Schubert 		if (NULL == pvdc->tag)
3827b5e14a13SCy Schubert 			continue;
3828b5e14a13SCy Schubert 		switch (pvdc->type) {
3829b5e14a13SCy Schubert 
3830b5e14a13SCy Schubert 		case NTP_STR:
3831b5e14a13SCy Schubert 			/* strip surrounding double quotes */
3832b5e14a13SCy Schubert 			if ('"' == val[0]) {
3833b5e14a13SCy Schubert 				len = strlen(val);
3834b5e14a13SCy Schubert 				if (len > 0 && '"' == val[len - 1]) {
3835b5e14a13SCy Schubert 					val[len - 1] = '\0';
3836b5e14a13SCy Schubert 					val++;
3837b5e14a13SCy Schubert 				}
3838b5e14a13SCy Schubert 			}
3839b5e14a13SCy Schubert 			/* fallthru */
38405171bc9bSCy Schubert 		case NTP_REFID:	/* fallthru */
3841b5e14a13SCy Schubert 		case NTP_MODE:	/* fallthru */
3842b5e14a13SCy Schubert 		case NTP_2BIT:
3843b5e14a13SCy Schubert 			pvdc->v.str = estrdup(val);
3844b5e14a13SCy Schubert 			break;
3845b5e14a13SCy Schubert 
3846b5e14a13SCy Schubert 		case NTP_LFP:
3847b5e14a13SCy Schubert 			decodets(val, &pvdc->v.lfp);
3848b5e14a13SCy Schubert 			break;
3849b5e14a13SCy Schubert 
3850b5e14a13SCy Schubert 		case NTP_ADP:
3851b5e14a13SCy Schubert 			if (!decodenetnum(val, &pvdc->v.sau))
38525171bc9bSCy Schubert 				xprintf(stderr, "malformed %s=%s\n",
3853b5e14a13SCy Schubert 					pvdc->tag, val);
3854b5e14a13SCy Schubert 			break;
3855b5e14a13SCy Schubert 
3856b5e14a13SCy Schubert 		case NTP_ADD:
3857b5e14a13SCy Schubert 			if (0 == n) {	/* adr */
3858b5e14a13SCy Schubert 				if (!decodenetnum(val, &pvdc->v.sau))
38595171bc9bSCy Schubert 					xprintf(stderr,
3860b5e14a13SCy Schubert 						"malformed %s=%s\n",
3861b5e14a13SCy Schubert 						pvdc->tag, val);
3862b5e14a13SCy Schubert 			} else {	/* port */
3863b5e14a13SCy Schubert 				if (atouint(val, &ul))
3864b5e14a13SCy Schubert 					SET_PORT(&pvdc->v.sau,
3865b5e14a13SCy Schubert 						 (u_short)ul);
3866b5e14a13SCy Schubert 			}
3867b5e14a13SCy Schubert 			break;
3868b5e14a13SCy Schubert 		}
3869b5e14a13SCy Schubert 	}
3870b5e14a13SCy Schubert 
3871b5e14a13SCy Schubert 	/* and display */
3872b5e14a13SCy Schubert 	if (decodestatus) {
3873b5e14a13SCy Schubert 		vtype = (0 == as)
3874b5e14a13SCy Schubert 			    ? TYPE_SYS
3875b5e14a13SCy Schubert 			    : TYPE_PEER;
38765171bc9bSCy Schubert 		xprintf(fp, "associd=%u status=%04x %s,\n", as, rstatus,
3877b5e14a13SCy Schubert 			statustoa(vtype, rstatus));
3878b5e14a13SCy Schubert 	}
3879b5e14a13SCy Schubert 
3880b5e14a13SCy Schubert 	for (pvdc = table; pvdc->tag != NULL; pvdc++) {
3881b5e14a13SCy Schubert 		switch (pvdc->type) {
3882b5e14a13SCy Schubert 
3883b5e14a13SCy Schubert 		case NTP_STR:
3884b5e14a13SCy Schubert 			if (pvdc->v.str != NULL) {
38855171bc9bSCy Schubert 				xprintf(fp, "%s  %s\n", pvdc->display,
3886b5e14a13SCy Schubert 					pvdc->v.str);
3887b5e14a13SCy Schubert 				free(pvdc->v.str);
3888b5e14a13SCy Schubert 				pvdc->v.str = NULL;
3889b5e14a13SCy Schubert 			}
3890b5e14a13SCy Schubert 			break;
3891b5e14a13SCy Schubert 
3892b5e14a13SCy Schubert 		case NTP_ADD:	/* fallthru */
3893b5e14a13SCy Schubert 		case NTP_ADP:
38945171bc9bSCy Schubert 			xprintf(fp, "%s  %s\n", pvdc->display,
3895b5e14a13SCy Schubert 				nntohostp(&pvdc->v.sau));
3896b5e14a13SCy Schubert 			break;
3897b5e14a13SCy Schubert 
3898b5e14a13SCy Schubert 		case NTP_LFP:
38995171bc9bSCy Schubert 			xprintf(fp, "%s  %s\n", pvdc->display,
3900b5e14a13SCy Schubert 				prettydate(&pvdc->v.lfp));
3901b5e14a13SCy Schubert 			break;
3902b5e14a13SCy Schubert 
3903b5e14a13SCy Schubert 		case NTP_MODE:
3904b5e14a13SCy Schubert 			atouint(pvdc->v.str, &ul);
39055171bc9bSCy Schubert 			xprintf(fp, "%s  %s\n", pvdc->display,
3906b5e14a13SCy Schubert 				modetoa((int)ul));
39075171bc9bSCy Schubert 			free(pvdc->v.str);
39085171bc9bSCy Schubert 			pvdc->v.str = NULL;
3909b5e14a13SCy Schubert 			break;
3910b5e14a13SCy Schubert 
3911b5e14a13SCy Schubert 		case NTP_2BIT:
3912b5e14a13SCy Schubert 			atouint(pvdc->v.str, &ul);
39135171bc9bSCy Schubert 			xprintf(fp, "%s  %s\n", pvdc->display,
3914b5e14a13SCy Schubert 				leapbits[ul & 0x3]);
39155171bc9bSCy Schubert 			free(pvdc->v.str);
39165171bc9bSCy Schubert 			pvdc->v.str = NULL;
39175171bc9bSCy Schubert 			break;
39185171bc9bSCy Schubert 
39195171bc9bSCy Schubert 		case NTP_REFID:
39205171bc9bSCy Schubert 			if (!decodenetnum(pvdc->v.str, &sau)) {
39215171bc9bSCy Schubert 				fprintf(fp, "%s  %s\n", pvdc->display,    /* Text fmt */
39225171bc9bSCy Schubert 					pvdc->v.str);
39235171bc9bSCy Schubert 			} else if (drefid == REFID_IPV4) {
39245171bc9bSCy Schubert 				fprintf(fp, "%s  %s\n", pvdc->display,    /* IPv4 fmt */
39255171bc9bSCy Schubert 					stoa(&sau));
39265171bc9bSCy Schubert 			} else {
39275171bc9bSCy Schubert 				fprintf (fp, "%s  0x%08x\n", pvdc->display,	   /* Hex / hash */
39285171bc9bSCy Schubert 					 ntohl(addr2refid(&sau)));
39295171bc9bSCy Schubert 			}
39305171bc9bSCy Schubert 			free(pvdc->v.str);
39315171bc9bSCy Schubert 			pvdc->v.str = NULL;
3932b5e14a13SCy Schubert 			break;
3933b5e14a13SCy Schubert 
3934b5e14a13SCy Schubert 		default:
39355171bc9bSCy Schubert 			xprintf(stderr, "unexpected vdc type %d for %s\n",
3936b5e14a13SCy Schubert 				pvdc->type, pvdc->tag);
3937b5e14a13SCy Schubert 			break;
3938b5e14a13SCy Schubert 		}
3939b5e14a13SCy Schubert 	}
3940b5e14a13SCy Schubert }
3941b5e14a13SCy Schubert 
3942b5e14a13SCy Schubert 
3943b5e14a13SCy Schubert /*
3944b5e14a13SCy Schubert  * sysstats - implements ntpq -c sysstats modeled on ntpdc -c sysstats
3945b5e14a13SCy Schubert  */
3946b5e14a13SCy Schubert static void
sysstats(struct parse * pcmd,FILE * fp)3947b5e14a13SCy Schubert sysstats(
3948b5e14a13SCy Schubert 	struct parse *pcmd,
3949b5e14a13SCy Schubert 	FILE *fp
3950b5e14a13SCy Schubert 	)
3951b5e14a13SCy Schubert {
3952b5e14a13SCy Schubert     static vdc sysstats_vdc[] = {
3953f7cba3a8SCy Schubert 	VDC_INIT("ss_uptime",		"uptime:               ", NTP_STR),
3954f7cba3a8SCy Schubert 	VDC_INIT("ss_reset",		"sysstats reset:       ", NTP_STR),
3955f7cba3a8SCy Schubert 	VDC_INIT("ss_received",		"packets received:     ", NTP_STR),
3956f7cba3a8SCy Schubert 	VDC_INIT("ss_thisver",		"current version:      ", NTP_STR),
3957f7cba3a8SCy Schubert 	VDC_INIT("ss_oldver",		"older version:        ", NTP_STR),
3958f7cba3a8SCy Schubert 	VDC_INIT("ss_badformat",	"bad length or format: ", NTP_STR),
3959f7cba3a8SCy Schubert 	VDC_INIT("ss_badauth",		"authentication failed:", NTP_STR),
3960f7cba3a8SCy Schubert 	VDC_INIT("ss_declined",		"declined:             ", NTP_STR),
3961f7cba3a8SCy Schubert 	VDC_INIT("ss_restricted",	"restricted:           ", NTP_STR),
3962f7cba3a8SCy Schubert 	VDC_INIT("ss_limited",		"rate limited:         ", NTP_STR),
3963f7cba3a8SCy Schubert 	VDC_INIT("ss_kodsent",		"KoD responses:        ", NTP_STR),
3964f7cba3a8SCy Schubert 	VDC_INIT("ss_processed",	"processed for time:   ", NTP_STR),
3965d14ac12fSXin LI #if 0
3966d14ac12fSXin LI 	VDC_INIT("ss_lamport",		"Lamport violations:    ", NTP_STR),
3967d14ac12fSXin LI 	VDC_INIT("ss_tsrounding",	"bad timestamp rounding:", NTP_STR),
3968d14ac12fSXin LI #endif
3969f7cba3a8SCy Schubert 	VDC_INIT(NULL,			NULL,			  0)
3970b5e14a13SCy Schubert     };
3971b5e14a13SCy Schubert 
3972b5e14a13SCy Schubert 	collect_display_vdc(0, sysstats_vdc, FALSE, fp);
3973b5e14a13SCy Schubert }
3974b5e14a13SCy Schubert 
3975b5e14a13SCy Schubert 
3976b5e14a13SCy Schubert /*
3977b5e14a13SCy Schubert  * sysinfo - modeled on ntpdc's sysinfo
3978b5e14a13SCy Schubert  */
3979b5e14a13SCy Schubert static void
sysinfo(struct parse * pcmd,FILE * fp)3980b5e14a13SCy Schubert sysinfo(
3981b5e14a13SCy Schubert 	struct parse *pcmd,
3982b5e14a13SCy Schubert 	FILE *fp
3983b5e14a13SCy Schubert 	)
3984b5e14a13SCy Schubert {
3985b5e14a13SCy Schubert     static vdc sysinfo_vdc[] = {
3986f7cba3a8SCy Schubert 	VDC_INIT("peeradr",		"system peer:      ", NTP_ADP),
3987f7cba3a8SCy Schubert 	VDC_INIT("peermode",		"system peer mode: ", NTP_MODE),
3988f7cba3a8SCy Schubert 	VDC_INIT("leap",		"leap indicator:   ", NTP_2BIT),
3989f7cba3a8SCy Schubert 	VDC_INIT("stratum",		"stratum:          ", NTP_STR),
3990f7cba3a8SCy Schubert 	VDC_INIT("precision",		"log2 precision:   ", NTP_STR),
3991f7cba3a8SCy Schubert 	VDC_INIT("rootdelay",		"root delay:       ", NTP_STR),
3992f7cba3a8SCy Schubert 	VDC_INIT("rootdisp",		"root dispersion:  ", NTP_STR),
39935171bc9bSCy Schubert 	VDC_INIT("refid",		"reference ID:     ", NTP_REFID),
3994f7cba3a8SCy Schubert 	VDC_INIT("reftime",		"reference time:   ", NTP_LFP),
3995f7cba3a8SCy Schubert 	VDC_INIT("sys_jitter",		"system jitter:    ", NTP_STR),
3996f7cba3a8SCy Schubert 	VDC_INIT("clk_jitter",		"clock jitter:     ", NTP_STR),
3997f7cba3a8SCy Schubert 	VDC_INIT("clk_wander",		"clock wander:     ", NTP_STR),
3998f7cba3a8SCy Schubert 	VDC_INIT("bcastdelay",		"broadcast delay:  ", NTP_STR),
3999f7cba3a8SCy Schubert 	VDC_INIT("authdelay",		"symm. auth. delay:", NTP_STR),
4000f7cba3a8SCy Schubert 	VDC_INIT(NULL,			NULL,		      0)
4001b5e14a13SCy Schubert     };
4002b5e14a13SCy Schubert 
4003b5e14a13SCy Schubert 	collect_display_vdc(0, sysinfo_vdc, TRUE, fp);
4004b5e14a13SCy Schubert }
4005b5e14a13SCy Schubert 
4006b5e14a13SCy Schubert 
4007b5e14a13SCy Schubert /*
4008b5e14a13SCy Schubert  * kerninfo - modeled on ntpdc's kerninfo
4009b5e14a13SCy Schubert  */
4010b5e14a13SCy Schubert static void
kerninfo(struct parse * pcmd,FILE * fp)4011b5e14a13SCy Schubert kerninfo(
4012b5e14a13SCy Schubert 	struct parse *pcmd,
4013b5e14a13SCy Schubert 	FILE *fp
4014b5e14a13SCy Schubert 	)
4015b5e14a13SCy Schubert {
4016b5e14a13SCy Schubert     static vdc kerninfo_vdc[] = {
4017f7cba3a8SCy Schubert 	VDC_INIT("koffset",		"pll offset:          ", NTP_STR),
4018f7cba3a8SCy Schubert 	VDC_INIT("kfreq",		"pll frequency:       ", NTP_STR),
4019f7cba3a8SCy Schubert 	VDC_INIT("kmaxerr",		"maximum error:       ", NTP_STR),
4020f7cba3a8SCy Schubert 	VDC_INIT("kesterr",		"estimated error:     ", NTP_STR),
4021f7cba3a8SCy Schubert 	VDC_INIT("kstflags",		"kernel status:       ", NTP_STR),
4022f7cba3a8SCy Schubert 	VDC_INIT("ktimeconst",		"pll time constant:   ", NTP_STR),
4023f7cba3a8SCy Schubert 	VDC_INIT("kprecis",		"precision:           ", NTP_STR),
4024f7cba3a8SCy Schubert 	VDC_INIT("kfreqtol",		"frequency tolerance: ", NTP_STR),
4025f7cba3a8SCy Schubert 	VDC_INIT("kppsfreq",		"pps frequency:       ", NTP_STR),
4026f7cba3a8SCy Schubert 	VDC_INIT("kppsstab",		"pps stability:       ", NTP_STR),
4027f7cba3a8SCy Schubert 	VDC_INIT("kppsjitter",		"pps jitter:          ", NTP_STR),
4028f7cba3a8SCy Schubert 	VDC_INIT("kppscalibdur",	"calibration interval ", NTP_STR),
4029f7cba3a8SCy Schubert 	VDC_INIT("kppscalibs",		"calibration cycles:  ", NTP_STR),
4030f7cba3a8SCy Schubert 	VDC_INIT("kppsjitexc",		"jitter exceeded:     ", NTP_STR),
4031f7cba3a8SCy Schubert 	VDC_INIT("kppsstbexc",		"stability exceeded:  ", NTP_STR),
4032f7cba3a8SCy Schubert 	VDC_INIT("kppscaliberrs",	"calibration errors:  ", NTP_STR),
4033f7cba3a8SCy Schubert 	VDC_INIT(NULL,			NULL,			 0)
4034b5e14a13SCy Schubert     };
4035b5e14a13SCy Schubert 
4036b5e14a13SCy Schubert 	collect_display_vdc(0, kerninfo_vdc, TRUE, fp);
4037b5e14a13SCy Schubert }
4038b5e14a13SCy Schubert 
4039b5e14a13SCy Schubert 
4040b5e14a13SCy Schubert /*
4041b5e14a13SCy Schubert  * monstats - implements ntpq -c monstats
4042b5e14a13SCy Schubert  */
4043b5e14a13SCy Schubert static void
monstats(struct parse * pcmd,FILE * fp)4044b5e14a13SCy Schubert monstats(
4045b5e14a13SCy Schubert 	struct parse *pcmd,
4046b5e14a13SCy Schubert 	FILE *fp
4047b5e14a13SCy Schubert 	)
4048b5e14a13SCy Schubert {
4049b5e14a13SCy Schubert     static vdc monstats_vdc[] = {
4050f7cba3a8SCy Schubert 	VDC_INIT("mru_enabled",		"enabled:            ", NTP_STR),
4051f7cba3a8SCy Schubert 	VDC_INIT("mru_depth",		"addresses:          ", NTP_STR),
4052f7cba3a8SCy Schubert 	VDC_INIT("mru_deepest",		"peak addresses:     ", NTP_STR),
4053f7cba3a8SCy Schubert 	VDC_INIT("mru_maxdepth",	"maximum addresses:  ", NTP_STR),
4054f7cba3a8SCy Schubert 	VDC_INIT("mru_mindepth",	"reclaim above count:", NTP_STR),
4055f7cba3a8SCy Schubert 	VDC_INIT("mru_maxage",		"reclaim older than: ", NTP_STR),
4056f7cba3a8SCy Schubert 	VDC_INIT("mru_mem",		"kilobytes:          ", NTP_STR),
4057f7cba3a8SCy Schubert 	VDC_INIT("mru_maxmem",		"maximum kilobytes:  ", NTP_STR),
4058f7cba3a8SCy Schubert 	VDC_INIT(NULL,			NULL,			0)
4059b5e14a13SCy Schubert     };
4060b5e14a13SCy Schubert 
4061b5e14a13SCy Schubert 	collect_display_vdc(0, monstats_vdc, FALSE, fp);
4062b5e14a13SCy Schubert }
4063b5e14a13SCy Schubert 
4064b5e14a13SCy Schubert 
4065b5e14a13SCy Schubert /*
4066b5e14a13SCy Schubert  * iostats - ntpq -c iostats - network input and output counters
4067b5e14a13SCy Schubert  */
4068b5e14a13SCy Schubert static void
iostats(struct parse * pcmd,FILE * fp)4069b5e14a13SCy Schubert iostats(
4070b5e14a13SCy Schubert 	struct parse *pcmd,
4071b5e14a13SCy Schubert 	FILE *fp
4072b5e14a13SCy Schubert 	)
4073b5e14a13SCy Schubert {
4074b5e14a13SCy Schubert     static vdc iostats_vdc[] = {
4075f7cba3a8SCy Schubert 	VDC_INIT("iostats_reset",	"time since reset:     ", NTP_STR),
4076f7cba3a8SCy Schubert 	VDC_INIT("total_rbuf",		"receive buffers:      ", NTP_STR),
4077f7cba3a8SCy Schubert 	VDC_INIT("free_rbuf",		"free receive buffers: ", NTP_STR),
4078f7cba3a8SCy Schubert 	VDC_INIT("used_rbuf",		"used receive buffers: ", NTP_STR),
4079f7cba3a8SCy Schubert 	VDC_INIT("rbuf_lowater",	"low water refills:    ", NTP_STR),
4080f7cba3a8SCy Schubert 	VDC_INIT("io_dropped",		"dropped packets:      ", NTP_STR),
4081f7cba3a8SCy Schubert 	VDC_INIT("io_ignored",		"ignored packets:      ", NTP_STR),
4082f7cba3a8SCy Schubert 	VDC_INIT("io_received",		"received packets:     ", NTP_STR),
4083f7cba3a8SCy Schubert 	VDC_INIT("io_sent",		"packets sent:         ", NTP_STR),
4084f7cba3a8SCy Schubert 	VDC_INIT("io_sendfailed",	"packet send failures: ", NTP_STR),
4085f7cba3a8SCy Schubert 	VDC_INIT("io_wakeups",		"input wakeups:        ", NTP_STR),
4086f7cba3a8SCy Schubert 	VDC_INIT("io_goodwakeups",	"useful input wakeups: ", NTP_STR),
4087f7cba3a8SCy Schubert 	VDC_INIT(NULL,			NULL,			  0)
4088b5e14a13SCy Schubert     };
4089b5e14a13SCy Schubert 
4090b5e14a13SCy Schubert 	collect_display_vdc(0, iostats_vdc, FALSE, fp);
4091b5e14a13SCy Schubert }
4092b5e14a13SCy Schubert 
4093b5e14a13SCy Schubert 
4094b5e14a13SCy Schubert /*
4095b5e14a13SCy Schubert  * timerstats - ntpq -c timerstats - interval timer counters
4096b5e14a13SCy Schubert  */
4097b5e14a13SCy Schubert static void
timerstats(struct parse * pcmd,FILE * fp)4098b5e14a13SCy Schubert timerstats(
4099b5e14a13SCy Schubert 	struct parse *pcmd,
4100b5e14a13SCy Schubert 	FILE *fp
4101b5e14a13SCy Schubert 	)
4102b5e14a13SCy Schubert {
4103b5e14a13SCy Schubert     static vdc timerstats_vdc[] = {
4104f7cba3a8SCy Schubert 	VDC_INIT("timerstats_reset",	"time since reset:  ", NTP_STR),
4105f7cba3a8SCy Schubert 	VDC_INIT("timer_overruns",	"timer overruns:    ", NTP_STR),
4106f7cba3a8SCy Schubert 	VDC_INIT("timer_xmts",		"calls to transmit: ", NTP_STR),
4107f7cba3a8SCy Schubert 	VDC_INIT(NULL,			NULL,		       0)
4108b5e14a13SCy Schubert     };
4109b5e14a13SCy Schubert 
4110b5e14a13SCy Schubert 	collect_display_vdc(0, timerstats_vdc, FALSE, fp);
4111b5e14a13SCy Schubert }
4112b5e14a13SCy Schubert 
4113b5e14a13SCy Schubert 
4114b5e14a13SCy Schubert /*
4115b5e14a13SCy Schubert  * authinfo - implements ntpq -c authinfo
4116b5e14a13SCy Schubert  */
4117b5e14a13SCy Schubert static void
authinfo(struct parse * pcmd,FILE * fp)4118b5e14a13SCy Schubert authinfo(
4119b5e14a13SCy Schubert 	struct parse *pcmd,
4120b5e14a13SCy Schubert 	FILE *fp
4121b5e14a13SCy Schubert 	)
4122b5e14a13SCy Schubert {
4123b5e14a13SCy Schubert     static vdc authinfo_vdc[] = {
4124f7cba3a8SCy Schubert 	VDC_INIT("authreset",		"time since reset:", NTP_STR),
4125f7cba3a8SCy Schubert 	VDC_INIT("authkeys",		"stored keys:     ", NTP_STR),
4126f7cba3a8SCy Schubert 	VDC_INIT("authfreek",		"free keys:       ", NTP_STR),
4127f7cba3a8SCy Schubert 	VDC_INIT("authklookups",	"key lookups:     ", NTP_STR),
4128f7cba3a8SCy Schubert 	VDC_INIT("authknotfound",	"keys not found:  ", NTP_STR),
4129f7cba3a8SCy Schubert 	VDC_INIT("authkuncached",	"uncached keys:   ", NTP_STR),
4130f7cba3a8SCy Schubert 	VDC_INIT("authkexpired",	"expired keys:    ", NTP_STR),
4131f7cba3a8SCy Schubert 	VDC_INIT("authencrypts",	"encryptions:     ", NTP_STR),
4132f7cba3a8SCy Schubert 	VDC_INIT("authdecrypts",	"decryptions:     ", NTP_STR),
4133f7cba3a8SCy Schubert 	VDC_INIT(NULL,			NULL,		     0)
4134b5e14a13SCy Schubert     };
4135b5e14a13SCy Schubert 
4136b5e14a13SCy Schubert 	collect_display_vdc(0, authinfo_vdc, FALSE, fp);
4137b5e14a13SCy Schubert }
4138b5e14a13SCy Schubert 
4139b5e14a13SCy Schubert 
4140b5e14a13SCy Schubert /*
4141b5e14a13SCy Schubert  * pstats - show statistics for a peer
4142b5e14a13SCy Schubert  */
4143b5e14a13SCy Schubert static void
pstats(struct parse * pcmd,FILE * fp)4144b5e14a13SCy Schubert pstats(
4145b5e14a13SCy Schubert 	struct parse *pcmd,
4146b5e14a13SCy Schubert 	FILE *fp
4147b5e14a13SCy Schubert 	)
4148b5e14a13SCy Schubert {
4149b5e14a13SCy Schubert     static vdc pstats_vdc[] = {
4150f7cba3a8SCy Schubert 	VDC_INIT("src",		"remote host:         ", NTP_ADD),
4151f7cba3a8SCy Schubert 	VDC_INIT("dst",		"local address:       ", NTP_ADD),
4152f7cba3a8SCy Schubert 	VDC_INIT("timerec",	"time last received:  ", NTP_STR),
4153f7cba3a8SCy Schubert 	VDC_INIT("timer",	"time until next send:", NTP_STR),
4154f7cba3a8SCy Schubert 	VDC_INIT("timereach",	"reachability change: ", NTP_STR),
4155f7cba3a8SCy Schubert 	VDC_INIT("sent",	"packets sent:        ", NTP_STR),
4156f7cba3a8SCy Schubert 	VDC_INIT("received",	"packets received:    ", NTP_STR),
4157f7cba3a8SCy Schubert 	VDC_INIT("badauth",	"bad authentication:  ", NTP_STR),
4158f7cba3a8SCy Schubert 	VDC_INIT("bogusorg",	"bogus origin:        ", NTP_STR),
4159f7cba3a8SCy Schubert 	VDC_INIT("oldpkt",	"duplicate:           ", NTP_STR),
4160f7cba3a8SCy Schubert 	VDC_INIT("seldisp",	"bad dispersion:      ", NTP_STR),
4161f7cba3a8SCy Schubert 	VDC_INIT("selbroken",	"bad reference time:  ", NTP_STR),
4162f7cba3a8SCy Schubert 	VDC_INIT("candidate",	"candidate order:     ", NTP_STR),
4163f7cba3a8SCy Schubert 	VDC_INIT(NULL,		NULL,			 0)
4164b5e14a13SCy Schubert     };
4165b5e14a13SCy Schubert 	associd_t associd;
4166b5e14a13SCy Schubert 
4167b5e14a13SCy Schubert 	associd = checkassocid(pcmd->argval[0].uval);
4168b5e14a13SCy Schubert 	if (0 == associd)
4169b5e14a13SCy Schubert 		return;
4170b5e14a13SCy Schubert 
4171b5e14a13SCy Schubert 	collect_display_vdc(associd, pstats_vdc, TRUE, fp);
4172b5e14a13SCy Schubert }
4173