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