xref: /freebsd/contrib/ntp/ntpq/ntpq-subs.c (revision a466cc55373fc3cf86837f09da729535b57e69a1)
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];
1189*a466cc55SCy 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 
1339*a466cc55SCy Schubert 		case PEVNT_AUTH:
1340*a466cc55SCy Schubert 			last_event = "bad_auth";
1341*a466cc55SCy Schubert 			break;
1342*a466cc55SCy Schubert 
1343*a466cc55SCy Schubert 		case PEVNT_POPCORN:
1344*a466cc55SCy Schubert 			last_event = "popcorn";
1345*a466cc55SCy Schubert 			break;
1346*a466cc55SCy Schubert 
1347*a466cc55SCy Schubert 		case PEVNT_XLEAVE:
1348*a466cc55SCy Schubert 			last_event = "interleave";
1349*a466cc55SCy Schubert 			break;
1350*a466cc55SCy Schubert 
1351*a466cc55SCy Schubert 		case PEVNT_XERR:
1352*a466cc55SCy Schubert 			last_event = "xleave_err";
1353*a466cc55SCy Schubert 			break;
1354*a466cc55SCy Schubert 
1355ea906c41SOllivier Robert 		default:
1356*a466cc55SCy Schubert 			snprintf(numev, sizeof(numev), "<?%x?>", event);
1357*a466cc55SCy 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 /*
1498ea906c41SOllivier Robert  * when - print 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;
16942b15cb3dSCy Schubert 	size_t drlen;
1695ea906c41SOllivier Robert 	u_long stratum = 0;
1696ea906c41SOllivier Robert 	long ppoll = 0;
1697ea906c41SOllivier Robert 	long hpoll = 0;
1698ea906c41SOllivier Robert 	u_long reach = 0;
1699ea906c41SOllivier Robert 	l_fp estoffset;
1700ea906c41SOllivier Robert 	l_fp estdelay;
1701ea906c41SOllivier Robert 	l_fp estjitter;
1702ea906c41SOllivier Robert 	l_fp estdisp;
1703ea906c41SOllivier Robert 	l_fp reftime;
1704ea906c41SOllivier Robert 	l_fp rec;
1705ea906c41SOllivier Robert 	l_fp ts;
1706ea906c41SOllivier Robert 	u_long poll_sec;
17074e1ef62aSXin LI 	u_long flash = 0;
1708ea906c41SOllivier Robert 	char type = '?';
1709ea906c41SOllivier Robert 	char clock_name[LENHOSTNAME];
17104e1ef62aSXin LI 	char whenbuf[12], pollbuf[12];
17114e1ef62aSXin LI 	/* [Bug 3482] formally whenbuf & pollbuf should be able to hold
17124e1ef62aSXin LI 	 * a full signed int. Not that we would use that much string
17134e1ef62aSXin LI 	 * data for it...
17144e1ef62aSXin LI 	 */
1715ea906c41SOllivier Robert 	get_systime(&ts);
1716ea906c41SOllivier Robert 
17172b15cb3dSCy Schubert 	have_srchost = FALSE;
17182b15cb3dSCy Schubert 	have_dstadr = FALSE;
17192b15cb3dSCy Schubert 	have_da_rid = FALSE;
17202b15cb3dSCy Schubert 	have_jitter = FALSE;
17212b15cb3dSCy Schubert 	ZERO_SOCK(&srcadr);
17222b15cb3dSCy Schubert 	ZERO_SOCK(&dstadr);
17232b15cb3dSCy Schubert 	clock_name[0] = '\0';
17242b15cb3dSCy Schubert 	ZERO(estoffset);
17252b15cb3dSCy Schubert 	ZERO(estdelay);
17262b15cb3dSCy Schubert 	ZERO(estjitter);
17272b15cb3dSCy Schubert 	ZERO(estdisp);
1728ea906c41SOllivier Robert 
1729ea906c41SOllivier Robert 	while (nextvar(&datalen, &data, &name, &value)) {
17304e1ef62aSXin LI 		INSIST(name && value);
17312b15cb3dSCy Schubert 		if (!strcmp("srcadr", name) ||
17322b15cb3dSCy Schubert 		    !strcmp("peeradr", name)) {
17332b15cb3dSCy Schubert 			if (!decodenetnum(value, &srcadr))
17342d4e511cSCy Schubert 				xprintf(stderr, "malformed %s=%s\n",
17352b15cb3dSCy Schubert 					name, value);
17362b15cb3dSCy Schubert 		} else if (!strcmp("srchost", name)) {
1737276da39aSCy Schubert 			if (pvl == peervarlist || pvl == apeervarlist) {
17382b15cb3dSCy Schubert 				len = strlen(value);
17392b15cb3dSCy Schubert 				if (2 < len &&
17402b15cb3dSCy Schubert 				    (size_t)len < sizeof(clock_name)) {
17412b15cb3dSCy Schubert 					/* strip quotes */
17422b15cb3dSCy Schubert 					value++;
17432b15cb3dSCy Schubert 					len -= 2;
17442b15cb3dSCy Schubert 					memcpy(clock_name, value, len);
17452b15cb3dSCy Schubert 					clock_name[len] = '\0';
17462b15cb3dSCy Schubert 					have_srchost = TRUE;
17472b15cb3dSCy Schubert 				}
17482b15cb3dSCy Schubert 			}
17492b15cb3dSCy Schubert 		} else if (!strcmp("dstadr", name)) {
17502b15cb3dSCy Schubert 			if (decodenetnum(value, &dum_store)) {
17512b15cb3dSCy Schubert 				type = decodeaddrtype(&dum_store);
17522b15cb3dSCy Schubert 				have_dstadr = TRUE;
17532b15cb3dSCy Schubert 				dstadr = dum_store;
17542b15cb3dSCy Schubert 				if (pvl == opeervarlist) {
17552b15cb3dSCy Schubert 					have_da_rid = TRUE;
17562b15cb3dSCy Schubert 					dstadr_refid = trunc_left(stoa(&dstadr), 15);
17572b15cb3dSCy Schubert 				}
17582b15cb3dSCy Schubert 			}
17592b15cb3dSCy Schubert 		} else if (!strcmp("hmode", name)) {
17602b15cb3dSCy Schubert 			decodeint(value, &hmode);
17612b15cb3dSCy Schubert 		} else if (!strcmp("refid", name)) {
17624990d495SXin LI 			if (   (pvl == peervarlist)
17634990d495SXin LI 			    && (drefid == REFID_IPV4)) {
17642b15cb3dSCy Schubert 				have_da_rid = TRUE;
17652b15cb3dSCy Schubert 				drlen = strlen(value);
17662b15cb3dSCy Schubert 				if (0 == drlen) {
17672b15cb3dSCy Schubert 					dstadr_refid = "";
17682b15cb3dSCy Schubert 				} else if (drlen <= 4) {
17692b15cb3dSCy Schubert 					ZERO(u32);
17702b15cb3dSCy Schubert 					memcpy(&u32, value, drlen);
17712b15cb3dSCy Schubert 					dstadr_refid = refid_str(u32, 1);
17722b15cb3dSCy Schubert 				} else if (decodenetnum(value, &refidadr)) {
17732b15cb3dSCy Schubert 					if (SOCK_UNSPEC(&refidadr))
1774ea906c41SOllivier Robert 						dstadr_refid = "0.0.0.0";
17752b15cb3dSCy Schubert 					else if (ISREFCLOCKADR(&refidadr))
1776ea906c41SOllivier Robert 						dstadr_refid =
17772b15cb3dSCy Schubert 						    refnumtoa(&refidadr);
1778ea906c41SOllivier Robert 					else
1779ea906c41SOllivier Robert 						dstadr_refid =
17802b15cb3dSCy Schubert 						    stoa(&refidadr);
1781ea906c41SOllivier Robert 				} else {
17822b15cb3dSCy Schubert 					have_da_rid = FALSE;
1783ea906c41SOllivier Robert 				}
17844990d495SXin LI 			} else if (   (pvl == apeervarlist)
17854990d495SXin LI 				   || (pvl == peervarlist)) {
17864990d495SXin LI 				/* no need to check drefid == REFID_HASH */
1787276da39aSCy Schubert 				have_da_rid = TRUE;
1788276da39aSCy Schubert 				drlen = strlen(value);
1789276da39aSCy Schubert 				if (0 == drlen) {
1790276da39aSCy Schubert 					dstadr_refid = "";
1791276da39aSCy Schubert 				} else if (drlen <= 4) {
1792276da39aSCy Schubert 					ZERO(u32);
1793276da39aSCy Schubert 					memcpy(&u32, value, drlen);
1794276da39aSCy Schubert 					dstadr_refid = refid_str(u32, 1);
17952d4e511cSCy Schubert 					//xprintf(stderr, "apeervarlist S1 refid: value=<%s>\n", value);
1796276da39aSCy Schubert 				} else if (decodenetnum(value, &refidadr)) {
1797276da39aSCy Schubert 					if (SOCK_UNSPEC(&refidadr))
1798276da39aSCy Schubert 						dstadr_refid = "0.0.0.0";
1799276da39aSCy Schubert 					else if (ISREFCLOCKADR(&refidadr))
1800276da39aSCy Schubert 						dstadr_refid =
1801276da39aSCy Schubert 						    refnumtoa(&refidadr);
1802276da39aSCy Schubert 					else {
1803276da39aSCy Schubert 						char *buf = emalloc(10);
1804276da39aSCy Schubert 						int i = ntohl(refidadr.sa4.sin_addr.s_addr);
1805276da39aSCy Schubert 
1806276da39aSCy Schubert 						snprintf(buf, 10,
1807276da39aSCy Schubert 							"%0x", i);
1808276da39aSCy Schubert 						dstadr_refid = buf;
18092d4e511cSCy Schubert 					//xprintf(stderr, "apeervarlist refid: value=<%x>\n", i);
1810276da39aSCy Schubert 					}
18112d4e511cSCy Schubert 					//xprintf(stderr, "apeervarlist refid: value=<%s>\n", value);
1812276da39aSCy Schubert 				} else {
1813276da39aSCy Schubert 					have_da_rid = FALSE;
1814276da39aSCy Schubert 				}
1815ea906c41SOllivier Robert 			}
18162b15cb3dSCy Schubert 		} else if (!strcmp("stratum", name)) {
18172b15cb3dSCy Schubert 			decodeuint(value, &stratum);
18182b15cb3dSCy Schubert 		} else if (!strcmp("hpoll", name)) {
18192b15cb3dSCy Schubert 			if (decodeint(value, &hpoll) && hpoll < 0)
1820ea906c41SOllivier Robert 				hpoll = NTP_MINPOLL;
18212b15cb3dSCy Schubert 		} else if (!strcmp("ppoll", name)) {
18222b15cb3dSCy Schubert 			if (decodeint(value, &ppoll) && ppoll < 0)
1823ea906c41SOllivier Robert 				ppoll = NTP_MINPOLL;
18242b15cb3dSCy Schubert 		} else if (!strcmp("reach", name)) {
18252b15cb3dSCy Schubert 			decodeuint(value, &reach);
18262b15cb3dSCy Schubert 		} else if (!strcmp("delay", name)) {
18272b15cb3dSCy Schubert 			decodetime(value, &estdelay);
18282b15cb3dSCy Schubert 		} else if (!strcmp("offset", name)) {
18292b15cb3dSCy Schubert 			decodetime(value, &estoffset);
18302b15cb3dSCy Schubert 		} else if (!strcmp("jitter", name)) {
1831276da39aSCy Schubert 			if ((pvl == peervarlist || pvl == apeervarlist)
1832276da39aSCy Schubert 			    && decodetime(value, &estjitter))
18332b15cb3dSCy Schubert 				have_jitter = 1;
18342b15cb3dSCy Schubert 		} else if (!strcmp("rootdisp", name) ||
18352b15cb3dSCy Schubert 			   !strcmp("dispersion", name)) {
18362b15cb3dSCy Schubert 			decodetime(value, &estdisp);
18372b15cb3dSCy Schubert 		} else if (!strcmp("rec", name)) {
18382b15cb3dSCy Schubert 			decodets(value, &rec);
18392b15cb3dSCy Schubert 		} else if (!strcmp("srcport", name) ||
18402b15cb3dSCy Schubert 			   !strcmp("peerport", name)) {
18412b15cb3dSCy Schubert 			decodeuint(value, &srcport);
18422b15cb3dSCy Schubert 		} else if (!strcmp("reftime", name)) {
1843ea906c41SOllivier Robert 			if (!decodets(value, &reftime))
1844ea906c41SOllivier Robert 				L_CLR(&reftime);
18454e1ef62aSXin LI 		} else if (!strcmp("flash", name)) {
18464e1ef62aSXin LI 		    decodeuint(value, &flash);
1847276da39aSCy Schubert 		} else {
18482d4e511cSCy Schubert 			// xprintf(stderr, "UNRECOGNIZED name=%s ", name);
1849ea906c41SOllivier Robert 		}
1850ea906c41SOllivier Robert 	}
1851ea906c41SOllivier Robert 
1852ea906c41SOllivier Robert 	/*
18532b15cb3dSCy Schubert 	 * hmode gives the best guidance for the t column.  If the response
18542b15cb3dSCy Schubert 	 * did not include hmode we'll use the old decodeaddrtype() result.
1855ea906c41SOllivier Robert 	 */
18562b15cb3dSCy Schubert 	switch (hmode) {
18572b15cb3dSCy Schubert 
18582b15cb3dSCy Schubert 	case MODE_BCLIENT:
18592b15cb3dSCy Schubert 		/* broadcastclient or multicastclient */
18602b15cb3dSCy Schubert 		type = 'b';
18612b15cb3dSCy Schubert 		break;
18622b15cb3dSCy Schubert 
18632b15cb3dSCy Schubert 	case MODE_BROADCAST:
18642b15cb3dSCy Schubert 		/* broadcast or multicast server */
18652b15cb3dSCy Schubert 		if (IS_MCAST(&srcadr))
18662b15cb3dSCy Schubert 			type = 'M';
18672b15cb3dSCy Schubert 		else
18682b15cb3dSCy Schubert 			type = 'B';
18692b15cb3dSCy Schubert 		break;
18702b15cb3dSCy Schubert 
18712b15cb3dSCy Schubert 	case MODE_CLIENT:
18722b15cb3dSCy Schubert 		if (ISREFCLOCKADR(&srcadr))
18732b15cb3dSCy Schubert 			type = 'l';	/* local refclock*/
18742b15cb3dSCy Schubert 		else if (SOCK_UNSPEC(&srcadr))
18752b15cb3dSCy Schubert 			type = 'p';	/* pool */
18762b15cb3dSCy Schubert 		else if (IS_MCAST(&srcadr))
18772b15cb3dSCy Schubert 			type = 'a';	/* manycastclient */
18782b15cb3dSCy Schubert 		else
18792b15cb3dSCy Schubert 			type = 'u';	/* unicast */
18802b15cb3dSCy Schubert 		break;
18812b15cb3dSCy Schubert 
18822b15cb3dSCy Schubert 	case MODE_ACTIVE:
18832b15cb3dSCy Schubert 		type = 's';		/* symmetric active */
18842b15cb3dSCy Schubert 		break;			/* configured */
18852b15cb3dSCy Schubert 
18862b15cb3dSCy Schubert 	case MODE_PASSIVE:
18872b15cb3dSCy Schubert 		type = 'S';		/* symmetric passive */
18882b15cb3dSCy Schubert 		break;			/* ephemeral */
18892b15cb3dSCy Schubert 	}
1890ea906c41SOllivier Robert 
1891ea906c41SOllivier Robert 	/*
1892ea906c41SOllivier Robert 	 * Got everything, format the line
1893ea906c41SOllivier Robert 	 */
18942b15cb3dSCy Schubert 	poll_sec = 1 << min(ppoll, hpoll);
1895ea906c41SOllivier Robert 	if (pktversion > NTP_OLDVERSION)
1896ea906c41SOllivier Robert 		c = flash3[CTL_PEER_STATVAL(rstatus) & 0x7];
1897ea906c41SOllivier Robert 	else
1898ea906c41SOllivier Robert 		c = flash2[CTL_PEER_STATVAL(rstatus) & 0x3];
18992b15cb3dSCy Schubert 	if (numhosts > 1) {
1900276da39aSCy Schubert 		if ((pvl == peervarlist || pvl == apeervarlist)
1901276da39aSCy Schubert 		    && have_dstadr) {
19022b15cb3dSCy Schubert 			serverlocal = nntohost_col(&dstadr,
19032b15cb3dSCy Schubert 			    (size_t)min(LIB_BUFLENGTH - 1, maxhostlen),
19042b15cb3dSCy Schubert 			    TRUE);
19052b15cb3dSCy Schubert 		} else {
19062b15cb3dSCy Schubert 			if (currenthostisnum)
19072b15cb3dSCy Schubert 				serverlocal = trunc_left(currenthost,
19082b15cb3dSCy Schubert 							 maxhostlen);
19092b15cb3dSCy Schubert 			else
19102b15cb3dSCy Schubert 				serverlocal = currenthost;
19112b15cb3dSCy Schubert 		}
19122d4e511cSCy Schubert 		xprintf(fp, "%-*s ", (int)maxhostlen, serverlocal);
19132b15cb3dSCy Schubert 	}
19142b15cb3dSCy Schubert 	if (AF_UNSPEC == af || AF(&srcadr) == af) {
19152b15cb3dSCy Schubert 		if (!have_srchost)
19162b15cb3dSCy Schubert 			strlcpy(clock_name, nntohost(&srcadr),
19172b15cb3dSCy Schubert 				sizeof(clock_name));
191809100258SXin LI 		/* wide and long source - space over on next line */
191909100258SXin LI 		/* allow for host + sp if > 1 and regular tally + source + sp */
19202b15cb3dSCy Schubert 		if (wideremote && 15 < strlen(clock_name))
19212d4e511cSCy Schubert 			xprintf(fp, "%c%s\n%*s", c, clock_name,
192209100258SXin LI 				((numhosts > 1) ? (int)maxhostlen + 1 : 0)
192309100258SXin LI 							+ 1 + 15 + 1, "");
19242b15cb3dSCy Schubert 		else
19252d4e511cSCy Schubert 			xprintf(fp, "%c%-15.15s ", c, clock_name);
19264e1ef62aSXin LI 		if ((flash & TEST12) && (pvl != opeervarlist)) {
19272d4e511cSCy Schubert 			drlen = xprintf(fp, "(loop)");
19284e1ef62aSXin LI 		} else if (!have_da_rid) {
19292b15cb3dSCy Schubert 			drlen = 0;
19302b15cb3dSCy Schubert 		} else {
19312b15cb3dSCy Schubert 			drlen = strlen(dstadr_refid);
19322b15cb3dSCy Schubert 			makeascii(drlen, dstadr_refid, fp);
19332b15cb3dSCy Schubert 		}
1934276da39aSCy Schubert 		if (pvl == apeervarlist) {
1935276da39aSCy Schubert 			while (drlen++ < 9)
19362d4e511cSCy Schubert 				xputc(' ', fp);
19372d4e511cSCy Schubert 			xprintf(fp, "%-6d", associd);
1938276da39aSCy Schubert 		} else {
19392b15cb3dSCy Schubert 			while (drlen++ < 15)
19402d4e511cSCy Schubert 				xputc(' ', fp);
1941276da39aSCy Schubert 		}
19422d4e511cSCy Schubert 		xprintf(fp,
19432b15cb3dSCy Schubert 			" %2ld %c %4.4s %4.4s  %3lo  %7.7s %8.7s %7.7s\n",
19442b15cb3dSCy Schubert 			stratum, type,
19452b15cb3dSCy Schubert 			prettyinterval(whenbuf, sizeof(whenbuf),
19462b15cb3dSCy Schubert 				       when(&ts, &rec, &reftime)),
19472b15cb3dSCy Schubert 			prettyinterval(pollbuf, sizeof(pollbuf),
19482b15cb3dSCy Schubert 				       (int)poll_sec),
19492d4e511cSCy Schubert 			reach, ulfptoms(&estdelay, 3),
19502b15cb3dSCy Schubert 			lfptoms(&estoffset, 3),
19512b15cb3dSCy Schubert 			(have_jitter)
19522d4e511cSCy Schubert 			    ? ulfptoms(&estjitter, 3)
19532d4e511cSCy Schubert 			    : ulfptoms(&estdisp, 3));
1954ea906c41SOllivier Robert 		return (1);
1955ea906c41SOllivier Robert 	}
1956ea906c41SOllivier Robert 	else
1957ea906c41SOllivier Robert 		return(1);
1958ea906c41SOllivier Robert }
1959ea906c41SOllivier Robert 
1960ea906c41SOllivier Robert 
1961ea906c41SOllivier Robert /*
1962ea906c41SOllivier Robert  * dogetpeers - given an association ID, read and print the spreadsheet
1963ea906c41SOllivier Robert  *		peer variables.
1964ea906c41SOllivier Robert  */
1965ea906c41SOllivier Robert static int
1966ea906c41SOllivier Robert dogetpeers(
1967ea906c41SOllivier Robert 	struct varlist *pvl,
19682b15cb3dSCy Schubert 	associd_t associd,
1969ea906c41SOllivier Robert 	FILE *fp,
1970ea906c41SOllivier Robert 	int af
1971ea906c41SOllivier Robert 	)
1972ea906c41SOllivier Robert {
19732b15cb3dSCy Schubert 	const char *datap;
1974ea906c41SOllivier Robert 	int res;
19753311ff84SXin LI 	size_t dsize;
1976ea906c41SOllivier Robert 	u_short rstatus;
1977ea906c41SOllivier Robert 
1978ea906c41SOllivier Robert #ifdef notdef
1979ea906c41SOllivier Robert 	res = doquerylist(pvl, CTL_OP_READVAR, associd, 0, &rstatus,
1980ea906c41SOllivier Robert 			  &dsize, &datap);
1981ea906c41SOllivier Robert #else
1982ea906c41SOllivier Robert 	/*
1983ea906c41SOllivier Robert 	 * Damn fuzzballs
1984ea906c41SOllivier Robert 	 */
19852b15cb3dSCy Schubert 	res = doquery(CTL_OP_READVAR, associd, 0, 0, NULL, &rstatus,
1986ea906c41SOllivier Robert 			  &dsize, &datap);
1987ea906c41SOllivier Robert #endif
1988ea906c41SOllivier Robert 
1989ea906c41SOllivier Robert 	if (res != 0)
1990ea906c41SOllivier Robert 		return 0;
1991ea906c41SOllivier Robert 
1992ea906c41SOllivier Robert 	if (dsize == 0) {
1993ea906c41SOllivier Robert 		if (numhosts > 1)
19942d4e511cSCy Schubert 			xprintf(stderr, "server=%s ", currenthost);
19952d4e511cSCy Schubert 		xprintf(stderr,
19962b15cb3dSCy Schubert 			"***No information returned for association %u\n",
1997ea906c41SOllivier Robert 			associd);
1998ea906c41SOllivier Robert 		return 0;
1999ea906c41SOllivier Robert 	}
2000ea906c41SOllivier Robert 
20012b15cb3dSCy Schubert 	return doprintpeers(pvl, associd, (int)rstatus, dsize, datap,
20022b15cb3dSCy Schubert 			    fp, af);
2003ea906c41SOllivier Robert }
2004ea906c41SOllivier Robert 
2005ea906c41SOllivier Robert 
2006ea906c41SOllivier Robert /*
2007ea906c41SOllivier Robert  * peers - print a peer spreadsheet
2008ea906c41SOllivier Robert  */
2009ea906c41SOllivier Robert static void
2010ea906c41SOllivier Robert dopeers(
2011ea906c41SOllivier Robert 	int showall,
2012ea906c41SOllivier Robert 	FILE *fp,
2013ea906c41SOllivier Robert 	int af
2014ea906c41SOllivier Robert 	)
2015ea906c41SOllivier Robert {
20162b15cb3dSCy Schubert 	u_int		u;
2017ea906c41SOllivier Robert 	char		fullname[LENHOSTNAME];
20182b15cb3dSCy Schubert 	sockaddr_u	netnum;
20192b15cb3dSCy Schubert 	const char *	name_or_num;
20202b15cb3dSCy Schubert 	size_t		sl;
2021ea906c41SOllivier Robert 
2022ea906c41SOllivier Robert 	if (!dogetassoc(fp))
2023ea906c41SOllivier Robert 		return;
2024ea906c41SOllivier Robert 
2025*a466cc55SCy Schubert 	if (numhosts > 1) {
20262b15cb3dSCy Schubert 		for (u = 0; u < numhosts; u++) {
20272b15cb3dSCy Schubert 			if (getnetnum(chosts[u].name, &netnum, fullname, af)) {
20282b15cb3dSCy Schubert 				name_or_num = nntohost(&netnum);
20292b15cb3dSCy Schubert 				sl = strlen(name_or_num);
20302b15cb3dSCy Schubert 				maxhostlen = max(maxhostlen, sl);
20312b15cb3dSCy Schubert 			}
2032ea906c41SOllivier Robert 		}
20332d4e511cSCy Schubert 		xprintf(fp, "%-*.*s ", (int)maxhostlen, (int)maxhostlen,
20342b15cb3dSCy Schubert 			"server (local)");
2035*a466cc55SCy Schubert 	}
20362d4e511cSCy Schubert 	xprintf(fp,
2037ea906c41SOllivier Robert 		"     remote           refid      st t when poll reach   delay   offset  jitter\n");
2038ea906c41SOllivier Robert 	if (numhosts > 1)
20392b15cb3dSCy Schubert 		for (u = 0; u <= maxhostlen; u++)
20402d4e511cSCy Schubert 			xprintf(fp, "=");
20412d4e511cSCy Schubert 	xprintf(fp,
2042ea906c41SOllivier Robert 		"==============================================================================\n");
2043ea906c41SOllivier Robert 
20442b15cb3dSCy Schubert 	for (u = 0; u < numassoc; u++) {
2045ea906c41SOllivier Robert 		if (!showall &&
20462b15cb3dSCy Schubert 		    !(CTL_PEER_STATVAL(assoc_cache[u].status)
20472b15cb3dSCy Schubert 		      & (CTL_PST_CONFIG|CTL_PST_REACH))) {
20482b15cb3dSCy Schubert 			if (debug)
20492d4e511cSCy Schubert 				xprintf(stderr, "eliding [%d]\n",
20502b15cb3dSCy Schubert 					(int)assoc_cache[u].assid);
2051ea906c41SOllivier Robert 			continue;
2052ea906c41SOllivier Robert 		}
20532b15cb3dSCy Schubert 		if (!dogetpeers(peervarlist, (int)assoc_cache[u].assid,
20542b15cb3dSCy Schubert 				fp, af))
20552b15cb3dSCy Schubert 			return;
2056ea906c41SOllivier Robert 	}
2057ea906c41SOllivier Robert 	return;
2058ea906c41SOllivier Robert }
2059ea906c41SOllivier Robert 
2060ea906c41SOllivier Robert 
2061ea906c41SOllivier Robert /*
2062276da39aSCy Schubert  * doapeers - print a peer spreadsheet with assocIDs
2063276da39aSCy Schubert  */
2064276da39aSCy Schubert static void
2065276da39aSCy Schubert doapeers(
2066276da39aSCy Schubert 	int showall,
2067276da39aSCy Schubert 	FILE *fp,
2068276da39aSCy Schubert 	int af
2069276da39aSCy Schubert 	)
2070276da39aSCy Schubert {
2071276da39aSCy Schubert 	u_int		u;
2072276da39aSCy Schubert 	char		fullname[LENHOSTNAME];
2073276da39aSCy Schubert 	sockaddr_u	netnum;
2074276da39aSCy Schubert 	const char *	name_or_num;
2075276da39aSCy Schubert 	size_t		sl;
2076276da39aSCy Schubert 
2077276da39aSCy Schubert 	if (!dogetassoc(fp))
2078276da39aSCy Schubert 		return;
2079276da39aSCy Schubert 
2080*a466cc55SCy Schubert 	if (numhosts > 1) {
2081276da39aSCy Schubert 		for (u = 0; u < numhosts; u++) {
2082276da39aSCy Schubert 			if (getnetnum(chosts[u].name, &netnum, fullname, af)) {
2083276da39aSCy Schubert 				name_or_num = nntohost(&netnum);
2084276da39aSCy Schubert 				sl = strlen(name_or_num);
2085276da39aSCy Schubert 				maxhostlen = max(maxhostlen, sl);
2086276da39aSCy Schubert 			}
2087276da39aSCy Schubert 		}
20882d4e511cSCy Schubert 		xprintf(fp, "%-*.*s ", (int)maxhostlen, (int)maxhostlen,
2089276da39aSCy Schubert 			"server (local)");
2090*a466cc55SCy Schubert 	}
20912d4e511cSCy Schubert 	xprintf(fp,
2092276da39aSCy Schubert 		"     remote       refid   assid  st t when poll reach   delay   offset  jitter\n");
2093276da39aSCy Schubert 	if (numhosts > 1)
2094276da39aSCy Schubert 		for (u = 0; u <= maxhostlen; u++)
20952d4e511cSCy Schubert 			xprintf(fp, "=");
20962d4e511cSCy Schubert 	xprintf(fp,
2097276da39aSCy Schubert 		"==============================================================================\n");
2098276da39aSCy Schubert 
2099276da39aSCy Schubert 	for (u = 0; u < numassoc; u++) {
2100276da39aSCy Schubert 		if (!showall &&
2101276da39aSCy Schubert 		    !(CTL_PEER_STATVAL(assoc_cache[u].status)
2102276da39aSCy Schubert 		      & (CTL_PST_CONFIG|CTL_PST_REACH))) {
2103276da39aSCy Schubert 			if (debug)
21042d4e511cSCy Schubert 				xprintf(stderr, "eliding [%d]\n",
2105276da39aSCy Schubert 					(int)assoc_cache[u].assid);
2106276da39aSCy Schubert 			continue;
2107276da39aSCy Schubert 		}
2108276da39aSCy Schubert 		if (!dogetpeers(apeervarlist, (int)assoc_cache[u].assid,
2109276da39aSCy Schubert 				fp, af))
2110276da39aSCy Schubert 			return;
2111276da39aSCy Schubert 	}
2112276da39aSCy Schubert 	return;
2113276da39aSCy Schubert }
2114276da39aSCy Schubert 
2115276da39aSCy Schubert 
2116276da39aSCy Schubert /*
2117ea906c41SOllivier Robert  * peers - print a peer spreadsheet
2118ea906c41SOllivier Robert  */
2119ea906c41SOllivier Robert /*ARGSUSED*/
2120ea906c41SOllivier Robert static void
2121ea906c41SOllivier Robert peers(
2122ea906c41SOllivier Robert 	struct parse *pcmd,
2123ea906c41SOllivier Robert 	FILE *fp
2124ea906c41SOllivier Robert 	)
2125ea906c41SOllivier Robert {
21264990d495SXin LI 	if (drefid == REFID_HASH) {
21274990d495SXin LI 		apeers(pcmd, fp);
21284990d495SXin LI 	} else {
2129ea906c41SOllivier Robert 		int af = 0;
2130ea906c41SOllivier Robert 
2131ea906c41SOllivier Robert 		if (pcmd->nargs == 1) {
2132ea906c41SOllivier Robert 			if (pcmd->argval->ival == 6)
2133ea906c41SOllivier Robert 				af = AF_INET6;
2134ea906c41SOllivier Robert 			else
2135ea906c41SOllivier Robert 				af = AF_INET;
2136ea906c41SOllivier Robert 		}
2137ea906c41SOllivier Robert 		dopeers(0, fp, af);
2138ea906c41SOllivier Robert 	}
21394990d495SXin LI }
2140ea906c41SOllivier Robert 
2141ea906c41SOllivier Robert 
2142ea906c41SOllivier Robert /*
2143276da39aSCy Schubert  * apeers - print a peer spreadsheet, with assocIDs
2144276da39aSCy Schubert  */
2145276da39aSCy Schubert /*ARGSUSED*/
2146276da39aSCy Schubert static void
2147276da39aSCy Schubert apeers(
2148276da39aSCy Schubert 	struct parse *pcmd,
2149276da39aSCy Schubert 	FILE *fp
2150276da39aSCy Schubert 	)
2151276da39aSCy Schubert {
2152276da39aSCy Schubert 	int af = 0;
2153276da39aSCy Schubert 
2154276da39aSCy Schubert 	if (pcmd->nargs == 1) {
2155276da39aSCy Schubert 		if (pcmd->argval->ival == 6)
2156276da39aSCy Schubert 			af = AF_INET6;
2157276da39aSCy Schubert 		else
2158276da39aSCy Schubert 			af = AF_INET;
2159276da39aSCy Schubert 	}
2160276da39aSCy Schubert 	doapeers(0, fp, af);
2161276da39aSCy Schubert }
2162276da39aSCy Schubert 
2163276da39aSCy Schubert 
2164276da39aSCy Schubert /*
2165ea906c41SOllivier Robert  * lpeers - print a peer spreadsheet including all fuzzball peers
2166ea906c41SOllivier Robert  */
2167ea906c41SOllivier Robert /*ARGSUSED*/
2168ea906c41SOllivier Robert static void
2169ea906c41SOllivier Robert lpeers(
2170ea906c41SOllivier Robert 	struct parse *pcmd,
2171ea906c41SOllivier Robert 	FILE *fp
2172ea906c41SOllivier Robert 	)
2173ea906c41SOllivier Robert {
2174ea906c41SOllivier Robert 	int af = 0;
2175ea906c41SOllivier Robert 
2176ea906c41SOllivier Robert 	if (pcmd->nargs == 1) {
2177ea906c41SOllivier Robert 		if (pcmd->argval->ival == 6)
2178ea906c41SOllivier Robert 			af = AF_INET6;
2179ea906c41SOllivier Robert 		else
2180ea906c41SOllivier Robert 			af = AF_INET;
2181ea906c41SOllivier Robert 	}
2182ea906c41SOllivier Robert 	dopeers(1, fp, af);
2183ea906c41SOllivier Robert }
2184ea906c41SOllivier Robert 
2185ea906c41SOllivier Robert 
2186ea906c41SOllivier Robert /*
2187ea906c41SOllivier Robert  * opeers - print a peer spreadsheet
2188ea906c41SOllivier Robert  */
2189ea906c41SOllivier Robert static void
2190ea906c41SOllivier Robert doopeers(
2191ea906c41SOllivier Robert 	int showall,
2192ea906c41SOllivier Robert 	FILE *fp,
2193ea906c41SOllivier Robert 	int af
2194ea906c41SOllivier Robert 	)
2195ea906c41SOllivier Robert {
21962b15cb3dSCy Schubert 	u_int i;
2197ea906c41SOllivier Robert 	char fullname[LENHOSTNAME];
21982b15cb3dSCy Schubert 	sockaddr_u netnum;
2199ea906c41SOllivier Robert 
2200ea906c41SOllivier Robert 	if (!dogetassoc(fp))
2201ea906c41SOllivier Robert 		return;
2202ea906c41SOllivier Robert 
2203*a466cc55SCy Schubert 	if (numhosts > 1) {
2204ea906c41SOllivier Robert 		for (i = 0; i < numhosts; ++i) {
2205*a466cc55SCy Schubert 			if (getnetnum(chosts[i].name, &netnum, fullname, af)) {
2206*a466cc55SCy Schubert 				maxhostlen = max(maxhostlen, strlen(fullname));
2207ea906c41SOllivier Robert 			}
22082d4e511cSCy Schubert 			xprintf(fp, "%-*.*s ", (int)maxhostlen, (int)maxhostlen,
22092b15cb3dSCy Schubert 				"server");
2210*a466cc55SCy Schubert 		}
2211*a466cc55SCy Schubert 	}
22122d4e511cSCy Schubert 	xprintf(fp,
2213ea906c41SOllivier Robert 	    "     remote           local      st t when poll reach   delay   offset    disp\n");
2214ea906c41SOllivier Robert 	if (numhosts > 1)
2215ea906c41SOllivier Robert 		for (i = 0; i <= maxhostlen; ++i)
22162d4e511cSCy Schubert 			xprintf(fp, "=");
22172d4e511cSCy Schubert 	xprintf(fp,
2218ea906c41SOllivier Robert 	    "==============================================================================\n");
2219ea906c41SOllivier Robert 
2220ea906c41SOllivier Robert 	for (i = 0; i < numassoc; i++) {
2221ea906c41SOllivier Robert 		if (!showall &&
22222b15cb3dSCy Schubert 		    !(CTL_PEER_STATVAL(assoc_cache[i].status) &
22232b15cb3dSCy Schubert 		      (CTL_PST_CONFIG | CTL_PST_REACH)))
2224ea906c41SOllivier Robert 			continue;
22252b15cb3dSCy Schubert 		if (!dogetpeers(opeervarlist, assoc_cache[i].assid, fp, af))
2226ea906c41SOllivier Robert 			return;
2227ea906c41SOllivier Robert 	}
2228ea906c41SOllivier Robert 	return;
2229ea906c41SOllivier Robert }
2230ea906c41SOllivier Robert 
2231ea906c41SOllivier Robert 
2232ea906c41SOllivier Robert /*
2233ea906c41SOllivier Robert  * opeers - print a peer spreadsheet the old way
2234ea906c41SOllivier Robert  */
2235ea906c41SOllivier Robert /*ARGSUSED*/
2236ea906c41SOllivier Robert static void
2237ea906c41SOllivier Robert opeers(
2238ea906c41SOllivier Robert 	struct parse *pcmd,
2239ea906c41SOllivier Robert 	FILE *fp
2240ea906c41SOllivier Robert 	)
2241ea906c41SOllivier Robert {
2242ea906c41SOllivier Robert 	int af = 0;
2243ea906c41SOllivier Robert 
2244ea906c41SOllivier Robert 	if (pcmd->nargs == 1) {
2245ea906c41SOllivier Robert 		if (pcmd->argval->ival == 6)
2246ea906c41SOllivier Robert 			af = AF_INET6;
2247ea906c41SOllivier Robert 		else
2248ea906c41SOllivier Robert 			af = AF_INET;
2249ea906c41SOllivier Robert 	}
2250ea906c41SOllivier Robert 	doopeers(0, fp, af);
2251ea906c41SOllivier Robert }
2252ea906c41SOllivier Robert 
2253ea906c41SOllivier Robert 
2254ea906c41SOllivier Robert /*
2255ea906c41SOllivier Robert  * lopeers - print a peer spreadsheet including all fuzzball peers
2256ea906c41SOllivier Robert  */
2257ea906c41SOllivier Robert /*ARGSUSED*/
2258ea906c41SOllivier Robert static void
2259ea906c41SOllivier Robert lopeers(
2260ea906c41SOllivier Robert 	struct parse *pcmd,
2261ea906c41SOllivier Robert 	FILE *fp
2262ea906c41SOllivier Robert 	)
2263ea906c41SOllivier Robert {
2264ea906c41SOllivier Robert 	int af = 0;
2265ea906c41SOllivier Robert 
2266ea906c41SOllivier Robert 	if (pcmd->nargs == 1) {
2267ea906c41SOllivier Robert 		if (pcmd->argval->ival == 6)
2268ea906c41SOllivier Robert 			af = AF_INET6;
2269ea906c41SOllivier Robert 		else
2270ea906c41SOllivier Robert 			af = AF_INET;
2271ea906c41SOllivier Robert 	}
2272ea906c41SOllivier Robert 	doopeers(1, fp, af);
2273ea906c41SOllivier Robert }
22742b15cb3dSCy Schubert 
22752b15cb3dSCy Schubert 
22762b15cb3dSCy Schubert /*
22772b15cb3dSCy Schubert  * config - send a configuration command to a remote host
22782b15cb3dSCy Schubert  */
22792b15cb3dSCy Schubert static void
22802b15cb3dSCy Schubert config (
22812b15cb3dSCy Schubert 	struct parse *pcmd,
22822b15cb3dSCy Schubert 	FILE *fp
22832b15cb3dSCy Schubert 	)
22842b15cb3dSCy Schubert {
22852b15cb3dSCy Schubert 	const char *cfgcmd;
22862b15cb3dSCy Schubert 	u_short rstatus;
22873311ff84SXin LI 	size_t rsize;
22882b15cb3dSCy Schubert 	const char *rdata;
22892b15cb3dSCy Schubert 	char *resp;
22902b15cb3dSCy Schubert 	int res;
22912b15cb3dSCy Schubert 	int col;
22922b15cb3dSCy Schubert 	int i;
22932b15cb3dSCy Schubert 
22942b15cb3dSCy Schubert 	cfgcmd = pcmd->argval[0].string;
22952b15cb3dSCy Schubert 
22962b15cb3dSCy Schubert 	if (debug > 2)
22972d4e511cSCy Schubert 		xprintf(stderr,
22982b15cb3dSCy Schubert 			"In Config\n"
22992b15cb3dSCy Schubert 			"Keyword = %s\n"
23002b15cb3dSCy Schubert 			"Command = %s\n", pcmd->keyword, cfgcmd);
23012b15cb3dSCy Schubert 
23023311ff84SXin LI 	res = doquery(CTL_OP_CONFIGURE, 0, 1,
23033311ff84SXin LI 		      strlen(cfgcmd), cfgcmd,
23042b15cb3dSCy Schubert 		      &rstatus, &rsize, &rdata);
23052b15cb3dSCy Schubert 
23062b15cb3dSCy Schubert 	if (res != 0)
23072b15cb3dSCy Schubert 		return;
23082b15cb3dSCy Schubert 
23092b15cb3dSCy Schubert 	if (rsize > 0 && '\n' == rdata[rsize - 1])
23102b15cb3dSCy Schubert 		rsize--;
23112b15cb3dSCy Schubert 
23122b15cb3dSCy Schubert 	resp = emalloc(rsize + 1);
23132b15cb3dSCy Schubert 	memcpy(resp, rdata, rsize);
23142b15cb3dSCy Schubert 	resp[rsize] = '\0';
23152b15cb3dSCy Schubert 
23162b15cb3dSCy Schubert 	col = -1;
23172b15cb3dSCy Schubert 	if (1 == sscanf(resp, "column %d syntax error", &col)
23182b15cb3dSCy Schubert 	    && col >= 0 && (size_t)col <= strlen(cfgcmd) + 1) {
231909100258SXin LI 		if (interactive)
23202d4e511cSCy Schubert 			xputs("             *", stdout); /* "ntpq> :config " */
232109100258SXin LI 		else
23222b15cb3dSCy Schubert 			printf("%s\n", cfgcmd);
232309100258SXin LI 		for (i = 0; i < col; i++)
23242d4e511cSCy Schubert 			xputc('_', stdout);
23252d4e511cSCy Schubert 		xputs("^\n", stdout);
23262b15cb3dSCy Schubert 	}
23272b15cb3dSCy Schubert 	printf("%s\n", resp);
23282b15cb3dSCy Schubert 	free(resp);
23292b15cb3dSCy Schubert }
23302b15cb3dSCy Schubert 
23312b15cb3dSCy Schubert 
23322b15cb3dSCy Schubert /*
23332b15cb3dSCy Schubert  * config_from_file - remotely configure an ntpd daemon using the
23342b15cb3dSCy Schubert  * specified configuration file
23352b15cb3dSCy Schubert  * SK: This function is a kludge at best and is full of bad design
23362b15cb3dSCy Schubert  * bugs:
23372b15cb3dSCy Schubert  * 1. ntpq uses UDP, which means that there is no guarantee of in-order,
23382b15cb3dSCy Schubert  *    error-free delivery.
23392b15cb3dSCy Schubert  * 2. The maximum length of a packet is constrained, and as a result, the
23402b15cb3dSCy Schubert  *    maximum length of a line in a configuration file is constrained.
23412b15cb3dSCy Schubert  *    Longer lines will lead to unpredictable results.
23422b15cb3dSCy Schubert  * 3. Since this function is sending a line at a time, we can't update
23432b15cb3dSCy Schubert  *    the control key through the configuration file (YUCK!!)
23444990d495SXin LI  *
23454990d495SXin LI  * Pearly: There are a few places where 'size_t' is cast to 'int' based
23464990d495SXin LI  * on the assumption that 'int' can hold the size of the involved
23474990d495SXin LI  * buffers without overflow.
23482b15cb3dSCy Schubert  */
23492b15cb3dSCy Schubert static void
23502b15cb3dSCy Schubert config_from_file (
23512b15cb3dSCy Schubert 	struct parse *pcmd,
23522b15cb3dSCy Schubert 	FILE *fp
23532b15cb3dSCy Schubert 	)
23542b15cb3dSCy Schubert {
23552b15cb3dSCy Schubert 	u_short rstatus;
23563311ff84SXin LI 	size_t rsize;
23572b15cb3dSCy Schubert 	const char *rdata;
23584990d495SXin LI 	char * cp;
23592b15cb3dSCy Schubert 	int res;
23602b15cb3dSCy Schubert 	FILE *config_fd;
23612b15cb3dSCy Schubert 	char config_cmd[MAXLINE];
23622b15cb3dSCy Schubert 	size_t config_len;
23632b15cb3dSCy Schubert 	int i;
23642b15cb3dSCy Schubert 	int retry_limit;
23652b15cb3dSCy Schubert 
23662b15cb3dSCy Schubert 	if (debug > 2)
23672d4e511cSCy Schubert 		xprintf(stderr,
23682b15cb3dSCy Schubert 			"In Config\n"
23692b15cb3dSCy Schubert 			"Keyword = %s\n"
23702b15cb3dSCy Schubert 			"Filename = %s\n", pcmd->keyword,
23712b15cb3dSCy Schubert 			pcmd->argval[0].string);
23722b15cb3dSCy Schubert 
23732b15cb3dSCy Schubert 	config_fd = fopen(pcmd->argval[0].string, "r");
23742b15cb3dSCy Schubert 	if (NULL == config_fd) {
23752b15cb3dSCy Schubert 		printf("ERROR!! Couldn't open file: %s\n",
23762b15cb3dSCy Schubert 		       pcmd->argval[0].string);
23772b15cb3dSCy Schubert 		return;
23782b15cb3dSCy Schubert 	}
23792b15cb3dSCy Schubert 
23802b15cb3dSCy Schubert 	printf("Sending configuration file, one line at a time.\n");
23812b15cb3dSCy Schubert 	i = 0;
23822b15cb3dSCy Schubert 	while (fgets(config_cmd, MAXLINE, config_fd) != NULL) {
23834990d495SXin LI 		/* Eliminate comments first. */
23844990d495SXin LI 		cp = strchr(config_cmd, '#');
23854990d495SXin LI 		config_len = (NULL != cp)
23864990d495SXin LI 		    ? (size_t)(cp - config_cmd)
23874990d495SXin LI 		    : strlen(config_cmd);
23884990d495SXin LI 
23894990d495SXin LI 		/* [Bug 3015] make sure there's no trailing whitespace;
23904990d495SXin LI 		 * the fix for [Bug 2853] on the server side forbids
23914990d495SXin LI 		 * those. And don't transmit empty lines, as this would
23924990d495SXin LI 		 * just be waste.
23934990d495SXin LI 		 */
23944990d495SXin LI 		while (config_len != 0 &&
23954990d495SXin LI 		       (u_char)config_cmd[config_len-1] <= ' ')
23964990d495SXin LI 			--config_len;
23974990d495SXin LI 		config_cmd[config_len] = '\0';
23984990d495SXin LI 
23992b15cb3dSCy Schubert 		++i;
24004990d495SXin LI 		if (0 == config_len)
24014990d495SXin LI 			continue;
24024990d495SXin LI 
24032b15cb3dSCy Schubert 		retry_limit = 2;
24042b15cb3dSCy Schubert 		do
24052b15cb3dSCy Schubert 			res = doquery(CTL_OP_CONFIGURE, 0, 1,
24064990d495SXin LI 				      config_len, config_cmd,
24072b15cb3dSCy Schubert 				      &rstatus, &rsize, &rdata);
24082b15cb3dSCy Schubert 		while (res != 0 && retry_limit--);
24092b15cb3dSCy Schubert 		if (res != 0) {
24104990d495SXin LI 			printf("Line No: %d query failed: %.*s\n"
24114990d495SXin LI 			       "Subsequent lines not sent.\n",
24124990d495SXin LI 			       i, (int)config_len, config_cmd);
24132b15cb3dSCy Schubert 			fclose(config_fd);
24142b15cb3dSCy Schubert 			return;
24152b15cb3dSCy Schubert 		}
24162b15cb3dSCy Schubert 
24174990d495SXin LI 		/* Right-strip the result code string, then output the
24184990d495SXin LI 		 * last line executed, with result code. */
24194990d495SXin LI 		while (rsize != 0 && (u_char)rdata[rsize - 1] <= ' ')
24204990d495SXin LI 			--rsize;
24214990d495SXin LI 		printf("Line No: %d %.*s: %.*s\n", i,
24224990d495SXin LI 		       (int)rsize, rdata,
24234990d495SXin LI 		       (int)config_len, config_cmd);
24242b15cb3dSCy Schubert 	}
24252b15cb3dSCy Schubert 	printf("Done sending file\n");
24262b15cb3dSCy Schubert 	fclose(config_fd);
24272b15cb3dSCy Schubert }
24282b15cb3dSCy Schubert 
24292b15cb3dSCy Schubert 
24302b15cb3dSCy Schubert static int
24312b15cb3dSCy Schubert fetch_nonce(
24322b15cb3dSCy Schubert 	char *	nonce,
24332b15cb3dSCy Schubert 	size_t	cb_nonce
24342b15cb3dSCy Schubert 	)
24352b15cb3dSCy Schubert {
24362b15cb3dSCy Schubert 	const char	nonce_eq[] = "nonce=";
24372b15cb3dSCy Schubert 	int		qres;
24382b15cb3dSCy Schubert 	u_short		rstatus;
24393311ff84SXin LI 	size_t		rsize;
24402b15cb3dSCy Schubert 	const char *	rdata;
24413311ff84SXin LI 	size_t		chars;
24422b15cb3dSCy Schubert 
24432b15cb3dSCy Schubert 	/*
24442b15cb3dSCy Schubert 	 * Retrieve a nonce specific to this client to demonstrate to
24452b15cb3dSCy Schubert 	 * ntpd that we're capable of receiving responses to our source
24462b15cb3dSCy Schubert 	 * IP address, and thereby unlikely to be forging the source.
24472b15cb3dSCy Schubert 	 */
24482b15cb3dSCy Schubert 	qres = doquery(CTL_OP_REQ_NONCE, 0, 0, 0, NULL, &rstatus,
24492b15cb3dSCy Schubert 		       &rsize, &rdata);
24502b15cb3dSCy Schubert 	if (qres) {
24512d4e511cSCy Schubert 		xprintf(stderr, "nonce request failed\n");
24522b15cb3dSCy Schubert 		return FALSE;
24532b15cb3dSCy Schubert 	}
24542b15cb3dSCy Schubert 
24552b15cb3dSCy Schubert 	if ((size_t)rsize <= sizeof(nonce_eq) - 1 ||
24562b15cb3dSCy Schubert 	    strncmp(rdata, nonce_eq, sizeof(nonce_eq) - 1)) {
24572d4e511cSCy Schubert 		xprintf(stderr, "unexpected nonce response format: %.*s\n",
24583311ff84SXin LI 			(int)rsize, rdata); /* cast is wobbly */
24592b15cb3dSCy Schubert 		return FALSE;
24602b15cb3dSCy Schubert 	}
24612b15cb3dSCy Schubert 	chars = rsize - (sizeof(nonce_eq) - 1);
24624e1ef62aSXin LI 	if (chars >= cb_nonce)
24632b15cb3dSCy Schubert 		return FALSE;
24642b15cb3dSCy Schubert 	memcpy(nonce, rdata + sizeof(nonce_eq) - 1, chars);
24652b15cb3dSCy Schubert 	nonce[chars] = '\0';
24662b15cb3dSCy Schubert 	while (chars > 0 &&
24672b15cb3dSCy Schubert 	       ('\r' == nonce[chars - 1] || '\n' == nonce[chars - 1])) {
24682b15cb3dSCy Schubert 		chars--;
24692b15cb3dSCy Schubert 		nonce[chars] = '\0';
24702b15cb3dSCy Schubert 	}
24712b15cb3dSCy Schubert 
24722b15cb3dSCy Schubert 	return TRUE;
24732b15cb3dSCy Schubert }
24742b15cb3dSCy Schubert 
24752b15cb3dSCy Schubert 
24762b15cb3dSCy Schubert /*
24772b15cb3dSCy Schubert  * add_mru	Add and entry to mru list, hash table, and allocate
24782b15cb3dSCy Schubert  *		and return a replacement.
24792b15cb3dSCy Schubert  *		This is a helper for collect_mru_list().
24802b15cb3dSCy Schubert  */
24812b15cb3dSCy Schubert static mru *
24822b15cb3dSCy Schubert add_mru(
24832b15cb3dSCy Schubert 	mru *add
24842b15cb3dSCy Schubert 	)
24852b15cb3dSCy Schubert {
24862b15cb3dSCy Schubert 	u_short hash;
24872b15cb3dSCy Schubert 	mru *mon;
24882b15cb3dSCy Schubert 	mru *unlinked;
24892b15cb3dSCy Schubert 
24902b15cb3dSCy Schubert 
24912b15cb3dSCy Schubert 	hash = NTP_HASH_ADDR(&add->addr);
24922b15cb3dSCy Schubert 	/* see if we have it among previously received entries */
24932b15cb3dSCy Schubert 	for (mon = hash_table[hash]; mon != NULL; mon = mon->hlink)
24942b15cb3dSCy Schubert 		if (SOCK_EQ(&mon->addr, &add->addr))
24952b15cb3dSCy Schubert 			break;
24962b15cb3dSCy Schubert 	if (mon != NULL) {
24972b15cb3dSCy Schubert 		if (!L_ISGEQ(&add->first, &mon->first)) {
24982d4e511cSCy Schubert 			xprintf(stderr,
24992b15cb3dSCy Schubert 				"add_mru duplicate %s new first ts %08x.%08x precedes prior %08x.%08x\n",
25002b15cb3dSCy Schubert 				sptoa(&add->addr), add->last.l_ui,
25012b15cb3dSCy Schubert 				add->last.l_uf, mon->last.l_ui,
25022b15cb3dSCy Schubert 				mon->last.l_uf);
25032b15cb3dSCy Schubert 			exit(1);
25042b15cb3dSCy Schubert 		}
25052b15cb3dSCy Schubert 		UNLINK_DLIST(mon, mlink);
25062b15cb3dSCy Schubert 		UNLINK_SLIST(unlinked, hash_table[hash], mon, hlink, mru);
25079034852cSGleb Smirnoff 		INSIST(unlinked == mon);
25082b15cb3dSCy Schubert 		mru_dupes++;
25092b15cb3dSCy Schubert 		TRACE(2, ("(updated from %08x.%08x) ", mon->last.l_ui,
25102b15cb3dSCy Schubert 		      mon->last.l_uf));
25112b15cb3dSCy Schubert 	}
25122b15cb3dSCy Schubert 	LINK_DLIST(mru_list, add, mlink);
25132b15cb3dSCy Schubert 	LINK_SLIST(hash_table[hash], add, hlink);
25142b15cb3dSCy Schubert 	TRACE(2, ("add_mru %08x.%08x c %d m %d v %d rest %x first %08x.%08x %s\n",
25152b15cb3dSCy Schubert 	      add->last.l_ui, add->last.l_uf, add->count,
25162b15cb3dSCy Schubert 	      (int)add->mode, (int)add->ver, (u_int)add->rs,
25172b15cb3dSCy Schubert 	      add->first.l_ui, add->first.l_uf, sptoa(&add->addr)));
25182b15cb3dSCy Schubert 	/* if we didn't update an existing entry, alloc replacement */
25192b15cb3dSCy Schubert 	if (NULL == mon) {
25202b15cb3dSCy Schubert 		mon = emalloc(sizeof(*mon));
25212b15cb3dSCy Schubert 		mru_count++;
25222b15cb3dSCy Schubert 	}
25232b15cb3dSCy Schubert 	ZERO(*mon);
25242b15cb3dSCy Schubert 
25252b15cb3dSCy Schubert 	return mon;
25262b15cb3dSCy Schubert }
25272b15cb3dSCy Schubert 
25282b15cb3dSCy Schubert 
25292b15cb3dSCy Schubert /* MGOT macro is specific to collect_mru_list() */
25302b15cb3dSCy Schubert #define MGOT(bit)				\
25312b15cb3dSCy Schubert 	do {					\
25322b15cb3dSCy Schubert 		got |= (bit);			\
25332b15cb3dSCy Schubert 		if (MRU_GOT_ALL == got) {	\
25342b15cb3dSCy Schubert 			got = 0;		\
25352b15cb3dSCy Schubert 			mon = add_mru(mon);	\
25362b15cb3dSCy Schubert 			ci++;			\
25372b15cb3dSCy Schubert 		}				\
25382b15cb3dSCy Schubert 	} while (0)
25392b15cb3dSCy Schubert 
25402b15cb3dSCy Schubert 
25413311ff84SXin LI int
25422b15cb3dSCy Schubert mrulist_ctrl_c_hook(void)
25432b15cb3dSCy Schubert {
25442b15cb3dSCy Schubert 	mrulist_interrupted = TRUE;
25453311ff84SXin LI 	return TRUE;
25462b15cb3dSCy Schubert }
25472b15cb3dSCy Schubert 
25482b15cb3dSCy Schubert 
25492b15cb3dSCy Schubert static int
25502b15cb3dSCy Schubert collect_mru_list(
25512b15cb3dSCy Schubert 	const char *	parms,
25522b15cb3dSCy Schubert 	l_fp *		pnow
25532b15cb3dSCy Schubert 	)
25542b15cb3dSCy Schubert {
25552b15cb3dSCy Schubert 	const u_int sleep_msecs = 5;
25562b15cb3dSCy Schubert 	static int ntpd_row_limit = MRU_ROW_LIMIT;
25572b15cb3dSCy Schubert 	int c_mru_l_rc;		/* this function's return code */
25582b15cb3dSCy Schubert 	u_char got;		/* MRU_GOT_* bits */
25592b15cb3dSCy Schubert 	time_t next_report;
25602b15cb3dSCy Schubert 	size_t cb;
25612b15cb3dSCy Schubert 	mru *mon;
25622b15cb3dSCy Schubert 	mru *head;
25632b15cb3dSCy Schubert 	mru *recent;
25642b15cb3dSCy Schubert 	int list_complete;
25652b15cb3dSCy Schubert 	char nonce[128];
25662b15cb3dSCy Schubert 	char buf[128];
25672b15cb3dSCy Schubert 	char req_buf[CTL_MAX_DATA_LEN];
25682b15cb3dSCy Schubert 	char *req;
25692b15cb3dSCy Schubert 	char *req_end;
25703311ff84SXin LI 	size_t chars;
25712b15cb3dSCy Schubert 	int qres;
25722b15cb3dSCy Schubert 	u_short rstatus;
25733311ff84SXin LI 	size_t rsize;
25742b15cb3dSCy Schubert 	const char *rdata;
25752b15cb3dSCy Schubert 	int limit;
25762b15cb3dSCy Schubert 	int frags;
25772b15cb3dSCy Schubert 	int cap_frags;
25782b15cb3dSCy Schubert 	char *tag;
25792b15cb3dSCy Schubert 	char *val;
25802b15cb3dSCy Schubert 	int si;		/* server index in response */
25812b15cb3dSCy Schubert 	int ci;		/* client (our) index for validation */
25822b15cb3dSCy Schubert 	int ri;		/* request index (.# suffix) */
25832b15cb3dSCy Schubert 	int mv;
25842b15cb3dSCy Schubert 	l_fp newest;
25852b15cb3dSCy Schubert 	l_fp last_older;
25862b15cb3dSCy Schubert 	sockaddr_u addr_older;
25872b15cb3dSCy Schubert 	int have_now;
25882b15cb3dSCy Schubert 	int have_addr_older;
25892b15cb3dSCy Schubert 	int have_last_older;
25902b15cb3dSCy Schubert 	u_int restarted_count;
25912b15cb3dSCy Schubert 	u_int nonce_uses;
25922b15cb3dSCy Schubert 	u_short hash;
25932b15cb3dSCy Schubert 	mru *unlinked;
25942b15cb3dSCy Schubert 
25952b15cb3dSCy Schubert 	if (!fetch_nonce(nonce, sizeof(nonce)))
25962b15cb3dSCy Schubert 		return FALSE;
25972b15cb3dSCy Schubert 
25982b15cb3dSCy Schubert 	nonce_uses = 0;
25992b15cb3dSCy Schubert 	restarted_count = 0;
26002b15cb3dSCy Schubert 	mru_count = 0;
26012b15cb3dSCy Schubert 	INIT_DLIST(mru_list, mlink);
26022b15cb3dSCy Schubert 	cb = NTP_HASH_SIZE * sizeof(*hash_table);
26039034852cSGleb Smirnoff 	INSIST(NULL == hash_table);
26042b15cb3dSCy Schubert 	hash_table = emalloc_zero(cb);
26052b15cb3dSCy Schubert 
26062b15cb3dSCy Schubert 	c_mru_l_rc = FALSE;
26072b15cb3dSCy Schubert 	list_complete = FALSE;
26082b15cb3dSCy Schubert 	have_now = FALSE;
26092b15cb3dSCy Schubert 	cap_frags = TRUE;
26102b15cb3dSCy Schubert 	got = 0;
26112b15cb3dSCy Schubert 	ri = 0;
26122b15cb3dSCy Schubert 	cb = sizeof(*mon);
26132b15cb3dSCy Schubert 	mon = emalloc_zero(cb);
26142b15cb3dSCy Schubert 	ZERO(*pnow);
26152b15cb3dSCy Schubert 	ZERO(last_older);
26162b15cb3dSCy Schubert 	next_report = time(NULL) + MRU_REPORT_SECS;
26172b15cb3dSCy Schubert 
26182b15cb3dSCy Schubert 	limit = min(3 * MAXFRAGS, ntpd_row_limit);
26192b15cb3dSCy Schubert 	frags = MAXFRAGS;
26202b15cb3dSCy Schubert 	snprintf(req_buf, sizeof(req_buf), "nonce=%s, frags=%d%s",
26212b15cb3dSCy Schubert 		 nonce, frags, parms);
26222b15cb3dSCy Schubert 	nonce_uses++;
26232b15cb3dSCy Schubert 
26242b15cb3dSCy Schubert 	while (TRUE) {
26252b15cb3dSCy Schubert 		if (debug)
26262d4e511cSCy Schubert 			xprintf(stderr, "READ_MRU parms: %s\n", req_buf);
26272b15cb3dSCy Schubert 
26283311ff84SXin LI 		qres = doqueryex(CTL_OP_READ_MRU, 0, 0,
26293311ff84SXin LI 				 strlen(req_buf), req_buf,
26303311ff84SXin LI 				 &rstatus, &rsize, &rdata, TRUE);
26312b15cb3dSCy Schubert 
26322b15cb3dSCy Schubert 		if (CERR_UNKNOWNVAR == qres && ri > 0) {
26332b15cb3dSCy Schubert 			/*
26342b15cb3dSCy Schubert 			 * None of the supplied prior entries match, so
26352b15cb3dSCy Schubert 			 * toss them from our list and try again.
26362b15cb3dSCy Schubert 			 */
26372b15cb3dSCy Schubert 			if (debug)
26382d4e511cSCy Schubert 				xprintf(stderr,
26392b15cb3dSCy Schubert 					"no overlap between %d prior entries and server MRU list\n",
26402b15cb3dSCy Schubert 					ri);
26412b15cb3dSCy Schubert 			while (ri--) {
26422b15cb3dSCy Schubert 				recent = HEAD_DLIST(mru_list, mlink);
26439034852cSGleb Smirnoff 				INSIST(recent != NULL);
26442b15cb3dSCy Schubert 				if (debug)
26452d4e511cSCy Schubert 					xprintf(stderr,
26462b15cb3dSCy Schubert 						"tossing prior entry %s to resync\n",
26472b15cb3dSCy Schubert 						sptoa(&recent->addr));
26482b15cb3dSCy Schubert 				UNLINK_DLIST(recent, mlink);
26492b15cb3dSCy Schubert 				hash = NTP_HASH_ADDR(&recent->addr);
26502b15cb3dSCy Schubert 				UNLINK_SLIST(unlinked, hash_table[hash],
26512b15cb3dSCy Schubert 					     recent, hlink, mru);
26529034852cSGleb Smirnoff 				INSIST(unlinked == recent);
26532b15cb3dSCy Schubert 				free(recent);
26542b15cb3dSCy Schubert 				mru_count--;
26552b15cb3dSCy Schubert 			}
26562b15cb3dSCy Schubert 			if (NULL == HEAD_DLIST(mru_list, mlink)) {
26572b15cb3dSCy Schubert 				restarted_count++;
26582b15cb3dSCy Schubert 				if (restarted_count > 8) {
26592d4e511cSCy Schubert 					xprintf(stderr,
26602b15cb3dSCy Schubert 						"Giving up after 8 restarts from the beginning.\n"
26612b15cb3dSCy Schubert 						"With high-traffic NTP servers, this can occur if the\n"
26622b15cb3dSCy Schubert 						"MRU list is limited to less than about 16 seconds' of\n"
26632b15cb3dSCy Schubert 						"entries.  See the 'mru' ntp.conf directive to adjust.\n");
26642b15cb3dSCy Schubert 					goto cleanup_return;
26652b15cb3dSCy Schubert 				}
26662b15cb3dSCy Schubert 				if (debug)
26672d4e511cSCy Schubert 					xprintf(stderr,
26682b15cb3dSCy Schubert 						"--->   Restarting from the beginning, retry #%u\n",
26692b15cb3dSCy Schubert 						restarted_count);
26702b15cb3dSCy Schubert 			}
26712b15cb3dSCy Schubert 		} else if (CERR_UNKNOWNVAR == qres) {
26722d4e511cSCy Schubert 			xprintf(stderr,
26732b15cb3dSCy Schubert 				"CERR_UNKNOWNVAR from ntpd but no priors given.\n");
26742b15cb3dSCy Schubert 			goto cleanup_return;
26752b15cb3dSCy Schubert 		} else if (CERR_BADVALUE == qres) {
26762b15cb3dSCy Schubert 			if (cap_frags) {
26772b15cb3dSCy Schubert 				cap_frags = FALSE;
26782b15cb3dSCy Schubert 				if (debug)
26792d4e511cSCy Schubert 					xprintf(stderr,
26802b15cb3dSCy Schubert 						"Reverted to row limit from fragments limit.\n");
26812b15cb3dSCy Schubert 			} else {
26822b15cb3dSCy Schubert 				/* ntpd has lower cap on row limit */
26832b15cb3dSCy Schubert 				ntpd_row_limit--;
26842b15cb3dSCy Schubert 				limit = min(limit, ntpd_row_limit);
26852b15cb3dSCy Schubert 				if (debug)
26862d4e511cSCy Schubert 					xprintf(stderr,
26872b15cb3dSCy Schubert 						"Row limit reduced to %d following CERR_BADVALUE.\n",
26882b15cb3dSCy Schubert 						limit);
26892b15cb3dSCy Schubert 			}
26902b15cb3dSCy Schubert 		} else if (ERR_INCOMPLETE == qres ||
26912b15cb3dSCy Schubert 			   ERR_TIMEOUT == qres) {
26922b15cb3dSCy Schubert 			/*
26932b15cb3dSCy Schubert 			 * Reduce the number of rows/frags requested by
26942b15cb3dSCy Schubert 			 * half to recover from lost response fragments.
26952b15cb3dSCy Schubert 			 */
26962b15cb3dSCy Schubert 			if (cap_frags) {
26972b15cb3dSCy Schubert 				frags = max(2, frags / 2);
26982b15cb3dSCy Schubert 				if (debug)
26992d4e511cSCy Schubert 					xprintf(stderr,
27002b15cb3dSCy Schubert 						"Frag limit reduced to %d following incomplete response.\n",
27012b15cb3dSCy Schubert 						frags);
27022b15cb3dSCy Schubert 			} else {
27032b15cb3dSCy Schubert 				limit = max(2, limit / 2);
27042b15cb3dSCy Schubert 				if (debug)
27052d4e511cSCy Schubert 					xprintf(stderr,
27062b15cb3dSCy Schubert 						"Row limit reduced to %d following incomplete response.\n",
27072b15cb3dSCy Schubert 						limit);
27082b15cb3dSCy Schubert 			}
27092b15cb3dSCy Schubert 		} else if (qres) {
27102b15cb3dSCy Schubert 			show_error_msg(qres, 0);
27112b15cb3dSCy Schubert 			goto cleanup_return;
27122b15cb3dSCy Schubert 		}
27132b15cb3dSCy Schubert 		/*
27142b15cb3dSCy Schubert 		 * This is a cheap cop-out implementation of rawmode
27152b15cb3dSCy Schubert 		 * output for mrulist.  A better approach would be to
27162b15cb3dSCy Schubert 		 * dump similar output after the list is collected by
27172b15cb3dSCy Schubert 		 * ntpq with a continuous sequence of indexes.  This
27182b15cb3dSCy Schubert 		 * cheap approach has indexes resetting to zero for
27192b15cb3dSCy Schubert 		 * each query/response, and duplicates are not
27202b15cb3dSCy Schubert 		 * coalesced.
27212b15cb3dSCy Schubert 		 */
27222b15cb3dSCy Schubert 		if (!qres && rawmode)
27232b15cb3dSCy Schubert 			printvars(rsize, rdata, rstatus, TYPE_SYS, 1, stdout);
27242b15cb3dSCy Schubert 		ci = 0;
27252b15cb3dSCy Schubert 		have_addr_older = FALSE;
27262b15cb3dSCy Schubert 		have_last_older = FALSE;
27272b15cb3dSCy Schubert 		while (!qres && nextvar(&rsize, &rdata, &tag, &val)) {
27284e1ef62aSXin LI 			INSIST(tag && val);
27292b15cb3dSCy Schubert 			if (debug > 1)
27302d4e511cSCy Schubert 				xprintf(stderr, "nextvar gave: %s = %s\n",
27312b15cb3dSCy Schubert 					tag, val);
27322b15cb3dSCy Schubert 			switch(tag[0]) {
27332b15cb3dSCy Schubert 
27342b15cb3dSCy Schubert 			case 'a':
27352b15cb3dSCy Schubert 				if (!strcmp(tag, "addr.older")) {
27362b15cb3dSCy Schubert 					if (!have_last_older) {
27372d4e511cSCy Schubert 						xprintf(stderr,
27382b15cb3dSCy Schubert 							"addr.older %s before last.older\n",
27392b15cb3dSCy Schubert 							val);
27402b15cb3dSCy Schubert 						goto cleanup_return;
27412b15cb3dSCy Schubert 					}
27422b15cb3dSCy Schubert 					if (!decodenetnum(val, &addr_older)) {
27432d4e511cSCy Schubert 						xprintf(stderr,
27442b15cb3dSCy Schubert 							"addr.older %s garbled\n",
27452b15cb3dSCy Schubert 							val);
27462b15cb3dSCy Schubert 						goto cleanup_return;
27472b15cb3dSCy Schubert 					}
27482b15cb3dSCy Schubert 					hash = NTP_HASH_ADDR(&addr_older);
27492b15cb3dSCy Schubert 					for (recent = hash_table[hash];
27502b15cb3dSCy Schubert 					     recent != NULL;
27512b15cb3dSCy Schubert 					     recent = recent->hlink)
27522b15cb3dSCy Schubert 						if (ADDR_PORT_EQ(
27532b15cb3dSCy Schubert 						      &addr_older,
27542b15cb3dSCy Schubert 						      &recent->addr))
27552b15cb3dSCy Schubert 							break;
27562b15cb3dSCy Schubert 					if (NULL == recent) {
27572d4e511cSCy Schubert 						xprintf(stderr,
27582b15cb3dSCy Schubert 							"addr.older %s not in hash table\n",
27592b15cb3dSCy Schubert 							val);
27602b15cb3dSCy Schubert 						goto cleanup_return;
27612b15cb3dSCy Schubert 					}
27622b15cb3dSCy Schubert 					if (!L_ISEQU(&last_older,
27632b15cb3dSCy Schubert 						     &recent->last)) {
27642d4e511cSCy Schubert 						xprintf(stderr,
27652b15cb3dSCy Schubert 							"last.older %08x.%08x mismatches %08x.%08x expected.\n",
27662b15cb3dSCy Schubert 							last_older.l_ui,
27672b15cb3dSCy Schubert 							last_older.l_uf,
27682b15cb3dSCy Schubert 							recent->last.l_ui,
27692b15cb3dSCy Schubert 							recent->last.l_uf);
27702b15cb3dSCy Schubert 						goto cleanup_return;
27712b15cb3dSCy Schubert 					}
27722b15cb3dSCy Schubert 					have_addr_older = TRUE;
27732b15cb3dSCy Schubert 				} else if (1 != sscanf(tag, "addr.%d", &si)
27742b15cb3dSCy Schubert 					   || si != ci)
27752b15cb3dSCy Schubert 					goto nomatch;
27762b15cb3dSCy Schubert 				else if (decodenetnum(val, &mon->addr))
27772b15cb3dSCy Schubert 					MGOT(MRU_GOT_ADDR);
27782b15cb3dSCy Schubert 				break;
27792b15cb3dSCy Schubert 
27802b15cb3dSCy Schubert 			case 'l':
27812b15cb3dSCy Schubert 				if (!strcmp(tag, "last.older")) {
27822b15cb3dSCy Schubert 					if ('0' != val[0] ||
27832b15cb3dSCy Schubert 					    'x' != val[1] ||
27842b15cb3dSCy Schubert 					    !hextolfp(val + 2, &last_older)) {
27852d4e511cSCy Schubert 						xprintf(stderr,
27862b15cb3dSCy Schubert 							"last.older %s garbled\n",
27872b15cb3dSCy Schubert 							val);
27882b15cb3dSCy Schubert 						goto cleanup_return;
27892b15cb3dSCy Schubert 					}
27902b15cb3dSCy Schubert 					have_last_older = TRUE;
27912b15cb3dSCy Schubert 				} else if (!strcmp(tag, "last.newest")) {
27922b15cb3dSCy Schubert 					if (0 != got) {
27932d4e511cSCy Schubert 						xprintf(stderr,
27942b15cb3dSCy Schubert 							"last.newest %s before complete row, got = 0x%x\n",
27952b15cb3dSCy Schubert 							val, (u_int)got);
27962b15cb3dSCy Schubert 						goto cleanup_return;
27972b15cb3dSCy Schubert 					}
27982b15cb3dSCy Schubert 					if (!have_now) {
27992d4e511cSCy Schubert 						xprintf(stderr,
28002b15cb3dSCy Schubert 							"last.newest %s before now=\n",
28012b15cb3dSCy Schubert 							val);
28022b15cb3dSCy Schubert 						goto cleanup_return;
28032b15cb3dSCy Schubert 					}
28042b15cb3dSCy Schubert 					head = HEAD_DLIST(mru_list, mlink);
28052b15cb3dSCy Schubert 					if (NULL != head) {
28062b15cb3dSCy Schubert 						if ('0' != val[0] ||
28072b15cb3dSCy Schubert 						    'x' != val[1] ||
28082b15cb3dSCy Schubert 						    !hextolfp(val + 2, &newest) ||
28092b15cb3dSCy Schubert 						    !L_ISEQU(&newest,
28102b15cb3dSCy Schubert 							     &head->last)) {
28112d4e511cSCy Schubert 							xprintf(stderr,
28122b15cb3dSCy Schubert 								"last.newest %s mismatches %08x.%08x",
28132b15cb3dSCy Schubert 								val,
28142b15cb3dSCy Schubert 								head->last.l_ui,
28152b15cb3dSCy Schubert 								head->last.l_uf);
28162b15cb3dSCy Schubert 							goto cleanup_return;
28172b15cb3dSCy Schubert 						}
28182b15cb3dSCy Schubert 					}
28192b15cb3dSCy Schubert 					list_complete = TRUE;
28202b15cb3dSCy Schubert 				} else if (1 != sscanf(tag, "last.%d", &si) ||
28212b15cb3dSCy Schubert 					   si != ci || '0' != val[0] ||
28222b15cb3dSCy Schubert 					   'x' != val[1] ||
28232b15cb3dSCy Schubert 					   !hextolfp(val + 2, &mon->last)) {
28242b15cb3dSCy Schubert 					goto nomatch;
28252b15cb3dSCy Schubert 				} else {
28262b15cb3dSCy Schubert 					MGOT(MRU_GOT_LAST);
28272b15cb3dSCy Schubert 					/*
28282b15cb3dSCy Schubert 					 * allow interrupted retrieval,
28292b15cb3dSCy Schubert 					 * using most recent retrieved
28302b15cb3dSCy Schubert 					 * entry's last seen timestamp
28312b15cb3dSCy Schubert 					 * as the end of operation.
28322b15cb3dSCy Schubert 					 */
28332b15cb3dSCy Schubert 					*pnow = mon->last;
28342b15cb3dSCy Schubert 				}
28352b15cb3dSCy Schubert 				break;
28362b15cb3dSCy Schubert 
28372b15cb3dSCy Schubert 			case 'f':
28382b15cb3dSCy Schubert 				if (1 != sscanf(tag, "first.%d", &si) ||
28392b15cb3dSCy Schubert 				    si != ci || '0' != val[0] ||
28402b15cb3dSCy Schubert 				    'x' != val[1] ||
28412b15cb3dSCy Schubert 				    !hextolfp(val + 2, &mon->first))
28422b15cb3dSCy Schubert 					goto nomatch;
28432b15cb3dSCy Schubert 				MGOT(MRU_GOT_FIRST);
28442b15cb3dSCy Schubert 				break;
28452b15cb3dSCy Schubert 
28462b15cb3dSCy Schubert 			case 'n':
28472b15cb3dSCy Schubert 				if (!strcmp(tag, "nonce")) {
28482b15cb3dSCy Schubert 					strlcpy(nonce, val, sizeof(nonce));
28492b15cb3dSCy Schubert 					nonce_uses = 0;
28502b15cb3dSCy Schubert 					break; /* case */
28512b15cb3dSCy Schubert 				} else if (strcmp(tag, "now") ||
28522b15cb3dSCy Schubert 					   '0' != val[0] ||
28532b15cb3dSCy Schubert 					   'x' != val[1] ||
28542b15cb3dSCy Schubert 					    !hextolfp(val + 2, pnow))
28552b15cb3dSCy Schubert 					goto nomatch;
28562b15cb3dSCy Schubert 				have_now = TRUE;
28572b15cb3dSCy Schubert 				break;
28582b15cb3dSCy Schubert 
28592b15cb3dSCy Schubert 			case 'c':
28602b15cb3dSCy Schubert 				if (1 != sscanf(tag, "ct.%d", &si) ||
28612b15cb3dSCy Schubert 				    si != ci ||
28622b15cb3dSCy Schubert 				    1 != sscanf(val, "%d", &mon->count)
28632b15cb3dSCy Schubert 				    || mon->count < 1)
28642b15cb3dSCy Schubert 					goto nomatch;
28652b15cb3dSCy Schubert 				MGOT(MRU_GOT_COUNT);
28662b15cb3dSCy Schubert 				break;
28672b15cb3dSCy Schubert 
28682b15cb3dSCy Schubert 			case 'm':
28692b15cb3dSCy Schubert 				if (1 != sscanf(tag, "mv.%d", &si) ||
28702b15cb3dSCy Schubert 				    si != ci ||
28712b15cb3dSCy Schubert 				    1 != sscanf(val, "%d", &mv))
28722b15cb3dSCy Schubert 					goto nomatch;
28732b15cb3dSCy Schubert 				mon->mode = PKT_MODE(mv);
28742b15cb3dSCy Schubert 				mon->ver = PKT_VERSION(mv);
28752b15cb3dSCy Schubert 				MGOT(MRU_GOT_MV);
28762b15cb3dSCy Schubert 				break;
28772b15cb3dSCy Schubert 
28782b15cb3dSCy Schubert 			case 'r':
28792b15cb3dSCy Schubert 				if (1 != sscanf(tag, "rs.%d", &si) ||
28802b15cb3dSCy Schubert 				    si != ci ||
28812b15cb3dSCy Schubert 				    1 != sscanf(val, "0x%hx", &mon->rs))
28822b15cb3dSCy Schubert 					goto nomatch;
28832b15cb3dSCy Schubert 				MGOT(MRU_GOT_RS);
28842b15cb3dSCy Schubert 				break;
28852b15cb3dSCy Schubert 
28862b15cb3dSCy Schubert 			default:
28872b15cb3dSCy Schubert 			nomatch:
28882b15cb3dSCy Schubert 				/* empty stmt */ ;
28892b15cb3dSCy Schubert 				/* ignore unknown tags */
28902b15cb3dSCy Schubert 			}
28912b15cb3dSCy Schubert 		}
28922b15cb3dSCy Schubert 		if (have_now)
28932b15cb3dSCy Schubert 			list_complete = TRUE;
28942b15cb3dSCy Schubert 		if (list_complete) {
28959034852cSGleb Smirnoff 			INSIST(0 == ri || have_addr_older);
28962b15cb3dSCy Schubert 		}
28972b15cb3dSCy Schubert 		if (mrulist_interrupted) {
28982b15cb3dSCy Schubert 			printf("mrulist retrieval interrupted by operator.\n"
28992b15cb3dSCy Schubert 			       "Displaying partial client list.\n");
29002b15cb3dSCy Schubert 			fflush(stdout);
29012b15cb3dSCy Schubert 		}
29022b15cb3dSCy Schubert 		if (list_complete || mrulist_interrupted) {
29032d4e511cSCy Schubert 			xprintf(stderr,
29042b15cb3dSCy Schubert 				"\rRetrieved %u unique MRU entries and %u updates.\n",
29052b15cb3dSCy Schubert 				mru_count, mru_dupes);
29062b15cb3dSCy Schubert 			fflush(stderr);
29072b15cb3dSCy Schubert 			break;
29082b15cb3dSCy Schubert 		}
29092b15cb3dSCy Schubert 		if (time(NULL) >= next_report) {
29102b15cb3dSCy Schubert 			next_report += MRU_REPORT_SECS;
29112d4e511cSCy Schubert 			xprintf(stderr, "\r%u (%u updates) ", mru_count,
29122b15cb3dSCy Schubert 				mru_dupes);
29132b15cb3dSCy Schubert 			fflush(stderr);
29142b15cb3dSCy Schubert 		}
29152b15cb3dSCy Schubert 
29162b15cb3dSCy Schubert 		/*
29172b15cb3dSCy Schubert 		 * Snooze for a bit between queries to let ntpd catch
29182b15cb3dSCy Schubert 		 * up with other duties.
29192b15cb3dSCy Schubert 		 */
29202b15cb3dSCy Schubert #ifdef SYS_WINNT
29212b15cb3dSCy Schubert 		Sleep(sleep_msecs);
29222b15cb3dSCy Schubert #elif !defined(HAVE_NANOSLEEP)
29232b15cb3dSCy Schubert 		sleep((sleep_msecs / 1000) + 1);
29242b15cb3dSCy Schubert #else
29252b15cb3dSCy Schubert 		{
29262b15cb3dSCy Schubert 			struct timespec interv = { 0,
29272b15cb3dSCy Schubert 						   1000 * sleep_msecs };
29282b15cb3dSCy Schubert 			nanosleep(&interv, NULL);
29292b15cb3dSCy Schubert 		}
29302b15cb3dSCy Schubert #endif
29312b15cb3dSCy Schubert 		/*
29322b15cb3dSCy Schubert 		 * If there were no errors, increase the number of rows
29332b15cb3dSCy Schubert 		 * to a maximum of 3 * MAXFRAGS (the most packets ntpq
29342b15cb3dSCy Schubert 		 * can handle in one response), on the assumption that
29352b15cb3dSCy Schubert 		 * no less than 3 rows fit in each packet, capped at
29362b15cb3dSCy Schubert 		 * our best guess at the server's row limit.
29372b15cb3dSCy Schubert 		 */
29382b15cb3dSCy Schubert 		if (!qres) {
29392b15cb3dSCy Schubert 			if (cap_frags) {
29402b15cb3dSCy Schubert 				frags = min(MAXFRAGS, frags + 1);
29412b15cb3dSCy Schubert 			} else {
29422b15cb3dSCy Schubert 				limit = min3(3 * MAXFRAGS,
29432b15cb3dSCy Schubert 					     ntpd_row_limit,
29442b15cb3dSCy Schubert 					     max(limit + 1,
29452b15cb3dSCy Schubert 					         limit * 33 / 32));
29462b15cb3dSCy Schubert 			}
29472b15cb3dSCy Schubert 		}
29482b15cb3dSCy Schubert 		/*
29492b15cb3dSCy Schubert 		 * prepare next query with as many address and last-seen
29502b15cb3dSCy Schubert 		 * timestamps as will fit in a single packet.
29512b15cb3dSCy Schubert 		 */
29522b15cb3dSCy Schubert 		req = req_buf;
29532b15cb3dSCy Schubert 		req_end = req_buf + sizeof(req_buf);
29542b15cb3dSCy Schubert #define REQ_ROOM	(req_end - req)
29552b15cb3dSCy Schubert 		snprintf(req, REQ_ROOM, "nonce=%s, %s=%d%s", nonce,
29562b15cb3dSCy Schubert 			 (cap_frags)
29572b15cb3dSCy Schubert 			     ? "frags"
29582b15cb3dSCy Schubert 			     : "limit",
29592b15cb3dSCy Schubert 			 (cap_frags)
29602b15cb3dSCy Schubert 			     ? frags
29612b15cb3dSCy Schubert 			     : limit,
29622b15cb3dSCy Schubert 			 parms);
29632b15cb3dSCy Schubert 		req += strlen(req);
29642b15cb3dSCy Schubert 		nonce_uses++;
29652b15cb3dSCy Schubert 		if (nonce_uses >= 4) {
29662b15cb3dSCy Schubert 			if (!fetch_nonce(nonce, sizeof(nonce)))
29672b15cb3dSCy Schubert 				goto cleanup_return;
29682b15cb3dSCy Schubert 			nonce_uses = 0;
29692b15cb3dSCy Schubert 		}
29702b15cb3dSCy Schubert 
29712b15cb3dSCy Schubert 
29722b15cb3dSCy Schubert 		for (ri = 0, recent = HEAD_DLIST(mru_list, mlink);
29732b15cb3dSCy Schubert 		     recent != NULL;
29742b15cb3dSCy Schubert 		     ri++, recent = NEXT_DLIST(mru_list, recent, mlink)) {
29752b15cb3dSCy Schubert 
29762b15cb3dSCy Schubert 			snprintf(buf, sizeof(buf),
29772b15cb3dSCy Schubert 				 ", addr.%d=%s, last.%d=0x%08x.%08x",
29782b15cb3dSCy Schubert 				 ri, sptoa(&recent->addr), ri,
29792b15cb3dSCy Schubert 				 recent->last.l_ui, recent->last.l_uf);
29802b15cb3dSCy Schubert 			chars = strlen(buf);
298168ba7e87SXin LI 			if ((size_t)REQ_ROOM <= chars)
29822b15cb3dSCy Schubert 				break;
29832b15cb3dSCy Schubert 			memcpy(req, buf, chars + 1);
29842b15cb3dSCy Schubert 			req += chars;
29852b15cb3dSCy Schubert 		}
29862b15cb3dSCy Schubert 	}
29872b15cb3dSCy Schubert 
29882b15cb3dSCy Schubert 	c_mru_l_rc = TRUE;
29892b15cb3dSCy Schubert 	goto retain_hash_table;
29902b15cb3dSCy Schubert 
29912b15cb3dSCy Schubert cleanup_return:
29922b15cb3dSCy Schubert 	free(hash_table);
29932b15cb3dSCy Schubert 	hash_table = NULL;
29942b15cb3dSCy Schubert 
29952b15cb3dSCy Schubert retain_hash_table:
29962b15cb3dSCy Schubert 	if (mon != NULL)
29972b15cb3dSCy Schubert 		free(mon);
29982b15cb3dSCy Schubert 
29992b15cb3dSCy Schubert 	return c_mru_l_rc;
30002b15cb3dSCy Schubert }
30012b15cb3dSCy Schubert 
30022b15cb3dSCy Schubert 
30032b15cb3dSCy Schubert /*
30042b15cb3dSCy Schubert  * qcmp_mru_addr - sort MRU entries by remote address.
30052b15cb3dSCy Schubert  *
30062b15cb3dSCy Schubert  * All IPv4 addresses sort before any IPv6, addresses are sorted by
30072b15cb3dSCy Schubert  * value within address family.
30082b15cb3dSCy Schubert  */
30092b15cb3dSCy Schubert static int
30102b15cb3dSCy Schubert qcmp_mru_addr(
30112b15cb3dSCy Schubert 	const void *v1,
30122b15cb3dSCy Schubert 	const void *v2
30132b15cb3dSCy Schubert 	)
30142b15cb3dSCy Schubert {
30152b15cb3dSCy Schubert 	const mru * const *	ppm1 = v1;
30162b15cb3dSCy Schubert 	const mru * const *	ppm2 = v2;
30172b15cb3dSCy Schubert 	const mru *		pm1;
30182b15cb3dSCy Schubert 	const mru *		pm2;
30192b15cb3dSCy Schubert 	u_short			af1;
30202b15cb3dSCy Schubert 	u_short			af2;
30212b15cb3dSCy Schubert 	size_t			cmplen;
30222b15cb3dSCy Schubert 	size_t			addr_off;
30232b15cb3dSCy Schubert 
30242b15cb3dSCy Schubert 	pm1 = *ppm1;
30252b15cb3dSCy Schubert 	pm2 = *ppm2;
30262b15cb3dSCy Schubert 
30272b15cb3dSCy Schubert 	af1 = AF(&pm1->addr);
30282b15cb3dSCy Schubert 	af2 = AF(&pm2->addr);
30292b15cb3dSCy Schubert 
30302b15cb3dSCy Schubert 	if (af1 != af2)
30312b15cb3dSCy Schubert 		return (AF_INET == af1)
30322b15cb3dSCy Schubert 			   ? -1
30332b15cb3dSCy Schubert 			   : 1;
30342b15cb3dSCy Schubert 
30352b15cb3dSCy Schubert 	cmplen = SIZEOF_INADDR(af1);
30362b15cb3dSCy Schubert 	addr_off = (AF_INET == af1)
30372b15cb3dSCy Schubert 		      ? offsetof(struct sockaddr_in, sin_addr)
30382b15cb3dSCy Schubert 		      : offsetof(struct sockaddr_in6, sin6_addr);
30392b15cb3dSCy Schubert 
30402b15cb3dSCy Schubert 	return memcmp((const char *)&pm1->addr + addr_off,
30412b15cb3dSCy Schubert 		      (const char *)&pm2->addr + addr_off,
30422b15cb3dSCy Schubert 		      cmplen);
30432b15cb3dSCy Schubert }
30442b15cb3dSCy Schubert 
30452b15cb3dSCy Schubert 
30462b15cb3dSCy Schubert static int
30472b15cb3dSCy Schubert qcmp_mru_r_addr(
30482b15cb3dSCy Schubert 	const void *v1,
30492b15cb3dSCy Schubert 	const void *v2
30502b15cb3dSCy Schubert 	)
30512b15cb3dSCy Schubert {
30522b15cb3dSCy Schubert 	return -qcmp_mru_addr(v1, v2);
30532b15cb3dSCy Schubert }
30542b15cb3dSCy Schubert 
30552b15cb3dSCy Schubert 
30562b15cb3dSCy Schubert /*
30572b15cb3dSCy Schubert  * qcmp_mru_count - sort MRU entries by times seen (hit count).
30582b15cb3dSCy Schubert  */
30592b15cb3dSCy Schubert static int
30602b15cb3dSCy Schubert qcmp_mru_count(
30612b15cb3dSCy Schubert 	const void *v1,
30622b15cb3dSCy Schubert 	const void *v2
30632b15cb3dSCy Schubert 	)
30642b15cb3dSCy Schubert {
30652b15cb3dSCy Schubert 	const mru * const *	ppm1 = v1;
30662b15cb3dSCy Schubert 	const mru * const *	ppm2 = v2;
30672b15cb3dSCy Schubert 	const mru *		pm1;
30682b15cb3dSCy Schubert 	const mru *		pm2;
30692b15cb3dSCy Schubert 
30702b15cb3dSCy Schubert 	pm1 = *ppm1;
30712b15cb3dSCy Schubert 	pm2 = *ppm2;
30722b15cb3dSCy Schubert 
30732b15cb3dSCy Schubert 	return (pm1->count < pm2->count)
30742b15cb3dSCy Schubert 		   ? -1
30752b15cb3dSCy Schubert 		   : ((pm1->count == pm2->count)
30762b15cb3dSCy Schubert 			  ? 0
30772b15cb3dSCy Schubert 			  : 1);
30782b15cb3dSCy Schubert }
30792b15cb3dSCy Schubert 
30802b15cb3dSCy Schubert 
30812b15cb3dSCy Schubert static int
30822b15cb3dSCy Schubert qcmp_mru_r_count(
30832b15cb3dSCy Schubert 	const void *v1,
30842b15cb3dSCy Schubert 	const void *v2
30852b15cb3dSCy Schubert 	)
30862b15cb3dSCy Schubert {
30872b15cb3dSCy Schubert 	return -qcmp_mru_count(v1, v2);
30882b15cb3dSCy Schubert }
30892b15cb3dSCy Schubert 
30902b15cb3dSCy Schubert 
30912b15cb3dSCy Schubert /*
30922b15cb3dSCy Schubert  * qcmp_mru_avgint - sort MRU entries by average interval.
30932b15cb3dSCy Schubert  */
30942b15cb3dSCy Schubert static int
30952b15cb3dSCy Schubert qcmp_mru_avgint(
30962b15cb3dSCy Schubert 	const void *v1,
30972b15cb3dSCy Schubert 	const void *v2
30982b15cb3dSCy Schubert 	)
30992b15cb3dSCy Schubert {
31002b15cb3dSCy Schubert 	const mru * const *	ppm1 = v1;
31012b15cb3dSCy Schubert 	const mru * const *	ppm2 = v2;
31022b15cb3dSCy Schubert 	const mru *		pm1;
31032b15cb3dSCy Schubert 	const mru *		pm2;
31042b15cb3dSCy Schubert 	l_fp			interval;
31052b15cb3dSCy Schubert 	double			avg1;
31062b15cb3dSCy Schubert 	double			avg2;
31072b15cb3dSCy Schubert 
31082b15cb3dSCy Schubert 	pm1 = *ppm1;
31092b15cb3dSCy Schubert 	pm2 = *ppm2;
31102b15cb3dSCy Schubert 
31112b15cb3dSCy Schubert 	interval = pm1->last;
31122b15cb3dSCy Schubert 	L_SUB(&interval, &pm1->first);
31132b15cb3dSCy Schubert 	LFPTOD(&interval, avg1);
31142b15cb3dSCy Schubert 	avg1 /= pm1->count;
31152b15cb3dSCy Schubert 
31162b15cb3dSCy Schubert 	interval = pm2->last;
31172b15cb3dSCy Schubert 	L_SUB(&interval, &pm2->first);
31182b15cb3dSCy Schubert 	LFPTOD(&interval, avg2);
31192b15cb3dSCy Schubert 	avg2 /= pm2->count;
31202b15cb3dSCy Schubert 
31212b15cb3dSCy Schubert 	if (avg1 < avg2)
31222b15cb3dSCy Schubert 		return -1;
31232b15cb3dSCy Schubert 	else if (avg1 > avg2)
31242b15cb3dSCy Schubert 		return 1;
31252b15cb3dSCy Schubert 
31262b15cb3dSCy Schubert 	/* secondary sort on lstint - rarely tested */
31272b15cb3dSCy Schubert 	if (L_ISEQU(&pm1->last, &pm2->last))
31282b15cb3dSCy Schubert 		return 0;
31292b15cb3dSCy Schubert 	else if (L_ISGEQ(&pm1->last, &pm2->last))
31302b15cb3dSCy Schubert 		return -1;
31312b15cb3dSCy Schubert 	else
31322b15cb3dSCy Schubert 		return 1;
31332b15cb3dSCy Schubert }
31342b15cb3dSCy Schubert 
31352b15cb3dSCy Schubert 
31362b15cb3dSCy Schubert static int
31372b15cb3dSCy Schubert qcmp_mru_r_avgint(
31382b15cb3dSCy Schubert 	const void *v1,
31392b15cb3dSCy Schubert 	const void *v2
31402b15cb3dSCy Schubert 	)
31412b15cb3dSCy Schubert {
31422b15cb3dSCy Schubert 	return -qcmp_mru_avgint(v1, v2);
31432b15cb3dSCy Schubert }
31442b15cb3dSCy Schubert 
31452b15cb3dSCy Schubert 
31462b15cb3dSCy Schubert /*
31472b15cb3dSCy Schubert  * mrulist - ntpq's mrulist command to fetch an arbitrarily large Most
31482b15cb3dSCy Schubert  *	     Recently Used (seen) remote address list from ntpd.
31492b15cb3dSCy Schubert  *
31502b15cb3dSCy Schubert  * Similar to ntpdc's monlist command, but not limited to a single
31512b15cb3dSCy Schubert  * request/response, and thereby not limited to a few hundred remote
31522b15cb3dSCy Schubert  * addresses.
31532b15cb3dSCy Schubert  *
31542b15cb3dSCy Schubert  * See ntpd/ntp_control.c read_mru_list() for comments on the way
31552b15cb3dSCy Schubert  * CTL_OP_READ_MRU is designed to be used.
31562b15cb3dSCy Schubert  *
31572b15cb3dSCy Schubert  * mrulist intentionally differs from monlist in the way the avgint
31582b15cb3dSCy Schubert  * column is calculated.  monlist includes the time after the last
31592b15cb3dSCy Schubert  * packet from the client until the monlist query time in the average,
31602b15cb3dSCy Schubert  * while mrulist excludes it.  That is, monlist's average interval grows
31612b15cb3dSCy Schubert  * over time for remote addresses not heard from in some time, while it
31622b15cb3dSCy Schubert  * remains unchanged in mrulist.  This also affects the avgint value for
31632b15cb3dSCy Schubert  * entries representing a single packet, with identical first and last
31642b15cb3dSCy Schubert  * timestamps.  mrulist shows 0 avgint, monlist shows a value identical
31652b15cb3dSCy Schubert  * to lstint.
31662b15cb3dSCy Schubert  */
31672b15cb3dSCy Schubert static void
31682b15cb3dSCy Schubert mrulist(
31692b15cb3dSCy Schubert 	struct parse *	pcmd,
31702b15cb3dSCy Schubert 	FILE *		fp
31712b15cb3dSCy Schubert 	)
31722b15cb3dSCy Schubert {
31732b15cb3dSCy Schubert 	const char mincount_eq[] =	"mincount=";
31742b15cb3dSCy Schubert 	const char resall_eq[] =	"resall=";
31752b15cb3dSCy Schubert 	const char resany_eq[] =	"resany=";
31762b15cb3dSCy Schubert 	const char maxlstint_eq[] =	"maxlstint=";
31772b15cb3dSCy Schubert 	const char laddr_eq[] =		"laddr=";
31782b15cb3dSCy Schubert 	const char sort_eq[] =		"sort=";
31792b15cb3dSCy Schubert 	mru_sort_order order;
31802b15cb3dSCy Schubert 	size_t n;
31812b15cb3dSCy Schubert 	char parms_buf[128];
31822b15cb3dSCy Schubert 	char buf[24];
31832b15cb3dSCy Schubert 	char *parms;
31842b15cb3dSCy Schubert 	const char *arg;
31852b15cb3dSCy Schubert 	size_t cb;
31862b15cb3dSCy Schubert 	mru **sorted;
31872b15cb3dSCy Schubert 	mru **ppentry;
31882b15cb3dSCy Schubert 	mru *recent;
31892b15cb3dSCy Schubert 	l_fp now;
31902b15cb3dSCy Schubert 	l_fp interval;
31912b15cb3dSCy Schubert 	double favgint;
31922b15cb3dSCy Schubert 	double flstint;
31932b15cb3dSCy Schubert 	int avgint;
31942b15cb3dSCy Schubert 	int lstint;
31952b15cb3dSCy Schubert 	size_t i;
31962b15cb3dSCy Schubert 
31973311ff84SXin LI 	mrulist_interrupted = FALSE;
31983311ff84SXin LI 	push_ctrl_c_handler(&mrulist_ctrl_c_hook);
31992d4e511cSCy Schubert 	xprintf(stderr,
32003311ff84SXin LI 		"Ctrl-C will stop MRU retrieval and display partial results.\n");
32013311ff84SXin LI 	fflush(stderr);
32023311ff84SXin LI 
32032b15cb3dSCy Schubert 	order = MRUSORT_DEF;
32042b15cb3dSCy Schubert 	parms_buf[0] = '\0';
32052b15cb3dSCy Schubert 	parms = parms_buf;
32062b15cb3dSCy Schubert 	for (i = 0; i < pcmd->nargs; i++) {
32072b15cb3dSCy Schubert 		arg = pcmd->argval[i].string;
32082b15cb3dSCy Schubert 		if (arg != NULL) {
32092b15cb3dSCy Schubert 			cb = strlen(arg) + 1;
32102b15cb3dSCy Schubert 			if ((!strncmp(resall_eq, arg, sizeof(resall_eq)
32112b15cb3dSCy Schubert 			    - 1) || !strncmp(resany_eq, arg,
32122b15cb3dSCy Schubert 			    sizeof(resany_eq) - 1) || !strncmp(
32132b15cb3dSCy Schubert 			    mincount_eq, arg, sizeof(mincount_eq) - 1)
32142b15cb3dSCy Schubert 			    || !strncmp(laddr_eq, arg, sizeof(laddr_eq)
32152b15cb3dSCy Schubert 			    - 1) || !strncmp(maxlstint_eq, arg,
32162b15cb3dSCy Schubert 			    sizeof(laddr_eq) - 1)) && parms + cb + 2 <=
32172b15cb3dSCy Schubert 			    parms_buf + sizeof(parms_buf)) {
32182b15cb3dSCy Schubert 				/* these are passed intact to ntpd */
32192b15cb3dSCy Schubert 				memcpy(parms, ", ", 2);
32202b15cb3dSCy Schubert 				parms += 2;
32212b15cb3dSCy Schubert 				memcpy(parms, arg, cb);
32222b15cb3dSCy Schubert 				parms += cb - 1;
32232b15cb3dSCy Schubert 			} else if (!strncmp(sort_eq, arg,
32242b15cb3dSCy Schubert 					    sizeof(sort_eq) - 1)) {
32252b15cb3dSCy Schubert 				arg += sizeof(sort_eq) - 1;
32262b15cb3dSCy Schubert 				for (n = 0;
32272b15cb3dSCy Schubert 				     n < COUNTOF(mru_sort_keywords);
32282b15cb3dSCy Schubert 				     n++)
32292b15cb3dSCy Schubert 					if (!strcmp(mru_sort_keywords[n],
32302b15cb3dSCy Schubert 						    arg))
32312b15cb3dSCy Schubert 						break;
32322b15cb3dSCy Schubert 				if (n < COUNTOF(mru_sort_keywords))
32332b15cb3dSCy Schubert 					order = n;
32342b15cb3dSCy Schubert 			} else if (!strcmp("limited", arg) ||
32352b15cb3dSCy Schubert 				   !strcmp("kod", arg)) {
32362b15cb3dSCy Schubert 				/* transform to resany=... */
32372b15cb3dSCy Schubert 				snprintf(buf, sizeof(buf),
32382b15cb3dSCy Schubert 					 ", resany=0x%x",
32392b15cb3dSCy Schubert 					 ('k' == arg[0])
32402b15cb3dSCy Schubert 					     ? RES_KOD
32412b15cb3dSCy Schubert 					     : RES_LIMITED);
32422b15cb3dSCy Schubert 				cb = 1 + strlen(buf);
32432b15cb3dSCy Schubert 				if (parms + cb <
32442b15cb3dSCy Schubert 					parms_buf + sizeof(parms_buf)) {
32452b15cb3dSCy Schubert 					memcpy(parms, buf, cb);
32462b15cb3dSCy Schubert 					parms += cb - 1;
32472b15cb3dSCy Schubert 				}
32482b15cb3dSCy Schubert 			} else
32492d4e511cSCy Schubert 				xprintf(stderr,
32502b15cb3dSCy Schubert 					"ignoring unrecognized mrulist parameter: %s\n",
32512b15cb3dSCy Schubert 					arg);
32522b15cb3dSCy Schubert 		}
32532b15cb3dSCy Schubert 	}
32542b15cb3dSCy Schubert 	parms = parms_buf;
32552b15cb3dSCy Schubert 
32562b15cb3dSCy Schubert 	if (!collect_mru_list(parms, &now))
32572b15cb3dSCy Schubert 		return;
32582b15cb3dSCy Schubert 
32592b15cb3dSCy Schubert 	/* display the results */
32602b15cb3dSCy Schubert 	if (rawmode)
32612b15cb3dSCy Schubert 		goto cleanup_return;
32622b15cb3dSCy Schubert 
32632b15cb3dSCy Schubert 	/* construct an array of entry pointers in default order */
3264276da39aSCy Schubert 	sorted = eallocarray(mru_count, sizeof(*sorted));
32652b15cb3dSCy Schubert 	ppentry = sorted;
32662b15cb3dSCy Schubert 	if (MRUSORT_R_DEF != order) {
32672b15cb3dSCy Schubert 		ITER_DLIST_BEGIN(mru_list, recent, mlink, mru)
32689034852cSGleb Smirnoff 			INSIST(ppentry < sorted + mru_count);
32692b15cb3dSCy Schubert 			*ppentry = recent;
32702b15cb3dSCy Schubert 			ppentry++;
32712b15cb3dSCy Schubert 		ITER_DLIST_END()
32722b15cb3dSCy Schubert 	} else {
32732b15cb3dSCy Schubert 		REV_ITER_DLIST_BEGIN(mru_list, recent, mlink, mru)
32749034852cSGleb Smirnoff 			INSIST(ppentry < sorted + mru_count);
32752b15cb3dSCy Schubert 			*ppentry = recent;
32762b15cb3dSCy Schubert 			ppentry++;
32772b15cb3dSCy Schubert 		REV_ITER_DLIST_END()
32782b15cb3dSCy Schubert 	}
32792b15cb3dSCy Schubert 
32802b15cb3dSCy Schubert 	if (ppentry - sorted != (int)mru_count) {
32812d4e511cSCy Schubert 		xprintf(stderr,
32822b15cb3dSCy Schubert 			"mru_count %u should match MRU list depth %ld.\n",
32832b15cb3dSCy Schubert 			mru_count, (long)(ppentry - sorted));
32842b15cb3dSCy Schubert 		free(sorted);
32852b15cb3dSCy Schubert 		goto cleanup_return;
32862b15cb3dSCy Schubert 	}
32872b15cb3dSCy Schubert 
32882b15cb3dSCy Schubert 	/* re-sort sorted[] if not default or reverse default */
32892b15cb3dSCy Schubert 	if (MRUSORT_R_DEF < order)
32902b15cb3dSCy Schubert 		qsort(sorted, mru_count, sizeof(sorted[0]),
32912b15cb3dSCy Schubert 		      mru_qcmp_table[order]);
32922b15cb3dSCy Schubert 
329368ba7e87SXin LI 	mrulist_interrupted = FALSE;
32942b15cb3dSCy Schubert 	printf(	"lstint avgint rstr r m v  count rport remote address\n"
32952b15cb3dSCy Schubert 		"==============================================================================\n");
32962b15cb3dSCy Schubert 		/* '=' x 78 */
32972b15cb3dSCy Schubert 	for (ppentry = sorted; ppentry < sorted + mru_count; ppentry++) {
32982b15cb3dSCy Schubert 		recent = *ppentry;
32992b15cb3dSCy Schubert 		interval = now;
33002b15cb3dSCy Schubert 		L_SUB(&interval, &recent->last);
33012b15cb3dSCy Schubert 		LFPTOD(&interval, flstint);
33022b15cb3dSCy Schubert 		lstint = (int)(flstint + 0.5);
33032b15cb3dSCy Schubert 		interval = recent->last;
33042b15cb3dSCy Schubert 		L_SUB(&interval, &recent->first);
33052b15cb3dSCy Schubert 		LFPTOD(&interval, favgint);
33062b15cb3dSCy Schubert 		favgint /= recent->count;
33072b15cb3dSCy Schubert 		avgint = (int)(favgint + 0.5);
33082d4e511cSCy Schubert 		xprintf(fp, "%6d %6d %4hx %c %d %d %6d %5u %s\n",
33092b15cb3dSCy Schubert 			lstint, avgint, recent->rs,
33102b15cb3dSCy Schubert 			(RES_KOD & recent->rs)
33112b15cb3dSCy Schubert 			    ? 'K'
33122b15cb3dSCy Schubert 			    : (RES_LIMITED & recent->rs)
33132b15cb3dSCy Schubert 				  ? 'L'
33142b15cb3dSCy Schubert 				  : '.',
33152b15cb3dSCy Schubert 			(int)recent->mode, (int)recent->ver,
33162b15cb3dSCy Schubert 			recent->count, SRCPORT(&recent->addr),
33172b15cb3dSCy Schubert 			nntohost(&recent->addr));
33182b15cb3dSCy Schubert 		if (showhostnames)
33192b15cb3dSCy Schubert 			fflush(fp);
332068ba7e87SXin LI 		if (mrulist_interrupted) {
33212d4e511cSCy Schubert 			xputs("\n --interrupted--\n", fp);
332268ba7e87SXin LI 			fflush(fp);
332368ba7e87SXin LI 			break;
332468ba7e87SXin LI 		}
33252b15cb3dSCy Schubert 	}
33262b15cb3dSCy Schubert 	fflush(fp);
33272b15cb3dSCy Schubert 	if (debug) {
33282d4e511cSCy Schubert 		xprintf(stderr,
33292b15cb3dSCy Schubert 			"--- completed, freeing sorted[] pointers\n");
33302b15cb3dSCy Schubert 		fflush(stderr);
33312b15cb3dSCy Schubert 	}
33322b15cb3dSCy Schubert 	free(sorted);
33332b15cb3dSCy Schubert 
33342b15cb3dSCy Schubert cleanup_return:
33352b15cb3dSCy Schubert 	if (debug) {
33362d4e511cSCy Schubert 		xprintf(stderr, "... freeing MRU entries\n");
33372b15cb3dSCy Schubert 		fflush(stderr);
33382b15cb3dSCy Schubert 	}
33392b15cb3dSCy Schubert 	ITER_DLIST_BEGIN(mru_list, recent, mlink, mru)
33402b15cb3dSCy Schubert 		free(recent);
33412b15cb3dSCy Schubert 	ITER_DLIST_END()
33422b15cb3dSCy Schubert 	if (debug) {
33432d4e511cSCy Schubert 		xprintf(stderr, "... freeing hash_table[]\n");
33442b15cb3dSCy Schubert 		fflush(stderr);
33452b15cb3dSCy Schubert 	}
33462b15cb3dSCy Schubert 	free(hash_table);
33472b15cb3dSCy Schubert 	hash_table = NULL;
33482b15cb3dSCy Schubert 	INIT_DLIST(mru_list, mlink);
33493311ff84SXin LI 
33503311ff84SXin LI 	pop_ctrl_c_handler(&mrulist_ctrl_c_hook);
33512b15cb3dSCy Schubert }
33522b15cb3dSCy Schubert 
33532b15cb3dSCy Schubert 
33542b15cb3dSCy Schubert /*
33552b15cb3dSCy Schubert  * validate_ifnum - helper for ifstats()
33562b15cb3dSCy Schubert  *
33572b15cb3dSCy Schubert  * Ensures rows are received in order and complete.
33582b15cb3dSCy Schubert  */
33592b15cb3dSCy Schubert static void
33602b15cb3dSCy Schubert validate_ifnum(
33612b15cb3dSCy Schubert 	FILE *		fp,
33622b15cb3dSCy Schubert 	u_int		ifnum,
33632b15cb3dSCy Schubert 	int *		pfields,
33642b15cb3dSCy Schubert 	ifstats_row *	prow
33652b15cb3dSCy Schubert 	)
33662b15cb3dSCy Schubert {
33672b15cb3dSCy Schubert 	if (prow->ifnum == ifnum)
33682b15cb3dSCy Schubert 		return;
3369276da39aSCy Schubert 	if (prow->ifnum + 1 <= ifnum) {
33702b15cb3dSCy Schubert 		if (*pfields < IFSTATS_FIELDS)
33712d4e511cSCy Schubert 			xprintf(fp, "Warning: incomplete row with %d (of %d) fields\n",
33722b15cb3dSCy Schubert 				*pfields, IFSTATS_FIELDS);
33732b15cb3dSCy Schubert 		*pfields = 0;
33742b15cb3dSCy Schubert 		prow->ifnum = ifnum;
33752b15cb3dSCy Schubert 		return;
33762b15cb3dSCy Schubert 	}
33772d4e511cSCy Schubert 	xprintf(stderr,
33782b15cb3dSCy Schubert 		"received if index %u, have %d of %d fields for index %u, aborting.\n",
33792b15cb3dSCy Schubert 		ifnum, *pfields, IFSTATS_FIELDS, prow->ifnum);
33802b15cb3dSCy Schubert 	exit(1);
33812b15cb3dSCy Schubert }
33822b15cb3dSCy Schubert 
33832b15cb3dSCy Schubert 
33842b15cb3dSCy Schubert /*
33852b15cb3dSCy Schubert  * another_ifstats_field - helper for ifstats()
33862b15cb3dSCy Schubert  *
33872b15cb3dSCy Schubert  * If all fields for the row have been received, print it.
33882b15cb3dSCy Schubert  */
33892b15cb3dSCy Schubert static void
33902b15cb3dSCy Schubert another_ifstats_field(
33912b15cb3dSCy Schubert 	int *		pfields,
33922b15cb3dSCy Schubert 	ifstats_row *	prow,
33932b15cb3dSCy Schubert 	FILE *		fp
33942b15cb3dSCy Schubert 	)
33952b15cb3dSCy Schubert {
33962b15cb3dSCy Schubert 	u_int ifnum;
33972b15cb3dSCy Schubert 
33982b15cb3dSCy Schubert 	(*pfields)++;
33992b15cb3dSCy Schubert 	/* we understand 12 tags */
34002b15cb3dSCy Schubert 	if (IFSTATS_FIELDS > *pfields)
34012b15cb3dSCy Schubert 		return;
34022b15cb3dSCy Schubert 	/*
34032b15cb3dSCy Schubert 	"    interface name                                        send\n"
34042b15cb3dSCy Schubert 	" #  address/broadcast     drop flag ttl mc received sent failed peers   uptime\n"
34052b15cb3dSCy Schubert 	"==============================================================================\n");
34062b15cb3dSCy Schubert 	 */
34072d4e511cSCy Schubert 	xprintf(fp,
340809100258SXin LI 		"%3u %-24.24s %c %4x %3u %2u %6u %6u %6u %5u %8d\n"
34092b15cb3dSCy Schubert 		"    %s\n",
34102b15cb3dSCy Schubert 		prow->ifnum, prow->name,
34112b15cb3dSCy Schubert 		(prow->enabled)
34122b15cb3dSCy Schubert 		    ? '.'
34132b15cb3dSCy Schubert 		    : 'D',
34142b15cb3dSCy Schubert 		prow->flags, prow->ttl, prow->mcast_count,
34152b15cb3dSCy Schubert 		prow->received, prow->sent, prow->send_errors,
34162b15cb3dSCy Schubert 		prow->peer_count, prow->uptime, sptoa(&prow->addr));
34172b15cb3dSCy Schubert 	if (!SOCK_UNSPEC(&prow->bcast))
34182d4e511cSCy Schubert 		xprintf(fp, "    %s\n", sptoa(&prow->bcast));
34192b15cb3dSCy Schubert 	ifnum = prow->ifnum;
34202b15cb3dSCy Schubert 	ZERO(*prow);
34212b15cb3dSCy Schubert 	prow->ifnum = ifnum;
34222b15cb3dSCy Schubert }
34232b15cb3dSCy Schubert 
34242b15cb3dSCy Schubert 
34252b15cb3dSCy Schubert /*
34262b15cb3dSCy Schubert  * ifstats - ntpq -c ifstats modeled on ntpdc -c ifstats.
34272b15cb3dSCy Schubert  */
34282b15cb3dSCy Schubert static void
34292b15cb3dSCy Schubert ifstats(
34302b15cb3dSCy Schubert 	struct parse *	pcmd,
34312b15cb3dSCy Schubert 	FILE *		fp
34322b15cb3dSCy Schubert 	)
34332b15cb3dSCy Schubert {
34342b15cb3dSCy Schubert 	const char	addr_fmt[] =	"addr.%u";
34352b15cb3dSCy Schubert 	const char	bcast_fmt[] =	"bcast.%u";
34362b15cb3dSCy Schubert 	const char	en_fmt[] =	"en.%u";	/* enabled */
34372b15cb3dSCy Schubert 	const char	flags_fmt[] =	"flags.%u";
34382b15cb3dSCy Schubert 	const char	mc_fmt[] =	"mc.%u";	/* mcast count */
34392b15cb3dSCy Schubert 	const char	name_fmt[] =	"name.%u";
34402b15cb3dSCy Schubert 	const char	pc_fmt[] =	"pc.%u";	/* peer count */
34412b15cb3dSCy Schubert 	const char	rx_fmt[] =	"rx.%u";
34422b15cb3dSCy Schubert 	const char	tl_fmt[] =	"tl.%u";	/* ttl */
34432b15cb3dSCy Schubert 	const char	tx_fmt[] =	"tx.%u";
34442b15cb3dSCy Schubert 	const char	txerr_fmt[] =	"txerr.%u";
34452b15cb3dSCy Schubert 	const char	up_fmt[] =	"up.%u";	/* uptime */
34462b15cb3dSCy Schubert 	const char *	datap;
34472b15cb3dSCy Schubert 	int		qres;
34483311ff84SXin LI 	size_t		dsize;
34492b15cb3dSCy Schubert 	u_short		rstatus;
34502b15cb3dSCy Schubert 	char *		tag;
34512b15cb3dSCy Schubert 	char *		val;
34522b15cb3dSCy Schubert 	int		fields;
34532b15cb3dSCy Schubert 	u_int		ui;
34542b15cb3dSCy Schubert 	ifstats_row	row;
34552b15cb3dSCy Schubert 	int		comprende;
34562b15cb3dSCy Schubert 	size_t		len;
34572b15cb3dSCy Schubert 
34582b15cb3dSCy Schubert 	qres = doquery(CTL_OP_READ_ORDLIST_A, 0, TRUE, 0, NULL, &rstatus,
34592b15cb3dSCy Schubert 		       &dsize, &datap);
34602b15cb3dSCy Schubert 	if (qres)	/* message already displayed */
34612b15cb3dSCy Schubert 		return;
34622b15cb3dSCy Schubert 
34632d4e511cSCy Schubert 	xprintf(fp,
34642b15cb3dSCy Schubert 		"    interface name                                        send\n"
34652b15cb3dSCy Schubert 		" #  address/broadcast     drop flag ttl mc received sent failed peers   uptime\n"
34662b15cb3dSCy Schubert 		"==============================================================================\n");
34672b15cb3dSCy Schubert 		/* '=' x 78 */
34682b15cb3dSCy Schubert 
34692b15cb3dSCy Schubert 	ZERO(row);
34702b15cb3dSCy Schubert 	fields = 0;
34712b15cb3dSCy Schubert 	ui = 0;
34722b15cb3dSCy Schubert 	while (nextvar(&dsize, &datap, &tag, &val)) {
34734e1ef62aSXin LI 		INSIST(tag && val);
34742b15cb3dSCy Schubert 		if (debug > 1)
34752d4e511cSCy Schubert 		    xprintf(stderr, "nextvar gave: %s = %s\n", tag, val);
34762b15cb3dSCy Schubert 		comprende = FALSE;
34772b15cb3dSCy Schubert 		switch(tag[0]) {
34782b15cb3dSCy Schubert 
34792b15cb3dSCy Schubert 		case 'a':
34802b15cb3dSCy Schubert 			if (1 == sscanf(tag, addr_fmt, &ui) &&
34812b15cb3dSCy Schubert 			    decodenetnum(val, &row.addr))
34822b15cb3dSCy Schubert 				comprende = TRUE;
34832b15cb3dSCy Schubert 			break;
34842b15cb3dSCy Schubert 
34852b15cb3dSCy Schubert 		case 'b':
34862b15cb3dSCy Schubert 			if (1 == sscanf(tag, bcast_fmt, &ui) &&
34874e1ef62aSXin LI 			    ('\0' == *val ||
34882b15cb3dSCy Schubert 			     decodenetnum(val, &row.bcast)))
34892b15cb3dSCy Schubert 				comprende = TRUE;
34902b15cb3dSCy Schubert 			break;
34912b15cb3dSCy Schubert 
34922b15cb3dSCy Schubert 		case 'e':
34932b15cb3dSCy Schubert 			if (1 == sscanf(tag, en_fmt, &ui) &&
34942b15cb3dSCy Schubert 			    1 == sscanf(val, "%d", &row.enabled))
34952b15cb3dSCy Schubert 				comprende = TRUE;
34962b15cb3dSCy Schubert 			break;
34972b15cb3dSCy Schubert 
34982b15cb3dSCy Schubert 		case 'f':
34992b15cb3dSCy Schubert 			if (1 == sscanf(tag, flags_fmt, &ui) &&
35002b15cb3dSCy Schubert 			    1 == sscanf(val, "0x%x", &row.flags))
35012b15cb3dSCy Schubert 				comprende = TRUE;
35022b15cb3dSCy Schubert 			break;
35032b15cb3dSCy Schubert 
35042b15cb3dSCy Schubert 		case 'm':
35052b15cb3dSCy Schubert 			if (1 == sscanf(tag, mc_fmt, &ui) &&
350609100258SXin LI 			    1 == sscanf(val, "%u", &row.mcast_count))
35072b15cb3dSCy Schubert 				comprende = TRUE;
35082b15cb3dSCy Schubert 			break;
35092b15cb3dSCy Schubert 
35102b15cb3dSCy Schubert 		case 'n':
35112b15cb3dSCy Schubert 			if (1 == sscanf(tag, name_fmt, &ui)) {
35122b15cb3dSCy Schubert 				/* strip quotes */
35132b15cb3dSCy Schubert 				len = strlen(val);
35142b15cb3dSCy Schubert 				if (len >= 2 &&
35152b15cb3dSCy Schubert 				    len - 2 < sizeof(row.name)) {
35162b15cb3dSCy Schubert 					len -= 2;
35172b15cb3dSCy Schubert 					memcpy(row.name, val + 1, len);
35182b15cb3dSCy Schubert 					row.name[len] = '\0';
35192b15cb3dSCy Schubert 					comprende = TRUE;
35202b15cb3dSCy Schubert 				}
35212b15cb3dSCy Schubert 			}
35222b15cb3dSCy Schubert 			break;
35232b15cb3dSCy Schubert 
35242b15cb3dSCy Schubert 		case 'p':
35252b15cb3dSCy Schubert 			if (1 == sscanf(tag, pc_fmt, &ui) &&
352609100258SXin LI 			    1 == sscanf(val, "%u", &row.peer_count))
35272b15cb3dSCy Schubert 				comprende = TRUE;
35282b15cb3dSCy Schubert 			break;
35292b15cb3dSCy Schubert 
35302b15cb3dSCy Schubert 		case 'r':
35312b15cb3dSCy Schubert 			if (1 == sscanf(tag, rx_fmt, &ui) &&
353209100258SXin LI 			    1 == sscanf(val, "%u", &row.received))
35332b15cb3dSCy Schubert 				comprende = TRUE;
35342b15cb3dSCy Schubert 			break;
35352b15cb3dSCy Schubert 
35362b15cb3dSCy Schubert 		case 't':
35372b15cb3dSCy Schubert 			if (1 == sscanf(tag, tl_fmt, &ui) &&
353809100258SXin LI 			    1 == sscanf(val, "%u", &row.ttl))
35392b15cb3dSCy Schubert 				comprende = TRUE;
35402b15cb3dSCy Schubert 			else if (1 == sscanf(tag, tx_fmt, &ui) &&
354109100258SXin LI 				 1 == sscanf(val, "%u", &row.sent))
35422b15cb3dSCy Schubert 				comprende = TRUE;
35432b15cb3dSCy Schubert 			else if (1 == sscanf(tag, txerr_fmt, &ui) &&
354409100258SXin LI 				 1 == sscanf(val, "%u", &row.send_errors))
35452b15cb3dSCy Schubert 				comprende = TRUE;
35462b15cb3dSCy Schubert 			break;
35472b15cb3dSCy Schubert 
35482b15cb3dSCy Schubert 		case 'u':
35492b15cb3dSCy Schubert 			if (1 == sscanf(tag, up_fmt, &ui) &&
355009100258SXin LI 			    1 == sscanf(val, "%u", &row.uptime))
35512b15cb3dSCy Schubert 				comprende = TRUE;
35522b15cb3dSCy Schubert 			break;
35532b15cb3dSCy Schubert 		}
35542b15cb3dSCy Schubert 
35552b15cb3dSCy Schubert 		if (comprende) {
35562b15cb3dSCy Schubert 			/* error out if rows out of order */
35572b15cb3dSCy Schubert 			validate_ifnum(fp, ui, &fields, &row);
35582b15cb3dSCy Schubert 			/* if the row is complete, print it */
35592b15cb3dSCy Schubert 			another_ifstats_field(&fields, &row, fp);
35602b15cb3dSCy Schubert 		}
35612b15cb3dSCy Schubert 	}
35622b15cb3dSCy Schubert 	if (fields != IFSTATS_FIELDS)
35632d4e511cSCy Schubert 		xprintf(fp, "Warning: incomplete row with %d (of %d) fields\n",
35642b15cb3dSCy Schubert 			fields, IFSTATS_FIELDS);
35652b15cb3dSCy Schubert 
35662b15cb3dSCy Schubert 	fflush(fp);
35672b15cb3dSCy Schubert }
35682b15cb3dSCy Schubert 
35692b15cb3dSCy Schubert 
35702b15cb3dSCy Schubert /*
35712b15cb3dSCy Schubert  * validate_reslist_idx - helper for reslist()
35722b15cb3dSCy Schubert  *
35732b15cb3dSCy Schubert  * Ensures rows are received in order and complete.
35742b15cb3dSCy Schubert  */
35752b15cb3dSCy Schubert static void
35762b15cb3dSCy Schubert validate_reslist_idx(
35772b15cb3dSCy Schubert 	FILE *		fp,
35782b15cb3dSCy Schubert 	u_int		idx,
35792b15cb3dSCy Schubert 	int *		pfields,
35802b15cb3dSCy Schubert 	reslist_row *	prow
35812b15cb3dSCy Schubert 	)
35822b15cb3dSCy Schubert {
35832b15cb3dSCy Schubert 	if (prow->idx == idx)
35842b15cb3dSCy Schubert 		return;
35852b15cb3dSCy Schubert 	if (prow->idx + 1 == idx) {
35862b15cb3dSCy Schubert 		if (*pfields < RESLIST_FIELDS)
35872d4e511cSCy Schubert 			xprintf(fp, "Warning: incomplete row with %d (of %d) fields",
35882b15cb3dSCy Schubert 				*pfields, RESLIST_FIELDS);
35892b15cb3dSCy Schubert 		*pfields = 0;
35902b15cb3dSCy Schubert 		prow->idx = idx;
35912b15cb3dSCy Schubert 		return;
35922b15cb3dSCy Schubert 	}
35932d4e511cSCy Schubert 	xprintf(stderr,
35942b15cb3dSCy Schubert 		"received reslist index %u, have %d of %d fields for index %u, aborting.\n",
35952b15cb3dSCy Schubert 		idx, *pfields, RESLIST_FIELDS, prow->idx);
35962b15cb3dSCy Schubert 	exit(1);
35972b15cb3dSCy Schubert }
35982b15cb3dSCy Schubert 
35992b15cb3dSCy Schubert 
36002b15cb3dSCy Schubert /*
36012b15cb3dSCy Schubert  * another_reslist_field - helper for reslist()
36022b15cb3dSCy Schubert  *
36032b15cb3dSCy Schubert  * If all fields for the row have been received, print it.
36042b15cb3dSCy Schubert  */
36052b15cb3dSCy Schubert static void
36062b15cb3dSCy Schubert another_reslist_field(
36072b15cb3dSCy Schubert 	int *		pfields,
36082b15cb3dSCy Schubert 	reslist_row *	prow,
36092b15cb3dSCy Schubert 	FILE *		fp
36102b15cb3dSCy Schubert 	)
36112b15cb3dSCy Schubert {
36122b15cb3dSCy Schubert 	char	addrmaskstr[128];
36132b15cb3dSCy Schubert 	int	prefix;	/* subnet mask as prefix bits count */
36142b15cb3dSCy Schubert 	u_int	idx;
36152b15cb3dSCy Schubert 
36162b15cb3dSCy Schubert 	(*pfields)++;
36172b15cb3dSCy Schubert 	/* we understand 4 tags */
36182b15cb3dSCy Schubert 	if (RESLIST_FIELDS > *pfields)
36192b15cb3dSCy Schubert 		return;
36202b15cb3dSCy Schubert 
36212b15cb3dSCy Schubert 	prefix = sockaddr_masktoprefixlen(&prow->mask);
36222b15cb3dSCy Schubert 	if (prefix >= 0)
36232b15cb3dSCy Schubert 		snprintf(addrmaskstr, sizeof(addrmaskstr), "%s/%d",
36242b15cb3dSCy Schubert 			 stoa(&prow->addr), prefix);
36252b15cb3dSCy Schubert 	else
36262b15cb3dSCy Schubert 		snprintf(addrmaskstr, sizeof(addrmaskstr), "%s %s",
36272b15cb3dSCy Schubert 			 stoa(&prow->addr), stoa(&prow->mask));
36282b15cb3dSCy Schubert 
36292b15cb3dSCy Schubert 	/*
36302b15cb3dSCy Schubert 	"   hits    addr/prefix or addr mask\n"
36312b15cb3dSCy Schubert 	"           restrictions\n"
36322b15cb3dSCy Schubert 	"==============================================================================\n");
36332b15cb3dSCy Schubert 	 */
36342d4e511cSCy Schubert 	xprintf(fp,
36352b15cb3dSCy Schubert 		"%10lu %s\n"
36362b15cb3dSCy Schubert 		"           %s\n",
36372b15cb3dSCy Schubert 		prow->hits, addrmaskstr, prow->flagstr);
36382b15cb3dSCy Schubert 	idx = prow->idx;
36392b15cb3dSCy Schubert 	ZERO(*prow);
36402b15cb3dSCy Schubert 	prow->idx = idx;
36412b15cb3dSCy Schubert }
36422b15cb3dSCy Schubert 
36432b15cb3dSCy Schubert 
36442b15cb3dSCy Schubert /*
36452b15cb3dSCy Schubert  * reslist - ntpq -c reslist modeled on ntpdc -c reslist.
36462b15cb3dSCy Schubert  */
36472b15cb3dSCy Schubert static void
36482b15cb3dSCy Schubert reslist(
36492b15cb3dSCy Schubert 	struct parse *	pcmd,
36502b15cb3dSCy Schubert 	FILE *		fp
36512b15cb3dSCy Schubert 	)
36522b15cb3dSCy Schubert {
36532b15cb3dSCy Schubert 	const char addr_fmtu[] =	"addr.%u";
36542b15cb3dSCy Schubert 	const char mask_fmtu[] =	"mask.%u";
36552b15cb3dSCy Schubert 	const char hits_fmt[] =		"hits.%u";
36562b15cb3dSCy Schubert 	const char flags_fmt[] =	"flags.%u";
36572b15cb3dSCy Schubert 	const char qdata[] =		"addr_restrictions";
36582b15cb3dSCy Schubert 	const int qdata_chars =		COUNTOF(qdata) - 1;
36592b15cb3dSCy Schubert 	const char *	datap;
36602b15cb3dSCy Schubert 	int		qres;
36613311ff84SXin LI 	size_t		dsize;
36622b15cb3dSCy Schubert 	u_short		rstatus;
36632b15cb3dSCy Schubert 	char *		tag;
36642b15cb3dSCy Schubert 	char *		val;
36652b15cb3dSCy Schubert 	int		fields;
36662b15cb3dSCy Schubert 	u_int		ui;
36672b15cb3dSCy Schubert 	reslist_row	row;
36682b15cb3dSCy Schubert 	int		comprende;
36692b15cb3dSCy Schubert 	size_t		len;
36702b15cb3dSCy Schubert 
36712b15cb3dSCy Schubert 	qres = doquery(CTL_OP_READ_ORDLIST_A, 0, TRUE, qdata_chars,
36722b15cb3dSCy Schubert 		       qdata, &rstatus, &dsize, &datap);
36732b15cb3dSCy Schubert 	if (qres)	/* message already displayed */
36742b15cb3dSCy Schubert 		return;
36752b15cb3dSCy Schubert 
36762d4e511cSCy Schubert 	xprintf(fp,
36772b15cb3dSCy Schubert 		"   hits    addr/prefix or addr mask\n"
36782b15cb3dSCy Schubert 		"           restrictions\n"
36792b15cb3dSCy Schubert 		"==============================================================================\n");
36802b15cb3dSCy Schubert 		/* '=' x 78 */
36812b15cb3dSCy Schubert 
36822b15cb3dSCy Schubert 	ZERO(row);
36832b15cb3dSCy Schubert 	fields = 0;
36842b15cb3dSCy Schubert 	ui = 0;
36852b15cb3dSCy Schubert 	while (nextvar(&dsize, &datap, &tag, &val)) {
36864e1ef62aSXin LI 		INSIST(tag && val);
36872b15cb3dSCy Schubert 		if (debug > 1)
36882d4e511cSCy Schubert 			xprintf(stderr, "nextvar gave: %s = %s\n", tag, val);
36892b15cb3dSCy Schubert 		comprende = FALSE;
36902b15cb3dSCy Schubert 		switch(tag[0]) {
36912b15cb3dSCy Schubert 
36922b15cb3dSCy Schubert 		case 'a':
36932b15cb3dSCy Schubert 			if (1 == sscanf(tag, addr_fmtu, &ui) &&
36942b15cb3dSCy Schubert 			    decodenetnum(val, &row.addr))
36952b15cb3dSCy Schubert 				comprende = TRUE;
36962b15cb3dSCy Schubert 			break;
36972b15cb3dSCy Schubert 
36982b15cb3dSCy Schubert 		case 'f':
36992b15cb3dSCy Schubert 			if (1 == sscanf(tag, flags_fmt, &ui)) {
37002b15cb3dSCy Schubert 				if (NULL == val) {
37012b15cb3dSCy Schubert 					row.flagstr[0] = '\0';
37022b15cb3dSCy Schubert 					comprende = TRUE;
3703f0574f5cSXin LI 				} else if ((len = strlen(val)) < sizeof(row.flagstr)) {
37042b15cb3dSCy Schubert 					memcpy(row.flagstr, val, len);
37052b15cb3dSCy Schubert 					row.flagstr[len] = '\0';
37062b15cb3dSCy Schubert 					comprende = TRUE;
3707f0574f5cSXin LI 				} else {
3708f0574f5cSXin LI 					 /* no flags, and still !comprende */
3709f0574f5cSXin LI 					row.flagstr[0] = '\0';
37102b15cb3dSCy Schubert 				}
37112b15cb3dSCy Schubert 			}
37122b15cb3dSCy Schubert 			break;
37132b15cb3dSCy Schubert 
37142b15cb3dSCy Schubert 		case 'h':
37152b15cb3dSCy Schubert 			if (1 == sscanf(tag, hits_fmt, &ui) &&
37162b15cb3dSCy Schubert 			    1 == sscanf(val, "%lu", &row.hits))
37172b15cb3dSCy Schubert 				comprende = TRUE;
37182b15cb3dSCy Schubert 			break;
37192b15cb3dSCy Schubert 
37202b15cb3dSCy Schubert 		case 'm':
37212b15cb3dSCy Schubert 			if (1 == sscanf(tag, mask_fmtu, &ui) &&
37222b15cb3dSCy Schubert 			    decodenetnum(val, &row.mask))
37232b15cb3dSCy Schubert 				comprende = TRUE;
37242b15cb3dSCy Schubert 			break;
37252b15cb3dSCy Schubert 		}
37262b15cb3dSCy Schubert 
37272b15cb3dSCy Schubert 		if (comprende) {
37282b15cb3dSCy Schubert 			/* error out if rows out of order */
37292b15cb3dSCy Schubert 			validate_reslist_idx(fp, ui, &fields, &row);
37302b15cb3dSCy Schubert 			/* if the row is complete, print it */
37312b15cb3dSCy Schubert 			another_reslist_field(&fields, &row, fp);
37322b15cb3dSCy Schubert 		}
37332b15cb3dSCy Schubert 	}
37342b15cb3dSCy Schubert 	if (fields != RESLIST_FIELDS)
37352d4e511cSCy Schubert 		xprintf(fp, "Warning: incomplete row with %d (of %d) fields",
37362b15cb3dSCy Schubert 			fields, RESLIST_FIELDS);
37372b15cb3dSCy Schubert 
37382b15cb3dSCy Schubert 	fflush(fp);
37392b15cb3dSCy Schubert }
37402b15cb3dSCy Schubert 
37412b15cb3dSCy Schubert 
37422b15cb3dSCy Schubert /*
37432b15cb3dSCy Schubert  * collect_display_vdc
37442b15cb3dSCy Schubert  */
37452b15cb3dSCy Schubert static void
37462b15cb3dSCy Schubert collect_display_vdc(
37472b15cb3dSCy Schubert 	associd_t	as,
37482b15cb3dSCy Schubert 	vdc *		table,
37492b15cb3dSCy Schubert 	int		decodestatus,
37502b15cb3dSCy Schubert 	FILE *		fp
37512b15cb3dSCy Schubert 	)
37522b15cb3dSCy Schubert {
37532b15cb3dSCy Schubert 	static const char * const suf[2] = { "adr", "port" };
37542b15cb3dSCy Schubert 	static const char * const leapbits[4] = { "00", "01",
37552b15cb3dSCy Schubert 						  "10", "11" };
37562b15cb3dSCy Schubert 	struct varlist vl[MAXLIST];
37572b15cb3dSCy Schubert 	char tagbuf[32];
37582b15cb3dSCy Schubert 	vdc *pvdc;
37592b15cb3dSCy Schubert 	u_short rstatus;
37603311ff84SXin LI 	size_t rsize;
37612b15cb3dSCy Schubert 	const char *rdata;
37622b15cb3dSCy Schubert 	int qres;
37632b15cb3dSCy Schubert 	char *tag;
37642b15cb3dSCy Schubert 	char *val;
37652b15cb3dSCy Schubert 	u_int n;
37662b15cb3dSCy Schubert 	size_t len;
37672b15cb3dSCy Schubert 	int match;
37682b15cb3dSCy Schubert 	u_long ul;
37692b15cb3dSCy Schubert 	int vtype;
37702d4e511cSCy Schubert 	sockaddr_u sau;
37712b15cb3dSCy Schubert 
37722b15cb3dSCy Schubert 	ZERO(vl);
37732b15cb3dSCy Schubert 	for (pvdc = table; pvdc->tag != NULL; pvdc++) {
37742b15cb3dSCy Schubert 		ZERO(pvdc->v);
37752b15cb3dSCy Schubert 		if (NTP_ADD != pvdc->type) {
37762b15cb3dSCy Schubert 			doaddvlist(vl, pvdc->tag);
37772b15cb3dSCy Schubert 		} else {
37782b15cb3dSCy Schubert 			for (n = 0; n < COUNTOF(suf); n++) {
37792b15cb3dSCy Schubert 				snprintf(tagbuf, sizeof(tagbuf), "%s%s",
37802b15cb3dSCy Schubert 					 pvdc->tag, suf[n]);
37812b15cb3dSCy Schubert 				doaddvlist(vl, tagbuf);
37822b15cb3dSCy Schubert 			}
37832b15cb3dSCy Schubert 		}
37842b15cb3dSCy Schubert 	}
37852b15cb3dSCy Schubert 	qres = doquerylist(vl, CTL_OP_READVAR, as, 0, &rstatus, &rsize,
37862b15cb3dSCy Schubert 			   &rdata);
37872b15cb3dSCy Schubert 	doclearvlist(vl);
37882b15cb3dSCy Schubert 	if (qres)
37892b15cb3dSCy Schubert 		return;		/* error msg already displayed */
37902b15cb3dSCy Schubert 
37912b15cb3dSCy Schubert 	/*
37922b15cb3dSCy Schubert 	 * iterate over the response variables filling vdc_table with
37932b15cb3dSCy Schubert 	 * the retrieved values.
37942b15cb3dSCy Schubert 	 */
37952b15cb3dSCy Schubert 	while (nextvar(&rsize, &rdata, &tag, &val)) {
37964e1ef62aSXin LI 		INSIST(tag && val);
37972b15cb3dSCy Schubert 		n = 0;
37982b15cb3dSCy Schubert 		for (pvdc = table; pvdc->tag != NULL; pvdc++) {
37992b15cb3dSCy Schubert 			len = strlen(pvdc->tag);
38002b15cb3dSCy Schubert 			if (strncmp(tag, pvdc->tag, len))
38012b15cb3dSCy Schubert 				continue;
38022b15cb3dSCy Schubert 			if (NTP_ADD != pvdc->type) {
38032b15cb3dSCy Schubert 				if ('\0' != tag[len])
38042b15cb3dSCy Schubert 					continue;
38052b15cb3dSCy Schubert 				break;
38062b15cb3dSCy Schubert 			}
38072b15cb3dSCy Schubert 			match = FALSE;
38082b15cb3dSCy Schubert 			for (n = 0; n < COUNTOF(suf); n++) {
38092b15cb3dSCy Schubert 				if (strcmp(tag + len, suf[n]))
38102b15cb3dSCy Schubert 					continue;
38112b15cb3dSCy Schubert 				match = TRUE;
38122b15cb3dSCy Schubert 				break;
38132b15cb3dSCy Schubert 			}
38142b15cb3dSCy Schubert 			if (match)
38152b15cb3dSCy Schubert 				break;
38162b15cb3dSCy Schubert 		}
38172b15cb3dSCy Schubert 		if (NULL == pvdc->tag)
38182b15cb3dSCy Schubert 			continue;
38192b15cb3dSCy Schubert 		switch (pvdc->type) {
38202b15cb3dSCy Schubert 
38212b15cb3dSCy Schubert 		case NTP_STR:
38222b15cb3dSCy Schubert 			/* strip surrounding double quotes */
38232b15cb3dSCy Schubert 			if ('"' == val[0]) {
38242b15cb3dSCy Schubert 				len = strlen(val);
38252b15cb3dSCy Schubert 				if (len > 0 && '"' == val[len - 1]) {
38262b15cb3dSCy Schubert 					val[len - 1] = '\0';
38272b15cb3dSCy Schubert 					val++;
38282b15cb3dSCy Schubert 				}
38292b15cb3dSCy Schubert 			}
38302b15cb3dSCy Schubert 			/* fallthru */
38312d4e511cSCy Schubert 		case NTP_REFID:	/* fallthru */
38322b15cb3dSCy Schubert 		case NTP_MODE:	/* fallthru */
38332b15cb3dSCy Schubert 		case NTP_2BIT:
38342b15cb3dSCy Schubert 			pvdc->v.str = estrdup(val);
38352b15cb3dSCy Schubert 			break;
38362b15cb3dSCy Schubert 
38372b15cb3dSCy Schubert 		case NTP_LFP:
38382b15cb3dSCy Schubert 			decodets(val, &pvdc->v.lfp);
38392b15cb3dSCy Schubert 			break;
38402b15cb3dSCy Schubert 
38412b15cb3dSCy Schubert 		case NTP_ADP:
38422b15cb3dSCy Schubert 			if (!decodenetnum(val, &pvdc->v.sau))
38432d4e511cSCy Schubert 				xprintf(stderr, "malformed %s=%s\n",
38442b15cb3dSCy Schubert 					pvdc->tag, val);
38452b15cb3dSCy Schubert 			break;
38462b15cb3dSCy Schubert 
38472b15cb3dSCy Schubert 		case NTP_ADD:
38482b15cb3dSCy Schubert 			if (0 == n) {	/* adr */
38492b15cb3dSCy Schubert 				if (!decodenetnum(val, &pvdc->v.sau))
38502d4e511cSCy Schubert 					xprintf(stderr,
38512b15cb3dSCy Schubert 						"malformed %s=%s\n",
38522b15cb3dSCy Schubert 						pvdc->tag, val);
38532b15cb3dSCy Schubert 			} else {	/* port */
38542b15cb3dSCy Schubert 				if (atouint(val, &ul))
38552b15cb3dSCy Schubert 					SET_PORT(&pvdc->v.sau,
38562b15cb3dSCy Schubert 						 (u_short)ul);
38572b15cb3dSCy Schubert 			}
38582b15cb3dSCy Schubert 			break;
38592b15cb3dSCy Schubert 		}
38602b15cb3dSCy Schubert 	}
38612b15cb3dSCy Schubert 
38622b15cb3dSCy Schubert 	/* and display */
38632b15cb3dSCy Schubert 	if (decodestatus) {
38642b15cb3dSCy Schubert 		vtype = (0 == as)
38652b15cb3dSCy Schubert 			    ? TYPE_SYS
38662b15cb3dSCy Schubert 			    : TYPE_PEER;
38672d4e511cSCy Schubert 		xprintf(fp, "associd=%u status=%04x %s,\n", as, rstatus,
38682b15cb3dSCy Schubert 			statustoa(vtype, rstatus));
38692b15cb3dSCy Schubert 	}
38702b15cb3dSCy Schubert 
38712b15cb3dSCy Schubert 	for (pvdc = table; pvdc->tag != NULL; pvdc++) {
38722b15cb3dSCy Schubert 		switch (pvdc->type) {
38732b15cb3dSCy Schubert 
38742b15cb3dSCy Schubert 		case NTP_STR:
38752b15cb3dSCy Schubert 			if (pvdc->v.str != NULL) {
38762d4e511cSCy Schubert 				xprintf(fp, "%s  %s\n", pvdc->display,
38772b15cb3dSCy Schubert 					pvdc->v.str);
38782b15cb3dSCy Schubert 				free(pvdc->v.str);
38792b15cb3dSCy Schubert 				pvdc->v.str = NULL;
38802b15cb3dSCy Schubert 			}
38812b15cb3dSCy Schubert 			break;
38822b15cb3dSCy Schubert 
38832b15cb3dSCy Schubert 		case NTP_ADD:	/* fallthru */
38842b15cb3dSCy Schubert 		case NTP_ADP:
38852d4e511cSCy Schubert 			xprintf(fp, "%s  %s\n", pvdc->display,
38862b15cb3dSCy Schubert 				nntohostp(&pvdc->v.sau));
38872b15cb3dSCy Schubert 			break;
38882b15cb3dSCy Schubert 
38892b15cb3dSCy Schubert 		case NTP_LFP:
38902d4e511cSCy Schubert 			xprintf(fp, "%s  %s\n", pvdc->display,
38912b15cb3dSCy Schubert 				prettydate(&pvdc->v.lfp));
38922b15cb3dSCy Schubert 			break;
38932b15cb3dSCy Schubert 
38942b15cb3dSCy Schubert 		case NTP_MODE:
38952b15cb3dSCy Schubert 			atouint(pvdc->v.str, &ul);
38962d4e511cSCy Schubert 			xprintf(fp, "%s  %s\n", pvdc->display,
38972b15cb3dSCy Schubert 				modetoa((int)ul));
38982d4e511cSCy Schubert 			free(pvdc->v.str);
38992d4e511cSCy Schubert 			pvdc->v.str = NULL;
39002b15cb3dSCy Schubert 			break;
39012b15cb3dSCy Schubert 
39022b15cb3dSCy Schubert 		case NTP_2BIT:
39032b15cb3dSCy Schubert 			atouint(pvdc->v.str, &ul);
39042d4e511cSCy Schubert 			xprintf(fp, "%s  %s\n", pvdc->display,
39052b15cb3dSCy Schubert 				leapbits[ul & 0x3]);
39062d4e511cSCy Schubert 			free(pvdc->v.str);
39072d4e511cSCy Schubert 			pvdc->v.str = NULL;
39082d4e511cSCy Schubert 			break;
39092d4e511cSCy Schubert 
39102d4e511cSCy Schubert 		case NTP_REFID:
39112d4e511cSCy Schubert 			if (!decodenetnum(pvdc->v.str, &sau)) {
39122d4e511cSCy Schubert 				fprintf(fp, "%s  %s\n", pvdc->display,    /* Text fmt */
39132d4e511cSCy Schubert 					pvdc->v.str);
39142d4e511cSCy Schubert 			} else if (drefid == REFID_IPV4) {
39152d4e511cSCy Schubert 				fprintf(fp, "%s  %s\n", pvdc->display,    /* IPv4 fmt */
39162d4e511cSCy Schubert 					stoa(&sau));
39172d4e511cSCy Schubert 			} else {
39182d4e511cSCy Schubert 				fprintf (fp, "%s  0x%08x\n", pvdc->display,	   /* Hex / hash */
39192d4e511cSCy Schubert 					 ntohl(addr2refid(&sau)));
39202d4e511cSCy Schubert 			}
39212d4e511cSCy Schubert 			free(pvdc->v.str);
39222d4e511cSCy Schubert 			pvdc->v.str = NULL;
39232b15cb3dSCy Schubert 			break;
39242b15cb3dSCy Schubert 
39252b15cb3dSCy Schubert 		default:
39262d4e511cSCy Schubert 			xprintf(stderr, "unexpected vdc type %d for %s\n",
39272b15cb3dSCy Schubert 				pvdc->type, pvdc->tag);
39282b15cb3dSCy Schubert 			break;
39292b15cb3dSCy Schubert 		}
39302b15cb3dSCy Schubert 	}
39312b15cb3dSCy Schubert }
39322b15cb3dSCy Schubert 
39332b15cb3dSCy Schubert 
39342b15cb3dSCy Schubert /*
39352b15cb3dSCy Schubert  * sysstats - implements ntpq -c sysstats modeled on ntpdc -c sysstats
39362b15cb3dSCy Schubert  */
39372b15cb3dSCy Schubert static void
39382b15cb3dSCy Schubert sysstats(
39392b15cb3dSCy Schubert 	struct parse *pcmd,
39402b15cb3dSCy Schubert 	FILE *fp
39412b15cb3dSCy Schubert 	)
39422b15cb3dSCy Schubert {
39432b15cb3dSCy Schubert     static vdc sysstats_vdc[] = {
39442b15cb3dSCy Schubert 	VDC_INIT("ss_uptime",		"uptime:               ", NTP_STR),
39452b15cb3dSCy Schubert 	VDC_INIT("ss_reset",		"sysstats reset:       ", NTP_STR),
39462b15cb3dSCy Schubert 	VDC_INIT("ss_received",		"packets received:     ", NTP_STR),
39472b15cb3dSCy Schubert 	VDC_INIT("ss_thisver",		"current version:      ", NTP_STR),
39482b15cb3dSCy Schubert 	VDC_INIT("ss_oldver",		"older version:        ", NTP_STR),
39492b15cb3dSCy Schubert 	VDC_INIT("ss_badformat",	"bad length or format: ", NTP_STR),
39502b15cb3dSCy Schubert 	VDC_INIT("ss_badauth",		"authentication failed:", NTP_STR),
39512b15cb3dSCy Schubert 	VDC_INIT("ss_declined",		"declined:             ", NTP_STR),
39522b15cb3dSCy Schubert 	VDC_INIT("ss_restricted",	"restricted:           ", NTP_STR),
39532b15cb3dSCy Schubert 	VDC_INIT("ss_limited",		"rate limited:         ", NTP_STR),
39542b15cb3dSCy Schubert 	VDC_INIT("ss_kodsent",		"KoD responses:        ", NTP_STR),
39552b15cb3dSCy Schubert 	VDC_INIT("ss_processed",	"processed for time:   ", NTP_STR),
395609100258SXin LI #if 0
395709100258SXin LI 	VDC_INIT("ss_lamport",		"Lamport violations:    ", NTP_STR),
395809100258SXin LI 	VDC_INIT("ss_tsrounding",	"bad timestamp rounding:", NTP_STR),
395909100258SXin LI #endif
39602b15cb3dSCy Schubert 	VDC_INIT(NULL,			NULL,			  0)
39612b15cb3dSCy Schubert     };
39622b15cb3dSCy Schubert 
39632b15cb3dSCy Schubert 	collect_display_vdc(0, sysstats_vdc, FALSE, fp);
39642b15cb3dSCy Schubert }
39652b15cb3dSCy Schubert 
39662b15cb3dSCy Schubert 
39672b15cb3dSCy Schubert /*
39682b15cb3dSCy Schubert  * sysinfo - modeled on ntpdc's sysinfo
39692b15cb3dSCy Schubert  */
39702b15cb3dSCy Schubert static void
39712b15cb3dSCy Schubert sysinfo(
39722b15cb3dSCy Schubert 	struct parse *pcmd,
39732b15cb3dSCy Schubert 	FILE *fp
39742b15cb3dSCy Schubert 	)
39752b15cb3dSCy Schubert {
39762b15cb3dSCy Schubert     static vdc sysinfo_vdc[] = {
39772b15cb3dSCy Schubert 	VDC_INIT("peeradr",		"system peer:      ", NTP_ADP),
39782b15cb3dSCy Schubert 	VDC_INIT("peermode",		"system peer mode: ", NTP_MODE),
39792b15cb3dSCy Schubert 	VDC_INIT("leap",		"leap indicator:   ", NTP_2BIT),
39802b15cb3dSCy Schubert 	VDC_INIT("stratum",		"stratum:          ", NTP_STR),
39812b15cb3dSCy Schubert 	VDC_INIT("precision",		"log2 precision:   ", NTP_STR),
39822b15cb3dSCy Schubert 	VDC_INIT("rootdelay",		"root delay:       ", NTP_STR),
39832b15cb3dSCy Schubert 	VDC_INIT("rootdisp",		"root dispersion:  ", NTP_STR),
39842d4e511cSCy Schubert 	VDC_INIT("refid",		"reference ID:     ", NTP_REFID),
39852b15cb3dSCy Schubert 	VDC_INIT("reftime",		"reference time:   ", NTP_LFP),
39862b15cb3dSCy Schubert 	VDC_INIT("sys_jitter",		"system jitter:    ", NTP_STR),
39872b15cb3dSCy Schubert 	VDC_INIT("clk_jitter",		"clock jitter:     ", NTP_STR),
39882b15cb3dSCy Schubert 	VDC_INIT("clk_wander",		"clock wander:     ", NTP_STR),
39892b15cb3dSCy Schubert 	VDC_INIT("bcastdelay",		"broadcast delay:  ", NTP_STR),
39902b15cb3dSCy Schubert 	VDC_INIT("authdelay",		"symm. auth. delay:", NTP_STR),
39912b15cb3dSCy Schubert 	VDC_INIT(NULL,			NULL,		      0)
39922b15cb3dSCy Schubert     };
39932b15cb3dSCy Schubert 
39942b15cb3dSCy Schubert 	collect_display_vdc(0, sysinfo_vdc, TRUE, fp);
39952b15cb3dSCy Schubert }
39962b15cb3dSCy Schubert 
39972b15cb3dSCy Schubert 
39982b15cb3dSCy Schubert /*
39992b15cb3dSCy Schubert  * kerninfo - modeled on ntpdc's kerninfo
40002b15cb3dSCy Schubert  */
40012b15cb3dSCy Schubert static void
40022b15cb3dSCy Schubert kerninfo(
40032b15cb3dSCy Schubert 	struct parse *pcmd,
40042b15cb3dSCy Schubert 	FILE *fp
40052b15cb3dSCy Schubert 	)
40062b15cb3dSCy Schubert {
40072b15cb3dSCy Schubert     static vdc kerninfo_vdc[] = {
40082b15cb3dSCy Schubert 	VDC_INIT("koffset",		"pll offset:          ", NTP_STR),
40092b15cb3dSCy Schubert 	VDC_INIT("kfreq",		"pll frequency:       ", NTP_STR),
40102b15cb3dSCy Schubert 	VDC_INIT("kmaxerr",		"maximum error:       ", NTP_STR),
40112b15cb3dSCy Schubert 	VDC_INIT("kesterr",		"estimated error:     ", NTP_STR),
40122b15cb3dSCy Schubert 	VDC_INIT("kstflags",		"kernel status:       ", NTP_STR),
40132b15cb3dSCy Schubert 	VDC_INIT("ktimeconst",		"pll time constant:   ", NTP_STR),
40142b15cb3dSCy Schubert 	VDC_INIT("kprecis",		"precision:           ", NTP_STR),
40152b15cb3dSCy Schubert 	VDC_INIT("kfreqtol",		"frequency tolerance: ", NTP_STR),
40162b15cb3dSCy Schubert 	VDC_INIT("kppsfreq",		"pps frequency:       ", NTP_STR),
40172b15cb3dSCy Schubert 	VDC_INIT("kppsstab",		"pps stability:       ", NTP_STR),
40182b15cb3dSCy Schubert 	VDC_INIT("kppsjitter",		"pps jitter:          ", NTP_STR),
40192b15cb3dSCy Schubert 	VDC_INIT("kppscalibdur",	"calibration interval ", NTP_STR),
40202b15cb3dSCy Schubert 	VDC_INIT("kppscalibs",		"calibration cycles:  ", NTP_STR),
40212b15cb3dSCy Schubert 	VDC_INIT("kppsjitexc",		"jitter exceeded:     ", NTP_STR),
40222b15cb3dSCy Schubert 	VDC_INIT("kppsstbexc",		"stability exceeded:  ", NTP_STR),
40232b15cb3dSCy Schubert 	VDC_INIT("kppscaliberrs",	"calibration errors:  ", NTP_STR),
40242b15cb3dSCy Schubert 	VDC_INIT(NULL,			NULL,			 0)
40252b15cb3dSCy Schubert     };
40262b15cb3dSCy Schubert 
40272b15cb3dSCy Schubert 	collect_display_vdc(0, kerninfo_vdc, TRUE, fp);
40282b15cb3dSCy Schubert }
40292b15cb3dSCy Schubert 
40302b15cb3dSCy Schubert 
40312b15cb3dSCy Schubert /*
40322b15cb3dSCy Schubert  * monstats - implements ntpq -c monstats
40332b15cb3dSCy Schubert  */
40342b15cb3dSCy Schubert static void
40352b15cb3dSCy Schubert monstats(
40362b15cb3dSCy Schubert 	struct parse *pcmd,
40372b15cb3dSCy Schubert 	FILE *fp
40382b15cb3dSCy Schubert 	)
40392b15cb3dSCy Schubert {
40402b15cb3dSCy Schubert     static vdc monstats_vdc[] = {
40412b15cb3dSCy Schubert 	VDC_INIT("mru_enabled",		"enabled:            ", NTP_STR),
40422b15cb3dSCy Schubert 	VDC_INIT("mru_depth",		"addresses:          ", NTP_STR),
40432b15cb3dSCy Schubert 	VDC_INIT("mru_deepest",		"peak addresses:     ", NTP_STR),
40442b15cb3dSCy Schubert 	VDC_INIT("mru_maxdepth",	"maximum addresses:  ", NTP_STR),
40452b15cb3dSCy Schubert 	VDC_INIT("mru_mindepth",	"reclaim above count:", NTP_STR),
40462b15cb3dSCy Schubert 	VDC_INIT("mru_maxage",		"reclaim older than: ", NTP_STR),
40472b15cb3dSCy Schubert 	VDC_INIT("mru_mem",		"kilobytes:          ", NTP_STR),
40482b15cb3dSCy Schubert 	VDC_INIT("mru_maxmem",		"maximum kilobytes:  ", NTP_STR),
40492b15cb3dSCy Schubert 	VDC_INIT(NULL,			NULL,			0)
40502b15cb3dSCy Schubert     };
40512b15cb3dSCy Schubert 
40522b15cb3dSCy Schubert 	collect_display_vdc(0, monstats_vdc, FALSE, fp);
40532b15cb3dSCy Schubert }
40542b15cb3dSCy Schubert 
40552b15cb3dSCy Schubert 
40562b15cb3dSCy Schubert /*
40572b15cb3dSCy Schubert  * iostats - ntpq -c iostats - network input and output counters
40582b15cb3dSCy Schubert  */
40592b15cb3dSCy Schubert static void
40602b15cb3dSCy Schubert iostats(
40612b15cb3dSCy Schubert 	struct parse *pcmd,
40622b15cb3dSCy Schubert 	FILE *fp
40632b15cb3dSCy Schubert 	)
40642b15cb3dSCy Schubert {
40652b15cb3dSCy Schubert     static vdc iostats_vdc[] = {
40662b15cb3dSCy Schubert 	VDC_INIT("iostats_reset",	"time since reset:     ", NTP_STR),
40672b15cb3dSCy Schubert 	VDC_INIT("total_rbuf",		"receive buffers:      ", NTP_STR),
40682b15cb3dSCy Schubert 	VDC_INIT("free_rbuf",		"free receive buffers: ", NTP_STR),
40692b15cb3dSCy Schubert 	VDC_INIT("used_rbuf",		"used receive buffers: ", NTP_STR),
40702b15cb3dSCy Schubert 	VDC_INIT("rbuf_lowater",	"low water refills:    ", NTP_STR),
40712b15cb3dSCy Schubert 	VDC_INIT("io_dropped",		"dropped packets:      ", NTP_STR),
40722b15cb3dSCy Schubert 	VDC_INIT("io_ignored",		"ignored packets:      ", NTP_STR),
40732b15cb3dSCy Schubert 	VDC_INIT("io_received",		"received packets:     ", NTP_STR),
40742b15cb3dSCy Schubert 	VDC_INIT("io_sent",		"packets sent:         ", NTP_STR),
40752b15cb3dSCy Schubert 	VDC_INIT("io_sendfailed",	"packet send failures: ", NTP_STR),
40762b15cb3dSCy Schubert 	VDC_INIT("io_wakeups",		"input wakeups:        ", NTP_STR),
40772b15cb3dSCy Schubert 	VDC_INIT("io_goodwakeups",	"useful input wakeups: ", NTP_STR),
40782b15cb3dSCy Schubert 	VDC_INIT(NULL,			NULL,			  0)
40792b15cb3dSCy Schubert     };
40802b15cb3dSCy Schubert 
40812b15cb3dSCy Schubert 	collect_display_vdc(0, iostats_vdc, FALSE, fp);
40822b15cb3dSCy Schubert }
40832b15cb3dSCy Schubert 
40842b15cb3dSCy Schubert 
40852b15cb3dSCy Schubert /*
40862b15cb3dSCy Schubert  * timerstats - ntpq -c timerstats - interval timer counters
40872b15cb3dSCy Schubert  */
40882b15cb3dSCy Schubert static void
40892b15cb3dSCy Schubert timerstats(
40902b15cb3dSCy Schubert 	struct parse *pcmd,
40912b15cb3dSCy Schubert 	FILE *fp
40922b15cb3dSCy Schubert 	)
40932b15cb3dSCy Schubert {
40942b15cb3dSCy Schubert     static vdc timerstats_vdc[] = {
40952b15cb3dSCy Schubert 	VDC_INIT("timerstats_reset",	"time since reset:  ", NTP_STR),
40962b15cb3dSCy Schubert 	VDC_INIT("timer_overruns",	"timer overruns:    ", NTP_STR),
40972b15cb3dSCy Schubert 	VDC_INIT("timer_xmts",		"calls to transmit: ", NTP_STR),
40982b15cb3dSCy Schubert 	VDC_INIT(NULL,			NULL,		       0)
40992b15cb3dSCy Schubert     };
41002b15cb3dSCy Schubert 
41012b15cb3dSCy Schubert 	collect_display_vdc(0, timerstats_vdc, FALSE, fp);
41022b15cb3dSCy Schubert }
41032b15cb3dSCy Schubert 
41042b15cb3dSCy Schubert 
41052b15cb3dSCy Schubert /*
41062b15cb3dSCy Schubert  * authinfo - implements ntpq -c authinfo
41072b15cb3dSCy Schubert  */
41082b15cb3dSCy Schubert static void
41092b15cb3dSCy Schubert authinfo(
41102b15cb3dSCy Schubert 	struct parse *pcmd,
41112b15cb3dSCy Schubert 	FILE *fp
41122b15cb3dSCy Schubert 	)
41132b15cb3dSCy Schubert {
41142b15cb3dSCy Schubert     static vdc authinfo_vdc[] = {
41152b15cb3dSCy Schubert 	VDC_INIT("authreset",		"time since reset:", NTP_STR),
41162b15cb3dSCy Schubert 	VDC_INIT("authkeys",		"stored keys:     ", NTP_STR),
41172b15cb3dSCy Schubert 	VDC_INIT("authfreek",		"free keys:       ", NTP_STR),
41182b15cb3dSCy Schubert 	VDC_INIT("authklookups",	"key lookups:     ", NTP_STR),
41192b15cb3dSCy Schubert 	VDC_INIT("authknotfound",	"keys not found:  ", NTP_STR),
41202b15cb3dSCy Schubert 	VDC_INIT("authkuncached",	"uncached keys:   ", NTP_STR),
41212b15cb3dSCy Schubert 	VDC_INIT("authkexpired",	"expired keys:    ", NTP_STR),
41222b15cb3dSCy Schubert 	VDC_INIT("authencrypts",	"encryptions:     ", NTP_STR),
41232b15cb3dSCy Schubert 	VDC_INIT("authdecrypts",	"decryptions:     ", NTP_STR),
41242b15cb3dSCy Schubert 	VDC_INIT(NULL,			NULL,		     0)
41252b15cb3dSCy Schubert     };
41262b15cb3dSCy Schubert 
41272b15cb3dSCy Schubert 	collect_display_vdc(0, authinfo_vdc, FALSE, fp);
41282b15cb3dSCy Schubert }
41292b15cb3dSCy Schubert 
41302b15cb3dSCy Schubert 
41312b15cb3dSCy Schubert /*
41322b15cb3dSCy Schubert  * pstats - show statistics for a peer
41332b15cb3dSCy Schubert  */
41342b15cb3dSCy Schubert static void
41352b15cb3dSCy Schubert pstats(
41362b15cb3dSCy Schubert 	struct parse *pcmd,
41372b15cb3dSCy Schubert 	FILE *fp
41382b15cb3dSCy Schubert 	)
41392b15cb3dSCy Schubert {
41402b15cb3dSCy Schubert     static vdc pstats_vdc[] = {
41412b15cb3dSCy Schubert 	VDC_INIT("src",		"remote host:         ", NTP_ADD),
41422b15cb3dSCy Schubert 	VDC_INIT("dst",		"local address:       ", NTP_ADD),
41432b15cb3dSCy Schubert 	VDC_INIT("timerec",	"time last received:  ", NTP_STR),
41442b15cb3dSCy Schubert 	VDC_INIT("timer",	"time until next send:", NTP_STR),
41452b15cb3dSCy Schubert 	VDC_INIT("timereach",	"reachability change: ", NTP_STR),
41462b15cb3dSCy Schubert 	VDC_INIT("sent",	"packets sent:        ", NTP_STR),
41472b15cb3dSCy Schubert 	VDC_INIT("received",	"packets received:    ", NTP_STR),
41482b15cb3dSCy Schubert 	VDC_INIT("badauth",	"bad authentication:  ", NTP_STR),
41492b15cb3dSCy Schubert 	VDC_INIT("bogusorg",	"bogus origin:        ", NTP_STR),
41502b15cb3dSCy Schubert 	VDC_INIT("oldpkt",	"duplicate:           ", NTP_STR),
41512b15cb3dSCy Schubert 	VDC_INIT("seldisp",	"bad dispersion:      ", NTP_STR),
41522b15cb3dSCy Schubert 	VDC_INIT("selbroken",	"bad reference time:  ", NTP_STR),
41532b15cb3dSCy Schubert 	VDC_INIT("candidate",	"candidate order:     ", NTP_STR),
41542b15cb3dSCy Schubert 	VDC_INIT(NULL,		NULL,			 0)
41552b15cb3dSCy Schubert     };
41562b15cb3dSCy Schubert 	associd_t associd;
41572b15cb3dSCy Schubert 
41582b15cb3dSCy Schubert 	associd = checkassocid(pcmd->argval[0].uval);
41592b15cb3dSCy Schubert 	if (0 == associd)
41602b15cb3dSCy Schubert 		return;
41612b15cb3dSCy Schubert 
41622b15cb3dSCy Schubert 	collect_display_vdc(associd, pstats_vdc, TRUE, fp);
41632b15cb3dSCy Schubert }
4164