xref: /freebsd/contrib/ntp/ntpq/ntpq-subs.c (revision f5f40dd63bc7acbb5312b26ac1ea1103c12352a6)
1ea906c41SOllivier Robert /*
22b15cb3dSCy Schubert  * ntpq-subs.c - subroutines which are called to perform ntpq commands.
3ea906c41SOllivier Robert  */
42b15cb3dSCy Schubert #include <config.h>
5ea906c41SOllivier Robert #include <stdio.h>
6ea906c41SOllivier Robert #include <ctype.h>
7ea906c41SOllivier Robert #include <sys/types.h>
8ea906c41SOllivier Robert #include <sys/time.h>
9ea906c41SOllivier Robert 
10ea906c41SOllivier Robert #include "ntpq.h"
112b15cb3dSCy Schubert #include "ntpq-opts.h"
12ea906c41SOllivier Robert 
13ea906c41SOllivier Robert extern char	currenthost[];
142b15cb3dSCy Schubert extern int	currenthostisnum;
152b15cb3dSCy Schubert size_t		maxhostlen;
16ea906c41SOllivier Robert 
17ea906c41SOllivier Robert /*
18ea906c41SOllivier Robert  * Declarations for command handlers in here
19ea906c41SOllivier Robert  */
202b15cb3dSCy Schubert static	associd_t checkassocid	(u_int32);
212b15cb3dSCy Schubert static	struct varlist *findlistvar (struct varlist *, char *);
222b15cb3dSCy Schubert static	void	doaddvlist	(struct varlist *, const char *);
232b15cb3dSCy Schubert static	void	dormvlist	(struct varlist *, const char *);
242b15cb3dSCy Schubert static	void	doclearvlist	(struct varlist *);
253311ff84SXin LI static	void	makequerydata	(struct varlist *, size_t *, char *);
262b15cb3dSCy Schubert static	int	doquerylist	(struct varlist *, int, associd_t, int,
273311ff84SXin LI 				 u_short *, size_t *, const char **);
282b15cb3dSCy Schubert static	void	doprintvlist	(struct varlist *, FILE *);
292b15cb3dSCy Schubert static	void	addvars 	(struct parse *, FILE *);
302b15cb3dSCy Schubert static	void	rmvars		(struct parse *, FILE *);
312b15cb3dSCy Schubert static	void	clearvars	(struct parse *, FILE *);
322b15cb3dSCy Schubert static	void	showvars	(struct parse *, FILE *);
332b15cb3dSCy Schubert static	int	dolist		(struct varlist *, associd_t, int, int,
342b15cb3dSCy Schubert 				 FILE *);
352b15cb3dSCy Schubert static	void	readlist	(struct parse *, FILE *);
362b15cb3dSCy Schubert static	void	writelist	(struct parse *, FILE *);
372b15cb3dSCy Schubert static	void	readvar 	(struct parse *, FILE *);
382b15cb3dSCy Schubert static	void	writevar	(struct parse *, FILE *);
392b15cb3dSCy Schubert static	void	clocklist	(struct parse *, FILE *);
402b15cb3dSCy Schubert static	void	clockvar	(struct parse *, FILE *);
412b15cb3dSCy Schubert static	int	findassidrange	(u_int32, u_int32, int *, int *,
422b15cb3dSCy Schubert 				 FILE *);
432b15cb3dSCy Schubert static	void	mreadlist	(struct parse *, FILE *);
442b15cb3dSCy Schubert static	void	mreadvar	(struct parse *, FILE *);
452b15cb3dSCy Schubert static	void	printassoc	(int, FILE *);
462b15cb3dSCy Schubert static	void	associations	(struct parse *, FILE *);
472b15cb3dSCy Schubert static	void	lassociations	(struct parse *, FILE *);
482b15cb3dSCy Schubert static	void	passociations	(struct parse *, FILE *);
492b15cb3dSCy Schubert static	void	lpassociations	(struct parse *, FILE *);
50ea906c41SOllivier Robert 
51ea906c41SOllivier Robert #ifdef	UNUSED
522b15cb3dSCy Schubert static	void	radiostatus (struct parse *, FILE *);
53ea906c41SOllivier Robert #endif	/* UNUSED */
54ea906c41SOllivier Robert 
552b15cb3dSCy Schubert static	void	authinfo	(struct parse *, FILE *);
562b15cb3dSCy Schubert static	void	pstats	 	(struct parse *, FILE *);
572b15cb3dSCy Schubert static	long	when		(l_fp *, l_fp *, l_fp *);
582b15cb3dSCy Schubert static	char *	prettyinterval	(char *, size_t, long);
593311ff84SXin LI static	int	doprintpeers	(struct varlist *, int, int, size_t, const char *, FILE *, int);
602b15cb3dSCy Schubert static	int	dogetpeers	(struct varlist *, associd_t, FILE *, int);
612b15cb3dSCy Schubert static	void	dopeers 	(int, FILE *, int);
622b15cb3dSCy Schubert static	void	peers		(struct parse *, FILE *);
63276da39aSCy Schubert static	void	doapeers 	(int, FILE *, int);
64276da39aSCy Schubert static	void	apeers		(struct parse *, FILE *);
652b15cb3dSCy Schubert static	void	lpeers		(struct parse *, FILE *);
662b15cb3dSCy Schubert static	void	doopeers	(int, FILE *, int);
672b15cb3dSCy Schubert static	void	opeers		(struct parse *, FILE *);
682b15cb3dSCy Schubert static	void	lopeers 	(struct parse *, FILE *);
692b15cb3dSCy Schubert static	void	config		(struct parse *, FILE *);
702b15cb3dSCy Schubert static	void	saveconfig	(struct parse *, FILE *);
712b15cb3dSCy Schubert static	void	config_from_file(struct parse *, FILE *);
722b15cb3dSCy Schubert static	void	mrulist		(struct parse *, FILE *);
732b15cb3dSCy Schubert static	void	ifstats		(struct parse *, FILE *);
742b15cb3dSCy Schubert static	void	reslist		(struct parse *, FILE *);
752b15cb3dSCy Schubert static	void	sysstats	(struct parse *, FILE *);
762b15cb3dSCy Schubert static	void	sysinfo		(struct parse *, FILE *);
772b15cb3dSCy Schubert static	void	kerninfo	(struct parse *, FILE *);
782b15cb3dSCy Schubert static	void	monstats	(struct parse *, FILE *);
792b15cb3dSCy Schubert static	void	iostats		(struct parse *, FILE *);
802b15cb3dSCy Schubert static	void	timerstats	(struct parse *, FILE *);
81ea906c41SOllivier Robert 
82ea906c41SOllivier Robert /*
83ea906c41SOllivier Robert  * Commands we understand.	Ntpdc imports this.
84ea906c41SOllivier Robert  */
85ea906c41SOllivier Robert struct xcmd opcmds[] = {
862b15cb3dSCy Schubert 	{ "saveconfig", saveconfig, { NTP_STR, NO, NO, NO },
872b15cb3dSCy Schubert 		{ "filename", "", "", ""},
882b15cb3dSCy Schubert 		"save ntpd configuration to file, . for current config file"},
89ea906c41SOllivier Robert 	{ "associations", associations, {  NO, NO, NO, NO },
90ea906c41SOllivier Robert 	  { "", "", "", "" },
91ea906c41SOllivier Robert 	  "print list of association ID's and statuses for the server's peers" },
92ea906c41SOllivier Robert 	{ "passociations", passociations,   {  NO, NO, NO, NO },
93ea906c41SOllivier Robert 	  { "", "", "", "" },
94ea906c41SOllivier Robert 	  "print list of associations returned by last associations command" },
95ea906c41SOllivier Robert 	{ "lassociations", lassociations,   {  NO, NO, NO, NO },
96ea906c41SOllivier Robert 	  { "", "", "", "" },
97ea906c41SOllivier Robert 	  "print list of associations including all client information" },
98ea906c41SOllivier Robert 	{ "lpassociations", lpassociations, {  NO, NO, NO, NO },
99ea906c41SOllivier Robert 	  { "", "", "", "" },
100ea906c41SOllivier Robert 	  "print last obtained list of associations, including client information" },
101ea906c41SOllivier Robert 	{ "addvars",    addvars,    { NTP_STR, NO, NO, NO },
102ea906c41SOllivier Robert 	  { "name[=value][,...]", "", "", "" },
103ea906c41SOllivier Robert 	  "add variables to the variable list or change their values" },
104ea906c41SOllivier Robert 	{ "rmvars", rmvars,     { NTP_STR, NO, NO, NO },
105ea906c41SOllivier Robert 	  { "name[,...]", "", "", "" },
106ea906c41SOllivier Robert 	  "remove variables from the variable list" },
107ea906c41SOllivier Robert 	{ "clearvars",  clearvars,  { NO, NO, NO, NO },
108ea906c41SOllivier Robert 	  { "", "", "", "" },
109ea906c41SOllivier Robert 	  "remove all variables from the variable list" },
110ea906c41SOllivier Robert 	{ "showvars",   showvars,   { NO, NO, NO, NO },
111ea906c41SOllivier Robert 	  { "", "", "", "" },
112ea906c41SOllivier Robert 	  "print variables on the variable list" },
113ea906c41SOllivier Robert 	{ "readlist",   readlist,   { OPT|NTP_UINT, NO, NO, NO },
114ea906c41SOllivier Robert 	  { "assocID", "", "", "" },
115ea906c41SOllivier Robert 	  "read the system or peer variables included in the variable list" },
116ea906c41SOllivier Robert 	{ "rl",     readlist,   { OPT|NTP_UINT, NO, NO, NO },
117ea906c41SOllivier Robert 	  { "assocID", "", "", "" },
118ea906c41SOllivier Robert 	  "read the system or peer variables included in the variable list" },
119ea906c41SOllivier Robert 	{ "writelist",  writelist,  { OPT|NTP_UINT, NO, NO, NO },
120ea906c41SOllivier Robert 	  { "assocID", "", "", "" },
121ea906c41SOllivier Robert 	  "write the system or peer variables included in the variable list" },
1222b15cb3dSCy Schubert 	{ "readvar", readvar,    { OPT|NTP_UINT, OPT|NTP_STR, OPT|NTP_STR, OPT|NTP_STR, },
1232b15cb3dSCy Schubert 	  { "assocID", "varname1", "varname2", "varname3" },
124ea906c41SOllivier Robert 	  "read system or peer variables" },
1252b15cb3dSCy Schubert 	{ "rv",      readvar,    { OPT|NTP_UINT, OPT|NTP_STR, OPT|NTP_STR, OPT|NTP_STR, },
1262b15cb3dSCy Schubert 	  { "assocID", "varname1", "varname2", "varname3" },
127ea906c41SOllivier Robert 	  "read system or peer variables" },
128ea906c41SOllivier Robert 	{ "writevar",   writevar,   { NTP_UINT, NTP_STR, NO, NO },
129ea906c41SOllivier Robert 	  { "assocID", "name=value,[...]", "", "" },
130ea906c41SOllivier Robert 	  "write system or peer variables" },
131ea906c41SOllivier Robert 	{ "mreadlist",  mreadlist,  { NTP_UINT, NTP_UINT, NO, NO },
1322b15cb3dSCy Schubert 	  { "assocIDlow", "assocIDhigh", "", "" },
133ea906c41SOllivier Robert 	  "read the peer variables in the variable list for multiple peers" },
134ea906c41SOllivier Robert 	{ "mrl",    mreadlist,  { NTP_UINT, NTP_UINT, NO, NO },
1352b15cb3dSCy Schubert 	  { "assocIDlow", "assocIDhigh", "", "" },
136ea906c41SOllivier Robert 	  "read the peer variables in the variable list for multiple peers" },
137ea906c41SOllivier Robert 	{ "mreadvar",   mreadvar,   { NTP_UINT, NTP_UINT, OPT|NTP_STR, NO },
1382b15cb3dSCy Schubert 	  { "assocIDlow", "assocIDhigh", "name=value[,...]", "" },
139ea906c41SOllivier Robert 	  "read peer variables from multiple peers" },
140ea906c41SOllivier Robert 	{ "mrv",    mreadvar,   { NTP_UINT, NTP_UINT, OPT|NTP_STR, NO },
1412b15cb3dSCy Schubert 	  { "assocIDlow", "assocIDhigh", "name=value[,...]", "" },
142ea906c41SOllivier Robert 	  "read peer variables from multiple peers" },
143ea906c41SOllivier Robert 	{ "clocklist",  clocklist,  { OPT|NTP_UINT, NO, NO, NO },
144ea906c41SOllivier Robert 	  { "assocID", "", "", "" },
145ea906c41SOllivier Robert 	  "read the clock variables included in the variable list" },
146ea906c41SOllivier Robert 	{ "cl",     clocklist,  { OPT|NTP_UINT, NO, NO, NO },
147ea906c41SOllivier Robert 	  { "assocID", "", "", "" },
148ea906c41SOllivier Robert 	  "read the clock variables included in the variable list" },
149ea906c41SOllivier Robert 	{ "clockvar",   clockvar,   { OPT|NTP_UINT, OPT|NTP_STR, NO, NO },
150ea906c41SOllivier Robert 	  { "assocID", "name=value[,...]", "", "" },
151ea906c41SOllivier Robert 	  "read clock variables" },
152ea906c41SOllivier Robert 	{ "cv",     clockvar,   { OPT|NTP_UINT, OPT|NTP_STR, NO, NO },
153ea906c41SOllivier Robert 	  { "assocID", "name=value[,...]", "", "" },
154ea906c41SOllivier Robert 	  "read clock variables" },
1552b15cb3dSCy Schubert 	{ "pstats",    pstats,    { NTP_UINT, NO, NO, NO },
156ea906c41SOllivier Robert 	  { "assocID", "", "", "" },
1572b15cb3dSCy Schubert 	  "show statistics for a peer" },
158ea906c41SOllivier Robert 	{ "peers",  peers,      { OPT|IP_VERSION, NO, NO, NO },
159ea906c41SOllivier Robert 	  { "-4|-6", "", "", "" },
160ea906c41SOllivier Robert 	  "obtain and print a list of the server's peers [IP version]" },
161276da39aSCy Schubert 	{ "apeers",  apeers,      { OPT|IP_VERSION, NO, NO, NO },
162276da39aSCy Schubert 	  { "-4|-6", "", "", "" },
163276da39aSCy Schubert 	  "obtain and print a list of the server's peers and their assocIDs [IP version]" },
164ea906c41SOllivier Robert 	{ "lpeers", lpeers,     { OPT|IP_VERSION, NO, NO, NO },
165ea906c41SOllivier Robert 	  { "-4|-6", "", "", "" },
166ea906c41SOllivier Robert 	  "obtain and print a list of all peers and clients [IP version]" },
167ea906c41SOllivier Robert 	{ "opeers", opeers,     { OPT|IP_VERSION, NO, NO, NO },
168ea906c41SOllivier Robert 	  { "-4|-6", "", "", "" },
169ea906c41SOllivier Robert 	  "print peer list the old way, with dstadr shown rather than refid [IP version]" },
170ea906c41SOllivier Robert 	{ "lopeers", lopeers,   { OPT|IP_VERSION, NO, NO, NO },
171ea906c41SOllivier Robert 	  { "-4|-6", "", "", "" },
172ea906c41SOllivier Robert 	  "obtain and print a list of all peers and clients showing dstadr [IP version]" },
1732b15cb3dSCy Schubert 	{ ":config", config,   { NTP_STR, NO, NO, NO },
1742b15cb3dSCy Schubert 	  { "<configuration command line>", "", "", "" },
1752b15cb3dSCy Schubert 	  "send a remote configuration command to ntpd" },
1762b15cb3dSCy Schubert 	{ "config-from-file", config_from_file, { NTP_STR, NO, NO, NO },
1772b15cb3dSCy Schubert 	  { "<configuration filename>", "", "", "" },
1782b15cb3dSCy Schubert 	  "configure ntpd using the configuration filename" },
1792b15cb3dSCy Schubert 	{ "mrulist", mrulist, { OPT|NTP_STR, OPT|NTP_STR, OPT|NTP_STR, OPT|NTP_STR },
1802b15cb3dSCy Schubert 	  { "tag=value", "tag=value", "tag=value", "tag=value" },
1812b15cb3dSCy Schubert 	  "display the list of most recently seen source addresses, tags mincount=... resall=0x... resany=0x..." },
1822b15cb3dSCy Schubert 	{ "ifstats", ifstats, { NO, NO, NO, NO },
1832b15cb3dSCy Schubert 	  { "", "", "", "" },
1842b15cb3dSCy Schubert 	  "show statistics for each local address ntpd is using" },
1852b15cb3dSCy Schubert 	{ "reslist", reslist, { NO, NO, NO, NO },
1862b15cb3dSCy Schubert 	  { "", "", "", "" },
1872b15cb3dSCy Schubert 	  "show ntpd access control list" },
1882b15cb3dSCy Schubert 	{ "sysinfo", sysinfo, { NO, NO, NO, NO },
1892b15cb3dSCy Schubert 	  { "", "", "", "" },
1902b15cb3dSCy Schubert 	  "display system summary" },
1912b15cb3dSCy Schubert 	{ "kerninfo", kerninfo, { NO, NO, NO, NO },
1922b15cb3dSCy Schubert 	  { "", "", "", "" },
1932b15cb3dSCy Schubert 	  "display kernel loop and PPS statistics" },
1942b15cb3dSCy Schubert 	{ "sysstats", sysstats, { NO, NO, NO, NO },
1952b15cb3dSCy Schubert 	  { "", "", "", "" },
1962b15cb3dSCy Schubert 	  "display system uptime and packet counts" },
1972b15cb3dSCy Schubert 	{ "monstats", monstats, { NO, NO, NO, NO },
1982b15cb3dSCy Schubert 	  { "", "", "", "" },
1992b15cb3dSCy Schubert 	  "display monitor (mrulist) counters and limits" },
2002b15cb3dSCy Schubert 	{ "authinfo", authinfo, { NO, NO, NO, NO },
2012b15cb3dSCy Schubert 	  { "", "", "", "" },
2022b15cb3dSCy Schubert 	  "display symmetric authentication counters" },
2032b15cb3dSCy Schubert 	{ "iostats", iostats, { NO, NO, NO, NO },
2042b15cb3dSCy Schubert 	  { "", "", "", "" },
2052b15cb3dSCy Schubert 	  "display network input and output counters" },
2062b15cb3dSCy Schubert 	{ "timerstats", timerstats, { NO, NO, NO, NO },
2072b15cb3dSCy Schubert 	  { "", "", "", "" },
2082b15cb3dSCy Schubert 	  "display interval timer counters" },
209ea906c41SOllivier Robert 	{ 0,		0,		{ NO, NO, NO, NO },
210ea906c41SOllivier Robert 	  { "-4|-6", "", "", "" }, "" }
211ea906c41SOllivier Robert };
212ea906c41SOllivier Robert 
213ea906c41SOllivier Robert 
214ea906c41SOllivier Robert /*
215ea906c41SOllivier Robert  * Variable list data space
216ea906c41SOllivier Robert  */
2172b15cb3dSCy Schubert #define MAXLINE		512	/* maximum length of a line */
2182b15cb3dSCy Schubert #define MAXLIST		128	/* maximum variables in list */
2192b15cb3dSCy Schubert #define LENHOSTNAME	256	/* host name limit */
2202b15cb3dSCy Schubert 
2212b15cb3dSCy Schubert #define MRU_GOT_COUNT	0x1
2222b15cb3dSCy Schubert #define MRU_GOT_LAST	0x2
2232b15cb3dSCy Schubert #define MRU_GOT_FIRST	0x4
2242b15cb3dSCy Schubert #define MRU_GOT_MV	0x8
2252b15cb3dSCy Schubert #define MRU_GOT_RS	0x10
2262b15cb3dSCy Schubert #define MRU_GOT_ADDR	0x20
2272b15cb3dSCy Schubert #define MRU_GOT_ALL	(MRU_GOT_COUNT | MRU_GOT_LAST | MRU_GOT_FIRST \
2282b15cb3dSCy Schubert 			 | MRU_GOT_MV | MRU_GOT_RS | MRU_GOT_ADDR)
2292b15cb3dSCy Schubert 
2302b15cb3dSCy Schubert /*
2312b15cb3dSCy Schubert  * mrulist() depends on MRUSORT_DEF and MRUSORT_RDEF being the first two
2322b15cb3dSCy Schubert  */
2332b15cb3dSCy Schubert typedef enum mru_sort_order_tag {
2342b15cb3dSCy Schubert 	MRUSORT_DEF = 0,	/* lstint ascending */
2352b15cb3dSCy Schubert 	MRUSORT_R_DEF,		/* lstint descending */
2362b15cb3dSCy Schubert 	MRUSORT_AVGINT,		/* avgint ascending */
2372b15cb3dSCy Schubert 	MRUSORT_R_AVGINT,	/* avgint descending */
2382b15cb3dSCy Schubert 	MRUSORT_ADDR,		/* IPv4 asc. then IPv6 asc. */
2392b15cb3dSCy Schubert 	MRUSORT_R_ADDR,		/* IPv6 desc. then IPv4 desc. */
2402b15cb3dSCy Schubert 	MRUSORT_COUNT,		/* hit count ascending */
2412b15cb3dSCy Schubert 	MRUSORT_R_COUNT,	/* hit count descending */
2422b15cb3dSCy Schubert 	MRUSORT_MAX,		/* special: count of this enum */
2432b15cb3dSCy Schubert } mru_sort_order;
2442b15cb3dSCy Schubert 
2452b15cb3dSCy Schubert const char * const mru_sort_keywords[MRUSORT_MAX] = {
2462b15cb3dSCy Schubert 	"lstint",		/* MRUSORT_DEF */
2472b15cb3dSCy Schubert 	"-lstint",		/* MRUSORT_R_DEF */
2482b15cb3dSCy Schubert 	"avgint",		/* MRUSORT_AVGINT */
2492b15cb3dSCy Schubert 	"-avgint",		/* MRUSORT_R_AVGINT */
2502b15cb3dSCy Schubert 	"addr",			/* MRUSORT_ADDR */
2512b15cb3dSCy Schubert 	"-addr",		/* MRUSORT_R_ADDR */
2522b15cb3dSCy Schubert 	"count",		/* MRUSORT_COUNT */
2532b15cb3dSCy Schubert 	"-count",		/* MRUSORT_R_COUNT */
2542b15cb3dSCy Schubert };
2552b15cb3dSCy Schubert 
2562b15cb3dSCy Schubert typedef int (*qsort_cmp)(const void *, const void *);
2572b15cb3dSCy Schubert 
258ea906c41SOllivier Robert /*
259ea906c41SOllivier Robert  * Old CTL_PST defines for version 2.
260ea906c41SOllivier Robert  */
261ea906c41SOllivier Robert #define OLD_CTL_PST_CONFIG		0x80
262ea906c41SOllivier Robert #define OLD_CTL_PST_AUTHENABLE		0x40
263ea906c41SOllivier Robert #define OLD_CTL_PST_AUTHENTIC		0x20
264ea906c41SOllivier Robert #define OLD_CTL_PST_REACH		0x10
265ea906c41SOllivier Robert #define OLD_CTL_PST_SANE		0x08
266ea906c41SOllivier Robert #define OLD_CTL_PST_DISP		0x04
2672b15cb3dSCy Schubert 
268ea906c41SOllivier Robert #define OLD_CTL_PST_SEL_REJECT		0
269ea906c41SOllivier Robert #define OLD_CTL_PST_SEL_SELCAND 	1
270ea906c41SOllivier Robert #define OLD_CTL_PST_SEL_SYNCCAND	2
271ea906c41SOllivier Robert #define OLD_CTL_PST_SEL_SYSPEER 	3
272ea906c41SOllivier Robert 
273ea906c41SOllivier Robert char flash2[] = " .+*    "; /* flash decode for version 2 */
274ea906c41SOllivier Robert char flash3[] = " x.-+#*o"; /* flash decode for peer status version 3 */
275ea906c41SOllivier Robert 
276ea906c41SOllivier Robert struct varlist {
2772b15cb3dSCy Schubert 	const char *name;
278ea906c41SOllivier Robert 	char *value;
2792b15cb3dSCy Schubert } g_varlist[MAXLIST] = { { 0, 0 } };
280ea906c41SOllivier Robert 
281ea906c41SOllivier Robert /*
282ea906c41SOllivier Robert  * Imported from ntpq.c
283ea906c41SOllivier Robert  */
284ea906c41SOllivier Robert extern int showhostnames;
2852b15cb3dSCy Schubert extern int wideremote;
286ea906c41SOllivier Robert extern int rawmode;
287ea906c41SOllivier Robert extern struct servent *server_entry;
2882b15cb3dSCy Schubert extern struct association *assoc_cache;
289ea906c41SOllivier Robert extern u_char pktversion;
2902b15cb3dSCy Schubert 
2912b15cb3dSCy Schubert typedef struct mru_tag mru;
2922b15cb3dSCy Schubert struct mru_tag {
2932b15cb3dSCy Schubert 	mru *		hlink;	/* next in hash table bucket */
2942b15cb3dSCy Schubert 	DECL_DLIST_LINK(mru, mlink);
2952b15cb3dSCy Schubert 	int		count;
2962b15cb3dSCy Schubert 	l_fp		last;
2972b15cb3dSCy Schubert 	l_fp		first;
2982b15cb3dSCy Schubert 	u_char		mode;
2992b15cb3dSCy Schubert 	u_char		ver;
3002b15cb3dSCy Schubert 	u_short		rs;
3012b15cb3dSCy Schubert 	sockaddr_u	addr;
3022b15cb3dSCy Schubert };
3032b15cb3dSCy Schubert 
3042b15cb3dSCy Schubert typedef struct ifstats_row_tag {
3052b15cb3dSCy Schubert 	u_int		ifnum;
3062b15cb3dSCy Schubert 	sockaddr_u	addr;
3072b15cb3dSCy Schubert 	sockaddr_u	bcast;
3082b15cb3dSCy Schubert 	int		enabled;
3092b15cb3dSCy Schubert 	u_int		flags;
31009100258SXin LI 	u_int		mcast_count;
3112b15cb3dSCy Schubert 	char		name[32];
31209100258SXin LI 	u_int		peer_count;
31309100258SXin LI 	u_int		received;
31409100258SXin LI 	u_int		sent;
31509100258SXin LI 	u_int		send_errors;
3162b15cb3dSCy Schubert 	u_int		ttl;
3172b15cb3dSCy Schubert 	u_int		uptime;
3182b15cb3dSCy Schubert } ifstats_row;
3192b15cb3dSCy Schubert 
3202b15cb3dSCy Schubert typedef struct reslist_row_tag {
3212b15cb3dSCy Schubert 	u_int		idx;
3222b15cb3dSCy Schubert 	sockaddr_u	addr;
3232b15cb3dSCy Schubert 	sockaddr_u	mask;
3242b15cb3dSCy Schubert 	u_long		hits;
3252b15cb3dSCy Schubert 	char		flagstr[128];
3262b15cb3dSCy Schubert } reslist_row;
3272b15cb3dSCy Schubert 
3282b15cb3dSCy Schubert typedef struct var_display_collection_tag {
3292b15cb3dSCy Schubert 	const char * const tag;		/* system variable */
3302b15cb3dSCy Schubert 	const char * const display;	/* descriptive text */
3312b15cb3dSCy Schubert 	u_char type;			/* NTP_STR, etc */
3322b15cb3dSCy Schubert 	union {
3332b15cb3dSCy Schubert 		char *		str;
3342b15cb3dSCy Schubert 		sockaddr_u	sau;	/* NTP_ADD */
3352b15cb3dSCy Schubert 		l_fp		lfp;	/* NTP_LFP */
3362b15cb3dSCy Schubert 	} v;				/* retrieved value */
3372b15cb3dSCy Schubert } vdc;
338a25439b6SCy Schubert #if !defined(MISSING_C99_STRUCT_INIT)
3392b15cb3dSCy Schubert # define VDC_INIT(a, b, c) { .tag = a, .display = b, .type = c }
3402b15cb3dSCy Schubert #else
3412b15cb3dSCy Schubert # define VDC_INIT(a, b, c) { a, b, c }
3422b15cb3dSCy Schubert #endif
3432b15cb3dSCy Schubert /*
3442b15cb3dSCy Schubert  * other local function prototypes
3452b15cb3dSCy Schubert  */
3463311ff84SXin LI static int	mrulist_ctrl_c_hook(void);
3472b15cb3dSCy Schubert static mru *	add_mru(mru *);
3482b15cb3dSCy Schubert static int	collect_mru_list(const char *, l_fp *);
3492b15cb3dSCy Schubert static int	fetch_nonce(char *, size_t);
3502b15cb3dSCy Schubert static int	qcmp_mru_avgint(const void *, const void *);
3512b15cb3dSCy Schubert static int	qcmp_mru_r_avgint(const void *, const void *);
3522b15cb3dSCy Schubert static int	qcmp_mru_addr(const void *, const void *);
3532b15cb3dSCy Schubert static int	qcmp_mru_r_addr(const void *, const void *);
3542b15cb3dSCy Schubert static int	qcmp_mru_count(const void *, const void *);
3552b15cb3dSCy Schubert static int	qcmp_mru_r_count(const void *, const void *);
3562b15cb3dSCy Schubert static void	validate_ifnum(FILE *, u_int, int *, ifstats_row *);
3572b15cb3dSCy Schubert static void	another_ifstats_field(int *, ifstats_row *, FILE *);
3582b15cb3dSCy Schubert static void	collect_display_vdc(associd_t as, vdc *table,
3592b15cb3dSCy Schubert 				    int decodestatus, FILE *fp);
360ea906c41SOllivier Robert 
3612d4e511cSCy Schubert static	int	xprintf(FILE *,	char const *, ...) NTP_PRINTF(2, 3);
3622d4e511cSCy Schubert static	int	xputs(char const *, FILE *);
3632d4e511cSCy Schubert static	int	xputc(int, FILE *);
3642d4e511cSCy Schubert 
365ea906c41SOllivier Robert /*
3662b15cb3dSCy Schubert  * static globals
367ea906c41SOllivier Robert  */
3682b15cb3dSCy Schubert static u_int	mru_count;
3692b15cb3dSCy Schubert static u_int	mru_dupes;
3702b15cb3dSCy Schubert volatile int	mrulist_interrupted;
3712b15cb3dSCy Schubert static mru	mru_list;		/* listhead */
3722b15cb3dSCy Schubert static mru **	hash_table;
373ea906c41SOllivier Robert 
3742b15cb3dSCy Schubert /*
3752b15cb3dSCy Schubert  * qsort comparison function table for mrulist().  The first two
3762b15cb3dSCy Schubert  * entries are NULL because they are handled without qsort().
3772b15cb3dSCy Schubert  */
3782b15cb3dSCy Schubert static const qsort_cmp mru_qcmp_table[MRUSORT_MAX] = {
3792b15cb3dSCy Schubert 	NULL,			/* MRUSORT_DEF unused */
3802b15cb3dSCy Schubert 	NULL,			/* MRUSORT_R_DEF unused */
3812b15cb3dSCy Schubert 	&qcmp_mru_avgint,	/* MRUSORT_AVGINT */
3822b15cb3dSCy Schubert 	&qcmp_mru_r_avgint,	/* MRUSORT_R_AVGINT */
3832b15cb3dSCy Schubert 	&qcmp_mru_addr,		/* MRUSORT_ADDR */
3842b15cb3dSCy Schubert 	&qcmp_mru_r_addr,	/* MRUSORT_R_ADDR */
3852b15cb3dSCy Schubert 	&qcmp_mru_count,	/* MRUSORT_COUNT */
3862b15cb3dSCy Schubert 	&qcmp_mru_r_count,	/* MRUSORT_R_COUNT */
3872b15cb3dSCy Schubert };
388ea906c41SOllivier Robert 
389ea906c41SOllivier Robert /*
3902d4e511cSCy Schubert  * NULL-pointer safe FILE I/O: use stderr if no file supplied.
3912d4e511cSCy Schubert  */
3922d4e511cSCy Schubert static	int
3932d4e511cSCy Schubert xprintf(
3942d4e511cSCy Schubert 	FILE *		ofp,
3952d4e511cSCy Schubert 	char const *	fmt,
3962d4e511cSCy Schubert 	...
3972d4e511cSCy Schubert 	)
3982d4e511cSCy Schubert {
3992d4e511cSCy Schubert 	va_list	va;
4002d4e511cSCy Schubert 	int	rc;
4012d4e511cSCy Schubert 
4022d4e511cSCy Schubert 	va_start(va, fmt);
4032d4e511cSCy Schubert 	rc = vfprintf((ofp ? ofp : stderr), fmt, va);
4042d4e511cSCy Schubert 	va_end(va);
4052d4e511cSCy Schubert 	return rc;
4062d4e511cSCy Schubert }
4072d4e511cSCy Schubert 
4082d4e511cSCy Schubert static	int
4092d4e511cSCy Schubert xputs(
4102d4e511cSCy Schubert 	char const *	str,
4112d4e511cSCy Schubert 	FILE *		ofp
4122d4e511cSCy Schubert 	)
4132d4e511cSCy Schubert {
4142d4e511cSCy Schubert 	return fputs(str, (ofp ? ofp : stderr));
4152d4e511cSCy Schubert }
4162d4e511cSCy Schubert 
4172d4e511cSCy Schubert static	int
4182d4e511cSCy Schubert xputc(
4192d4e511cSCy Schubert 	int	ch,
4202d4e511cSCy Schubert 	FILE *	ofp
4212d4e511cSCy Schubert 	)
4222d4e511cSCy Schubert {
4232d4e511cSCy Schubert 	return fputc(ch, (ofp ? ofp : stderr));
4242d4e511cSCy Schubert }
4252d4e511cSCy Schubert 
4262d4e511cSCy Schubert /*
427ea906c41SOllivier Robert  * checkassocid - return the association ID, checking to see if it is valid
428ea906c41SOllivier Robert  */
4292b15cb3dSCy Schubert static associd_t
430ea906c41SOllivier Robert checkassocid(
431ea906c41SOllivier Robert 	u_int32 value
432ea906c41SOllivier Robert 	)
433ea906c41SOllivier Robert {
4342b15cb3dSCy Schubert 	associd_t	associd;
4352b15cb3dSCy Schubert 	u_long		ulvalue;
4362b15cb3dSCy Schubert 
4372b15cb3dSCy Schubert 	associd = (associd_t)value;
4382b15cb3dSCy Schubert 	if (0 == associd || value != associd) {
4392b15cb3dSCy Schubert 		ulvalue = value;
4402d4e511cSCy Schubert 		xprintf(stderr,
4412b15cb3dSCy Schubert 			"***Invalid association ID %lu specified\n",
4422b15cb3dSCy Schubert 			ulvalue);
443ea906c41SOllivier Robert 		return 0;
444ea906c41SOllivier Robert 	}
4452b15cb3dSCy Schubert 
4462b15cb3dSCy Schubert 	return associd;
447ea906c41SOllivier Robert }
448ea906c41SOllivier Robert 
449ea906c41SOllivier Robert 
450ea906c41SOllivier Robert /*
4512b15cb3dSCy Schubert  * findlistvar - Look for the named variable in a varlist.  If found,
4522b15cb3dSCy Schubert  *		 return a pointer to it.  Otherwise, if the list has
4532b15cb3dSCy Schubert  *		 slots available, return the pointer to the first free
4542b15cb3dSCy Schubert  *		 slot, or NULL if it's full.
455ea906c41SOllivier Robert  */
456ea906c41SOllivier Robert static struct varlist *
457ea906c41SOllivier Robert findlistvar(
458ea906c41SOllivier Robert 	struct varlist *list,
459ea906c41SOllivier Robert 	char *name
460ea906c41SOllivier Robert 	)
461ea906c41SOllivier Robert {
4622b15cb3dSCy Schubert 	struct varlist *vl;
463ea906c41SOllivier Robert 
4642b15cb3dSCy Schubert 	for (vl = list; vl < list + MAXLIST && vl->name != NULL; vl++)
4652b15cb3dSCy Schubert 		if (!strcmp(name, vl->name))
466ea906c41SOllivier Robert 			return vl;
467ea906c41SOllivier Robert 	if (vl < list + MAXLIST)
468ea906c41SOllivier Robert 		return vl;
4692b15cb3dSCy Schubert 
4702b15cb3dSCy Schubert 	return NULL;
471ea906c41SOllivier Robert }
472ea906c41SOllivier Robert 
473ea906c41SOllivier Robert 
474ea906c41SOllivier Robert /*
475ea906c41SOllivier Robert  * doaddvlist - add variable(s) to the variable list
476ea906c41SOllivier Robert  */
477ea906c41SOllivier Robert static void
478ea906c41SOllivier Robert doaddvlist(
479ea906c41SOllivier Robert 	struct varlist *vlist,
4802b15cb3dSCy Schubert 	const char *vars
481ea906c41SOllivier Robert 	)
482ea906c41SOllivier Robert {
4832b15cb3dSCy Schubert 	struct varlist *vl;
4843311ff84SXin LI 	size_t len;
485ea906c41SOllivier Robert 	char *name;
486ea906c41SOllivier Robert 	char *value;
487ea906c41SOllivier Robert 
488ea906c41SOllivier Robert 	len = strlen(vars);
489ea906c41SOllivier Robert 	while (nextvar(&len, &vars, &name, &value)) {
4904e1ef62aSXin LI 		INSIST(name && value);
491ea906c41SOllivier Robert 		vl = findlistvar(vlist, name);
4922b15cb3dSCy Schubert 		if (NULL == vl) {
4932d4e511cSCy Schubert 			xprintf(stderr, "Variable list full\n");
494ea906c41SOllivier Robert 			return;
495ea906c41SOllivier Robert 		}
496ea906c41SOllivier Robert 
4972b15cb3dSCy Schubert 		if (NULL == vl->name) {
4982b15cb3dSCy Schubert 			vl->name = estrdup(name);
4992b15cb3dSCy Schubert 		} else if (vl->value != NULL) {
500ea906c41SOllivier Robert 			free(vl->value);
5012b15cb3dSCy Schubert 			vl->value = NULL;
502ea906c41SOllivier Robert 		}
503ea906c41SOllivier Robert 
5042b15cb3dSCy Schubert 		if (value != NULL)
5052b15cb3dSCy Schubert 			vl->value = estrdup(value);
506ea906c41SOllivier Robert 	}
507ea906c41SOllivier Robert }
508ea906c41SOllivier Robert 
509ea906c41SOllivier Robert 
510ea906c41SOllivier Robert /*
511ea906c41SOllivier Robert  * dormvlist - remove variable(s) from the variable list
512ea906c41SOllivier Robert  */
513ea906c41SOllivier Robert static void
514ea906c41SOllivier Robert dormvlist(
515ea906c41SOllivier Robert 	struct varlist *vlist,
5162b15cb3dSCy Schubert 	const char *vars
517ea906c41SOllivier Robert 	)
518ea906c41SOllivier Robert {
5192b15cb3dSCy Schubert 	struct varlist *vl;
5203311ff84SXin LI 	size_t len;
521ea906c41SOllivier Robert 	char *name;
522ea906c41SOllivier Robert 	char *value;
523ea906c41SOllivier Robert 
524ea906c41SOllivier Robert 	len = strlen(vars);
525ea906c41SOllivier Robert 	while (nextvar(&len, &vars, &name, &value)) {
5264e1ef62aSXin LI 		INSIST(name && value);
527ea906c41SOllivier Robert 		vl = findlistvar(vlist, name);
528ea906c41SOllivier Robert 		if (vl == 0 || vl->name == 0) {
5292d4e511cSCy Schubert 			(void) xprintf(stderr, "Variable `%s' not found\n",
530ea906c41SOllivier Robert 				       name);
531ea906c41SOllivier Robert 		} else {
5322b15cb3dSCy Schubert 			free((void *)(intptr_t)vl->name);
533ea906c41SOllivier Robert 			if (vl->value != 0)
534ea906c41SOllivier Robert 			    free(vl->value);
5352b15cb3dSCy Schubert 			for ( ; (vl+1) < (g_varlist + MAXLIST)
536ea906c41SOllivier Robert 				      && (vl+1)->name != 0; vl++) {
537ea906c41SOllivier Robert 				vl->name = (vl+1)->name;
538ea906c41SOllivier Robert 				vl->value = (vl+1)->value;
539ea906c41SOllivier Robert 			}
540ea906c41SOllivier Robert 			vl->name = vl->value = 0;
541ea906c41SOllivier Robert 		}
542ea906c41SOllivier Robert 	}
543ea906c41SOllivier Robert }
544ea906c41SOllivier Robert 
545ea906c41SOllivier Robert 
546ea906c41SOllivier Robert /*
547ea906c41SOllivier Robert  * doclearvlist - clear a variable list
548ea906c41SOllivier Robert  */
549ea906c41SOllivier Robert static void
550ea906c41SOllivier Robert doclearvlist(
551ea906c41SOllivier Robert 	struct varlist *vlist
552ea906c41SOllivier Robert 	)
553ea906c41SOllivier Robert {
554ea906c41SOllivier Robert 	register struct varlist *vl;
555ea906c41SOllivier Robert 
556ea906c41SOllivier Robert 	for (vl = vlist; vl < vlist + MAXLIST && vl->name != 0; vl++) {
5572b15cb3dSCy Schubert 		free((void *)(intptr_t)vl->name);
558ea906c41SOllivier Robert 		vl->name = 0;
559ea906c41SOllivier Robert 		if (vl->value != 0) {
560ea906c41SOllivier Robert 			free(vl->value);
561ea906c41SOllivier Robert 			vl->value = 0;
562ea906c41SOllivier Robert 		}
563ea906c41SOllivier Robert 	}
564ea906c41SOllivier Robert }
565ea906c41SOllivier Robert 
566ea906c41SOllivier Robert 
567ea906c41SOllivier Robert /*
568ea906c41SOllivier Robert  * makequerydata - form a data buffer to be included with a query
569ea906c41SOllivier Robert  */
570ea906c41SOllivier Robert static void
571ea906c41SOllivier Robert makequerydata(
572ea906c41SOllivier Robert 	struct varlist *vlist,
5733311ff84SXin LI 	size_t *datalen,
574ea906c41SOllivier Robert 	char *data
575ea906c41SOllivier Robert 	)
576ea906c41SOllivier Robert {
577ea906c41SOllivier Robert 	register struct varlist *vl;
578ea906c41SOllivier Robert 	register char *cp, *cpend;
5793311ff84SXin LI 	register size_t namelen, valuelen;
5803311ff84SXin LI 	register size_t totallen;
581ea906c41SOllivier Robert 
582ea906c41SOllivier Robert 	cp = data;
583ea906c41SOllivier Robert 	cpend = data + *datalen;
584ea906c41SOllivier Robert 
585ea906c41SOllivier Robert 	for (vl = vlist; vl < vlist + MAXLIST && vl->name != 0; vl++) {
586ea906c41SOllivier Robert 		namelen = strlen(vl->name);
587ea906c41SOllivier Robert 		if (vl->value == 0)
588ea906c41SOllivier Robert 			valuelen = 0;
589ea906c41SOllivier Robert 		else
590ea906c41SOllivier Robert 			valuelen = strlen(vl->value);
591ea906c41SOllivier Robert 		totallen = namelen + valuelen + (valuelen != 0) + (cp != data);
5922b15cb3dSCy Schubert 		if (cp + totallen > cpend) {
5932d4e511cSCy Schubert 		    xprintf(stderr,
5942b15cb3dSCy Schubert 			    "***Ignoring variables starting with `%s'\n",
5952b15cb3dSCy Schubert 			    vl->name);
596ea906c41SOllivier Robert 		    break;
5972b15cb3dSCy Schubert 		}
598ea906c41SOllivier Robert 
599ea906c41SOllivier Robert 		if (cp != data)
600ea906c41SOllivier Robert 			*cp++ = ',';
6012b15cb3dSCy Schubert 		memcpy(cp, vl->name, (size_t)namelen);
602ea906c41SOllivier Robert 		cp += namelen;
603ea906c41SOllivier Robert 		if (valuelen != 0) {
604ea906c41SOllivier Robert 			*cp++ = '=';
6052b15cb3dSCy Schubert 			memcpy(cp, vl->value, (size_t)valuelen);
606ea906c41SOllivier Robert 			cp += valuelen;
607ea906c41SOllivier Robert 		}
608ea906c41SOllivier Robert 	}
6093311ff84SXin LI 	*datalen = (size_t)(cp - data);
610ea906c41SOllivier Robert }
611ea906c41SOllivier Robert 
612ea906c41SOllivier Robert 
613ea906c41SOllivier Robert /*
614ea906c41SOllivier Robert  * doquerylist - send a message including variables in a list
615ea906c41SOllivier Robert  */
616ea906c41SOllivier Robert static int
617ea906c41SOllivier Robert doquerylist(
618ea906c41SOllivier Robert 	struct varlist *vlist,
619ea906c41SOllivier Robert 	int op,
6202b15cb3dSCy Schubert 	associd_t associd,
621ea906c41SOllivier Robert 	int auth,
622ea906c41SOllivier Robert 	u_short *rstatus,
6233311ff84SXin LI 	size_t *dsize,
6242b15cb3dSCy Schubert 	const char **datap
625ea906c41SOllivier Robert 	)
626ea906c41SOllivier Robert {
627ea906c41SOllivier Robert 	char data[CTL_MAX_DATA_LEN];
6283311ff84SXin LI 	size_t datalen;
629ea906c41SOllivier Robert 
630ea906c41SOllivier Robert 	datalen = sizeof(data);
631ea906c41SOllivier Robert 	makequerydata(vlist, &datalen, data);
632ea906c41SOllivier Robert 
6332b15cb3dSCy Schubert 	return doquery(op, associd, auth, datalen, data, rstatus, dsize,
6342b15cb3dSCy Schubert 		       datap);
635ea906c41SOllivier Robert }
636ea906c41SOllivier Robert 
637ea906c41SOllivier Robert 
638ea906c41SOllivier Robert /*
639ea906c41SOllivier Robert  * doprintvlist - print the variables on a list
640ea906c41SOllivier Robert  */
641ea906c41SOllivier Robert static void
642ea906c41SOllivier Robert doprintvlist(
643ea906c41SOllivier Robert 	struct varlist *vlist,
644ea906c41SOllivier Robert 	FILE *fp
645ea906c41SOllivier Robert 	)
646ea906c41SOllivier Robert {
6472b15cb3dSCy Schubert 	size_t n;
648ea906c41SOllivier Robert 
6492b15cb3dSCy Schubert 	if (NULL == vlist->name) {
6502d4e511cSCy Schubert 		xprintf(fp, "No variables on list\n");
6512b15cb3dSCy Schubert 		return;
6522b15cb3dSCy Schubert 	}
6532b15cb3dSCy Schubert 	for (n = 0; n < MAXLIST && vlist[n].name != NULL; n++) {
6542b15cb3dSCy Schubert 		if (NULL == vlist[n].value)
6552d4e511cSCy Schubert 			xprintf(fp, "%s\n", vlist[n].name);
6562b15cb3dSCy Schubert 		else
6572d4e511cSCy Schubert 			xprintf(fp, "%s=%s\n", vlist[n].name,
6582b15cb3dSCy Schubert 				vlist[n].value);
659ea906c41SOllivier Robert 	}
660ea906c41SOllivier Robert }
661ea906c41SOllivier Robert 
662ea906c41SOllivier Robert /*
663ea906c41SOllivier Robert  * addvars - add variables to the variable list
664ea906c41SOllivier Robert  */
665ea906c41SOllivier Robert /*ARGSUSED*/
666ea906c41SOllivier Robert static void
667ea906c41SOllivier Robert addvars(
668ea906c41SOllivier Robert 	struct parse *pcmd,
669ea906c41SOllivier Robert 	FILE *fp
670ea906c41SOllivier Robert 	)
671ea906c41SOllivier Robert {
6722b15cb3dSCy Schubert 	doaddvlist(g_varlist, pcmd->argval[0].string);
673ea906c41SOllivier Robert }
674ea906c41SOllivier Robert 
675ea906c41SOllivier Robert 
676ea906c41SOllivier Robert /*
677ea906c41SOllivier Robert  * rmvars - remove variables from the variable list
678ea906c41SOllivier Robert  */
679ea906c41SOllivier Robert /*ARGSUSED*/
680ea906c41SOllivier Robert static void
681ea906c41SOllivier Robert rmvars(
682ea906c41SOllivier Robert 	struct parse *pcmd,
683ea906c41SOllivier Robert 	FILE *fp
684ea906c41SOllivier Robert 	)
685ea906c41SOllivier Robert {
6862b15cb3dSCy Schubert 	dormvlist(g_varlist, pcmd->argval[0].string);
687ea906c41SOllivier Robert }
688ea906c41SOllivier Robert 
689ea906c41SOllivier Robert 
690ea906c41SOllivier Robert /*
691ea906c41SOllivier Robert  * clearvars - clear the variable list
692ea906c41SOllivier Robert  */
693ea906c41SOllivier Robert /*ARGSUSED*/
694ea906c41SOllivier Robert static void
695ea906c41SOllivier Robert clearvars(
696ea906c41SOllivier Robert 	struct parse *pcmd,
697ea906c41SOllivier Robert 	FILE *fp
698ea906c41SOllivier Robert 	)
699ea906c41SOllivier Robert {
7002b15cb3dSCy Schubert 	doclearvlist(g_varlist);
701ea906c41SOllivier Robert }
702ea906c41SOllivier Robert 
703ea906c41SOllivier Robert 
704ea906c41SOllivier Robert /*
705ea906c41SOllivier Robert  * showvars - show variables on the variable list
706ea906c41SOllivier Robert  */
707ea906c41SOllivier Robert /*ARGSUSED*/
708ea906c41SOllivier Robert static void
709ea906c41SOllivier Robert showvars(
710ea906c41SOllivier Robert 	struct parse *pcmd,
711ea906c41SOllivier Robert 	FILE *fp
712ea906c41SOllivier Robert 	)
713ea906c41SOllivier Robert {
7142b15cb3dSCy Schubert 	doprintvlist(g_varlist, fp);
715ea906c41SOllivier Robert }
716ea906c41SOllivier Robert 
717ea906c41SOllivier Robert 
718ea906c41SOllivier Robert /*
719ea906c41SOllivier Robert  * dolist - send a request with the given list of variables
720ea906c41SOllivier Robert  */
721ea906c41SOllivier Robert static int
722ea906c41SOllivier Robert dolist(
723ea906c41SOllivier Robert 	struct varlist *vlist,
7242b15cb3dSCy Schubert 	associd_t associd,
725ea906c41SOllivier Robert 	int op,
726ea906c41SOllivier Robert 	int type,
727ea906c41SOllivier Robert 	FILE *fp
728ea906c41SOllivier Robert 	)
729ea906c41SOllivier Robert {
7302b15cb3dSCy Schubert 	const char *datap;
731ea906c41SOllivier Robert 	int res;
7323311ff84SXin LI 	size_t dsize;
733ea906c41SOllivier Robert 	u_short rstatus;
7342b15cb3dSCy Schubert 	int quiet;
7352b15cb3dSCy Schubert 
7362b15cb3dSCy Schubert 	/*
7372b15cb3dSCy Schubert 	 * if we're asking for specific variables don't include the
7382b15cb3dSCy Schubert 	 * status header line in the output.
7392b15cb3dSCy Schubert 	 */
7402b15cb3dSCy Schubert 	if (old_rv)
7412b15cb3dSCy Schubert 		quiet = 0;
7422b15cb3dSCy Schubert 	else
7432b15cb3dSCy Schubert 		quiet = (vlist->name != NULL);
744ea906c41SOllivier Robert 
745ea906c41SOllivier Robert 	res = doquerylist(vlist, op, associd, 0, &rstatus, &dsize, &datap);
746ea906c41SOllivier Robert 
747ea906c41SOllivier Robert 	if (res != 0)
748ea906c41SOllivier Robert 		return 0;
749ea906c41SOllivier Robert 
750ea906c41SOllivier Robert 	if (numhosts > 1)
7512d4e511cSCy Schubert 		xprintf(fp, "server=%s ", currenthost);
752ea906c41SOllivier Robert 	if (dsize == 0) {
753ea906c41SOllivier Robert 		if (associd == 0)
7542d4e511cSCy Schubert 			xprintf(fp, "No system%s variables returned\n",
755ea906c41SOllivier Robert 				(type == TYPE_CLOCK) ? " clock" : "");
756ea906c41SOllivier Robert 		else
7572d4e511cSCy Schubert 			xprintf(fp,
758ea906c41SOllivier Robert 				"No information returned for%s association %u\n",
7592b15cb3dSCy Schubert 				(type == TYPE_CLOCK) ? " clock" : "",
7602b15cb3dSCy Schubert 				associd);
761ea906c41SOllivier Robert 		return 1;
762ea906c41SOllivier Robert 	}
763ea906c41SOllivier Robert 
7642b15cb3dSCy Schubert 	if (!quiet)
7652d4e511cSCy Schubert 		xprintf(fp, "associd=%u ", associd);
7662b15cb3dSCy Schubert 	printvars(dsize, datap, (int)rstatus, type, quiet, fp);
767ea906c41SOllivier Robert 	return 1;
768ea906c41SOllivier Robert }
769ea906c41SOllivier Robert 
770ea906c41SOllivier Robert 
771ea906c41SOllivier Robert /*
772ea906c41SOllivier Robert  * readlist - send a read variables request with the variables on the list
773ea906c41SOllivier Robert  */
774ea906c41SOllivier Robert static void
775ea906c41SOllivier Robert readlist(
776ea906c41SOllivier Robert 	struct parse *pcmd,
777ea906c41SOllivier Robert 	FILE *fp
778ea906c41SOllivier Robert 	)
779ea906c41SOllivier Robert {
7802b15cb3dSCy Schubert 	associd_t	associd;
7812b15cb3dSCy Schubert 	int		type;
782ea906c41SOllivier Robert 
783ea906c41SOllivier Robert 	if (pcmd->nargs == 0) {
784ea906c41SOllivier Robert 		associd = 0;
785ea906c41SOllivier Robert 	} else {
786ea906c41SOllivier Robert 	  /* HMS: I think we want the u_int32 target here, not the u_long */
787ea906c41SOllivier Robert 		if (pcmd->argval[0].uval == 0)
788ea906c41SOllivier Robert 			associd = 0;
789ea906c41SOllivier Robert 		else if ((associd = checkassocid(pcmd->argval[0].uval)) == 0)
790ea906c41SOllivier Robert 			return;
791ea906c41SOllivier Robert 	}
792ea906c41SOllivier Robert 
7932b15cb3dSCy Schubert 	type = (0 == associd)
7942b15cb3dSCy Schubert 		   ? TYPE_SYS
7952b15cb3dSCy Schubert 		   : TYPE_PEER;
7962b15cb3dSCy Schubert 	dolist(g_varlist, associd, CTL_OP_READVAR, type, fp);
797ea906c41SOllivier Robert }
798ea906c41SOllivier Robert 
799ea906c41SOllivier Robert 
800ea906c41SOllivier Robert /*
801ea906c41SOllivier Robert  * writelist - send a write variables request with the variables on the list
802ea906c41SOllivier Robert  */
803ea906c41SOllivier Robert static void
804ea906c41SOllivier Robert writelist(
805ea906c41SOllivier Robert 	struct parse *pcmd,
806ea906c41SOllivier Robert 	FILE *fp
807ea906c41SOllivier Robert 	)
808ea906c41SOllivier Robert {
8092b15cb3dSCy Schubert 	const char *datap;
810ea906c41SOllivier Robert 	int res;
8112b15cb3dSCy Schubert 	associd_t associd;
8123311ff84SXin LI 	size_t dsize;
813ea906c41SOllivier Robert 	u_short rstatus;
814ea906c41SOllivier Robert 
815ea906c41SOllivier Robert 	if (pcmd->nargs == 0) {
816ea906c41SOllivier Robert 		associd = 0;
817ea906c41SOllivier Robert 	} else {
818ea906c41SOllivier Robert 		/* HMS: Do we really want uval here? */
819ea906c41SOllivier Robert 		if (pcmd->argval[0].uval == 0)
820ea906c41SOllivier Robert 			associd = 0;
821ea906c41SOllivier Robert 		else if ((associd = checkassocid(pcmd->argval[0].uval)) == 0)
822ea906c41SOllivier Robert 			return;
823ea906c41SOllivier Robert 	}
824ea906c41SOllivier Robert 
8252b15cb3dSCy Schubert 	res = doquerylist(g_varlist, CTL_OP_WRITEVAR, associd, 1, &rstatus,
826ea906c41SOllivier Robert 			  &dsize, &datap);
827ea906c41SOllivier Robert 
828ea906c41SOllivier Robert 	if (res != 0)
829ea906c41SOllivier Robert 		return;
830ea906c41SOllivier Robert 
831ea906c41SOllivier Robert 	if (numhosts > 1)
8322d4e511cSCy Schubert 		(void) xprintf(fp, "server=%s ", currenthost);
833ea906c41SOllivier Robert 	if (dsize == 0)
8342d4e511cSCy Schubert 		(void) xprintf(fp, "done! (no data returned)\n");
835ea906c41SOllivier Robert 	else {
8362d4e511cSCy Schubert 		(void) xprintf(fp,"associd=%u ", associd);
837ea906c41SOllivier Robert 		printvars(dsize, datap, (int)rstatus,
8382b15cb3dSCy Schubert 			  (associd != 0) ? TYPE_PEER : TYPE_SYS, 0, fp);
839ea906c41SOllivier Robert 	}
840ea906c41SOllivier Robert 	return;
841ea906c41SOllivier Robert }
842ea906c41SOllivier Robert 
843ea906c41SOllivier Robert 
844ea906c41SOllivier Robert /*
845ea906c41SOllivier Robert  * readvar - send a read variables request with the specified variables
846ea906c41SOllivier Robert  */
847ea906c41SOllivier Robert static void
848ea906c41SOllivier Robert readvar(
849ea906c41SOllivier Robert 	struct parse *pcmd,
850ea906c41SOllivier Robert 	FILE *fp
851ea906c41SOllivier Robert 	)
852ea906c41SOllivier Robert {
8532b15cb3dSCy Schubert 	associd_t	associd;
8543311ff84SXin LI 	size_t		tmpcount;
8553311ff84SXin LI 	size_t		u;
8562b15cb3dSCy Schubert 	int		type;
857ea906c41SOllivier Robert 	struct varlist	tmplist[MAXLIST];
858ea906c41SOllivier Robert 
8592b15cb3dSCy Schubert 
860ea906c41SOllivier Robert 	/* HMS: uval? */
861ea906c41SOllivier Robert 	if (pcmd->nargs == 0 || pcmd->argval[0].uval == 0)
862ea906c41SOllivier Robert 		associd = 0;
863ea906c41SOllivier Robert 	else if ((associd = checkassocid(pcmd->argval[0].uval)) == 0)
864ea906c41SOllivier Robert 		return;
865ea906c41SOllivier Robert 
8662b15cb3dSCy Schubert 	ZERO(tmplist);
8672b15cb3dSCy Schubert 	if (pcmd->nargs > 1) {
8682b15cb3dSCy Schubert 		tmpcount = pcmd->nargs - 1;
8692b15cb3dSCy Schubert 		for (u = 0; u < tmpcount; u++)
8702b15cb3dSCy Schubert 			doaddvlist(tmplist, pcmd->argval[1 + u].string);
8712b15cb3dSCy Schubert 	}
872ea906c41SOllivier Robert 
8732b15cb3dSCy Schubert 	type = (0 == associd)
8742b15cb3dSCy Schubert 		   ? TYPE_SYS
8752b15cb3dSCy Schubert 		   : TYPE_PEER;
8762b15cb3dSCy Schubert 	dolist(tmplist, associd, CTL_OP_READVAR, type, fp);
877ea906c41SOllivier Robert 
878ea906c41SOllivier Robert 	doclearvlist(tmplist);
879ea906c41SOllivier Robert }
880ea906c41SOllivier Robert 
881ea906c41SOllivier Robert 
882ea906c41SOllivier Robert /*
883ea906c41SOllivier Robert  * writevar - send a write variables request with the specified variables
884ea906c41SOllivier Robert  */
885ea906c41SOllivier Robert static void
886ea906c41SOllivier Robert writevar(
887ea906c41SOllivier Robert 	struct parse *pcmd,
888ea906c41SOllivier Robert 	FILE *fp
889ea906c41SOllivier Robert 	)
890ea906c41SOllivier Robert {
8912b15cb3dSCy Schubert 	const char *datap;
892ea906c41SOllivier Robert 	int res;
8932b15cb3dSCy Schubert 	associd_t associd;
8942b15cb3dSCy Schubert 	int type;
8953311ff84SXin LI 	size_t dsize;
896ea906c41SOllivier Robert 	u_short rstatus;
897ea906c41SOllivier Robert 	struct varlist tmplist[MAXLIST];
898ea906c41SOllivier Robert 
899ea906c41SOllivier Robert 	/* HMS: uval? */
900ea906c41SOllivier Robert 	if (pcmd->argval[0].uval == 0)
901ea906c41SOllivier Robert 		associd = 0;
902ea906c41SOllivier Robert 	else if ((associd = checkassocid(pcmd->argval[0].uval)) == 0)
903ea906c41SOllivier Robert 		return;
904ea906c41SOllivier Robert 
9052b15cb3dSCy Schubert 	ZERO(tmplist);
906ea906c41SOllivier Robert 	doaddvlist(tmplist, pcmd->argval[1].string);
907ea906c41SOllivier Robert 
908ea906c41SOllivier Robert 	res = doquerylist(tmplist, CTL_OP_WRITEVAR, associd, 1, &rstatus,
909ea906c41SOllivier Robert 			  &dsize, &datap);
910ea906c41SOllivier Robert 
911ea906c41SOllivier Robert 	doclearvlist(tmplist);
912ea906c41SOllivier Robert 
913ea906c41SOllivier Robert 	if (res != 0)
914ea906c41SOllivier Robert 		return;
915ea906c41SOllivier Robert 
916ea906c41SOllivier Robert 	if (numhosts > 1)
9172d4e511cSCy Schubert 		xprintf(fp, "server=%s ", currenthost);
918ea906c41SOllivier Robert 	if (dsize == 0)
9192d4e511cSCy Schubert 		xprintf(fp, "done! (no data returned)\n");
920ea906c41SOllivier Robert 	else {
9212d4e511cSCy Schubert 		xprintf(fp,"associd=%u ", associd);
9222b15cb3dSCy Schubert 		type = (0 == associd)
9232b15cb3dSCy Schubert 			   ? TYPE_SYS
9242b15cb3dSCy Schubert 			   : TYPE_PEER;
9252b15cb3dSCy Schubert 		printvars(dsize, datap, (int)rstatus, type, 0, fp);
926ea906c41SOllivier Robert 	}
927ea906c41SOllivier Robert 	return;
928ea906c41SOllivier Robert }
929ea906c41SOllivier Robert 
930ea906c41SOllivier Robert 
931ea906c41SOllivier Robert /*
932ea906c41SOllivier Robert  * clocklist - send a clock variables request with the variables on the list
933ea906c41SOllivier Robert  */
934ea906c41SOllivier Robert static void
935ea906c41SOllivier Robert clocklist(
936ea906c41SOllivier Robert 	struct parse *pcmd,
937ea906c41SOllivier Robert 	FILE *fp
938ea906c41SOllivier Robert 	)
939ea906c41SOllivier Robert {
9402b15cb3dSCy Schubert 	associd_t associd;
941ea906c41SOllivier Robert 
942ea906c41SOllivier Robert 	/* HMS: uval? */
943ea906c41SOllivier Robert 	if (pcmd->nargs == 0) {
944ea906c41SOllivier Robert 		associd = 0;
945ea906c41SOllivier Robert 	} else {
946ea906c41SOllivier Robert 		if (pcmd->argval[0].uval == 0)
947ea906c41SOllivier Robert 			associd = 0;
948ea906c41SOllivier Robert 		else if ((associd = checkassocid(pcmd->argval[0].uval)) == 0)
949ea906c41SOllivier Robert 			return;
950ea906c41SOllivier Robert 	}
951ea906c41SOllivier Robert 
9522b15cb3dSCy Schubert 	dolist(g_varlist, associd, CTL_OP_READCLOCK, TYPE_CLOCK, fp);
953ea906c41SOllivier Robert }
954ea906c41SOllivier Robert 
955ea906c41SOllivier Robert 
956ea906c41SOllivier Robert /*
957ea906c41SOllivier Robert  * clockvar - send a clock variables request with the specified variables
958ea906c41SOllivier Robert  */
959ea906c41SOllivier Robert static void
960ea906c41SOllivier Robert clockvar(
961ea906c41SOllivier Robert 	struct parse *pcmd,
962ea906c41SOllivier Robert 	FILE *fp
963ea906c41SOllivier Robert 	)
964ea906c41SOllivier Robert {
9652b15cb3dSCy Schubert 	associd_t associd;
966ea906c41SOllivier Robert 	struct varlist tmplist[MAXLIST];
967ea906c41SOllivier Robert 
968ea906c41SOllivier Robert 	/* HMS: uval? */
969ea906c41SOllivier Robert 	if (pcmd->nargs == 0 || pcmd->argval[0].uval == 0)
970ea906c41SOllivier Robert 		associd = 0;
971ea906c41SOllivier Robert 	else if ((associd = checkassocid(pcmd->argval[0].uval)) == 0)
972ea906c41SOllivier Robert 		return;
973ea906c41SOllivier Robert 
9742b15cb3dSCy Schubert 	ZERO(tmplist);
975ea906c41SOllivier Robert 	if (pcmd->nargs >= 2)
976ea906c41SOllivier Robert 		doaddvlist(tmplist, pcmd->argval[1].string);
977ea906c41SOllivier Robert 
9782b15cb3dSCy Schubert 	dolist(tmplist, associd, CTL_OP_READCLOCK, TYPE_CLOCK, fp);
979ea906c41SOllivier Robert 
980ea906c41SOllivier Robert 	doclearvlist(tmplist);
981ea906c41SOllivier Robert }
982ea906c41SOllivier Robert 
983ea906c41SOllivier Robert 
984ea906c41SOllivier Robert /*
985ea906c41SOllivier Robert  * findassidrange - verify a range of association ID's
986ea906c41SOllivier Robert  */
987ea906c41SOllivier Robert static int
988ea906c41SOllivier Robert findassidrange(
989ea906c41SOllivier Robert 	u_int32	assid1,
990ea906c41SOllivier Robert 	u_int32	assid2,
991ea906c41SOllivier Robert 	int *	from,
9922b15cb3dSCy Schubert 	int *	to,
9932b15cb3dSCy Schubert 	FILE *	fp
994ea906c41SOllivier Robert 	)
995ea906c41SOllivier Robert {
9962b15cb3dSCy Schubert 	associd_t	assids[2];
9972b15cb3dSCy Schubert 	int		ind[COUNTOF(assids)];
9982b15cb3dSCy Schubert 	u_int		i;
9992b15cb3dSCy Schubert 	size_t		a;
1000ea906c41SOllivier Robert 
10012b15cb3dSCy Schubert 
10022b15cb3dSCy Schubert 	if (0 == numassoc)
10032b15cb3dSCy Schubert 		dogetassoc(fp);
10042b15cb3dSCy Schubert 
10052b15cb3dSCy Schubert 	assids[0] = checkassocid(assid1);
10062b15cb3dSCy Schubert 	if (0 == assids[0])
10072b15cb3dSCy Schubert 		return 0;
10082b15cb3dSCy Schubert 	assids[1] = checkassocid(assid2);
10092b15cb3dSCy Schubert 	if (0 == assids[1])
10102b15cb3dSCy Schubert 		return 0;
10112b15cb3dSCy Schubert 
10122b15cb3dSCy Schubert 	for (a = 0; a < COUNTOF(assids); a++) {
10132b15cb3dSCy Schubert 		ind[a] = -1;
10142b15cb3dSCy Schubert 		for (i = 0; i < numassoc; i++)
10152b15cb3dSCy Schubert 			if (assoc_cache[i].assid == assids[a])
10162b15cb3dSCy Schubert 				ind[a] = i;
10172b15cb3dSCy Schubert 	}
10182b15cb3dSCy Schubert 	for (a = 0; a < COUNTOF(assids); a++)
10192b15cb3dSCy Schubert 		if (-1 == ind[a]) {
10202d4e511cSCy Schubert 			xprintf(stderr,
10212b15cb3dSCy Schubert 				"***Association ID %u not found in list\n",
10222b15cb3dSCy Schubert 				assids[a]);
1023ea906c41SOllivier Robert 			return 0;
1024ea906c41SOllivier Robert 		}
1025ea906c41SOllivier Robert 
10262b15cb3dSCy Schubert 	if (ind[0] < ind[1]) {
10272b15cb3dSCy Schubert 		*from = ind[0];
10282b15cb3dSCy Schubert 		*to = ind[1];
1029ea906c41SOllivier Robert 	} else {
10302b15cb3dSCy Schubert 		*to = ind[0];
10312b15cb3dSCy Schubert 		*from = ind[1];
1032ea906c41SOllivier Robert 	}
1033ea906c41SOllivier Robert 	return 1;
1034ea906c41SOllivier Robert }
1035ea906c41SOllivier Robert 
1036ea906c41SOllivier Robert 
1037ea906c41SOllivier Robert 
1038ea906c41SOllivier Robert /*
1039ea906c41SOllivier Robert  * mreadlist - send a read variables request for multiple associations
1040ea906c41SOllivier Robert  */
1041ea906c41SOllivier Robert static void
1042ea906c41SOllivier Robert mreadlist(
1043ea906c41SOllivier Robert 	struct parse *pcmd,
1044ea906c41SOllivier Robert 	FILE *fp
1045ea906c41SOllivier Robert 	)
1046ea906c41SOllivier Robert {
1047ea906c41SOllivier Robert 	int i;
1048ea906c41SOllivier Robert 	int from;
1049ea906c41SOllivier Robert 	int to;
1050ea906c41SOllivier Robert 
1051ea906c41SOllivier Robert 	if (!findassidrange(pcmd->argval[0].uval, pcmd->argval[1].uval,
10522b15cb3dSCy Schubert 			    &from, &to, fp))
1053ea906c41SOllivier Robert 		return;
1054ea906c41SOllivier Robert 
1055ea906c41SOllivier Robert 	for (i = from; i <= to; i++) {
1056ea906c41SOllivier Robert 		if (i != from)
10572d4e511cSCy Schubert 			xprintf(fp, "\n");
10582b15cb3dSCy Schubert 		if (!dolist(g_varlist, assoc_cache[i].assid,
1059ea906c41SOllivier Robert 			    CTL_OP_READVAR, TYPE_PEER, fp))
1060ea906c41SOllivier Robert 			return;
1061ea906c41SOllivier Robert 	}
1062ea906c41SOllivier Robert 	return;
1063ea906c41SOllivier Robert }
1064ea906c41SOllivier Robert 
1065ea906c41SOllivier Robert 
1066ea906c41SOllivier Robert /*
1067ea906c41SOllivier Robert  * mreadvar - send a read variables request for multiple associations
1068ea906c41SOllivier Robert  */
1069ea906c41SOllivier Robert static void
1070ea906c41SOllivier Robert mreadvar(
1071ea906c41SOllivier Robert 	struct parse *pcmd,
1072ea906c41SOllivier Robert 	FILE *fp
1073ea906c41SOllivier Robert 	)
1074ea906c41SOllivier Robert {
1075ea906c41SOllivier Robert 	int i;
1076ea906c41SOllivier Robert 	int from;
1077ea906c41SOllivier Robert 	int to;
1078ea906c41SOllivier Robert 	struct varlist tmplist[MAXLIST];
10792b15cb3dSCy Schubert 	struct varlist *pvars;
1080ea906c41SOllivier Robert 
1081ea906c41SOllivier Robert 	if (!findassidrange(pcmd->argval[0].uval, pcmd->argval[1].uval,
10822b15cb3dSCy Schubert 				&from, &to, fp))
1083ea906c41SOllivier Robert 		return;
1084ea906c41SOllivier Robert 
10852b15cb3dSCy Schubert 	ZERO(tmplist);
10862b15cb3dSCy Schubert 	if (pcmd->nargs >= 3) {
1087ea906c41SOllivier Robert 		doaddvlist(tmplist, pcmd->argval[2].string);
10882b15cb3dSCy Schubert 		pvars = tmplist;
10892b15cb3dSCy Schubert 	} else {
10902b15cb3dSCy Schubert 		pvars = g_varlist;
10912b15cb3dSCy Schubert 	}
1092ea906c41SOllivier Robert 
1093ea906c41SOllivier Robert 	for (i = from; i <= to; i++) {
10942b15cb3dSCy Schubert 		if (!dolist(pvars, assoc_cache[i].assid, CTL_OP_READVAR,
10952b15cb3dSCy Schubert 			    TYPE_PEER, fp))
1096ea906c41SOllivier Robert 			break;
1097ea906c41SOllivier Robert 	}
10982b15cb3dSCy Schubert 
10992b15cb3dSCy Schubert 	if (pvars == tmplist)
1100ea906c41SOllivier Robert 		doclearvlist(tmplist);
11012b15cb3dSCy Schubert 
1102ea906c41SOllivier Robert 	return;
1103ea906c41SOllivier Robert }
1104ea906c41SOllivier Robert 
1105ea906c41SOllivier Robert 
1106ea906c41SOllivier Robert /*
1107ea906c41SOllivier Robert  * dogetassoc - query the host for its list of associations
1108ea906c41SOllivier Robert  */
11092b15cb3dSCy Schubert int
1110ea906c41SOllivier Robert dogetassoc(
1111ea906c41SOllivier Robert 	FILE *fp
1112ea906c41SOllivier Robert 	)
1113ea906c41SOllivier Robert {
11142b15cb3dSCy Schubert 	const char *datap;
11152b15cb3dSCy Schubert 	const u_short *pus;
1116ea906c41SOllivier Robert 	int res;
11173311ff84SXin LI 	size_t dsize;
1118ea906c41SOllivier Robert 	u_short rstatus;
1119ea906c41SOllivier Robert 
1120ea906c41SOllivier Robert 	res = doquery(CTL_OP_READSTAT, 0, 0, 0, (char *)0, &rstatus,
1121ea906c41SOllivier Robert 			  &dsize, &datap);
1122ea906c41SOllivier Robert 
1123ea906c41SOllivier Robert 	if (res != 0)
1124ea906c41SOllivier Robert 		return 0;
1125ea906c41SOllivier Robert 
1126ea906c41SOllivier Robert 	if (dsize == 0) {
1127ea906c41SOllivier Robert 		if (numhosts > 1)
11282d4e511cSCy Schubert 			xprintf(fp, "server=%s ", currenthost);
11292d4e511cSCy Schubert 		xprintf(fp, "No association ID's returned\n");
1130ea906c41SOllivier Robert 		return 0;
1131ea906c41SOllivier Robert 	}
1132ea906c41SOllivier Robert 
1133ea906c41SOllivier Robert 	if (dsize & 0x3) {
1134ea906c41SOllivier Robert 		if (numhosts > 1)
11352d4e511cSCy Schubert 			xprintf(stderr, "server=%s ", currenthost);
11362d4e511cSCy Schubert 		xprintf(stderr,
11373311ff84SXin LI 			"***Server returned %zu octets, should be multiple of 4\n",
1138ea906c41SOllivier Robert 			dsize);
1139ea906c41SOllivier Robert 		return 0;
1140ea906c41SOllivier Robert 	}
1141ea906c41SOllivier Robert 
1142ea906c41SOllivier Robert 	numassoc = 0;
11432b15cb3dSCy Schubert 
1144ea906c41SOllivier Robert 	while (dsize > 0) {
11452b15cb3dSCy Schubert 		if (numassoc >= assoc_cache_slots) {
11462b15cb3dSCy Schubert 			grow_assoc_cache();
11472b15cb3dSCy Schubert 		}
11482b15cb3dSCy Schubert 		pus = (const void *)datap;
11492b15cb3dSCy Schubert 		assoc_cache[numassoc].assid = ntohs(*pus);
11502b15cb3dSCy Schubert 		datap += sizeof(*pus);
11512b15cb3dSCy Schubert 		pus = (const void *)datap;
11522b15cb3dSCy Schubert 		assoc_cache[numassoc].status = ntohs(*pus);
11532b15cb3dSCy Schubert 		datap += sizeof(*pus);
11542b15cb3dSCy Schubert 		dsize -= 2 * sizeof(*pus);
11552b15cb3dSCy Schubert 		if (debug) {
11562d4e511cSCy Schubert 			xprintf(stderr, "[%u] ",
11572b15cb3dSCy Schubert 				assoc_cache[numassoc].assid);
11582b15cb3dSCy Schubert 		}
11592b15cb3dSCy Schubert 		numassoc++;
11602b15cb3dSCy Schubert 	}
11612b15cb3dSCy Schubert 	if (debug) {
11622d4e511cSCy Schubert 		xprintf(stderr, "\n%d associations total\n", numassoc);
1163ea906c41SOllivier Robert 	}
1164ea906c41SOllivier Robert 	sortassoc();
1165ea906c41SOllivier Robert 	return 1;
1166ea906c41SOllivier Robert }
1167ea906c41SOllivier Robert 
1168ea906c41SOllivier Robert 
1169ea906c41SOllivier Robert /*
1170ea906c41SOllivier Robert  * printassoc - print the current list of associations
1171ea906c41SOllivier Robert  */
1172ea906c41SOllivier Robert static void
1173ea906c41SOllivier Robert printassoc(
1174ea906c41SOllivier Robert 	int showall,
1175ea906c41SOllivier Robert 	FILE *fp
1176ea906c41SOllivier Robert 	)
1177ea906c41SOllivier Robert {
1178ea906c41SOllivier Robert 	register char *bp;
11792b15cb3dSCy Schubert 	u_int i;
1180ea906c41SOllivier Robert 	u_char statval;
1181ea906c41SOllivier Robert 	int event;
1182ea906c41SOllivier Robert 	u_long event_count;
1183ea906c41SOllivier Robert 	const char *conf;
1184ea906c41SOllivier Robert 	const char *reach;
1185ea906c41SOllivier Robert 	const char *auth;
1186ea906c41SOllivier Robert 	const char *condition = "";
1187ea906c41SOllivier Robert 	const char *last_event;
1188ea906c41SOllivier Robert 	char buf[128];
1189a466cc55SCy Schubert 	char numev[32];
1190ea906c41SOllivier Robert 
1191ea906c41SOllivier Robert 	if (numassoc == 0) {
11922d4e511cSCy Schubert 		(void) xprintf(fp, "No association ID's in list\n");
1193ea906c41SOllivier Robert 		return;
1194ea906c41SOllivier Robert 	}
1195ea906c41SOllivier Robert 
1196ea906c41SOllivier Robert 	/*
1197ea906c41SOllivier Robert 	 * Output a header
1198ea906c41SOllivier Robert 	 */
11992d4e511cSCy Schubert 	(void) xprintf(fp,
12004e1ef62aSXin LI 			   "ind assid status  conf reach auth condition  last_event cnt\n");
12012d4e511cSCy Schubert 	(void) xprintf(fp,
1202ea906c41SOllivier Robert 			   "===========================================================\n");
1203ea906c41SOllivier Robert 	for (i = 0; i < numassoc; i++) {
1204ea906c41SOllivier Robert 		statval = (u_char) CTL_PEER_STATVAL(assoc_cache[i].status);
1205ea906c41SOllivier Robert 		if (!showall && !(statval & (CTL_PST_CONFIG|CTL_PST_REACH)))
1206ea906c41SOllivier Robert 			continue;
1207ea906c41SOllivier Robert 		event = CTL_PEER_EVENT(assoc_cache[i].status);
1208ea906c41SOllivier Robert 		event_count = CTL_PEER_NEVNT(assoc_cache[i].status);
1209ea906c41SOllivier Robert 		if (statval & CTL_PST_CONFIG)
1210ea906c41SOllivier Robert 			conf = "yes";
1211ea906c41SOllivier Robert 		else
1212ea906c41SOllivier Robert 			conf = "no";
12132b15cb3dSCy Schubert 		if (statval & CTL_PST_BCAST) {
12142b15cb3dSCy Schubert 			reach = "none";
12152b15cb3dSCy Schubert 			if (statval & CTL_PST_AUTHENABLE)
12162b15cb3dSCy Schubert 				auth = "yes";
12172b15cb3dSCy Schubert 			else
12182b15cb3dSCy Schubert 				auth = "none";
12192b15cb3dSCy Schubert 		} else {
12202b15cb3dSCy Schubert 			if (statval & CTL_PST_REACH)
1221ea906c41SOllivier Robert 				reach = "yes";
12222b15cb3dSCy Schubert 			else
12232b15cb3dSCy Schubert 				reach = "no";
1224ea906c41SOllivier Robert 			if (statval & CTL_PST_AUTHENABLE) {
1225ea906c41SOllivier Robert 				if (statval & CTL_PST_AUTHENTIC)
1226ea906c41SOllivier Robert 					auth = "ok ";
1227ea906c41SOllivier Robert 				else
1228ea906c41SOllivier Robert 					auth = "bad";
12292b15cb3dSCy Schubert 			} else {
1230ea906c41SOllivier Robert 				auth = "none";
12312b15cb3dSCy Schubert 			}
12322b15cb3dSCy Schubert 		}
12332b15cb3dSCy Schubert 		if (pktversion > NTP_OLDVERSION) {
1234ea906c41SOllivier Robert 			switch (statval & 0x7) {
12352b15cb3dSCy Schubert 
1236ea906c41SOllivier Robert 			case CTL_PST_SEL_REJECT:
1237ea906c41SOllivier Robert 				condition = "reject";
1238ea906c41SOllivier Robert 				break;
12392b15cb3dSCy Schubert 
1240ea906c41SOllivier Robert 			case CTL_PST_SEL_SANE:
1241ea906c41SOllivier Robert 				condition = "falsetick";
1242ea906c41SOllivier Robert 				break;
12432b15cb3dSCy Schubert 
1244ea906c41SOllivier Robert 			case CTL_PST_SEL_CORRECT:
1245ea906c41SOllivier Robert 				condition = "excess";
1246ea906c41SOllivier Robert 				break;
12472b15cb3dSCy Schubert 
1248ea906c41SOllivier Robert 			case CTL_PST_SEL_SELCAND:
12499034852cSGleb Smirnoff 				condition = "outlier";
1250ea906c41SOllivier Robert 				break;
12512b15cb3dSCy Schubert 
1252ea906c41SOllivier Robert 			case CTL_PST_SEL_SYNCCAND:
12532b15cb3dSCy Schubert 				condition = "candidate";
1254ea906c41SOllivier Robert 				break;
12552b15cb3dSCy Schubert 
12562b15cb3dSCy Schubert 			case CTL_PST_SEL_EXCESS:
12572b15cb3dSCy Schubert 				condition = "backup";
1258ea906c41SOllivier Robert 				break;
12592b15cb3dSCy Schubert 
1260ea906c41SOllivier Robert 			case CTL_PST_SEL_SYSPEER:
1261ea906c41SOllivier Robert 				condition = "sys.peer";
1262ea906c41SOllivier Robert 				break;
12632b15cb3dSCy Schubert 
1264ea906c41SOllivier Robert 			case CTL_PST_SEL_PPS:
1265ea906c41SOllivier Robert 				condition = "pps.peer";
1266ea906c41SOllivier Robert 				break;
1267ea906c41SOllivier Robert 			}
12682b15cb3dSCy Schubert 		} else {
1269ea906c41SOllivier Robert 			switch (statval & 0x3) {
12702b15cb3dSCy Schubert 
1271ea906c41SOllivier Robert 			case OLD_CTL_PST_SEL_REJECT:
1272ea906c41SOllivier Robert 				if (!(statval & OLD_CTL_PST_SANE))
1273ea906c41SOllivier Robert 					condition = "insane";
1274ea906c41SOllivier Robert 				else if (!(statval & OLD_CTL_PST_DISP))
1275ea906c41SOllivier Robert 					condition = "hi_disp";
1276ea906c41SOllivier Robert 				else
1277ea906c41SOllivier Robert 					condition = "";
1278ea906c41SOllivier Robert 				break;
12792b15cb3dSCy Schubert 
1280ea906c41SOllivier Robert 			case OLD_CTL_PST_SEL_SELCAND:
1281ea906c41SOllivier Robert 				condition = "sel_cand";
1282ea906c41SOllivier Robert 				break;
12832b15cb3dSCy Schubert 
1284ea906c41SOllivier Robert 			case OLD_CTL_PST_SEL_SYNCCAND:
1285ea906c41SOllivier Robert 				condition = "sync_cand";
1286ea906c41SOllivier Robert 				break;
12872b15cb3dSCy Schubert 
1288ea906c41SOllivier Robert 			case OLD_CTL_PST_SEL_SYSPEER:
1289ea906c41SOllivier Robert 				condition = "sys_peer";
1290ea906c41SOllivier Robert 				break;
1291ea906c41SOllivier Robert 			}
1292ea906c41SOllivier Robert 		}
1293ea906c41SOllivier Robert 		switch (PEER_EVENT|event) {
12942b15cb3dSCy Schubert 
12952b15cb3dSCy Schubert 		case PEVNT_MOBIL:
12962b15cb3dSCy Schubert 			last_event = "mobilize";
1297ea906c41SOllivier Robert 			break;
12982b15cb3dSCy Schubert 
12992b15cb3dSCy Schubert 		case PEVNT_DEMOBIL:
13002b15cb3dSCy Schubert 			last_event = "demobilize";
1301ea906c41SOllivier Robert 			break;
13022b15cb3dSCy Schubert 
13032b15cb3dSCy Schubert 		case PEVNT_REACH:
1304ea906c41SOllivier Robert 			last_event = "reachable";
1305ea906c41SOllivier Robert 			break;
13062b15cb3dSCy Schubert 
13072b15cb3dSCy Schubert 		case PEVNT_UNREACH:
13082b15cb3dSCy Schubert 			last_event = "unreachable";
1309ea906c41SOllivier Robert 			break;
13102b15cb3dSCy Schubert 
13112b15cb3dSCy Schubert 		case PEVNT_RESTART:
13122b15cb3dSCy Schubert 			last_event = "restart";
1313ea906c41SOllivier Robert 			break;
13142b15cb3dSCy Schubert 
13152b15cb3dSCy Schubert 		case PEVNT_REPLY:
13162b15cb3dSCy Schubert 			last_event = "no_reply";
13172b15cb3dSCy Schubert 			break;
13182b15cb3dSCy Schubert 
13192b15cb3dSCy Schubert 		case PEVNT_RATE:
13202b15cb3dSCy Schubert 			last_event = "rate_exceeded";
13212b15cb3dSCy Schubert 			break;
13222b15cb3dSCy Schubert 
13232b15cb3dSCy Schubert 		case PEVNT_DENY:
13242b15cb3dSCy Schubert 			last_event = "access_denied";
13252b15cb3dSCy Schubert 			break;
13262b15cb3dSCy Schubert 
13272b15cb3dSCy Schubert 		case PEVNT_ARMED:
13282b15cb3dSCy Schubert 			last_event = "leap_armed";
13292b15cb3dSCy Schubert 			break;
13302b15cb3dSCy Schubert 
13312b15cb3dSCy Schubert 		case PEVNT_NEWPEER:
13322b15cb3dSCy Schubert 			last_event = "sys_peer";
13332b15cb3dSCy Schubert 			break;
13342b15cb3dSCy Schubert 
13352b15cb3dSCy Schubert 		case PEVNT_CLOCK:
13362b15cb3dSCy Schubert 			last_event = "clock_alarm";
13372b15cb3dSCy Schubert 			break;
13382b15cb3dSCy Schubert 
1339a466cc55SCy Schubert 		case PEVNT_AUTH:
1340a466cc55SCy Schubert 			last_event = "bad_auth";
1341a466cc55SCy Schubert 			break;
1342a466cc55SCy Schubert 
1343a466cc55SCy Schubert 		case PEVNT_POPCORN:
1344a466cc55SCy Schubert 			last_event = "popcorn";
1345a466cc55SCy Schubert 			break;
1346a466cc55SCy Schubert 
1347a466cc55SCy Schubert 		case PEVNT_XLEAVE:
1348a466cc55SCy Schubert 			last_event = "interleave";
1349a466cc55SCy Schubert 			break;
1350a466cc55SCy Schubert 
1351a466cc55SCy Schubert 		case PEVNT_XERR:
1352a466cc55SCy Schubert 			last_event = "xleave_err";
1353a466cc55SCy Schubert 			break;
1354a466cc55SCy Schubert 
1355ea906c41SOllivier Robert 		default:
1356a466cc55SCy Schubert 			snprintf(numev, sizeof(numev), "<?%x?>", event);
1357a466cc55SCy Schubert 			last_event = numev;
1358ea906c41SOllivier Robert 			break;
1359ea906c41SOllivier Robert 		}
13602b15cb3dSCy Schubert 		snprintf(buf, sizeof(buf),
13612b15cb3dSCy Schubert 			 "%3d %5u  %04x   %3.3s  %4s  %4.4s %9.9s %11s %2lu",
13622b15cb3dSCy Schubert 			 i + 1, assoc_cache[i].assid,
13632b15cb3dSCy Schubert 			 assoc_cache[i].status, conf, reach, auth,
13642b15cb3dSCy Schubert 			 condition, last_event, event_count);
13652b15cb3dSCy Schubert 		bp = buf + strlen(buf);
13662b15cb3dSCy Schubert 		while (bp > buf && ' ' == bp[-1])
13672b15cb3dSCy Schubert 			--bp;
13682b15cb3dSCy Schubert 		bp[0] = '\0';
13692d4e511cSCy Schubert 		xprintf(fp, "%s\n", buf);
1370ea906c41SOllivier Robert 	}
1371ea906c41SOllivier Robert }
1372ea906c41SOllivier Robert 
1373ea906c41SOllivier Robert 
1374ea906c41SOllivier Robert /*
1375ea906c41SOllivier Robert  * associations - get, record and print a list of associations
1376ea906c41SOllivier Robert  */
1377ea906c41SOllivier Robert /*ARGSUSED*/
1378ea906c41SOllivier Robert static void
1379ea906c41SOllivier Robert associations(
1380ea906c41SOllivier Robert 	struct parse *pcmd,
1381ea906c41SOllivier Robert 	FILE *fp
1382ea906c41SOllivier Robert 	)
1383ea906c41SOllivier Robert {
1384ea906c41SOllivier Robert 	if (dogetassoc(fp))
1385ea906c41SOllivier Robert 		printassoc(0, fp);
1386ea906c41SOllivier Robert }
1387ea906c41SOllivier Robert 
1388ea906c41SOllivier Robert 
1389ea906c41SOllivier Robert /*
1390ea906c41SOllivier Robert  * lassociations - get, record and print a long list of associations
1391ea906c41SOllivier Robert  */
1392ea906c41SOllivier Robert /*ARGSUSED*/
1393ea906c41SOllivier Robert static void
1394ea906c41SOllivier Robert lassociations(
1395ea906c41SOllivier Robert 	struct parse *pcmd,
1396ea906c41SOllivier Robert 	FILE *fp
1397ea906c41SOllivier Robert 	)
1398ea906c41SOllivier Robert {
1399ea906c41SOllivier Robert 	if (dogetassoc(fp))
1400ea906c41SOllivier Robert 		printassoc(1, fp);
1401ea906c41SOllivier Robert }
1402ea906c41SOllivier Robert 
1403ea906c41SOllivier Robert 
1404ea906c41SOllivier Robert /*
1405ea906c41SOllivier Robert  * passociations - print the association list
1406ea906c41SOllivier Robert  */
1407ea906c41SOllivier Robert /*ARGSUSED*/
1408ea906c41SOllivier Robert static void
1409ea906c41SOllivier Robert passociations(
1410ea906c41SOllivier Robert 	struct parse *pcmd,
1411ea906c41SOllivier Robert 	FILE *fp
1412ea906c41SOllivier Robert 	)
1413ea906c41SOllivier Robert {
1414ea906c41SOllivier Robert 	printassoc(0, fp);
1415ea906c41SOllivier Robert }
1416ea906c41SOllivier Robert 
1417ea906c41SOllivier Robert 
1418ea906c41SOllivier Robert /*
1419ea906c41SOllivier Robert  * lpassociations - print the long association list
1420ea906c41SOllivier Robert  */
1421ea906c41SOllivier Robert /*ARGSUSED*/
1422ea906c41SOllivier Robert static void
1423ea906c41SOllivier Robert lpassociations(
1424ea906c41SOllivier Robert 	struct parse *pcmd,
1425ea906c41SOllivier Robert 	FILE *fp
1426ea906c41SOllivier Robert 	)
1427ea906c41SOllivier Robert {
1428ea906c41SOllivier Robert 	printassoc(1, fp);
1429ea906c41SOllivier Robert }
1430ea906c41SOllivier Robert 
1431ea906c41SOllivier Robert 
14322b15cb3dSCy Schubert /*
14332b15cb3dSCy Schubert  *  saveconfig - dump ntp server configuration to server file
14342b15cb3dSCy Schubert  */
14352b15cb3dSCy Schubert static void
14362b15cb3dSCy Schubert saveconfig(
14372b15cb3dSCy Schubert 	struct parse *pcmd,
14382b15cb3dSCy Schubert 	FILE *fp
14392b15cb3dSCy Schubert 	)
14402b15cb3dSCy Schubert {
14412b15cb3dSCy Schubert 	const char *datap;
14422b15cb3dSCy Schubert 	int res;
14433311ff84SXin LI 	size_t dsize;
14442b15cb3dSCy Schubert 	u_short rstatus;
14452b15cb3dSCy Schubert 
14462b15cb3dSCy Schubert 	if (0 == pcmd->nargs)
14472b15cb3dSCy Schubert 		return;
14482b15cb3dSCy Schubert 
14492b15cb3dSCy Schubert 	res = doquery(CTL_OP_SAVECONFIG, 0, 1,
14502b15cb3dSCy Schubert 		      strlen(pcmd->argval[0].string),
14512b15cb3dSCy Schubert 		      pcmd->argval[0].string, &rstatus, &dsize,
14522b15cb3dSCy Schubert 		      &datap);
14532b15cb3dSCy Schubert 
14542b15cb3dSCy Schubert 	if (res != 0)
14552b15cb3dSCy Schubert 		return;
14562b15cb3dSCy Schubert 
14572b15cb3dSCy Schubert 	if (0 == dsize)
14582d4e511cSCy Schubert 		xprintf(fp, "(no response message, curiously)");
14592b15cb3dSCy Schubert 	else
14602d4e511cSCy Schubert 		xprintf(fp, "%.*s", (int)dsize, datap); /* cast is wobbly */
14612b15cb3dSCy Schubert }
14622b15cb3dSCy Schubert 
14632b15cb3dSCy Schubert 
1464ea906c41SOllivier Robert #ifdef	UNUSED
1465ea906c41SOllivier Robert /*
1466ea906c41SOllivier Robert  * radiostatus - print the radio status returned by the server
1467ea906c41SOllivier Robert  */
1468ea906c41SOllivier Robert /*ARGSUSED*/
1469ea906c41SOllivier Robert static void
1470ea906c41SOllivier Robert radiostatus(
1471ea906c41SOllivier Robert 	struct parse *pcmd,
1472ea906c41SOllivier Robert 	FILE *fp
1473ea906c41SOllivier Robert 	)
1474ea906c41SOllivier Robert {
1475ea906c41SOllivier Robert 	char *datap;
1476ea906c41SOllivier Robert 	int res;
1477ea906c41SOllivier Robert 	int dsize;
1478ea906c41SOllivier Robert 	u_short rstatus;
1479ea906c41SOllivier Robert 
1480ea906c41SOllivier Robert 	res = doquery(CTL_OP_READCLOCK, 0, 0, 0, (char *)0, &rstatus,
1481ea906c41SOllivier Robert 			  &dsize, &datap);
1482ea906c41SOllivier Robert 
1483ea906c41SOllivier Robert 	if (res != 0)
1484ea906c41SOllivier Robert 		return;
1485ea906c41SOllivier Robert 
1486ea906c41SOllivier Robert 	if (numhosts > 1)
14872d4e511cSCy Schubert 		(void) xprintf(fp, "server=%s ", currenthost);
1488ea906c41SOllivier Robert 	if (dsize == 0) {
14892d4e511cSCy Schubert 		(void) xprintf(fp, "No radio status string returned\n");
1490ea906c41SOllivier Robert 		return;
1491ea906c41SOllivier Robert 	}
1492ea906c41SOllivier Robert 
1493ea906c41SOllivier Robert 	asciize(dsize, datap, fp);
1494ea906c41SOllivier Robert }
1495ea906c41SOllivier Robert #endif	/* UNUSED */
1496ea906c41SOllivier Robert 
1497ea906c41SOllivier Robert /*
1498*f5f40dd6SCy Schubert  * when - return how long its been since his last packet arrived
1499ea906c41SOllivier Robert  */
1500ea906c41SOllivier Robert static long
1501ea906c41SOllivier Robert when(
1502ea906c41SOllivier Robert 	l_fp *ts,
1503ea906c41SOllivier Robert 	l_fp *rec,
1504ea906c41SOllivier Robert 	l_fp *reftime
1505ea906c41SOllivier Robert 	)
1506ea906c41SOllivier Robert {
1507ea906c41SOllivier Robert 	l_fp *lasttime;
1508ea906c41SOllivier Robert 
1509ea906c41SOllivier Robert 	if (rec->l_ui != 0)
1510ea906c41SOllivier Robert 		lasttime = rec;
1511ea906c41SOllivier Robert 	else if (reftime->l_ui != 0)
1512ea906c41SOllivier Robert 		lasttime = reftime;
1513ea906c41SOllivier Robert 	else
1514ea906c41SOllivier Robert 		return 0;
1515ea906c41SOllivier Robert 
151609100258SXin LI 	if (ts->l_ui < lasttime->l_ui)
151709100258SXin LI 		return -1;
1518ea906c41SOllivier Robert 	return (ts->l_ui - lasttime->l_ui);
1519ea906c41SOllivier Robert }
1520ea906c41SOllivier Robert 
1521ea906c41SOllivier Robert 
1522ea906c41SOllivier Robert /*
1523ea906c41SOllivier Robert  * Pretty-print an interval into the given buffer, in a human-friendly format.
1524ea906c41SOllivier Robert  */
1525ea906c41SOllivier Robert static char *
1526ea906c41SOllivier Robert prettyinterval(
1527ea906c41SOllivier Robert 	char *buf,
15282b15cb3dSCy Schubert 	size_t cb,
1529ea906c41SOllivier Robert 	long diff
1530ea906c41SOllivier Robert 	)
1531ea906c41SOllivier Robert {
1532ea906c41SOllivier Robert 	if (diff <= 0) {
1533ea906c41SOllivier Robert 		buf[0] = '-';
1534ea906c41SOllivier Robert 		buf[1] = 0;
1535ea906c41SOllivier Robert 		return buf;
1536ea906c41SOllivier Robert 	}
1537ea906c41SOllivier Robert 
1538ea906c41SOllivier Robert 	if (diff <= 2048) {
15394e1ef62aSXin LI 		snprintf(buf, cb, "%u", (unsigned int)diff);
1540ea906c41SOllivier Robert 		return buf;
1541ea906c41SOllivier Robert 	}
1542ea906c41SOllivier Robert 
1543ea906c41SOllivier Robert 	diff = (diff + 29) / 60;
1544ea906c41SOllivier Robert 	if (diff <= 300) {
15454e1ef62aSXin LI 		snprintf(buf, cb, "%um", (unsigned int)diff);
1546ea906c41SOllivier Robert 		return buf;
1547ea906c41SOllivier Robert 	}
1548ea906c41SOllivier Robert 
1549ea906c41SOllivier Robert 	diff = (diff + 29) / 60;
1550ea906c41SOllivier Robert 	if (diff <= 96) {
15514e1ef62aSXin LI 		snprintf(buf, cb, "%uh", (unsigned int)diff);
1552ea906c41SOllivier Robert 		return buf;
1553ea906c41SOllivier Robert 	}
1554ea906c41SOllivier Robert 
1555ea906c41SOllivier Robert 	diff = (diff + 11) / 24;
155609100258SXin LI 	if (diff <= 999) {
15574e1ef62aSXin LI 		snprintf(buf, cb, "%ud", (unsigned int)diff);
1558ea906c41SOllivier Robert 		return buf;
1559ea906c41SOllivier Robert 	}
1560ea906c41SOllivier Robert 
156109100258SXin LI 	/* years are only approximated... */
156209100258SXin LI 	diff = (long)floor(diff / 365.25 + 0.5);
15634e1ef62aSXin LI 	if (diff <= 999) {
15644e1ef62aSXin LI 		snprintf(buf, cb, "%uy", (unsigned int)diff);
15654e1ef62aSXin LI 		return buf;
15664e1ef62aSXin LI 	}
15674e1ef62aSXin LI 	/* Ok, this amounts to infinity... */
15684e1ef62aSXin LI 	strlcpy(buf, "INF", cb);
156909100258SXin LI 	return buf;
157009100258SXin LI }
157109100258SXin LI 
1572ea906c41SOllivier Robert static char
1573ea906c41SOllivier Robert decodeaddrtype(
15742b15cb3dSCy Schubert 	sockaddr_u *sock
1575ea906c41SOllivier Robert 	)
1576ea906c41SOllivier Robert {
1577ea906c41SOllivier Robert 	char ch = '-';
1578ea906c41SOllivier Robert 	u_int32 dummy;
1579ea906c41SOllivier Robert 
15802b15cb3dSCy Schubert 	switch(AF(sock)) {
1581ea906c41SOllivier Robert 	case AF_INET:
15822b15cb3dSCy Schubert 		dummy = SRCADR(sock);
1583ea906c41SOllivier Robert 		ch = (char)(((dummy&0xf0000000)==0xe0000000) ? 'm' :
1584ea906c41SOllivier Robert 			((dummy&0x000000ff)==0x000000ff) ? 'b' :
1585ea906c41SOllivier Robert 			((dummy&0xffffffff)==0x7f000001) ? 'l' :
1586ea906c41SOllivier Robert 			((dummy&0xffffffe0)==0x00000000) ? '-' :
1587ea906c41SOllivier Robert 			'u');
1588ea906c41SOllivier Robert 		break;
1589ea906c41SOllivier Robert 	case AF_INET6:
15902b15cb3dSCy Schubert 		if (IN6_IS_ADDR_MULTICAST(PSOCK_ADDR6(sock)))
1591ea906c41SOllivier Robert 			ch = 'm';
1592ea906c41SOllivier Robert 		else
1593ea906c41SOllivier Robert 			ch = 'u';
1594ea906c41SOllivier Robert 		break;
1595ea906c41SOllivier Robert 	default:
1596ea906c41SOllivier Robert 		ch = '-';
1597ea906c41SOllivier Robert 		break;
1598ea906c41SOllivier Robert 	}
1599ea906c41SOllivier Robert 	return ch;
1600ea906c41SOllivier Robert }
1601ea906c41SOllivier Robert 
1602ea906c41SOllivier Robert /*
1603ea906c41SOllivier Robert  * A list of variables required by the peers command
1604ea906c41SOllivier Robert  */
1605ea906c41SOllivier Robert struct varlist opeervarlist[] = {
1606ea906c41SOllivier Robert 	{ "srcadr",	0 },	/* 0 */
1607ea906c41SOllivier Robert 	{ "dstadr",	0 },	/* 1 */
1608ea906c41SOllivier Robert 	{ "stratum",	0 },	/* 2 */
1609ea906c41SOllivier Robert 	{ "hpoll",	0 },	/* 3 */
1610ea906c41SOllivier Robert 	{ "ppoll",	0 },	/* 4 */
1611ea906c41SOllivier Robert 	{ "reach",	0 },	/* 5 */
1612ea906c41SOllivier Robert 	{ "delay",	0 },	/* 6 */
1613ea906c41SOllivier Robert 	{ "offset",	0 },	/* 7 */
1614ea906c41SOllivier Robert 	{ "jitter",	0 },	/* 8 */
1615ea906c41SOllivier Robert 	{ "dispersion", 0 },	/* 9 */
1616ea906c41SOllivier Robert 	{ "rec",	0 },	/* 10 */
1617ea906c41SOllivier Robert 	{ "reftime",	0 },	/* 11 */
1618ea906c41SOllivier Robert 	{ "srcport",	0 },	/* 12 */
16192b15cb3dSCy Schubert 	{ "hmode",	0 },	/* 13 */
1620ea906c41SOllivier Robert 	{ 0,		0 }
1621ea906c41SOllivier Robert };
1622ea906c41SOllivier Robert 
1623ea906c41SOllivier Robert struct varlist peervarlist[] = {
1624ea906c41SOllivier Robert 	{ "srcadr",	0 },	/* 0 */
1625ea906c41SOllivier Robert 	{ "refid",	0 },	/* 1 */
1626ea906c41SOllivier Robert 	{ "stratum",	0 },	/* 2 */
1627ea906c41SOllivier Robert 	{ "hpoll",	0 },	/* 3 */
1628ea906c41SOllivier Robert 	{ "ppoll",	0 },	/* 4 */
1629ea906c41SOllivier Robert 	{ "reach",	0 },	/* 5 */
1630ea906c41SOllivier Robert 	{ "delay",	0 },	/* 6 */
1631ea906c41SOllivier Robert 	{ "offset",	0 },	/* 7 */
1632ea906c41SOllivier Robert 	{ "jitter",	0 },	/* 8 */
1633ea906c41SOllivier Robert 	{ "dispersion", 0 },	/* 9 */
1634ea906c41SOllivier Robert 	{ "rec",	0 },	/* 10 */
1635ea906c41SOllivier Robert 	{ "reftime",	0 },	/* 11 */
1636ea906c41SOllivier Robert 	{ "srcport",	0 },	/* 12 */
16372b15cb3dSCy Schubert 	{ "hmode",	0 },	/* 13 */
16382b15cb3dSCy Schubert 	{ "srchost",	0 },	/* 14 */
1639ea906c41SOllivier Robert 	{ 0,		0 }
1640ea906c41SOllivier Robert };
1641ea906c41SOllivier Robert 
1642276da39aSCy Schubert struct varlist apeervarlist[] = {
1643276da39aSCy Schubert 	{ "srcadr",	0 },	/* 0 */
1644276da39aSCy Schubert 	{ "refid",	0 },	/* 1 */
1645276da39aSCy Schubert 	{ "assid",	0 },	/* 2 */
1646276da39aSCy Schubert 	{ "stratum",	0 },	/* 3 */
1647276da39aSCy Schubert 	{ "hpoll",	0 },	/* 4 */
1648276da39aSCy Schubert 	{ "ppoll",	0 },	/* 5 */
1649276da39aSCy Schubert 	{ "reach",	0 },	/* 6 */
1650276da39aSCy Schubert 	{ "delay",	0 },	/* 7 */
1651276da39aSCy Schubert 	{ "offset",	0 },	/* 8 */
1652276da39aSCy Schubert 	{ "jitter",	0 },	/* 9 */
1653276da39aSCy Schubert 	{ "dispersion", 0 },	/* 10 */
1654276da39aSCy Schubert 	{ "rec",	0 },	/* 11 */
1655276da39aSCy Schubert 	{ "reftime",	0 },	/* 12 */
1656276da39aSCy Schubert 	{ "srcport",	0 },	/* 13 */
1657276da39aSCy Schubert 	{ "hmode",	0 },	/* 14 */
1658276da39aSCy Schubert 	{ "srchost",	0 },	/* 15 */
1659276da39aSCy Schubert 	{ 0,		0 }
1660276da39aSCy Schubert };
1661276da39aSCy Schubert 
1662ea906c41SOllivier Robert 
1663ea906c41SOllivier Robert /*
1664ea906c41SOllivier Robert  * Decode an incoming data buffer and print a line in the peer list
1665ea906c41SOllivier Robert  */
1666ea906c41SOllivier Robert static int
1667ea906c41SOllivier Robert doprintpeers(
1668ea906c41SOllivier Robert 	struct varlist *pvl,
1669ea906c41SOllivier Robert 	int associd,
1670ea906c41SOllivier Robert 	int rstatus,
16713311ff84SXin LI 	size_t datalen,
16722b15cb3dSCy Schubert 	const char *data,
1673ea906c41SOllivier Robert 	FILE *fp,
1674ea906c41SOllivier Robert 	int af
1675ea906c41SOllivier Robert 	)
1676ea906c41SOllivier Robert {
1677ea906c41SOllivier Robert 	char *name;
1678ea906c41SOllivier Robert 	char *value = NULL;
1679ea906c41SOllivier Robert 	int c;
16803311ff84SXin LI 	size_t len;
16812b15cb3dSCy Schubert 	int have_srchost;
16822b15cb3dSCy Schubert 	int have_dstadr;
16832b15cb3dSCy Schubert 	int have_da_rid;
16842b15cb3dSCy Schubert 	int have_jitter;
16852b15cb3dSCy Schubert 	sockaddr_u srcadr;
16862b15cb3dSCy Schubert 	sockaddr_u dstadr;
16872b15cb3dSCy Schubert 	sockaddr_u dum_store;
16882b15cb3dSCy Schubert 	sockaddr_u refidadr;
16892b15cb3dSCy Schubert 	long hmode = 0;
1690ea906c41SOllivier Robert 	u_long srcport = 0;
16912b15cb3dSCy Schubert 	u_int32 u32;
16922b15cb3dSCy Schubert 	const char *dstadr_refid = "0.0.0.0";
16932b15cb3dSCy Schubert 	const char *serverlocal;
1694*f5f40dd6SCy Schubert 	char *drbuf = NULL;
16952b15cb3dSCy Schubert 	size_t drlen;
1696ea906c41SOllivier Robert 	u_long stratum = 0;
1697ea906c41SOllivier Robert 	long ppoll = 0;
1698ea906c41SOllivier Robert 	long hpoll = 0;
1699ea906c41SOllivier Robert 	u_long reach = 0;
1700ea906c41SOllivier Robert 	l_fp estoffset;
1701ea906c41SOllivier Robert 	l_fp estdelay;
1702ea906c41SOllivier Robert 	l_fp estjitter;
1703ea906c41SOllivier Robert 	l_fp estdisp;
1704ea906c41SOllivier Robert 	l_fp reftime;
1705ea906c41SOllivier Robert 	l_fp rec;
1706ea906c41SOllivier Robert 	l_fp ts;
1707ea906c41SOllivier Robert 	u_long poll_sec;
17084e1ef62aSXin LI 	u_long flash = 0;
1709ea906c41SOllivier Robert 	char type = '?';
1710ea906c41SOllivier Robert 	char clock_name[LENHOSTNAME];
17114e1ef62aSXin LI 	char whenbuf[12], pollbuf[12];
17124e1ef62aSXin LI 	/* [Bug 3482] formally whenbuf & pollbuf should be able to hold
17134e1ef62aSXin LI 	 * a full signed int. Not that we would use that much string
17144e1ef62aSXin LI 	 * data for it...
17154e1ef62aSXin LI 	 */
1716ea906c41SOllivier Robert 	get_systime(&ts);
1717ea906c41SOllivier Robert 
17182b15cb3dSCy Schubert 	have_srchost = FALSE;
17192b15cb3dSCy Schubert 	have_dstadr = FALSE;
17202b15cb3dSCy Schubert 	have_da_rid = FALSE;
17212b15cb3dSCy Schubert 	have_jitter = FALSE;
17222b15cb3dSCy Schubert 	ZERO_SOCK(&srcadr);
17232b15cb3dSCy Schubert 	ZERO_SOCK(&dstadr);
17242b15cb3dSCy Schubert 	clock_name[0] = '\0';
17252b15cb3dSCy Schubert 	ZERO(estoffset);
17262b15cb3dSCy Schubert 	ZERO(estdelay);
17272b15cb3dSCy Schubert 	ZERO(estjitter);
17282b15cb3dSCy Schubert 	ZERO(estdisp);
1729ea906c41SOllivier Robert 
1730ea906c41SOllivier Robert 	while (nextvar(&datalen, &data, &name, &value)) {
17314e1ef62aSXin LI 		INSIST(name && value);
17322b15cb3dSCy Schubert 		if (!strcmp("srcadr", name) ||
17332b15cb3dSCy Schubert 		    !strcmp("peeradr", name)) {
17342b15cb3dSCy Schubert 			if (!decodenetnum(value, &srcadr))
17352d4e511cSCy Schubert 				xprintf(stderr, "malformed %s=%s\n",
17362b15cb3dSCy Schubert 					name, value);
17372b15cb3dSCy Schubert 		} else if (!strcmp("srchost", name)) {
1738276da39aSCy Schubert 			if (pvl == peervarlist || pvl == apeervarlist) {
17392b15cb3dSCy Schubert 				len = strlen(value);
17402b15cb3dSCy Schubert 				if (2 < len &&
17412b15cb3dSCy Schubert 				    (size_t)len < sizeof(clock_name)) {
17422b15cb3dSCy Schubert 					/* strip quotes */
17432b15cb3dSCy Schubert 					value++;
17442b15cb3dSCy Schubert 					len -= 2;
17452b15cb3dSCy Schubert 					memcpy(clock_name, value, len);
17462b15cb3dSCy Schubert 					clock_name[len] = '\0';
17472b15cb3dSCy Schubert 					have_srchost = TRUE;
17482b15cb3dSCy Schubert 				}
17492b15cb3dSCy Schubert 			}
17502b15cb3dSCy Schubert 		} else if (!strcmp("dstadr", name)) {
17512b15cb3dSCy Schubert 			if (decodenetnum(value, &dum_store)) {
17522b15cb3dSCy Schubert 				type = decodeaddrtype(&dum_store);
17532b15cb3dSCy Schubert 				have_dstadr = TRUE;
17542b15cb3dSCy Schubert 				dstadr = dum_store;
17552b15cb3dSCy Schubert 				if (pvl == opeervarlist) {
17562b15cb3dSCy Schubert 					have_da_rid = TRUE;
17572b15cb3dSCy Schubert 					dstadr_refid = trunc_left(stoa(&dstadr), 15);
17582b15cb3dSCy Schubert 				}
17592b15cb3dSCy Schubert 			}
17602b15cb3dSCy Schubert 		} else if (!strcmp("hmode", name)) {
17612b15cb3dSCy Schubert 			decodeint(value, &hmode);
17622b15cb3dSCy Schubert 		} else if (!strcmp("refid", name)) {
17634990d495SXin LI 			if (   (pvl == peervarlist)
17644990d495SXin LI 			    && (drefid == REFID_IPV4)) {
17652b15cb3dSCy Schubert 				have_da_rid = TRUE;
17662b15cb3dSCy Schubert 				drlen = strlen(value);
17672b15cb3dSCy Schubert 				if (0 == drlen) {
17682b15cb3dSCy Schubert 					dstadr_refid = "";
17692b15cb3dSCy Schubert 				} else if (drlen <= 4) {
17702b15cb3dSCy Schubert 					ZERO(u32);
17712b15cb3dSCy Schubert 					memcpy(&u32, value, drlen);
17722b15cb3dSCy Schubert 					dstadr_refid = refid_str(u32, 1);
17732b15cb3dSCy Schubert 				} else if (decodenetnum(value, &refidadr)) {
17742b15cb3dSCy Schubert 					if (SOCK_UNSPEC(&refidadr))
1775ea906c41SOllivier Robert 						dstadr_refid = "0.0.0.0";
1776*f5f40dd6SCy Schubert 					else if (ISREFCLOCKADR(&refidadr)) {
1777ea906c41SOllivier Robert 						dstadr_refid =
17782b15cb3dSCy Schubert 						    refnumtoa(&refidadr);
1779*f5f40dd6SCy Schubert 					} else {
1780ea906c41SOllivier Robert 						dstadr_refid =
17812b15cb3dSCy Schubert 						    stoa(&refidadr);
1782*f5f40dd6SCy Schubert 					}
1783ea906c41SOllivier Robert 				} else {
17842b15cb3dSCy Schubert 					have_da_rid = FALSE;
1785ea906c41SOllivier Robert 				}
17864990d495SXin LI 			} else if (   (pvl == apeervarlist)
17874990d495SXin LI 				   || (pvl == peervarlist)) {
17884990d495SXin LI 				/* no need to check drefid == REFID_HASH */
1789276da39aSCy Schubert 				have_da_rid = TRUE;
1790276da39aSCy Schubert 				drlen = strlen(value);
1791276da39aSCy Schubert 				if (0 == drlen) {
1792276da39aSCy Schubert 					dstadr_refid = "";
1793276da39aSCy Schubert 				} else if (drlen <= 4) {
1794276da39aSCy Schubert 					ZERO(u32);
1795276da39aSCy Schubert 					memcpy(&u32, value, drlen);
1796276da39aSCy Schubert 					dstadr_refid = refid_str(u32, 1);
17972d4e511cSCy Schubert 					//xprintf(stderr, "apeervarlist S1 refid: value=<%s>\n", value);
1798276da39aSCy Schubert 				} else if (decodenetnum(value, &refidadr)) {
1799276da39aSCy Schubert 					if (SOCK_UNSPEC(&refidadr))
1800276da39aSCy Schubert 						dstadr_refid = "0.0.0.0";
1801*f5f40dd6SCy Schubert 					else if (ISREFCLOCKADR(&refidadr)) {
1802276da39aSCy Schubert 						dstadr_refid =
1803276da39aSCy Schubert 							refnumtoa(&refidadr);
1804*f5f40dd6SCy Schubert 						if (pvl == apeervarlist) {
1805*f5f40dd6SCy Schubert 							/*
1806*f5f40dd6SCy Schubert 							 * restrict refid to
1807*f5f40dd6SCy Schubert 							 * 8 chars [Bug 3850]
1808*f5f40dd6SCy Schubert 							 */
1809*f5f40dd6SCy Schubert 							dstadr_refid =
1810*f5f40dd6SCy Schubert 								trunc_right(
1811*f5f40dd6SCy Schubert 									dstadr_refid,
1812*f5f40dd6SCy Schubert 									8);
1813276da39aSCy Schubert 						}
1814*f5f40dd6SCy Schubert 					} else {
1815*f5f40dd6SCy Schubert 						drbuf = emalloc(10);
1816*f5f40dd6SCy Schubert 						snprintf(drbuf, 10, "%0x",
1817*f5f40dd6SCy Schubert 							 SRCADR(&refidadr));
1818*f5f40dd6SCy Schubert 						dstadr_refid = drbuf;
1819*f5f40dd6SCy Schubert 					}
1820276da39aSCy Schubert 				} else {
1821276da39aSCy Schubert 					have_da_rid = FALSE;
1822276da39aSCy Schubert 				}
1823ea906c41SOllivier Robert 			}
18242b15cb3dSCy Schubert 		} else if (!strcmp("stratum", name)) {
18252b15cb3dSCy Schubert 			decodeuint(value, &stratum);
18262b15cb3dSCy Schubert 		} else if (!strcmp("hpoll", name)) {
18272b15cb3dSCy Schubert 			if (decodeint(value, &hpoll) && hpoll < 0)
1828ea906c41SOllivier Robert 				hpoll = NTP_MINPOLL;
18292b15cb3dSCy Schubert 		} else if (!strcmp("ppoll", name)) {
18302b15cb3dSCy Schubert 			if (decodeint(value, &ppoll) && ppoll < 0)
1831ea906c41SOllivier Robert 				ppoll = NTP_MINPOLL;
18322b15cb3dSCy Schubert 		} else if (!strcmp("reach", name)) {
18332b15cb3dSCy Schubert 			decodeuint(value, &reach);
18342b15cb3dSCy Schubert 		} else if (!strcmp("delay", name)) {
18352b15cb3dSCy Schubert 			decodetime(value, &estdelay);
18362b15cb3dSCy Schubert 		} else if (!strcmp("offset", name)) {
18372b15cb3dSCy Schubert 			decodetime(value, &estoffset);
18382b15cb3dSCy Schubert 		} else if (!strcmp("jitter", name)) {
1839276da39aSCy Schubert 			if ((pvl == peervarlist || pvl == apeervarlist)
1840276da39aSCy Schubert 			    && decodetime(value, &estjitter))
18412b15cb3dSCy Schubert 				have_jitter = 1;
18422b15cb3dSCy Schubert 		} else if (!strcmp("rootdisp", name) ||
18432b15cb3dSCy Schubert 			   !strcmp("dispersion", name)) {
18442b15cb3dSCy Schubert 			decodetime(value, &estdisp);
18452b15cb3dSCy Schubert 		} else if (!strcmp("rec", name)) {
18462b15cb3dSCy Schubert 			decodets(value, &rec);
18472b15cb3dSCy Schubert 		} else if (!strcmp("srcport", name) ||
18482b15cb3dSCy Schubert 			   !strcmp("peerport", name)) {
18492b15cb3dSCy Schubert 			decodeuint(value, &srcport);
18502b15cb3dSCy Schubert 		} else if (!strcmp("reftime", name)) {
1851ea906c41SOllivier Robert 			if (!decodets(value, &reftime))
1852ea906c41SOllivier Robert 				L_CLR(&reftime);
18534e1ef62aSXin LI 		} else if (!strcmp("flash", name)) {
18544e1ef62aSXin LI 			decodeuint(value, &flash);
1855276da39aSCy Schubert 		} else {
18562d4e511cSCy Schubert 			// xprintf(stderr, "UNRECOGNIZED name=%s ", name);
1857ea906c41SOllivier Robert 		}
1858ea906c41SOllivier Robert 	}
1859ea906c41SOllivier Robert 
1860ea906c41SOllivier Robert 	/*
18612b15cb3dSCy Schubert 	 * hmode gives the best guidance for the t column.  If the response
18622b15cb3dSCy Schubert 	 * did not include hmode we'll use the old decodeaddrtype() result.
1863ea906c41SOllivier Robert 	 */
18642b15cb3dSCy Schubert 	switch (hmode) {
18652b15cb3dSCy Schubert 
18662b15cb3dSCy Schubert 	case MODE_BCLIENT:
18672b15cb3dSCy Schubert 		/* broadcastclient or multicastclient */
18682b15cb3dSCy Schubert 		type = 'b';
18692b15cb3dSCy Schubert 		break;
18702b15cb3dSCy Schubert 
18712b15cb3dSCy Schubert 	case MODE_BROADCAST:
18722b15cb3dSCy Schubert 		/* broadcast or multicast server */
18732b15cb3dSCy Schubert 		if (IS_MCAST(&srcadr))
18742b15cb3dSCy Schubert 			type = 'M';
18752b15cb3dSCy Schubert 		else
18762b15cb3dSCy Schubert 			type = 'B';
18772b15cb3dSCy Schubert 		break;
18782b15cb3dSCy Schubert 
18792b15cb3dSCy Schubert 	case MODE_CLIENT:
18802b15cb3dSCy Schubert 		if (ISREFCLOCKADR(&srcadr))
18812b15cb3dSCy Schubert 			type = 'l';	/* local refclock*/
18822b15cb3dSCy Schubert 		else if (SOCK_UNSPEC(&srcadr))
18832b15cb3dSCy Schubert 			type = 'p';	/* pool */
18842b15cb3dSCy Schubert 		else if (IS_MCAST(&srcadr))
18852b15cb3dSCy Schubert 			type = 'a';	/* manycastclient */
18862b15cb3dSCy Schubert 		else
18872b15cb3dSCy Schubert 			type = 'u';	/* unicast */
18882b15cb3dSCy Schubert 		break;
18892b15cb3dSCy Schubert 
18902b15cb3dSCy Schubert 	case MODE_ACTIVE:
18912b15cb3dSCy Schubert 		type = 's';		/* symmetric active */
18922b15cb3dSCy Schubert 		break;			/* configured */
18932b15cb3dSCy Schubert 
18942b15cb3dSCy Schubert 	case MODE_PASSIVE:
18952b15cb3dSCy Schubert 		type = 'S';		/* symmetric passive */
18962b15cb3dSCy Schubert 		break;			/* ephemeral */
18972b15cb3dSCy Schubert 	}
1898ea906c41SOllivier Robert 
1899ea906c41SOllivier Robert 	/*
1900ea906c41SOllivier Robert 	 * Got everything, format the line
1901ea906c41SOllivier Robert 	 */
19022b15cb3dSCy Schubert 	poll_sec = 1 << min(ppoll, hpoll);
1903ea906c41SOllivier Robert 	if (pktversion > NTP_OLDVERSION)
1904ea906c41SOllivier Robert 		c = flash3[CTL_PEER_STATVAL(rstatus) & 0x7];
1905ea906c41SOllivier Robert 	else
1906ea906c41SOllivier Robert 		c = flash2[CTL_PEER_STATVAL(rstatus) & 0x3];
19072b15cb3dSCy Schubert 	if (numhosts > 1) {
1908276da39aSCy Schubert 		if ((pvl == peervarlist || pvl == apeervarlist)
1909276da39aSCy Schubert 		    && have_dstadr) {
19102b15cb3dSCy Schubert 			serverlocal = nntohost_col(&dstadr,
19112b15cb3dSCy Schubert 			    (size_t)min(LIB_BUFLENGTH - 1, maxhostlen),
19122b15cb3dSCy Schubert 			    TRUE);
19132b15cb3dSCy Schubert 		} else {
19142b15cb3dSCy Schubert 			if (currenthostisnum)
19152b15cb3dSCy Schubert 				serverlocal = trunc_left(currenthost,
19162b15cb3dSCy Schubert 							 maxhostlen);
19172b15cb3dSCy Schubert 			else
19182b15cb3dSCy Schubert 				serverlocal = currenthost;
19192b15cb3dSCy Schubert 		}
19202d4e511cSCy Schubert 		xprintf(fp, "%-*s ", (int)maxhostlen, serverlocal);
19212b15cb3dSCy Schubert 	}
19222b15cb3dSCy Schubert 	if (AF_UNSPEC == af || AF(&srcadr) == af) {
19232b15cb3dSCy Schubert 		if (!have_srchost)
19242b15cb3dSCy Schubert 			strlcpy(clock_name, nntohost(&srcadr),
19252b15cb3dSCy Schubert 				sizeof(clock_name));
192609100258SXin LI 		/* wide and long source - space over on next line */
192709100258SXin LI 		/* allow for host + sp if > 1 and regular tally + source + sp */
19282b15cb3dSCy Schubert 		if (wideremote && 15 < strlen(clock_name))
19292d4e511cSCy Schubert 			xprintf(fp, "%c%s\n%*s", c, clock_name,
193009100258SXin LI 				((numhosts > 1) ? (int)maxhostlen + 1 : 0)
193109100258SXin LI 							+ 1 + 15 + 1, "");
19322b15cb3dSCy Schubert 		else
19332d4e511cSCy Schubert 			xprintf(fp, "%c%-15.15s ", c, clock_name);
19344e1ef62aSXin LI 		if ((flash & TEST12) && (pvl != opeervarlist)) {
19352d4e511cSCy Schubert 			drlen = xprintf(fp, "(loop)");
19364e1ef62aSXin LI 		} else if (!have_da_rid) {
19372b15cb3dSCy Schubert 			drlen = 0;
19382b15cb3dSCy Schubert 		} else {
19392b15cb3dSCy Schubert 			drlen = strlen(dstadr_refid);
19402b15cb3dSCy Schubert 			makeascii(drlen, dstadr_refid, fp);
19412b15cb3dSCy Schubert 		}
1942*f5f40dd6SCy Schubert 		free(drbuf);
1943276da39aSCy Schubert 		if (pvl == apeervarlist) {
1944276da39aSCy Schubert 			while (drlen++ < 9)
19452d4e511cSCy Schubert 				xputc(' ', fp);
19462d4e511cSCy Schubert 			xprintf(fp, "%-6d", associd);
1947276da39aSCy Schubert 		} else {
19482b15cb3dSCy Schubert 			while (drlen++ < 15)
19492d4e511cSCy Schubert 				xputc(' ', fp);
1950276da39aSCy Schubert 		}
19512d4e511cSCy Schubert 		xprintf(fp,
19522b15cb3dSCy Schubert 			" %2ld %c %4.4s %4.4s  %3lo  %7.7s %8.7s %7.7s\n",
19532b15cb3dSCy Schubert 			stratum, type,
19542b15cb3dSCy Schubert 			prettyinterval(whenbuf, sizeof(whenbuf),
19552b15cb3dSCy Schubert 				       when(&ts, &rec, &reftime)),
19562b15cb3dSCy Schubert 			prettyinterval(pollbuf, sizeof(pollbuf),
19572b15cb3dSCy Schubert 				       (int)poll_sec),
19582d4e511cSCy Schubert 			reach, ulfptoms(&estdelay, 3),
19592b15cb3dSCy Schubert 			lfptoms(&estoffset, 3),
19602b15cb3dSCy Schubert 			(have_jitter)
19612d4e511cSCy Schubert 			    ? ulfptoms(&estjitter, 3)
19622d4e511cSCy Schubert 			    : ulfptoms(&estdisp, 3));
1963ea906c41SOllivier Robert 		return (1);
1964ea906c41SOllivier Robert 	}
1965ea906c41SOllivier Robert 	else
1966ea906c41SOllivier Robert 		return(1);
1967ea906c41SOllivier Robert }
1968ea906c41SOllivier Robert 
1969ea906c41SOllivier Robert 
1970ea906c41SOllivier Robert /*
1971ea906c41SOllivier Robert  * dogetpeers - given an association ID, read and print the spreadsheet
1972ea906c41SOllivier Robert  *		peer variables.
1973ea906c41SOllivier Robert  */
1974ea906c41SOllivier Robert static int
1975ea906c41SOllivier Robert dogetpeers(
1976ea906c41SOllivier Robert 	struct varlist *pvl,
19772b15cb3dSCy Schubert 	associd_t associd,
1978ea906c41SOllivier Robert 	FILE *fp,
1979ea906c41SOllivier Robert 	int af
1980ea906c41SOllivier Robert 	)
1981ea906c41SOllivier Robert {
19822b15cb3dSCy Schubert 	const char *datap;
1983ea906c41SOllivier Robert 	int res;
19843311ff84SXin LI 	size_t dsize;
1985ea906c41SOllivier Robert 	u_short rstatus;
1986ea906c41SOllivier Robert 
1987ea906c41SOllivier Robert #ifdef notdef
1988ea906c41SOllivier Robert 	res = doquerylist(pvl, CTL_OP_READVAR, associd, 0, &rstatus,
1989ea906c41SOllivier Robert 			  &dsize, &datap);
1990ea906c41SOllivier Robert #else
1991ea906c41SOllivier Robert 	/*
1992ea906c41SOllivier Robert 	 * Damn fuzzballs
1993ea906c41SOllivier Robert 	 */
19942b15cb3dSCy Schubert 	res = doquery(CTL_OP_READVAR, associd, 0, 0, NULL, &rstatus,
1995ea906c41SOllivier Robert 			  &dsize, &datap);
1996ea906c41SOllivier Robert #endif
1997ea906c41SOllivier Robert 
1998ea906c41SOllivier Robert 	if (res != 0)
1999ea906c41SOllivier Robert 		return 0;
2000ea906c41SOllivier Robert 
2001ea906c41SOllivier Robert 	if (dsize == 0) {
2002ea906c41SOllivier Robert 		if (numhosts > 1)
20032d4e511cSCy Schubert 			xprintf(stderr, "server=%s ", currenthost);
20042d4e511cSCy Schubert 		xprintf(stderr,
20052b15cb3dSCy Schubert 			"***No information returned for association %u\n",
2006ea906c41SOllivier Robert 			associd);
2007ea906c41SOllivier Robert 		return 0;
2008ea906c41SOllivier Robert 	}
2009ea906c41SOllivier Robert 
20102b15cb3dSCy Schubert 	return doprintpeers(pvl, associd, (int)rstatus, dsize, datap,
20112b15cb3dSCy Schubert 			    fp, af);
2012ea906c41SOllivier Robert }
2013ea906c41SOllivier Robert 
2014ea906c41SOllivier Robert 
2015ea906c41SOllivier Robert /*
2016ea906c41SOllivier Robert  * peers - print a peer spreadsheet
2017ea906c41SOllivier Robert  */
2018ea906c41SOllivier Robert static void
2019ea906c41SOllivier Robert dopeers(
2020ea906c41SOllivier Robert 	int showall,
2021ea906c41SOllivier Robert 	FILE *fp,
2022ea906c41SOllivier Robert 	int af
2023ea906c41SOllivier Robert 	)
2024ea906c41SOllivier Robert {
20252b15cb3dSCy Schubert 	u_int		u;
2026ea906c41SOllivier Robert 	char		fullname[LENHOSTNAME];
20272b15cb3dSCy Schubert 	sockaddr_u	netnum;
20282b15cb3dSCy Schubert 	const char *	name_or_num;
20292b15cb3dSCy Schubert 	size_t		sl;
2030ea906c41SOllivier Robert 
2031ea906c41SOllivier Robert 	if (!dogetassoc(fp))
2032ea906c41SOllivier Robert 		return;
2033ea906c41SOllivier Robert 
2034a466cc55SCy Schubert 	if (numhosts > 1) {
20352b15cb3dSCy Schubert 		for (u = 0; u < numhosts; u++) {
20362b15cb3dSCy Schubert 			if (getnetnum(chosts[u].name, &netnum, fullname, af)) {
20372b15cb3dSCy Schubert 				name_or_num = nntohost(&netnum);
20382b15cb3dSCy Schubert 				sl = strlen(name_or_num);
20392b15cb3dSCy Schubert 				maxhostlen = max(maxhostlen, sl);
20402b15cb3dSCy Schubert 			}
2041ea906c41SOllivier Robert 		}
20422d4e511cSCy Schubert 		xprintf(fp, "%-*.*s ", (int)maxhostlen, (int)maxhostlen,
20432b15cb3dSCy Schubert 			"server (local)");
2044a466cc55SCy Schubert 	}
20452d4e511cSCy Schubert 	xprintf(fp,
2046ea906c41SOllivier Robert 		"     remote           refid      st t when poll reach   delay   offset  jitter\n");
2047ea906c41SOllivier Robert 	if (numhosts > 1)
20482b15cb3dSCy Schubert 		for (u = 0; u <= maxhostlen; u++)
20492d4e511cSCy Schubert 			xprintf(fp, "=");
20502d4e511cSCy Schubert 	xprintf(fp,
2051ea906c41SOllivier Robert 		"==============================================================================\n");
2052ea906c41SOllivier Robert 
20532b15cb3dSCy Schubert 	for (u = 0; u < numassoc; u++) {
2054ea906c41SOllivier Robert 		if (!showall &&
20552b15cb3dSCy Schubert 		    !(CTL_PEER_STATVAL(assoc_cache[u].status)
20562b15cb3dSCy Schubert 		      & (CTL_PST_CONFIG|CTL_PST_REACH))) {
20572b15cb3dSCy Schubert 			if (debug)
20582d4e511cSCy Schubert 				xprintf(stderr, "eliding [%d]\n",
20592b15cb3dSCy Schubert 					(int)assoc_cache[u].assid);
2060ea906c41SOllivier Robert 			continue;
2061ea906c41SOllivier Robert 		}
20622b15cb3dSCy Schubert 		if (!dogetpeers(peervarlist, (int)assoc_cache[u].assid,
20632b15cb3dSCy Schubert 				fp, af))
20642b15cb3dSCy Schubert 			return;
2065ea906c41SOllivier Robert 	}
2066ea906c41SOllivier Robert 	return;
2067ea906c41SOllivier Robert }
2068ea906c41SOllivier Robert 
2069ea906c41SOllivier Robert 
2070ea906c41SOllivier Robert /*
2071276da39aSCy Schubert  * doapeers - print a peer spreadsheet with assocIDs
2072276da39aSCy Schubert  */
2073276da39aSCy Schubert static void
2074276da39aSCy Schubert doapeers(
2075276da39aSCy Schubert 	int showall,
2076276da39aSCy Schubert 	FILE *fp,
2077276da39aSCy Schubert 	int af
2078276da39aSCy Schubert 	)
2079276da39aSCy Schubert {
2080276da39aSCy Schubert 	u_int		u;
2081276da39aSCy Schubert 	char		fullname[LENHOSTNAME];
2082276da39aSCy Schubert 	sockaddr_u	netnum;
2083276da39aSCy Schubert 	const char *	name_or_num;
2084276da39aSCy Schubert 	size_t		sl;
2085276da39aSCy Schubert 
2086276da39aSCy Schubert 	if (!dogetassoc(fp))
2087276da39aSCy Schubert 		return;
2088276da39aSCy Schubert 
2089a466cc55SCy Schubert 	if (numhosts > 1) {
2090276da39aSCy Schubert 		for (u = 0; u < numhosts; u++) {
2091276da39aSCy Schubert 			if (getnetnum(chosts[u].name, &netnum, fullname, af)) {
2092276da39aSCy Schubert 				name_or_num = nntohost(&netnum);
2093276da39aSCy Schubert 				sl = strlen(name_or_num);
2094276da39aSCy Schubert 				maxhostlen = max(maxhostlen, sl);
2095276da39aSCy Schubert 			}
2096276da39aSCy Schubert 		}
20972d4e511cSCy Schubert 		xprintf(fp, "%-*.*s ", (int)maxhostlen, (int)maxhostlen,
2098276da39aSCy Schubert 			"server (local)");
2099a466cc55SCy Schubert 	}
21002d4e511cSCy Schubert 	xprintf(fp,
2101276da39aSCy Schubert 		"     remote       refid   assid  st t when poll reach   delay   offset  jitter\n");
2102276da39aSCy Schubert 	if (numhosts > 1)
2103276da39aSCy Schubert 		for (u = 0; u <= maxhostlen; u++)
21042d4e511cSCy Schubert 			xprintf(fp, "=");
21052d4e511cSCy Schubert 	xprintf(fp,
2106276da39aSCy Schubert 		"==============================================================================\n");
2107276da39aSCy Schubert 
2108276da39aSCy Schubert 	for (u = 0; u < numassoc; u++) {
2109276da39aSCy Schubert 		if (!showall &&
2110276da39aSCy Schubert 		    !(CTL_PEER_STATVAL(assoc_cache[u].status)
2111276da39aSCy Schubert 		      & (CTL_PST_CONFIG|CTL_PST_REACH))) {
2112276da39aSCy Schubert 			if (debug)
21132d4e511cSCy Schubert 				xprintf(stderr, "eliding [%d]\n",
2114276da39aSCy Schubert 					(int)assoc_cache[u].assid);
2115276da39aSCy Schubert 			continue;
2116276da39aSCy Schubert 		}
2117276da39aSCy Schubert 		if (!dogetpeers(apeervarlist, (int)assoc_cache[u].assid,
2118276da39aSCy Schubert 				fp, af))
2119276da39aSCy Schubert 			return;
2120276da39aSCy Schubert 	}
2121276da39aSCy Schubert 	return;
2122276da39aSCy Schubert }
2123276da39aSCy Schubert 
2124276da39aSCy Schubert 
2125276da39aSCy Schubert /*
2126ea906c41SOllivier Robert  * peers - print a peer spreadsheet
2127ea906c41SOllivier Robert  */
2128ea906c41SOllivier Robert /*ARGSUSED*/
2129ea906c41SOllivier Robert static void
2130ea906c41SOllivier Robert peers(
2131ea906c41SOllivier Robert 	struct parse *pcmd,
2132ea906c41SOllivier Robert 	FILE *fp
2133ea906c41SOllivier Robert 	)
2134ea906c41SOllivier Robert {
21354990d495SXin LI 	if (drefid == REFID_HASH) {
21364990d495SXin LI 		apeers(pcmd, fp);
21374990d495SXin LI 	} else {
2138ea906c41SOllivier Robert 		int af = 0;
2139ea906c41SOllivier Robert 
2140ea906c41SOllivier Robert 		if (pcmd->nargs == 1) {
2141ea906c41SOllivier Robert 			if (pcmd->argval->ival == 6)
2142ea906c41SOllivier Robert 				af = AF_INET6;
2143ea906c41SOllivier Robert 			else
2144ea906c41SOllivier Robert 				af = AF_INET;
2145ea906c41SOllivier Robert 		}
2146ea906c41SOllivier Robert 		dopeers(0, fp, af);
2147ea906c41SOllivier Robert 	}
21484990d495SXin LI }
2149ea906c41SOllivier Robert 
2150ea906c41SOllivier Robert 
2151ea906c41SOllivier Robert /*
2152276da39aSCy Schubert  * apeers - print a peer spreadsheet, with assocIDs
2153276da39aSCy Schubert  */
2154276da39aSCy Schubert /*ARGSUSED*/
2155276da39aSCy Schubert static void
2156276da39aSCy Schubert apeers(
2157276da39aSCy Schubert 	struct parse *pcmd,
2158276da39aSCy Schubert 	FILE *fp
2159276da39aSCy Schubert 	)
2160276da39aSCy Schubert {
2161276da39aSCy Schubert 	int af = 0;
2162276da39aSCy Schubert 
2163276da39aSCy Schubert 	if (pcmd->nargs == 1) {
2164276da39aSCy Schubert 		if (pcmd->argval->ival == 6)
2165276da39aSCy Schubert 			af = AF_INET6;
2166276da39aSCy Schubert 		else
2167276da39aSCy Schubert 			af = AF_INET;
2168276da39aSCy Schubert 	}
2169276da39aSCy Schubert 	doapeers(0, fp, af);
2170276da39aSCy Schubert }
2171276da39aSCy Schubert 
2172276da39aSCy Schubert 
2173276da39aSCy Schubert /*
2174ea906c41SOllivier Robert  * lpeers - print a peer spreadsheet including all fuzzball peers
2175ea906c41SOllivier Robert  */
2176ea906c41SOllivier Robert /*ARGSUSED*/
2177ea906c41SOllivier Robert static void
2178ea906c41SOllivier Robert lpeers(
2179ea906c41SOllivier Robert 	struct parse *pcmd,
2180ea906c41SOllivier Robert 	FILE *fp
2181ea906c41SOllivier Robert 	)
2182ea906c41SOllivier Robert {
2183ea906c41SOllivier Robert 	int af = 0;
2184ea906c41SOllivier Robert 
2185ea906c41SOllivier Robert 	if (pcmd->nargs == 1) {
2186ea906c41SOllivier Robert 		if (pcmd->argval->ival == 6)
2187ea906c41SOllivier Robert 			af = AF_INET6;
2188ea906c41SOllivier Robert 		else
2189ea906c41SOllivier Robert 			af = AF_INET;
2190ea906c41SOllivier Robert 	}
2191ea906c41SOllivier Robert 	dopeers(1, fp, af);
2192ea906c41SOllivier Robert }
2193ea906c41SOllivier Robert 
2194ea906c41SOllivier Robert 
2195ea906c41SOllivier Robert /*
2196ea906c41SOllivier Robert  * opeers - print a peer spreadsheet
2197ea906c41SOllivier Robert  */
2198ea906c41SOllivier Robert static void
2199ea906c41SOllivier Robert doopeers(
2200ea906c41SOllivier Robert 	int showall,
2201ea906c41SOllivier Robert 	FILE *fp,
2202ea906c41SOllivier Robert 	int af
2203ea906c41SOllivier Robert 	)
2204ea906c41SOllivier Robert {
22052b15cb3dSCy Schubert 	u_int i;
2206ea906c41SOllivier Robert 	char fullname[LENHOSTNAME];
22072b15cb3dSCy Schubert 	sockaddr_u netnum;
2208ea906c41SOllivier Robert 
2209ea906c41SOllivier Robert 	if (!dogetassoc(fp))
2210ea906c41SOllivier Robert 		return;
2211ea906c41SOllivier Robert 
2212a466cc55SCy Schubert 	if (numhosts > 1) {
2213ea906c41SOllivier Robert 		for (i = 0; i < numhosts; ++i) {
2214a466cc55SCy Schubert 			if (getnetnum(chosts[i].name, &netnum, fullname, af)) {
2215a466cc55SCy Schubert 				maxhostlen = max(maxhostlen, strlen(fullname));
2216ea906c41SOllivier Robert 			}
22172d4e511cSCy Schubert 			xprintf(fp, "%-*.*s ", (int)maxhostlen, (int)maxhostlen,
22182b15cb3dSCy Schubert 				"server");
2219a466cc55SCy Schubert 		}
2220a466cc55SCy Schubert 	}
22212d4e511cSCy Schubert 	xprintf(fp,
2222ea906c41SOllivier Robert 	    "     remote           local      st t when poll reach   delay   offset    disp\n");
2223ea906c41SOllivier Robert 	if (numhosts > 1)
2224ea906c41SOllivier Robert 		for (i = 0; i <= maxhostlen; ++i)
22252d4e511cSCy Schubert 			xprintf(fp, "=");
22262d4e511cSCy Schubert 	xprintf(fp,
2227ea906c41SOllivier Robert 	    "==============================================================================\n");
2228ea906c41SOllivier Robert 
2229ea906c41SOllivier Robert 	for (i = 0; i < numassoc; i++) {
2230ea906c41SOllivier Robert 		if (!showall &&
22312b15cb3dSCy Schubert 		    !(CTL_PEER_STATVAL(assoc_cache[i].status) &
22322b15cb3dSCy Schubert 		      (CTL_PST_CONFIG | CTL_PST_REACH)))
2233ea906c41SOllivier Robert 			continue;
22342b15cb3dSCy Schubert 		if (!dogetpeers(opeervarlist, assoc_cache[i].assid, fp, af))
2235ea906c41SOllivier Robert 			return;
2236ea906c41SOllivier Robert 	}
2237ea906c41SOllivier Robert 	return;
2238ea906c41SOllivier Robert }
2239ea906c41SOllivier Robert 
2240ea906c41SOllivier Robert 
2241ea906c41SOllivier Robert /*
2242ea906c41SOllivier Robert  * opeers - print a peer spreadsheet the old way
2243ea906c41SOllivier Robert  */
2244ea906c41SOllivier Robert /*ARGSUSED*/
2245ea906c41SOllivier Robert static void
2246ea906c41SOllivier Robert opeers(
2247ea906c41SOllivier Robert 	struct parse *pcmd,
2248ea906c41SOllivier Robert 	FILE *fp
2249ea906c41SOllivier Robert 	)
2250ea906c41SOllivier Robert {
2251ea906c41SOllivier Robert 	int af = 0;
2252ea906c41SOllivier Robert 
2253ea906c41SOllivier Robert 	if (pcmd->nargs == 1) {
2254ea906c41SOllivier Robert 		if (pcmd->argval->ival == 6)
2255ea906c41SOllivier Robert 			af = AF_INET6;
2256ea906c41SOllivier Robert 		else
2257ea906c41SOllivier Robert 			af = AF_INET;
2258ea906c41SOllivier Robert 	}
2259ea906c41SOllivier Robert 	doopeers(0, fp, af);
2260ea906c41SOllivier Robert }
2261ea906c41SOllivier Robert 
2262ea906c41SOllivier Robert 
2263ea906c41SOllivier Robert /*
2264ea906c41SOllivier Robert  * lopeers - print a peer spreadsheet including all fuzzball peers
2265ea906c41SOllivier Robert  */
2266ea906c41SOllivier Robert /*ARGSUSED*/
2267ea906c41SOllivier Robert static void
2268ea906c41SOllivier Robert lopeers(
2269ea906c41SOllivier Robert 	struct parse *pcmd,
2270ea906c41SOllivier Robert 	FILE *fp
2271ea906c41SOllivier Robert 	)
2272ea906c41SOllivier Robert {
2273ea906c41SOllivier Robert 	int af = 0;
2274ea906c41SOllivier Robert 
2275ea906c41SOllivier Robert 	if (pcmd->nargs == 1) {
2276ea906c41SOllivier Robert 		if (pcmd->argval->ival == 6)
2277ea906c41SOllivier Robert 			af = AF_INET6;
2278ea906c41SOllivier Robert 		else
2279ea906c41SOllivier Robert 			af = AF_INET;
2280ea906c41SOllivier Robert 	}
2281ea906c41SOllivier Robert 	doopeers(1, fp, af);
2282ea906c41SOllivier Robert }
22832b15cb3dSCy Schubert 
22842b15cb3dSCy Schubert 
22852b15cb3dSCy Schubert /*
22862b15cb3dSCy Schubert  * config - send a configuration command to a remote host
22872b15cb3dSCy Schubert  */
22882b15cb3dSCy Schubert static void
22892b15cb3dSCy Schubert config (
22902b15cb3dSCy Schubert 	struct parse *pcmd,
22912b15cb3dSCy Schubert 	FILE *fp
22922b15cb3dSCy Schubert 	)
22932b15cb3dSCy Schubert {
22942b15cb3dSCy Schubert 	const char *cfgcmd;
22952b15cb3dSCy Schubert 	u_short rstatus;
22963311ff84SXin LI 	size_t rsize;
22972b15cb3dSCy Schubert 	const char *rdata;
22982b15cb3dSCy Schubert 	char *resp;
22992b15cb3dSCy Schubert 	int res;
23002b15cb3dSCy Schubert 	int col;
23012b15cb3dSCy Schubert 	int i;
23022b15cb3dSCy Schubert 
23032b15cb3dSCy Schubert 	cfgcmd = pcmd->argval[0].string;
23042b15cb3dSCy Schubert 
23052b15cb3dSCy Schubert 	if (debug > 2)
23062d4e511cSCy Schubert 		xprintf(stderr,
23072b15cb3dSCy Schubert 			"In Config\n"
23082b15cb3dSCy Schubert 			"Keyword = %s\n"
23092b15cb3dSCy Schubert 			"Command = %s\n", pcmd->keyword, cfgcmd);
23102b15cb3dSCy Schubert 
23113311ff84SXin LI 	res = doquery(CTL_OP_CONFIGURE, 0, 1,
23123311ff84SXin LI 		      strlen(cfgcmd), cfgcmd,
23132b15cb3dSCy Schubert 		      &rstatus, &rsize, &rdata);
23142b15cb3dSCy Schubert 
23152b15cb3dSCy Schubert 	if (res != 0)
23162b15cb3dSCy Schubert 		return;
23172b15cb3dSCy Schubert 
23182b15cb3dSCy Schubert 	if (rsize > 0 && '\n' == rdata[rsize - 1])
23192b15cb3dSCy Schubert 		rsize--;
23202b15cb3dSCy Schubert 
23212b15cb3dSCy Schubert 	resp = emalloc(rsize + 1);
23222b15cb3dSCy Schubert 	memcpy(resp, rdata, rsize);
23232b15cb3dSCy Schubert 	resp[rsize] = '\0';
23242b15cb3dSCy Schubert 
23252b15cb3dSCy Schubert 	col = -1;
23262b15cb3dSCy Schubert 	if (1 == sscanf(resp, "column %d syntax error", &col)
23272b15cb3dSCy Schubert 	    && col >= 0 && (size_t)col <= strlen(cfgcmd) + 1) {
232809100258SXin LI 		if (interactive)
23292d4e511cSCy Schubert 			xputs("             *", stdout); /* "ntpq> :config " */
233009100258SXin LI 		else
23312b15cb3dSCy Schubert 			printf("%s\n", cfgcmd);
233209100258SXin LI 		for (i = 0; i < col; i++)
23332d4e511cSCy Schubert 			xputc('_', stdout);
23342d4e511cSCy Schubert 		xputs("^\n", stdout);
23352b15cb3dSCy Schubert 	}
23362b15cb3dSCy Schubert 	printf("%s\n", resp);
23372b15cb3dSCy Schubert 	free(resp);
23382b15cb3dSCy Schubert }
23392b15cb3dSCy Schubert 
23402b15cb3dSCy Schubert 
23412b15cb3dSCy Schubert /*
23422b15cb3dSCy Schubert  * config_from_file - remotely configure an ntpd daemon using the
23432b15cb3dSCy Schubert  * specified configuration file
23442b15cb3dSCy Schubert  * SK: This function is a kludge at best and is full of bad design
23452b15cb3dSCy Schubert  * bugs:
23462b15cb3dSCy Schubert  * 1. ntpq uses UDP, which means that there is no guarantee of in-order,
23472b15cb3dSCy Schubert  *    error-free delivery.
23482b15cb3dSCy Schubert  * 2. The maximum length of a packet is constrained, and as a result, the
23492b15cb3dSCy Schubert  *    maximum length of a line in a configuration file is constrained.
23502b15cb3dSCy Schubert  *    Longer lines will lead to unpredictable results.
23512b15cb3dSCy Schubert  * 3. Since this function is sending a line at a time, we can't update
23522b15cb3dSCy Schubert  *    the control key through the configuration file (YUCK!!)
23534990d495SXin LI  *
23544990d495SXin LI  * Pearly: There are a few places where 'size_t' is cast to 'int' based
23554990d495SXin LI  * on the assumption that 'int' can hold the size of the involved
23564990d495SXin LI  * buffers without overflow.
23572b15cb3dSCy Schubert  */
23582b15cb3dSCy Schubert static void
23592b15cb3dSCy Schubert config_from_file (
23602b15cb3dSCy Schubert 	struct parse *pcmd,
23612b15cb3dSCy Schubert 	FILE *fp
23622b15cb3dSCy Schubert 	)
23632b15cb3dSCy Schubert {
23642b15cb3dSCy Schubert 	u_short rstatus;
23653311ff84SXin LI 	size_t rsize;
23662b15cb3dSCy Schubert 	const char *rdata;
23674990d495SXin LI 	char * cp;
23682b15cb3dSCy Schubert 	int res;
23692b15cb3dSCy Schubert 	FILE *config_fd;
23702b15cb3dSCy Schubert 	char config_cmd[MAXLINE];
23712b15cb3dSCy Schubert 	size_t config_len;
23722b15cb3dSCy Schubert 	int i;
23732b15cb3dSCy Schubert 	int retry_limit;
23742b15cb3dSCy Schubert 
23752b15cb3dSCy Schubert 	if (debug > 2)
23762d4e511cSCy Schubert 		xprintf(stderr,
23772b15cb3dSCy Schubert 			"In Config\n"
23782b15cb3dSCy Schubert 			"Keyword = %s\n"
23792b15cb3dSCy Schubert 			"Filename = %s\n", pcmd->keyword,
23802b15cb3dSCy Schubert 			pcmd->argval[0].string);
23812b15cb3dSCy Schubert 
23822b15cb3dSCy Schubert 	config_fd = fopen(pcmd->argval[0].string, "r");
23832b15cb3dSCy Schubert 	if (NULL == config_fd) {
23842b15cb3dSCy Schubert 		printf("ERROR!! Couldn't open file: %s\n",
23852b15cb3dSCy Schubert 		       pcmd->argval[0].string);
23862b15cb3dSCy Schubert 		return;
23872b15cb3dSCy Schubert 	}
23882b15cb3dSCy Schubert 
23892b15cb3dSCy Schubert 	printf("Sending configuration file, one line at a time.\n");
23902b15cb3dSCy Schubert 	i = 0;
23912b15cb3dSCy Schubert 	while (fgets(config_cmd, MAXLINE, config_fd) != NULL) {
23924990d495SXin LI 		/* Eliminate comments first. */
23934990d495SXin LI 		cp = strchr(config_cmd, '#');
23944990d495SXin LI 		config_len = (NULL != cp)
23954990d495SXin LI 		    ? (size_t)(cp - config_cmd)
23964990d495SXin LI 		    : strlen(config_cmd);
23974990d495SXin LI 
23984990d495SXin LI 		/* [Bug 3015] make sure there's no trailing whitespace;
23994990d495SXin LI 		 * the fix for [Bug 2853] on the server side forbids
24004990d495SXin LI 		 * those. And don't transmit empty lines, as this would
24014990d495SXin LI 		 * just be waste.
24024990d495SXin LI 		 */
24034990d495SXin LI 		while (config_len != 0 &&
24044990d495SXin LI 		       (u_char)config_cmd[config_len-1] <= ' ')
24054990d495SXin LI 			--config_len;
24064990d495SXin LI 		config_cmd[config_len] = '\0';
24074990d495SXin LI 
24082b15cb3dSCy Schubert 		++i;
24094990d495SXin LI 		if (0 == config_len)
24104990d495SXin LI 			continue;
24114990d495SXin LI 
24122b15cb3dSCy Schubert 		retry_limit = 2;
24132b15cb3dSCy Schubert 		do
24142b15cb3dSCy Schubert 			res = doquery(CTL_OP_CONFIGURE, 0, 1,
24154990d495SXin LI 				      config_len, config_cmd,
24162b15cb3dSCy Schubert 				      &rstatus, &rsize, &rdata);
24172b15cb3dSCy Schubert 		while (res != 0 && retry_limit--);
24182b15cb3dSCy Schubert 		if (res != 0) {
24194990d495SXin LI 			printf("Line No: %d query failed: %.*s\n"
24204990d495SXin LI 			       "Subsequent lines not sent.\n",
24214990d495SXin LI 			       i, (int)config_len, config_cmd);
24222b15cb3dSCy Schubert 			fclose(config_fd);
24232b15cb3dSCy Schubert 			return;
24242b15cb3dSCy Schubert 		}
24252b15cb3dSCy Schubert 
24264990d495SXin LI 		/* Right-strip the result code string, then output the
24274990d495SXin LI 		 * last line executed, with result code. */
24284990d495SXin LI 		while (rsize != 0 && (u_char)rdata[rsize - 1] <= ' ')
24294990d495SXin LI 			--rsize;
24304990d495SXin LI 		printf("Line No: %d %.*s: %.*s\n", i,
24314990d495SXin LI 		       (int)rsize, rdata,
24324990d495SXin LI 		       (int)config_len, config_cmd);
24332b15cb3dSCy Schubert 	}
24342b15cb3dSCy Schubert 	printf("Done sending file\n");
24352b15cb3dSCy Schubert 	fclose(config_fd);
24362b15cb3dSCy Schubert }
24372b15cb3dSCy Schubert 
24382b15cb3dSCy Schubert 
24392b15cb3dSCy Schubert static int
24402b15cb3dSCy Schubert fetch_nonce(
24412b15cb3dSCy Schubert 	char *	nonce,
24422b15cb3dSCy Schubert 	size_t	cb_nonce
24432b15cb3dSCy Schubert 	)
24442b15cb3dSCy Schubert {
24452b15cb3dSCy Schubert 	const char	nonce_eq[] = "nonce=";
24462b15cb3dSCy Schubert 	int		qres;
24472b15cb3dSCy Schubert 	u_short		rstatus;
24483311ff84SXin LI 	size_t		rsize;
24492b15cb3dSCy Schubert 	const char *	rdata;
24503311ff84SXin LI 	size_t		chars;
24512b15cb3dSCy Schubert 
24522b15cb3dSCy Schubert 	/*
24532b15cb3dSCy Schubert 	 * Retrieve a nonce specific to this client to demonstrate to
24542b15cb3dSCy Schubert 	 * ntpd that we're capable of receiving responses to our source
24552b15cb3dSCy Schubert 	 * IP address, and thereby unlikely to be forging the source.
24562b15cb3dSCy Schubert 	 */
24572b15cb3dSCy Schubert 	qres = doquery(CTL_OP_REQ_NONCE, 0, 0, 0, NULL, &rstatus,
24582b15cb3dSCy Schubert 		       &rsize, &rdata);
24592b15cb3dSCy Schubert 	if (qres) {
24602d4e511cSCy Schubert 		xprintf(stderr, "nonce request failed\n");
24612b15cb3dSCy Schubert 		return FALSE;
24622b15cb3dSCy Schubert 	}
24632b15cb3dSCy Schubert 
2464*f5f40dd6SCy Schubert 	if (rsize <= sizeof(nonce_eq) - 1 ||
24652b15cb3dSCy Schubert 	    strncmp(rdata, nonce_eq, sizeof(nonce_eq) - 1)) {
24662d4e511cSCy Schubert 		xprintf(stderr, "unexpected nonce response format: %.*s\n",
24673311ff84SXin LI 			(int)rsize, rdata); /* cast is wobbly */
24682b15cb3dSCy Schubert 		return FALSE;
24692b15cb3dSCy Schubert 	}
24702b15cb3dSCy Schubert 	chars = rsize - (sizeof(nonce_eq) - 1);
24714e1ef62aSXin LI 	if (chars >= cb_nonce)
24722b15cb3dSCy Schubert 		return FALSE;
24732b15cb3dSCy Schubert 	memcpy(nonce, rdata + sizeof(nonce_eq) - 1, chars);
24742b15cb3dSCy Schubert 	nonce[chars] = '\0';
24752b15cb3dSCy Schubert 	while (chars > 0 &&
24762b15cb3dSCy Schubert 	       ('\r' == nonce[chars - 1] || '\n' == nonce[chars - 1])) {
24772b15cb3dSCy Schubert 		chars--;
24782b15cb3dSCy Schubert 		nonce[chars] = '\0';
24792b15cb3dSCy Schubert 	}
24802b15cb3dSCy Schubert 
24812b15cb3dSCy Schubert 	return TRUE;
24822b15cb3dSCy Schubert }
24832b15cb3dSCy Schubert 
24842b15cb3dSCy Schubert 
24852b15cb3dSCy Schubert /*
24862b15cb3dSCy Schubert  * add_mru	Add and entry to mru list, hash table, and allocate
24872b15cb3dSCy Schubert  *		and return a replacement.
24882b15cb3dSCy Schubert  *		This is a helper for collect_mru_list().
24892b15cb3dSCy Schubert  */
24902b15cb3dSCy Schubert static mru *
24912b15cb3dSCy Schubert add_mru(
24922b15cb3dSCy Schubert 	mru *add
24932b15cb3dSCy Schubert 	)
24942b15cb3dSCy Schubert {
24952b15cb3dSCy Schubert 	u_short hash;
24962b15cb3dSCy Schubert 	mru *mon;
24972b15cb3dSCy Schubert 	mru *unlinked;
24982b15cb3dSCy Schubert 
24992b15cb3dSCy Schubert 
25002b15cb3dSCy Schubert 	hash = NTP_HASH_ADDR(&add->addr);
25012b15cb3dSCy Schubert 	/* see if we have it among previously received entries */
25022b15cb3dSCy Schubert 	for (mon = hash_table[hash]; mon != NULL; mon = mon->hlink)
25032b15cb3dSCy Schubert 		if (SOCK_EQ(&mon->addr, &add->addr))
25042b15cb3dSCy Schubert 			break;
25052b15cb3dSCy Schubert 	if (mon != NULL) {
25062b15cb3dSCy Schubert 		if (!L_ISGEQ(&add->first, &mon->first)) {
25072d4e511cSCy Schubert 			xprintf(stderr,
25082b15cb3dSCy Schubert 				"add_mru duplicate %s new first ts %08x.%08x precedes prior %08x.%08x\n",
25092b15cb3dSCy Schubert 				sptoa(&add->addr), add->last.l_ui,
25102b15cb3dSCy Schubert 				add->last.l_uf, mon->last.l_ui,
25112b15cb3dSCy Schubert 				mon->last.l_uf);
25122b15cb3dSCy Schubert 			exit(1);
25132b15cb3dSCy Schubert 		}
25142b15cb3dSCy Schubert 		UNLINK_DLIST(mon, mlink);
25152b15cb3dSCy Schubert 		UNLINK_SLIST(unlinked, hash_table[hash], mon, hlink, mru);
25169034852cSGleb Smirnoff 		INSIST(unlinked == mon);
25172b15cb3dSCy Schubert 		mru_dupes++;
25182b15cb3dSCy Schubert 		TRACE(2, ("(updated from %08x.%08x) ", mon->last.l_ui,
25192b15cb3dSCy Schubert 		      mon->last.l_uf));
25202b15cb3dSCy Schubert 	}
25212b15cb3dSCy Schubert 	LINK_DLIST(mru_list, add, mlink);
25222b15cb3dSCy Schubert 	LINK_SLIST(hash_table[hash], add, hlink);
25232b15cb3dSCy Schubert 	TRACE(2, ("add_mru %08x.%08x c %d m %d v %d rest %x first %08x.%08x %s\n",
25242b15cb3dSCy Schubert 	      add->last.l_ui, add->last.l_uf, add->count,
25252b15cb3dSCy Schubert 	      (int)add->mode, (int)add->ver, (u_int)add->rs,
25262b15cb3dSCy Schubert 	      add->first.l_ui, add->first.l_uf, sptoa(&add->addr)));
25272b15cb3dSCy Schubert 	/* if we didn't update an existing entry, alloc replacement */
25282b15cb3dSCy Schubert 	if (NULL == mon) {
25292b15cb3dSCy Schubert 		mon = emalloc(sizeof(*mon));
25302b15cb3dSCy Schubert 		mru_count++;
25312b15cb3dSCy Schubert 	}
25322b15cb3dSCy Schubert 	ZERO(*mon);
25332b15cb3dSCy Schubert 
25342b15cb3dSCy Schubert 	return mon;
25352b15cb3dSCy Schubert }
25362b15cb3dSCy Schubert 
25372b15cb3dSCy Schubert 
25382b15cb3dSCy Schubert /* MGOT macro is specific to collect_mru_list() */
25392b15cb3dSCy Schubert #define MGOT(bit)				\
25402b15cb3dSCy Schubert 	do {					\
25412b15cb3dSCy Schubert 		got |= (bit);			\
25422b15cb3dSCy Schubert 		if (MRU_GOT_ALL == got) {	\
25432b15cb3dSCy Schubert 			got = 0;		\
25442b15cb3dSCy Schubert 			mon = add_mru(mon);	\
25452b15cb3dSCy Schubert 			ci++;			\
25462b15cb3dSCy Schubert 		}				\
25472b15cb3dSCy Schubert 	} while (0)
25482b15cb3dSCy Schubert 
25492b15cb3dSCy Schubert 
25503311ff84SXin LI int
25512b15cb3dSCy Schubert mrulist_ctrl_c_hook(void)
25522b15cb3dSCy Schubert {
25532b15cb3dSCy Schubert 	mrulist_interrupted = TRUE;
25543311ff84SXin LI 	return TRUE;
25552b15cb3dSCy Schubert }
25562b15cb3dSCy Schubert 
25572b15cb3dSCy Schubert 
25582b15cb3dSCy Schubert static int
25592b15cb3dSCy Schubert collect_mru_list(
25602b15cb3dSCy Schubert 	const char *	parms,
25612b15cb3dSCy Schubert 	l_fp *		pnow
25622b15cb3dSCy Schubert 	)
25632b15cb3dSCy Schubert {
25642b15cb3dSCy Schubert 	const u_int sleep_msecs = 5;
25652b15cb3dSCy Schubert 	static int ntpd_row_limit = MRU_ROW_LIMIT;
25662b15cb3dSCy Schubert 	int c_mru_l_rc;		/* this function's return code */
25672b15cb3dSCy Schubert 	u_char got;		/* MRU_GOT_* bits */
25682b15cb3dSCy Schubert 	time_t next_report;
25692b15cb3dSCy Schubert 	size_t cb;
25702b15cb3dSCy Schubert 	mru *mon;
25712b15cb3dSCy Schubert 	mru *head;
25722b15cb3dSCy Schubert 	mru *recent;
25732b15cb3dSCy Schubert 	int list_complete;
25742b15cb3dSCy Schubert 	char nonce[128];
25752b15cb3dSCy Schubert 	char buf[128];
25762b15cb3dSCy Schubert 	char req_buf[CTL_MAX_DATA_LEN];
25772b15cb3dSCy Schubert 	char *req;
25782b15cb3dSCy Schubert 	char *req_end;
25793311ff84SXin LI 	size_t chars;
25802b15cb3dSCy Schubert 	int qres;
25812b15cb3dSCy Schubert 	u_short rstatus;
25823311ff84SXin LI 	size_t rsize;
25832b15cb3dSCy Schubert 	const char *rdata;
25842b15cb3dSCy Schubert 	int limit;
25852b15cb3dSCy Schubert 	int frags;
25862b15cb3dSCy Schubert 	int cap_frags;
25872b15cb3dSCy Schubert 	char *tag;
25882b15cb3dSCy Schubert 	char *val;
25892b15cb3dSCy Schubert 	int si;		/* server index in response */
25902b15cb3dSCy Schubert 	int ci;		/* client (our) index for validation */
25912b15cb3dSCy Schubert 	int ri;		/* request index (.# suffix) */
25922b15cb3dSCy Schubert 	int mv;
25932b15cb3dSCy Schubert 	l_fp newest;
25942b15cb3dSCy Schubert 	l_fp last_older;
25952b15cb3dSCy Schubert 	sockaddr_u addr_older;
25962b15cb3dSCy Schubert 	int have_now;
25972b15cb3dSCy Schubert 	int have_addr_older;
25982b15cb3dSCy Schubert 	int have_last_older;
25992b15cb3dSCy Schubert 	u_int restarted_count;
26002b15cb3dSCy Schubert 	u_int nonce_uses;
26012b15cb3dSCy Schubert 	u_short hash;
26022b15cb3dSCy Schubert 	mru *unlinked;
26032b15cb3dSCy Schubert 
26042b15cb3dSCy Schubert 	if (!fetch_nonce(nonce, sizeof(nonce)))
26052b15cb3dSCy Schubert 		return FALSE;
26062b15cb3dSCy Schubert 
26072b15cb3dSCy Schubert 	nonce_uses = 0;
26082b15cb3dSCy Schubert 	restarted_count = 0;
26092b15cb3dSCy Schubert 	mru_count = 0;
26102b15cb3dSCy Schubert 	INIT_DLIST(mru_list, mlink);
26112b15cb3dSCy Schubert 	cb = NTP_HASH_SIZE * sizeof(*hash_table);
26129034852cSGleb Smirnoff 	INSIST(NULL == hash_table);
26132b15cb3dSCy Schubert 	hash_table = emalloc_zero(cb);
26142b15cb3dSCy Schubert 
26152b15cb3dSCy Schubert 	c_mru_l_rc = FALSE;
26162b15cb3dSCy Schubert 	list_complete = FALSE;
26172b15cb3dSCy Schubert 	have_now = FALSE;
26182b15cb3dSCy Schubert 	cap_frags = TRUE;
26192b15cb3dSCy Schubert 	got = 0;
26202b15cb3dSCy Schubert 	ri = 0;
26212b15cb3dSCy Schubert 	cb = sizeof(*mon);
26222b15cb3dSCy Schubert 	mon = emalloc_zero(cb);
26232b15cb3dSCy Schubert 	ZERO(*pnow);
26242b15cb3dSCy Schubert 	ZERO(last_older);
26252b15cb3dSCy Schubert 	next_report = time(NULL) + MRU_REPORT_SECS;
26262b15cb3dSCy Schubert 
26272b15cb3dSCy Schubert 	limit = min(3 * MAXFRAGS, ntpd_row_limit);
26282b15cb3dSCy Schubert 	frags = MAXFRAGS;
26292b15cb3dSCy Schubert 	snprintf(req_buf, sizeof(req_buf), "nonce=%s, frags=%d%s",
26302b15cb3dSCy Schubert 		 nonce, frags, parms);
26312b15cb3dSCy Schubert 	nonce_uses++;
26322b15cb3dSCy Schubert 
26332b15cb3dSCy Schubert 	while (TRUE) {
26342b15cb3dSCy Schubert 		if (debug)
26352d4e511cSCy Schubert 			xprintf(stderr, "READ_MRU parms: %s\n", req_buf);
26362b15cb3dSCy Schubert 
26373311ff84SXin LI 		qres = doqueryex(CTL_OP_READ_MRU, 0, 0,
26383311ff84SXin LI 				 strlen(req_buf), req_buf,
26393311ff84SXin LI 				 &rstatus, &rsize, &rdata, TRUE);
26402b15cb3dSCy Schubert 
26412b15cb3dSCy Schubert 		if (CERR_UNKNOWNVAR == qres && ri > 0) {
26422b15cb3dSCy Schubert 			/*
26432b15cb3dSCy Schubert 			 * None of the supplied prior entries match, so
26442b15cb3dSCy Schubert 			 * toss them from our list and try again.
26452b15cb3dSCy Schubert 			 */
26462b15cb3dSCy Schubert 			if (debug)
26472d4e511cSCy Schubert 				xprintf(stderr,
26482b15cb3dSCy Schubert 					"no overlap between %d prior entries and server MRU list\n",
26492b15cb3dSCy Schubert 					ri);
26502b15cb3dSCy Schubert 			while (ri--) {
26512b15cb3dSCy Schubert 				recent = HEAD_DLIST(mru_list, mlink);
26529034852cSGleb Smirnoff 				INSIST(recent != NULL);
26532b15cb3dSCy Schubert 				if (debug)
26542d4e511cSCy Schubert 					xprintf(stderr,
26552b15cb3dSCy Schubert 						"tossing prior entry %s to resync\n",
26562b15cb3dSCy Schubert 						sptoa(&recent->addr));
26572b15cb3dSCy Schubert 				UNLINK_DLIST(recent, mlink);
26582b15cb3dSCy Schubert 				hash = NTP_HASH_ADDR(&recent->addr);
26592b15cb3dSCy Schubert 				UNLINK_SLIST(unlinked, hash_table[hash],
26602b15cb3dSCy Schubert 					     recent, hlink, mru);
26619034852cSGleb Smirnoff 				INSIST(unlinked == recent);
26622b15cb3dSCy Schubert 				free(recent);
26632b15cb3dSCy Schubert 				mru_count--;
26642b15cb3dSCy Schubert 			}
26652b15cb3dSCy Schubert 			if (NULL == HEAD_DLIST(mru_list, mlink)) {
26662b15cb3dSCy Schubert 				restarted_count++;
26672b15cb3dSCy Schubert 				if (restarted_count > 8) {
26682d4e511cSCy Schubert 					xprintf(stderr,
26692b15cb3dSCy Schubert 						"Giving up after 8 restarts from the beginning.\n"
26702b15cb3dSCy Schubert 						"With high-traffic NTP servers, this can occur if the\n"
26712b15cb3dSCy Schubert 						"MRU list is limited to less than about 16 seconds' of\n"
26722b15cb3dSCy Schubert 						"entries.  See the 'mru' ntp.conf directive to adjust.\n");
26732b15cb3dSCy Schubert 					goto cleanup_return;
26742b15cb3dSCy Schubert 				}
26752b15cb3dSCy Schubert 				if (debug)
26762d4e511cSCy Schubert 					xprintf(stderr,
26772b15cb3dSCy Schubert 						"--->   Restarting from the beginning, retry #%u\n",
26782b15cb3dSCy Schubert 						restarted_count);
26792b15cb3dSCy Schubert 			}
26802b15cb3dSCy Schubert 		} else if (CERR_UNKNOWNVAR == qres) {
26812d4e511cSCy Schubert 			xprintf(stderr,
26822b15cb3dSCy Schubert 				"CERR_UNKNOWNVAR from ntpd but no priors given.\n");
26832b15cb3dSCy Schubert 			goto cleanup_return;
26842b15cb3dSCy Schubert 		} else if (CERR_BADVALUE == qres) {
26852b15cb3dSCy Schubert 			if (cap_frags) {
26862b15cb3dSCy Schubert 				cap_frags = FALSE;
26872b15cb3dSCy Schubert 				if (debug)
26882d4e511cSCy Schubert 					xprintf(stderr,
26892b15cb3dSCy Schubert 						"Reverted to row limit from fragments limit.\n");
26902b15cb3dSCy Schubert 			} else {
26912b15cb3dSCy Schubert 				/* ntpd has lower cap on row limit */
26922b15cb3dSCy Schubert 				ntpd_row_limit--;
26932b15cb3dSCy Schubert 				limit = min(limit, ntpd_row_limit);
26942b15cb3dSCy Schubert 				if (debug)
26952d4e511cSCy Schubert 					xprintf(stderr,
26962b15cb3dSCy Schubert 						"Row limit reduced to %d following CERR_BADVALUE.\n",
26972b15cb3dSCy Schubert 						limit);
26982b15cb3dSCy Schubert 			}
26992b15cb3dSCy Schubert 		} else if (ERR_INCOMPLETE == qres ||
27002b15cb3dSCy Schubert 			   ERR_TIMEOUT == qres) {
27012b15cb3dSCy Schubert 			/*
27022b15cb3dSCy Schubert 			 * Reduce the number of rows/frags requested by
27032b15cb3dSCy Schubert 			 * half to recover from lost response fragments.
27042b15cb3dSCy Schubert 			 */
27052b15cb3dSCy Schubert 			if (cap_frags) {
27062b15cb3dSCy Schubert 				frags = max(2, frags / 2);
27072b15cb3dSCy Schubert 				if (debug)
27082d4e511cSCy Schubert 					xprintf(stderr,
27092b15cb3dSCy Schubert 						"Frag limit reduced to %d following incomplete response.\n",
27102b15cb3dSCy Schubert 						frags);
27112b15cb3dSCy Schubert 			} else {
27122b15cb3dSCy Schubert 				limit = max(2, limit / 2);
27132b15cb3dSCy Schubert 				if (debug)
27142d4e511cSCy Schubert 					xprintf(stderr,
27152b15cb3dSCy Schubert 						"Row limit reduced to %d following incomplete response.\n",
27162b15cb3dSCy Schubert 						limit);
27172b15cb3dSCy Schubert 			}
27182b15cb3dSCy Schubert 		} else if (qres) {
27192b15cb3dSCy Schubert 			show_error_msg(qres, 0);
27202b15cb3dSCy Schubert 			goto cleanup_return;
27212b15cb3dSCy Schubert 		}
27222b15cb3dSCy Schubert 		/*
27232b15cb3dSCy Schubert 		 * This is a cheap cop-out implementation of rawmode
27242b15cb3dSCy Schubert 		 * output for mrulist.  A better approach would be to
27252b15cb3dSCy Schubert 		 * dump similar output after the list is collected by
27262b15cb3dSCy Schubert 		 * ntpq with a continuous sequence of indexes.  This
27272b15cb3dSCy Schubert 		 * cheap approach has indexes resetting to zero for
27282b15cb3dSCy Schubert 		 * each query/response, and duplicates are not
27292b15cb3dSCy Schubert 		 * coalesced.
27302b15cb3dSCy Schubert 		 */
27312b15cb3dSCy Schubert 		if (!qres && rawmode)
27322b15cb3dSCy Schubert 			printvars(rsize, rdata, rstatus, TYPE_SYS, 1, stdout);
27332b15cb3dSCy Schubert 		ci = 0;
27342b15cb3dSCy Schubert 		have_addr_older = FALSE;
27352b15cb3dSCy Schubert 		have_last_older = FALSE;
27362b15cb3dSCy Schubert 		while (!qres && nextvar(&rsize, &rdata, &tag, &val)) {
27374e1ef62aSXin LI 			INSIST(tag && val);
27382b15cb3dSCy Schubert 			if (debug > 1)
27392d4e511cSCy Schubert 				xprintf(stderr, "nextvar gave: %s = %s\n",
27402b15cb3dSCy Schubert 					tag, val);
27412b15cb3dSCy Schubert 			switch(tag[0]) {
27422b15cb3dSCy Schubert 
27432b15cb3dSCy Schubert 			case 'a':
27442b15cb3dSCy Schubert 				if (!strcmp(tag, "addr.older")) {
27452b15cb3dSCy Schubert 					if (!have_last_older) {
27462d4e511cSCy Schubert 						xprintf(stderr,
27472b15cb3dSCy Schubert 							"addr.older %s before last.older\n",
27482b15cb3dSCy Schubert 							val);
27492b15cb3dSCy Schubert 						goto cleanup_return;
27502b15cb3dSCy Schubert 					}
27512b15cb3dSCy Schubert 					if (!decodenetnum(val, &addr_older)) {
27522d4e511cSCy Schubert 						xprintf(stderr,
27532b15cb3dSCy Schubert 							"addr.older %s garbled\n",
27542b15cb3dSCy Schubert 							val);
27552b15cb3dSCy Schubert 						goto cleanup_return;
27562b15cb3dSCy Schubert 					}
27572b15cb3dSCy Schubert 					hash = NTP_HASH_ADDR(&addr_older);
27582b15cb3dSCy Schubert 					for (recent = hash_table[hash];
27592b15cb3dSCy Schubert 					     recent != NULL;
27602b15cb3dSCy Schubert 					     recent = recent->hlink)
27612b15cb3dSCy Schubert 						if (ADDR_PORT_EQ(
27622b15cb3dSCy Schubert 						      &addr_older,
27632b15cb3dSCy Schubert 						      &recent->addr))
27642b15cb3dSCy Schubert 							break;
27652b15cb3dSCy Schubert 					if (NULL == recent) {
27662d4e511cSCy Schubert 						xprintf(stderr,
27672b15cb3dSCy Schubert 							"addr.older %s not in hash table\n",
27682b15cb3dSCy Schubert 							val);
27692b15cb3dSCy Schubert 						goto cleanup_return;
27702b15cb3dSCy Schubert 					}
27712b15cb3dSCy Schubert 					if (!L_ISEQU(&last_older,
27722b15cb3dSCy Schubert 						     &recent->last)) {
27732d4e511cSCy Schubert 						xprintf(stderr,
27742b15cb3dSCy Schubert 							"last.older %08x.%08x mismatches %08x.%08x expected.\n",
27752b15cb3dSCy Schubert 							last_older.l_ui,
27762b15cb3dSCy Schubert 							last_older.l_uf,
27772b15cb3dSCy Schubert 							recent->last.l_ui,
27782b15cb3dSCy Schubert 							recent->last.l_uf);
27792b15cb3dSCy Schubert 						goto cleanup_return;
27802b15cb3dSCy Schubert 					}
27812b15cb3dSCy Schubert 					have_addr_older = TRUE;
27822b15cb3dSCy Schubert 				} else if (1 != sscanf(tag, "addr.%d", &si)
27832b15cb3dSCy Schubert 					   || si != ci)
27842b15cb3dSCy Schubert 					goto nomatch;
27852b15cb3dSCy Schubert 				else if (decodenetnum(val, &mon->addr))
27862b15cb3dSCy Schubert 					MGOT(MRU_GOT_ADDR);
27872b15cb3dSCy Schubert 				break;
27882b15cb3dSCy Schubert 
27892b15cb3dSCy Schubert 			case 'l':
27902b15cb3dSCy Schubert 				if (!strcmp(tag, "last.older")) {
27912b15cb3dSCy Schubert 					if ('0' != val[0] ||
27922b15cb3dSCy Schubert 					    'x' != val[1] ||
27932b15cb3dSCy Schubert 					    !hextolfp(val + 2, &last_older)) {
27942d4e511cSCy Schubert 						xprintf(stderr,
27952b15cb3dSCy Schubert 							"last.older %s garbled\n",
27962b15cb3dSCy Schubert 							val);
27972b15cb3dSCy Schubert 						goto cleanup_return;
27982b15cb3dSCy Schubert 					}
27992b15cb3dSCy Schubert 					have_last_older = TRUE;
28002b15cb3dSCy Schubert 				} else if (!strcmp(tag, "last.newest")) {
28012b15cb3dSCy Schubert 					if (0 != got) {
28022d4e511cSCy Schubert 						xprintf(stderr,
28032b15cb3dSCy Schubert 							"last.newest %s before complete row, got = 0x%x\n",
28042b15cb3dSCy Schubert 							val, (u_int)got);
28052b15cb3dSCy Schubert 						goto cleanup_return;
28062b15cb3dSCy Schubert 					}
28072b15cb3dSCy Schubert 					if (!have_now) {
28082d4e511cSCy Schubert 						xprintf(stderr,
28092b15cb3dSCy Schubert 							"last.newest %s before now=\n",
28102b15cb3dSCy Schubert 							val);
28112b15cb3dSCy Schubert 						goto cleanup_return;
28122b15cb3dSCy Schubert 					}
28132b15cb3dSCy Schubert 					head = HEAD_DLIST(mru_list, mlink);
28142b15cb3dSCy Schubert 					if (NULL != head) {
28152b15cb3dSCy Schubert 						if ('0' != val[0] ||
28162b15cb3dSCy Schubert 						    'x' != val[1] ||
28172b15cb3dSCy Schubert 						    !hextolfp(val + 2, &newest) ||
28182b15cb3dSCy Schubert 						    !L_ISEQU(&newest,
28192b15cb3dSCy Schubert 							     &head->last)) {
28202d4e511cSCy Schubert 							xprintf(stderr,
28212b15cb3dSCy Schubert 								"last.newest %s mismatches %08x.%08x",
28222b15cb3dSCy Schubert 								val,
28232b15cb3dSCy Schubert 								head->last.l_ui,
28242b15cb3dSCy Schubert 								head->last.l_uf);
28252b15cb3dSCy Schubert 							goto cleanup_return;
28262b15cb3dSCy Schubert 						}
28272b15cb3dSCy Schubert 					}
28282b15cb3dSCy Schubert 					list_complete = TRUE;
28292b15cb3dSCy Schubert 				} else if (1 != sscanf(tag, "last.%d", &si) ||
28302b15cb3dSCy Schubert 					   si != ci || '0' != val[0] ||
28312b15cb3dSCy Schubert 					   'x' != val[1] ||
28322b15cb3dSCy Schubert 					   !hextolfp(val + 2, &mon->last)) {
28332b15cb3dSCy Schubert 					goto nomatch;
28342b15cb3dSCy Schubert 				} else {
28352b15cb3dSCy Schubert 					MGOT(MRU_GOT_LAST);
28362b15cb3dSCy Schubert 					/*
28372b15cb3dSCy Schubert 					 * allow interrupted retrieval,
28382b15cb3dSCy Schubert 					 * using most recent retrieved
28392b15cb3dSCy Schubert 					 * entry's last seen timestamp
28402b15cb3dSCy Schubert 					 * as the end of operation.
28412b15cb3dSCy Schubert 					 */
28422b15cb3dSCy Schubert 					*pnow = mon->last;
28432b15cb3dSCy Schubert 				}
28442b15cb3dSCy Schubert 				break;
28452b15cb3dSCy Schubert 
28462b15cb3dSCy Schubert 			case 'f':
28472b15cb3dSCy Schubert 				if (1 != sscanf(tag, "first.%d", &si) ||
28482b15cb3dSCy Schubert 				    si != ci || '0' != val[0] ||
28492b15cb3dSCy Schubert 				    'x' != val[1] ||
28502b15cb3dSCy Schubert 				    !hextolfp(val + 2, &mon->first))
28512b15cb3dSCy Schubert 					goto nomatch;
28522b15cb3dSCy Schubert 				MGOT(MRU_GOT_FIRST);
28532b15cb3dSCy Schubert 				break;
28542b15cb3dSCy Schubert 
28552b15cb3dSCy Schubert 			case 'n':
28562b15cb3dSCy Schubert 				if (!strcmp(tag, "nonce")) {
28572b15cb3dSCy Schubert 					strlcpy(nonce, val, sizeof(nonce));
28582b15cb3dSCy Schubert 					nonce_uses = 0;
28592b15cb3dSCy Schubert 					break; /* case */
28602b15cb3dSCy Schubert 				} else if (strcmp(tag, "now") ||
28612b15cb3dSCy Schubert 					   '0' != val[0] ||
28622b15cb3dSCy Schubert 					   'x' != val[1] ||
28632b15cb3dSCy Schubert 					    !hextolfp(val + 2, pnow))
28642b15cb3dSCy Schubert 					goto nomatch;
28652b15cb3dSCy Schubert 				have_now = TRUE;
28662b15cb3dSCy Schubert 				break;
28672b15cb3dSCy Schubert 
28682b15cb3dSCy Schubert 			case 'c':
28692b15cb3dSCy Schubert 				if (1 != sscanf(tag, "ct.%d", &si) ||
28702b15cb3dSCy Schubert 				    si != ci ||
28712b15cb3dSCy Schubert 				    1 != sscanf(val, "%d", &mon->count)
28722b15cb3dSCy Schubert 				    || mon->count < 1)
28732b15cb3dSCy Schubert 					goto nomatch;
28742b15cb3dSCy Schubert 				MGOT(MRU_GOT_COUNT);
28752b15cb3dSCy Schubert 				break;
28762b15cb3dSCy Schubert 
28772b15cb3dSCy Schubert 			case 'm':
28782b15cb3dSCy Schubert 				if (1 != sscanf(tag, "mv.%d", &si) ||
28792b15cb3dSCy Schubert 				    si != ci ||
28802b15cb3dSCy Schubert 				    1 != sscanf(val, "%d", &mv))
28812b15cb3dSCy Schubert 					goto nomatch;
28822b15cb3dSCy Schubert 				mon->mode = PKT_MODE(mv);
28832b15cb3dSCy Schubert 				mon->ver = PKT_VERSION(mv);
28842b15cb3dSCy Schubert 				MGOT(MRU_GOT_MV);
28852b15cb3dSCy Schubert 				break;
28862b15cb3dSCy Schubert 
28872b15cb3dSCy Schubert 			case 'r':
28882b15cb3dSCy Schubert 				if (1 != sscanf(tag, "rs.%d", &si) ||
28892b15cb3dSCy Schubert 				    si != ci ||
28902b15cb3dSCy Schubert 				    1 != sscanf(val, "0x%hx", &mon->rs))
28912b15cb3dSCy Schubert 					goto nomatch;
28922b15cb3dSCy Schubert 				MGOT(MRU_GOT_RS);
28932b15cb3dSCy Schubert 				break;
28942b15cb3dSCy Schubert 
28952b15cb3dSCy Schubert 			default:
28962b15cb3dSCy Schubert 			nomatch:
28972b15cb3dSCy Schubert 				/* empty stmt */ ;
28982b15cb3dSCy Schubert 				/* ignore unknown tags */
28992b15cb3dSCy Schubert 			}
29002b15cb3dSCy Schubert 		}
29012b15cb3dSCy Schubert 		if (have_now)
29022b15cb3dSCy Schubert 			list_complete = TRUE;
29032b15cb3dSCy Schubert 		if (list_complete) {
29049034852cSGleb Smirnoff 			INSIST(0 == ri || have_addr_older);
29052b15cb3dSCy Schubert 		}
29062b15cb3dSCy Schubert 		if (mrulist_interrupted) {
29072b15cb3dSCy Schubert 			printf("mrulist retrieval interrupted by operator.\n"
29082b15cb3dSCy Schubert 			       "Displaying partial client list.\n");
29092b15cb3dSCy Schubert 			fflush(stdout);
29102b15cb3dSCy Schubert 		}
29112b15cb3dSCy Schubert 		if (list_complete || mrulist_interrupted) {
29122d4e511cSCy Schubert 			xprintf(stderr,
29132b15cb3dSCy Schubert 				"\rRetrieved %u unique MRU entries and %u updates.\n",
29142b15cb3dSCy Schubert 				mru_count, mru_dupes);
29152b15cb3dSCy Schubert 			fflush(stderr);
29162b15cb3dSCy Schubert 			break;
29172b15cb3dSCy Schubert 		}
29182b15cb3dSCy Schubert 		if (time(NULL) >= next_report) {
29192b15cb3dSCy Schubert 			next_report += MRU_REPORT_SECS;
29202d4e511cSCy Schubert 			xprintf(stderr, "\r%u (%u updates) ", mru_count,
29212b15cb3dSCy Schubert 				mru_dupes);
29222b15cb3dSCy Schubert 			fflush(stderr);
29232b15cb3dSCy Schubert 		}
29242b15cb3dSCy Schubert 
29252b15cb3dSCy Schubert 		/*
29262b15cb3dSCy Schubert 		 * Snooze for a bit between queries to let ntpd catch
29272b15cb3dSCy Schubert 		 * up with other duties.
29282b15cb3dSCy Schubert 		 */
29292b15cb3dSCy Schubert #ifdef SYS_WINNT
29302b15cb3dSCy Schubert 		Sleep(sleep_msecs);
29312b15cb3dSCy Schubert #elif !defined(HAVE_NANOSLEEP)
29322b15cb3dSCy Schubert 		sleep((sleep_msecs / 1000) + 1);
29332b15cb3dSCy Schubert #else
29342b15cb3dSCy Schubert 		{
29352b15cb3dSCy Schubert 			struct timespec interv = { 0,
29362b15cb3dSCy Schubert 						   1000 * sleep_msecs };
29372b15cb3dSCy Schubert 			nanosleep(&interv, NULL);
29382b15cb3dSCy Schubert 		}
29392b15cb3dSCy Schubert #endif
29402b15cb3dSCy Schubert 		/*
29412b15cb3dSCy Schubert 		 * If there were no errors, increase the number of rows
29422b15cb3dSCy Schubert 		 * to a maximum of 3 * MAXFRAGS (the most packets ntpq
29432b15cb3dSCy Schubert 		 * can handle in one response), on the assumption that
29442b15cb3dSCy Schubert 		 * no less than 3 rows fit in each packet, capped at
29452b15cb3dSCy Schubert 		 * our best guess at the server's row limit.
29462b15cb3dSCy Schubert 		 */
29472b15cb3dSCy Schubert 		if (!qres) {
29482b15cb3dSCy Schubert 			if (cap_frags) {
29492b15cb3dSCy Schubert 				frags = min(MAXFRAGS, frags + 1);
29502b15cb3dSCy Schubert 			} else {
29512b15cb3dSCy Schubert 				limit = min3(3 * MAXFRAGS,
29522b15cb3dSCy Schubert 					     ntpd_row_limit,
29532b15cb3dSCy Schubert 					     max(limit + 1,
29542b15cb3dSCy Schubert 					         limit * 33 / 32));
29552b15cb3dSCy Schubert 			}
29562b15cb3dSCy Schubert 		}
29572b15cb3dSCy Schubert 		/*
29582b15cb3dSCy Schubert 		 * prepare next query with as many address and last-seen
29592b15cb3dSCy Schubert 		 * timestamps as will fit in a single packet.
29602b15cb3dSCy Schubert 		 */
29612b15cb3dSCy Schubert 		req = req_buf;
29622b15cb3dSCy Schubert 		req_end = req_buf + sizeof(req_buf);
29632b15cb3dSCy Schubert #define REQ_ROOM	(req_end - req)
29642b15cb3dSCy Schubert 		snprintf(req, REQ_ROOM, "nonce=%s, %s=%d%s", nonce,
29652b15cb3dSCy Schubert 			 (cap_frags)
29662b15cb3dSCy Schubert 			     ? "frags"
29672b15cb3dSCy Schubert 			     : "limit",
29682b15cb3dSCy Schubert 			 (cap_frags)
29692b15cb3dSCy Schubert 			     ? frags
29702b15cb3dSCy Schubert 			     : limit,
29712b15cb3dSCy Schubert 			 parms);
29722b15cb3dSCy Schubert 		req += strlen(req);
29732b15cb3dSCy Schubert 		nonce_uses++;
29742b15cb3dSCy Schubert 		if (nonce_uses >= 4) {
29752b15cb3dSCy Schubert 			if (!fetch_nonce(nonce, sizeof(nonce)))
29762b15cb3dSCy Schubert 				goto cleanup_return;
29772b15cb3dSCy Schubert 			nonce_uses = 0;
29782b15cb3dSCy Schubert 		}
29792b15cb3dSCy Schubert 
29802b15cb3dSCy Schubert 
29812b15cb3dSCy Schubert 		for (ri = 0, recent = HEAD_DLIST(mru_list, mlink);
29822b15cb3dSCy Schubert 		     recent != NULL;
29832b15cb3dSCy Schubert 		     ri++, recent = NEXT_DLIST(mru_list, recent, mlink)) {
29842b15cb3dSCy Schubert 
29852b15cb3dSCy Schubert 			snprintf(buf, sizeof(buf),
29862b15cb3dSCy Schubert 				 ", addr.%d=%s, last.%d=0x%08x.%08x",
29872b15cb3dSCy Schubert 				 ri, sptoa(&recent->addr), ri,
29882b15cb3dSCy Schubert 				 recent->last.l_ui, recent->last.l_uf);
29892b15cb3dSCy Schubert 			chars = strlen(buf);
299068ba7e87SXin LI 			if ((size_t)REQ_ROOM <= chars)
29912b15cb3dSCy Schubert 				break;
29922b15cb3dSCy Schubert 			memcpy(req, buf, chars + 1);
29932b15cb3dSCy Schubert 			req += chars;
29942b15cb3dSCy Schubert 		}
29952b15cb3dSCy Schubert 	}
29962b15cb3dSCy Schubert 
29972b15cb3dSCy Schubert 	c_mru_l_rc = TRUE;
29982b15cb3dSCy Schubert 	goto retain_hash_table;
29992b15cb3dSCy Schubert 
30002b15cb3dSCy Schubert cleanup_return:
30012b15cb3dSCy Schubert 	free(hash_table);
30022b15cb3dSCy Schubert 	hash_table = NULL;
30032b15cb3dSCy Schubert 
30042b15cb3dSCy Schubert retain_hash_table:
30052b15cb3dSCy Schubert 	if (mon != NULL)
30062b15cb3dSCy Schubert 		free(mon);
30072b15cb3dSCy Schubert 
30082b15cb3dSCy Schubert 	return c_mru_l_rc;
30092b15cb3dSCy Schubert }
30102b15cb3dSCy Schubert 
30112b15cb3dSCy Schubert 
30122b15cb3dSCy Schubert /*
30132b15cb3dSCy Schubert  * qcmp_mru_addr - sort MRU entries by remote address.
30142b15cb3dSCy Schubert  *
30152b15cb3dSCy Schubert  * All IPv4 addresses sort before any IPv6, addresses are sorted by
30162b15cb3dSCy Schubert  * value within address family.
30172b15cb3dSCy Schubert  */
30182b15cb3dSCy Schubert static int
30192b15cb3dSCy Schubert qcmp_mru_addr(
30202b15cb3dSCy Schubert 	const void *v1,
30212b15cb3dSCy Schubert 	const void *v2
30222b15cb3dSCy Schubert 	)
30232b15cb3dSCy Schubert {
30242b15cb3dSCy Schubert 	const mru * const *	ppm1 = v1;
30252b15cb3dSCy Schubert 	const mru * const *	ppm2 = v2;
30262b15cb3dSCy Schubert 	const mru *		pm1;
30272b15cb3dSCy Schubert 	const mru *		pm2;
30282b15cb3dSCy Schubert 	u_short			af1;
30292b15cb3dSCy Schubert 	u_short			af2;
30302b15cb3dSCy Schubert 	size_t			cmplen;
30312b15cb3dSCy Schubert 	size_t			addr_off;
30322b15cb3dSCy Schubert 
30332b15cb3dSCy Schubert 	pm1 = *ppm1;
30342b15cb3dSCy Schubert 	pm2 = *ppm2;
30352b15cb3dSCy Schubert 
30362b15cb3dSCy Schubert 	af1 = AF(&pm1->addr);
30372b15cb3dSCy Schubert 	af2 = AF(&pm2->addr);
30382b15cb3dSCy Schubert 
30392b15cb3dSCy Schubert 	if (af1 != af2)
30402b15cb3dSCy Schubert 		return (AF_INET == af1)
30412b15cb3dSCy Schubert 			   ? -1
30422b15cb3dSCy Schubert 			   : 1;
30432b15cb3dSCy Schubert 
30442b15cb3dSCy Schubert 	cmplen = SIZEOF_INADDR(af1);
30452b15cb3dSCy Schubert 	addr_off = (AF_INET == af1)
30462b15cb3dSCy Schubert 		      ? offsetof(struct sockaddr_in, sin_addr)
30472b15cb3dSCy Schubert 		      : offsetof(struct sockaddr_in6, sin6_addr);
30482b15cb3dSCy Schubert 
30492b15cb3dSCy Schubert 	return memcmp((const char *)&pm1->addr + addr_off,
30502b15cb3dSCy Schubert 		      (const char *)&pm2->addr + addr_off,
30512b15cb3dSCy Schubert 		      cmplen);
30522b15cb3dSCy Schubert }
30532b15cb3dSCy Schubert 
30542b15cb3dSCy Schubert 
30552b15cb3dSCy Schubert static int
30562b15cb3dSCy Schubert qcmp_mru_r_addr(
30572b15cb3dSCy Schubert 	const void *v1,
30582b15cb3dSCy Schubert 	const void *v2
30592b15cb3dSCy Schubert 	)
30602b15cb3dSCy Schubert {
30612b15cb3dSCy Schubert 	return -qcmp_mru_addr(v1, v2);
30622b15cb3dSCy Schubert }
30632b15cb3dSCy Schubert 
30642b15cb3dSCy Schubert 
30652b15cb3dSCy Schubert /*
30662b15cb3dSCy Schubert  * qcmp_mru_count - sort MRU entries by times seen (hit count).
30672b15cb3dSCy Schubert  */
30682b15cb3dSCy Schubert static int
30692b15cb3dSCy Schubert qcmp_mru_count(
30702b15cb3dSCy Schubert 	const void *v1,
30712b15cb3dSCy Schubert 	const void *v2
30722b15cb3dSCy Schubert 	)
30732b15cb3dSCy Schubert {
30742b15cb3dSCy Schubert 	const mru * const *	ppm1 = v1;
30752b15cb3dSCy Schubert 	const mru * const *	ppm2 = v2;
30762b15cb3dSCy Schubert 	const mru *		pm1;
30772b15cb3dSCy Schubert 	const mru *		pm2;
30782b15cb3dSCy Schubert 
30792b15cb3dSCy Schubert 	pm1 = *ppm1;
30802b15cb3dSCy Schubert 	pm2 = *ppm2;
30812b15cb3dSCy Schubert 
30822b15cb3dSCy Schubert 	return (pm1->count < pm2->count)
30832b15cb3dSCy Schubert 		   ? -1
30842b15cb3dSCy Schubert 		   : ((pm1->count == pm2->count)
30852b15cb3dSCy Schubert 			  ? 0
30862b15cb3dSCy Schubert 			  : 1);
30872b15cb3dSCy Schubert }
30882b15cb3dSCy Schubert 
30892b15cb3dSCy Schubert 
30902b15cb3dSCy Schubert static int
30912b15cb3dSCy Schubert qcmp_mru_r_count(
30922b15cb3dSCy Schubert 	const void *v1,
30932b15cb3dSCy Schubert 	const void *v2
30942b15cb3dSCy Schubert 	)
30952b15cb3dSCy Schubert {
30962b15cb3dSCy Schubert 	return -qcmp_mru_count(v1, v2);
30972b15cb3dSCy Schubert }
30982b15cb3dSCy Schubert 
30992b15cb3dSCy Schubert 
31002b15cb3dSCy Schubert /*
31012b15cb3dSCy Schubert  * qcmp_mru_avgint - sort MRU entries by average interval.
31022b15cb3dSCy Schubert  */
31032b15cb3dSCy Schubert static int
31042b15cb3dSCy Schubert qcmp_mru_avgint(
31052b15cb3dSCy Schubert 	const void *v1,
31062b15cb3dSCy Schubert 	const void *v2
31072b15cb3dSCy Schubert 	)
31082b15cb3dSCy Schubert {
31092b15cb3dSCy Schubert 	const mru * const *	ppm1 = v1;
31102b15cb3dSCy Schubert 	const mru * const *	ppm2 = v2;
31112b15cb3dSCy Schubert 	const mru *		pm1;
31122b15cb3dSCy Schubert 	const mru *		pm2;
31132b15cb3dSCy Schubert 	l_fp			interval;
31142b15cb3dSCy Schubert 	double			avg1;
31152b15cb3dSCy Schubert 	double			avg2;
31162b15cb3dSCy Schubert 
31172b15cb3dSCy Schubert 	pm1 = *ppm1;
31182b15cb3dSCy Schubert 	pm2 = *ppm2;
31192b15cb3dSCy Schubert 
31202b15cb3dSCy Schubert 	interval = pm1->last;
31212b15cb3dSCy Schubert 	L_SUB(&interval, &pm1->first);
31222b15cb3dSCy Schubert 	LFPTOD(&interval, avg1);
31232b15cb3dSCy Schubert 	avg1 /= pm1->count;
31242b15cb3dSCy Schubert 
31252b15cb3dSCy Schubert 	interval = pm2->last;
31262b15cb3dSCy Schubert 	L_SUB(&interval, &pm2->first);
31272b15cb3dSCy Schubert 	LFPTOD(&interval, avg2);
31282b15cb3dSCy Schubert 	avg2 /= pm2->count;
31292b15cb3dSCy Schubert 
31302b15cb3dSCy Schubert 	if (avg1 < avg2)
31312b15cb3dSCy Schubert 		return -1;
31322b15cb3dSCy Schubert 	else if (avg1 > avg2)
31332b15cb3dSCy Schubert 		return 1;
31342b15cb3dSCy Schubert 
31352b15cb3dSCy Schubert 	/* secondary sort on lstint - rarely tested */
31362b15cb3dSCy Schubert 	if (L_ISEQU(&pm1->last, &pm2->last))
31372b15cb3dSCy Schubert 		return 0;
31382b15cb3dSCy Schubert 	else if (L_ISGEQ(&pm1->last, &pm2->last))
31392b15cb3dSCy Schubert 		return -1;
31402b15cb3dSCy Schubert 	else
31412b15cb3dSCy Schubert 		return 1;
31422b15cb3dSCy Schubert }
31432b15cb3dSCy Schubert 
31442b15cb3dSCy Schubert 
31452b15cb3dSCy Schubert static int
31462b15cb3dSCy Schubert qcmp_mru_r_avgint(
31472b15cb3dSCy Schubert 	const void *v1,
31482b15cb3dSCy Schubert 	const void *v2
31492b15cb3dSCy Schubert 	)
31502b15cb3dSCy Schubert {
31512b15cb3dSCy Schubert 	return -qcmp_mru_avgint(v1, v2);
31522b15cb3dSCy Schubert }
31532b15cb3dSCy Schubert 
31542b15cb3dSCy Schubert 
31552b15cb3dSCy Schubert /*
31562b15cb3dSCy Schubert  * mrulist - ntpq's mrulist command to fetch an arbitrarily large Most
31572b15cb3dSCy Schubert  *	     Recently Used (seen) remote address list from ntpd.
31582b15cb3dSCy Schubert  *
31592b15cb3dSCy Schubert  * Similar to ntpdc's monlist command, but not limited to a single
31602b15cb3dSCy Schubert  * request/response, and thereby not limited to a few hundred remote
31612b15cb3dSCy Schubert  * addresses.
31622b15cb3dSCy Schubert  *
31632b15cb3dSCy Schubert  * See ntpd/ntp_control.c read_mru_list() for comments on the way
31642b15cb3dSCy Schubert  * CTL_OP_READ_MRU is designed to be used.
31652b15cb3dSCy Schubert  *
31662b15cb3dSCy Schubert  * mrulist intentionally differs from monlist in the way the avgint
31672b15cb3dSCy Schubert  * column is calculated.  monlist includes the time after the last
31682b15cb3dSCy Schubert  * packet from the client until the monlist query time in the average,
31692b15cb3dSCy Schubert  * while mrulist excludes it.  That is, monlist's average interval grows
31702b15cb3dSCy Schubert  * over time for remote addresses not heard from in some time, while it
31712b15cb3dSCy Schubert  * remains unchanged in mrulist.  This also affects the avgint value for
31722b15cb3dSCy Schubert  * entries representing a single packet, with identical first and last
31732b15cb3dSCy Schubert  * timestamps.  mrulist shows 0 avgint, monlist shows a value identical
31742b15cb3dSCy Schubert  * to lstint.
31752b15cb3dSCy Schubert  */
31762b15cb3dSCy Schubert static void
31772b15cb3dSCy Schubert mrulist(
31782b15cb3dSCy Schubert 	struct parse *	pcmd,
31792b15cb3dSCy Schubert 	FILE *		fp
31802b15cb3dSCy Schubert 	)
31812b15cb3dSCy Schubert {
31822b15cb3dSCy Schubert 	const char mincount_eq[] =	"mincount=";
31832b15cb3dSCy Schubert 	const char resall_eq[] =	"resall=";
31842b15cb3dSCy Schubert 	const char resany_eq[] =	"resany=";
31852b15cb3dSCy Schubert 	const char maxlstint_eq[] =	"maxlstint=";
31862b15cb3dSCy Schubert 	const char laddr_eq[] =		"laddr=";
31872b15cb3dSCy Schubert 	const char sort_eq[] =		"sort=";
31882b15cb3dSCy Schubert 	mru_sort_order order;
31892b15cb3dSCy Schubert 	size_t n;
31902b15cb3dSCy Schubert 	char parms_buf[128];
31912b15cb3dSCy Schubert 	char buf[24];
31922b15cb3dSCy Schubert 	char *parms;
31932b15cb3dSCy Schubert 	const char *arg;
31942b15cb3dSCy Schubert 	size_t cb;
31952b15cb3dSCy Schubert 	mru **sorted;
31962b15cb3dSCy Schubert 	mru **ppentry;
31972b15cb3dSCy Schubert 	mru *recent;
31982b15cb3dSCy Schubert 	l_fp now;
31992b15cb3dSCy Schubert 	l_fp interval;
32002b15cb3dSCy Schubert 	double favgint;
32012b15cb3dSCy Schubert 	double flstint;
32022b15cb3dSCy Schubert 	int avgint;
32032b15cb3dSCy Schubert 	int lstint;
32042b15cb3dSCy Schubert 	size_t i;
32052b15cb3dSCy Schubert 
32063311ff84SXin LI 	mrulist_interrupted = FALSE;
32073311ff84SXin LI 	push_ctrl_c_handler(&mrulist_ctrl_c_hook);
32082d4e511cSCy Schubert 	xprintf(stderr,
32093311ff84SXin LI 		"Ctrl-C will stop MRU retrieval and display partial results.\n");
32103311ff84SXin LI 	fflush(stderr);
32113311ff84SXin LI 
32122b15cb3dSCy Schubert 	order = MRUSORT_DEF;
32132b15cb3dSCy Schubert 	parms_buf[0] = '\0';
32142b15cb3dSCy Schubert 	parms = parms_buf;
32152b15cb3dSCy Schubert 	for (i = 0; i < pcmd->nargs; i++) {
32162b15cb3dSCy Schubert 		arg = pcmd->argval[i].string;
32172b15cb3dSCy Schubert 		if (arg != NULL) {
32182b15cb3dSCy Schubert 			cb = strlen(arg) + 1;
32192b15cb3dSCy Schubert 			if ((!strncmp(resall_eq, arg, sizeof(resall_eq)
32202b15cb3dSCy Schubert 			    - 1) || !strncmp(resany_eq, arg,
32212b15cb3dSCy Schubert 			    sizeof(resany_eq) - 1) || !strncmp(
32222b15cb3dSCy Schubert 			    mincount_eq, arg, sizeof(mincount_eq) - 1)
32232b15cb3dSCy Schubert 			    || !strncmp(laddr_eq, arg, sizeof(laddr_eq)
32242b15cb3dSCy Schubert 			    - 1) || !strncmp(maxlstint_eq, arg,
32252b15cb3dSCy Schubert 			    sizeof(laddr_eq) - 1)) && parms + cb + 2 <=
32262b15cb3dSCy Schubert 			    parms_buf + sizeof(parms_buf)) {
32272b15cb3dSCy Schubert 				/* these are passed intact to ntpd */
32282b15cb3dSCy Schubert 				memcpy(parms, ", ", 2);
32292b15cb3dSCy Schubert 				parms += 2;
32302b15cb3dSCy Schubert 				memcpy(parms, arg, cb);
32312b15cb3dSCy Schubert 				parms += cb - 1;
32322b15cb3dSCy Schubert 			} else if (!strncmp(sort_eq, arg,
32332b15cb3dSCy Schubert 					    sizeof(sort_eq) - 1)) {
32342b15cb3dSCy Schubert 				arg += sizeof(sort_eq) - 1;
32352b15cb3dSCy Schubert 				for (n = 0;
32362b15cb3dSCy Schubert 				     n < COUNTOF(mru_sort_keywords);
32372b15cb3dSCy Schubert 				     n++)
32382b15cb3dSCy Schubert 					if (!strcmp(mru_sort_keywords[n],
32392b15cb3dSCy Schubert 						    arg))
32402b15cb3dSCy Schubert 						break;
32412b15cb3dSCy Schubert 				if (n < COUNTOF(mru_sort_keywords))
32422b15cb3dSCy Schubert 					order = n;
32432b15cb3dSCy Schubert 			} else if (!strcmp("limited", arg) ||
32442b15cb3dSCy Schubert 				   !strcmp("kod", arg)) {
32452b15cb3dSCy Schubert 				/* transform to resany=... */
32462b15cb3dSCy Schubert 				snprintf(buf, sizeof(buf),
32472b15cb3dSCy Schubert 					 ", resany=0x%x",
32482b15cb3dSCy Schubert 					 ('k' == arg[0])
32492b15cb3dSCy Schubert 					     ? RES_KOD
32502b15cb3dSCy Schubert 					     : RES_LIMITED);
32512b15cb3dSCy Schubert 				cb = 1 + strlen(buf);
32522b15cb3dSCy Schubert 				if (parms + cb <
32532b15cb3dSCy Schubert 					parms_buf + sizeof(parms_buf)) {
32542b15cb3dSCy Schubert 					memcpy(parms, buf, cb);
32552b15cb3dSCy Schubert 					parms += cb - 1;
32562b15cb3dSCy Schubert 				}
32572b15cb3dSCy Schubert 			} else
32582d4e511cSCy Schubert 				xprintf(stderr,
32592b15cb3dSCy Schubert 					"ignoring unrecognized mrulist parameter: %s\n",
32602b15cb3dSCy Schubert 					arg);
32612b15cb3dSCy Schubert 		}
32622b15cb3dSCy Schubert 	}
32632b15cb3dSCy Schubert 	parms = parms_buf;
32642b15cb3dSCy Schubert 
32652b15cb3dSCy Schubert 	if (!collect_mru_list(parms, &now))
32662b15cb3dSCy Schubert 		return;
32672b15cb3dSCy Schubert 
32682b15cb3dSCy Schubert 	/* display the results */
32692b15cb3dSCy Schubert 	if (rawmode)
32702b15cb3dSCy Schubert 		goto cleanup_return;
32712b15cb3dSCy Schubert 
32722b15cb3dSCy Schubert 	/* construct an array of entry pointers in default order */
3273276da39aSCy Schubert 	sorted = eallocarray(mru_count, sizeof(*sorted));
32742b15cb3dSCy Schubert 	ppentry = sorted;
32752b15cb3dSCy Schubert 	if (MRUSORT_R_DEF != order) {
32762b15cb3dSCy Schubert 		ITER_DLIST_BEGIN(mru_list, recent, mlink, mru)
32779034852cSGleb Smirnoff 			INSIST(ppentry < sorted + mru_count);
32782b15cb3dSCy Schubert 			*ppentry = recent;
32792b15cb3dSCy Schubert 			ppentry++;
32802b15cb3dSCy Schubert 		ITER_DLIST_END()
32812b15cb3dSCy Schubert 	} else {
32822b15cb3dSCy Schubert 		REV_ITER_DLIST_BEGIN(mru_list, recent, mlink, mru)
32839034852cSGleb Smirnoff 			INSIST(ppentry < sorted + mru_count);
32842b15cb3dSCy Schubert 			*ppentry = recent;
32852b15cb3dSCy Schubert 			ppentry++;
32862b15cb3dSCy Schubert 		REV_ITER_DLIST_END()
32872b15cb3dSCy Schubert 	}
32882b15cb3dSCy Schubert 
32892b15cb3dSCy Schubert 	if (ppentry - sorted != (int)mru_count) {
32902d4e511cSCy Schubert 		xprintf(stderr,
32912b15cb3dSCy Schubert 			"mru_count %u should match MRU list depth %ld.\n",
32922b15cb3dSCy Schubert 			mru_count, (long)(ppentry - sorted));
32932b15cb3dSCy Schubert 		free(sorted);
32942b15cb3dSCy Schubert 		goto cleanup_return;
32952b15cb3dSCy Schubert 	}
32962b15cb3dSCy Schubert 
32972b15cb3dSCy Schubert 	/* re-sort sorted[] if not default or reverse default */
32982b15cb3dSCy Schubert 	if (MRUSORT_R_DEF < order)
32992b15cb3dSCy Schubert 		qsort(sorted, mru_count, sizeof(sorted[0]),
33002b15cb3dSCy Schubert 		      mru_qcmp_table[order]);
33012b15cb3dSCy Schubert 
330268ba7e87SXin LI 	mrulist_interrupted = FALSE;
33032b15cb3dSCy Schubert 	printf(	"lstint avgint rstr r m v  count rport remote address\n"
33042b15cb3dSCy Schubert 		"==============================================================================\n");
33052b15cb3dSCy Schubert 		/* '=' x 78 */
33062b15cb3dSCy Schubert 	for (ppentry = sorted; ppentry < sorted + mru_count; ppentry++) {
33072b15cb3dSCy Schubert 		recent = *ppentry;
33082b15cb3dSCy Schubert 		interval = now;
33092b15cb3dSCy Schubert 		L_SUB(&interval, &recent->last);
33102b15cb3dSCy Schubert 		LFPTOD(&interval, flstint);
33112b15cb3dSCy Schubert 		lstint = (int)(flstint + 0.5);
33122b15cb3dSCy Schubert 		interval = recent->last;
33132b15cb3dSCy Schubert 		L_SUB(&interval, &recent->first);
33142b15cb3dSCy Schubert 		LFPTOD(&interval, favgint);
33152b15cb3dSCy Schubert 		favgint /= recent->count;
33162b15cb3dSCy Schubert 		avgint = (int)(favgint + 0.5);
33172d4e511cSCy Schubert 		xprintf(fp, "%6d %6d %4hx %c %d %d %6d %5u %s\n",
33182b15cb3dSCy Schubert 			lstint, avgint, recent->rs,
33192b15cb3dSCy Schubert 			(RES_KOD & recent->rs)
33202b15cb3dSCy Schubert 			    ? 'K'
33212b15cb3dSCy Schubert 			    : (RES_LIMITED & recent->rs)
33222b15cb3dSCy Schubert 				  ? 'L'
33232b15cb3dSCy Schubert 				  : '.',
33242b15cb3dSCy Schubert 			(int)recent->mode, (int)recent->ver,
33252b15cb3dSCy Schubert 			recent->count, SRCPORT(&recent->addr),
33262b15cb3dSCy Schubert 			nntohost(&recent->addr));
33272b15cb3dSCy Schubert 		if (showhostnames)
33282b15cb3dSCy Schubert 			fflush(fp);
332968ba7e87SXin LI 		if (mrulist_interrupted) {
33302d4e511cSCy Schubert 			xputs("\n --interrupted--\n", fp);
333168ba7e87SXin LI 			fflush(fp);
333268ba7e87SXin LI 			break;
333368ba7e87SXin LI 		}
33342b15cb3dSCy Schubert 	}
33352b15cb3dSCy Schubert 	fflush(fp);
33362b15cb3dSCy Schubert 	if (debug) {
33372d4e511cSCy Schubert 		xprintf(stderr,
33382b15cb3dSCy Schubert 			"--- completed, freeing sorted[] pointers\n");
33392b15cb3dSCy Schubert 		fflush(stderr);
33402b15cb3dSCy Schubert 	}
33412b15cb3dSCy Schubert 	free(sorted);
33422b15cb3dSCy Schubert 
33432b15cb3dSCy Schubert cleanup_return:
33442b15cb3dSCy Schubert 	if (debug) {
33452d4e511cSCy Schubert 		xprintf(stderr, "... freeing MRU entries\n");
33462b15cb3dSCy Schubert 		fflush(stderr);
33472b15cb3dSCy Schubert 	}
33482b15cb3dSCy Schubert 	ITER_DLIST_BEGIN(mru_list, recent, mlink, mru)
33492b15cb3dSCy Schubert 		free(recent);
33502b15cb3dSCy Schubert 	ITER_DLIST_END()
33512b15cb3dSCy Schubert 	if (debug) {
33522d4e511cSCy Schubert 		xprintf(stderr, "... freeing hash_table[]\n");
33532b15cb3dSCy Schubert 		fflush(stderr);
33542b15cb3dSCy Schubert 	}
33552b15cb3dSCy Schubert 	free(hash_table);
33562b15cb3dSCy Schubert 	hash_table = NULL;
33572b15cb3dSCy Schubert 	INIT_DLIST(mru_list, mlink);
33583311ff84SXin LI 
33593311ff84SXin LI 	pop_ctrl_c_handler(&mrulist_ctrl_c_hook);
33602b15cb3dSCy Schubert }
33612b15cb3dSCy Schubert 
33622b15cb3dSCy Schubert 
33632b15cb3dSCy Schubert /*
33642b15cb3dSCy Schubert  * validate_ifnum - helper for ifstats()
33652b15cb3dSCy Schubert  *
33662b15cb3dSCy Schubert  * Ensures rows are received in order and complete.
33672b15cb3dSCy Schubert  */
33682b15cb3dSCy Schubert static void
33692b15cb3dSCy Schubert validate_ifnum(
33702b15cb3dSCy Schubert 	FILE *		fp,
33712b15cb3dSCy Schubert 	u_int		ifnum,
33722b15cb3dSCy Schubert 	int *		pfields,
33732b15cb3dSCy Schubert 	ifstats_row *	prow
33742b15cb3dSCy Schubert 	)
33752b15cb3dSCy Schubert {
33762b15cb3dSCy Schubert 	if (prow->ifnum == ifnum)
33772b15cb3dSCy Schubert 		return;
3378276da39aSCy Schubert 	if (prow->ifnum + 1 <= ifnum) {
33792b15cb3dSCy Schubert 		if (*pfields < IFSTATS_FIELDS)
33802d4e511cSCy Schubert 			xprintf(fp, "Warning: incomplete row with %d (of %d) fields\n",
33812b15cb3dSCy Schubert 				*pfields, IFSTATS_FIELDS);
33822b15cb3dSCy Schubert 		*pfields = 0;
33832b15cb3dSCy Schubert 		prow->ifnum = ifnum;
33842b15cb3dSCy Schubert 		return;
33852b15cb3dSCy Schubert 	}
33862d4e511cSCy Schubert 	xprintf(stderr,
33872b15cb3dSCy Schubert 		"received if index %u, have %d of %d fields for index %u, aborting.\n",
33882b15cb3dSCy Schubert 		ifnum, *pfields, IFSTATS_FIELDS, prow->ifnum);
33892b15cb3dSCy Schubert 	exit(1);
33902b15cb3dSCy Schubert }
33912b15cb3dSCy Schubert 
33922b15cb3dSCy Schubert 
33932b15cb3dSCy Schubert /*
33942b15cb3dSCy Schubert  * another_ifstats_field - helper for ifstats()
33952b15cb3dSCy Schubert  *
33962b15cb3dSCy Schubert  * If all fields for the row have been received, print it.
33972b15cb3dSCy Schubert  */
33982b15cb3dSCy Schubert static void
33992b15cb3dSCy Schubert another_ifstats_field(
34002b15cb3dSCy Schubert 	int *		pfields,
34012b15cb3dSCy Schubert 	ifstats_row *	prow,
34022b15cb3dSCy Schubert 	FILE *		fp
34032b15cb3dSCy Schubert 	)
34042b15cb3dSCy Schubert {
34052b15cb3dSCy Schubert 	u_int ifnum;
34062b15cb3dSCy Schubert 
34072b15cb3dSCy Schubert 	(*pfields)++;
34082b15cb3dSCy Schubert 	/* we understand 12 tags */
34092b15cb3dSCy Schubert 	if (IFSTATS_FIELDS > *pfields)
34102b15cb3dSCy Schubert 		return;
34112b15cb3dSCy Schubert 	/*
34122b15cb3dSCy Schubert 	"    interface name                                        send\n"
34132b15cb3dSCy Schubert 	" #  address/broadcast     drop flag ttl mc received sent failed peers   uptime\n"
34142b15cb3dSCy Schubert 	"==============================================================================\n");
34152b15cb3dSCy Schubert 	 */
34162d4e511cSCy Schubert 	xprintf(fp,
341709100258SXin LI 		"%3u %-24.24s %c %4x %3u %2u %6u %6u %6u %5u %8d\n"
34182b15cb3dSCy Schubert 		"    %s\n",
34192b15cb3dSCy Schubert 		prow->ifnum, prow->name,
34202b15cb3dSCy Schubert 		(prow->enabled)
34212b15cb3dSCy Schubert 		    ? '.'
34222b15cb3dSCy Schubert 		    : 'D',
34232b15cb3dSCy Schubert 		prow->flags, prow->ttl, prow->mcast_count,
34242b15cb3dSCy Schubert 		prow->received, prow->sent, prow->send_errors,
34252b15cb3dSCy Schubert 		prow->peer_count, prow->uptime, sptoa(&prow->addr));
34262b15cb3dSCy Schubert 	if (!SOCK_UNSPEC(&prow->bcast))
34272d4e511cSCy Schubert 		xprintf(fp, "    %s\n", sptoa(&prow->bcast));
34282b15cb3dSCy Schubert 	ifnum = prow->ifnum;
34292b15cb3dSCy Schubert 	ZERO(*prow);
34302b15cb3dSCy Schubert 	prow->ifnum = ifnum;
34312b15cb3dSCy Schubert }
34322b15cb3dSCy Schubert 
34332b15cb3dSCy Schubert 
34342b15cb3dSCy Schubert /*
34352b15cb3dSCy Schubert  * ifstats - ntpq -c ifstats modeled on ntpdc -c ifstats.
34362b15cb3dSCy Schubert  */
34372b15cb3dSCy Schubert static void
34382b15cb3dSCy Schubert ifstats(
34392b15cb3dSCy Schubert 	struct parse *	pcmd,
34402b15cb3dSCy Schubert 	FILE *		fp
34412b15cb3dSCy Schubert 	)
34422b15cb3dSCy Schubert {
34432b15cb3dSCy Schubert 	const char	addr_fmt[] =	"addr.%u";
34442b15cb3dSCy Schubert 	const char	bcast_fmt[] =	"bcast.%u";
34452b15cb3dSCy Schubert 	const char	en_fmt[] =	"en.%u";	/* enabled */
34462b15cb3dSCy Schubert 	const char	flags_fmt[] =	"flags.%u";
34472b15cb3dSCy Schubert 	const char	mc_fmt[] =	"mc.%u";	/* mcast count */
34482b15cb3dSCy Schubert 	const char	name_fmt[] =	"name.%u";
34492b15cb3dSCy Schubert 	const char	pc_fmt[] =	"pc.%u";	/* peer count */
34502b15cb3dSCy Schubert 	const char	rx_fmt[] =	"rx.%u";
34512b15cb3dSCy Schubert 	const char	tl_fmt[] =	"tl.%u";	/* ttl */
34522b15cb3dSCy Schubert 	const char	tx_fmt[] =	"tx.%u";
34532b15cb3dSCy Schubert 	const char	txerr_fmt[] =	"txerr.%u";
34542b15cb3dSCy Schubert 	const char	up_fmt[] =	"up.%u";	/* uptime */
34552b15cb3dSCy Schubert 	const char *	datap;
34562b15cb3dSCy Schubert 	int		qres;
34573311ff84SXin LI 	size_t		dsize;
34582b15cb3dSCy Schubert 	u_short		rstatus;
34592b15cb3dSCy Schubert 	char *		tag;
34602b15cb3dSCy Schubert 	char *		val;
34612b15cb3dSCy Schubert 	int		fields;
34622b15cb3dSCy Schubert 	u_int		ui;
34632b15cb3dSCy Schubert 	ifstats_row	row;
34642b15cb3dSCy Schubert 	int		comprende;
34652b15cb3dSCy Schubert 	size_t		len;
34662b15cb3dSCy Schubert 
34672b15cb3dSCy Schubert 	qres = doquery(CTL_OP_READ_ORDLIST_A, 0, TRUE, 0, NULL, &rstatus,
34682b15cb3dSCy Schubert 		       &dsize, &datap);
34692b15cb3dSCy Schubert 	if (qres)	/* message already displayed */
34702b15cb3dSCy Schubert 		return;
34712b15cb3dSCy Schubert 
34722d4e511cSCy Schubert 	xprintf(fp,
34732b15cb3dSCy Schubert 		"    interface name                                        send\n"
34742b15cb3dSCy Schubert 		" #  address/broadcast     drop flag ttl mc received sent failed peers   uptime\n"
34752b15cb3dSCy Schubert 		"==============================================================================\n");
34762b15cb3dSCy Schubert 		/* '=' x 78 */
34772b15cb3dSCy Schubert 
34782b15cb3dSCy Schubert 	ZERO(row);
34792b15cb3dSCy Schubert 	fields = 0;
34802b15cb3dSCy Schubert 	ui = 0;
34812b15cb3dSCy Schubert 	while (nextvar(&dsize, &datap, &tag, &val)) {
34824e1ef62aSXin LI 		INSIST(tag && val);
34832b15cb3dSCy Schubert 		if (debug > 1)
34842d4e511cSCy Schubert 		    xprintf(stderr, "nextvar gave: %s = %s\n", tag, val);
34852b15cb3dSCy Schubert 		comprende = FALSE;
34862b15cb3dSCy Schubert 		switch(tag[0]) {
34872b15cb3dSCy Schubert 
34882b15cb3dSCy Schubert 		case 'a':
34892b15cb3dSCy Schubert 			if (1 == sscanf(tag, addr_fmt, &ui) &&
34902b15cb3dSCy Schubert 			    decodenetnum(val, &row.addr))
34912b15cb3dSCy Schubert 				comprende = TRUE;
34922b15cb3dSCy Schubert 			break;
34932b15cb3dSCy Schubert 
34942b15cb3dSCy Schubert 		case 'b':
34952b15cb3dSCy Schubert 			if (1 == sscanf(tag, bcast_fmt, &ui) &&
34964e1ef62aSXin LI 			    ('\0' == *val ||
34972b15cb3dSCy Schubert 			     decodenetnum(val, &row.bcast)))
34982b15cb3dSCy Schubert 				comprende = TRUE;
34992b15cb3dSCy Schubert 			break;
35002b15cb3dSCy Schubert 
35012b15cb3dSCy Schubert 		case 'e':
35022b15cb3dSCy Schubert 			if (1 == sscanf(tag, en_fmt, &ui) &&
35032b15cb3dSCy Schubert 			    1 == sscanf(val, "%d", &row.enabled))
35042b15cb3dSCy Schubert 				comprende = TRUE;
35052b15cb3dSCy Schubert 			break;
35062b15cb3dSCy Schubert 
35072b15cb3dSCy Schubert 		case 'f':
35082b15cb3dSCy Schubert 			if (1 == sscanf(tag, flags_fmt, &ui) &&
35092b15cb3dSCy Schubert 			    1 == sscanf(val, "0x%x", &row.flags))
35102b15cb3dSCy Schubert 				comprende = TRUE;
35112b15cb3dSCy Schubert 			break;
35122b15cb3dSCy Schubert 
35132b15cb3dSCy Schubert 		case 'm':
35142b15cb3dSCy Schubert 			if (1 == sscanf(tag, mc_fmt, &ui) &&
351509100258SXin LI 			    1 == sscanf(val, "%u", &row.mcast_count))
35162b15cb3dSCy Schubert 				comprende = TRUE;
35172b15cb3dSCy Schubert 			break;
35182b15cb3dSCy Schubert 
35192b15cb3dSCy Schubert 		case 'n':
35202b15cb3dSCy Schubert 			if (1 == sscanf(tag, name_fmt, &ui)) {
35212b15cb3dSCy Schubert 				/* strip quotes */
35222b15cb3dSCy Schubert 				len = strlen(val);
35232b15cb3dSCy Schubert 				if (len >= 2 &&
35242b15cb3dSCy Schubert 				    len - 2 < sizeof(row.name)) {
35252b15cb3dSCy Schubert 					len -= 2;
35262b15cb3dSCy Schubert 					memcpy(row.name, val + 1, len);
35272b15cb3dSCy Schubert 					row.name[len] = '\0';
35282b15cb3dSCy Schubert 					comprende = TRUE;
35292b15cb3dSCy Schubert 				}
35302b15cb3dSCy Schubert 			}
35312b15cb3dSCy Schubert 			break;
35322b15cb3dSCy Schubert 
35332b15cb3dSCy Schubert 		case 'p':
35342b15cb3dSCy Schubert 			if (1 == sscanf(tag, pc_fmt, &ui) &&
353509100258SXin LI 			    1 == sscanf(val, "%u", &row.peer_count))
35362b15cb3dSCy Schubert 				comprende = TRUE;
35372b15cb3dSCy Schubert 			break;
35382b15cb3dSCy Schubert 
35392b15cb3dSCy Schubert 		case 'r':
35402b15cb3dSCy Schubert 			if (1 == sscanf(tag, rx_fmt, &ui) &&
354109100258SXin LI 			    1 == sscanf(val, "%u", &row.received))
35422b15cb3dSCy Schubert 				comprende = TRUE;
35432b15cb3dSCy Schubert 			break;
35442b15cb3dSCy Schubert 
35452b15cb3dSCy Schubert 		case 't':
35462b15cb3dSCy Schubert 			if (1 == sscanf(tag, tl_fmt, &ui) &&
354709100258SXin LI 			    1 == sscanf(val, "%u", &row.ttl))
35482b15cb3dSCy Schubert 				comprende = TRUE;
35492b15cb3dSCy Schubert 			else if (1 == sscanf(tag, tx_fmt, &ui) &&
355009100258SXin LI 				 1 == sscanf(val, "%u", &row.sent))
35512b15cb3dSCy Schubert 				comprende = TRUE;
35522b15cb3dSCy Schubert 			else if (1 == sscanf(tag, txerr_fmt, &ui) &&
355309100258SXin LI 				 1 == sscanf(val, "%u", &row.send_errors))
35542b15cb3dSCy Schubert 				comprende = TRUE;
35552b15cb3dSCy Schubert 			break;
35562b15cb3dSCy Schubert 
35572b15cb3dSCy Schubert 		case 'u':
35582b15cb3dSCy Schubert 			if (1 == sscanf(tag, up_fmt, &ui) &&
355909100258SXin LI 			    1 == sscanf(val, "%u", &row.uptime))
35602b15cb3dSCy Schubert 				comprende = TRUE;
35612b15cb3dSCy Schubert 			break;
35622b15cb3dSCy Schubert 		}
35632b15cb3dSCy Schubert 
35642b15cb3dSCy Schubert 		if (comprende) {
35652b15cb3dSCy Schubert 			/* error out if rows out of order */
35662b15cb3dSCy Schubert 			validate_ifnum(fp, ui, &fields, &row);
35672b15cb3dSCy Schubert 			/* if the row is complete, print it */
35682b15cb3dSCy Schubert 			another_ifstats_field(&fields, &row, fp);
35692b15cb3dSCy Schubert 		}
35702b15cb3dSCy Schubert 	}
35712b15cb3dSCy Schubert 	if (fields != IFSTATS_FIELDS)
35722d4e511cSCy Schubert 		xprintf(fp, "Warning: incomplete row with %d (of %d) fields\n",
35732b15cb3dSCy Schubert 			fields, IFSTATS_FIELDS);
35742b15cb3dSCy Schubert 
35752b15cb3dSCy Schubert 	fflush(fp);
35762b15cb3dSCy Schubert }
35772b15cb3dSCy Schubert 
35782b15cb3dSCy Schubert 
35792b15cb3dSCy Schubert /*
35802b15cb3dSCy Schubert  * validate_reslist_idx - helper for reslist()
35812b15cb3dSCy Schubert  *
35822b15cb3dSCy Schubert  * Ensures rows are received in order and complete.
35832b15cb3dSCy Schubert  */
35842b15cb3dSCy Schubert static void
35852b15cb3dSCy Schubert validate_reslist_idx(
35862b15cb3dSCy Schubert 	FILE *		fp,
35872b15cb3dSCy Schubert 	u_int		idx,
35882b15cb3dSCy Schubert 	int *		pfields,
35892b15cb3dSCy Schubert 	reslist_row *	prow
35902b15cb3dSCy Schubert 	)
35912b15cb3dSCy Schubert {
35922b15cb3dSCy Schubert 	if (prow->idx == idx)
35932b15cb3dSCy Schubert 		return;
35942b15cb3dSCy Schubert 	if (prow->idx + 1 == idx) {
35952b15cb3dSCy Schubert 		if (*pfields < RESLIST_FIELDS)
35962d4e511cSCy Schubert 			xprintf(fp, "Warning: incomplete row with %d (of %d) fields",
35972b15cb3dSCy Schubert 				*pfields, RESLIST_FIELDS);
35982b15cb3dSCy Schubert 		*pfields = 0;
35992b15cb3dSCy Schubert 		prow->idx = idx;
36002b15cb3dSCy Schubert 		return;
36012b15cb3dSCy Schubert 	}
36022d4e511cSCy Schubert 	xprintf(stderr,
36032b15cb3dSCy Schubert 		"received reslist index %u, have %d of %d fields for index %u, aborting.\n",
36042b15cb3dSCy Schubert 		idx, *pfields, RESLIST_FIELDS, prow->idx);
36052b15cb3dSCy Schubert 	exit(1);
36062b15cb3dSCy Schubert }
36072b15cb3dSCy Schubert 
36082b15cb3dSCy Schubert 
36092b15cb3dSCy Schubert /*
36102b15cb3dSCy Schubert  * another_reslist_field - helper for reslist()
36112b15cb3dSCy Schubert  *
36122b15cb3dSCy Schubert  * If all fields for the row have been received, print it.
36132b15cb3dSCy Schubert  */
36142b15cb3dSCy Schubert static void
36152b15cb3dSCy Schubert another_reslist_field(
36162b15cb3dSCy Schubert 	int *		pfields,
36172b15cb3dSCy Schubert 	reslist_row *	prow,
36182b15cb3dSCy Schubert 	FILE *		fp
36192b15cb3dSCy Schubert 	)
36202b15cb3dSCy Schubert {
36212b15cb3dSCy Schubert 	char	addrmaskstr[128];
36222b15cb3dSCy Schubert 	int	prefix;	/* subnet mask as prefix bits count */
36232b15cb3dSCy Schubert 	u_int	idx;
36242b15cb3dSCy Schubert 
36252b15cb3dSCy Schubert 	(*pfields)++;
36262b15cb3dSCy Schubert 	/* we understand 4 tags */
36272b15cb3dSCy Schubert 	if (RESLIST_FIELDS > *pfields)
36282b15cb3dSCy Schubert 		return;
36292b15cb3dSCy Schubert 
36302b15cb3dSCy Schubert 	prefix = sockaddr_masktoprefixlen(&prow->mask);
36312b15cb3dSCy Schubert 	if (prefix >= 0)
36322b15cb3dSCy Schubert 		snprintf(addrmaskstr, sizeof(addrmaskstr), "%s/%d",
36332b15cb3dSCy Schubert 			 stoa(&prow->addr), prefix);
36342b15cb3dSCy Schubert 	else
36352b15cb3dSCy Schubert 		snprintf(addrmaskstr, sizeof(addrmaskstr), "%s %s",
36362b15cb3dSCy Schubert 			 stoa(&prow->addr), stoa(&prow->mask));
36372b15cb3dSCy Schubert 
36382b15cb3dSCy Schubert 	/*
36392b15cb3dSCy Schubert 	"   hits    addr/prefix or addr mask\n"
36402b15cb3dSCy Schubert 	"           restrictions\n"
36412b15cb3dSCy Schubert 	"==============================================================================\n");
36422b15cb3dSCy Schubert 	 */
36432d4e511cSCy Schubert 	xprintf(fp,
36442b15cb3dSCy Schubert 		"%10lu %s\n"
36452b15cb3dSCy Schubert 		"           %s\n",
36462b15cb3dSCy Schubert 		prow->hits, addrmaskstr, prow->flagstr);
36472b15cb3dSCy Schubert 	idx = prow->idx;
36482b15cb3dSCy Schubert 	ZERO(*prow);
36492b15cb3dSCy Schubert 	prow->idx = idx;
36502b15cb3dSCy Schubert }
36512b15cb3dSCy Schubert 
36522b15cb3dSCy Schubert 
36532b15cb3dSCy Schubert /*
36542b15cb3dSCy Schubert  * reslist - ntpq -c reslist modeled on ntpdc -c reslist.
36552b15cb3dSCy Schubert  */
36562b15cb3dSCy Schubert static void
36572b15cb3dSCy Schubert reslist(
36582b15cb3dSCy Schubert 	struct parse *	pcmd,
36592b15cb3dSCy Schubert 	FILE *		fp
36602b15cb3dSCy Schubert 	)
36612b15cb3dSCy Schubert {
36622b15cb3dSCy Schubert 	const char addr_fmtu[] =	"addr.%u";
36632b15cb3dSCy Schubert 	const char mask_fmtu[] =	"mask.%u";
36642b15cb3dSCy Schubert 	const char hits_fmt[] =		"hits.%u";
36652b15cb3dSCy Schubert 	const char flags_fmt[] =	"flags.%u";
36662b15cb3dSCy Schubert 	const char qdata[] =		"addr_restrictions";
36672b15cb3dSCy Schubert 	const int qdata_chars =		COUNTOF(qdata) - 1;
36682b15cb3dSCy Schubert 	const char *	datap;
36692b15cb3dSCy Schubert 	int		qres;
36703311ff84SXin LI 	size_t		dsize;
36712b15cb3dSCy Schubert 	u_short		rstatus;
36722b15cb3dSCy Schubert 	char *		tag;
36732b15cb3dSCy Schubert 	char *		val;
36742b15cb3dSCy Schubert 	int		fields;
36752b15cb3dSCy Schubert 	u_int		ui;
36762b15cb3dSCy Schubert 	reslist_row	row;
36772b15cb3dSCy Schubert 	int		comprende;
36782b15cb3dSCy Schubert 	size_t		len;
36792b15cb3dSCy Schubert 
36802b15cb3dSCy Schubert 	qres = doquery(CTL_OP_READ_ORDLIST_A, 0, TRUE, qdata_chars,
36812b15cb3dSCy Schubert 		       qdata, &rstatus, &dsize, &datap);
36822b15cb3dSCy Schubert 	if (qres)	/* message already displayed */
36832b15cb3dSCy Schubert 		return;
36842b15cb3dSCy Schubert 
36852d4e511cSCy Schubert 	xprintf(fp,
36862b15cb3dSCy Schubert 		"   hits    addr/prefix or addr mask\n"
36872b15cb3dSCy Schubert 		"           restrictions\n"
36882b15cb3dSCy Schubert 		"==============================================================================\n");
36892b15cb3dSCy Schubert 		/* '=' x 78 */
36902b15cb3dSCy Schubert 
36912b15cb3dSCy Schubert 	ZERO(row);
36922b15cb3dSCy Schubert 	fields = 0;
36932b15cb3dSCy Schubert 	ui = 0;
36942b15cb3dSCy Schubert 	while (nextvar(&dsize, &datap, &tag, &val)) {
36954e1ef62aSXin LI 		INSIST(tag && val);
36962b15cb3dSCy Schubert 		if (debug > 1)
36972d4e511cSCy Schubert 			xprintf(stderr, "nextvar gave: %s = %s\n", tag, val);
36982b15cb3dSCy Schubert 		comprende = FALSE;
36992b15cb3dSCy Schubert 		switch(tag[0]) {
37002b15cb3dSCy Schubert 
37012b15cb3dSCy Schubert 		case 'a':
37022b15cb3dSCy Schubert 			if (1 == sscanf(tag, addr_fmtu, &ui) &&
37032b15cb3dSCy Schubert 			    decodenetnum(val, &row.addr))
37042b15cb3dSCy Schubert 				comprende = TRUE;
37052b15cb3dSCy Schubert 			break;
37062b15cb3dSCy Schubert 
37072b15cb3dSCy Schubert 		case 'f':
37082b15cb3dSCy Schubert 			if (1 == sscanf(tag, flags_fmt, &ui)) {
37092b15cb3dSCy Schubert 				if (NULL == val) {
37102b15cb3dSCy Schubert 					row.flagstr[0] = '\0';
37112b15cb3dSCy Schubert 					comprende = TRUE;
3712f0574f5cSXin LI 				} else if ((len = strlen(val)) < sizeof(row.flagstr)) {
37132b15cb3dSCy Schubert 					memcpy(row.flagstr, val, len);
37142b15cb3dSCy Schubert 					row.flagstr[len] = '\0';
37152b15cb3dSCy Schubert 					comprende = TRUE;
3716f0574f5cSXin LI 				} else {
3717f0574f5cSXin LI 					 /* no flags, and still !comprende */
3718f0574f5cSXin LI 					row.flagstr[0] = '\0';
37192b15cb3dSCy Schubert 				}
37202b15cb3dSCy Schubert 			}
37212b15cb3dSCy Schubert 			break;
37222b15cb3dSCy Schubert 
37232b15cb3dSCy Schubert 		case 'h':
37242b15cb3dSCy Schubert 			if (1 == sscanf(tag, hits_fmt, &ui) &&
37252b15cb3dSCy Schubert 			    1 == sscanf(val, "%lu", &row.hits))
37262b15cb3dSCy Schubert 				comprende = TRUE;
37272b15cb3dSCy Schubert 			break;
37282b15cb3dSCy Schubert 
37292b15cb3dSCy Schubert 		case 'm':
37302b15cb3dSCy Schubert 			if (1 == sscanf(tag, mask_fmtu, &ui) &&
37312b15cb3dSCy Schubert 			    decodenetnum(val, &row.mask))
37322b15cb3dSCy Schubert 				comprende = TRUE;
37332b15cb3dSCy Schubert 			break;
37342b15cb3dSCy Schubert 		}
37352b15cb3dSCy Schubert 
37362b15cb3dSCy Schubert 		if (comprende) {
37372b15cb3dSCy Schubert 			/* error out if rows out of order */
37382b15cb3dSCy Schubert 			validate_reslist_idx(fp, ui, &fields, &row);
37392b15cb3dSCy Schubert 			/* if the row is complete, print it */
37402b15cb3dSCy Schubert 			another_reslist_field(&fields, &row, fp);
37412b15cb3dSCy Schubert 		}
37422b15cb3dSCy Schubert 	}
37432b15cb3dSCy Schubert 	if (fields != RESLIST_FIELDS)
37442d4e511cSCy Schubert 		xprintf(fp, "Warning: incomplete row with %d (of %d) fields",
37452b15cb3dSCy Schubert 			fields, RESLIST_FIELDS);
37462b15cb3dSCy Schubert 
37472b15cb3dSCy Schubert 	fflush(fp);
37482b15cb3dSCy Schubert }
37492b15cb3dSCy Schubert 
37502b15cb3dSCy Schubert 
37512b15cb3dSCy Schubert /*
37522b15cb3dSCy Schubert  * collect_display_vdc
37532b15cb3dSCy Schubert  */
37542b15cb3dSCy Schubert static void
37552b15cb3dSCy Schubert collect_display_vdc(
37562b15cb3dSCy Schubert 	associd_t	as,
37572b15cb3dSCy Schubert 	vdc *		table,
37582b15cb3dSCy Schubert 	int		decodestatus,
37592b15cb3dSCy Schubert 	FILE *		fp
37602b15cb3dSCy Schubert 	)
37612b15cb3dSCy Schubert {
37622b15cb3dSCy Schubert 	static const char * const suf[2] = { "adr", "port" };
37632b15cb3dSCy Schubert 	static const char * const leapbits[4] = { "00", "01",
37642b15cb3dSCy Schubert 						  "10", "11" };
37652b15cb3dSCy Schubert 	struct varlist vl[MAXLIST];
37662b15cb3dSCy Schubert 	char tagbuf[32];
37672b15cb3dSCy Schubert 	vdc *pvdc;
37682b15cb3dSCy Schubert 	u_short rstatus;
37693311ff84SXin LI 	size_t rsize;
37702b15cb3dSCy Schubert 	const char *rdata;
37712b15cb3dSCy Schubert 	int qres;
37722b15cb3dSCy Schubert 	char *tag;
37732b15cb3dSCy Schubert 	char *val;
37742b15cb3dSCy Schubert 	u_int n;
37752b15cb3dSCy Schubert 	size_t len;
37762b15cb3dSCy Schubert 	int match;
37772b15cb3dSCy Schubert 	u_long ul;
37782b15cb3dSCy Schubert 	int vtype;
37792d4e511cSCy Schubert 	sockaddr_u sau;
37802b15cb3dSCy Schubert 
37812b15cb3dSCy Schubert 	ZERO(vl);
37822b15cb3dSCy Schubert 	for (pvdc = table; pvdc->tag != NULL; pvdc++) {
37832b15cb3dSCy Schubert 		ZERO(pvdc->v);
37842b15cb3dSCy Schubert 		if (NTP_ADD != pvdc->type) {
37852b15cb3dSCy Schubert 			doaddvlist(vl, pvdc->tag);
37862b15cb3dSCy Schubert 		} else {
37872b15cb3dSCy Schubert 			for (n = 0; n < COUNTOF(suf); n++) {
37882b15cb3dSCy Schubert 				snprintf(tagbuf, sizeof(tagbuf), "%s%s",
37892b15cb3dSCy Schubert 					 pvdc->tag, suf[n]);
37902b15cb3dSCy Schubert 				doaddvlist(vl, tagbuf);
37912b15cb3dSCy Schubert 			}
37922b15cb3dSCy Schubert 		}
37932b15cb3dSCy Schubert 	}
37942b15cb3dSCy Schubert 	qres = doquerylist(vl, CTL_OP_READVAR, as, 0, &rstatus, &rsize,
37952b15cb3dSCy Schubert 			   &rdata);
37962b15cb3dSCy Schubert 	doclearvlist(vl);
37972b15cb3dSCy Schubert 	if (qres)
37982b15cb3dSCy Schubert 		return;		/* error msg already displayed */
37992b15cb3dSCy Schubert 
38002b15cb3dSCy Schubert 	/*
38012b15cb3dSCy Schubert 	 * iterate over the response variables filling vdc_table with
38022b15cb3dSCy Schubert 	 * the retrieved values.
38032b15cb3dSCy Schubert 	 */
38042b15cb3dSCy Schubert 	while (nextvar(&rsize, &rdata, &tag, &val)) {
38054e1ef62aSXin LI 		INSIST(tag && val);
38062b15cb3dSCy Schubert 		n = 0;
38072b15cb3dSCy Schubert 		for (pvdc = table; pvdc->tag != NULL; pvdc++) {
38082b15cb3dSCy Schubert 			len = strlen(pvdc->tag);
38092b15cb3dSCy Schubert 			if (strncmp(tag, pvdc->tag, len))
38102b15cb3dSCy Schubert 				continue;
38112b15cb3dSCy Schubert 			if (NTP_ADD != pvdc->type) {
38122b15cb3dSCy Schubert 				if ('\0' != tag[len])
38132b15cb3dSCy Schubert 					continue;
38142b15cb3dSCy Schubert 				break;
38152b15cb3dSCy Schubert 			}
38162b15cb3dSCy Schubert 			match = FALSE;
38172b15cb3dSCy Schubert 			for (n = 0; n < COUNTOF(suf); n++) {
38182b15cb3dSCy Schubert 				if (strcmp(tag + len, suf[n]))
38192b15cb3dSCy Schubert 					continue;
38202b15cb3dSCy Schubert 				match = TRUE;
38212b15cb3dSCy Schubert 				break;
38222b15cb3dSCy Schubert 			}
38232b15cb3dSCy Schubert 			if (match)
38242b15cb3dSCy Schubert 				break;
38252b15cb3dSCy Schubert 		}
38262b15cb3dSCy Schubert 		if (NULL == pvdc->tag)
38272b15cb3dSCy Schubert 			continue;
38282b15cb3dSCy Schubert 		switch (pvdc->type) {
38292b15cb3dSCy Schubert 
38302b15cb3dSCy Schubert 		case NTP_STR:
38312b15cb3dSCy Schubert 			/* strip surrounding double quotes */
38322b15cb3dSCy Schubert 			if ('"' == val[0]) {
38332b15cb3dSCy Schubert 				len = strlen(val);
38342b15cb3dSCy Schubert 				if (len > 0 && '"' == val[len - 1]) {
38352b15cb3dSCy Schubert 					val[len - 1] = '\0';
38362b15cb3dSCy Schubert 					val++;
38372b15cb3dSCy Schubert 				}
38382b15cb3dSCy Schubert 			}
38392b15cb3dSCy Schubert 			/* fallthru */
38402d4e511cSCy Schubert 		case NTP_REFID:	/* fallthru */
38412b15cb3dSCy Schubert 		case NTP_MODE:	/* fallthru */
38422b15cb3dSCy Schubert 		case NTP_2BIT:
38432b15cb3dSCy Schubert 			pvdc->v.str = estrdup(val);
38442b15cb3dSCy Schubert 			break;
38452b15cb3dSCy Schubert 
38462b15cb3dSCy Schubert 		case NTP_LFP:
38472b15cb3dSCy Schubert 			decodets(val, &pvdc->v.lfp);
38482b15cb3dSCy Schubert 			break;
38492b15cb3dSCy Schubert 
38502b15cb3dSCy Schubert 		case NTP_ADP:
38512b15cb3dSCy Schubert 			if (!decodenetnum(val, &pvdc->v.sau))
38522d4e511cSCy Schubert 				xprintf(stderr, "malformed %s=%s\n",
38532b15cb3dSCy Schubert 					pvdc->tag, val);
38542b15cb3dSCy Schubert 			break;
38552b15cb3dSCy Schubert 
38562b15cb3dSCy Schubert 		case NTP_ADD:
38572b15cb3dSCy Schubert 			if (0 == n) {	/* adr */
38582b15cb3dSCy Schubert 				if (!decodenetnum(val, &pvdc->v.sau))
38592d4e511cSCy Schubert 					xprintf(stderr,
38602b15cb3dSCy Schubert 						"malformed %s=%s\n",
38612b15cb3dSCy Schubert 						pvdc->tag, val);
38622b15cb3dSCy Schubert 			} else {	/* port */
38632b15cb3dSCy Schubert 				if (atouint(val, &ul))
38642b15cb3dSCy Schubert 					SET_PORT(&pvdc->v.sau,
38652b15cb3dSCy Schubert 						 (u_short)ul);
38662b15cb3dSCy Schubert 			}
38672b15cb3dSCy Schubert 			break;
38682b15cb3dSCy Schubert 		}
38692b15cb3dSCy Schubert 	}
38702b15cb3dSCy Schubert 
38712b15cb3dSCy Schubert 	/* and display */
38722b15cb3dSCy Schubert 	if (decodestatus) {
38732b15cb3dSCy Schubert 		vtype = (0 == as)
38742b15cb3dSCy Schubert 			    ? TYPE_SYS
38752b15cb3dSCy Schubert 			    : TYPE_PEER;
38762d4e511cSCy Schubert 		xprintf(fp, "associd=%u status=%04x %s,\n", as, rstatus,
38772b15cb3dSCy Schubert 			statustoa(vtype, rstatus));
38782b15cb3dSCy Schubert 	}
38792b15cb3dSCy Schubert 
38802b15cb3dSCy Schubert 	for (pvdc = table; pvdc->tag != NULL; pvdc++) {
38812b15cb3dSCy Schubert 		switch (pvdc->type) {
38822b15cb3dSCy Schubert 
38832b15cb3dSCy Schubert 		case NTP_STR:
38842b15cb3dSCy Schubert 			if (pvdc->v.str != NULL) {
38852d4e511cSCy Schubert 				xprintf(fp, "%s  %s\n", pvdc->display,
38862b15cb3dSCy Schubert 					pvdc->v.str);
38872b15cb3dSCy Schubert 				free(pvdc->v.str);
38882b15cb3dSCy Schubert 				pvdc->v.str = NULL;
38892b15cb3dSCy Schubert 			}
38902b15cb3dSCy Schubert 			break;
38912b15cb3dSCy Schubert 
38922b15cb3dSCy Schubert 		case NTP_ADD:	/* fallthru */
38932b15cb3dSCy Schubert 		case NTP_ADP:
38942d4e511cSCy Schubert 			xprintf(fp, "%s  %s\n", pvdc->display,
38952b15cb3dSCy Schubert 				nntohostp(&pvdc->v.sau));
38962b15cb3dSCy Schubert 			break;
38972b15cb3dSCy Schubert 
38982b15cb3dSCy Schubert 		case NTP_LFP:
38992d4e511cSCy Schubert 			xprintf(fp, "%s  %s\n", pvdc->display,
39002b15cb3dSCy Schubert 				prettydate(&pvdc->v.lfp));
39012b15cb3dSCy Schubert 			break;
39022b15cb3dSCy Schubert 
39032b15cb3dSCy Schubert 		case NTP_MODE:
39042b15cb3dSCy Schubert 			atouint(pvdc->v.str, &ul);
39052d4e511cSCy Schubert 			xprintf(fp, "%s  %s\n", pvdc->display,
39062b15cb3dSCy Schubert 				modetoa((int)ul));
39072d4e511cSCy Schubert 			free(pvdc->v.str);
39082d4e511cSCy Schubert 			pvdc->v.str = NULL;
39092b15cb3dSCy Schubert 			break;
39102b15cb3dSCy Schubert 
39112b15cb3dSCy Schubert 		case NTP_2BIT:
39122b15cb3dSCy Schubert 			atouint(pvdc->v.str, &ul);
39132d4e511cSCy Schubert 			xprintf(fp, "%s  %s\n", pvdc->display,
39142b15cb3dSCy Schubert 				leapbits[ul & 0x3]);
39152d4e511cSCy Schubert 			free(pvdc->v.str);
39162d4e511cSCy Schubert 			pvdc->v.str = NULL;
39172d4e511cSCy Schubert 			break;
39182d4e511cSCy Schubert 
39192d4e511cSCy Schubert 		case NTP_REFID:
39202d4e511cSCy Schubert 			if (!decodenetnum(pvdc->v.str, &sau)) {
39212d4e511cSCy Schubert 				fprintf(fp, "%s  %s\n", pvdc->display,    /* Text fmt */
39222d4e511cSCy Schubert 					pvdc->v.str);
39232d4e511cSCy Schubert 			} else if (drefid == REFID_IPV4) {
39242d4e511cSCy Schubert 				fprintf(fp, "%s  %s\n", pvdc->display,    /* IPv4 fmt */
39252d4e511cSCy Schubert 					stoa(&sau));
39262d4e511cSCy Schubert 			} else {
39272d4e511cSCy Schubert 				fprintf (fp, "%s  0x%08x\n", pvdc->display,	   /* Hex / hash */
39282d4e511cSCy Schubert 					 ntohl(addr2refid(&sau)));
39292d4e511cSCy Schubert 			}
39302d4e511cSCy Schubert 			free(pvdc->v.str);
39312d4e511cSCy Schubert 			pvdc->v.str = NULL;
39322b15cb3dSCy Schubert 			break;
39332b15cb3dSCy Schubert 
39342b15cb3dSCy Schubert 		default:
39352d4e511cSCy Schubert 			xprintf(stderr, "unexpected vdc type %d for %s\n",
39362b15cb3dSCy Schubert 				pvdc->type, pvdc->tag);
39372b15cb3dSCy Schubert 			break;
39382b15cb3dSCy Schubert 		}
39392b15cb3dSCy Schubert 	}
39402b15cb3dSCy Schubert }
39412b15cb3dSCy Schubert 
39422b15cb3dSCy Schubert 
39432b15cb3dSCy Schubert /*
39442b15cb3dSCy Schubert  * sysstats - implements ntpq -c sysstats modeled on ntpdc -c sysstats
39452b15cb3dSCy Schubert  */
39462b15cb3dSCy Schubert static void
39472b15cb3dSCy Schubert sysstats(
39482b15cb3dSCy Schubert 	struct parse *pcmd,
39492b15cb3dSCy Schubert 	FILE *fp
39502b15cb3dSCy Schubert 	)
39512b15cb3dSCy Schubert {
39522b15cb3dSCy Schubert     static vdc sysstats_vdc[] = {
39532b15cb3dSCy Schubert 	VDC_INIT("ss_uptime",		"uptime:               ", NTP_STR),
39542b15cb3dSCy Schubert 	VDC_INIT("ss_reset",		"sysstats reset:       ", NTP_STR),
39552b15cb3dSCy Schubert 	VDC_INIT("ss_received",		"packets received:     ", NTP_STR),
39562b15cb3dSCy Schubert 	VDC_INIT("ss_thisver",		"current version:      ", NTP_STR),
39572b15cb3dSCy Schubert 	VDC_INIT("ss_oldver",		"older version:        ", NTP_STR),
39582b15cb3dSCy Schubert 	VDC_INIT("ss_badformat",	"bad length or format: ", NTP_STR),
39592b15cb3dSCy Schubert 	VDC_INIT("ss_badauth",		"authentication failed:", NTP_STR),
39602b15cb3dSCy Schubert 	VDC_INIT("ss_declined",		"declined:             ", NTP_STR),
39612b15cb3dSCy Schubert 	VDC_INIT("ss_restricted",	"restricted:           ", NTP_STR),
39622b15cb3dSCy Schubert 	VDC_INIT("ss_limited",		"rate limited:         ", NTP_STR),
39632b15cb3dSCy Schubert 	VDC_INIT("ss_kodsent",		"KoD responses:        ", NTP_STR),
39642b15cb3dSCy Schubert 	VDC_INIT("ss_processed",	"processed for time:   ", NTP_STR),
396509100258SXin LI #if 0
396609100258SXin LI 	VDC_INIT("ss_lamport",		"Lamport violations:    ", NTP_STR),
396709100258SXin LI 	VDC_INIT("ss_tsrounding",	"bad timestamp rounding:", NTP_STR),
396809100258SXin LI #endif
39692b15cb3dSCy Schubert 	VDC_INIT(NULL,			NULL,			  0)
39702b15cb3dSCy Schubert     };
39712b15cb3dSCy Schubert 
39722b15cb3dSCy Schubert 	collect_display_vdc(0, sysstats_vdc, FALSE, fp);
39732b15cb3dSCy Schubert }
39742b15cb3dSCy Schubert 
39752b15cb3dSCy Schubert 
39762b15cb3dSCy Schubert /*
39772b15cb3dSCy Schubert  * sysinfo - modeled on ntpdc's sysinfo
39782b15cb3dSCy Schubert  */
39792b15cb3dSCy Schubert static void
39802b15cb3dSCy Schubert sysinfo(
39812b15cb3dSCy Schubert 	struct parse *pcmd,
39822b15cb3dSCy Schubert 	FILE *fp
39832b15cb3dSCy Schubert 	)
39842b15cb3dSCy Schubert {
39852b15cb3dSCy Schubert     static vdc sysinfo_vdc[] = {
39862b15cb3dSCy Schubert 	VDC_INIT("peeradr",		"system peer:      ", NTP_ADP),
39872b15cb3dSCy Schubert 	VDC_INIT("peermode",		"system peer mode: ", NTP_MODE),
39882b15cb3dSCy Schubert 	VDC_INIT("leap",		"leap indicator:   ", NTP_2BIT),
39892b15cb3dSCy Schubert 	VDC_INIT("stratum",		"stratum:          ", NTP_STR),
39902b15cb3dSCy Schubert 	VDC_INIT("precision",		"log2 precision:   ", NTP_STR),
39912b15cb3dSCy Schubert 	VDC_INIT("rootdelay",		"root delay:       ", NTP_STR),
39922b15cb3dSCy Schubert 	VDC_INIT("rootdisp",		"root dispersion:  ", NTP_STR),
39932d4e511cSCy Schubert 	VDC_INIT("refid",		"reference ID:     ", NTP_REFID),
39942b15cb3dSCy Schubert 	VDC_INIT("reftime",		"reference time:   ", NTP_LFP),
39952b15cb3dSCy Schubert 	VDC_INIT("sys_jitter",		"system jitter:    ", NTP_STR),
39962b15cb3dSCy Schubert 	VDC_INIT("clk_jitter",		"clock jitter:     ", NTP_STR),
39972b15cb3dSCy Schubert 	VDC_INIT("clk_wander",		"clock wander:     ", NTP_STR),
39982b15cb3dSCy Schubert 	VDC_INIT("bcastdelay",		"broadcast delay:  ", NTP_STR),
39992b15cb3dSCy Schubert 	VDC_INIT("authdelay",		"symm. auth. delay:", NTP_STR),
40002b15cb3dSCy Schubert 	VDC_INIT(NULL,			NULL,		      0)
40012b15cb3dSCy Schubert     };
40022b15cb3dSCy Schubert 
40032b15cb3dSCy Schubert 	collect_display_vdc(0, sysinfo_vdc, TRUE, fp);
40042b15cb3dSCy Schubert }
40052b15cb3dSCy Schubert 
40062b15cb3dSCy Schubert 
40072b15cb3dSCy Schubert /*
40082b15cb3dSCy Schubert  * kerninfo - modeled on ntpdc's kerninfo
40092b15cb3dSCy Schubert  */
40102b15cb3dSCy Schubert static void
40112b15cb3dSCy Schubert kerninfo(
40122b15cb3dSCy Schubert 	struct parse *pcmd,
40132b15cb3dSCy Schubert 	FILE *fp
40142b15cb3dSCy Schubert 	)
40152b15cb3dSCy Schubert {
40162b15cb3dSCy Schubert     static vdc kerninfo_vdc[] = {
40172b15cb3dSCy Schubert 	VDC_INIT("koffset",		"pll offset:          ", NTP_STR),
40182b15cb3dSCy Schubert 	VDC_INIT("kfreq",		"pll frequency:       ", NTP_STR),
40192b15cb3dSCy Schubert 	VDC_INIT("kmaxerr",		"maximum error:       ", NTP_STR),
40202b15cb3dSCy Schubert 	VDC_INIT("kesterr",		"estimated error:     ", NTP_STR),
40212b15cb3dSCy Schubert 	VDC_INIT("kstflags",		"kernel status:       ", NTP_STR),
40222b15cb3dSCy Schubert 	VDC_INIT("ktimeconst",		"pll time constant:   ", NTP_STR),
40232b15cb3dSCy Schubert 	VDC_INIT("kprecis",		"precision:           ", NTP_STR),
40242b15cb3dSCy Schubert 	VDC_INIT("kfreqtol",		"frequency tolerance: ", NTP_STR),
40252b15cb3dSCy Schubert 	VDC_INIT("kppsfreq",		"pps frequency:       ", NTP_STR),
40262b15cb3dSCy Schubert 	VDC_INIT("kppsstab",		"pps stability:       ", NTP_STR),
40272b15cb3dSCy Schubert 	VDC_INIT("kppsjitter",		"pps jitter:          ", NTP_STR),
40282b15cb3dSCy Schubert 	VDC_INIT("kppscalibdur",	"calibration interval ", NTP_STR),
40292b15cb3dSCy Schubert 	VDC_INIT("kppscalibs",		"calibration cycles:  ", NTP_STR),
40302b15cb3dSCy Schubert 	VDC_INIT("kppsjitexc",		"jitter exceeded:     ", NTP_STR),
40312b15cb3dSCy Schubert 	VDC_INIT("kppsstbexc",		"stability exceeded:  ", NTP_STR),
40322b15cb3dSCy Schubert 	VDC_INIT("kppscaliberrs",	"calibration errors:  ", NTP_STR),
40332b15cb3dSCy Schubert 	VDC_INIT(NULL,			NULL,			 0)
40342b15cb3dSCy Schubert     };
40352b15cb3dSCy Schubert 
40362b15cb3dSCy Schubert 	collect_display_vdc(0, kerninfo_vdc, TRUE, fp);
40372b15cb3dSCy Schubert }
40382b15cb3dSCy Schubert 
40392b15cb3dSCy Schubert 
40402b15cb3dSCy Schubert /*
40412b15cb3dSCy Schubert  * monstats - implements ntpq -c monstats
40422b15cb3dSCy Schubert  */
40432b15cb3dSCy Schubert static void
40442b15cb3dSCy Schubert monstats(
40452b15cb3dSCy Schubert 	struct parse *pcmd,
40462b15cb3dSCy Schubert 	FILE *fp
40472b15cb3dSCy Schubert 	)
40482b15cb3dSCy Schubert {
40492b15cb3dSCy Schubert     static vdc monstats_vdc[] = {
40502b15cb3dSCy Schubert 	VDC_INIT("mru_enabled",		"enabled:            ", NTP_STR),
40512b15cb3dSCy Schubert 	VDC_INIT("mru_depth",		"addresses:          ", NTP_STR),
40522b15cb3dSCy Schubert 	VDC_INIT("mru_deepest",		"peak addresses:     ", NTP_STR),
40532b15cb3dSCy Schubert 	VDC_INIT("mru_maxdepth",	"maximum addresses:  ", NTP_STR),
40542b15cb3dSCy Schubert 	VDC_INIT("mru_mindepth",	"reclaim above count:", NTP_STR),
40552b15cb3dSCy Schubert 	VDC_INIT("mru_maxage",		"reclaim older than: ", NTP_STR),
40562b15cb3dSCy Schubert 	VDC_INIT("mru_mem",		"kilobytes:          ", NTP_STR),
40572b15cb3dSCy Schubert 	VDC_INIT("mru_maxmem",		"maximum kilobytes:  ", NTP_STR),
40582b15cb3dSCy Schubert 	VDC_INIT(NULL,			NULL,			0)
40592b15cb3dSCy Schubert     };
40602b15cb3dSCy Schubert 
40612b15cb3dSCy Schubert 	collect_display_vdc(0, monstats_vdc, FALSE, fp);
40622b15cb3dSCy Schubert }
40632b15cb3dSCy Schubert 
40642b15cb3dSCy Schubert 
40652b15cb3dSCy Schubert /*
40662b15cb3dSCy Schubert  * iostats - ntpq -c iostats - network input and output counters
40672b15cb3dSCy Schubert  */
40682b15cb3dSCy Schubert static void
40692b15cb3dSCy Schubert iostats(
40702b15cb3dSCy Schubert 	struct parse *pcmd,
40712b15cb3dSCy Schubert 	FILE *fp
40722b15cb3dSCy Schubert 	)
40732b15cb3dSCy Schubert {
40742b15cb3dSCy Schubert     static vdc iostats_vdc[] = {
40752b15cb3dSCy Schubert 	VDC_INIT("iostats_reset",	"time since reset:     ", NTP_STR),
40762b15cb3dSCy Schubert 	VDC_INIT("total_rbuf",		"receive buffers:      ", NTP_STR),
40772b15cb3dSCy Schubert 	VDC_INIT("free_rbuf",		"free receive buffers: ", NTP_STR),
40782b15cb3dSCy Schubert 	VDC_INIT("used_rbuf",		"used receive buffers: ", NTP_STR),
40792b15cb3dSCy Schubert 	VDC_INIT("rbuf_lowater",	"low water refills:    ", NTP_STR),
40802b15cb3dSCy Schubert 	VDC_INIT("io_dropped",		"dropped packets:      ", NTP_STR),
40812b15cb3dSCy Schubert 	VDC_INIT("io_ignored",		"ignored packets:      ", NTP_STR),
40822b15cb3dSCy Schubert 	VDC_INIT("io_received",		"received packets:     ", NTP_STR),
40832b15cb3dSCy Schubert 	VDC_INIT("io_sent",		"packets sent:         ", NTP_STR),
40842b15cb3dSCy Schubert 	VDC_INIT("io_sendfailed",	"packet send failures: ", NTP_STR),
40852b15cb3dSCy Schubert 	VDC_INIT("io_wakeups",		"input wakeups:        ", NTP_STR),
40862b15cb3dSCy Schubert 	VDC_INIT("io_goodwakeups",	"useful input wakeups: ", NTP_STR),
40872b15cb3dSCy Schubert 	VDC_INIT(NULL,			NULL,			  0)
40882b15cb3dSCy Schubert     };
40892b15cb3dSCy Schubert 
40902b15cb3dSCy Schubert 	collect_display_vdc(0, iostats_vdc, FALSE, fp);
40912b15cb3dSCy Schubert }
40922b15cb3dSCy Schubert 
40932b15cb3dSCy Schubert 
40942b15cb3dSCy Schubert /*
40952b15cb3dSCy Schubert  * timerstats - ntpq -c timerstats - interval timer counters
40962b15cb3dSCy Schubert  */
40972b15cb3dSCy Schubert static void
40982b15cb3dSCy Schubert timerstats(
40992b15cb3dSCy Schubert 	struct parse *pcmd,
41002b15cb3dSCy Schubert 	FILE *fp
41012b15cb3dSCy Schubert 	)
41022b15cb3dSCy Schubert {
41032b15cb3dSCy Schubert     static vdc timerstats_vdc[] = {
41042b15cb3dSCy Schubert 	VDC_INIT("timerstats_reset",	"time since reset:  ", NTP_STR),
41052b15cb3dSCy Schubert 	VDC_INIT("timer_overruns",	"timer overruns:    ", NTP_STR),
41062b15cb3dSCy Schubert 	VDC_INIT("timer_xmts",		"calls to transmit: ", NTP_STR),
41072b15cb3dSCy Schubert 	VDC_INIT(NULL,			NULL,		       0)
41082b15cb3dSCy Schubert     };
41092b15cb3dSCy Schubert 
41102b15cb3dSCy Schubert 	collect_display_vdc(0, timerstats_vdc, FALSE, fp);
41112b15cb3dSCy Schubert }
41122b15cb3dSCy Schubert 
41132b15cb3dSCy Schubert 
41142b15cb3dSCy Schubert /*
41152b15cb3dSCy Schubert  * authinfo - implements ntpq -c authinfo
41162b15cb3dSCy Schubert  */
41172b15cb3dSCy Schubert static void
41182b15cb3dSCy Schubert authinfo(
41192b15cb3dSCy Schubert 	struct parse *pcmd,
41202b15cb3dSCy Schubert 	FILE *fp
41212b15cb3dSCy Schubert 	)
41222b15cb3dSCy Schubert {
41232b15cb3dSCy Schubert     static vdc authinfo_vdc[] = {
41242b15cb3dSCy Schubert 	VDC_INIT("authreset",		"time since reset:", NTP_STR),
41252b15cb3dSCy Schubert 	VDC_INIT("authkeys",		"stored keys:     ", NTP_STR),
41262b15cb3dSCy Schubert 	VDC_INIT("authfreek",		"free keys:       ", NTP_STR),
41272b15cb3dSCy Schubert 	VDC_INIT("authklookups",	"key lookups:     ", NTP_STR),
41282b15cb3dSCy Schubert 	VDC_INIT("authknotfound",	"keys not found:  ", NTP_STR),
41292b15cb3dSCy Schubert 	VDC_INIT("authkuncached",	"uncached keys:   ", NTP_STR),
41302b15cb3dSCy Schubert 	VDC_INIT("authkexpired",	"expired keys:    ", NTP_STR),
41312b15cb3dSCy Schubert 	VDC_INIT("authencrypts",	"encryptions:     ", NTP_STR),
41322b15cb3dSCy Schubert 	VDC_INIT("authdecrypts",	"decryptions:     ", NTP_STR),
41332b15cb3dSCy Schubert 	VDC_INIT(NULL,			NULL,		     0)
41342b15cb3dSCy Schubert     };
41352b15cb3dSCy Schubert 
41362b15cb3dSCy Schubert 	collect_display_vdc(0, authinfo_vdc, FALSE, fp);
41372b15cb3dSCy Schubert }
41382b15cb3dSCy Schubert 
41392b15cb3dSCy Schubert 
41402b15cb3dSCy Schubert /*
41412b15cb3dSCy Schubert  * pstats - show statistics for a peer
41422b15cb3dSCy Schubert  */
41432b15cb3dSCy Schubert static void
41442b15cb3dSCy Schubert pstats(
41452b15cb3dSCy Schubert 	struct parse *pcmd,
41462b15cb3dSCy Schubert 	FILE *fp
41472b15cb3dSCy Schubert 	)
41482b15cb3dSCy Schubert {
41492b15cb3dSCy Schubert     static vdc pstats_vdc[] = {
41502b15cb3dSCy Schubert 	VDC_INIT("src",		"remote host:         ", NTP_ADD),
41512b15cb3dSCy Schubert 	VDC_INIT("dst",		"local address:       ", NTP_ADD),
41522b15cb3dSCy Schubert 	VDC_INIT("timerec",	"time last received:  ", NTP_STR),
41532b15cb3dSCy Schubert 	VDC_INIT("timer",	"time until next send:", NTP_STR),
41542b15cb3dSCy Schubert 	VDC_INIT("timereach",	"reachability change: ", NTP_STR),
41552b15cb3dSCy Schubert 	VDC_INIT("sent",	"packets sent:        ", NTP_STR),
41562b15cb3dSCy Schubert 	VDC_INIT("received",	"packets received:    ", NTP_STR),
41572b15cb3dSCy Schubert 	VDC_INIT("badauth",	"bad authentication:  ", NTP_STR),
41582b15cb3dSCy Schubert 	VDC_INIT("bogusorg",	"bogus origin:        ", NTP_STR),
41592b15cb3dSCy Schubert 	VDC_INIT("oldpkt",	"duplicate:           ", NTP_STR),
41602b15cb3dSCy Schubert 	VDC_INIT("seldisp",	"bad dispersion:      ", NTP_STR),
41612b15cb3dSCy Schubert 	VDC_INIT("selbroken",	"bad reference time:  ", NTP_STR),
41622b15cb3dSCy Schubert 	VDC_INIT("candidate",	"candidate order:     ", NTP_STR),
41632b15cb3dSCy Schubert 	VDC_INIT(NULL,		NULL,			 0)
41642b15cb3dSCy Schubert     };
41652b15cb3dSCy Schubert 	associd_t associd;
41662b15cb3dSCy Schubert 
41672b15cb3dSCy Schubert 	associd = checkassocid(pcmd->argval[0].uval);
41682b15cb3dSCy Schubert 	if (0 == associd)
41692b15cb3dSCy Schubert 		return;
41702b15cb3dSCy Schubert 
41712b15cb3dSCy Schubert 	collect_display_vdc(associd, pstats_vdc, TRUE, fp);
41722b15cb3dSCy Schubert }
4173