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