2 * ntpq-subs.c - subroutines which are called to perform ntpq commands.
11 #include "ntpq-opts.h"
13 extern char currenthost[];
14 extern int currenthostisnum;
18 * Declarations for command handlers in here
20 static associd_t checkassocid (u_int32);
21 static struct varlist *findlistvar (struct varlist *, char *);
22 static void doaddvlist (struct varlist *, const char *);
23 static void dormvlist (struct varlist *, const char *);
24 static void doclearvlist (struct varlist *);
25 static void makequerydata (struct varlist *, int *, char *);
26 static int doquerylist (struct varlist *, int, associd_t, int,
27 u_short *, int *, const char **);
28 static void doprintvlist (struct varlist *, FILE *);
29 static void addvars (struct parse *, FILE *);
30 static void rmvars (struct parse *, FILE *);
31 static void clearvars (struct parse *, FILE *);
32 static void showvars (struct parse *, FILE *);
33 static int dolist (struct varlist *, associd_t, int, int,
35 static void readlist (struct parse *, FILE *);
36 static void writelist (struct parse *, FILE *);
37 static void readvar (struct parse *, FILE *);
38 static void writevar (struct parse *, FILE *);
39 static void clocklist (struct parse *, FILE *);
40 static void clockvar (struct parse *, FILE *);
41 static int findassidrange (u_int32, u_int32, int *, int *,
43 static void mreadlist (struct parse *, FILE *);
44 static void mreadvar (struct parse *, FILE *);
45 static void printassoc (int, FILE *);
46 static void associations (struct parse *, FILE *);
47 static void lassociations (struct parse *, FILE *);
48 static void passociations (struct parse *, FILE *);
49 static void lpassociations (struct parse *, FILE *);
52 static void radiostatus (struct parse *, FILE *);
55 static void authinfo (struct parse *, FILE *);
56 static void pstats (struct parse *, FILE *);
57 static long when (l_fp *, l_fp *, l_fp *);
58 static char * prettyinterval (char *, size_t, long);
59 static int doprintpeers (struct varlist *, int, int, int, const char *, FILE *, int);
60 static int dogetpeers (struct varlist *, associd_t, FILE *, int);
61 static void dopeers (int, FILE *, int);
62 static void peers (struct parse *, FILE *);
63 static void lpeers (struct parse *, FILE *);
64 static void doopeers (int, FILE *, int);
65 static void opeers (struct parse *, FILE *);
66 static void lopeers (struct parse *, FILE *);
67 static void config (struct parse *, FILE *);
68 static void saveconfig (struct parse *, FILE *);
69 static void config_from_file(struct parse *, FILE *);
70 static void mrulist (struct parse *, FILE *);
71 static void ifstats (struct parse *, FILE *);
72 static void reslist (struct parse *, FILE *);
73 static void sysstats (struct parse *, FILE *);
74 static void sysinfo (struct parse *, FILE *);
75 static void kerninfo (struct parse *, FILE *);
76 static void monstats (struct parse *, FILE *);
77 static void iostats (struct parse *, FILE *);
78 static void timerstats (struct parse *, FILE *);
81 * Commands we understand. Ntpdc imports this.
83 struct xcmd opcmds[] = {
84 { "saveconfig", saveconfig, { NTP_STR, NO, NO, NO },
85 { "filename", "", "", ""},
86 "save ntpd configuration to file, . for current config file"},
87 { "associations", associations, { NO, NO, NO, NO },
89 "print list of association ID's and statuses for the server's peers" },
90 { "passociations", passociations, { NO, NO, NO, NO },
92 "print list of associations returned by last associations command" },
93 { "lassociations", lassociations, { NO, NO, NO, NO },
95 "print list of associations including all client information" },
96 { "lpassociations", lpassociations, { NO, NO, NO, NO },
98 "print last obtained list of associations, including client information" },
99 { "addvars", addvars, { NTP_STR, NO, NO, NO },
100 { "name[=value][,...]", "", "", "" },
101 "add variables to the variable list or change their values" },
102 { "rmvars", rmvars, { NTP_STR, NO, NO, NO },
103 { "name[,...]", "", "", "" },
104 "remove variables from the variable list" },
105 { "clearvars", clearvars, { NO, NO, NO, NO },
107 "remove all variables from the variable list" },
108 { "showvars", showvars, { NO, NO, NO, NO },
110 "print variables on the variable list" },
111 { "readlist", readlist, { OPT|NTP_UINT, NO, NO, NO },
112 { "assocID", "", "", "" },
113 "read the system or peer variables included in the variable list" },
114 { "rl", readlist, { OPT|NTP_UINT, NO, NO, NO },
115 { "assocID", "", "", "" },
116 "read the system or peer variables included in the variable list" },
117 { "writelist", writelist, { OPT|NTP_UINT, NO, NO, NO },
118 { "assocID", "", "", "" },
119 "write the system or peer variables included in the variable list" },
120 { "readvar", readvar, { OPT|NTP_UINT, OPT|NTP_STR, OPT|NTP_STR, OPT|NTP_STR, },
121 { "assocID", "varname1", "varname2", "varname3" },
122 "read system or peer variables" },
123 { "rv", readvar, { OPT|NTP_UINT, OPT|NTP_STR, OPT|NTP_STR, OPT|NTP_STR, },
124 { "assocID", "varname1", "varname2", "varname3" },
125 "read system or peer variables" },
126 { "writevar", writevar, { NTP_UINT, NTP_STR, NO, NO },
127 { "assocID", "name=value,[...]", "", "" },
128 "write system or peer variables" },
129 { "mreadlist", mreadlist, { NTP_UINT, NTP_UINT, NO, NO },
130 { "assocIDlow", "assocIDhigh", "", "" },
131 "read the peer variables in the variable list for multiple peers" },
132 { "mrl", mreadlist, { NTP_UINT, NTP_UINT, NO, NO },
133 { "assocIDlow", "assocIDhigh", "", "" },
134 "read the peer variables in the variable list for multiple peers" },
135 { "mreadvar", mreadvar, { NTP_UINT, NTP_UINT, OPT|NTP_STR, NO },
136 { "assocIDlow", "assocIDhigh", "name=value[,...]", "" },
137 "read peer variables from multiple peers" },
138 { "mrv", mreadvar, { NTP_UINT, NTP_UINT, OPT|NTP_STR, NO },
139 { "assocIDlow", "assocIDhigh", "name=value[,...]", "" },
140 "read peer variables from multiple peers" },
141 { "clocklist", clocklist, { OPT|NTP_UINT, NO, NO, NO },
142 { "assocID", "", "", "" },
143 "read the clock variables included in the variable list" },
144 { "cl", clocklist, { OPT|NTP_UINT, NO, NO, NO },
145 { "assocID", "", "", "" },
146 "read the clock variables included in the variable list" },
147 { "clockvar", clockvar, { OPT|NTP_UINT, OPT|NTP_STR, NO, NO },
148 { "assocID", "name=value[,...]", "", "" },
149 "read clock variables" },
150 { "cv", clockvar, { OPT|NTP_UINT, OPT|NTP_STR, NO, NO },
151 { "assocID", "name=value[,...]", "", "" },
152 "read clock variables" },
153 { "pstats", pstats, { NTP_UINT, NO, NO, NO },
154 { "assocID", "", "", "" },
155 "show statistics for a peer" },
156 { "peers", peers, { OPT|IP_VERSION, NO, NO, NO },
157 { "-4|-6", "", "", "" },
158 "obtain and print a list of the server's peers [IP version]" },
159 { "lpeers", lpeers, { OPT|IP_VERSION, NO, NO, NO },
160 { "-4|-6", "", "", "" },
161 "obtain and print a list of all peers and clients [IP version]" },
162 { "opeers", opeers, { OPT|IP_VERSION, NO, NO, NO },
163 { "-4|-6", "", "", "" },
164 "print peer list the old way, with dstadr shown rather than refid [IP version]" },
165 { "lopeers", lopeers, { OPT|IP_VERSION, NO, NO, NO },
166 { "-4|-6", "", "", "" },
167 "obtain and print a list of all peers and clients showing dstadr [IP version]" },
168 { ":config", config, { NTP_STR, NO, NO, NO },
169 { "<configuration command line>", "", "", "" },
170 "send a remote configuration command to ntpd" },
171 { "config-from-file", config_from_file, { NTP_STR, NO, NO, NO },
172 { "<configuration filename>", "", "", "" },
173 "configure ntpd using the configuration filename" },
174 { "mrulist", mrulist, { OPT|NTP_STR, OPT|NTP_STR, OPT|NTP_STR, OPT|NTP_STR },
175 { "tag=value", "tag=value", "tag=value", "tag=value" },
176 "display the list of most recently seen source addresses, tags mincount=... resall=0x... resany=0x..." },
177 { "ifstats", ifstats, { NO, NO, NO, NO },
179 "show statistics for each local address ntpd is using" },
180 { "reslist", reslist, { NO, NO, NO, NO },
182 "show ntpd access control list" },
183 { "sysinfo", sysinfo, { NO, NO, NO, NO },
185 "display system summary" },
186 { "kerninfo", kerninfo, { NO, NO, NO, NO },
188 "display kernel loop and PPS statistics" },
189 { "sysstats", sysstats, { NO, NO, NO, NO },
191 "display system uptime and packet counts" },
192 { "monstats", monstats, { NO, NO, NO, NO },
194 "display monitor (mrulist) counters and limits" },
195 { "authinfo", authinfo, { NO, NO, NO, NO },
197 "display symmetric authentication counters" },
198 { "iostats", iostats, { NO, NO, NO, NO },
200 "display network input and output counters" },
201 { "timerstats", timerstats, { NO, NO, NO, NO },
203 "display interval timer counters" },
204 { 0, 0, { NO, NO, NO, NO },
205 { "-4|-6", "", "", "" }, "" }
210 * Variable list data space
212 #define MAXLINE 512 /* maximum length of a line */
213 #define MAXLIST 128 /* maximum variables in list */
214 #define LENHOSTNAME 256 /* host name limit */
216 #define MRU_GOT_COUNT 0x1
217 #define MRU_GOT_LAST 0x2
218 #define MRU_GOT_FIRST 0x4
219 #define MRU_GOT_MV 0x8
220 #define MRU_GOT_RS 0x10
221 #define MRU_GOT_ADDR 0x20
222 #define MRU_GOT_ALL (MRU_GOT_COUNT | MRU_GOT_LAST | MRU_GOT_FIRST \
223 | MRU_GOT_MV | MRU_GOT_RS | MRU_GOT_ADDR)
226 * mrulist() depends on MRUSORT_DEF and MRUSORT_RDEF being the first two
228 typedef enum mru_sort_order_tag {
229 MRUSORT_DEF = 0, /* lstint ascending */
230 MRUSORT_R_DEF, /* lstint descending */
231 MRUSORT_AVGINT, /* avgint ascending */
232 MRUSORT_R_AVGINT, /* avgint descending */
233 MRUSORT_ADDR, /* IPv4 asc. then IPv6 asc. */
234 MRUSORT_R_ADDR, /* IPv6 desc. then IPv4 desc. */
235 MRUSORT_COUNT, /* hit count ascending */
236 MRUSORT_R_COUNT, /* hit count descending */
237 MRUSORT_MAX, /* special: count of this enum */
240 const char * const mru_sort_keywords[MRUSORT_MAX] = {
241 "lstint", /* MRUSORT_DEF */
242 "-lstint", /* MRUSORT_R_DEF */
243 "avgint", /* MRUSORT_AVGINT */
244 "-avgint", /* MRUSORT_R_AVGINT */
245 "addr", /* MRUSORT_ADDR */
246 "-addr", /* MRUSORT_R_ADDR */
247 "count", /* MRUSORT_COUNT */
248 "-count", /* MRUSORT_R_COUNT */
251 typedef int (*qsort_cmp)(const void *, const void *);
254 * Old CTL_PST defines for version 2.
256 #define OLD_CTL_PST_CONFIG 0x80
257 #define OLD_CTL_PST_AUTHENABLE 0x40
258 #define OLD_CTL_PST_AUTHENTIC 0x20
259 #define OLD_CTL_PST_REACH 0x10
260 #define OLD_CTL_PST_SANE 0x08
261 #define OLD_CTL_PST_DISP 0x04
263 #define OLD_CTL_PST_SEL_REJECT 0
264 #define OLD_CTL_PST_SEL_SELCAND 1
265 #define OLD_CTL_PST_SEL_SYNCCAND 2
266 #define OLD_CTL_PST_SEL_SYSPEER 3
268 char flash2[] = " .+* "; /* flash decode for version 2 */
269 char flash3[] = " x.-+#*o"; /* flash decode for peer status version 3 */
274 } g_varlist[MAXLIST] = { { 0, 0 } };
277 * Imported from ntpq.c
279 extern int showhostnames;
280 extern int wideremote;
282 extern struct servent *server_entry;
283 extern struct association *assoc_cache;
284 extern u_char pktversion;
286 typedef struct mru_tag mru;
288 mru * hlink; /* next in hash table bucket */
289 DECL_DLIST_LINK(mru, mlink);
299 typedef struct ifstats_row_tag {
315 typedef struct reslist_row_tag {
323 typedef struct var_display_collection_tag {
324 const char * const tag; /* system variable */
325 const char * const display; /* descriptive text */
326 u_char type; /* NTP_STR, etc */
329 sockaddr_u sau; /* NTP_ADD */
330 l_fp lfp; /* NTP_LFP */
331 } v; /* retrieved value */
333 #if !defined(MISSING_C99_STRUCT_INIT)
334 # define VDC_INIT(a, b, c) { .tag = a, .display = b, .type = c }
336 # define VDC_INIT(a, b, c) { a, b, c }
339 * other local function prototypes
341 void mrulist_ctrl_c_hook(void);
342 static mru * add_mru(mru *);
343 static int collect_mru_list(const char *, l_fp *);
344 static int fetch_nonce(char *, size_t);
345 static int qcmp_mru_avgint(const void *, const void *);
346 static int qcmp_mru_r_avgint(const void *, const void *);
347 static int qcmp_mru_addr(const void *, const void *);
348 static int qcmp_mru_r_addr(const void *, const void *);
349 static int qcmp_mru_count(const void *, const void *);
350 static int qcmp_mru_r_count(const void *, const void *);
351 static void validate_ifnum(FILE *, u_int, int *, ifstats_row *);
352 static void another_ifstats_field(int *, ifstats_row *, FILE *);
353 static void collect_display_vdc(associd_t as, vdc *table,
354 int decodestatus, FILE *fp);
359 static u_int mru_count;
360 static u_int mru_dupes;
361 volatile int mrulist_interrupted;
362 static mru mru_list; /* listhead */
363 static mru ** hash_table;
366 * qsort comparison function table for mrulist(). The first two
367 * entries are NULL because they are handled without qsort().
369 static const qsort_cmp mru_qcmp_table[MRUSORT_MAX] = {
370 NULL, /* MRUSORT_DEF unused */
371 NULL, /* MRUSORT_R_DEF unused */
372 &qcmp_mru_avgint, /* MRUSORT_AVGINT */
373 &qcmp_mru_r_avgint, /* MRUSORT_R_AVGINT */
374 &qcmp_mru_addr, /* MRUSORT_ADDR */
375 &qcmp_mru_r_addr, /* MRUSORT_R_ADDR */
376 &qcmp_mru_count, /* MRUSORT_COUNT */
377 &qcmp_mru_r_count, /* MRUSORT_R_COUNT */
381 * checkassocid - return the association ID, checking to see if it is valid
391 associd = (associd_t)value;
392 if (0 == associd || value != associd) {
395 "***Invalid association ID %lu specified\n",
405 * findlistvar - Look for the named variable in a varlist. If found,
406 * return a pointer to it. Otherwise, if the list has
407 * slots available, return the pointer to the first free
408 * slot, or NULL if it's full.
410 static struct varlist *
412 struct varlist *list,
418 for (vl = list; vl < list + MAXLIST && vl->name != NULL; vl++)
419 if (!strcmp(name, vl->name))
421 if (vl < list + MAXLIST)
429 * doaddvlist - add variable(s) to the variable list
433 struct varlist *vlist,
443 while (nextvar(&len, &vars, &name, &value)) {
444 vl = findlistvar(vlist, name);
446 fprintf(stderr, "Variable list full\n");
450 if (NULL == vl->name) {
451 vl->name = estrdup(name);
452 } else if (vl->value != NULL) {
458 vl->value = estrdup(value);
464 * dormvlist - remove variable(s) from the variable list
468 struct varlist *vlist,
478 while (nextvar(&len, &vars, &name, &value)) {
479 vl = findlistvar(vlist, name);
480 if (vl == 0 || vl->name == 0) {
481 (void) fprintf(stderr, "Variable `%s' not found\n",
484 free((void *)(intptr_t)vl->name);
487 for ( ; (vl+1) < (g_varlist + MAXLIST)
488 && (vl+1)->name != 0; vl++) {
489 vl->name = (vl+1)->name;
490 vl->value = (vl+1)->value;
492 vl->name = vl->value = 0;
499 * doclearvlist - clear a variable list
503 struct varlist *vlist
506 register struct varlist *vl;
508 for (vl = vlist; vl < vlist + MAXLIST && vl->name != 0; vl++) {
509 free((void *)(intptr_t)vl->name);
511 if (vl->value != 0) {
520 * makequerydata - form a data buffer to be included with a query
524 struct varlist *vlist,
529 register struct varlist *vl;
530 register char *cp, *cpend;
531 register int namelen, valuelen;
532 register int totallen;
535 cpend = data + *datalen;
537 for (vl = vlist; vl < vlist + MAXLIST && vl->name != 0; vl++) {
538 namelen = strlen(vl->name);
542 valuelen = strlen(vl->value);
543 totallen = namelen + valuelen + (valuelen != 0) + (cp != data);
544 if (cp + totallen > cpend) {
546 "***Ignoring variables starting with `%s'\n",
553 memcpy(cp, vl->name, (size_t)namelen);
557 memcpy(cp, vl->value, (size_t)valuelen);
561 *datalen = cp - data;
566 * doquerylist - send a message including variables in a list
570 struct varlist *vlist,
579 char data[CTL_MAX_DATA_LEN];
582 datalen = sizeof(data);
583 makequerydata(vlist, &datalen, data);
585 return doquery(op, associd, auth, datalen, data, rstatus, dsize,
591 * doprintvlist - print the variables on a list
595 struct varlist *vlist,
601 if (NULL == vlist->name) {
602 fprintf(fp, "No variables on list\n");
605 for (n = 0; n < MAXLIST && vlist[n].name != NULL; n++) {
606 if (NULL == vlist[n].value)
607 fprintf(fp, "%s\n", vlist[n].name);
609 fprintf(fp, "%s=%s\n", vlist[n].name,
615 * addvars - add variables to the variable list
624 doaddvlist(g_varlist, pcmd->argval[0].string);
629 * rmvars - remove variables from the variable list
638 dormvlist(g_varlist, pcmd->argval[0].string);
643 * clearvars - clear the variable list
652 doclearvlist(g_varlist);
657 * showvars - show variables on the variable list
666 doprintvlist(g_varlist, fp);
671 * dolist - send a request with the given list of variables
675 struct varlist *vlist,
689 * if we're asking for specific variables don't include the
690 * status header line in the output.
695 quiet = (vlist->name != NULL);
697 res = doquerylist(vlist, op, associd, 0, &rstatus, &dsize, &datap);
703 fprintf(fp, "server=%s ", currenthost);
706 fprintf(fp, "No system%s variables returned\n",
707 (type == TYPE_CLOCK) ? " clock" : "");
710 "No information returned for%s association %u\n",
711 (type == TYPE_CLOCK) ? " clock" : "",
717 fprintf(fp, "associd=%u ", associd);
718 printvars(dsize, datap, (int)rstatus, type, quiet, fp);
724 * readlist - send a read variables request with the variables on the list
735 if (pcmd->nargs == 0) {
738 /* HMS: I think we want the u_int32 target here, not the u_long */
739 if (pcmd->argval[0].uval == 0)
741 else if ((associd = checkassocid(pcmd->argval[0].uval)) == 0)
745 type = (0 == associd)
748 dolist(g_varlist, associd, CTL_OP_READVAR, type, fp);
753 * writelist - send a write variables request with the variables on the list
767 if (pcmd->nargs == 0) {
770 /* HMS: Do we really want uval here? */
771 if (pcmd->argval[0].uval == 0)
773 else if ((associd = checkassocid(pcmd->argval[0].uval)) == 0)
777 res = doquerylist(g_varlist, CTL_OP_WRITEVAR, associd, 1, &rstatus,
784 (void) fprintf(fp, "server=%s ", currenthost);
786 (void) fprintf(fp, "done! (no data returned)\n");
788 (void) fprintf(fp,"associd=%u ", associd);
789 printvars(dsize, datap, (int)rstatus,
790 (associd != 0) ? TYPE_PEER : TYPE_SYS, 0, fp);
797 * readvar - send a read variables request with the specified variables
809 struct varlist tmplist[MAXLIST];
813 if (pcmd->nargs == 0 || pcmd->argval[0].uval == 0)
815 else if ((associd = checkassocid(pcmd->argval[0].uval)) == 0)
819 if (pcmd->nargs > 1) {
820 tmpcount = pcmd->nargs - 1;
821 for (u = 0; u < tmpcount; u++)
822 doaddvlist(tmplist, pcmd->argval[1 + u].string);
825 type = (0 == associd)
828 dolist(tmplist, associd, CTL_OP_READVAR, type, fp);
830 doclearvlist(tmplist);
835 * writevar - send a write variables request with the specified variables
849 struct varlist tmplist[MAXLIST];
852 if (pcmd->argval[0].uval == 0)
854 else if ((associd = checkassocid(pcmd->argval[0].uval)) == 0)
858 doaddvlist(tmplist, pcmd->argval[1].string);
860 res = doquerylist(tmplist, CTL_OP_WRITEVAR, associd, 1, &rstatus,
863 doclearvlist(tmplist);
869 fprintf(fp, "server=%s ", currenthost);
871 fprintf(fp, "done! (no data returned)\n");
873 fprintf(fp,"associd=%u ", associd);
874 type = (0 == associd)
877 printvars(dsize, datap, (int)rstatus, type, 0, fp);
884 * clocklist - send a clock variables request with the variables on the list
895 if (pcmd->nargs == 0) {
898 if (pcmd->argval[0].uval == 0)
900 else if ((associd = checkassocid(pcmd->argval[0].uval)) == 0)
904 dolist(g_varlist, associd, CTL_OP_READCLOCK, TYPE_CLOCK, fp);
909 * clockvar - send a clock variables request with the specified variables
918 struct varlist tmplist[MAXLIST];
921 if (pcmd->nargs == 0 || pcmd->argval[0].uval == 0)
923 else if ((associd = checkassocid(pcmd->argval[0].uval)) == 0)
927 if (pcmd->nargs >= 2)
928 doaddvlist(tmplist, pcmd->argval[1].string);
930 dolist(tmplist, associd, CTL_OP_READCLOCK, TYPE_CLOCK, fp);
932 doclearvlist(tmplist);
937 * findassidrange - verify a range of association ID's
949 int ind[COUNTOF(assids)];
957 assids[0] = checkassocid(assid1);
960 assids[1] = checkassocid(assid2);
964 for (a = 0; a < COUNTOF(assids); a++) {
966 for (i = 0; i < numassoc; i++)
967 if (assoc_cache[i].assid == assids[a])
970 for (a = 0; a < COUNTOF(assids); a++)
973 "***Association ID %u not found in list\n",
978 if (ind[0] < ind[1]) {
991 * mreadlist - send a read variables request for multiple associations
1003 if (!findassidrange(pcmd->argval[0].uval, pcmd->argval[1].uval,
1007 for (i = from; i <= to; i++) {
1010 if (!dolist(g_varlist, assoc_cache[i].assid,
1011 CTL_OP_READVAR, TYPE_PEER, fp))
1019 * mreadvar - send a read variables request for multiple associations
1030 struct varlist tmplist[MAXLIST];
1031 struct varlist *pvars;
1033 if (!findassidrange(pcmd->argval[0].uval, pcmd->argval[1].uval,
1038 if (pcmd->nargs >= 3) {
1039 doaddvlist(tmplist, pcmd->argval[2].string);
1045 for (i = from; i <= to; i++) {
1046 if (!dolist(pvars, assoc_cache[i].assid, CTL_OP_READVAR,
1051 if (pvars == tmplist)
1052 doclearvlist(tmplist);
1059 * dogetassoc - query the host for its list of associations
1072 res = doquery(CTL_OP_READSTAT, 0, 0, 0, (char *)0, &rstatus,
1080 fprintf(fp, "server=%s ", currenthost);
1081 fprintf(fp, "No association ID's returned\n");
1087 fprintf(stderr, "server=%s ", currenthost);
1089 "***Server returned %d octets, should be multiple of 4\n",
1097 if (numassoc >= assoc_cache_slots) {
1100 pus = (const void *)datap;
1101 assoc_cache[numassoc].assid = ntohs(*pus);
1102 datap += sizeof(*pus);
1103 pus = (const void *)datap;
1104 assoc_cache[numassoc].status = ntohs(*pus);
1105 datap += sizeof(*pus);
1106 dsize -= 2 * sizeof(*pus);
1108 fprintf(stderr, "[%u] ",
1109 assoc_cache[numassoc].assid);
1114 fprintf(stderr, "\n%d associations total\n", numassoc);
1122 * printassoc - print the current list of associations
1138 const char *condition = "";
1139 const char *last_event;
1142 if (numassoc == 0) {
1143 (void) fprintf(fp, "No association ID's in list\n");
1151 "\nind assid status conf reach auth condition last_event cnt\n");
1153 "===========================================================\n");
1154 for (i = 0; i < numassoc; i++) {
1155 statval = (u_char) CTL_PEER_STATVAL(assoc_cache[i].status);
1156 if (!showall && !(statval & (CTL_PST_CONFIG|CTL_PST_REACH)))
1158 event = CTL_PEER_EVENT(assoc_cache[i].status);
1159 event_count = CTL_PEER_NEVNT(assoc_cache[i].status);
1160 if (statval & CTL_PST_CONFIG)
1164 if (statval & CTL_PST_BCAST) {
1166 if (statval & CTL_PST_AUTHENABLE)
1171 if (statval & CTL_PST_REACH)
1175 if (statval & CTL_PST_AUTHENABLE) {
1176 if (statval & CTL_PST_AUTHENTIC)
1184 if (pktversion > NTP_OLDVERSION) {
1185 switch (statval & 0x7) {
1187 case CTL_PST_SEL_REJECT:
1188 condition = "reject";
1191 case CTL_PST_SEL_SANE:
1192 condition = "falsetick";
1195 case CTL_PST_SEL_CORRECT:
1196 condition = "excess";
1199 case CTL_PST_SEL_SELCAND:
1200 condition = "outlyer";
1203 case CTL_PST_SEL_SYNCCAND:
1204 condition = "candidate";
1207 case CTL_PST_SEL_EXCESS:
1208 condition = "backup";
1211 case CTL_PST_SEL_SYSPEER:
1212 condition = "sys.peer";
1215 case CTL_PST_SEL_PPS:
1216 condition = "pps.peer";
1220 switch (statval & 0x3) {
1222 case OLD_CTL_PST_SEL_REJECT:
1223 if (!(statval & OLD_CTL_PST_SANE))
1224 condition = "insane";
1225 else if (!(statval & OLD_CTL_PST_DISP))
1226 condition = "hi_disp";
1231 case OLD_CTL_PST_SEL_SELCAND:
1232 condition = "sel_cand";
1235 case OLD_CTL_PST_SEL_SYNCCAND:
1236 condition = "sync_cand";
1239 case OLD_CTL_PST_SEL_SYSPEER:
1240 condition = "sys_peer";
1244 switch (PEER_EVENT|event) {
1247 last_event = "mobilize";
1251 last_event = "demobilize";
1255 last_event = "reachable";
1259 last_event = "unreachable";
1263 last_event = "restart";
1267 last_event = "no_reply";
1271 last_event = "rate_exceeded";
1275 last_event = "access_denied";
1279 last_event = "leap_armed";
1283 last_event = "sys_peer";
1287 last_event = "clock_alarm";
1294 snprintf(buf, sizeof(buf),
1295 "%3d %5u %04x %3.3s %4s %4.4s %9.9s %11s %2lu",
1296 i + 1, assoc_cache[i].assid,
1297 assoc_cache[i].status, conf, reach, auth,
1298 condition, last_event, event_count);
1299 bp = buf + strlen(buf);
1300 while (bp > buf && ' ' == bp[-1])
1303 fprintf(fp, "%s\n", buf);
1309 * associations - get, record and print a list of associations
1324 * lassociations - get, record and print a long list of associations
1339 * passociations - print the association list
1353 * lpassociations - print the long association list
1367 * saveconfig - dump ntp server configuration to server file
1380 if (0 == pcmd->nargs)
1383 res = doquery(CTL_OP_SAVECONFIG, 0, 1,
1384 strlen(pcmd->argval[0].string),
1385 pcmd->argval[0].string, &rstatus, &dsize,
1392 fprintf(fp, "(no response message, curiously)");
1394 fprintf(fp, "%.*s", dsize, datap);
1400 * radiostatus - print the radio status returned by the server
1414 res = doquery(CTL_OP_READCLOCK, 0, 0, 0, (char *)0, &rstatus,
1421 (void) fprintf(fp, "server=%s ", currenthost);
1423 (void) fprintf(fp, "No radio status string returned\n");
1427 asciize(dsize, datap, fp);
1432 * when - print how long its been since his last packet arrived
1445 else if (reftime->l_ui != 0)
1450 return (ts->l_ui - lasttime->l_ui);
1455 * Pretty-print an interval into the given buffer, in a human-friendly format.
1471 snprintf(buf, cb, "%ld", diff);
1475 diff = (diff + 29) / 60;
1477 snprintf(buf, cb, "%ldm", diff);
1481 diff = (diff + 29) / 60;
1483 snprintf(buf, cb, "%ldh", diff);
1487 diff = (diff + 11) / 24;
1488 snprintf(buf, cb, "%ldd", diff);
1502 dummy = SRCADR(sock);
1503 ch = (char)(((dummy&0xf0000000)==0xe0000000) ? 'm' :
1504 ((dummy&0x000000ff)==0x000000ff) ? 'b' :
1505 ((dummy&0xffffffff)==0x7f000001) ? 'l' :
1506 ((dummy&0xffffffe0)==0x00000000) ? '-' :
1510 if (IN6_IS_ADDR_MULTICAST(PSOCK_ADDR6(sock)))
1523 * A list of variables required by the peers command
1525 struct varlist opeervarlist[] = {
1526 { "srcadr", 0 }, /* 0 */
1527 { "dstadr", 0 }, /* 1 */
1528 { "stratum", 0 }, /* 2 */
1529 { "hpoll", 0 }, /* 3 */
1530 { "ppoll", 0 }, /* 4 */
1531 { "reach", 0 }, /* 5 */
1532 { "delay", 0 }, /* 6 */
1533 { "offset", 0 }, /* 7 */
1534 { "jitter", 0 }, /* 8 */
1535 { "dispersion", 0 }, /* 9 */
1536 { "rec", 0 }, /* 10 */
1537 { "reftime", 0 }, /* 11 */
1538 { "srcport", 0 }, /* 12 */
1539 { "hmode", 0 }, /* 13 */
1543 struct varlist peervarlist[] = {
1544 { "srcadr", 0 }, /* 0 */
1545 { "refid", 0 }, /* 1 */
1546 { "stratum", 0 }, /* 2 */
1547 { "hpoll", 0 }, /* 3 */
1548 { "ppoll", 0 }, /* 4 */
1549 { "reach", 0 }, /* 5 */
1550 { "delay", 0 }, /* 6 */
1551 { "offset", 0 }, /* 7 */
1552 { "jitter", 0 }, /* 8 */
1553 { "dispersion", 0 }, /* 9 */
1554 { "rec", 0 }, /* 10 */
1555 { "reftime", 0 }, /* 11 */
1556 { "srcport", 0 }, /* 12 */
1557 { "hmode", 0 }, /* 13 */
1558 { "srchost", 0 }, /* 14 */
1564 * Decode an incoming data buffer and print a line in the peer list
1568 struct varlist *pvl,
1587 sockaddr_u dum_store;
1588 sockaddr_u refidadr;
1592 const char *dstadr_refid = "0.0.0.0";
1593 const char *serverlocal;
1608 char whenbuf[8], pollbuf[8];
1609 char clock_name[LENHOSTNAME];
1613 have_srchost = FALSE;
1614 have_dstadr = FALSE;
1615 have_da_rid = FALSE;
1616 have_jitter = FALSE;
1619 clock_name[0] = '\0';
1625 while (nextvar(&datalen, &data, &name, &value)) {
1626 if (!strcmp("srcadr", name) ||
1627 !strcmp("peeradr", name)) {
1628 if (!decodenetnum(value, &srcadr))
1629 fprintf(stderr, "malformed %s=%s\n",
1631 } else if (!strcmp("srchost", name)) {
1632 if (pvl == peervarlist) {
1633 len = strlen(value);
1635 (size_t)len < sizeof(clock_name)) {
1639 memcpy(clock_name, value, len);
1640 clock_name[len] = '\0';
1641 have_srchost = TRUE;
1644 } else if (!strcmp("dstadr", name)) {
1645 if (decodenetnum(value, &dum_store)) {
1646 type = decodeaddrtype(&dum_store);
1649 if (pvl == opeervarlist) {
1651 dstadr_refid = trunc_left(stoa(&dstadr), 15);
1654 } else if (!strcmp("hmode", name)) {
1655 decodeint(value, &hmode);
1656 } else if (!strcmp("refid", name)) {
1657 if (pvl == peervarlist) {
1659 drlen = strlen(value);
1662 } else if (drlen <= 4) {
1664 memcpy(&u32, value, drlen);
1665 dstadr_refid = refid_str(u32, 1);
1666 } else if (decodenetnum(value, &refidadr)) {
1667 if (SOCK_UNSPEC(&refidadr))
1668 dstadr_refid = "0.0.0.0";
1669 else if (ISREFCLOCKADR(&refidadr))
1671 refnumtoa(&refidadr);
1676 have_da_rid = FALSE;
1679 } else if (!strcmp("stratum", name)) {
1680 decodeuint(value, &stratum);
1681 } else if (!strcmp("hpoll", name)) {
1682 if (decodeint(value, &hpoll) && hpoll < 0)
1683 hpoll = NTP_MINPOLL;
1684 } else if (!strcmp("ppoll", name)) {
1685 if (decodeint(value, &ppoll) && ppoll < 0)
1686 ppoll = NTP_MINPOLL;
1687 } else if (!strcmp("reach", name)) {
1688 decodeuint(value, &reach);
1689 } else if (!strcmp("delay", name)) {
1690 decodetime(value, &estdelay);
1691 } else if (!strcmp("offset", name)) {
1692 decodetime(value, &estoffset);
1693 } else if (!strcmp("jitter", name)) {
1694 if (pvl == peervarlist &&
1695 decodetime(value, &estjitter))
1697 } else if (!strcmp("rootdisp", name) ||
1698 !strcmp("dispersion", name)) {
1699 decodetime(value, &estdisp);
1700 } else if (!strcmp("rec", name)) {
1701 decodets(value, &rec);
1702 } else if (!strcmp("srcport", name) ||
1703 !strcmp("peerport", name)) {
1704 decodeuint(value, &srcport);
1705 } else if (!strcmp("reftime", name)) {
1706 if (!decodets(value, &reftime))
1712 * hmode gives the best guidance for the t column. If the response
1713 * did not include hmode we'll use the old decodeaddrtype() result.
1718 /* broadcastclient or multicastclient */
1722 case MODE_BROADCAST:
1723 /* broadcast or multicast server */
1724 if (IS_MCAST(&srcadr))
1731 if (ISREFCLOCKADR(&srcadr))
1732 type = 'l'; /* local refclock*/
1733 else if (SOCK_UNSPEC(&srcadr))
1734 type = 'p'; /* pool */
1735 else if (IS_MCAST(&srcadr))
1736 type = 'a'; /* manycastclient */
1738 type = 'u'; /* unicast */
1742 type = 's'; /* symmetric active */
1743 break; /* configured */
1746 type = 'S'; /* symmetric passive */
1747 break; /* ephemeral */
1751 * Got everything, format the line
1753 poll_sec = 1 << min(ppoll, hpoll);
1754 if (pktversion > NTP_OLDVERSION)
1755 c = flash3[CTL_PEER_STATVAL(rstatus) & 0x7];
1757 c = flash2[CTL_PEER_STATVAL(rstatus) & 0x3];
1759 if (peervarlist == pvl && have_dstadr) {
1760 serverlocal = nntohost_col(&dstadr,
1761 (size_t)min(LIB_BUFLENGTH - 1, maxhostlen),
1764 if (currenthostisnum)
1765 serverlocal = trunc_left(currenthost,
1768 serverlocal = currenthost;
1770 fprintf(fp, "%-*s ", (int)maxhostlen, serverlocal);
1772 if (AF_UNSPEC == af || AF(&srcadr) == af) {
1774 strlcpy(clock_name, nntohost(&srcadr),
1775 sizeof(clock_name));
1776 if (wideremote && 15 < strlen(clock_name))
1777 fprintf(fp, "%c%s\n ", c, clock_name);
1779 fprintf(fp, "%c%-15.15s ", c, clock_name);
1783 drlen = strlen(dstadr_refid);
1784 makeascii(drlen, dstadr_refid, fp);
1786 while (drlen++ < 15)
1789 " %2ld %c %4.4s %4.4s %3lo %7.7s %8.7s %7.7s\n",
1791 prettyinterval(whenbuf, sizeof(whenbuf),
1792 when(&ts, &rec, &reftime)),
1793 prettyinterval(pollbuf, sizeof(pollbuf),
1795 reach, lfptoms(&estdelay, 3),
1796 lfptoms(&estoffset, 3),
1798 ? lfptoms(&estjitter, 3)
1799 : lfptoms(&estdisp, 3));
1808 * dogetpeers - given an association ID, read and print the spreadsheet
1813 struct varlist *pvl,
1825 res = doquerylist(pvl, CTL_OP_READVAR, associd, 0, &rstatus,
1831 res = doquery(CTL_OP_READVAR, associd, 0, 0, NULL, &rstatus,
1840 fprintf(stderr, "server=%s ", currenthost);
1842 "***No information returned for association %u\n",
1847 return doprintpeers(pvl, associd, (int)rstatus, dsize, datap,
1853 * peers - print a peer spreadsheet
1863 char fullname[LENHOSTNAME];
1865 const char * name_or_num;
1868 if (!dogetassoc(fp))
1871 for (u = 0; u < numhosts; u++) {
1872 if (getnetnum(chosts[u].name, &netnum, fullname, af)) {
1873 name_or_num = nntohost(&netnum);
1874 sl = strlen(name_or_num);
1875 maxhostlen = max(maxhostlen, sl);
1879 fprintf(fp, "%-*.*s ", (int)maxhostlen, (int)maxhostlen,
1882 " remote refid st t when poll reach delay offset jitter\n");
1884 for (u = 0; u <= maxhostlen; u++)
1887 "==============================================================================\n");
1889 for (u = 0; u < numassoc; u++) {
1891 !(CTL_PEER_STATVAL(assoc_cache[u].status)
1892 & (CTL_PST_CONFIG|CTL_PST_REACH))) {
1894 fprintf(stderr, "eliding [%d]\n",
1895 (int)assoc_cache[u].assid);
1898 if (!dogetpeers(peervarlist, (int)assoc_cache[u].assid,
1907 * peers - print a peer spreadsheet
1918 if (pcmd->nargs == 1) {
1919 if (pcmd->argval->ival == 6)
1929 * lpeers - print a peer spreadsheet including all fuzzball peers
1940 if (pcmd->nargs == 1) {
1941 if (pcmd->argval->ival == 6)
1951 * opeers - print a peer spreadsheet
1961 char fullname[LENHOSTNAME];
1964 if (!dogetassoc(fp))
1967 for (i = 0; i < numhosts; ++i) {
1968 if (getnetnum(chosts[i].name, &netnum, fullname, af))
1969 if (strlen(fullname) > maxhostlen)
1970 maxhostlen = strlen(fullname);
1973 fprintf(fp, "%-*.*s ", (int)maxhostlen, (int)maxhostlen,
1976 " remote local st t when poll reach delay offset disp\n");
1978 for (i = 0; i <= maxhostlen; ++i)
1981 "==============================================================================\n");
1983 for (i = 0; i < numassoc; i++) {
1985 !(CTL_PEER_STATVAL(assoc_cache[i].status) &
1986 (CTL_PST_CONFIG | CTL_PST_REACH)))
1988 if (!dogetpeers(opeervarlist, assoc_cache[i].assid, fp, af))
1996 * opeers - print a peer spreadsheet the old way
2007 if (pcmd->nargs == 1) {
2008 if (pcmd->argval->ival == 6)
2013 doopeers(0, fp, af);
2018 * lopeers - print a peer spreadsheet including all fuzzball peers
2029 if (pcmd->nargs == 1) {
2030 if (pcmd->argval->ival == 6)
2035 doopeers(1, fp, af);
2040 * config - send a configuration command to a remote host
2057 cfgcmd = pcmd->argval[0].string;
2063 "Command = %s\n", pcmd->keyword, cfgcmd);
2065 res = doquery(CTL_OP_CONFIGURE, 0, 1, strlen(cfgcmd), cfgcmd,
2066 &rstatus, &rsize, &rdata);
2071 if (rsize > 0 && '\n' == rdata[rsize - 1])
2074 resp = emalloc(rsize + 1);
2075 memcpy(resp, rdata, rsize);
2079 if (1 == sscanf(resp, "column %d syntax error", &col)
2080 && col >= 0 && (size_t)col <= strlen(cfgcmd) + 1) {
2082 printf("______"); /* "ntpq> " */
2083 printf("________"); /* ":config " */
2085 printf("%s\n", cfgcmd);
2086 for (i = 1; i < col; i++)
2090 printf("%s\n", resp);
2096 * config_from_file - remotely configure an ntpd daemon using the
2097 * specified configuration file
2098 * SK: This function is a kludge at best and is full of bad design
2100 * 1. ntpq uses UDP, which means that there is no guarantee of in-order,
2101 * error-free delivery.
2102 * 2. The maximum length of a packet is constrained, and as a result, the
2103 * maximum length of a line in a configuration file is constrained.
2104 * Longer lines will lead to unpredictable results.
2105 * 3. Since this function is sending a line at a time, we can't update
2106 * the control key through the configuration file (YUCK!!)
2119 char config_cmd[MAXLINE];
2128 "Filename = %s\n", pcmd->keyword,
2129 pcmd->argval[0].string);
2131 config_fd = fopen(pcmd->argval[0].string, "r");
2132 if (NULL == config_fd) {
2133 printf("ERROR!! Couldn't open file: %s\n",
2134 pcmd->argval[0].string);
2138 printf("Sending configuration file, one line at a time.\n");
2140 while (fgets(config_cmd, MAXLINE, config_fd) != NULL) {
2141 config_len = strlen(config_cmd);
2142 /* ensure even the last line has newline, if possible */
2143 if (config_len > 0 &&
2144 config_len + 2 < sizeof(config_cmd) &&
2145 '\n' != config_cmd[config_len - 1])
2146 config_cmd[config_len++] = '\n';
2150 res = doquery(CTL_OP_CONFIGURE, 0, 1,
2151 strlen(config_cmd), config_cmd,
2152 &rstatus, &rsize, &rdata);
2153 while (res != 0 && retry_limit--);
2155 printf("Line No: %d query failed: %s", i,
2157 printf("Subsequent lines not sent.\n");
2162 if (rsize > 0 && '\n' == rdata[rsize - 1])
2164 if (rsize > 0 && '\r' == rdata[rsize - 1])
2166 printf("Line No: %d %.*s: %s", i, rsize, rdata,
2169 printf("Done sending file\n");
2180 const char nonce_eq[] = "nonce=";
2188 * Retrieve a nonce specific to this client to demonstrate to
2189 * ntpd that we're capable of receiving responses to our source
2190 * IP address, and thereby unlikely to be forging the source.
2192 qres = doquery(CTL_OP_REQ_NONCE, 0, 0, 0, NULL, &rstatus,
2195 fprintf(stderr, "nonce request failed\n");
2199 if ((size_t)rsize <= sizeof(nonce_eq) - 1 ||
2200 strncmp(rdata, nonce_eq, sizeof(nonce_eq) - 1)) {
2201 fprintf(stderr, "unexpected nonce response format: %.*s\n",
2205 chars = rsize - (sizeof(nonce_eq) - 1);
2206 if (chars >= (int)cb_nonce)
2208 memcpy(nonce, rdata + sizeof(nonce_eq) - 1, chars);
2209 nonce[chars] = '\0';
2211 ('\r' == nonce[chars - 1] || '\n' == nonce[chars - 1])) {
2213 nonce[chars] = '\0';
2221 * add_mru Add and entry to mru list, hash table, and allocate
2222 * and return a replacement.
2223 * This is a helper for collect_mru_list().
2235 hash = NTP_HASH_ADDR(&add->addr);
2236 /* see if we have it among previously received entries */
2237 for (mon = hash_table[hash]; mon != NULL; mon = mon->hlink)
2238 if (SOCK_EQ(&mon->addr, &add->addr))
2241 if (!L_ISGEQ(&add->first, &mon->first)) {
2243 "add_mru duplicate %s new first ts %08x.%08x precedes prior %08x.%08x\n",
2244 sptoa(&add->addr), add->last.l_ui,
2245 add->last.l_uf, mon->last.l_ui,
2249 UNLINK_DLIST(mon, mlink);
2250 UNLINK_SLIST(unlinked, hash_table[hash], mon, hlink, mru);
2251 NTP_INSIST(unlinked == mon);
2253 TRACE(2, ("(updated from %08x.%08x) ", mon->last.l_ui,
2256 LINK_DLIST(mru_list, add, mlink);
2257 LINK_SLIST(hash_table[hash], add, hlink);
2258 TRACE(2, ("add_mru %08x.%08x c %d m %d v %d rest %x first %08x.%08x %s\n",
2259 add->last.l_ui, add->last.l_uf, add->count,
2260 (int)add->mode, (int)add->ver, (u_int)add->rs,
2261 add->first.l_ui, add->first.l_uf, sptoa(&add->addr)));
2262 /* if we didn't update an existing entry, alloc replacement */
2264 mon = emalloc(sizeof(*mon));
2273 /* MGOT macro is specific to collect_mru_list() */
2277 if (MRU_GOT_ALL == got) { \
2279 mon = add_mru(mon); \
2286 mrulist_ctrl_c_hook(void)
2288 mrulist_interrupted = TRUE;
2298 const u_int sleep_msecs = 5;
2299 static int ntpd_row_limit = MRU_ROW_LIMIT;
2300 int c_mru_l_rc; /* this function's return code */
2301 u_char got; /* MRU_GOT_* bits */
2310 char req_buf[CTL_MAX_DATA_LEN];
2323 int si; /* server index in response */
2324 int ci; /* client (our) index for validation */
2325 int ri; /* request index (.# suffix) */
2329 sockaddr_u addr_older;
2331 int have_addr_older;
2332 int have_last_older;
2333 u_int restarted_count;
2338 if (!fetch_nonce(nonce, sizeof(nonce)))
2342 restarted_count = 0;
2344 INIT_DLIST(mru_list, mlink);
2345 cb = NTP_HASH_SIZE * sizeof(*hash_table);
2346 NTP_INSIST(NULL == hash_table);
2347 hash_table = emalloc_zero(cb);
2350 list_complete = FALSE;
2356 mon = emalloc_zero(cb);
2359 mrulist_interrupted = FALSE;
2360 set_ctrl_c_hook(&mrulist_ctrl_c_hook);
2362 "Ctrl-C will stop MRU retrieval and display partial results.\n");
2364 next_report = time(NULL) + MRU_REPORT_SECS;
2366 limit = min(3 * MAXFRAGS, ntpd_row_limit);
2368 snprintf(req_buf, sizeof(req_buf), "nonce=%s, frags=%d%s",
2369 nonce, frags, parms);
2374 fprintf(stderr, "READ_MRU parms: %s\n", req_buf);
2376 qres = doqueryex(CTL_OP_READ_MRU, 0, 0, strlen(req_buf),
2377 req_buf, &rstatus, &rsize, &rdata, TRUE);
2379 if (CERR_UNKNOWNVAR == qres && ri > 0) {
2381 * None of the supplied prior entries match, so
2382 * toss them from our list and try again.
2386 "no overlap between %d prior entries and server MRU list\n",
2389 recent = HEAD_DLIST(mru_list, mlink);
2390 NTP_INSIST(recent != NULL);
2393 "tossing prior entry %s to resync\n",
2394 sptoa(&recent->addr));
2395 UNLINK_DLIST(recent, mlink);
2396 hash = NTP_HASH_ADDR(&recent->addr);
2397 UNLINK_SLIST(unlinked, hash_table[hash],
2398 recent, hlink, mru);
2399 NTP_INSIST(unlinked == recent);
2403 if (NULL == HEAD_DLIST(mru_list, mlink)) {
2405 if (restarted_count > 8) {
2407 "Giving up after 8 restarts from the beginning.\n"
2408 "With high-traffic NTP servers, this can occur if the\n"
2409 "MRU list is limited to less than about 16 seconds' of\n"
2410 "entries. See the 'mru' ntp.conf directive to adjust.\n");
2411 goto cleanup_return;
2415 "---> Restarting from the beginning, retry #%u\n",
2418 } else if (CERR_UNKNOWNVAR == qres) {
2420 "CERR_UNKNOWNVAR from ntpd but no priors given.\n");
2421 goto cleanup_return;
2422 } else if (CERR_BADVALUE == qres) {
2427 "Reverted to row limit from fragments limit.\n");
2429 /* ntpd has lower cap on row limit */
2431 limit = min(limit, ntpd_row_limit);
2434 "Row limit reduced to %d following CERR_BADVALUE.\n",
2437 } else if (ERR_INCOMPLETE == qres ||
2438 ERR_TIMEOUT == qres) {
2440 * Reduce the number of rows/frags requested by
2441 * half to recover from lost response fragments.
2444 frags = max(2, frags / 2);
2447 "Frag limit reduced to %d following incomplete response.\n",
2450 limit = max(2, limit / 2);
2453 "Row limit reduced to %d following incomplete response.\n",
2457 show_error_msg(qres, 0);
2458 goto cleanup_return;
2461 * This is a cheap cop-out implementation of rawmode
2462 * output for mrulist. A better approach would be to
2463 * dump similar output after the list is collected by
2464 * ntpq with a continuous sequence of indexes. This
2465 * cheap approach has indexes resetting to zero for
2466 * each query/response, and duplicates are not
2469 if (!qres && rawmode)
2470 printvars(rsize, rdata, rstatus, TYPE_SYS, 1, stdout);
2472 have_addr_older = FALSE;
2473 have_last_older = FALSE;
2474 while (!qres && nextvar(&rsize, &rdata, &tag, &val)) {
2476 fprintf(stderr, "nextvar gave: %s = %s\n",
2481 if (!strcmp(tag, "addr.older")) {
2482 if (!have_last_older) {
2484 "addr.older %s before last.older\n",
2486 goto cleanup_return;
2488 if (!decodenetnum(val, &addr_older)) {
2490 "addr.older %s garbled\n",
2492 goto cleanup_return;
2494 hash = NTP_HASH_ADDR(&addr_older);
2495 for (recent = hash_table[hash];
2497 recent = recent->hlink)
2502 if (NULL == recent) {
2504 "addr.older %s not in hash table\n",
2506 goto cleanup_return;
2508 if (!L_ISEQU(&last_older,
2511 "last.older %08x.%08x mismatches %08x.%08x expected.\n",
2516 goto cleanup_return;
2518 have_addr_older = TRUE;
2519 } else if (1 != sscanf(tag, "addr.%d", &si)
2522 else if (decodenetnum(val, &mon->addr))
2527 if (!strcmp(tag, "last.older")) {
2528 if ('0' != val[0] ||
2530 !hextolfp(val + 2, &last_older)) {
2532 "last.older %s garbled\n",
2534 goto cleanup_return;
2536 have_last_older = TRUE;
2537 } else if (!strcmp(tag, "last.newest")) {
2540 "last.newest %s before complete row, got = 0x%x\n",
2542 goto cleanup_return;
2546 "last.newest %s before now=\n",
2548 goto cleanup_return;
2550 head = HEAD_DLIST(mru_list, mlink);
2552 if ('0' != val[0] ||
2554 !hextolfp(val + 2, &newest) ||
2558 "last.newest %s mismatches %08x.%08x",
2562 goto cleanup_return;
2565 list_complete = TRUE;
2566 } else if (1 != sscanf(tag, "last.%d", &si) ||
2567 si != ci || '0' != val[0] ||
2569 !hextolfp(val + 2, &mon->last)) {
2574 * allow interrupted retrieval,
2575 * using most recent retrieved
2576 * entry's last seen timestamp
2577 * as the end of operation.
2584 if (1 != sscanf(tag, "first.%d", &si) ||
2585 si != ci || '0' != val[0] ||
2587 !hextolfp(val + 2, &mon->first))
2589 MGOT(MRU_GOT_FIRST);
2593 if (!strcmp(tag, "nonce")) {
2594 strlcpy(nonce, val, sizeof(nonce));
2597 } else if (strcmp(tag, "now") ||
2600 !hextolfp(val + 2, pnow))
2606 if (1 != sscanf(tag, "ct.%d", &si) ||
2608 1 != sscanf(val, "%d", &mon->count)
2611 MGOT(MRU_GOT_COUNT);
2615 if (1 != sscanf(tag, "mv.%d", &si) ||
2617 1 != sscanf(val, "%d", &mv))
2619 mon->mode = PKT_MODE(mv);
2620 mon->ver = PKT_VERSION(mv);
2625 if (1 != sscanf(tag, "rs.%d", &si) ||
2627 1 != sscanf(val, "0x%hx", &mon->rs))
2635 /* ignore unknown tags */
2639 list_complete = TRUE;
2640 if (list_complete) {
2641 NTP_INSIST(0 == ri || have_addr_older);
2643 if (mrulist_interrupted) {
2644 printf("mrulist retrieval interrupted by operator.\n"
2645 "Displaying partial client list.\n");
2648 if (list_complete || mrulist_interrupted) {
2650 "\rRetrieved %u unique MRU entries and %u updates.\n",
2651 mru_count, mru_dupes);
2655 if (time(NULL) >= next_report) {
2656 next_report += MRU_REPORT_SECS;
2657 fprintf(stderr, "\r%u (%u updates) ", mru_count,
2663 * Snooze for a bit between queries to let ntpd catch
2664 * up with other duties.
2668 #elif !defined(HAVE_NANOSLEEP)
2669 sleep((sleep_msecs / 1000) + 1);
2672 struct timespec interv = { 0,
2673 1000 * sleep_msecs };
2674 nanosleep(&interv, NULL);
2678 * If there were no errors, increase the number of rows
2679 * to a maximum of 3 * MAXFRAGS (the most packets ntpq
2680 * can handle in one response), on the assumption that
2681 * no less than 3 rows fit in each packet, capped at
2682 * our best guess at the server's row limit.
2686 frags = min(MAXFRAGS, frags + 1);
2688 limit = min3(3 * MAXFRAGS,
2695 * prepare next query with as many address and last-seen
2696 * timestamps as will fit in a single packet.
2699 req_end = req_buf + sizeof(req_buf);
2700 #define REQ_ROOM (req_end - req)
2701 snprintf(req, REQ_ROOM, "nonce=%s, %s=%d%s", nonce,
2711 if (nonce_uses >= 4) {
2712 if (!fetch_nonce(nonce, sizeof(nonce)))
2713 goto cleanup_return;
2718 for (ri = 0, recent = HEAD_DLIST(mru_list, mlink);
2720 ri++, recent = NEXT_DLIST(mru_list, recent, mlink)) {
2722 snprintf(buf, sizeof(buf),
2723 ", addr.%d=%s, last.%d=0x%08x.%08x",
2724 ri, sptoa(&recent->addr), ri,
2725 recent->last.l_ui, recent->last.l_uf);
2726 chars = strlen(buf);
2727 if (REQ_ROOM - chars < 1)
2729 memcpy(req, buf, chars + 1);
2734 set_ctrl_c_hook(NULL);
2736 goto retain_hash_table;
2751 * qcmp_mru_addr - sort MRU entries by remote address.
2753 * All IPv4 addresses sort before any IPv6, addresses are sorted by
2754 * value within address family.
2762 const mru * const * ppm1 = v1;
2763 const mru * const * ppm2 = v2;
2774 af1 = AF(&pm1->addr);
2775 af2 = AF(&pm2->addr);
2778 return (AF_INET == af1)
2782 cmplen = SIZEOF_INADDR(af1);
2783 addr_off = (AF_INET == af1)
2784 ? offsetof(struct sockaddr_in, sin_addr)
2785 : offsetof(struct sockaddr_in6, sin6_addr);
2787 return memcmp((const char *)&pm1->addr + addr_off,
2788 (const char *)&pm2->addr + addr_off,
2799 return -qcmp_mru_addr(v1, v2);
2804 * qcmp_mru_count - sort MRU entries by times seen (hit count).
2812 const mru * const * ppm1 = v1;
2813 const mru * const * ppm2 = v2;
2820 return (pm1->count < pm2->count)
2822 : ((pm1->count == pm2->count)
2834 return -qcmp_mru_count(v1, v2);
2839 * qcmp_mru_avgint - sort MRU entries by average interval.
2847 const mru * const * ppm1 = v1;
2848 const mru * const * ppm2 = v2;
2858 interval = pm1->last;
2859 L_SUB(&interval, &pm1->first);
2860 LFPTOD(&interval, avg1);
2863 interval = pm2->last;
2864 L_SUB(&interval, &pm2->first);
2865 LFPTOD(&interval, avg2);
2870 else if (avg1 > avg2)
2873 /* secondary sort on lstint - rarely tested */
2874 if (L_ISEQU(&pm1->last, &pm2->last))
2876 else if (L_ISGEQ(&pm1->last, &pm2->last))
2889 return -qcmp_mru_avgint(v1, v2);
2894 * mrulist - ntpq's mrulist command to fetch an arbitrarily large Most
2895 * Recently Used (seen) remote address list from ntpd.
2897 * Similar to ntpdc's monlist command, but not limited to a single
2898 * request/response, and thereby not limited to a few hundred remote
2901 * See ntpd/ntp_control.c read_mru_list() for comments on the way
2902 * CTL_OP_READ_MRU is designed to be used.
2904 * mrulist intentionally differs from monlist in the way the avgint
2905 * column is calculated. monlist includes the time after the last
2906 * packet from the client until the monlist query time in the average,
2907 * while mrulist excludes it. That is, monlist's average interval grows
2908 * over time for remote addresses not heard from in some time, while it
2909 * remains unchanged in mrulist. This also affects the avgint value for
2910 * entries representing a single packet, with identical first and last
2911 * timestamps. mrulist shows 0 avgint, monlist shows a value identical
2916 struct parse * pcmd,
2920 const char mincount_eq[] = "mincount=";
2921 const char resall_eq[] = "resall=";
2922 const char resany_eq[] = "resany=";
2923 const char maxlstint_eq[] = "maxlstint=";
2924 const char laddr_eq[] = "laddr=";
2925 const char sort_eq[] = "sort=";
2926 mru_sort_order order;
2928 char parms_buf[128];
2944 order = MRUSORT_DEF;
2945 parms_buf[0] = '\0';
2947 for (i = 0; i < pcmd->nargs; i++) {
2948 arg = pcmd->argval[i].string;
2950 cb = strlen(arg) + 1;
2951 if ((!strncmp(resall_eq, arg, sizeof(resall_eq)
2952 - 1) || !strncmp(resany_eq, arg,
2953 sizeof(resany_eq) - 1) || !strncmp(
2954 mincount_eq, arg, sizeof(mincount_eq) - 1)
2955 || !strncmp(laddr_eq, arg, sizeof(laddr_eq)
2956 - 1) || !strncmp(maxlstint_eq, arg,
2957 sizeof(laddr_eq) - 1)) && parms + cb + 2 <=
2958 parms_buf + sizeof(parms_buf)) {
2959 /* these are passed intact to ntpd */
2960 memcpy(parms, ", ", 2);
2962 memcpy(parms, arg, cb);
2964 } else if (!strncmp(sort_eq, arg,
2965 sizeof(sort_eq) - 1)) {
2966 arg += sizeof(sort_eq) - 1;
2968 n < COUNTOF(mru_sort_keywords);
2970 if (!strcmp(mru_sort_keywords[n],
2973 if (n < COUNTOF(mru_sort_keywords))
2975 } else if (!strcmp("limited", arg) ||
2976 !strcmp("kod", arg)) {
2977 /* transform to resany=... */
2978 snprintf(buf, sizeof(buf),
2983 cb = 1 + strlen(buf);
2985 parms_buf + sizeof(parms_buf)) {
2986 memcpy(parms, buf, cb);
2991 "ignoring unrecognized mrulist parameter: %s\n",
2997 if (!collect_mru_list(parms, &now))
3000 /* display the results */
3002 goto cleanup_return;
3004 /* construct an array of entry pointers in default order */
3005 sorted = emalloc(mru_count * sizeof(*sorted));
3007 if (MRUSORT_R_DEF != order) {
3008 ITER_DLIST_BEGIN(mru_list, recent, mlink, mru)
3009 NTP_INSIST(ppentry < sorted + mru_count);
3014 REV_ITER_DLIST_BEGIN(mru_list, recent, mlink, mru)
3015 NTP_INSIST(ppentry < sorted + mru_count);
3018 REV_ITER_DLIST_END()
3021 if (ppentry - sorted != (int)mru_count) {
3023 "mru_count %u should match MRU list depth %ld.\n",
3024 mru_count, (long)(ppentry - sorted));
3026 goto cleanup_return;
3029 /* re-sort sorted[] if not default or reverse default */
3030 if (MRUSORT_R_DEF < order)
3031 qsort(sorted, mru_count, sizeof(sorted[0]),
3032 mru_qcmp_table[order]);
3034 printf( "lstint avgint rstr r m v count rport remote address\n"
3035 "==============================================================================\n");
3037 for (ppentry = sorted; ppentry < sorted + mru_count; ppentry++) {
3040 L_SUB(&interval, &recent->last);
3041 LFPTOD(&interval, flstint);
3042 lstint = (int)(flstint + 0.5);
3043 interval = recent->last;
3044 L_SUB(&interval, &recent->first);
3045 LFPTOD(&interval, favgint);
3046 favgint /= recent->count;
3047 avgint = (int)(favgint + 0.5);
3048 fprintf(fp, "%6d %6d %4hx %c %d %d %6d %5u %s\n",
3049 lstint, avgint, recent->rs,
3050 (RES_KOD & recent->rs)
3052 : (RES_LIMITED & recent->rs)
3055 (int)recent->mode, (int)recent->ver,
3056 recent->count, SRCPORT(&recent->addr),
3057 nntohost(&recent->addr));
3064 "--- completed, freeing sorted[] pointers\n");
3071 fprintf(stderr, "... freeing MRU entries\n");
3074 ITER_DLIST_BEGIN(mru_list, recent, mlink, mru)
3078 fprintf(stderr, "... freeing hash_table[]\n");
3083 INIT_DLIST(mru_list, mlink);
3088 * validate_ifnum - helper for ifstats()
3090 * Ensures rows are received in order and complete.
3100 if (prow->ifnum == ifnum)
3102 if (prow->ifnum + 1 == ifnum) {
3103 if (*pfields < IFSTATS_FIELDS)
3104 fprintf(fp, "Warning: incomplete row with %d (of %d) fields",
3105 *pfields, IFSTATS_FIELDS);
3107 prow->ifnum = ifnum;
3111 "received if index %u, have %d of %d fields for index %u, aborting.\n",
3112 ifnum, *pfields, IFSTATS_FIELDS, prow->ifnum);
3118 * another_ifstats_field - helper for ifstats()
3120 * If all fields for the row have been received, print it.
3123 another_ifstats_field(
3132 /* we understand 12 tags */
3133 if (IFSTATS_FIELDS > *pfields)
3136 " interface name send\n"
3137 " # address/broadcast drop flag ttl mc received sent failed peers uptime\n"
3138 "==============================================================================\n");
3141 "%3u %-24.24s %c %4x %3d %2d %6d %6d %6d %5d %8d\n"
3143 prow->ifnum, prow->name,
3147 prow->flags, prow->ttl, prow->mcast_count,
3148 prow->received, prow->sent, prow->send_errors,
3149 prow->peer_count, prow->uptime, sptoa(&prow->addr));
3150 if (!SOCK_UNSPEC(&prow->bcast))
3151 fprintf(fp, " %s\n", sptoa(&prow->bcast));
3152 ifnum = prow->ifnum;
3154 prow->ifnum = ifnum;
3159 * ifstats - ntpq -c ifstats modeled on ntpdc -c ifstats.
3163 struct parse * pcmd,
3167 const char addr_fmt[] = "addr.%u";
3168 const char bcast_fmt[] = "bcast.%u";
3169 const char en_fmt[] = "en.%u"; /* enabled */
3170 const char flags_fmt[] = "flags.%u";
3171 const char mc_fmt[] = "mc.%u"; /* mcast count */
3172 const char name_fmt[] = "name.%u";
3173 const char pc_fmt[] = "pc.%u"; /* peer count */
3174 const char rx_fmt[] = "rx.%u";
3175 const char tl_fmt[] = "tl.%u"; /* ttl */
3176 const char tx_fmt[] = "tx.%u";
3177 const char txerr_fmt[] = "txerr.%u";
3178 const char up_fmt[] = "up.%u"; /* uptime */
3191 qres = doquery(CTL_OP_READ_ORDLIST_A, 0, TRUE, 0, NULL, &rstatus,
3193 if (qres) /* message already displayed */
3197 " interface name send\n"
3198 " # address/broadcast drop flag ttl mc received sent failed peers uptime\n"
3199 "==============================================================================\n");
3205 while (nextvar(&dsize, &datap, &tag, &val)) {
3207 fprintf(stderr, "nextvar gave: %s = %s\n", tag,
3215 if (1 == sscanf(tag, addr_fmt, &ui) &&
3216 decodenetnum(val, &row.addr))
3221 if (1 == sscanf(tag, bcast_fmt, &ui) &&
3223 decodenetnum(val, &row.bcast)))
3228 if (1 == sscanf(tag, en_fmt, &ui) &&
3229 1 == sscanf(val, "%d", &row.enabled))
3234 if (1 == sscanf(tag, flags_fmt, &ui) &&
3235 1 == sscanf(val, "0x%x", &row.flags))
3240 if (1 == sscanf(tag, mc_fmt, &ui) &&
3241 1 == sscanf(val, "%d", &row.mcast_count))
3246 if (1 == sscanf(tag, name_fmt, &ui)) {
3250 len - 2 < sizeof(row.name)) {
3252 memcpy(row.name, val + 1, len);
3253 row.name[len] = '\0';
3260 if (1 == sscanf(tag, pc_fmt, &ui) &&
3261 1 == sscanf(val, "%d", &row.peer_count))
3266 if (1 == sscanf(tag, rx_fmt, &ui) &&
3267 1 == sscanf(val, "%d", &row.received))
3272 if (1 == sscanf(tag, tl_fmt, &ui) &&
3273 1 == sscanf(val, "%d", &row.ttl))
3275 else if (1 == sscanf(tag, tx_fmt, &ui) &&
3276 1 == sscanf(val, "%d", &row.sent))
3278 else if (1 == sscanf(tag, txerr_fmt, &ui) &&
3279 1 == sscanf(val, "%d", &row.send_errors))
3284 if (1 == sscanf(tag, up_fmt, &ui) &&
3285 1 == sscanf(val, "%d", &row.uptime))
3291 /* error out if rows out of order */
3292 validate_ifnum(fp, ui, &fields, &row);
3293 /* if the row is complete, print it */
3294 another_ifstats_field(&fields, &row, fp);
3297 if (fields != IFSTATS_FIELDS)
3298 fprintf(fp, "Warning: incomplete row with %d (of %d) fields",
3299 fields, IFSTATS_FIELDS);
3306 * validate_reslist_idx - helper for reslist()
3308 * Ensures rows are received in order and complete.
3311 validate_reslist_idx(
3318 if (prow->idx == idx)
3320 if (prow->idx + 1 == idx) {
3321 if (*pfields < RESLIST_FIELDS)
3322 fprintf(fp, "Warning: incomplete row with %d (of %d) fields",
3323 *pfields, RESLIST_FIELDS);
3329 "received reslist index %u, have %d of %d fields for index %u, aborting.\n",
3330 idx, *pfields, RESLIST_FIELDS, prow->idx);
3336 * another_reslist_field - helper for reslist()
3338 * If all fields for the row have been received, print it.
3341 another_reslist_field(
3347 char addrmaskstr[128];
3348 int prefix; /* subnet mask as prefix bits count */
3352 /* we understand 4 tags */
3353 if (RESLIST_FIELDS > *pfields)
3356 prefix = sockaddr_masktoprefixlen(&prow->mask);
3358 snprintf(addrmaskstr, sizeof(addrmaskstr), "%s/%d",
3359 stoa(&prow->addr), prefix);
3361 snprintf(addrmaskstr, sizeof(addrmaskstr), "%s %s",
3362 stoa(&prow->addr), stoa(&prow->mask));
3365 " hits addr/prefix or addr mask\n"
3367 "==============================================================================\n");
3372 prow->hits, addrmaskstr, prow->flagstr);
3380 * reslist - ntpq -c reslist modeled on ntpdc -c reslist.
3384 struct parse * pcmd,
3388 const char addr_fmtu[] = "addr.%u";
3389 const char mask_fmtu[] = "mask.%u";
3390 const char hits_fmt[] = "hits.%u";
3391 const char flags_fmt[] = "flags.%u";
3392 const char qdata[] = "addr_restrictions";
3393 const int qdata_chars = COUNTOF(qdata) - 1;
3406 qres = doquery(CTL_OP_READ_ORDLIST_A, 0, TRUE, qdata_chars,
3407 qdata, &rstatus, &dsize, &datap);
3408 if (qres) /* message already displayed */
3412 " hits addr/prefix or addr mask\n"
3414 "==============================================================================\n");
3420 while (nextvar(&dsize, &datap, &tag, &val)) {
3422 fprintf(stderr, "nextvar gave: %s = %s\n", tag,
3430 if (1 == sscanf(tag, addr_fmtu, &ui) &&
3431 decodenetnum(val, &row.addr))
3436 if (1 == sscanf(tag, flags_fmt, &ui)) {
3438 row.flagstr[0] = '\0';
3442 memcpy(row.flagstr, val, len);
3443 row.flagstr[len] = '\0';
3450 if (1 == sscanf(tag, hits_fmt, &ui) &&
3451 1 == sscanf(val, "%lu", &row.hits))
3456 if (1 == sscanf(tag, mask_fmtu, &ui) &&
3457 decodenetnum(val, &row.mask))
3463 /* error out if rows out of order */
3464 validate_reslist_idx(fp, ui, &fields, &row);
3465 /* if the row is complete, print it */
3466 another_reslist_field(&fields, &row, fp);
3469 if (fields != RESLIST_FIELDS)
3470 fprintf(fp, "Warning: incomplete row with %d (of %d) fields",
3471 fields, RESLIST_FIELDS);
3478 * collect_display_vdc
3481 collect_display_vdc(
3488 static const char * const suf[2] = { "adr", "port" };
3489 static const char * const leapbits[4] = { "00", "01",
3491 struct varlist vl[MAXLIST];
3507 for (pvdc = table; pvdc->tag != NULL; pvdc++) {
3509 if (NTP_ADD != pvdc->type) {
3510 doaddvlist(vl, pvdc->tag);
3512 for (n = 0; n < COUNTOF(suf); n++) {
3513 snprintf(tagbuf, sizeof(tagbuf), "%s%s",
3515 doaddvlist(vl, tagbuf);
3519 qres = doquerylist(vl, CTL_OP_READVAR, as, 0, &rstatus, &rsize,
3523 return; /* error msg already displayed */
3526 * iterate over the response variables filling vdc_table with
3527 * the retrieved values.
3529 while (nextvar(&rsize, &rdata, &tag, &val)) {
3533 for (pvdc = table; pvdc->tag != NULL; pvdc++) {
3534 len = strlen(pvdc->tag);
3535 if (strncmp(tag, pvdc->tag, len))
3537 if (NTP_ADD != pvdc->type) {
3538 if ('\0' != tag[len])
3543 for (n = 0; n < COUNTOF(suf); n++) {
3544 if (strcmp(tag + len, suf[n]))
3552 if (NULL == pvdc->tag)
3554 switch (pvdc->type) {
3557 /* strip surrounding double quotes */
3558 if ('"' == val[0]) {
3560 if (len > 0 && '"' == val[len - 1]) {
3561 val[len - 1] = '\0';
3566 case NTP_MODE: /* fallthru */
3568 pvdc->v.str = estrdup(val);
3572 decodets(val, &pvdc->v.lfp);
3576 if (!decodenetnum(val, &pvdc->v.sau))
3577 fprintf(stderr, "malformed %s=%s\n",
3582 if (0 == n) { /* adr */
3583 if (!decodenetnum(val, &pvdc->v.sau))
3585 "malformed %s=%s\n",
3588 if (atouint(val, &ul))
3589 SET_PORT(&pvdc->v.sau,
3601 fprintf(fp, "associd=%u status=%04x %s,\n", as, rstatus,
3602 statustoa(vtype, rstatus));
3605 for (pvdc = table; pvdc->tag != NULL; pvdc++) {
3606 switch (pvdc->type) {
3609 if (pvdc->v.str != NULL) {
3610 fprintf(fp, "%s %s\n", pvdc->display,
3617 case NTP_ADD: /* fallthru */
3619 fprintf(fp, "%s %s\n", pvdc->display,
3620 nntohostp(&pvdc->v.sau));
3624 fprintf(fp, "%s %s\n", pvdc->display,
3625 prettydate(&pvdc->v.lfp));
3629 atouint(pvdc->v.str, &ul);
3630 fprintf(fp, "%s %s\n", pvdc->display,
3635 atouint(pvdc->v.str, &ul);
3636 fprintf(fp, "%s %s\n", pvdc->display,
3637 leapbits[ul & 0x3]);
3641 fprintf(stderr, "unexpected vdc type %d for %s\n",
3642 pvdc->type, pvdc->tag);
3650 * sysstats - implements ntpq -c sysstats modeled on ntpdc -c sysstats
3658 static vdc sysstats_vdc[] = {
3659 VDC_INIT("ss_uptime", "uptime: ", NTP_STR),
3660 VDC_INIT("ss_reset", "sysstats reset: ", NTP_STR),
3661 VDC_INIT("ss_received", "packets received: ", NTP_STR),
3662 VDC_INIT("ss_thisver", "current version: ", NTP_STR),
3663 VDC_INIT("ss_oldver", "older version: ", NTP_STR),
3664 VDC_INIT("ss_badformat", "bad length or format: ", NTP_STR),
3665 VDC_INIT("ss_badauth", "authentication failed:", NTP_STR),
3666 VDC_INIT("ss_declined", "declined: ", NTP_STR),
3667 VDC_INIT("ss_restricted", "restricted: ", NTP_STR),
3668 VDC_INIT("ss_limited", "rate limited: ", NTP_STR),
3669 VDC_INIT("ss_kodsent", "KoD responses: ", NTP_STR),
3670 VDC_INIT("ss_processed", "processed for time: ", NTP_STR),
3671 VDC_INIT(NULL, NULL, 0)
3674 collect_display_vdc(0, sysstats_vdc, FALSE, fp);
3679 * sysinfo - modeled on ntpdc's sysinfo
3687 static vdc sysinfo_vdc[] = {
3688 VDC_INIT("peeradr", "system peer: ", NTP_ADP),
3689 VDC_INIT("peermode", "system peer mode: ", NTP_MODE),
3690 VDC_INIT("leap", "leap indicator: ", NTP_2BIT),
3691 VDC_INIT("stratum", "stratum: ", NTP_STR),
3692 VDC_INIT("precision", "log2 precision: ", NTP_STR),
3693 VDC_INIT("rootdelay", "root delay: ", NTP_STR),
3694 VDC_INIT("rootdisp", "root dispersion: ", NTP_STR),
3695 VDC_INIT("refid", "reference ID: ", NTP_STR),
3696 VDC_INIT("reftime", "reference time: ", NTP_LFP),
3697 VDC_INIT("sys_jitter", "system jitter: ", NTP_STR),
3698 VDC_INIT("clk_jitter", "clock jitter: ", NTP_STR),
3699 VDC_INIT("clk_wander", "clock wander: ", NTP_STR),
3700 VDC_INIT("bcastdelay", "broadcast delay: ", NTP_STR),
3701 VDC_INIT("authdelay", "symm. auth. delay:", NTP_STR),
3702 VDC_INIT(NULL, NULL, 0)
3705 collect_display_vdc(0, sysinfo_vdc, TRUE, fp);
3710 * kerninfo - modeled on ntpdc's kerninfo
3718 static vdc kerninfo_vdc[] = {
3719 VDC_INIT("koffset", "pll offset: ", NTP_STR),
3720 VDC_INIT("kfreq", "pll frequency: ", NTP_STR),
3721 VDC_INIT("kmaxerr", "maximum error: ", NTP_STR),
3722 VDC_INIT("kesterr", "estimated error: ", NTP_STR),
3723 VDC_INIT("kstflags", "kernel status: ", NTP_STR),
3724 VDC_INIT("ktimeconst", "pll time constant: ", NTP_STR),
3725 VDC_INIT("kprecis", "precision: ", NTP_STR),
3726 VDC_INIT("kfreqtol", "frequency tolerance: ", NTP_STR),
3727 VDC_INIT("kppsfreq", "pps frequency: ", NTP_STR),
3728 VDC_INIT("kppsstab", "pps stability: ", NTP_STR),
3729 VDC_INIT("kppsjitter", "pps jitter: ", NTP_STR),
3730 VDC_INIT("kppscalibdur", "calibration interval ", NTP_STR),
3731 VDC_INIT("kppscalibs", "calibration cycles: ", NTP_STR),
3732 VDC_INIT("kppsjitexc", "jitter exceeded: ", NTP_STR),
3733 VDC_INIT("kppsstbexc", "stability exceeded: ", NTP_STR),
3734 VDC_INIT("kppscaliberrs", "calibration errors: ", NTP_STR),
3735 VDC_INIT(NULL, NULL, 0)
3738 collect_display_vdc(0, kerninfo_vdc, TRUE, fp);
3743 * monstats - implements ntpq -c monstats
3751 static vdc monstats_vdc[] = {
3752 VDC_INIT("mru_enabled", "enabled: ", NTP_STR),
3753 VDC_INIT("mru_depth", "addresses: ", NTP_STR),
3754 VDC_INIT("mru_deepest", "peak addresses: ", NTP_STR),
3755 VDC_INIT("mru_maxdepth", "maximum addresses: ", NTP_STR),
3756 VDC_INIT("mru_mindepth", "reclaim above count:", NTP_STR),
3757 VDC_INIT("mru_maxage", "reclaim older than: ", NTP_STR),
3758 VDC_INIT("mru_mem", "kilobytes: ", NTP_STR),
3759 VDC_INIT("mru_maxmem", "maximum kilobytes: ", NTP_STR),
3760 VDC_INIT(NULL, NULL, 0)
3763 collect_display_vdc(0, monstats_vdc, FALSE, fp);
3768 * iostats - ntpq -c iostats - network input and output counters
3776 static vdc iostats_vdc[] = {
3777 VDC_INIT("iostats_reset", "time since reset: ", NTP_STR),
3778 VDC_INIT("total_rbuf", "receive buffers: ", NTP_STR),
3779 VDC_INIT("free_rbuf", "free receive buffers: ", NTP_STR),
3780 VDC_INIT("used_rbuf", "used receive buffers: ", NTP_STR),
3781 VDC_INIT("rbuf_lowater", "low water refills: ", NTP_STR),
3782 VDC_INIT("io_dropped", "dropped packets: ", NTP_STR),
3783 VDC_INIT("io_ignored", "ignored packets: ", NTP_STR),
3784 VDC_INIT("io_received", "received packets: ", NTP_STR),
3785 VDC_INIT("io_sent", "packets sent: ", NTP_STR),
3786 VDC_INIT("io_sendfailed", "packet send failures: ", NTP_STR),
3787 VDC_INIT("io_wakeups", "input wakeups: ", NTP_STR),
3788 VDC_INIT("io_goodwakeups", "useful input wakeups: ", NTP_STR),
3789 VDC_INIT(NULL, NULL, 0)
3792 collect_display_vdc(0, iostats_vdc, FALSE, fp);
3797 * timerstats - ntpq -c timerstats - interval timer counters
3805 static vdc timerstats_vdc[] = {
3806 VDC_INIT("timerstats_reset", "time since reset: ", NTP_STR),
3807 VDC_INIT("timer_overruns", "timer overruns: ", NTP_STR),
3808 VDC_INIT("timer_xmts", "calls to transmit: ", NTP_STR),
3809 VDC_INIT(NULL, NULL, 0)
3812 collect_display_vdc(0, timerstats_vdc, FALSE, fp);
3817 * authinfo - implements ntpq -c authinfo
3825 static vdc authinfo_vdc[] = {
3826 VDC_INIT("authreset", "time since reset:", NTP_STR),
3827 VDC_INIT("authkeys", "stored keys: ", NTP_STR),
3828 VDC_INIT("authfreek", "free keys: ", NTP_STR),
3829 VDC_INIT("authklookups", "key lookups: ", NTP_STR),
3830 VDC_INIT("authknotfound", "keys not found: ", NTP_STR),
3831 VDC_INIT("authkuncached", "uncached keys: ", NTP_STR),
3832 VDC_INIT("authkexpired", "expired keys: ", NTP_STR),
3833 VDC_INIT("authencrypts", "encryptions: ", NTP_STR),
3834 VDC_INIT("authdecrypts", "decryptions: ", NTP_STR),
3835 VDC_INIT(NULL, NULL, 0)
3838 collect_display_vdc(0, authinfo_vdc, FALSE, fp);
3843 * pstats - show statistics for a peer
3851 static vdc pstats_vdc[] = {
3852 VDC_INIT("src", "remote host: ", NTP_ADD),
3853 VDC_INIT("dst", "local address: ", NTP_ADD),
3854 VDC_INIT("timerec", "time last received: ", NTP_STR),
3855 VDC_INIT("timer", "time until next send:", NTP_STR),
3856 VDC_INIT("timereach", "reachability change: ", NTP_STR),
3857 VDC_INIT("sent", "packets sent: ", NTP_STR),
3858 VDC_INIT("received", "packets received: ", NTP_STR),
3859 VDC_INIT("badauth", "bad authentication: ", NTP_STR),
3860 VDC_INIT("bogusorg", "bogus origin: ", NTP_STR),
3861 VDC_INIT("oldpkt", "duplicate: ", NTP_STR),
3862 VDC_INIT("seldisp", "bad dispersion: ", NTP_STR),
3863 VDC_INIT("selbroken", "bad reference time: ", NTP_STR),
3864 VDC_INIT("candidate", "candidate order: ", NTP_STR),
3865 VDC_INIT(NULL, NULL, 0)
3869 associd = checkassocid(pcmd->argval[0].uval);
3873 collect_display_vdc(associd, pstats_vdc, TRUE, fp);