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