1181834Sroberto/* 2290000Sglebius * ntpq-subs.c - subroutines which are called to perform ntpq commands. 3181834Sroberto */ 4290000Sglebius#include <config.h> 5181834Sroberto#include <stdio.h> 6181834Sroberto#include <ctype.h> 7181834Sroberto#include <sys/types.h> 8181834Sroberto#include <sys/time.h> 9181834Sroberto 10181834Sroberto#include "ntpq.h" 11290000Sglebius#include "ntpq-opts.h" 12181834Sroberto 13290000Sglebiusextern char currenthost[]; 14290000Sglebiusextern int currenthostisnum; 15290000Sglebiussize_t maxhostlen; 16181834Sroberto 17181834Sroberto/* 18181834Sroberto * Declarations for command handlers in here 19181834Sroberto */ 20290000Sglebiusstatic associd_t checkassocid (u_int32); 21290000Sglebiusstatic struct varlist *findlistvar (struct varlist *, char *); 22290000Sglebiusstatic void doaddvlist (struct varlist *, const char *); 23290000Sglebiusstatic void dormvlist (struct varlist *, const char *); 24290000Sglebiusstatic void doclearvlist (struct varlist *); 25293894Sglebiusstatic void makequerydata (struct varlist *, size_t *, char *); 26290000Sglebiusstatic int doquerylist (struct varlist *, int, associd_t, int, 27293894Sglebius u_short *, size_t *, const char **); 28290000Sglebiusstatic void doprintvlist (struct varlist *, FILE *); 29290000Sglebiusstatic void addvars (struct parse *, FILE *); 30290000Sglebiusstatic void rmvars (struct parse *, FILE *); 31290000Sglebiusstatic void clearvars (struct parse *, FILE *); 32290000Sglebiusstatic void showvars (struct parse *, FILE *); 33290000Sglebiusstatic int dolist (struct varlist *, associd_t, int, int, 34290000Sglebius FILE *); 35290000Sglebiusstatic void readlist (struct parse *, FILE *); 36290000Sglebiusstatic void writelist (struct parse *, FILE *); 37290000Sglebiusstatic void readvar (struct parse *, FILE *); 38290000Sglebiusstatic void writevar (struct parse *, FILE *); 39290000Sglebiusstatic void clocklist (struct parse *, FILE *); 40290000Sglebiusstatic void clockvar (struct parse *, FILE *); 41290000Sglebiusstatic int findassidrange (u_int32, u_int32, int *, int *, 42290000Sglebius FILE *); 43290000Sglebiusstatic void mreadlist (struct parse *, FILE *); 44290000Sglebiusstatic void mreadvar (struct parse *, FILE *); 45290000Sglebiusstatic void printassoc (int, FILE *); 46290000Sglebiusstatic void associations (struct parse *, FILE *); 47290000Sglebiusstatic void lassociations (struct parse *, FILE *); 48290000Sglebiusstatic void passociations (struct parse *, FILE *); 49290000Sglebiusstatic void lpassociations (struct parse *, FILE *); 50181834Sroberto 51181834Sroberto#ifdef UNUSED 52290000Sglebiusstatic void radiostatus (struct parse *, FILE *); 53181834Sroberto#endif /* UNUSED */ 54181834Sroberto 55290000Sglebiusstatic void authinfo (struct parse *, FILE *); 56290000Sglebiusstatic void pstats (struct parse *, FILE *); 57290000Sglebiusstatic long when (l_fp *, l_fp *, l_fp *); 58290000Sglebiusstatic char * prettyinterval (char *, size_t, long); 59293894Sglebiusstatic int doprintpeers (struct varlist *, int, int, size_t, const char *, FILE *, int); 60290000Sglebiusstatic int dogetpeers (struct varlist *, associd_t, FILE *, int); 61290000Sglebiusstatic void dopeers (int, FILE *, int); 62290000Sglebiusstatic void peers (struct parse *, FILE *); 63290000Sglebiusstatic void doapeers (int, FILE *, int); 64290000Sglebiusstatic void apeers (struct parse *, FILE *); 65290000Sglebiusstatic void lpeers (struct parse *, FILE *); 66290000Sglebiusstatic void doopeers (int, FILE *, int); 67290000Sglebiusstatic void opeers (struct parse *, FILE *); 68290000Sglebiusstatic void lopeers (struct parse *, FILE *); 69290000Sglebiusstatic void config (struct parse *, FILE *); 70290000Sglebiusstatic void saveconfig (struct parse *, FILE *); 71290000Sglebiusstatic void config_from_file(struct parse *, FILE *); 72290000Sglebiusstatic void mrulist (struct parse *, FILE *); 73290000Sglebiusstatic void ifstats (struct parse *, FILE *); 74290000Sglebiusstatic void reslist (struct parse *, FILE *); 75290000Sglebiusstatic void sysstats (struct parse *, FILE *); 76290000Sglebiusstatic void sysinfo (struct parse *, FILE *); 77290000Sglebiusstatic void kerninfo (struct parse *, FILE *); 78290000Sglebiusstatic void monstats (struct parse *, FILE *); 79290000Sglebiusstatic void iostats (struct parse *, FILE *); 80290000Sglebiusstatic void timerstats (struct parse *, FILE *); 81181834Sroberto 82181834Sroberto/* 83181834Sroberto * Commands we understand. Ntpdc imports this. 84181834Sroberto */ 85181834Srobertostruct xcmd opcmds[] = { 86290000Sglebius { "saveconfig", saveconfig, { NTP_STR, NO, NO, NO }, 87290000Sglebius { "filename", "", "", ""}, 88290000Sglebius "save ntpd configuration to file, . for current config file"}, 89181834Sroberto { "associations", associations, { NO, NO, NO, NO }, 90181834Sroberto { "", "", "", "" }, 91181834Sroberto "print list of association ID's and statuses for the server's peers" }, 92181834Sroberto { "passociations", passociations, { NO, NO, NO, NO }, 93181834Sroberto { "", "", "", "" }, 94181834Sroberto "print list of associations returned by last associations command" }, 95181834Sroberto { "lassociations", lassociations, { NO, NO, NO, NO }, 96181834Sroberto { "", "", "", "" }, 97181834Sroberto "print list of associations including all client information" }, 98181834Sroberto { "lpassociations", lpassociations, { NO, NO, NO, NO }, 99181834Sroberto { "", "", "", "" }, 100181834Sroberto "print last obtained list of associations, including client information" }, 101181834Sroberto { "addvars", addvars, { NTP_STR, NO, NO, NO }, 102181834Sroberto { "name[=value][,...]", "", "", "" }, 103181834Sroberto "add variables to the variable list or change their values" }, 104181834Sroberto { "rmvars", rmvars, { NTP_STR, NO, NO, NO }, 105181834Sroberto { "name[,...]", "", "", "" }, 106181834Sroberto "remove variables from the variable list" }, 107181834Sroberto { "clearvars", clearvars, { NO, NO, NO, NO }, 108181834Sroberto { "", "", "", "" }, 109181834Sroberto "remove all variables from the variable list" }, 110181834Sroberto { "showvars", showvars, { NO, NO, NO, NO }, 111181834Sroberto { "", "", "", "" }, 112181834Sroberto "print variables on the variable list" }, 113181834Sroberto { "readlist", readlist, { OPT|NTP_UINT, NO, NO, NO }, 114181834Sroberto { "assocID", "", "", "" }, 115181834Sroberto "read the system or peer variables included in the variable list" }, 116181834Sroberto { "rl", readlist, { OPT|NTP_UINT, NO, NO, NO }, 117181834Sroberto { "assocID", "", "", "" }, 118181834Sroberto "read the system or peer variables included in the variable list" }, 119181834Sroberto { "writelist", writelist, { OPT|NTP_UINT, NO, NO, NO }, 120181834Sroberto { "assocID", "", "", "" }, 121181834Sroberto "write the system or peer variables included in the variable list" }, 122290000Sglebius { "readvar", readvar, { OPT|NTP_UINT, OPT|NTP_STR, OPT|NTP_STR, OPT|NTP_STR, }, 123290000Sglebius { "assocID", "varname1", "varname2", "varname3" }, 124181834Sroberto "read system or peer variables" }, 125290000Sglebius { "rv", readvar, { OPT|NTP_UINT, OPT|NTP_STR, OPT|NTP_STR, OPT|NTP_STR, }, 126290000Sglebius { "assocID", "varname1", "varname2", "varname3" }, 127181834Sroberto "read system or peer variables" }, 128181834Sroberto { "writevar", writevar, { NTP_UINT, NTP_STR, NO, NO }, 129181834Sroberto { "assocID", "name=value,[...]", "", "" }, 130181834Sroberto "write system or peer variables" }, 131181834Sroberto { "mreadlist", mreadlist, { NTP_UINT, NTP_UINT, NO, NO }, 132290000Sglebius { "assocIDlow", "assocIDhigh", "", "" }, 133181834Sroberto "read the peer variables in the variable list for multiple peers" }, 134181834Sroberto { "mrl", mreadlist, { NTP_UINT, NTP_UINT, NO, NO }, 135290000Sglebius { "assocIDlow", "assocIDhigh", "", "" }, 136181834Sroberto "read the peer variables in the variable list for multiple peers" }, 137181834Sroberto { "mreadvar", mreadvar, { NTP_UINT, NTP_UINT, OPT|NTP_STR, NO }, 138290000Sglebius { "assocIDlow", "assocIDhigh", "name=value[,...]", "" }, 139181834Sroberto "read peer variables from multiple peers" }, 140181834Sroberto { "mrv", mreadvar, { NTP_UINT, NTP_UINT, OPT|NTP_STR, NO }, 141290000Sglebius { "assocIDlow", "assocIDhigh", "name=value[,...]", "" }, 142181834Sroberto "read peer variables from multiple peers" }, 143181834Sroberto { "clocklist", clocklist, { OPT|NTP_UINT, NO, NO, NO }, 144181834Sroberto { "assocID", "", "", "" }, 145181834Sroberto "read the clock variables included in the variable list" }, 146181834Sroberto { "cl", clocklist, { OPT|NTP_UINT, NO, NO, NO }, 147181834Sroberto { "assocID", "", "", "" }, 148181834Sroberto "read the clock variables included in the variable list" }, 149181834Sroberto { "clockvar", clockvar, { OPT|NTP_UINT, OPT|NTP_STR, NO, NO }, 150181834Sroberto { "assocID", "name=value[,...]", "", "" }, 151181834Sroberto "read clock variables" }, 152181834Sroberto { "cv", clockvar, { OPT|NTP_UINT, OPT|NTP_STR, NO, NO }, 153181834Sroberto { "assocID", "name=value[,...]", "", "" }, 154181834Sroberto "read clock variables" }, 155290000Sglebius { "pstats", pstats, { NTP_UINT, NO, NO, NO }, 156181834Sroberto { "assocID", "", "", "" }, 157290000Sglebius "show statistics for a peer" }, 158181834Sroberto { "peers", peers, { OPT|IP_VERSION, NO, NO, NO }, 159181834Sroberto { "-4|-6", "", "", "" }, 160181834Sroberto "obtain and print a list of the server's peers [IP version]" }, 161290000Sglebius { "apeers", apeers, { OPT|IP_VERSION, NO, NO, NO }, 162290000Sglebius { "-4|-6", "", "", "" }, 163290000Sglebius "obtain and print a list of the server's peers and their assocIDs [IP version]" }, 164181834Sroberto { "lpeers", lpeers, { OPT|IP_VERSION, NO, NO, NO }, 165181834Sroberto { "-4|-6", "", "", "" }, 166181834Sroberto "obtain and print a list of all peers and clients [IP version]" }, 167181834Sroberto { "opeers", opeers, { OPT|IP_VERSION, NO, NO, NO }, 168181834Sroberto { "-4|-6", "", "", "" }, 169181834Sroberto "print peer list the old way, with dstadr shown rather than refid [IP version]" }, 170181834Sroberto { "lopeers", lopeers, { OPT|IP_VERSION, NO, NO, NO }, 171181834Sroberto { "-4|-6", "", "", "" }, 172181834Sroberto "obtain and print a list of all peers and clients showing dstadr [IP version]" }, 173290000Sglebius { ":config", config, { NTP_STR, NO, NO, NO }, 174290000Sglebius { "<configuration command line>", "", "", "" }, 175290000Sglebius "send a remote configuration command to ntpd" }, 176290000Sglebius { "config-from-file", config_from_file, { NTP_STR, NO, NO, NO }, 177290000Sglebius { "<configuration filename>", "", "", "" }, 178290000Sglebius "configure ntpd using the configuration filename" }, 179290000Sglebius { "mrulist", mrulist, { OPT|NTP_STR, OPT|NTP_STR, OPT|NTP_STR, OPT|NTP_STR }, 180290000Sglebius { "tag=value", "tag=value", "tag=value", "tag=value" }, 181290000Sglebius "display the list of most recently seen source addresses, tags mincount=... resall=0x... resany=0x..." }, 182290000Sglebius { "ifstats", ifstats, { NO, NO, NO, NO }, 183290000Sglebius { "", "", "", "" }, 184290000Sglebius "show statistics for each local address ntpd is using" }, 185290000Sglebius { "reslist", reslist, { NO, NO, NO, NO }, 186290000Sglebius { "", "", "", "" }, 187290000Sglebius "show ntpd access control list" }, 188290000Sglebius { "sysinfo", sysinfo, { NO, NO, NO, NO }, 189290000Sglebius { "", "", "", "" }, 190290000Sglebius "display system summary" }, 191290000Sglebius { "kerninfo", kerninfo, { NO, NO, NO, NO }, 192290000Sglebius { "", "", "", "" }, 193290000Sglebius "display kernel loop and PPS statistics" }, 194290000Sglebius { "sysstats", sysstats, { NO, NO, NO, NO }, 195290000Sglebius { "", "", "", "" }, 196290000Sglebius "display system uptime and packet counts" }, 197290000Sglebius { "monstats", monstats, { NO, NO, NO, NO }, 198290000Sglebius { "", "", "", "" }, 199290000Sglebius "display monitor (mrulist) counters and limits" }, 200290000Sglebius { "authinfo", authinfo, { NO, NO, NO, NO }, 201290000Sglebius { "", "", "", "" }, 202290000Sglebius "display symmetric authentication counters" }, 203290000Sglebius { "iostats", iostats, { NO, NO, NO, NO }, 204290000Sglebius { "", "", "", "" }, 205290000Sglebius "display network input and output counters" }, 206290000Sglebius { "timerstats", timerstats, { NO, NO, NO, NO }, 207290000Sglebius { "", "", "", "" }, 208290000Sglebius "display interval timer counters" }, 209181834Sroberto { 0, 0, { NO, NO, NO, NO }, 210181834Sroberto { "-4|-6", "", "", "" }, "" } 211181834Sroberto}; 212181834Sroberto 213181834Sroberto 214181834Sroberto/* 215181834Sroberto * Variable list data space 216181834Sroberto */ 217290000Sglebius#define MAXLINE 512 /* maximum length of a line */ 218290000Sglebius#define MAXLIST 128 /* maximum variables in list */ 219290000Sglebius#define LENHOSTNAME 256 /* host name limit */ 220290000Sglebius 221290000Sglebius#define MRU_GOT_COUNT 0x1 222290000Sglebius#define MRU_GOT_LAST 0x2 223290000Sglebius#define MRU_GOT_FIRST 0x4 224290000Sglebius#define MRU_GOT_MV 0x8 225290000Sglebius#define MRU_GOT_RS 0x10 226290000Sglebius#define MRU_GOT_ADDR 0x20 227290000Sglebius#define MRU_GOT_ALL (MRU_GOT_COUNT | MRU_GOT_LAST | MRU_GOT_FIRST \ 228290000Sglebius | MRU_GOT_MV | MRU_GOT_RS | MRU_GOT_ADDR) 229290000Sglebius 230181834Sroberto/* 231290000Sglebius * mrulist() depends on MRUSORT_DEF and MRUSORT_RDEF being the first two 232290000Sglebius */ 233290000Sglebiustypedef enum mru_sort_order_tag { 234290000Sglebius MRUSORT_DEF = 0, /* lstint ascending */ 235290000Sglebius MRUSORT_R_DEF, /* lstint descending */ 236290000Sglebius MRUSORT_AVGINT, /* avgint ascending */ 237290000Sglebius MRUSORT_R_AVGINT, /* avgint descending */ 238290000Sglebius MRUSORT_ADDR, /* IPv4 asc. then IPv6 asc. */ 239290000Sglebius MRUSORT_R_ADDR, /* IPv6 desc. then IPv4 desc. */ 240290000Sglebius MRUSORT_COUNT, /* hit count ascending */ 241290000Sglebius MRUSORT_R_COUNT, /* hit count descending */ 242290000Sglebius MRUSORT_MAX, /* special: count of this enum */ 243290000Sglebius} mru_sort_order; 244290000Sglebius 245290000Sglebiusconst char * const mru_sort_keywords[MRUSORT_MAX] = { 246290000Sglebius "lstint", /* MRUSORT_DEF */ 247290000Sglebius "-lstint", /* MRUSORT_R_DEF */ 248290000Sglebius "avgint", /* MRUSORT_AVGINT */ 249290000Sglebius "-avgint", /* MRUSORT_R_AVGINT */ 250290000Sglebius "addr", /* MRUSORT_ADDR */ 251290000Sglebius "-addr", /* MRUSORT_R_ADDR */ 252290000Sglebius "count", /* MRUSORT_COUNT */ 253290000Sglebius "-count", /* MRUSORT_R_COUNT */ 254290000Sglebius}; 255290000Sglebius 256290000Sglebiustypedef int (*qsort_cmp)(const void *, const void *); 257290000Sglebius 258290000Sglebius/* 259181834Sroberto * Old CTL_PST defines for version 2. 260181834Sroberto */ 261290000Sglebius#define OLD_CTL_PST_CONFIG 0x80 262181834Sroberto#define OLD_CTL_PST_AUTHENABLE 0x40 263181834Sroberto#define OLD_CTL_PST_AUTHENTIC 0x20 264290000Sglebius#define OLD_CTL_PST_REACH 0x10 265290000Sglebius#define OLD_CTL_PST_SANE 0x08 266290000Sglebius#define OLD_CTL_PST_DISP 0x04 267290000Sglebius 268181834Sroberto#define OLD_CTL_PST_SEL_REJECT 0 269181834Sroberto#define OLD_CTL_PST_SEL_SELCAND 1 270181834Sroberto#define OLD_CTL_PST_SEL_SYNCCAND 2 271181834Sroberto#define OLD_CTL_PST_SEL_SYSPEER 3 272181834Sroberto 273181834Srobertochar flash2[] = " .+* "; /* flash decode for version 2 */ 274181834Srobertochar flash3[] = " x.-+#*o"; /* flash decode for peer status version 3 */ 275181834Sroberto 276181834Srobertostruct varlist { 277290000Sglebius const char *name; 278181834Sroberto char *value; 279290000Sglebius} g_varlist[MAXLIST] = { { 0, 0 } }; 280181834Sroberto 281181834Sroberto/* 282181834Sroberto * Imported from ntpq.c 283181834Sroberto */ 284181834Srobertoextern int showhostnames; 285290000Sglebiusextern int wideremote; 286181834Srobertoextern int rawmode; 287181834Srobertoextern struct servent *server_entry; 288290000Sglebiusextern struct association *assoc_cache; 289181834Srobertoextern u_char pktversion; 290181834Sroberto 291290000Sglebiustypedef struct mru_tag mru; 292290000Sglebiusstruct mru_tag { 293290000Sglebius mru * hlink; /* next in hash table bucket */ 294290000Sglebius DECL_DLIST_LINK(mru, mlink); 295290000Sglebius int count; 296290000Sglebius l_fp last; 297290000Sglebius l_fp first; 298290000Sglebius u_char mode; 299290000Sglebius u_char ver; 300290000Sglebius u_short rs; 301290000Sglebius sockaddr_u addr; 302290000Sglebius}; 303290000Sglebius 304290000Sglebiustypedef struct ifstats_row_tag { 305290000Sglebius u_int ifnum; 306290000Sglebius sockaddr_u addr; 307290000Sglebius sockaddr_u bcast; 308290000Sglebius int enabled; 309290000Sglebius u_int flags; 310290000Sglebius int mcast_count; 311290000Sglebius char name[32]; 312290000Sglebius int peer_count; 313290000Sglebius int received; 314290000Sglebius int sent; 315290000Sglebius int send_errors; 316290000Sglebius u_int ttl; 317290000Sglebius u_int uptime; 318290000Sglebius} ifstats_row; 319290000Sglebius 320290000Sglebiustypedef struct reslist_row_tag { 321290000Sglebius u_int idx; 322290000Sglebius sockaddr_u addr; 323290000Sglebius sockaddr_u mask; 324290000Sglebius u_long hits; 325290000Sglebius char flagstr[128]; 326290000Sglebius} reslist_row; 327290000Sglebius 328290000Sglebiustypedef struct var_display_collection_tag { 329290000Sglebius const char * const tag; /* system variable */ 330290000Sglebius const char * const display; /* descriptive text */ 331290000Sglebius u_char type; /* NTP_STR, etc */ 332290000Sglebius union { 333290000Sglebius char * str; 334290000Sglebius sockaddr_u sau; /* NTP_ADD */ 335290000Sglebius l_fp lfp; /* NTP_LFP */ 336290000Sglebius } v; /* retrieved value */ 337290000Sglebius} vdc; 338290000Sglebius#if !defined(MISSING_C99_STRUCT_INIT) 339290000Sglebius# define VDC_INIT(a, b, c) { .tag = a, .display = b, .type = c } 340290000Sglebius#else 341290000Sglebius# define VDC_INIT(a, b, c) { a, b, c } 342290000Sglebius#endif 343181834Sroberto/* 344290000Sglebius * other local function prototypes 345181834Sroberto */ 346293894Sglebiusstatic int mrulist_ctrl_c_hook(void); 347290000Sglebiusstatic mru * add_mru(mru *); 348290000Sglebiusstatic int collect_mru_list(const char *, l_fp *); 349290000Sglebiusstatic int fetch_nonce(char *, size_t); 350290000Sglebiusstatic int qcmp_mru_avgint(const void *, const void *); 351290000Sglebiusstatic int qcmp_mru_r_avgint(const void *, const void *); 352290000Sglebiusstatic int qcmp_mru_addr(const void *, const void *); 353290000Sglebiusstatic int qcmp_mru_r_addr(const void *, const void *); 354290000Sglebiusstatic int qcmp_mru_count(const void *, const void *); 355290000Sglebiusstatic int qcmp_mru_r_count(const void *, const void *); 356290000Sglebiusstatic void validate_ifnum(FILE *, u_int, int *, ifstats_row *); 357290000Sglebiusstatic void another_ifstats_field(int *, ifstats_row *, FILE *); 358290000Sglebiusstatic void collect_display_vdc(associd_t as, vdc *table, 359290000Sglebius int decodestatus, FILE *fp); 360181834Sroberto 361290000Sglebius/* 362290000Sglebius * static globals 363290000Sglebius */ 364290000Sglebiusstatic u_int mru_count; 365290000Sglebiusstatic u_int mru_dupes; 366290000Sglebiusvolatile int mrulist_interrupted; 367290000Sglebiusstatic mru mru_list; /* listhead */ 368290000Sglebiusstatic mru ** hash_table; 369181834Sroberto 370181834Sroberto/* 371290000Sglebius * qsort comparison function table for mrulist(). The first two 372290000Sglebius * entries are NULL because they are handled without qsort(). 373290000Sglebius */ 374290000Sglebiusstatic const qsort_cmp mru_qcmp_table[MRUSORT_MAX] = { 375290000Sglebius NULL, /* MRUSORT_DEF unused */ 376290000Sglebius NULL, /* MRUSORT_R_DEF unused */ 377290000Sglebius &qcmp_mru_avgint, /* MRUSORT_AVGINT */ 378290000Sglebius &qcmp_mru_r_avgint, /* MRUSORT_R_AVGINT */ 379290000Sglebius &qcmp_mru_addr, /* MRUSORT_ADDR */ 380290000Sglebius &qcmp_mru_r_addr, /* MRUSORT_R_ADDR */ 381290000Sglebius &qcmp_mru_count, /* MRUSORT_COUNT */ 382290000Sglebius &qcmp_mru_r_count, /* MRUSORT_R_COUNT */ 383290000Sglebius}; 384290000Sglebius 385290000Sglebius/* 386181834Sroberto * checkassocid - return the association ID, checking to see if it is valid 387181834Sroberto */ 388290000Sglebiusstatic associd_t 389181834Srobertocheckassocid( 390181834Sroberto u_int32 value 391181834Sroberto ) 392181834Sroberto{ 393290000Sglebius associd_t associd; 394290000Sglebius u_long ulvalue; 395290000Sglebius 396290000Sglebius associd = (associd_t)value; 397290000Sglebius if (0 == associd || value != associd) { 398290000Sglebius ulvalue = value; 399290000Sglebius fprintf(stderr, 400290000Sglebius "***Invalid association ID %lu specified\n", 401290000Sglebius ulvalue); 402181834Sroberto return 0; 403181834Sroberto } 404181834Sroberto 405290000Sglebius return associd; 406181834Sroberto} 407181834Sroberto 408181834Sroberto 409181834Sroberto/* 410290000Sglebius * findlistvar - Look for the named variable in a varlist. If found, 411290000Sglebius * return a pointer to it. Otherwise, if the list has 412290000Sglebius * slots available, return the pointer to the first free 413290000Sglebius * slot, or NULL if it's full. 414181834Sroberto */ 415181834Srobertostatic struct varlist * 416181834Srobertofindlistvar( 417181834Sroberto struct varlist *list, 418181834Sroberto char *name 419181834Sroberto ) 420181834Sroberto{ 421290000Sglebius struct varlist *vl; 422181834Sroberto 423290000Sglebius for (vl = list; vl < list + MAXLIST && vl->name != NULL; vl++) 424290000Sglebius if (!strcmp(name, vl->name)) 425290000Sglebius return vl; 426181834Sroberto if (vl < list + MAXLIST) 427181834Sroberto return vl; 428290000Sglebius 429290000Sglebius return NULL; 430181834Sroberto} 431181834Sroberto 432181834Sroberto 433181834Sroberto/* 434181834Sroberto * doaddvlist - add variable(s) to the variable list 435181834Sroberto */ 436181834Srobertostatic void 437181834Srobertodoaddvlist( 438181834Sroberto struct varlist *vlist, 439290000Sglebius const char *vars 440181834Sroberto ) 441181834Sroberto{ 442290000Sglebius struct varlist *vl; 443293894Sglebius size_t len; 444181834Sroberto char *name; 445181834Sroberto char *value; 446181834Sroberto 447181834Sroberto len = strlen(vars); 448181834Sroberto while (nextvar(&len, &vars, &name, &value)) { 449181834Sroberto vl = findlistvar(vlist, name); 450290000Sglebius if (NULL == vl) { 451290000Sglebius fprintf(stderr, "Variable list full\n"); 452181834Sroberto return; 453181834Sroberto } 454181834Sroberto 455290000Sglebius if (NULL == vl->name) { 456290000Sglebius vl->name = estrdup(name); 457290000Sglebius } else if (vl->value != NULL) { 458181834Sroberto free(vl->value); 459290000Sglebius vl->value = NULL; 460181834Sroberto } 461181834Sroberto 462290000Sglebius if (value != NULL) 463290000Sglebius vl->value = estrdup(value); 464181834Sroberto } 465181834Sroberto} 466181834Sroberto 467181834Sroberto 468181834Sroberto/* 469181834Sroberto * dormvlist - remove variable(s) from the variable list 470181834Sroberto */ 471181834Srobertostatic void 472181834Srobertodormvlist( 473181834Sroberto struct varlist *vlist, 474290000Sglebius const char *vars 475181834Sroberto ) 476181834Sroberto{ 477290000Sglebius struct varlist *vl; 478293894Sglebius size_t len; 479181834Sroberto char *name; 480181834Sroberto char *value; 481181834Sroberto 482181834Sroberto len = strlen(vars); 483181834Sroberto while (nextvar(&len, &vars, &name, &value)) { 484181834Sroberto vl = findlistvar(vlist, name); 485181834Sroberto if (vl == 0 || vl->name == 0) { 486181834Sroberto (void) fprintf(stderr, "Variable `%s' not found\n", 487181834Sroberto name); 488181834Sroberto } else { 489290000Sglebius free((void *)(intptr_t)vl->name); 490181834Sroberto if (vl->value != 0) 491181834Sroberto free(vl->value); 492290000Sglebius for ( ; (vl+1) < (g_varlist + MAXLIST) 493181834Sroberto && (vl+1)->name != 0; vl++) { 494181834Sroberto vl->name = (vl+1)->name; 495181834Sroberto vl->value = (vl+1)->value; 496181834Sroberto } 497181834Sroberto vl->name = vl->value = 0; 498181834Sroberto } 499181834Sroberto } 500181834Sroberto} 501181834Sroberto 502181834Sroberto 503181834Sroberto/* 504181834Sroberto * doclearvlist - clear a variable list 505181834Sroberto */ 506181834Srobertostatic void 507181834Srobertodoclearvlist( 508181834Sroberto struct varlist *vlist 509181834Sroberto ) 510181834Sroberto{ 511181834Sroberto register struct varlist *vl; 512181834Sroberto 513181834Sroberto for (vl = vlist; vl < vlist + MAXLIST && vl->name != 0; vl++) { 514290000Sglebius free((void *)(intptr_t)vl->name); 515181834Sroberto vl->name = 0; 516181834Sroberto if (vl->value != 0) { 517181834Sroberto free(vl->value); 518181834Sroberto vl->value = 0; 519181834Sroberto } 520181834Sroberto } 521181834Sroberto} 522181834Sroberto 523181834Sroberto 524181834Sroberto/* 525181834Sroberto * makequerydata - form a data buffer to be included with a query 526181834Sroberto */ 527181834Srobertostatic void 528181834Srobertomakequerydata( 529181834Sroberto struct varlist *vlist, 530293894Sglebius size_t *datalen, 531181834Sroberto char *data 532181834Sroberto ) 533181834Sroberto{ 534181834Sroberto register struct varlist *vl; 535181834Sroberto register char *cp, *cpend; 536293894Sglebius register size_t namelen, valuelen; 537293894Sglebius register size_t totallen; 538181834Sroberto 539181834Sroberto cp = data; 540181834Sroberto cpend = data + *datalen; 541181834Sroberto 542181834Sroberto for (vl = vlist; vl < vlist + MAXLIST && vl->name != 0; vl++) { 543181834Sroberto namelen = strlen(vl->name); 544181834Sroberto if (vl->value == 0) 545181834Sroberto valuelen = 0; 546181834Sroberto else 547181834Sroberto valuelen = strlen(vl->value); 548181834Sroberto totallen = namelen + valuelen + (valuelen != 0) + (cp != data); 549290000Sglebius if (cp + totallen > cpend) { 550290000Sglebius fprintf(stderr, 551290000Sglebius "***Ignoring variables starting with `%s'\n", 552290000Sglebius vl->name); 553290000Sglebius break; 554290000Sglebius } 555181834Sroberto 556181834Sroberto if (cp != data) 557181834Sroberto *cp++ = ','; 558290000Sglebius memcpy(cp, vl->name, (size_t)namelen); 559181834Sroberto cp += namelen; 560181834Sroberto if (valuelen != 0) { 561181834Sroberto *cp++ = '='; 562290000Sglebius memcpy(cp, vl->value, (size_t)valuelen); 563181834Sroberto cp += valuelen; 564181834Sroberto } 565181834Sroberto } 566293894Sglebius *datalen = (size_t)(cp - data); 567181834Sroberto} 568181834Sroberto 569181834Sroberto 570181834Sroberto/* 571181834Sroberto * doquerylist - send a message including variables in a list 572181834Sroberto */ 573181834Srobertostatic int 574181834Srobertodoquerylist( 575181834Sroberto struct varlist *vlist, 576181834Sroberto int op, 577290000Sglebius associd_t associd, 578181834Sroberto int auth, 579181834Sroberto u_short *rstatus, 580293894Sglebius size_t *dsize, 581290000Sglebius const char **datap 582181834Sroberto ) 583181834Sroberto{ 584181834Sroberto char data[CTL_MAX_DATA_LEN]; 585293894Sglebius size_t datalen; 586181834Sroberto 587181834Sroberto datalen = sizeof(data); 588181834Sroberto makequerydata(vlist, &datalen, data); 589181834Sroberto 590290000Sglebius return doquery(op, associd, auth, datalen, data, rstatus, dsize, 591290000Sglebius datap); 592181834Sroberto} 593181834Sroberto 594181834Sroberto 595181834Sroberto/* 596181834Sroberto * doprintvlist - print the variables on a list 597181834Sroberto */ 598181834Srobertostatic void 599181834Srobertodoprintvlist( 600181834Sroberto struct varlist *vlist, 601181834Sroberto FILE *fp 602181834Sroberto ) 603181834Sroberto{ 604290000Sglebius size_t n; 605181834Sroberto 606290000Sglebius if (NULL == vlist->name) { 607290000Sglebius fprintf(fp, "No variables on list\n"); 608290000Sglebius return; 609181834Sroberto } 610290000Sglebius for (n = 0; n < MAXLIST && vlist[n].name != NULL; n++) { 611290000Sglebius if (NULL == vlist[n].value) 612290000Sglebius fprintf(fp, "%s\n", vlist[n].name); 613290000Sglebius else 614290000Sglebius fprintf(fp, "%s=%s\n", vlist[n].name, 615290000Sglebius vlist[n].value); 616290000Sglebius } 617181834Sroberto} 618181834Sroberto 619181834Sroberto/* 620181834Sroberto * addvars - add variables to the variable list 621181834Sroberto */ 622181834Sroberto/*ARGSUSED*/ 623181834Srobertostatic void 624181834Srobertoaddvars( 625181834Sroberto struct parse *pcmd, 626181834Sroberto FILE *fp 627181834Sroberto ) 628181834Sroberto{ 629290000Sglebius doaddvlist(g_varlist, pcmd->argval[0].string); 630181834Sroberto} 631181834Sroberto 632181834Sroberto 633181834Sroberto/* 634181834Sroberto * rmvars - remove variables from the variable list 635181834Sroberto */ 636181834Sroberto/*ARGSUSED*/ 637181834Srobertostatic void 638181834Srobertormvars( 639181834Sroberto struct parse *pcmd, 640181834Sroberto FILE *fp 641181834Sroberto ) 642181834Sroberto{ 643290000Sglebius dormvlist(g_varlist, pcmd->argval[0].string); 644181834Sroberto} 645181834Sroberto 646181834Sroberto 647181834Sroberto/* 648181834Sroberto * clearvars - clear the variable list 649181834Sroberto */ 650181834Sroberto/*ARGSUSED*/ 651181834Srobertostatic void 652181834Srobertoclearvars( 653181834Sroberto struct parse *pcmd, 654181834Sroberto FILE *fp 655181834Sroberto ) 656181834Sroberto{ 657290000Sglebius doclearvlist(g_varlist); 658181834Sroberto} 659181834Sroberto 660181834Sroberto 661181834Sroberto/* 662181834Sroberto * showvars - show variables on the variable list 663181834Sroberto */ 664181834Sroberto/*ARGSUSED*/ 665181834Srobertostatic void 666181834Srobertoshowvars( 667181834Sroberto struct parse *pcmd, 668181834Sroberto FILE *fp 669181834Sroberto ) 670181834Sroberto{ 671290000Sglebius doprintvlist(g_varlist, fp); 672181834Sroberto} 673181834Sroberto 674181834Sroberto 675181834Sroberto/* 676181834Sroberto * dolist - send a request with the given list of variables 677181834Sroberto */ 678181834Srobertostatic int 679181834Srobertodolist( 680181834Sroberto struct varlist *vlist, 681290000Sglebius associd_t associd, 682181834Sroberto int op, 683181834Sroberto int type, 684181834Sroberto FILE *fp 685181834Sroberto ) 686181834Sroberto{ 687290000Sglebius const char *datap; 688181834Sroberto int res; 689293894Sglebius size_t dsize; 690181834Sroberto u_short rstatus; 691290000Sglebius int quiet; 692181834Sroberto 693290000Sglebius /* 694290000Sglebius * if we're asking for specific variables don't include the 695290000Sglebius * status header line in the output. 696290000Sglebius */ 697290000Sglebius if (old_rv) 698290000Sglebius quiet = 0; 699290000Sglebius else 700290000Sglebius quiet = (vlist->name != NULL); 701290000Sglebius 702181834Sroberto res = doquerylist(vlist, op, associd, 0, &rstatus, &dsize, &datap); 703181834Sroberto 704181834Sroberto if (res != 0) 705181834Sroberto return 0; 706181834Sroberto 707181834Sroberto if (numhosts > 1) 708290000Sglebius fprintf(fp, "server=%s ", currenthost); 709181834Sroberto if (dsize == 0) { 710181834Sroberto if (associd == 0) 711290000Sglebius fprintf(fp, "No system%s variables returned\n", 712290000Sglebius (type == TYPE_CLOCK) ? " clock" : ""); 713181834Sroberto else 714290000Sglebius fprintf(fp, 715290000Sglebius "No information returned for%s association %u\n", 716290000Sglebius (type == TYPE_CLOCK) ? " clock" : "", 717290000Sglebius associd); 718181834Sroberto return 1; 719181834Sroberto } 720181834Sroberto 721290000Sglebius if (!quiet) 722290000Sglebius fprintf(fp, "associd=%u ", associd); 723290000Sglebius printvars(dsize, datap, (int)rstatus, type, quiet, fp); 724181834Sroberto return 1; 725181834Sroberto} 726181834Sroberto 727181834Sroberto 728181834Sroberto/* 729181834Sroberto * readlist - send a read variables request with the variables on the list 730181834Sroberto */ 731181834Srobertostatic void 732181834Srobertoreadlist( 733181834Sroberto struct parse *pcmd, 734181834Sroberto FILE *fp 735181834Sroberto ) 736181834Sroberto{ 737290000Sglebius associd_t associd; 738290000Sglebius int type; 739181834Sroberto 740181834Sroberto if (pcmd->nargs == 0) { 741181834Sroberto associd = 0; 742181834Sroberto } else { 743181834Sroberto /* HMS: I think we want the u_int32 target here, not the u_long */ 744181834Sroberto if (pcmd->argval[0].uval == 0) 745181834Sroberto associd = 0; 746181834Sroberto else if ((associd = checkassocid(pcmd->argval[0].uval)) == 0) 747181834Sroberto return; 748181834Sroberto } 749181834Sroberto 750290000Sglebius type = (0 == associd) 751290000Sglebius ? TYPE_SYS 752290000Sglebius : TYPE_PEER; 753290000Sglebius dolist(g_varlist, associd, CTL_OP_READVAR, type, fp); 754181834Sroberto} 755181834Sroberto 756181834Sroberto 757181834Sroberto/* 758181834Sroberto * writelist - send a write variables request with the variables on the list 759181834Sroberto */ 760181834Srobertostatic void 761181834Srobertowritelist( 762181834Sroberto struct parse *pcmd, 763181834Sroberto FILE *fp 764181834Sroberto ) 765181834Sroberto{ 766290000Sglebius const char *datap; 767181834Sroberto int res; 768290000Sglebius associd_t associd; 769293894Sglebius size_t dsize; 770181834Sroberto u_short rstatus; 771181834Sroberto 772181834Sroberto if (pcmd->nargs == 0) { 773181834Sroberto associd = 0; 774181834Sroberto } else { 775181834Sroberto /* HMS: Do we really want uval here? */ 776181834Sroberto if (pcmd->argval[0].uval == 0) 777181834Sroberto associd = 0; 778181834Sroberto else if ((associd = checkassocid(pcmd->argval[0].uval)) == 0) 779181834Sroberto return; 780181834Sroberto } 781181834Sroberto 782290000Sglebius res = doquerylist(g_varlist, CTL_OP_WRITEVAR, associd, 1, &rstatus, 783181834Sroberto &dsize, &datap); 784181834Sroberto 785181834Sroberto if (res != 0) 786181834Sroberto return; 787181834Sroberto 788181834Sroberto if (numhosts > 1) 789181834Sroberto (void) fprintf(fp, "server=%s ", currenthost); 790181834Sroberto if (dsize == 0) 791181834Sroberto (void) fprintf(fp, "done! (no data returned)\n"); 792181834Sroberto else { 793290000Sglebius (void) fprintf(fp,"associd=%u ", associd); 794181834Sroberto printvars(dsize, datap, (int)rstatus, 795290000Sglebius (associd != 0) ? TYPE_PEER : TYPE_SYS, 0, fp); 796181834Sroberto } 797181834Sroberto return; 798181834Sroberto} 799181834Sroberto 800181834Sroberto 801181834Sroberto/* 802181834Sroberto * readvar - send a read variables request with the specified variables 803181834Sroberto */ 804181834Srobertostatic void 805181834Srobertoreadvar( 806181834Sroberto struct parse *pcmd, 807181834Sroberto FILE *fp 808181834Sroberto ) 809181834Sroberto{ 810290000Sglebius associd_t associd; 811293894Sglebius size_t tmpcount; 812293894Sglebius size_t u; 813290000Sglebius int type; 814290000Sglebius struct varlist tmplist[MAXLIST]; 815181834Sroberto 816290000Sglebius 817181834Sroberto /* HMS: uval? */ 818181834Sroberto if (pcmd->nargs == 0 || pcmd->argval[0].uval == 0) 819181834Sroberto associd = 0; 820181834Sroberto else if ((associd = checkassocid(pcmd->argval[0].uval)) == 0) 821181834Sroberto return; 822181834Sroberto 823290000Sglebius ZERO(tmplist); 824290000Sglebius if (pcmd->nargs > 1) { 825290000Sglebius tmpcount = pcmd->nargs - 1; 826290000Sglebius for (u = 0; u < tmpcount; u++) 827290000Sglebius doaddvlist(tmplist, pcmd->argval[1 + u].string); 828290000Sglebius } 829181834Sroberto 830290000Sglebius type = (0 == associd) 831290000Sglebius ? TYPE_SYS 832290000Sglebius : TYPE_PEER; 833290000Sglebius dolist(tmplist, associd, CTL_OP_READVAR, type, fp); 834181834Sroberto 835181834Sroberto doclearvlist(tmplist); 836181834Sroberto} 837181834Sroberto 838181834Sroberto 839181834Sroberto/* 840181834Sroberto * writevar - send a write variables request with the specified variables 841181834Sroberto */ 842181834Srobertostatic void 843181834Srobertowritevar( 844181834Sroberto struct parse *pcmd, 845181834Sroberto FILE *fp 846181834Sroberto ) 847181834Sroberto{ 848290000Sglebius const char *datap; 849181834Sroberto int res; 850290000Sglebius associd_t associd; 851290000Sglebius int type; 852293894Sglebius size_t dsize; 853181834Sroberto u_short rstatus; 854181834Sroberto struct varlist tmplist[MAXLIST]; 855181834Sroberto 856181834Sroberto /* HMS: uval? */ 857181834Sroberto if (pcmd->argval[0].uval == 0) 858181834Sroberto associd = 0; 859181834Sroberto else if ((associd = checkassocid(pcmd->argval[0].uval)) == 0) 860181834Sroberto return; 861181834Sroberto 862290000Sglebius ZERO(tmplist); 863181834Sroberto doaddvlist(tmplist, pcmd->argval[1].string); 864181834Sroberto 865181834Sroberto res = doquerylist(tmplist, CTL_OP_WRITEVAR, associd, 1, &rstatus, 866181834Sroberto &dsize, &datap); 867181834Sroberto 868181834Sroberto doclearvlist(tmplist); 869181834Sroberto 870181834Sroberto if (res != 0) 871181834Sroberto return; 872181834Sroberto 873181834Sroberto if (numhosts > 1) 874290000Sglebius fprintf(fp, "server=%s ", currenthost); 875181834Sroberto if (dsize == 0) 876290000Sglebius fprintf(fp, "done! (no data returned)\n"); 877181834Sroberto else { 878290000Sglebius fprintf(fp,"associd=%u ", associd); 879290000Sglebius type = (0 == associd) 880290000Sglebius ? TYPE_SYS 881290000Sglebius : TYPE_PEER; 882290000Sglebius printvars(dsize, datap, (int)rstatus, type, 0, fp); 883181834Sroberto } 884181834Sroberto return; 885181834Sroberto} 886181834Sroberto 887181834Sroberto 888181834Sroberto/* 889181834Sroberto * clocklist - send a clock variables request with the variables on the list 890181834Sroberto */ 891181834Srobertostatic void 892181834Srobertoclocklist( 893181834Sroberto struct parse *pcmd, 894181834Sroberto FILE *fp 895181834Sroberto ) 896181834Sroberto{ 897290000Sglebius associd_t associd; 898181834Sroberto 899181834Sroberto /* HMS: uval? */ 900181834Sroberto if (pcmd->nargs == 0) { 901181834Sroberto associd = 0; 902181834Sroberto } else { 903181834Sroberto if (pcmd->argval[0].uval == 0) 904181834Sroberto associd = 0; 905181834Sroberto else if ((associd = checkassocid(pcmd->argval[0].uval)) == 0) 906181834Sroberto return; 907181834Sroberto } 908181834Sroberto 909290000Sglebius dolist(g_varlist, associd, CTL_OP_READCLOCK, TYPE_CLOCK, fp); 910181834Sroberto} 911181834Sroberto 912181834Sroberto 913181834Sroberto/* 914181834Sroberto * clockvar - send a clock variables request with the specified variables 915181834Sroberto */ 916181834Srobertostatic void 917181834Srobertoclockvar( 918181834Sroberto struct parse *pcmd, 919181834Sroberto FILE *fp 920181834Sroberto ) 921181834Sroberto{ 922290000Sglebius associd_t associd; 923181834Sroberto struct varlist tmplist[MAXLIST]; 924181834Sroberto 925181834Sroberto /* HMS: uval? */ 926181834Sroberto if (pcmd->nargs == 0 || pcmd->argval[0].uval == 0) 927181834Sroberto associd = 0; 928181834Sroberto else if ((associd = checkassocid(pcmd->argval[0].uval)) == 0) 929181834Sroberto return; 930181834Sroberto 931290000Sglebius ZERO(tmplist); 932181834Sroberto if (pcmd->nargs >= 2) 933181834Sroberto doaddvlist(tmplist, pcmd->argval[1].string); 934181834Sroberto 935290000Sglebius dolist(tmplist, associd, CTL_OP_READCLOCK, TYPE_CLOCK, fp); 936181834Sroberto 937181834Sroberto doclearvlist(tmplist); 938181834Sroberto} 939181834Sroberto 940181834Sroberto 941181834Sroberto/* 942181834Sroberto * findassidrange - verify a range of association ID's 943181834Sroberto */ 944181834Srobertostatic int 945181834Srobertofindassidrange( 946290000Sglebius u_int32 assid1, 947290000Sglebius u_int32 assid2, 948290000Sglebius int * from, 949290000Sglebius int * to, 950290000Sglebius FILE * fp 951181834Sroberto ) 952181834Sroberto{ 953290000Sglebius associd_t assids[2]; 954290000Sglebius int ind[COUNTOF(assids)]; 955290000Sglebius u_int i; 956290000Sglebius size_t a; 957181834Sroberto 958290000Sglebius 959290000Sglebius if (0 == numassoc) 960290000Sglebius dogetassoc(fp); 961290000Sglebius 962290000Sglebius assids[0] = checkassocid(assid1); 963290000Sglebius if (0 == assids[0]) 964181834Sroberto return 0; 965290000Sglebius assids[1] = checkassocid(assid2); 966290000Sglebius if (0 == assids[1]) 967290000Sglebius return 0; 968181834Sroberto 969290000Sglebius for (a = 0; a < COUNTOF(assids); a++) { 970290000Sglebius ind[a] = -1; 971290000Sglebius for (i = 0; i < numassoc; i++) 972290000Sglebius if (assoc_cache[i].assid == assids[a]) 973290000Sglebius ind[a] = i; 974181834Sroberto } 975290000Sglebius for (a = 0; a < COUNTOF(assids); a++) 976290000Sglebius if (-1 == ind[a]) { 977290000Sglebius fprintf(stderr, 978290000Sglebius "***Association ID %u not found in list\n", 979290000Sglebius assids[a]); 980290000Sglebius return 0; 981181834Sroberto } 982181834Sroberto 983290000Sglebius if (ind[0] < ind[1]) { 984290000Sglebius *from = ind[0]; 985290000Sglebius *to = ind[1]; 986181834Sroberto } else { 987290000Sglebius *to = ind[0]; 988290000Sglebius *from = ind[1]; 989181834Sroberto } 990181834Sroberto return 1; 991181834Sroberto} 992181834Sroberto 993181834Sroberto 994181834Sroberto 995181834Sroberto/* 996181834Sroberto * mreadlist - send a read variables request for multiple associations 997181834Sroberto */ 998181834Srobertostatic void 999181834Srobertomreadlist( 1000181834Sroberto struct parse *pcmd, 1001181834Sroberto FILE *fp 1002181834Sroberto ) 1003181834Sroberto{ 1004181834Sroberto int i; 1005181834Sroberto int from; 1006181834Sroberto int to; 1007181834Sroberto 1008181834Sroberto if (!findassidrange(pcmd->argval[0].uval, pcmd->argval[1].uval, 1009290000Sglebius &from, &to, fp)) 1010181834Sroberto return; 1011181834Sroberto 1012181834Sroberto for (i = from; i <= to; i++) { 1013181834Sroberto if (i != from) 1014290000Sglebius fprintf(fp, "\n"); 1015290000Sglebius if (!dolist(g_varlist, assoc_cache[i].assid, 1016290000Sglebius CTL_OP_READVAR, TYPE_PEER, fp)) 1017181834Sroberto return; 1018181834Sroberto } 1019181834Sroberto return; 1020181834Sroberto} 1021181834Sroberto 1022181834Sroberto 1023181834Sroberto/* 1024181834Sroberto * mreadvar - send a read variables request for multiple associations 1025181834Sroberto */ 1026181834Srobertostatic void 1027181834Srobertomreadvar( 1028181834Sroberto struct parse *pcmd, 1029181834Sroberto FILE *fp 1030181834Sroberto ) 1031181834Sroberto{ 1032181834Sroberto int i; 1033181834Sroberto int from; 1034181834Sroberto int to; 1035181834Sroberto struct varlist tmplist[MAXLIST]; 1036290000Sglebius struct varlist *pvars; 1037181834Sroberto 1038181834Sroberto if (!findassidrange(pcmd->argval[0].uval, pcmd->argval[1].uval, 1039290000Sglebius &from, &to, fp)) 1040181834Sroberto return; 1041181834Sroberto 1042290000Sglebius ZERO(tmplist); 1043290000Sglebius if (pcmd->nargs >= 3) { 1044181834Sroberto doaddvlist(tmplist, pcmd->argval[2].string); 1045290000Sglebius pvars = tmplist; 1046290000Sglebius } else { 1047290000Sglebius pvars = g_varlist; 1048290000Sglebius } 1049181834Sroberto 1050181834Sroberto for (i = from; i <= to; i++) { 1051290000Sglebius if (!dolist(pvars, assoc_cache[i].assid, CTL_OP_READVAR, 1052290000Sglebius TYPE_PEER, fp)) 1053181834Sroberto break; 1054181834Sroberto } 1055290000Sglebius 1056290000Sglebius if (pvars == tmplist) 1057290000Sglebius doclearvlist(tmplist); 1058290000Sglebius 1059181834Sroberto return; 1060181834Sroberto} 1061181834Sroberto 1062181834Sroberto 1063181834Sroberto/* 1064181834Sroberto * dogetassoc - query the host for its list of associations 1065181834Sroberto */ 1066290000Sglebiusint 1067181834Srobertodogetassoc( 1068181834Sroberto FILE *fp 1069181834Sroberto ) 1070181834Sroberto{ 1071290000Sglebius const char *datap; 1072290000Sglebius const u_short *pus; 1073181834Sroberto int res; 1074293894Sglebius size_t dsize; 1075181834Sroberto u_short rstatus; 1076181834Sroberto 1077181834Sroberto res = doquery(CTL_OP_READSTAT, 0, 0, 0, (char *)0, &rstatus, 1078181834Sroberto &dsize, &datap); 1079181834Sroberto 1080181834Sroberto if (res != 0) 1081181834Sroberto return 0; 1082181834Sroberto 1083181834Sroberto if (dsize == 0) { 1084181834Sroberto if (numhosts > 1) 1085290000Sglebius fprintf(fp, "server=%s ", currenthost); 1086290000Sglebius fprintf(fp, "No association ID's returned\n"); 1087181834Sroberto return 0; 1088181834Sroberto } 1089181834Sroberto 1090181834Sroberto if (dsize & 0x3) { 1091181834Sroberto if (numhosts > 1) 1092290000Sglebius fprintf(stderr, "server=%s ", currenthost); 1093290000Sglebius fprintf(stderr, 1094293894Sglebius "***Server returned %zu octets, should be multiple of 4\n", 1095290000Sglebius dsize); 1096181834Sroberto return 0; 1097181834Sroberto } 1098181834Sroberto 1099181834Sroberto numassoc = 0; 1100290000Sglebius 1101181834Sroberto while (dsize > 0) { 1102290000Sglebius if (numassoc >= assoc_cache_slots) { 1103290000Sglebius grow_assoc_cache(); 1104290000Sglebius } 1105290000Sglebius pus = (const void *)datap; 1106290000Sglebius assoc_cache[numassoc].assid = ntohs(*pus); 1107290000Sglebius datap += sizeof(*pus); 1108290000Sglebius pus = (const void *)datap; 1109290000Sglebius assoc_cache[numassoc].status = ntohs(*pus); 1110290000Sglebius datap += sizeof(*pus); 1111290000Sglebius dsize -= 2 * sizeof(*pus); 1112290000Sglebius if (debug) { 1113290000Sglebius fprintf(stderr, "[%u] ", 1114290000Sglebius assoc_cache[numassoc].assid); 1115290000Sglebius } 1116290000Sglebius numassoc++; 1117181834Sroberto } 1118290000Sglebius if (debug) { 1119290000Sglebius fprintf(stderr, "\n%d associations total\n", numassoc); 1120290000Sglebius } 1121181834Sroberto sortassoc(); 1122181834Sroberto return 1; 1123181834Sroberto} 1124181834Sroberto 1125181834Sroberto 1126181834Sroberto/* 1127181834Sroberto * printassoc - print the current list of associations 1128181834Sroberto */ 1129181834Srobertostatic void 1130181834Srobertoprintassoc( 1131181834Sroberto int showall, 1132181834Sroberto FILE *fp 1133181834Sroberto ) 1134181834Sroberto{ 1135181834Sroberto register char *bp; 1136290000Sglebius u_int i; 1137181834Sroberto u_char statval; 1138181834Sroberto int event; 1139181834Sroberto u_long event_count; 1140181834Sroberto const char *conf; 1141181834Sroberto const char *reach; 1142181834Sroberto const char *auth; 1143181834Sroberto const char *condition = ""; 1144181834Sroberto const char *last_event; 1145181834Sroberto char buf[128]; 1146181834Sroberto 1147181834Sroberto if (numassoc == 0) { 1148181834Sroberto (void) fprintf(fp, "No association ID's in list\n"); 1149181834Sroberto return; 1150181834Sroberto } 1151181834Sroberto 1152181834Sroberto /* 1153181834Sroberto * Output a header 1154181834Sroberto */ 1155181834Sroberto (void) fprintf(fp, 1156290000Sglebius "\nind assid status conf reach auth condition last_event cnt\n"); 1157181834Sroberto (void) fprintf(fp, 1158181834Sroberto "===========================================================\n"); 1159181834Sroberto for (i = 0; i < numassoc; i++) { 1160181834Sroberto statval = (u_char) CTL_PEER_STATVAL(assoc_cache[i].status); 1161181834Sroberto if (!showall && !(statval & (CTL_PST_CONFIG|CTL_PST_REACH))) 1162181834Sroberto continue; 1163181834Sroberto event = CTL_PEER_EVENT(assoc_cache[i].status); 1164181834Sroberto event_count = CTL_PEER_NEVNT(assoc_cache[i].status); 1165181834Sroberto if (statval & CTL_PST_CONFIG) 1166181834Sroberto conf = "yes"; 1167181834Sroberto else 1168181834Sroberto conf = "no"; 1169290000Sglebius if (statval & CTL_PST_BCAST) { 1170290000Sglebius reach = "none"; 1171290000Sglebius if (statval & CTL_PST_AUTHENABLE) 1172290000Sglebius auth = "yes"; 1173290000Sglebius else 1174290000Sglebius auth = "none"; 1175290000Sglebius } else { 1176290000Sglebius if (statval & CTL_PST_REACH) 1177290000Sglebius reach = "yes"; 1178290000Sglebius else 1179290000Sglebius reach = "no"; 1180181834Sroberto if (statval & CTL_PST_AUTHENABLE) { 1181181834Sroberto if (statval & CTL_PST_AUTHENTIC) 1182181834Sroberto auth = "ok "; 1183181834Sroberto else 1184181834Sroberto auth = "bad"; 1185290000Sglebius } else { 1186181834Sroberto auth = "none"; 1187290000Sglebius } 1188290000Sglebius } 1189290000Sglebius if (pktversion > NTP_OLDVERSION) { 1190290000Sglebius switch (statval & 0x7) { 1191181834Sroberto 1192290000Sglebius case CTL_PST_SEL_REJECT: 1193290000Sglebius condition = "reject"; 1194290000Sglebius break; 1195290000Sglebius 1196290000Sglebius case CTL_PST_SEL_SANE: 1197290000Sglebius condition = "falsetick"; 1198290000Sglebius break; 1199290000Sglebius 1200290000Sglebius case CTL_PST_SEL_CORRECT: 1201290000Sglebius condition = "excess"; 1202290000Sglebius break; 1203290000Sglebius 1204290000Sglebius case CTL_PST_SEL_SELCAND: 1205290000Sglebius condition = "outlier"; 1206290000Sglebius break; 1207290000Sglebius 1208290000Sglebius case CTL_PST_SEL_SYNCCAND: 1209290000Sglebius condition = "candidate"; 1210290000Sglebius break; 1211290000Sglebius 1212290000Sglebius case CTL_PST_SEL_EXCESS: 1213290000Sglebius condition = "backup"; 1214290000Sglebius break; 1215290000Sglebius 1216290000Sglebius case CTL_PST_SEL_SYSPEER: 1217290000Sglebius condition = "sys.peer"; 1218290000Sglebius break; 1219290000Sglebius 1220290000Sglebius case CTL_PST_SEL_PPS: 1221290000Sglebius condition = "pps.peer"; 1222290000Sglebius break; 1223290000Sglebius } 1224290000Sglebius } else { 1225290000Sglebius switch (statval & 0x3) { 1226290000Sglebius 1227290000Sglebius case OLD_CTL_PST_SEL_REJECT: 1228290000Sglebius if (!(statval & OLD_CTL_PST_SANE)) 1229181834Sroberto condition = "insane"; 1230290000Sglebius else if (!(statval & OLD_CTL_PST_DISP)) 1231181834Sroberto condition = "hi_disp"; 1232290000Sglebius else 1233181834Sroberto condition = ""; 1234290000Sglebius break; 1235181834Sroberto 1236290000Sglebius case OLD_CTL_PST_SEL_SELCAND: 1237290000Sglebius condition = "sel_cand"; 1238290000Sglebius break; 1239290000Sglebius 1240290000Sglebius case OLD_CTL_PST_SEL_SYNCCAND: 1241290000Sglebius condition = "sync_cand"; 1242290000Sglebius break; 1243290000Sglebius 1244290000Sglebius case OLD_CTL_PST_SEL_SYSPEER: 1245290000Sglebius condition = "sys_peer"; 1246290000Sglebius break; 1247290000Sglebius } 1248181834Sroberto } 1249290000Sglebius switch (PEER_EVENT|event) { 1250181834Sroberto 1251290000Sglebius case PEVNT_MOBIL: 1252290000Sglebius last_event = "mobilize"; 1253181834Sroberto break; 1254290000Sglebius 1255290000Sglebius case PEVNT_DEMOBIL: 1256290000Sglebius last_event = "demobilize"; 1257181834Sroberto break; 1258290000Sglebius 1259290000Sglebius case PEVNT_REACH: 1260181834Sroberto last_event = "reachable"; 1261181834Sroberto break; 1262290000Sglebius 1263290000Sglebius case PEVNT_UNREACH: 1264290000Sglebius last_event = "unreachable"; 1265181834Sroberto break; 1266290000Sglebius 1267290000Sglebius case PEVNT_RESTART: 1268290000Sglebius last_event = "restart"; 1269181834Sroberto break; 1270290000Sglebius 1271290000Sglebius case PEVNT_REPLY: 1272290000Sglebius last_event = "no_reply"; 1273290000Sglebius break; 1274290000Sglebius 1275290000Sglebius case PEVNT_RATE: 1276290000Sglebius last_event = "rate_exceeded"; 1277290000Sglebius break; 1278290000Sglebius 1279290000Sglebius case PEVNT_DENY: 1280290000Sglebius last_event = "access_denied"; 1281290000Sglebius break; 1282290000Sglebius 1283290000Sglebius case PEVNT_ARMED: 1284290000Sglebius last_event = "leap_armed"; 1285290000Sglebius break; 1286290000Sglebius 1287290000Sglebius case PEVNT_NEWPEER: 1288290000Sglebius last_event = "sys_peer"; 1289290000Sglebius break; 1290290000Sglebius 1291290000Sglebius case PEVNT_CLOCK: 1292290000Sglebius last_event = "clock_alarm"; 1293290000Sglebius break; 1294290000Sglebius 1295290000Sglebius default: 1296181834Sroberto last_event = ""; 1297181834Sroberto break; 1298181834Sroberto } 1299290000Sglebius snprintf(buf, sizeof(buf), 1300290000Sglebius "%3d %5u %04x %3.3s %4s %4.4s %9.9s %11s %2lu", 1301290000Sglebius i + 1, assoc_cache[i].assid, 1302290000Sglebius assoc_cache[i].status, conf, reach, auth, 1303290000Sglebius condition, last_event, event_count); 1304290000Sglebius bp = buf + strlen(buf); 1305290000Sglebius while (bp > buf && ' ' == bp[-1]) 1306290000Sglebius --bp; 1307290000Sglebius bp[0] = '\0'; 1308290000Sglebius fprintf(fp, "%s\n", buf); 1309181834Sroberto } 1310181834Sroberto} 1311181834Sroberto 1312181834Sroberto 1313181834Sroberto/* 1314181834Sroberto * associations - get, record and print a list of associations 1315181834Sroberto */ 1316181834Sroberto/*ARGSUSED*/ 1317181834Srobertostatic void 1318181834Srobertoassociations( 1319181834Sroberto struct parse *pcmd, 1320181834Sroberto FILE *fp 1321181834Sroberto ) 1322181834Sroberto{ 1323181834Sroberto if (dogetassoc(fp)) 1324181834Sroberto printassoc(0, fp); 1325181834Sroberto} 1326181834Sroberto 1327181834Sroberto 1328181834Sroberto/* 1329181834Sroberto * lassociations - get, record and print a long list of associations 1330181834Sroberto */ 1331181834Sroberto/*ARGSUSED*/ 1332181834Srobertostatic void 1333181834Srobertolassociations( 1334181834Sroberto struct parse *pcmd, 1335181834Sroberto FILE *fp 1336181834Sroberto ) 1337181834Sroberto{ 1338181834Sroberto if (dogetassoc(fp)) 1339181834Sroberto printassoc(1, fp); 1340181834Sroberto} 1341181834Sroberto 1342181834Sroberto 1343181834Sroberto/* 1344181834Sroberto * passociations - print the association list 1345181834Sroberto */ 1346181834Sroberto/*ARGSUSED*/ 1347181834Srobertostatic void 1348181834Srobertopassociations( 1349181834Sroberto struct parse *pcmd, 1350181834Sroberto FILE *fp 1351181834Sroberto ) 1352181834Sroberto{ 1353181834Sroberto printassoc(0, fp); 1354181834Sroberto} 1355181834Sroberto 1356181834Sroberto 1357181834Sroberto/* 1358181834Sroberto * lpassociations - print the long association list 1359181834Sroberto */ 1360181834Sroberto/*ARGSUSED*/ 1361181834Srobertostatic void 1362181834Srobertolpassociations( 1363181834Sroberto struct parse *pcmd, 1364181834Sroberto FILE *fp 1365181834Sroberto ) 1366181834Sroberto{ 1367181834Sroberto printassoc(1, fp); 1368181834Sroberto} 1369181834Sroberto 1370181834Sroberto 1371181834Sroberto/* 1372290000Sglebius * saveconfig - dump ntp server configuration to server file 1373181834Sroberto */ 1374181834Srobertostatic void 1375290000Sglebiussaveconfig( 1376181834Sroberto struct parse *pcmd, 1377181834Sroberto FILE *fp 1378181834Sroberto ) 1379181834Sroberto{ 1380290000Sglebius const char *datap; 1381181834Sroberto int res; 1382293894Sglebius size_t dsize; 1383181834Sroberto u_short rstatus; 1384181834Sroberto 1385290000Sglebius if (0 == pcmd->nargs) 1386290000Sglebius return; 1387290000Sglebius 1388290000Sglebius res = doquery(CTL_OP_SAVECONFIG, 0, 1, 1389290000Sglebius strlen(pcmd->argval[0].string), 1390290000Sglebius pcmd->argval[0].string, &rstatus, &dsize, 1391290000Sglebius &datap); 1392181834Sroberto 1393181834Sroberto if (res != 0) 1394181834Sroberto return; 1395181834Sroberto 1396290000Sglebius if (0 == dsize) 1397290000Sglebius fprintf(fp, "(no response message, curiously)"); 1398290000Sglebius else 1399293894Sglebius fprintf(fp, "%.*s", (int)dsize, datap); /* cast is wobbly */ 1400181834Sroberto} 1401181834Sroberto 1402290000Sglebius 1403290000Sglebius#ifdef UNUSED 1404181834Sroberto/* 1405290000Sglebius * radiostatus - print the radio status returned by the server 1406181834Sroberto */ 1407290000Sglebius/*ARGSUSED*/ 1408181834Srobertostatic void 1409290000Sglebiusradiostatus( 1410181834Sroberto struct parse *pcmd, 1411181834Sroberto FILE *fp 1412181834Sroberto ) 1413181834Sroberto{ 1414181834Sroberto char *datap; 1415181834Sroberto int res; 1416181834Sroberto int dsize; 1417181834Sroberto u_short rstatus; 1418181834Sroberto 1419290000Sglebius res = doquery(CTL_OP_READCLOCK, 0, 0, 0, (char *)0, &rstatus, 1420181834Sroberto &dsize, &datap); 1421181834Sroberto 1422181834Sroberto if (res != 0) 1423181834Sroberto return; 1424181834Sroberto 1425181834Sroberto if (numhosts > 1) 1426181834Sroberto (void) fprintf(fp, "server=%s ", currenthost); 1427181834Sroberto if (dsize == 0) { 1428290000Sglebius (void) fprintf(fp, "No radio status string returned\n"); 1429181834Sroberto return; 1430181834Sroberto } 1431181834Sroberto 1432290000Sglebius asciize(dsize, datap, fp); 1433181834Sroberto} 1434290000Sglebius#endif /* UNUSED */ 1435181834Sroberto 1436181834Sroberto/* 1437181834Sroberto * when - print how long its been since his last packet arrived 1438181834Sroberto */ 1439181834Srobertostatic long 1440181834Srobertowhen( 1441181834Sroberto l_fp *ts, 1442181834Sroberto l_fp *rec, 1443181834Sroberto l_fp *reftime 1444181834Sroberto ) 1445181834Sroberto{ 1446181834Sroberto l_fp *lasttime; 1447181834Sroberto 1448181834Sroberto if (rec->l_ui != 0) 1449181834Sroberto lasttime = rec; 1450181834Sroberto else if (reftime->l_ui != 0) 1451181834Sroberto lasttime = reftime; 1452181834Sroberto else 1453181834Sroberto return 0; 1454181834Sroberto 1455181834Sroberto return (ts->l_ui - lasttime->l_ui); 1456181834Sroberto} 1457181834Sroberto 1458181834Sroberto 1459181834Sroberto/* 1460181834Sroberto * Pretty-print an interval into the given buffer, in a human-friendly format. 1461181834Sroberto */ 1462181834Srobertostatic char * 1463181834Srobertoprettyinterval( 1464181834Sroberto char *buf, 1465290000Sglebius size_t cb, 1466181834Sroberto long diff 1467181834Sroberto ) 1468181834Sroberto{ 1469181834Sroberto if (diff <= 0) { 1470181834Sroberto buf[0] = '-'; 1471181834Sroberto buf[1] = 0; 1472181834Sroberto return buf; 1473181834Sroberto } 1474181834Sroberto 1475181834Sroberto if (diff <= 2048) { 1476290000Sglebius snprintf(buf, cb, "%ld", diff); 1477181834Sroberto return buf; 1478181834Sroberto } 1479181834Sroberto 1480181834Sroberto diff = (diff + 29) / 60; 1481181834Sroberto if (diff <= 300) { 1482290000Sglebius snprintf(buf, cb, "%ldm", diff); 1483181834Sroberto return buf; 1484181834Sroberto } 1485181834Sroberto 1486181834Sroberto diff = (diff + 29) / 60; 1487181834Sroberto if (diff <= 96) { 1488290000Sglebius snprintf(buf, cb, "%ldh", diff); 1489181834Sroberto return buf; 1490181834Sroberto } 1491181834Sroberto 1492181834Sroberto diff = (diff + 11) / 24; 1493290000Sglebius snprintf(buf, cb, "%ldd", diff); 1494181834Sroberto return buf; 1495181834Sroberto} 1496181834Sroberto 1497181834Srobertostatic char 1498181834Srobertodecodeaddrtype( 1499290000Sglebius sockaddr_u *sock 1500181834Sroberto ) 1501181834Sroberto{ 1502181834Sroberto char ch = '-'; 1503181834Sroberto u_int32 dummy; 1504181834Sroberto 1505290000Sglebius switch(AF(sock)) { 1506181834Sroberto case AF_INET: 1507290000Sglebius dummy = SRCADR(sock); 1508181834Sroberto ch = (char)(((dummy&0xf0000000)==0xe0000000) ? 'm' : 1509181834Sroberto ((dummy&0x000000ff)==0x000000ff) ? 'b' : 1510181834Sroberto ((dummy&0xffffffff)==0x7f000001) ? 'l' : 1511181834Sroberto ((dummy&0xffffffe0)==0x00000000) ? '-' : 1512181834Sroberto 'u'); 1513181834Sroberto break; 1514181834Sroberto case AF_INET6: 1515290000Sglebius if (IN6_IS_ADDR_MULTICAST(PSOCK_ADDR6(sock))) 1516181834Sroberto ch = 'm'; 1517181834Sroberto else 1518181834Sroberto ch = 'u'; 1519181834Sroberto break; 1520181834Sroberto default: 1521181834Sroberto ch = '-'; 1522181834Sroberto break; 1523181834Sroberto } 1524181834Sroberto return ch; 1525181834Sroberto} 1526181834Sroberto 1527181834Sroberto/* 1528181834Sroberto * A list of variables required by the peers command 1529181834Sroberto */ 1530181834Srobertostruct varlist opeervarlist[] = { 1531290000Sglebius { "srcadr", 0 }, /* 0 */ 1532290000Sglebius { "dstadr", 0 }, /* 1 */ 1533290000Sglebius { "stratum", 0 }, /* 2 */ 1534290000Sglebius { "hpoll", 0 }, /* 3 */ 1535290000Sglebius { "ppoll", 0 }, /* 4 */ 1536290000Sglebius { "reach", 0 }, /* 5 */ 1537290000Sglebius { "delay", 0 }, /* 6 */ 1538290000Sglebius { "offset", 0 }, /* 7 */ 1539290000Sglebius { "jitter", 0 }, /* 8 */ 1540290000Sglebius { "dispersion", 0 }, /* 9 */ 1541290000Sglebius { "rec", 0 }, /* 10 */ 1542290000Sglebius { "reftime", 0 }, /* 11 */ 1543290000Sglebius { "srcport", 0 }, /* 12 */ 1544290000Sglebius { "hmode", 0 }, /* 13 */ 1545181834Sroberto { 0, 0 } 1546181834Sroberto}; 1547181834Sroberto 1548181834Srobertostruct varlist peervarlist[] = { 1549290000Sglebius { "srcadr", 0 }, /* 0 */ 1550290000Sglebius { "refid", 0 }, /* 1 */ 1551290000Sglebius { "stratum", 0 }, /* 2 */ 1552290000Sglebius { "hpoll", 0 }, /* 3 */ 1553290000Sglebius { "ppoll", 0 }, /* 4 */ 1554290000Sglebius { "reach", 0 }, /* 5 */ 1555290000Sglebius { "delay", 0 }, /* 6 */ 1556290000Sglebius { "offset", 0 }, /* 7 */ 1557290000Sglebius { "jitter", 0 }, /* 8 */ 1558290000Sglebius { "dispersion", 0 }, /* 9 */ 1559290000Sglebius { "rec", 0 }, /* 10 */ 1560290000Sglebius { "reftime", 0 }, /* 11 */ 1561290000Sglebius { "srcport", 0 }, /* 12 */ 1562290000Sglebius { "hmode", 0 }, /* 13 */ 1563290000Sglebius { "srchost", 0 }, /* 14 */ 1564181834Sroberto { 0, 0 } 1565181834Sroberto}; 1566181834Sroberto 1567290000Sglebiusstruct varlist apeervarlist[] = { 1568290000Sglebius { "srcadr", 0 }, /* 0 */ 1569290000Sglebius { "refid", 0 }, /* 1 */ 1570290000Sglebius { "assid", 0 }, /* 2 */ 1571290000Sglebius { "stratum", 0 }, /* 3 */ 1572290000Sglebius { "hpoll", 0 }, /* 4 */ 1573290000Sglebius { "ppoll", 0 }, /* 5 */ 1574290000Sglebius { "reach", 0 }, /* 6 */ 1575290000Sglebius { "delay", 0 }, /* 7 */ 1576290000Sglebius { "offset", 0 }, /* 8 */ 1577290000Sglebius { "jitter", 0 }, /* 9 */ 1578290000Sglebius { "dispersion", 0 }, /* 10 */ 1579290000Sglebius { "rec", 0 }, /* 11 */ 1580290000Sglebius { "reftime", 0 }, /* 12 */ 1581290000Sglebius { "srcport", 0 }, /* 13 */ 1582290000Sglebius { "hmode", 0 }, /* 14 */ 1583290000Sglebius { "srchost", 0 }, /* 15 */ 1584290000Sglebius { 0, 0 } 1585290000Sglebius}; 1586181834Sroberto 1587290000Sglebius 1588181834Sroberto/* 1589181834Sroberto * Decode an incoming data buffer and print a line in the peer list 1590181834Sroberto */ 1591181834Srobertostatic int 1592181834Srobertodoprintpeers( 1593181834Sroberto struct varlist *pvl, 1594181834Sroberto int associd, 1595181834Sroberto int rstatus, 1596293894Sglebius size_t datalen, 1597290000Sglebius const char *data, 1598181834Sroberto FILE *fp, 1599181834Sroberto int af 1600181834Sroberto ) 1601181834Sroberto{ 1602181834Sroberto char *name; 1603181834Sroberto char *value = NULL; 1604181834Sroberto int c; 1605293894Sglebius size_t len; 1606290000Sglebius int have_srchost; 1607290000Sglebius int have_dstadr; 1608290000Sglebius int have_da_rid; 1609290000Sglebius int have_jitter; 1610290000Sglebius sockaddr_u srcadr; 1611290000Sglebius sockaddr_u dstadr; 1612290000Sglebius sockaddr_u dum_store; 1613290000Sglebius sockaddr_u refidadr; 1614290000Sglebius long hmode = 0; 1615181834Sroberto u_long srcport = 0; 1616290000Sglebius u_int32 u32; 1617290000Sglebius const char *dstadr_refid = "0.0.0.0"; 1618290000Sglebius const char *serverlocal; 1619290000Sglebius size_t drlen; 1620181834Sroberto u_long stratum = 0; 1621181834Sroberto long ppoll = 0; 1622181834Sroberto long hpoll = 0; 1623181834Sroberto u_long reach = 0; 1624181834Sroberto l_fp estoffset; 1625181834Sroberto l_fp estdelay; 1626181834Sroberto l_fp estjitter; 1627181834Sroberto l_fp estdisp; 1628181834Sroberto l_fp reftime; 1629181834Sroberto l_fp rec; 1630181834Sroberto l_fp ts; 1631181834Sroberto u_long poll_sec; 1632181834Sroberto char type = '?'; 1633181834Sroberto char whenbuf[8], pollbuf[8]; 1634181834Sroberto char clock_name[LENHOSTNAME]; 1635181834Sroberto 1636181834Sroberto get_systime(&ts); 1637181834Sroberto 1638290000Sglebius have_srchost = FALSE; 1639290000Sglebius have_dstadr = FALSE; 1640290000Sglebius have_da_rid = FALSE; 1641290000Sglebius have_jitter = FALSE; 1642290000Sglebius ZERO_SOCK(&srcadr); 1643290000Sglebius ZERO_SOCK(&dstadr); 1644290000Sglebius clock_name[0] = '\0'; 1645290000Sglebius ZERO(estoffset); 1646290000Sglebius ZERO(estdelay); 1647290000Sglebius ZERO(estjitter); 1648290000Sglebius ZERO(estdisp); 1649181834Sroberto 1650181834Sroberto while (nextvar(&datalen, &data, &name, &value)) { 1651290000Sglebius if (!strcmp("srcadr", name) || 1652290000Sglebius !strcmp("peeradr", name)) { 1653290000Sglebius if (!decodenetnum(value, &srcadr)) 1654290000Sglebius fprintf(stderr, "malformed %s=%s\n", 1655290000Sglebius name, value); 1656290000Sglebius } else if (!strcmp("srchost", name)) { 1657290000Sglebius if (pvl == peervarlist || pvl == apeervarlist) { 1658290000Sglebius len = strlen(value); 1659290000Sglebius if (2 < len && 1660290000Sglebius (size_t)len < sizeof(clock_name)) { 1661290000Sglebius /* strip quotes */ 1662290000Sglebius value++; 1663290000Sglebius len -= 2; 1664290000Sglebius memcpy(clock_name, value, len); 1665290000Sglebius clock_name[len] = '\0'; 1666290000Sglebius have_srchost = TRUE; 1667290000Sglebius } 1668290000Sglebius } 1669290000Sglebius } else if (!strcmp("dstadr", name)) { 1670290000Sglebius if (decodenetnum(value, &dum_store)) { 1671181834Sroberto type = decodeaddrtype(&dum_store); 1672290000Sglebius have_dstadr = TRUE; 1673290000Sglebius dstadr = dum_store; 1674290000Sglebius if (pvl == opeervarlist) { 1675290000Sglebius have_da_rid = TRUE; 1676290000Sglebius dstadr_refid = trunc_left(stoa(&dstadr), 15); 1677181834Sroberto } 1678181834Sroberto } 1679290000Sglebius } else if (!strcmp("hmode", name)) { 1680290000Sglebius decodeint(value, &hmode); 1681290000Sglebius } else if (!strcmp("refid", name)) { 1682298770Sdelphij if ( (pvl == peervarlist) 1683298770Sdelphij && (drefid == REFID_IPV4)) { 1684290000Sglebius have_da_rid = TRUE; 1685290000Sglebius drlen = strlen(value); 1686290000Sglebius if (0 == drlen) { 1687290000Sglebius dstadr_refid = ""; 1688290000Sglebius } else if (drlen <= 4) { 1689290000Sglebius ZERO(u32); 1690290000Sglebius memcpy(&u32, value, drlen); 1691290000Sglebius dstadr_refid = refid_str(u32, 1); 1692290000Sglebius } else if (decodenetnum(value, &refidadr)) { 1693290000Sglebius if (SOCK_UNSPEC(&refidadr)) 1694181834Sroberto dstadr_refid = "0.0.0.0"; 1695290000Sglebius else if (ISREFCLOCKADR(&refidadr)) 1696290000Sglebius dstadr_refid = 1697290000Sglebius refnumtoa(&refidadr); 1698181834Sroberto else 1699181834Sroberto dstadr_refid = 1700290000Sglebius stoa(&refidadr); 1701181834Sroberto } else { 1702290000Sglebius have_da_rid = FALSE; 1703181834Sroberto } 1704298770Sdelphij } else if ( (pvl == apeervarlist) 1705298770Sdelphij || (pvl == peervarlist)) { 1706298770Sdelphij /* no need to check drefid == REFID_HASH */ 1707290000Sglebius have_da_rid = TRUE; 1708290000Sglebius drlen = strlen(value); 1709290000Sglebius if (0 == drlen) { 1710290000Sglebius dstadr_refid = ""; 1711290000Sglebius } else if (drlen <= 4) { 1712290000Sglebius ZERO(u32); 1713290000Sglebius memcpy(&u32, value, drlen); 1714290000Sglebius dstadr_refid = refid_str(u32, 1); 1715290000Sglebius //fprintf(stderr, "apeervarlist S1 refid: value=<%s>\n", value); 1716290000Sglebius } else if (decodenetnum(value, &refidadr)) { 1717290000Sglebius if (SOCK_UNSPEC(&refidadr)) 1718290000Sglebius dstadr_refid = "0.0.0.0"; 1719290000Sglebius else if (ISREFCLOCKADR(&refidadr)) 1720290000Sglebius dstadr_refid = 1721290000Sglebius refnumtoa(&refidadr); 1722290000Sglebius else { 1723290000Sglebius char *buf = emalloc(10); 1724290000Sglebius int i = ntohl(refidadr.sa4.sin_addr.s_addr); 1725290000Sglebius 1726290000Sglebius snprintf(buf, 10, 1727290000Sglebius "%0x", i); 1728290000Sglebius dstadr_refid = buf; 1729290000Sglebius //fprintf(stderr, "apeervarlist refid: value=<%x>\n", i); 1730290000Sglebius } 1731290000Sglebius //fprintf(stderr, "apeervarlist refid: value=<%s>\n", value); 1732290000Sglebius } else { 1733290000Sglebius have_da_rid = FALSE; 1734290000Sglebius } 1735181834Sroberto } 1736290000Sglebius } else if (!strcmp("stratum", name)) { 1737290000Sglebius decodeuint(value, &stratum); 1738290000Sglebius } else if (!strcmp("hpoll", name)) { 1739290000Sglebius if (decodeint(value, &hpoll) && hpoll < 0) 1740290000Sglebius hpoll = NTP_MINPOLL; 1741290000Sglebius } else if (!strcmp("ppoll", name)) { 1742290000Sglebius if (decodeint(value, &ppoll) && ppoll < 0) 1743290000Sglebius ppoll = NTP_MINPOLL; 1744290000Sglebius } else if (!strcmp("reach", name)) { 1745290000Sglebius decodeuint(value, &reach); 1746290000Sglebius } else if (!strcmp("delay", name)) { 1747290000Sglebius decodetime(value, &estdelay); 1748290000Sglebius } else if (!strcmp("offset", name)) { 1749290000Sglebius decodetime(value, &estoffset); 1750290000Sglebius } else if (!strcmp("jitter", name)) { 1751290000Sglebius if ((pvl == peervarlist || pvl == apeervarlist) 1752290000Sglebius && decodetime(value, &estjitter)) 1753290000Sglebius have_jitter = 1; 1754290000Sglebius } else if (!strcmp("rootdisp", name) || 1755290000Sglebius !strcmp("dispersion", name)) { 1756290000Sglebius decodetime(value, &estdisp); 1757290000Sglebius } else if (!strcmp("rec", name)) { 1758290000Sglebius decodets(value, &rec); 1759290000Sglebius } else if (!strcmp("srcport", name) || 1760290000Sglebius !strcmp("peerport", name)) { 1761290000Sglebius decodeuint(value, &srcport); 1762290000Sglebius } else if (!strcmp("reftime", name)) { 1763181834Sroberto if (!decodets(value, &reftime)) 1764181834Sroberto L_CLR(&reftime); 1765290000Sglebius } else { 1766290000Sglebius // fprintf(stderr, "UNRECOGNIZED name=%s ", name); 1767181834Sroberto } 1768181834Sroberto } 1769181834Sroberto 1770181834Sroberto /* 1771290000Sglebius * hmode gives the best guidance for the t column. If the response 1772290000Sglebius * did not include hmode we'll use the old decodeaddrtype() result. 1773181834Sroberto */ 1774290000Sglebius switch (hmode) { 1775181834Sroberto 1776290000Sglebius case MODE_BCLIENT: 1777290000Sglebius /* broadcastclient or multicastclient */ 1778290000Sglebius type = 'b'; 1779290000Sglebius break; 1780290000Sglebius 1781290000Sglebius case MODE_BROADCAST: 1782290000Sglebius /* broadcast or multicast server */ 1783290000Sglebius if (IS_MCAST(&srcadr)) 1784290000Sglebius type = 'M'; 1785290000Sglebius else 1786290000Sglebius type = 'B'; 1787290000Sglebius break; 1788290000Sglebius 1789290000Sglebius case MODE_CLIENT: 1790290000Sglebius if (ISREFCLOCKADR(&srcadr)) 1791290000Sglebius type = 'l'; /* local refclock*/ 1792290000Sglebius else if (SOCK_UNSPEC(&srcadr)) 1793290000Sglebius type = 'p'; /* pool */ 1794290000Sglebius else if (IS_MCAST(&srcadr)) 1795290000Sglebius type = 'a'; /* manycastclient */ 1796290000Sglebius else 1797290000Sglebius type = 'u'; /* unicast */ 1798290000Sglebius break; 1799290000Sglebius 1800290000Sglebius case MODE_ACTIVE: 1801290000Sglebius type = 's'; /* symmetric active */ 1802290000Sglebius break; /* configured */ 1803290000Sglebius 1804290000Sglebius case MODE_PASSIVE: 1805290000Sglebius type = 'S'; /* symmetric passive */ 1806290000Sglebius break; /* ephemeral */ 1807290000Sglebius } 1808290000Sglebius 1809181834Sroberto /* 1810181834Sroberto * Got everything, format the line 1811181834Sroberto */ 1812290000Sglebius poll_sec = 1 << min(ppoll, hpoll); 1813181834Sroberto if (pktversion > NTP_OLDVERSION) 1814181834Sroberto c = flash3[CTL_PEER_STATVAL(rstatus) & 0x7]; 1815181834Sroberto else 1816181834Sroberto c = flash2[CTL_PEER_STATVAL(rstatus) & 0x3]; 1817290000Sglebius if (numhosts > 1) { 1818290000Sglebius if ((pvl == peervarlist || pvl == apeervarlist) 1819290000Sglebius && have_dstadr) { 1820290000Sglebius serverlocal = nntohost_col(&dstadr, 1821290000Sglebius (size_t)min(LIB_BUFLENGTH - 1, maxhostlen), 1822290000Sglebius TRUE); 1823290000Sglebius } else { 1824290000Sglebius if (currenthostisnum) 1825290000Sglebius serverlocal = trunc_left(currenthost, 1826290000Sglebius maxhostlen); 1827290000Sglebius else 1828290000Sglebius serverlocal = currenthost; 1829290000Sglebius } 1830290000Sglebius fprintf(fp, "%-*s ", (int)maxhostlen, serverlocal); 1831290000Sglebius } 1832290000Sglebius if (AF_UNSPEC == af || AF(&srcadr) == af) { 1833290000Sglebius if (!have_srchost) 1834290000Sglebius strlcpy(clock_name, nntohost(&srcadr), 1835290000Sglebius sizeof(clock_name)); 1836290000Sglebius if (wideremote && 15 < strlen(clock_name)) 1837290000Sglebius fprintf(fp, "%c%s\n ", c, clock_name); 1838290000Sglebius else 1839290000Sglebius fprintf(fp, "%c%-15.15s ", c, clock_name); 1840290000Sglebius if (!have_da_rid) { 1841290000Sglebius drlen = 0; 1842290000Sglebius } else { 1843290000Sglebius drlen = strlen(dstadr_refid); 1844290000Sglebius makeascii(drlen, dstadr_refid, fp); 1845290000Sglebius } 1846290000Sglebius if (pvl == apeervarlist) { 1847290000Sglebius while (drlen++ < 9) 1848290000Sglebius fputc(' ', fp); 1849290000Sglebius fprintf(fp, "%-6d", associd); 1850290000Sglebius } else { 1851290000Sglebius while (drlen++ < 15) 1852290000Sglebius fputc(' ', fp); 1853290000Sglebius } 1854290000Sglebius fprintf(fp, 1855290000Sglebius " %2ld %c %4.4s %4.4s %3lo %7.7s %8.7s %7.7s\n", 1856290000Sglebius stratum, type, 1857290000Sglebius prettyinterval(whenbuf, sizeof(whenbuf), 1858290000Sglebius when(&ts, &rec, &reftime)), 1859290000Sglebius prettyinterval(pollbuf, sizeof(pollbuf), 1860290000Sglebius (int)poll_sec), 1861290000Sglebius reach, lfptoms(&estdelay, 3), 1862290000Sglebius lfptoms(&estoffset, 3), 1863290000Sglebius (have_jitter) 1864290000Sglebius ? lfptoms(&estjitter, 3) 1865290000Sglebius : lfptoms(&estdisp, 3)); 1866181834Sroberto return (1); 1867181834Sroberto } 1868181834Sroberto else 1869181834Sroberto return(1); 1870181834Sroberto} 1871181834Sroberto 1872181834Sroberto 1873181834Sroberto/* 1874181834Sroberto * dogetpeers - given an association ID, read and print the spreadsheet 1875181834Sroberto * peer variables. 1876181834Sroberto */ 1877181834Srobertostatic int 1878181834Srobertodogetpeers( 1879181834Sroberto struct varlist *pvl, 1880290000Sglebius associd_t associd, 1881181834Sroberto FILE *fp, 1882181834Sroberto int af 1883181834Sroberto ) 1884181834Sroberto{ 1885290000Sglebius const char *datap; 1886181834Sroberto int res; 1887293894Sglebius size_t dsize; 1888181834Sroberto u_short rstatus; 1889181834Sroberto 1890181834Sroberto#ifdef notdef 1891181834Sroberto res = doquerylist(pvl, CTL_OP_READVAR, associd, 0, &rstatus, 1892181834Sroberto &dsize, &datap); 1893181834Sroberto#else 1894181834Sroberto /* 1895181834Sroberto * Damn fuzzballs 1896181834Sroberto */ 1897290000Sglebius res = doquery(CTL_OP_READVAR, associd, 0, 0, NULL, &rstatus, 1898181834Sroberto &dsize, &datap); 1899181834Sroberto#endif 1900181834Sroberto 1901181834Sroberto if (res != 0) 1902181834Sroberto return 0; 1903181834Sroberto 1904181834Sroberto if (dsize == 0) { 1905181834Sroberto if (numhosts > 1) 1906290000Sglebius fprintf(stderr, "server=%s ", currenthost); 1907290000Sglebius fprintf(stderr, 1908290000Sglebius "***No information returned for association %u\n", 1909290000Sglebius associd); 1910181834Sroberto return 0; 1911181834Sroberto } 1912181834Sroberto 1913290000Sglebius return doprintpeers(pvl, associd, (int)rstatus, dsize, datap, 1914290000Sglebius fp, af); 1915181834Sroberto} 1916181834Sroberto 1917181834Sroberto 1918181834Sroberto/* 1919181834Sroberto * peers - print a peer spreadsheet 1920181834Sroberto */ 1921181834Srobertostatic void 1922181834Srobertodopeers( 1923181834Sroberto int showall, 1924181834Sroberto FILE *fp, 1925181834Sroberto int af 1926181834Sroberto ) 1927181834Sroberto{ 1928290000Sglebius u_int u; 1929290000Sglebius char fullname[LENHOSTNAME]; 1930290000Sglebius sockaddr_u netnum; 1931290000Sglebius const char * name_or_num; 1932290000Sglebius size_t sl; 1933181834Sroberto 1934181834Sroberto if (!dogetassoc(fp)) 1935181834Sroberto return; 1936181834Sroberto 1937290000Sglebius for (u = 0; u < numhosts; u++) { 1938290000Sglebius if (getnetnum(chosts[u].name, &netnum, fullname, af)) { 1939290000Sglebius name_or_num = nntohost(&netnum); 1940290000Sglebius sl = strlen(name_or_num); 1941290000Sglebius maxhostlen = max(maxhostlen, sl); 1942290000Sglebius } 1943181834Sroberto } 1944181834Sroberto if (numhosts > 1) 1945290000Sglebius fprintf(fp, "%-*.*s ", (int)maxhostlen, (int)maxhostlen, 1946290000Sglebius "server (local)"); 1947290000Sglebius fprintf(fp, 1948290000Sglebius " remote refid st t when poll reach delay offset jitter\n"); 1949181834Sroberto if (numhosts > 1) 1950290000Sglebius for (u = 0; u <= maxhostlen; u++) 1951290000Sglebius fprintf(fp, "="); 1952290000Sglebius fprintf(fp, 1953290000Sglebius "==============================================================================\n"); 1954181834Sroberto 1955290000Sglebius for (u = 0; u < numassoc; u++) { 1956181834Sroberto if (!showall && 1957290000Sglebius !(CTL_PEER_STATVAL(assoc_cache[u].status) 1958290000Sglebius & (CTL_PST_CONFIG|CTL_PST_REACH))) { 1959290000Sglebius if (debug) 1960290000Sglebius fprintf(stderr, "eliding [%d]\n", 1961290000Sglebius (int)assoc_cache[u].assid); 1962181834Sroberto continue; 1963290000Sglebius } 1964290000Sglebius if (!dogetpeers(peervarlist, (int)assoc_cache[u].assid, 1965290000Sglebius fp, af)) 1966181834Sroberto return; 1967290000Sglebius } 1968290000Sglebius return; 1969290000Sglebius} 1970290000Sglebius 1971290000Sglebius 1972290000Sglebius/* 1973290000Sglebius * doapeers - print a peer spreadsheet with assocIDs 1974290000Sglebius */ 1975290000Sglebiusstatic void 1976290000Sglebiusdoapeers( 1977290000Sglebius int showall, 1978290000Sglebius FILE *fp, 1979290000Sglebius int af 1980290000Sglebius ) 1981290000Sglebius{ 1982290000Sglebius u_int u; 1983290000Sglebius char fullname[LENHOSTNAME]; 1984290000Sglebius sockaddr_u netnum; 1985290000Sglebius const char * name_or_num; 1986290000Sglebius size_t sl; 1987290000Sglebius 1988290000Sglebius if (!dogetassoc(fp)) 1989290000Sglebius return; 1990290000Sglebius 1991290000Sglebius for (u = 0; u < numhosts; u++) { 1992290000Sglebius if (getnetnum(chosts[u].name, &netnum, fullname, af)) { 1993290000Sglebius name_or_num = nntohost(&netnum); 1994290000Sglebius sl = strlen(name_or_num); 1995290000Sglebius maxhostlen = max(maxhostlen, sl); 1996181834Sroberto } 1997181834Sroberto } 1998290000Sglebius if (numhosts > 1) 1999290000Sglebius fprintf(fp, "%-*.*s ", (int)maxhostlen, (int)maxhostlen, 2000290000Sglebius "server (local)"); 2001290000Sglebius fprintf(fp, 2002290000Sglebius " remote refid assid st t when poll reach delay offset jitter\n"); 2003290000Sglebius if (numhosts > 1) 2004290000Sglebius for (u = 0; u <= maxhostlen; u++) 2005290000Sglebius fprintf(fp, "="); 2006290000Sglebius fprintf(fp, 2007290000Sglebius "==============================================================================\n"); 2008290000Sglebius 2009290000Sglebius for (u = 0; u < numassoc; u++) { 2010290000Sglebius if (!showall && 2011290000Sglebius !(CTL_PEER_STATVAL(assoc_cache[u].status) 2012290000Sglebius & (CTL_PST_CONFIG|CTL_PST_REACH))) { 2013290000Sglebius if (debug) 2014290000Sglebius fprintf(stderr, "eliding [%d]\n", 2015290000Sglebius (int)assoc_cache[u].assid); 2016290000Sglebius continue; 2017290000Sglebius } 2018290000Sglebius if (!dogetpeers(apeervarlist, (int)assoc_cache[u].assid, 2019290000Sglebius fp, af)) 2020290000Sglebius return; 2021290000Sglebius } 2022181834Sroberto return; 2023181834Sroberto} 2024181834Sroberto 2025181834Sroberto 2026181834Sroberto/* 2027181834Sroberto * peers - print a peer spreadsheet 2028181834Sroberto */ 2029181834Sroberto/*ARGSUSED*/ 2030181834Srobertostatic void 2031181834Srobertopeers( 2032181834Sroberto struct parse *pcmd, 2033181834Sroberto FILE *fp 2034181834Sroberto ) 2035181834Sroberto{ 2036298770Sdelphij if (drefid == REFID_HASH) { 2037298770Sdelphij apeers(pcmd, fp); 2038298770Sdelphij } else { 2039298770Sdelphij int af = 0; 2040181834Sroberto 2041298770Sdelphij if (pcmd->nargs == 1) { 2042298770Sdelphij if (pcmd->argval->ival == 6) 2043298770Sdelphij af = AF_INET6; 2044298770Sdelphij else 2045298770Sdelphij af = AF_INET; 2046298770Sdelphij } 2047298770Sdelphij dopeers(0, fp, af); 2048181834Sroberto } 2049181834Sroberto} 2050181834Sroberto 2051181834Sroberto 2052181834Sroberto/* 2053290000Sglebius * apeers - print a peer spreadsheet, with assocIDs 2054290000Sglebius */ 2055290000Sglebius/*ARGSUSED*/ 2056290000Sglebiusstatic void 2057290000Sglebiusapeers( 2058290000Sglebius struct parse *pcmd, 2059290000Sglebius FILE *fp 2060290000Sglebius ) 2061290000Sglebius{ 2062290000Sglebius int af = 0; 2063290000Sglebius 2064290000Sglebius if (pcmd->nargs == 1) { 2065290000Sglebius if (pcmd->argval->ival == 6) 2066290000Sglebius af = AF_INET6; 2067290000Sglebius else 2068290000Sglebius af = AF_INET; 2069290000Sglebius } 2070290000Sglebius doapeers(0, fp, af); 2071290000Sglebius} 2072290000Sglebius 2073290000Sglebius 2074290000Sglebius/* 2075181834Sroberto * lpeers - print a peer spreadsheet including all fuzzball peers 2076181834Sroberto */ 2077181834Sroberto/*ARGSUSED*/ 2078181834Srobertostatic void 2079181834Srobertolpeers( 2080181834Sroberto struct parse *pcmd, 2081181834Sroberto FILE *fp 2082181834Sroberto ) 2083181834Sroberto{ 2084181834Sroberto int af = 0; 2085181834Sroberto 2086181834Sroberto if (pcmd->nargs == 1) { 2087181834Sroberto if (pcmd->argval->ival == 6) 2088181834Sroberto af = AF_INET6; 2089181834Sroberto else 2090181834Sroberto af = AF_INET; 2091181834Sroberto } 2092181834Sroberto dopeers(1, fp, af); 2093181834Sroberto} 2094181834Sroberto 2095181834Sroberto 2096181834Sroberto/* 2097181834Sroberto * opeers - print a peer spreadsheet 2098181834Sroberto */ 2099181834Srobertostatic void 2100181834Srobertodoopeers( 2101181834Sroberto int showall, 2102181834Sroberto FILE *fp, 2103181834Sroberto int af 2104181834Sroberto ) 2105181834Sroberto{ 2106290000Sglebius u_int i; 2107181834Sroberto char fullname[LENHOSTNAME]; 2108290000Sglebius sockaddr_u netnum; 2109181834Sroberto 2110181834Sroberto if (!dogetassoc(fp)) 2111181834Sroberto return; 2112181834Sroberto 2113181834Sroberto for (i = 0; i < numhosts; ++i) { 2114290000Sglebius if (getnetnum(chosts[i].name, &netnum, fullname, af)) 2115290000Sglebius if (strlen(fullname) > maxhostlen) 2116181834Sroberto maxhostlen = strlen(fullname); 2117181834Sroberto } 2118181834Sroberto if (numhosts > 1) 2119290000Sglebius fprintf(fp, "%-*.*s ", (int)maxhostlen, (int)maxhostlen, 2120290000Sglebius "server"); 2121290000Sglebius fprintf(fp, 2122290000Sglebius " remote local st t when poll reach delay offset disp\n"); 2123181834Sroberto if (numhosts > 1) 2124181834Sroberto for (i = 0; i <= maxhostlen; ++i) 2125290000Sglebius fprintf(fp, "="); 2126290000Sglebius fprintf(fp, 2127290000Sglebius "==============================================================================\n"); 2128181834Sroberto 2129181834Sroberto for (i = 0; i < numassoc; i++) { 2130181834Sroberto if (!showall && 2131290000Sglebius !(CTL_PEER_STATVAL(assoc_cache[i].status) & 2132290000Sglebius (CTL_PST_CONFIG | CTL_PST_REACH))) 2133181834Sroberto continue; 2134290000Sglebius if (!dogetpeers(opeervarlist, assoc_cache[i].assid, fp, af)) 2135181834Sroberto return; 2136181834Sroberto } 2137181834Sroberto return; 2138181834Sroberto} 2139181834Sroberto 2140181834Sroberto 2141181834Sroberto/* 2142181834Sroberto * opeers - print a peer spreadsheet the old way 2143181834Sroberto */ 2144181834Sroberto/*ARGSUSED*/ 2145181834Srobertostatic void 2146181834Srobertoopeers( 2147181834Sroberto struct parse *pcmd, 2148181834Sroberto FILE *fp 2149181834Sroberto ) 2150181834Sroberto{ 2151181834Sroberto int af = 0; 2152181834Sroberto 2153181834Sroberto if (pcmd->nargs == 1) { 2154181834Sroberto if (pcmd->argval->ival == 6) 2155181834Sroberto af = AF_INET6; 2156181834Sroberto else 2157181834Sroberto af = AF_INET; 2158181834Sroberto } 2159181834Sroberto doopeers(0, fp, af); 2160181834Sroberto} 2161181834Sroberto 2162181834Sroberto 2163181834Sroberto/* 2164181834Sroberto * lopeers - print a peer spreadsheet including all fuzzball peers 2165181834Sroberto */ 2166181834Sroberto/*ARGSUSED*/ 2167181834Srobertostatic void 2168181834Srobertolopeers( 2169181834Sroberto struct parse *pcmd, 2170181834Sroberto FILE *fp 2171181834Sroberto ) 2172181834Sroberto{ 2173181834Sroberto int af = 0; 2174181834Sroberto 2175181834Sroberto if (pcmd->nargs == 1) { 2176181834Sroberto if (pcmd->argval->ival == 6) 2177181834Sroberto af = AF_INET6; 2178181834Sroberto else 2179181834Sroberto af = AF_INET; 2180181834Sroberto } 2181181834Sroberto doopeers(1, fp, af); 2182181834Sroberto} 2183290000Sglebius 2184290000Sglebius 2185290000Sglebius/* 2186290000Sglebius * config - send a configuration command to a remote host 2187290000Sglebius */ 2188290000Sglebiusstatic void 2189290000Sglebiusconfig ( 2190290000Sglebius struct parse *pcmd, 2191290000Sglebius FILE *fp 2192290000Sglebius ) 2193290000Sglebius{ 2194290000Sglebius const char *cfgcmd; 2195290000Sglebius u_short rstatus; 2196293894Sglebius size_t rsize; 2197290000Sglebius const char *rdata; 2198290000Sglebius char *resp; 2199290000Sglebius int res; 2200290000Sglebius int col; 2201290000Sglebius int i; 2202290000Sglebius 2203290000Sglebius cfgcmd = pcmd->argval[0].string; 2204290000Sglebius 2205290000Sglebius if (debug > 2) 2206290000Sglebius fprintf(stderr, 2207290000Sglebius "In Config\n" 2208290000Sglebius "Keyword = %s\n" 2209290000Sglebius "Command = %s\n", pcmd->keyword, cfgcmd); 2210290000Sglebius 2211293894Sglebius res = doquery(CTL_OP_CONFIGURE, 0, 1, 2212293894Sglebius strlen(cfgcmd), cfgcmd, 2213290000Sglebius &rstatus, &rsize, &rdata); 2214290000Sglebius 2215290000Sglebius if (res != 0) 2216290000Sglebius return; 2217290000Sglebius 2218290000Sglebius if (rsize > 0 && '\n' == rdata[rsize - 1]) 2219290000Sglebius rsize--; 2220290000Sglebius 2221290000Sglebius resp = emalloc(rsize + 1); 2222290000Sglebius memcpy(resp, rdata, rsize); 2223290000Sglebius resp[rsize] = '\0'; 2224290000Sglebius 2225290000Sglebius col = -1; 2226290000Sglebius if (1 == sscanf(resp, "column %d syntax error", &col) 2227290000Sglebius && col >= 0 && (size_t)col <= strlen(cfgcmd) + 1) { 2228290000Sglebius if (interactive) { 2229290000Sglebius printf("______"); /* "ntpq> " */ 2230290000Sglebius printf("________"); /* ":config " */ 2231290000Sglebius } else 2232290000Sglebius printf("%s\n", cfgcmd); 2233290000Sglebius for (i = 1; i < col; i++) 2234290000Sglebius putchar('_'); 2235290000Sglebius printf("^\n"); 2236290000Sglebius } 2237290000Sglebius printf("%s\n", resp); 2238290000Sglebius free(resp); 2239290000Sglebius} 2240290000Sglebius 2241290000Sglebius 2242290000Sglebius/* 2243290000Sglebius * config_from_file - remotely configure an ntpd daemon using the 2244290000Sglebius * specified configuration file 2245290000Sglebius * SK: This function is a kludge at best and is full of bad design 2246290000Sglebius * bugs: 2247290000Sglebius * 1. ntpq uses UDP, which means that there is no guarantee of in-order, 2248290000Sglebius * error-free delivery. 2249290000Sglebius * 2. The maximum length of a packet is constrained, and as a result, the 2250290000Sglebius * maximum length of a line in a configuration file is constrained. 2251290000Sglebius * Longer lines will lead to unpredictable results. 2252290000Sglebius * 3. Since this function is sending a line at a time, we can't update 2253290000Sglebius * the control key through the configuration file (YUCK!!) 2254298770Sdelphij * 2255298770Sdelphij * Pearly: There are a few places where 'size_t' is cast to 'int' based 2256298770Sdelphij * on the assumption that 'int' can hold the size of the involved 2257298770Sdelphij * buffers without overflow. 2258290000Sglebius */ 2259290000Sglebiusstatic void 2260290000Sglebiusconfig_from_file ( 2261290000Sglebius struct parse *pcmd, 2262290000Sglebius FILE *fp 2263290000Sglebius ) 2264290000Sglebius{ 2265290000Sglebius u_short rstatus; 2266293894Sglebius size_t rsize; 2267290000Sglebius const char *rdata; 2268298770Sdelphij char * cp; 2269290000Sglebius int res; 2270290000Sglebius FILE *config_fd; 2271290000Sglebius char config_cmd[MAXLINE]; 2272290000Sglebius size_t config_len; 2273290000Sglebius int i; 2274290000Sglebius int retry_limit; 2275290000Sglebius 2276290000Sglebius if (debug > 2) 2277290000Sglebius fprintf(stderr, 2278290000Sglebius "In Config\n" 2279290000Sglebius "Keyword = %s\n" 2280290000Sglebius "Filename = %s\n", pcmd->keyword, 2281290000Sglebius pcmd->argval[0].string); 2282290000Sglebius 2283290000Sglebius config_fd = fopen(pcmd->argval[0].string, "r"); 2284290000Sglebius if (NULL == config_fd) { 2285290000Sglebius printf("ERROR!! Couldn't open file: %s\n", 2286290000Sglebius pcmd->argval[0].string); 2287290000Sglebius return; 2288290000Sglebius } 2289290000Sglebius 2290290000Sglebius printf("Sending configuration file, one line at a time.\n"); 2291290000Sglebius i = 0; 2292290000Sglebius while (fgets(config_cmd, MAXLINE, config_fd) != NULL) { 2293298770Sdelphij /* Eliminate comments first. */ 2294298770Sdelphij cp = strchr(config_cmd, '#'); 2295298770Sdelphij config_len = (NULL != cp) 2296298770Sdelphij ? (size_t)(cp - config_cmd) 2297298770Sdelphij : strlen(config_cmd); 2298298770Sdelphij 2299298770Sdelphij /* [Bug 3015] make sure there's no trailing whitespace; 2300298770Sdelphij * the fix for [Bug 2853] on the server side forbids 2301298770Sdelphij * those. And don't transmit empty lines, as this would 2302298770Sdelphij * just be waste. 2303298770Sdelphij */ 2304298770Sdelphij while (config_len != 0 && 2305298770Sdelphij (u_char)config_cmd[config_len-1] <= ' ') 2306298770Sdelphij --config_len; 2307298770Sdelphij config_cmd[config_len] = '\0'; 2308298770Sdelphij 2309290000Sglebius ++i; 2310298770Sdelphij if (0 == config_len) 2311298770Sdelphij continue; 2312298770Sdelphij 2313290000Sglebius retry_limit = 2; 2314290000Sglebius do 2315290000Sglebius res = doquery(CTL_OP_CONFIGURE, 0, 1, 2316298770Sdelphij config_len, config_cmd, 2317290000Sglebius &rstatus, &rsize, &rdata); 2318290000Sglebius while (res != 0 && retry_limit--); 2319290000Sglebius if (res != 0) { 2320298770Sdelphij printf("Line No: %d query failed: %.*s\n" 2321298770Sdelphij "Subsequent lines not sent.\n", 2322298770Sdelphij i, (int)config_len, config_cmd); 2323290000Sglebius fclose(config_fd); 2324290000Sglebius return; 2325290000Sglebius } 2326290000Sglebius 2327298770Sdelphij /* Right-strip the result code string, then output the 2328298770Sdelphij * last line executed, with result code. */ 2329298770Sdelphij while (rsize != 0 && (u_char)rdata[rsize - 1] <= ' ') 2330298770Sdelphij --rsize; 2331298770Sdelphij printf("Line No: %d %.*s: %.*s\n", i, 2332298770Sdelphij (int)rsize, rdata, 2333298770Sdelphij (int)config_len, config_cmd); 2334290000Sglebius } 2335290000Sglebius printf("Done sending file\n"); 2336290000Sglebius fclose(config_fd); 2337290000Sglebius} 2338290000Sglebius 2339290000Sglebius 2340290000Sglebiusstatic int 2341290000Sglebiusfetch_nonce( 2342290000Sglebius char * nonce, 2343290000Sglebius size_t cb_nonce 2344290000Sglebius ) 2345290000Sglebius{ 2346290000Sglebius const char nonce_eq[] = "nonce="; 2347290000Sglebius int qres; 2348290000Sglebius u_short rstatus; 2349293894Sglebius size_t rsize; 2350290000Sglebius const char * rdata; 2351293894Sglebius size_t chars; 2352290000Sglebius 2353290000Sglebius /* 2354290000Sglebius * Retrieve a nonce specific to this client to demonstrate to 2355290000Sglebius * ntpd that we're capable of receiving responses to our source 2356290000Sglebius * IP address, and thereby unlikely to be forging the source. 2357290000Sglebius */ 2358290000Sglebius qres = doquery(CTL_OP_REQ_NONCE, 0, 0, 0, NULL, &rstatus, 2359290000Sglebius &rsize, &rdata); 2360290000Sglebius if (qres) { 2361290000Sglebius fprintf(stderr, "nonce request failed\n"); 2362290000Sglebius return FALSE; 2363290000Sglebius } 2364290000Sglebius 2365290000Sglebius if ((size_t)rsize <= sizeof(nonce_eq) - 1 || 2366290000Sglebius strncmp(rdata, nonce_eq, sizeof(nonce_eq) - 1)) { 2367290000Sglebius fprintf(stderr, "unexpected nonce response format: %.*s\n", 2368293894Sglebius (int)rsize, rdata); /* cast is wobbly */ 2369290000Sglebius return FALSE; 2370290000Sglebius } 2371290000Sglebius chars = rsize - (sizeof(nonce_eq) - 1); 2372290000Sglebius if (chars >= (int)cb_nonce) 2373290000Sglebius return FALSE; 2374290000Sglebius memcpy(nonce, rdata + sizeof(nonce_eq) - 1, chars); 2375290000Sglebius nonce[chars] = '\0'; 2376290000Sglebius while (chars > 0 && 2377290000Sglebius ('\r' == nonce[chars - 1] || '\n' == nonce[chars - 1])) { 2378290000Sglebius chars--; 2379290000Sglebius nonce[chars] = '\0'; 2380290000Sglebius } 2381290000Sglebius 2382290000Sglebius return TRUE; 2383290000Sglebius} 2384290000Sglebius 2385290000Sglebius 2386290000Sglebius/* 2387290000Sglebius * add_mru Add and entry to mru list, hash table, and allocate 2388290000Sglebius * and return a replacement. 2389290000Sglebius * This is a helper for collect_mru_list(). 2390290000Sglebius */ 2391290000Sglebiusstatic mru * 2392290000Sglebiusadd_mru( 2393290000Sglebius mru *add 2394290000Sglebius ) 2395290000Sglebius{ 2396290000Sglebius u_short hash; 2397290000Sglebius mru *mon; 2398290000Sglebius mru *unlinked; 2399290000Sglebius 2400290000Sglebius 2401290000Sglebius hash = NTP_HASH_ADDR(&add->addr); 2402290000Sglebius /* see if we have it among previously received entries */ 2403290000Sglebius for (mon = hash_table[hash]; mon != NULL; mon = mon->hlink) 2404290000Sglebius if (SOCK_EQ(&mon->addr, &add->addr)) 2405290000Sglebius break; 2406290000Sglebius if (mon != NULL) { 2407290000Sglebius if (!L_ISGEQ(&add->first, &mon->first)) { 2408290000Sglebius fprintf(stderr, 2409290000Sglebius "add_mru duplicate %s new first ts %08x.%08x precedes prior %08x.%08x\n", 2410290000Sglebius sptoa(&add->addr), add->last.l_ui, 2411290000Sglebius add->last.l_uf, mon->last.l_ui, 2412290000Sglebius mon->last.l_uf); 2413290000Sglebius exit(1); 2414290000Sglebius } 2415290000Sglebius UNLINK_DLIST(mon, mlink); 2416290000Sglebius UNLINK_SLIST(unlinked, hash_table[hash], mon, hlink, mru); 2417290000Sglebius INSIST(unlinked == mon); 2418290000Sglebius mru_dupes++; 2419290000Sglebius TRACE(2, ("(updated from %08x.%08x) ", mon->last.l_ui, 2420290000Sglebius mon->last.l_uf)); 2421290000Sglebius } 2422290000Sglebius LINK_DLIST(mru_list, add, mlink); 2423290000Sglebius LINK_SLIST(hash_table[hash], add, hlink); 2424290000Sglebius TRACE(2, ("add_mru %08x.%08x c %d m %d v %d rest %x first %08x.%08x %s\n", 2425290000Sglebius add->last.l_ui, add->last.l_uf, add->count, 2426290000Sglebius (int)add->mode, (int)add->ver, (u_int)add->rs, 2427290000Sglebius add->first.l_ui, add->first.l_uf, sptoa(&add->addr))); 2428290000Sglebius /* if we didn't update an existing entry, alloc replacement */ 2429290000Sglebius if (NULL == mon) { 2430290000Sglebius mon = emalloc(sizeof(*mon)); 2431290000Sglebius mru_count++; 2432290000Sglebius } 2433290000Sglebius ZERO(*mon); 2434290000Sglebius 2435290000Sglebius return mon; 2436290000Sglebius} 2437290000Sglebius 2438290000Sglebius 2439290000Sglebius/* MGOT macro is specific to collect_mru_list() */ 2440290000Sglebius#define MGOT(bit) \ 2441290000Sglebius do { \ 2442290000Sglebius got |= (bit); \ 2443290000Sglebius if (MRU_GOT_ALL == got) { \ 2444290000Sglebius got = 0; \ 2445290000Sglebius mon = add_mru(mon); \ 2446290000Sglebius ci++; \ 2447290000Sglebius } \ 2448290000Sglebius } while (0) 2449290000Sglebius 2450290000Sglebius 2451293894Sglebiusint 2452290000Sglebiusmrulist_ctrl_c_hook(void) 2453290000Sglebius{ 2454290000Sglebius mrulist_interrupted = TRUE; 2455293894Sglebius return TRUE; 2456290000Sglebius} 2457290000Sglebius 2458290000Sglebius 2459290000Sglebiusstatic int 2460290000Sglebiuscollect_mru_list( 2461290000Sglebius const char * parms, 2462290000Sglebius l_fp * pnow 2463290000Sglebius ) 2464290000Sglebius{ 2465290000Sglebius const u_int sleep_msecs = 5; 2466290000Sglebius static int ntpd_row_limit = MRU_ROW_LIMIT; 2467290000Sglebius int c_mru_l_rc; /* this function's return code */ 2468290000Sglebius u_char got; /* MRU_GOT_* bits */ 2469290000Sglebius time_t next_report; 2470290000Sglebius size_t cb; 2471290000Sglebius mru *mon; 2472290000Sglebius mru *head; 2473290000Sglebius mru *recent; 2474290000Sglebius int list_complete; 2475290000Sglebius char nonce[128]; 2476290000Sglebius char buf[128]; 2477290000Sglebius char req_buf[CTL_MAX_DATA_LEN]; 2478290000Sglebius char *req; 2479290000Sglebius char *req_end; 2480293894Sglebius size_t chars; 2481290000Sglebius int qres; 2482290000Sglebius u_short rstatus; 2483293894Sglebius size_t rsize; 2484290000Sglebius const char *rdata; 2485290000Sglebius int limit; 2486290000Sglebius int frags; 2487290000Sglebius int cap_frags; 2488290000Sglebius char *tag; 2489290000Sglebius char *val; 2490290000Sglebius int si; /* server index in response */ 2491290000Sglebius int ci; /* client (our) index for validation */ 2492290000Sglebius int ri; /* request index (.# suffix) */ 2493290000Sglebius int mv; 2494290000Sglebius l_fp newest; 2495290000Sglebius l_fp last_older; 2496290000Sglebius sockaddr_u addr_older; 2497290000Sglebius int have_now; 2498290000Sglebius int have_addr_older; 2499290000Sglebius int have_last_older; 2500290000Sglebius u_int restarted_count; 2501290000Sglebius u_int nonce_uses; 2502290000Sglebius u_short hash; 2503290000Sglebius mru *unlinked; 2504290000Sglebius 2505290000Sglebius if (!fetch_nonce(nonce, sizeof(nonce))) 2506290000Sglebius return FALSE; 2507290000Sglebius 2508290000Sglebius nonce_uses = 0; 2509290000Sglebius restarted_count = 0; 2510290000Sglebius mru_count = 0; 2511290000Sglebius INIT_DLIST(mru_list, mlink); 2512290000Sglebius cb = NTP_HASH_SIZE * sizeof(*hash_table); 2513290000Sglebius INSIST(NULL == hash_table); 2514290000Sglebius hash_table = emalloc_zero(cb); 2515290000Sglebius 2516290000Sglebius c_mru_l_rc = FALSE; 2517290000Sglebius list_complete = FALSE; 2518290000Sglebius have_now = FALSE; 2519290000Sglebius cap_frags = TRUE; 2520290000Sglebius got = 0; 2521290000Sglebius ri = 0; 2522290000Sglebius cb = sizeof(*mon); 2523290000Sglebius mon = emalloc_zero(cb); 2524290000Sglebius ZERO(*pnow); 2525290000Sglebius ZERO(last_older); 2526290000Sglebius next_report = time(NULL) + MRU_REPORT_SECS; 2527290000Sglebius 2528290000Sglebius limit = min(3 * MAXFRAGS, ntpd_row_limit); 2529290000Sglebius frags = MAXFRAGS; 2530290000Sglebius snprintf(req_buf, sizeof(req_buf), "nonce=%s, frags=%d%s", 2531290000Sglebius nonce, frags, parms); 2532290000Sglebius nonce_uses++; 2533290000Sglebius 2534290000Sglebius while (TRUE) { 2535290000Sglebius if (debug) 2536290000Sglebius fprintf(stderr, "READ_MRU parms: %s\n", req_buf); 2537290000Sglebius 2538293894Sglebius qres = doqueryex(CTL_OP_READ_MRU, 0, 0, 2539293894Sglebius strlen(req_buf), req_buf, 2540293894Sglebius &rstatus, &rsize, &rdata, TRUE); 2541290000Sglebius 2542290000Sglebius if (CERR_UNKNOWNVAR == qres && ri > 0) { 2543290000Sglebius /* 2544290000Sglebius * None of the supplied prior entries match, so 2545290000Sglebius * toss them from our list and try again. 2546290000Sglebius */ 2547290000Sglebius if (debug) 2548290000Sglebius fprintf(stderr, 2549290000Sglebius "no overlap between %d prior entries and server MRU list\n", 2550290000Sglebius ri); 2551290000Sglebius while (ri--) { 2552290000Sglebius recent = HEAD_DLIST(mru_list, mlink); 2553290000Sglebius INSIST(recent != NULL); 2554290000Sglebius if (debug) 2555290000Sglebius fprintf(stderr, 2556290000Sglebius "tossing prior entry %s to resync\n", 2557290000Sglebius sptoa(&recent->addr)); 2558290000Sglebius UNLINK_DLIST(recent, mlink); 2559290000Sglebius hash = NTP_HASH_ADDR(&recent->addr); 2560290000Sglebius UNLINK_SLIST(unlinked, hash_table[hash], 2561290000Sglebius recent, hlink, mru); 2562290000Sglebius INSIST(unlinked == recent); 2563290000Sglebius free(recent); 2564290000Sglebius mru_count--; 2565290000Sglebius } 2566290000Sglebius if (NULL == HEAD_DLIST(mru_list, mlink)) { 2567290000Sglebius restarted_count++; 2568290000Sglebius if (restarted_count > 8) { 2569290000Sglebius fprintf(stderr, 2570290000Sglebius "Giving up after 8 restarts from the beginning.\n" 2571290000Sglebius "With high-traffic NTP servers, this can occur if the\n" 2572290000Sglebius "MRU list is limited to less than about 16 seconds' of\n" 2573290000Sglebius "entries. See the 'mru' ntp.conf directive to adjust.\n"); 2574290000Sglebius goto cleanup_return; 2575290000Sglebius } 2576290000Sglebius if (debug) 2577290000Sglebius fprintf(stderr, 2578290000Sglebius "---> Restarting from the beginning, retry #%u\n", 2579290000Sglebius restarted_count); 2580290000Sglebius } 2581290000Sglebius } else if (CERR_UNKNOWNVAR == qres) { 2582290000Sglebius fprintf(stderr, 2583290000Sglebius "CERR_UNKNOWNVAR from ntpd but no priors given.\n"); 2584290000Sglebius goto cleanup_return; 2585290000Sglebius } else if (CERR_BADVALUE == qres) { 2586290000Sglebius if (cap_frags) { 2587290000Sglebius cap_frags = FALSE; 2588290000Sglebius if (debug) 2589290000Sglebius fprintf(stderr, 2590290000Sglebius "Reverted to row limit from fragments limit.\n"); 2591290000Sglebius } else { 2592290000Sglebius /* ntpd has lower cap on row limit */ 2593290000Sglebius ntpd_row_limit--; 2594290000Sglebius limit = min(limit, ntpd_row_limit); 2595290000Sglebius if (debug) 2596290000Sglebius fprintf(stderr, 2597290000Sglebius "Row limit reduced to %d following CERR_BADVALUE.\n", 2598290000Sglebius limit); 2599290000Sglebius } 2600290000Sglebius } else if (ERR_INCOMPLETE == qres || 2601290000Sglebius ERR_TIMEOUT == qres) { 2602290000Sglebius /* 2603290000Sglebius * Reduce the number of rows/frags requested by 2604290000Sglebius * half to recover from lost response fragments. 2605290000Sglebius */ 2606290000Sglebius if (cap_frags) { 2607290000Sglebius frags = max(2, frags / 2); 2608290000Sglebius if (debug) 2609290000Sglebius fprintf(stderr, 2610290000Sglebius "Frag limit reduced to %d following incomplete response.\n", 2611290000Sglebius frags); 2612290000Sglebius } else { 2613290000Sglebius limit = max(2, limit / 2); 2614290000Sglebius if (debug) 2615290000Sglebius fprintf(stderr, 2616290000Sglebius "Row limit reduced to %d following incomplete response.\n", 2617290000Sglebius limit); 2618290000Sglebius } 2619290000Sglebius } else if (qres) { 2620290000Sglebius show_error_msg(qres, 0); 2621290000Sglebius goto cleanup_return; 2622290000Sglebius } 2623290000Sglebius /* 2624290000Sglebius * This is a cheap cop-out implementation of rawmode 2625290000Sglebius * output for mrulist. A better approach would be to 2626290000Sglebius * dump similar output after the list is collected by 2627290000Sglebius * ntpq with a continuous sequence of indexes. This 2628290000Sglebius * cheap approach has indexes resetting to zero for 2629290000Sglebius * each query/response, and duplicates are not 2630290000Sglebius * coalesced. 2631290000Sglebius */ 2632290000Sglebius if (!qres && rawmode) 2633290000Sglebius printvars(rsize, rdata, rstatus, TYPE_SYS, 1, stdout); 2634290000Sglebius ci = 0; 2635290000Sglebius have_addr_older = FALSE; 2636290000Sglebius have_last_older = FALSE; 2637290000Sglebius while (!qres && nextvar(&rsize, &rdata, &tag, &val)) { 2638290000Sglebius if (debug > 1) 2639290000Sglebius fprintf(stderr, "nextvar gave: %s = %s\n", 2640290000Sglebius tag, val); 2641290000Sglebius switch(tag[0]) { 2642290000Sglebius 2643290000Sglebius case 'a': 2644290000Sglebius if (!strcmp(tag, "addr.older")) { 2645290000Sglebius if (!have_last_older) { 2646290000Sglebius fprintf(stderr, 2647290000Sglebius "addr.older %s before last.older\n", 2648290000Sglebius val); 2649290000Sglebius goto cleanup_return; 2650290000Sglebius } 2651290000Sglebius if (!decodenetnum(val, &addr_older)) { 2652290000Sglebius fprintf(stderr, 2653290000Sglebius "addr.older %s garbled\n", 2654290000Sglebius val); 2655290000Sglebius goto cleanup_return; 2656290000Sglebius } 2657290000Sglebius hash = NTP_HASH_ADDR(&addr_older); 2658290000Sglebius for (recent = hash_table[hash]; 2659290000Sglebius recent != NULL; 2660290000Sglebius recent = recent->hlink) 2661290000Sglebius if (ADDR_PORT_EQ( 2662290000Sglebius &addr_older, 2663290000Sglebius &recent->addr)) 2664290000Sglebius break; 2665290000Sglebius if (NULL == recent) { 2666290000Sglebius fprintf(stderr, 2667290000Sglebius "addr.older %s not in hash table\n", 2668290000Sglebius val); 2669290000Sglebius goto cleanup_return; 2670290000Sglebius } 2671290000Sglebius if (!L_ISEQU(&last_older, 2672290000Sglebius &recent->last)) { 2673290000Sglebius fprintf(stderr, 2674290000Sglebius "last.older %08x.%08x mismatches %08x.%08x expected.\n", 2675290000Sglebius last_older.l_ui, 2676290000Sglebius last_older.l_uf, 2677290000Sglebius recent->last.l_ui, 2678290000Sglebius recent->last.l_uf); 2679290000Sglebius goto cleanup_return; 2680290000Sglebius } 2681290000Sglebius have_addr_older = TRUE; 2682290000Sglebius } else if (1 != sscanf(tag, "addr.%d", &si) 2683290000Sglebius || si != ci) 2684290000Sglebius goto nomatch; 2685290000Sglebius else if (decodenetnum(val, &mon->addr)) 2686290000Sglebius MGOT(MRU_GOT_ADDR); 2687290000Sglebius break; 2688290000Sglebius 2689290000Sglebius case 'l': 2690290000Sglebius if (!strcmp(tag, "last.older")) { 2691290000Sglebius if ('0' != val[0] || 2692290000Sglebius 'x' != val[1] || 2693290000Sglebius !hextolfp(val + 2, &last_older)) { 2694290000Sglebius fprintf(stderr, 2695290000Sglebius "last.older %s garbled\n", 2696290000Sglebius val); 2697290000Sglebius goto cleanup_return; 2698290000Sglebius } 2699290000Sglebius have_last_older = TRUE; 2700290000Sglebius } else if (!strcmp(tag, "last.newest")) { 2701290000Sglebius if (0 != got) { 2702290000Sglebius fprintf(stderr, 2703290000Sglebius "last.newest %s before complete row, got = 0x%x\n", 2704290000Sglebius val, (u_int)got); 2705290000Sglebius goto cleanup_return; 2706290000Sglebius } 2707290000Sglebius if (!have_now) { 2708290000Sglebius fprintf(stderr, 2709290000Sglebius "last.newest %s before now=\n", 2710290000Sglebius val); 2711290000Sglebius goto cleanup_return; 2712290000Sglebius } 2713290000Sglebius head = HEAD_DLIST(mru_list, mlink); 2714290000Sglebius if (NULL != head) { 2715290000Sglebius if ('0' != val[0] || 2716290000Sglebius 'x' != val[1] || 2717290000Sglebius !hextolfp(val + 2, &newest) || 2718290000Sglebius !L_ISEQU(&newest, 2719290000Sglebius &head->last)) { 2720290000Sglebius fprintf(stderr, 2721290000Sglebius "last.newest %s mismatches %08x.%08x", 2722290000Sglebius val, 2723290000Sglebius head->last.l_ui, 2724290000Sglebius head->last.l_uf); 2725290000Sglebius goto cleanup_return; 2726290000Sglebius } 2727290000Sglebius } 2728290000Sglebius list_complete = TRUE; 2729290000Sglebius } else if (1 != sscanf(tag, "last.%d", &si) || 2730290000Sglebius si != ci || '0' != val[0] || 2731290000Sglebius 'x' != val[1] || 2732290000Sglebius !hextolfp(val + 2, &mon->last)) { 2733290000Sglebius goto nomatch; 2734290000Sglebius } else { 2735290000Sglebius MGOT(MRU_GOT_LAST); 2736290000Sglebius /* 2737290000Sglebius * allow interrupted retrieval, 2738290000Sglebius * using most recent retrieved 2739290000Sglebius * entry's last seen timestamp 2740290000Sglebius * as the end of operation. 2741290000Sglebius */ 2742290000Sglebius *pnow = mon->last; 2743290000Sglebius } 2744290000Sglebius break; 2745290000Sglebius 2746290000Sglebius case 'f': 2747290000Sglebius if (1 != sscanf(tag, "first.%d", &si) || 2748290000Sglebius si != ci || '0' != val[0] || 2749290000Sglebius 'x' != val[1] || 2750290000Sglebius !hextolfp(val + 2, &mon->first)) 2751290000Sglebius goto nomatch; 2752290000Sglebius MGOT(MRU_GOT_FIRST); 2753290000Sglebius break; 2754290000Sglebius 2755290000Sglebius case 'n': 2756290000Sglebius if (!strcmp(tag, "nonce")) { 2757290000Sglebius strlcpy(nonce, val, sizeof(nonce)); 2758290000Sglebius nonce_uses = 0; 2759290000Sglebius break; /* case */ 2760290000Sglebius } else if (strcmp(tag, "now") || 2761290000Sglebius '0' != val[0] || 2762290000Sglebius 'x' != val[1] || 2763290000Sglebius !hextolfp(val + 2, pnow)) 2764290000Sglebius goto nomatch; 2765290000Sglebius have_now = TRUE; 2766290000Sglebius break; 2767290000Sglebius 2768290000Sglebius case 'c': 2769290000Sglebius if (1 != sscanf(tag, "ct.%d", &si) || 2770290000Sglebius si != ci || 2771290000Sglebius 1 != sscanf(val, "%d", &mon->count) 2772290000Sglebius || mon->count < 1) 2773290000Sglebius goto nomatch; 2774290000Sglebius MGOT(MRU_GOT_COUNT); 2775290000Sglebius break; 2776290000Sglebius 2777290000Sglebius case 'm': 2778290000Sglebius if (1 != sscanf(tag, "mv.%d", &si) || 2779290000Sglebius si != ci || 2780290000Sglebius 1 != sscanf(val, "%d", &mv)) 2781290000Sglebius goto nomatch; 2782290000Sglebius mon->mode = PKT_MODE(mv); 2783290000Sglebius mon->ver = PKT_VERSION(mv); 2784290000Sglebius MGOT(MRU_GOT_MV); 2785290000Sglebius break; 2786290000Sglebius 2787290000Sglebius case 'r': 2788290000Sglebius if (1 != sscanf(tag, "rs.%d", &si) || 2789290000Sglebius si != ci || 2790290000Sglebius 1 != sscanf(val, "0x%hx", &mon->rs)) 2791290000Sglebius goto nomatch; 2792290000Sglebius MGOT(MRU_GOT_RS); 2793290000Sglebius break; 2794290000Sglebius 2795290000Sglebius default: 2796290000Sglebius nomatch: 2797290000Sglebius /* empty stmt */ ; 2798290000Sglebius /* ignore unknown tags */ 2799290000Sglebius } 2800290000Sglebius } 2801290000Sglebius if (have_now) 2802290000Sglebius list_complete = TRUE; 2803290000Sglebius if (list_complete) { 2804290000Sglebius INSIST(0 == ri || have_addr_older); 2805290000Sglebius } 2806290000Sglebius if (mrulist_interrupted) { 2807290000Sglebius printf("mrulist retrieval interrupted by operator.\n" 2808290000Sglebius "Displaying partial client list.\n"); 2809290000Sglebius fflush(stdout); 2810290000Sglebius } 2811290000Sglebius if (list_complete || mrulist_interrupted) { 2812290000Sglebius fprintf(stderr, 2813290000Sglebius "\rRetrieved %u unique MRU entries and %u updates.\n", 2814290000Sglebius mru_count, mru_dupes); 2815290000Sglebius fflush(stderr); 2816290000Sglebius break; 2817290000Sglebius } 2818290000Sglebius if (time(NULL) >= next_report) { 2819290000Sglebius next_report += MRU_REPORT_SECS; 2820290000Sglebius fprintf(stderr, "\r%u (%u updates) ", mru_count, 2821290000Sglebius mru_dupes); 2822290000Sglebius fflush(stderr); 2823290000Sglebius } 2824290000Sglebius 2825290000Sglebius /* 2826290000Sglebius * Snooze for a bit between queries to let ntpd catch 2827290000Sglebius * up with other duties. 2828290000Sglebius */ 2829290000Sglebius#ifdef SYS_WINNT 2830290000Sglebius Sleep(sleep_msecs); 2831290000Sglebius#elif !defined(HAVE_NANOSLEEP) 2832290000Sglebius sleep((sleep_msecs / 1000) + 1); 2833290000Sglebius#else 2834290000Sglebius { 2835290000Sglebius struct timespec interv = { 0, 2836290000Sglebius 1000 * sleep_msecs }; 2837290000Sglebius nanosleep(&interv, NULL); 2838290000Sglebius } 2839290000Sglebius#endif 2840290000Sglebius /* 2841290000Sglebius * If there were no errors, increase the number of rows 2842290000Sglebius * to a maximum of 3 * MAXFRAGS (the most packets ntpq 2843290000Sglebius * can handle in one response), on the assumption that 2844290000Sglebius * no less than 3 rows fit in each packet, capped at 2845290000Sglebius * our best guess at the server's row limit. 2846290000Sglebius */ 2847290000Sglebius if (!qres) { 2848290000Sglebius if (cap_frags) { 2849290000Sglebius frags = min(MAXFRAGS, frags + 1); 2850290000Sglebius } else { 2851290000Sglebius limit = min3(3 * MAXFRAGS, 2852290000Sglebius ntpd_row_limit, 2853290000Sglebius max(limit + 1, 2854290000Sglebius limit * 33 / 32)); 2855290000Sglebius } 2856290000Sglebius } 2857290000Sglebius /* 2858290000Sglebius * prepare next query with as many address and last-seen 2859290000Sglebius * timestamps as will fit in a single packet. 2860290000Sglebius */ 2861290000Sglebius req = req_buf; 2862290000Sglebius req_end = req_buf + sizeof(req_buf); 2863290000Sglebius#define REQ_ROOM (req_end - req) 2864290000Sglebius snprintf(req, REQ_ROOM, "nonce=%s, %s=%d%s", nonce, 2865290000Sglebius (cap_frags) 2866290000Sglebius ? "frags" 2867290000Sglebius : "limit", 2868290000Sglebius (cap_frags) 2869290000Sglebius ? frags 2870290000Sglebius : limit, 2871290000Sglebius parms); 2872290000Sglebius req += strlen(req); 2873290000Sglebius nonce_uses++; 2874290000Sglebius if (nonce_uses >= 4) { 2875290000Sglebius if (!fetch_nonce(nonce, sizeof(nonce))) 2876290000Sglebius goto cleanup_return; 2877290000Sglebius nonce_uses = 0; 2878290000Sglebius } 2879290000Sglebius 2880290000Sglebius 2881290000Sglebius for (ri = 0, recent = HEAD_DLIST(mru_list, mlink); 2882290000Sglebius recent != NULL; 2883290000Sglebius ri++, recent = NEXT_DLIST(mru_list, recent, mlink)) { 2884290000Sglebius 2885290000Sglebius snprintf(buf, sizeof(buf), 2886290000Sglebius ", addr.%d=%s, last.%d=0x%08x.%08x", 2887290000Sglebius ri, sptoa(&recent->addr), ri, 2888290000Sglebius recent->last.l_ui, recent->last.l_uf); 2889290000Sglebius chars = strlen(buf); 2890294904Sdelphij if ((size_t)REQ_ROOM <= chars) 2891290000Sglebius break; 2892290000Sglebius memcpy(req, buf, chars + 1); 2893290000Sglebius req += chars; 2894290000Sglebius } 2895290000Sglebius } 2896290000Sglebius 2897290000Sglebius c_mru_l_rc = TRUE; 2898290000Sglebius goto retain_hash_table; 2899290000Sglebius 2900290000Sglebiuscleanup_return: 2901290000Sglebius free(hash_table); 2902290000Sglebius hash_table = NULL; 2903290000Sglebius 2904290000Sglebiusretain_hash_table: 2905290000Sglebius if (mon != NULL) 2906290000Sglebius free(mon); 2907290000Sglebius 2908290000Sglebius return c_mru_l_rc; 2909290000Sglebius} 2910290000Sglebius 2911290000Sglebius 2912290000Sglebius/* 2913290000Sglebius * qcmp_mru_addr - sort MRU entries by remote address. 2914290000Sglebius * 2915290000Sglebius * All IPv4 addresses sort before any IPv6, addresses are sorted by 2916290000Sglebius * value within address family. 2917290000Sglebius */ 2918290000Sglebiusstatic int 2919290000Sglebiusqcmp_mru_addr( 2920290000Sglebius const void *v1, 2921290000Sglebius const void *v2 2922290000Sglebius ) 2923290000Sglebius{ 2924290000Sglebius const mru * const * ppm1 = v1; 2925290000Sglebius const mru * const * ppm2 = v2; 2926290000Sglebius const mru * pm1; 2927290000Sglebius const mru * pm2; 2928290000Sglebius u_short af1; 2929290000Sglebius u_short af2; 2930290000Sglebius size_t cmplen; 2931290000Sglebius size_t addr_off; 2932290000Sglebius 2933290000Sglebius pm1 = *ppm1; 2934290000Sglebius pm2 = *ppm2; 2935290000Sglebius 2936290000Sglebius af1 = AF(&pm1->addr); 2937290000Sglebius af2 = AF(&pm2->addr); 2938290000Sglebius 2939290000Sglebius if (af1 != af2) 2940290000Sglebius return (AF_INET == af1) 2941290000Sglebius ? -1 2942290000Sglebius : 1; 2943290000Sglebius 2944290000Sglebius cmplen = SIZEOF_INADDR(af1); 2945290000Sglebius addr_off = (AF_INET == af1) 2946290000Sglebius ? offsetof(struct sockaddr_in, sin_addr) 2947290000Sglebius : offsetof(struct sockaddr_in6, sin6_addr); 2948290000Sglebius 2949290000Sglebius return memcmp((const char *)&pm1->addr + addr_off, 2950290000Sglebius (const char *)&pm2->addr + addr_off, 2951290000Sglebius cmplen); 2952290000Sglebius} 2953290000Sglebius 2954290000Sglebius 2955290000Sglebiusstatic int 2956290000Sglebiusqcmp_mru_r_addr( 2957290000Sglebius const void *v1, 2958290000Sglebius const void *v2 2959290000Sglebius ) 2960290000Sglebius{ 2961290000Sglebius return -qcmp_mru_addr(v1, v2); 2962290000Sglebius} 2963290000Sglebius 2964290000Sglebius 2965290000Sglebius/* 2966290000Sglebius * qcmp_mru_count - sort MRU entries by times seen (hit count). 2967290000Sglebius */ 2968290000Sglebiusstatic int 2969290000Sglebiusqcmp_mru_count( 2970290000Sglebius const void *v1, 2971290000Sglebius const void *v2 2972290000Sglebius ) 2973290000Sglebius{ 2974290000Sglebius const mru * const * ppm1 = v1; 2975290000Sglebius const mru * const * ppm2 = v2; 2976290000Sglebius const mru * pm1; 2977290000Sglebius const mru * pm2; 2978290000Sglebius 2979290000Sglebius pm1 = *ppm1; 2980290000Sglebius pm2 = *ppm2; 2981290000Sglebius 2982290000Sglebius return (pm1->count < pm2->count) 2983290000Sglebius ? -1 2984290000Sglebius : ((pm1->count == pm2->count) 2985290000Sglebius ? 0 2986290000Sglebius : 1); 2987290000Sglebius} 2988290000Sglebius 2989290000Sglebius 2990290000Sglebiusstatic int 2991290000Sglebiusqcmp_mru_r_count( 2992290000Sglebius const void *v1, 2993290000Sglebius const void *v2 2994290000Sglebius ) 2995290000Sglebius{ 2996290000Sglebius return -qcmp_mru_count(v1, v2); 2997290000Sglebius} 2998290000Sglebius 2999290000Sglebius 3000290000Sglebius/* 3001290000Sglebius * qcmp_mru_avgint - sort MRU entries by average interval. 3002290000Sglebius */ 3003290000Sglebiusstatic int 3004290000Sglebiusqcmp_mru_avgint( 3005290000Sglebius const void *v1, 3006290000Sglebius const void *v2 3007290000Sglebius ) 3008290000Sglebius{ 3009290000Sglebius const mru * const * ppm1 = v1; 3010290000Sglebius const mru * const * ppm2 = v2; 3011290000Sglebius const mru * pm1; 3012290000Sglebius const mru * pm2; 3013290000Sglebius l_fp interval; 3014290000Sglebius double avg1; 3015290000Sglebius double avg2; 3016290000Sglebius 3017290000Sglebius pm1 = *ppm1; 3018290000Sglebius pm2 = *ppm2; 3019290000Sglebius 3020290000Sglebius interval = pm1->last; 3021290000Sglebius L_SUB(&interval, &pm1->first); 3022290000Sglebius LFPTOD(&interval, avg1); 3023290000Sglebius avg1 /= pm1->count; 3024290000Sglebius 3025290000Sglebius interval = pm2->last; 3026290000Sglebius L_SUB(&interval, &pm2->first); 3027290000Sglebius LFPTOD(&interval, avg2); 3028290000Sglebius avg2 /= pm2->count; 3029290000Sglebius 3030290000Sglebius if (avg1 < avg2) 3031290000Sglebius return -1; 3032290000Sglebius else if (avg1 > avg2) 3033290000Sglebius return 1; 3034290000Sglebius 3035290000Sglebius /* secondary sort on lstint - rarely tested */ 3036290000Sglebius if (L_ISEQU(&pm1->last, &pm2->last)) 3037290000Sglebius return 0; 3038290000Sglebius else if (L_ISGEQ(&pm1->last, &pm2->last)) 3039290000Sglebius return -1; 3040290000Sglebius else 3041290000Sglebius return 1; 3042290000Sglebius} 3043290000Sglebius 3044290000Sglebius 3045290000Sglebiusstatic int 3046290000Sglebiusqcmp_mru_r_avgint( 3047290000Sglebius const void *v1, 3048290000Sglebius const void *v2 3049290000Sglebius ) 3050290000Sglebius{ 3051290000Sglebius return -qcmp_mru_avgint(v1, v2); 3052290000Sglebius} 3053290000Sglebius 3054290000Sglebius 3055290000Sglebius/* 3056290000Sglebius * mrulist - ntpq's mrulist command to fetch an arbitrarily large Most 3057290000Sglebius * Recently Used (seen) remote address list from ntpd. 3058290000Sglebius * 3059290000Sglebius * Similar to ntpdc's monlist command, but not limited to a single 3060290000Sglebius * request/response, and thereby not limited to a few hundred remote 3061290000Sglebius * addresses. 3062290000Sglebius * 3063290000Sglebius * See ntpd/ntp_control.c read_mru_list() for comments on the way 3064290000Sglebius * CTL_OP_READ_MRU is designed to be used. 3065290000Sglebius * 3066290000Sglebius * mrulist intentionally differs from monlist in the way the avgint 3067290000Sglebius * column is calculated. monlist includes the time after the last 3068290000Sglebius * packet from the client until the monlist query time in the average, 3069290000Sglebius * while mrulist excludes it. That is, monlist's average interval grows 3070290000Sglebius * over time for remote addresses not heard from in some time, while it 3071290000Sglebius * remains unchanged in mrulist. This also affects the avgint value for 3072290000Sglebius * entries representing a single packet, with identical first and last 3073290000Sglebius * timestamps. mrulist shows 0 avgint, monlist shows a value identical 3074290000Sglebius * to lstint. 3075290000Sglebius */ 3076290000Sglebiusstatic void 3077290000Sglebiusmrulist( 3078290000Sglebius struct parse * pcmd, 3079290000Sglebius FILE * fp 3080290000Sglebius ) 3081290000Sglebius{ 3082290000Sglebius const char mincount_eq[] = "mincount="; 3083290000Sglebius const char resall_eq[] = "resall="; 3084290000Sglebius const char resany_eq[] = "resany="; 3085290000Sglebius const char maxlstint_eq[] = "maxlstint="; 3086290000Sglebius const char laddr_eq[] = "laddr="; 3087290000Sglebius const char sort_eq[] = "sort="; 3088290000Sglebius mru_sort_order order; 3089290000Sglebius size_t n; 3090290000Sglebius char parms_buf[128]; 3091290000Sglebius char buf[24]; 3092290000Sglebius char *parms; 3093290000Sglebius const char *arg; 3094290000Sglebius size_t cb; 3095290000Sglebius mru **sorted; 3096290000Sglebius mru **ppentry; 3097290000Sglebius mru *recent; 3098290000Sglebius l_fp now; 3099290000Sglebius l_fp interval; 3100290000Sglebius double favgint; 3101290000Sglebius double flstint; 3102290000Sglebius int avgint; 3103290000Sglebius int lstint; 3104290000Sglebius size_t i; 3105290000Sglebius 3106293894Sglebius mrulist_interrupted = FALSE; 3107293894Sglebius push_ctrl_c_handler(&mrulist_ctrl_c_hook); 3108293894Sglebius fprintf(stderr, 3109293894Sglebius "Ctrl-C will stop MRU retrieval and display partial results.\n"); 3110293894Sglebius fflush(stderr); 3111293894Sglebius 3112290000Sglebius order = MRUSORT_DEF; 3113290000Sglebius parms_buf[0] = '\0'; 3114290000Sglebius parms = parms_buf; 3115290000Sglebius for (i = 0; i < pcmd->nargs; i++) { 3116290000Sglebius arg = pcmd->argval[i].string; 3117290000Sglebius if (arg != NULL) { 3118290000Sglebius cb = strlen(arg) + 1; 3119290000Sglebius if ((!strncmp(resall_eq, arg, sizeof(resall_eq) 3120290000Sglebius - 1) || !strncmp(resany_eq, arg, 3121290000Sglebius sizeof(resany_eq) - 1) || !strncmp( 3122290000Sglebius mincount_eq, arg, sizeof(mincount_eq) - 1) 3123290000Sglebius || !strncmp(laddr_eq, arg, sizeof(laddr_eq) 3124290000Sglebius - 1) || !strncmp(maxlstint_eq, arg, 3125290000Sglebius sizeof(laddr_eq) - 1)) && parms + cb + 2 <= 3126290000Sglebius parms_buf + sizeof(parms_buf)) { 3127290000Sglebius /* these are passed intact to ntpd */ 3128290000Sglebius memcpy(parms, ", ", 2); 3129290000Sglebius parms += 2; 3130290000Sglebius memcpy(parms, arg, cb); 3131290000Sglebius parms += cb - 1; 3132290000Sglebius } else if (!strncmp(sort_eq, arg, 3133290000Sglebius sizeof(sort_eq) - 1)) { 3134290000Sglebius arg += sizeof(sort_eq) - 1; 3135290000Sglebius for (n = 0; 3136290000Sglebius n < COUNTOF(mru_sort_keywords); 3137290000Sglebius n++) 3138290000Sglebius if (!strcmp(mru_sort_keywords[n], 3139290000Sglebius arg)) 3140290000Sglebius break; 3141290000Sglebius if (n < COUNTOF(mru_sort_keywords)) 3142290000Sglebius order = n; 3143290000Sglebius } else if (!strcmp("limited", arg) || 3144290000Sglebius !strcmp("kod", arg)) { 3145290000Sglebius /* transform to resany=... */ 3146290000Sglebius snprintf(buf, sizeof(buf), 3147290000Sglebius ", resany=0x%x", 3148290000Sglebius ('k' == arg[0]) 3149290000Sglebius ? RES_KOD 3150290000Sglebius : RES_LIMITED); 3151290000Sglebius cb = 1 + strlen(buf); 3152290000Sglebius if (parms + cb < 3153290000Sglebius parms_buf + sizeof(parms_buf)) { 3154290000Sglebius memcpy(parms, buf, cb); 3155290000Sglebius parms += cb - 1; 3156290000Sglebius } 3157290000Sglebius } else 3158290000Sglebius fprintf(stderr, 3159290000Sglebius "ignoring unrecognized mrulist parameter: %s\n", 3160290000Sglebius arg); 3161290000Sglebius } 3162290000Sglebius } 3163290000Sglebius parms = parms_buf; 3164290000Sglebius 3165290000Sglebius if (!collect_mru_list(parms, &now)) 3166290000Sglebius return; 3167290000Sglebius 3168290000Sglebius /* display the results */ 3169290000Sglebius if (rawmode) 3170290000Sglebius goto cleanup_return; 3171290000Sglebius 3172290000Sglebius /* construct an array of entry pointers in default order */ 3173290000Sglebius sorted = eallocarray(mru_count, sizeof(*sorted)); 3174290000Sglebius ppentry = sorted; 3175290000Sglebius if (MRUSORT_R_DEF != order) { 3176290000Sglebius ITER_DLIST_BEGIN(mru_list, recent, mlink, mru) 3177290000Sglebius INSIST(ppentry < sorted + mru_count); 3178290000Sglebius *ppentry = recent; 3179290000Sglebius ppentry++; 3180290000Sglebius ITER_DLIST_END() 3181290000Sglebius } else { 3182290000Sglebius REV_ITER_DLIST_BEGIN(mru_list, recent, mlink, mru) 3183290000Sglebius INSIST(ppentry < sorted + mru_count); 3184290000Sglebius *ppentry = recent; 3185290000Sglebius ppentry++; 3186290000Sglebius REV_ITER_DLIST_END() 3187290000Sglebius } 3188290000Sglebius 3189290000Sglebius if (ppentry - sorted != (int)mru_count) { 3190290000Sglebius fprintf(stderr, 3191290000Sglebius "mru_count %u should match MRU list depth %ld.\n", 3192290000Sglebius mru_count, (long)(ppentry - sorted)); 3193290000Sglebius free(sorted); 3194290000Sglebius goto cleanup_return; 3195290000Sglebius } 3196290000Sglebius 3197290000Sglebius /* re-sort sorted[] if not default or reverse default */ 3198290000Sglebius if (MRUSORT_R_DEF < order) 3199290000Sglebius qsort(sorted, mru_count, sizeof(sorted[0]), 3200290000Sglebius mru_qcmp_table[order]); 3201290000Sglebius 3202294904Sdelphij mrulist_interrupted = FALSE; 3203290000Sglebius printf( "lstint avgint rstr r m v count rport remote address\n" 3204290000Sglebius "==============================================================================\n"); 3205290000Sglebius /* '=' x 78 */ 3206290000Sglebius for (ppentry = sorted; ppentry < sorted + mru_count; ppentry++) { 3207290000Sglebius recent = *ppentry; 3208290000Sglebius interval = now; 3209290000Sglebius L_SUB(&interval, &recent->last); 3210290000Sglebius LFPTOD(&interval, flstint); 3211290000Sglebius lstint = (int)(flstint + 0.5); 3212290000Sglebius interval = recent->last; 3213290000Sglebius L_SUB(&interval, &recent->first); 3214290000Sglebius LFPTOD(&interval, favgint); 3215290000Sglebius favgint /= recent->count; 3216290000Sglebius avgint = (int)(favgint + 0.5); 3217290000Sglebius fprintf(fp, "%6d %6d %4hx %c %d %d %6d %5u %s\n", 3218290000Sglebius lstint, avgint, recent->rs, 3219290000Sglebius (RES_KOD & recent->rs) 3220290000Sglebius ? 'K' 3221290000Sglebius : (RES_LIMITED & recent->rs) 3222290000Sglebius ? 'L' 3223290000Sglebius : '.', 3224290000Sglebius (int)recent->mode, (int)recent->ver, 3225290000Sglebius recent->count, SRCPORT(&recent->addr), 3226290000Sglebius nntohost(&recent->addr)); 3227290000Sglebius if (showhostnames) 3228290000Sglebius fflush(fp); 3229294904Sdelphij if (mrulist_interrupted) { 3230294904Sdelphij fputs("\n --interrupted--\n", fp); 3231294904Sdelphij fflush(fp); 3232294904Sdelphij break; 3233294904Sdelphij } 3234290000Sglebius } 3235290000Sglebius fflush(fp); 3236290000Sglebius if (debug) { 3237290000Sglebius fprintf(stderr, 3238290000Sglebius "--- completed, freeing sorted[] pointers\n"); 3239290000Sglebius fflush(stderr); 3240290000Sglebius } 3241290000Sglebius free(sorted); 3242290000Sglebius 3243290000Sglebiuscleanup_return: 3244290000Sglebius if (debug) { 3245290000Sglebius fprintf(stderr, "... freeing MRU entries\n"); 3246290000Sglebius fflush(stderr); 3247290000Sglebius } 3248290000Sglebius ITER_DLIST_BEGIN(mru_list, recent, mlink, mru) 3249290000Sglebius free(recent); 3250290000Sglebius ITER_DLIST_END() 3251290000Sglebius if (debug) { 3252290000Sglebius fprintf(stderr, "... freeing hash_table[]\n"); 3253290000Sglebius fflush(stderr); 3254290000Sglebius } 3255290000Sglebius free(hash_table); 3256290000Sglebius hash_table = NULL; 3257290000Sglebius INIT_DLIST(mru_list, mlink); 3258293894Sglebius 3259293894Sglebius pop_ctrl_c_handler(&mrulist_ctrl_c_hook); 3260290000Sglebius} 3261290000Sglebius 3262290000Sglebius 3263290000Sglebius/* 3264290000Sglebius * validate_ifnum - helper for ifstats() 3265290000Sglebius * 3266290000Sglebius * Ensures rows are received in order and complete. 3267290000Sglebius */ 3268290000Sglebiusstatic void 3269290000Sglebiusvalidate_ifnum( 3270290000Sglebius FILE * fp, 3271290000Sglebius u_int ifnum, 3272290000Sglebius int * pfields, 3273290000Sglebius ifstats_row * prow 3274290000Sglebius ) 3275290000Sglebius{ 3276290000Sglebius if (prow->ifnum == ifnum) 3277290000Sglebius return; 3278290000Sglebius if (prow->ifnum + 1 <= ifnum) { 3279290000Sglebius if (*pfields < IFSTATS_FIELDS) 3280290000Sglebius fprintf(fp, "Warning: incomplete row with %d (of %d) fields", 3281290000Sglebius *pfields, IFSTATS_FIELDS); 3282290000Sglebius *pfields = 0; 3283290000Sglebius prow->ifnum = ifnum; 3284290000Sglebius return; 3285290000Sglebius } 3286290000Sglebius fprintf(stderr, 3287290000Sglebius "received if index %u, have %d of %d fields for index %u, aborting.\n", 3288290000Sglebius ifnum, *pfields, IFSTATS_FIELDS, prow->ifnum); 3289290000Sglebius exit(1); 3290290000Sglebius} 3291290000Sglebius 3292290000Sglebius 3293290000Sglebius/* 3294290000Sglebius * another_ifstats_field - helper for ifstats() 3295290000Sglebius * 3296290000Sglebius * If all fields for the row have been received, print it. 3297290000Sglebius */ 3298290000Sglebiusstatic void 3299290000Sglebiusanother_ifstats_field( 3300290000Sglebius int * pfields, 3301290000Sglebius ifstats_row * prow, 3302290000Sglebius FILE * fp 3303290000Sglebius ) 3304290000Sglebius{ 3305290000Sglebius u_int ifnum; 3306290000Sglebius 3307290000Sglebius (*pfields)++; 3308290000Sglebius /* we understand 12 tags */ 3309290000Sglebius if (IFSTATS_FIELDS > *pfields) 3310290000Sglebius return; 3311290000Sglebius /* 3312290000Sglebius " interface name send\n" 3313290000Sglebius " # address/broadcast drop flag ttl mc received sent failed peers uptime\n" 3314290000Sglebius "==============================================================================\n"); 3315290000Sglebius */ 3316290000Sglebius fprintf(fp, 3317290000Sglebius "%3u %-24.24s %c %4x %3d %2d %6d %6d %6d %5d %8d\n" 3318290000Sglebius " %s\n", 3319290000Sglebius prow->ifnum, prow->name, 3320290000Sglebius (prow->enabled) 3321290000Sglebius ? '.' 3322290000Sglebius : 'D', 3323290000Sglebius prow->flags, prow->ttl, prow->mcast_count, 3324290000Sglebius prow->received, prow->sent, prow->send_errors, 3325290000Sglebius prow->peer_count, prow->uptime, sptoa(&prow->addr)); 3326290000Sglebius if (!SOCK_UNSPEC(&prow->bcast)) 3327290000Sglebius fprintf(fp, " %s\n", sptoa(&prow->bcast)); 3328290000Sglebius ifnum = prow->ifnum; 3329290000Sglebius ZERO(*prow); 3330290000Sglebius prow->ifnum = ifnum; 3331290000Sglebius} 3332290000Sglebius 3333290000Sglebius 3334290000Sglebius/* 3335290000Sglebius * ifstats - ntpq -c ifstats modeled on ntpdc -c ifstats. 3336290000Sglebius */ 3337290000Sglebiusstatic void 3338290000Sglebiusifstats( 3339290000Sglebius struct parse * pcmd, 3340290000Sglebius FILE * fp 3341290000Sglebius ) 3342290000Sglebius{ 3343290000Sglebius const char addr_fmt[] = "addr.%u"; 3344290000Sglebius const char bcast_fmt[] = "bcast.%u"; 3345290000Sglebius const char en_fmt[] = "en.%u"; /* enabled */ 3346290000Sglebius const char flags_fmt[] = "flags.%u"; 3347290000Sglebius const char mc_fmt[] = "mc.%u"; /* mcast count */ 3348290000Sglebius const char name_fmt[] = "name.%u"; 3349290000Sglebius const char pc_fmt[] = "pc.%u"; /* peer count */ 3350290000Sglebius const char rx_fmt[] = "rx.%u"; 3351290000Sglebius const char tl_fmt[] = "tl.%u"; /* ttl */ 3352290000Sglebius const char tx_fmt[] = "tx.%u"; 3353290000Sglebius const char txerr_fmt[] = "txerr.%u"; 3354290000Sglebius const char up_fmt[] = "up.%u"; /* uptime */ 3355290000Sglebius const char * datap; 3356290000Sglebius int qres; 3357293894Sglebius size_t dsize; 3358290000Sglebius u_short rstatus; 3359290000Sglebius char * tag; 3360290000Sglebius char * val; 3361290000Sglebius int fields; 3362290000Sglebius u_int ui; 3363290000Sglebius ifstats_row row; 3364290000Sglebius int comprende; 3365290000Sglebius size_t len; 3366290000Sglebius 3367290000Sglebius qres = doquery(CTL_OP_READ_ORDLIST_A, 0, TRUE, 0, NULL, &rstatus, 3368290000Sglebius &dsize, &datap); 3369290000Sglebius if (qres) /* message already displayed */ 3370290000Sglebius return; 3371290000Sglebius 3372290000Sglebius fprintf(fp, 3373290000Sglebius " interface name send\n" 3374290000Sglebius " # address/broadcast drop flag ttl mc received sent failed peers uptime\n" 3375290000Sglebius "==============================================================================\n"); 3376290000Sglebius /* '=' x 78 */ 3377290000Sglebius 3378290000Sglebius ZERO(row); 3379290000Sglebius fields = 0; 3380290000Sglebius ui = 0; 3381290000Sglebius while (nextvar(&dsize, &datap, &tag, &val)) { 3382290000Sglebius if (debug > 1) 3383290000Sglebius fprintf(stderr, "nextvar gave: %s = %s\n", tag, 3384290000Sglebius (NULL == val) 3385290000Sglebius ? "" 3386290000Sglebius : val); 3387290000Sglebius comprende = FALSE; 3388290000Sglebius switch(tag[0]) { 3389290000Sglebius 3390290000Sglebius case 'a': 3391290000Sglebius if (1 == sscanf(tag, addr_fmt, &ui) && 3392290000Sglebius decodenetnum(val, &row.addr)) 3393290000Sglebius comprende = TRUE; 3394290000Sglebius break; 3395290000Sglebius 3396290000Sglebius case 'b': 3397290000Sglebius if (1 == sscanf(tag, bcast_fmt, &ui) && 3398290000Sglebius (NULL == val || 3399290000Sglebius decodenetnum(val, &row.bcast))) 3400290000Sglebius comprende = TRUE; 3401290000Sglebius break; 3402290000Sglebius 3403290000Sglebius case 'e': 3404290000Sglebius if (1 == sscanf(tag, en_fmt, &ui) && 3405290000Sglebius 1 == sscanf(val, "%d", &row.enabled)) 3406290000Sglebius comprende = TRUE; 3407290000Sglebius break; 3408290000Sglebius 3409290000Sglebius case 'f': 3410290000Sglebius if (1 == sscanf(tag, flags_fmt, &ui) && 3411290000Sglebius 1 == sscanf(val, "0x%x", &row.flags)) 3412290000Sglebius comprende = TRUE; 3413290000Sglebius break; 3414290000Sglebius 3415290000Sglebius case 'm': 3416290000Sglebius if (1 == sscanf(tag, mc_fmt, &ui) && 3417290000Sglebius 1 == sscanf(val, "%d", &row.mcast_count)) 3418290000Sglebius comprende = TRUE; 3419290000Sglebius break; 3420290000Sglebius 3421290000Sglebius case 'n': 3422290000Sglebius if (1 == sscanf(tag, name_fmt, &ui)) { 3423290000Sglebius /* strip quotes */ 3424290000Sglebius INSIST(val); 3425290000Sglebius len = strlen(val); 3426290000Sglebius if (len >= 2 && 3427290000Sglebius len - 2 < sizeof(row.name)) { 3428290000Sglebius len -= 2; 3429290000Sglebius memcpy(row.name, val + 1, len); 3430290000Sglebius row.name[len] = '\0'; 3431290000Sglebius comprende = TRUE; 3432290000Sglebius } 3433290000Sglebius } 3434290000Sglebius break; 3435290000Sglebius 3436290000Sglebius case 'p': 3437290000Sglebius if (1 == sscanf(tag, pc_fmt, &ui) && 3438290000Sglebius 1 == sscanf(val, "%d", &row.peer_count)) 3439290000Sglebius comprende = TRUE; 3440290000Sglebius break; 3441290000Sglebius 3442290000Sglebius case 'r': 3443290000Sglebius if (1 == sscanf(tag, rx_fmt, &ui) && 3444290000Sglebius 1 == sscanf(val, "%d", &row.received)) 3445290000Sglebius comprende = TRUE; 3446290000Sglebius break; 3447290000Sglebius 3448290000Sglebius case 't': 3449290000Sglebius if (1 == sscanf(tag, tl_fmt, &ui) && 3450290000Sglebius 1 == sscanf(val, "%d", &row.ttl)) 3451290000Sglebius comprende = TRUE; 3452290000Sglebius else if (1 == sscanf(tag, tx_fmt, &ui) && 3453290000Sglebius 1 == sscanf(val, "%d", &row.sent)) 3454290000Sglebius comprende = TRUE; 3455290000Sglebius else if (1 == sscanf(tag, txerr_fmt, &ui) && 3456290000Sglebius 1 == sscanf(val, "%d", &row.send_errors)) 3457290000Sglebius comprende = TRUE; 3458290000Sglebius break; 3459290000Sglebius 3460290000Sglebius case 'u': 3461290000Sglebius if (1 == sscanf(tag, up_fmt, &ui) && 3462290000Sglebius 1 == sscanf(val, "%d", &row.uptime)) 3463290000Sglebius comprende = TRUE; 3464290000Sglebius break; 3465290000Sglebius } 3466290000Sglebius 3467290000Sglebius if (comprende) { 3468290000Sglebius /* error out if rows out of order */ 3469290000Sglebius validate_ifnum(fp, ui, &fields, &row); 3470290000Sglebius /* if the row is complete, print it */ 3471290000Sglebius another_ifstats_field(&fields, &row, fp); 3472290000Sglebius } 3473290000Sglebius } 3474290000Sglebius if (fields != IFSTATS_FIELDS) 3475290000Sglebius fprintf(fp, "Warning: incomplete row with %d (of %d) fields", 3476290000Sglebius fields, IFSTATS_FIELDS); 3477290000Sglebius 3478290000Sglebius fflush(fp); 3479290000Sglebius} 3480290000Sglebius 3481290000Sglebius 3482290000Sglebius/* 3483290000Sglebius * validate_reslist_idx - helper for reslist() 3484290000Sglebius * 3485290000Sglebius * Ensures rows are received in order and complete. 3486290000Sglebius */ 3487290000Sglebiusstatic void 3488290000Sglebiusvalidate_reslist_idx( 3489290000Sglebius FILE * fp, 3490290000Sglebius u_int idx, 3491290000Sglebius int * pfields, 3492290000Sglebius reslist_row * prow 3493290000Sglebius ) 3494290000Sglebius{ 3495290000Sglebius if (prow->idx == idx) 3496290000Sglebius return; 3497290000Sglebius if (prow->idx + 1 == idx) { 3498290000Sglebius if (*pfields < RESLIST_FIELDS) 3499290000Sglebius fprintf(fp, "Warning: incomplete row with %d (of %d) fields", 3500290000Sglebius *pfields, RESLIST_FIELDS); 3501290000Sglebius *pfields = 0; 3502290000Sglebius prow->idx = idx; 3503290000Sglebius return; 3504290000Sglebius } 3505290000Sglebius fprintf(stderr, 3506290000Sglebius "received reslist index %u, have %d of %d fields for index %u, aborting.\n", 3507290000Sglebius idx, *pfields, RESLIST_FIELDS, prow->idx); 3508290000Sglebius exit(1); 3509290000Sglebius} 3510290000Sglebius 3511290000Sglebius 3512290000Sglebius/* 3513290000Sglebius * another_reslist_field - helper for reslist() 3514290000Sglebius * 3515290000Sglebius * If all fields for the row have been received, print it. 3516290000Sglebius */ 3517290000Sglebiusstatic void 3518290000Sglebiusanother_reslist_field( 3519290000Sglebius int * pfields, 3520290000Sglebius reslist_row * prow, 3521290000Sglebius FILE * fp 3522290000Sglebius ) 3523290000Sglebius{ 3524290000Sglebius char addrmaskstr[128]; 3525290000Sglebius int prefix; /* subnet mask as prefix bits count */ 3526290000Sglebius u_int idx; 3527290000Sglebius 3528290000Sglebius (*pfields)++; 3529290000Sglebius /* we understand 4 tags */ 3530290000Sglebius if (RESLIST_FIELDS > *pfields) 3531290000Sglebius return; 3532290000Sglebius 3533290000Sglebius prefix = sockaddr_masktoprefixlen(&prow->mask); 3534290000Sglebius if (prefix >= 0) 3535290000Sglebius snprintf(addrmaskstr, sizeof(addrmaskstr), "%s/%d", 3536290000Sglebius stoa(&prow->addr), prefix); 3537290000Sglebius else 3538290000Sglebius snprintf(addrmaskstr, sizeof(addrmaskstr), "%s %s", 3539290000Sglebius stoa(&prow->addr), stoa(&prow->mask)); 3540290000Sglebius 3541290000Sglebius /* 3542290000Sglebius " hits addr/prefix or addr mask\n" 3543290000Sglebius " restrictions\n" 3544290000Sglebius "==============================================================================\n"); 3545290000Sglebius */ 3546290000Sglebius fprintf(fp, 3547290000Sglebius "%10lu %s\n" 3548290000Sglebius " %s\n", 3549290000Sglebius prow->hits, addrmaskstr, prow->flagstr); 3550290000Sglebius idx = prow->idx; 3551290000Sglebius ZERO(*prow); 3552290000Sglebius prow->idx = idx; 3553290000Sglebius} 3554290000Sglebius 3555290000Sglebius 3556290000Sglebius/* 3557290000Sglebius * reslist - ntpq -c reslist modeled on ntpdc -c reslist. 3558290000Sglebius */ 3559290000Sglebiusstatic void 3560290000Sglebiusreslist( 3561290000Sglebius struct parse * pcmd, 3562290000Sglebius FILE * fp 3563290000Sglebius ) 3564290000Sglebius{ 3565290000Sglebius const char addr_fmtu[] = "addr.%u"; 3566290000Sglebius const char mask_fmtu[] = "mask.%u"; 3567290000Sglebius const char hits_fmt[] = "hits.%u"; 3568290000Sglebius const char flags_fmt[] = "flags.%u"; 3569290000Sglebius const char qdata[] = "addr_restrictions"; 3570290000Sglebius const int qdata_chars = COUNTOF(qdata) - 1; 3571290000Sglebius const char * datap; 3572290000Sglebius int qres; 3573293894Sglebius size_t dsize; 3574290000Sglebius u_short rstatus; 3575290000Sglebius char * tag; 3576290000Sglebius char * val; 3577290000Sglebius int fields; 3578290000Sglebius u_int ui; 3579290000Sglebius reslist_row row; 3580290000Sglebius int comprende; 3581290000Sglebius size_t len; 3582290000Sglebius 3583290000Sglebius qres = doquery(CTL_OP_READ_ORDLIST_A, 0, TRUE, qdata_chars, 3584290000Sglebius qdata, &rstatus, &dsize, &datap); 3585290000Sglebius if (qres) /* message already displayed */ 3586290000Sglebius return; 3587290000Sglebius 3588290000Sglebius fprintf(fp, 3589290000Sglebius " hits addr/prefix or addr mask\n" 3590290000Sglebius " restrictions\n" 3591290000Sglebius "==============================================================================\n"); 3592290000Sglebius /* '=' x 78 */ 3593290000Sglebius 3594290000Sglebius ZERO(row); 3595290000Sglebius fields = 0; 3596290000Sglebius ui = 0; 3597290000Sglebius while (nextvar(&dsize, &datap, &tag, &val)) { 3598290000Sglebius if (debug > 1) 3599290000Sglebius fprintf(stderr, "nextvar gave: %s = %s\n", tag, 3600290000Sglebius (NULL == val) 3601290000Sglebius ? "" 3602290000Sglebius : val); 3603290000Sglebius comprende = FALSE; 3604290000Sglebius switch(tag[0]) { 3605290000Sglebius 3606290000Sglebius case 'a': 3607290000Sglebius if (1 == sscanf(tag, addr_fmtu, &ui) && 3608290000Sglebius decodenetnum(val, &row.addr)) 3609290000Sglebius comprende = TRUE; 3610290000Sglebius break; 3611290000Sglebius 3612290000Sglebius case 'f': 3613290000Sglebius if (1 == sscanf(tag, flags_fmt, &ui)) { 3614290000Sglebius if (NULL == val) { 3615290000Sglebius row.flagstr[0] = '\0'; 3616290000Sglebius comprende = TRUE; 3617290000Sglebius } else { 3618290000Sglebius len = strlen(val); 3619290000Sglebius memcpy(row.flagstr, val, len); 3620290000Sglebius row.flagstr[len] = '\0'; 3621290000Sglebius comprende = TRUE; 3622290000Sglebius } 3623290000Sglebius } 3624290000Sglebius break; 3625290000Sglebius 3626290000Sglebius case 'h': 3627290000Sglebius if (1 == sscanf(tag, hits_fmt, &ui) && 3628290000Sglebius 1 == sscanf(val, "%lu", &row.hits)) 3629290000Sglebius comprende = TRUE; 3630290000Sglebius break; 3631290000Sglebius 3632290000Sglebius case 'm': 3633290000Sglebius if (1 == sscanf(tag, mask_fmtu, &ui) && 3634290000Sglebius decodenetnum(val, &row.mask)) 3635290000Sglebius comprende = TRUE; 3636290000Sglebius break; 3637290000Sglebius } 3638290000Sglebius 3639290000Sglebius if (comprende) { 3640290000Sglebius /* error out if rows out of order */ 3641290000Sglebius validate_reslist_idx(fp, ui, &fields, &row); 3642290000Sglebius /* if the row is complete, print it */ 3643290000Sglebius another_reslist_field(&fields, &row, fp); 3644290000Sglebius } 3645290000Sglebius } 3646290000Sglebius if (fields != RESLIST_FIELDS) 3647290000Sglebius fprintf(fp, "Warning: incomplete row with %d (of %d) fields", 3648290000Sglebius fields, RESLIST_FIELDS); 3649290000Sglebius 3650290000Sglebius fflush(fp); 3651290000Sglebius} 3652290000Sglebius 3653290000Sglebius 3654290000Sglebius/* 3655290000Sglebius * collect_display_vdc 3656290000Sglebius */ 3657290000Sglebiusstatic void 3658290000Sglebiuscollect_display_vdc( 3659290000Sglebius associd_t as, 3660290000Sglebius vdc * table, 3661290000Sglebius int decodestatus, 3662290000Sglebius FILE * fp 3663290000Sglebius ) 3664290000Sglebius{ 3665290000Sglebius static const char * const suf[2] = { "adr", "port" }; 3666290000Sglebius static const char * const leapbits[4] = { "00", "01", 3667290000Sglebius "10", "11" }; 3668290000Sglebius struct varlist vl[MAXLIST]; 3669290000Sglebius char tagbuf[32]; 3670290000Sglebius vdc *pvdc; 3671290000Sglebius u_short rstatus; 3672293894Sglebius size_t rsize; 3673290000Sglebius const char *rdata; 3674290000Sglebius int qres; 3675290000Sglebius char *tag; 3676290000Sglebius char *val; 3677290000Sglebius u_int n; 3678290000Sglebius size_t len; 3679290000Sglebius int match; 3680290000Sglebius u_long ul; 3681290000Sglebius int vtype; 3682290000Sglebius 3683290000Sglebius ZERO(vl); 3684290000Sglebius for (pvdc = table; pvdc->tag != NULL; pvdc++) { 3685290000Sglebius ZERO(pvdc->v); 3686290000Sglebius if (NTP_ADD != pvdc->type) { 3687290000Sglebius doaddvlist(vl, pvdc->tag); 3688290000Sglebius } else { 3689290000Sglebius for (n = 0; n < COUNTOF(suf); n++) { 3690290000Sglebius snprintf(tagbuf, sizeof(tagbuf), "%s%s", 3691290000Sglebius pvdc->tag, suf[n]); 3692290000Sglebius doaddvlist(vl, tagbuf); 3693290000Sglebius } 3694290000Sglebius } 3695290000Sglebius } 3696290000Sglebius qres = doquerylist(vl, CTL_OP_READVAR, as, 0, &rstatus, &rsize, 3697290000Sglebius &rdata); 3698290000Sglebius doclearvlist(vl); 3699290000Sglebius if (qres) 3700290000Sglebius return; /* error msg already displayed */ 3701290000Sglebius 3702290000Sglebius /* 3703290000Sglebius * iterate over the response variables filling vdc_table with 3704290000Sglebius * the retrieved values. 3705290000Sglebius */ 3706290000Sglebius while (nextvar(&rsize, &rdata, &tag, &val)) { 3707290000Sglebius if (NULL == val) 3708290000Sglebius continue; 3709290000Sglebius n = 0; 3710290000Sglebius for (pvdc = table; pvdc->tag != NULL; pvdc++) { 3711290000Sglebius len = strlen(pvdc->tag); 3712290000Sglebius if (strncmp(tag, pvdc->tag, len)) 3713290000Sglebius continue; 3714290000Sglebius if (NTP_ADD != pvdc->type) { 3715290000Sglebius if ('\0' != tag[len]) 3716290000Sglebius continue; 3717290000Sglebius break; 3718290000Sglebius } 3719290000Sglebius match = FALSE; 3720290000Sglebius for (n = 0; n < COUNTOF(suf); n++) { 3721290000Sglebius if (strcmp(tag + len, suf[n])) 3722290000Sglebius continue; 3723290000Sglebius match = TRUE; 3724290000Sglebius break; 3725290000Sglebius } 3726290000Sglebius if (match) 3727290000Sglebius break; 3728290000Sglebius } 3729290000Sglebius if (NULL == pvdc->tag) 3730290000Sglebius continue; 3731290000Sglebius switch (pvdc->type) { 3732290000Sglebius 3733290000Sglebius case NTP_STR: 3734290000Sglebius /* strip surrounding double quotes */ 3735290000Sglebius if ('"' == val[0]) { 3736290000Sglebius len = strlen(val); 3737290000Sglebius if (len > 0 && '"' == val[len - 1]) { 3738290000Sglebius val[len - 1] = '\0'; 3739290000Sglebius val++; 3740290000Sglebius } 3741290000Sglebius } 3742290000Sglebius /* fallthru */ 3743290000Sglebius case NTP_MODE: /* fallthru */ 3744290000Sglebius case NTP_2BIT: 3745290000Sglebius pvdc->v.str = estrdup(val); 3746290000Sglebius break; 3747290000Sglebius 3748290000Sglebius case NTP_LFP: 3749290000Sglebius decodets(val, &pvdc->v.lfp); 3750290000Sglebius break; 3751290000Sglebius 3752290000Sglebius case NTP_ADP: 3753290000Sglebius if (!decodenetnum(val, &pvdc->v.sau)) 3754290000Sglebius fprintf(stderr, "malformed %s=%s\n", 3755290000Sglebius pvdc->tag, val); 3756290000Sglebius break; 3757290000Sglebius 3758290000Sglebius case NTP_ADD: 3759290000Sglebius if (0 == n) { /* adr */ 3760290000Sglebius if (!decodenetnum(val, &pvdc->v.sau)) 3761290000Sglebius fprintf(stderr, 3762290000Sglebius "malformed %s=%s\n", 3763290000Sglebius pvdc->tag, val); 3764290000Sglebius } else { /* port */ 3765290000Sglebius if (atouint(val, &ul)) 3766290000Sglebius SET_PORT(&pvdc->v.sau, 3767290000Sglebius (u_short)ul); 3768290000Sglebius } 3769290000Sglebius break; 3770290000Sglebius } 3771290000Sglebius } 3772290000Sglebius 3773290000Sglebius /* and display */ 3774290000Sglebius if (decodestatus) { 3775290000Sglebius vtype = (0 == as) 3776290000Sglebius ? TYPE_SYS 3777290000Sglebius : TYPE_PEER; 3778290000Sglebius fprintf(fp, "associd=%u status=%04x %s,\n", as, rstatus, 3779290000Sglebius statustoa(vtype, rstatus)); 3780290000Sglebius } 3781290000Sglebius 3782290000Sglebius for (pvdc = table; pvdc->tag != NULL; pvdc++) { 3783290000Sglebius switch (pvdc->type) { 3784290000Sglebius 3785290000Sglebius case NTP_STR: 3786290000Sglebius if (pvdc->v.str != NULL) { 3787290000Sglebius fprintf(fp, "%s %s\n", pvdc->display, 3788290000Sglebius pvdc->v.str); 3789290000Sglebius free(pvdc->v.str); 3790290000Sglebius pvdc->v.str = NULL; 3791290000Sglebius } 3792290000Sglebius break; 3793290000Sglebius 3794290000Sglebius case NTP_ADD: /* fallthru */ 3795290000Sglebius case NTP_ADP: 3796290000Sglebius fprintf(fp, "%s %s\n", pvdc->display, 3797290000Sglebius nntohostp(&pvdc->v.sau)); 3798290000Sglebius break; 3799290000Sglebius 3800290000Sglebius case NTP_LFP: 3801290000Sglebius fprintf(fp, "%s %s\n", pvdc->display, 3802290000Sglebius prettydate(&pvdc->v.lfp)); 3803290000Sglebius break; 3804290000Sglebius 3805290000Sglebius case NTP_MODE: 3806290000Sglebius atouint(pvdc->v.str, &ul); 3807290000Sglebius fprintf(fp, "%s %s\n", pvdc->display, 3808290000Sglebius modetoa((int)ul)); 3809290000Sglebius break; 3810290000Sglebius 3811290000Sglebius case NTP_2BIT: 3812290000Sglebius atouint(pvdc->v.str, &ul); 3813290000Sglebius fprintf(fp, "%s %s\n", pvdc->display, 3814290000Sglebius leapbits[ul & 0x3]); 3815290000Sglebius break; 3816290000Sglebius 3817290000Sglebius default: 3818290000Sglebius fprintf(stderr, "unexpected vdc type %d for %s\n", 3819290000Sglebius pvdc->type, pvdc->tag); 3820290000Sglebius break; 3821290000Sglebius } 3822290000Sglebius } 3823290000Sglebius} 3824290000Sglebius 3825290000Sglebius 3826290000Sglebius/* 3827290000Sglebius * sysstats - implements ntpq -c sysstats modeled on ntpdc -c sysstats 3828290000Sglebius */ 3829290000Sglebiusstatic void 3830290000Sglebiussysstats( 3831290000Sglebius struct parse *pcmd, 3832290000Sglebius FILE *fp 3833290000Sglebius ) 3834290000Sglebius{ 3835290000Sglebius static vdc sysstats_vdc[] = { 3836290000Sglebius VDC_INIT("ss_uptime", "uptime: ", NTP_STR), 3837290000Sglebius VDC_INIT("ss_reset", "sysstats reset: ", NTP_STR), 3838290000Sglebius VDC_INIT("ss_received", "packets received: ", NTP_STR), 3839290000Sglebius VDC_INIT("ss_thisver", "current version: ", NTP_STR), 3840290000Sglebius VDC_INIT("ss_oldver", "older version: ", NTP_STR), 3841290000Sglebius VDC_INIT("ss_badformat", "bad length or format: ", NTP_STR), 3842290000Sglebius VDC_INIT("ss_badauth", "authentication failed:", NTP_STR), 3843290000Sglebius VDC_INIT("ss_declined", "declined: ", NTP_STR), 3844290000Sglebius VDC_INIT("ss_restricted", "restricted: ", NTP_STR), 3845290000Sglebius VDC_INIT("ss_limited", "rate limited: ", NTP_STR), 3846290000Sglebius VDC_INIT("ss_kodsent", "KoD responses: ", NTP_STR), 3847290000Sglebius VDC_INIT("ss_processed", "processed for time: ", NTP_STR), 3848290000Sglebius VDC_INIT(NULL, NULL, 0) 3849290000Sglebius }; 3850290000Sglebius 3851290000Sglebius collect_display_vdc(0, sysstats_vdc, FALSE, fp); 3852290000Sglebius} 3853290000Sglebius 3854290000Sglebius 3855290000Sglebius/* 3856290000Sglebius * sysinfo - modeled on ntpdc's sysinfo 3857290000Sglebius */ 3858290000Sglebiusstatic void 3859290000Sglebiussysinfo( 3860290000Sglebius struct parse *pcmd, 3861290000Sglebius FILE *fp 3862290000Sglebius ) 3863290000Sglebius{ 3864290000Sglebius static vdc sysinfo_vdc[] = { 3865290000Sglebius VDC_INIT("peeradr", "system peer: ", NTP_ADP), 3866290000Sglebius VDC_INIT("peermode", "system peer mode: ", NTP_MODE), 3867290000Sglebius VDC_INIT("leap", "leap indicator: ", NTP_2BIT), 3868290000Sglebius VDC_INIT("stratum", "stratum: ", NTP_STR), 3869290000Sglebius VDC_INIT("precision", "log2 precision: ", NTP_STR), 3870290000Sglebius VDC_INIT("rootdelay", "root delay: ", NTP_STR), 3871290000Sglebius VDC_INIT("rootdisp", "root dispersion: ", NTP_STR), 3872290000Sglebius VDC_INIT("refid", "reference ID: ", NTP_STR), 3873290000Sglebius VDC_INIT("reftime", "reference time: ", NTP_LFP), 3874290000Sglebius VDC_INIT("sys_jitter", "system jitter: ", NTP_STR), 3875290000Sglebius VDC_INIT("clk_jitter", "clock jitter: ", NTP_STR), 3876290000Sglebius VDC_INIT("clk_wander", "clock wander: ", NTP_STR), 3877290000Sglebius VDC_INIT("bcastdelay", "broadcast delay: ", NTP_STR), 3878290000Sglebius VDC_INIT("authdelay", "symm. auth. delay:", NTP_STR), 3879290000Sglebius VDC_INIT(NULL, NULL, 0) 3880290000Sglebius }; 3881290000Sglebius 3882290000Sglebius collect_display_vdc(0, sysinfo_vdc, TRUE, fp); 3883290000Sglebius} 3884290000Sglebius 3885290000Sglebius 3886290000Sglebius/* 3887290000Sglebius * kerninfo - modeled on ntpdc's kerninfo 3888290000Sglebius */ 3889290000Sglebiusstatic void 3890290000Sglebiuskerninfo( 3891290000Sglebius struct parse *pcmd, 3892290000Sglebius FILE *fp 3893290000Sglebius ) 3894290000Sglebius{ 3895290000Sglebius static vdc kerninfo_vdc[] = { 3896290000Sglebius VDC_INIT("koffset", "pll offset: ", NTP_STR), 3897290000Sglebius VDC_INIT("kfreq", "pll frequency: ", NTP_STR), 3898290000Sglebius VDC_INIT("kmaxerr", "maximum error: ", NTP_STR), 3899290000Sglebius VDC_INIT("kesterr", "estimated error: ", NTP_STR), 3900290000Sglebius VDC_INIT("kstflags", "kernel status: ", NTP_STR), 3901290000Sglebius VDC_INIT("ktimeconst", "pll time constant: ", NTP_STR), 3902290000Sglebius VDC_INIT("kprecis", "precision: ", NTP_STR), 3903290000Sglebius VDC_INIT("kfreqtol", "frequency tolerance: ", NTP_STR), 3904290000Sglebius VDC_INIT("kppsfreq", "pps frequency: ", NTP_STR), 3905290000Sglebius VDC_INIT("kppsstab", "pps stability: ", NTP_STR), 3906290000Sglebius VDC_INIT("kppsjitter", "pps jitter: ", NTP_STR), 3907290000Sglebius VDC_INIT("kppscalibdur", "calibration interval ", NTP_STR), 3908290000Sglebius VDC_INIT("kppscalibs", "calibration cycles: ", NTP_STR), 3909290000Sglebius VDC_INIT("kppsjitexc", "jitter exceeded: ", NTP_STR), 3910290000Sglebius VDC_INIT("kppsstbexc", "stability exceeded: ", NTP_STR), 3911290000Sglebius VDC_INIT("kppscaliberrs", "calibration errors: ", NTP_STR), 3912290000Sglebius VDC_INIT(NULL, NULL, 0) 3913290000Sglebius }; 3914290000Sglebius 3915290000Sglebius collect_display_vdc(0, kerninfo_vdc, TRUE, fp); 3916290000Sglebius} 3917290000Sglebius 3918290000Sglebius 3919290000Sglebius/* 3920290000Sglebius * monstats - implements ntpq -c monstats 3921290000Sglebius */ 3922290000Sglebiusstatic void 3923290000Sglebiusmonstats( 3924290000Sglebius struct parse *pcmd, 3925290000Sglebius FILE *fp 3926290000Sglebius ) 3927290000Sglebius{ 3928290000Sglebius static vdc monstats_vdc[] = { 3929290000Sglebius VDC_INIT("mru_enabled", "enabled: ", NTP_STR), 3930290000Sglebius VDC_INIT("mru_depth", "addresses: ", NTP_STR), 3931290000Sglebius VDC_INIT("mru_deepest", "peak addresses: ", NTP_STR), 3932290000Sglebius VDC_INIT("mru_maxdepth", "maximum addresses: ", NTP_STR), 3933290000Sglebius VDC_INIT("mru_mindepth", "reclaim above count:", NTP_STR), 3934290000Sglebius VDC_INIT("mru_maxage", "reclaim older than: ", NTP_STR), 3935290000Sglebius VDC_INIT("mru_mem", "kilobytes: ", NTP_STR), 3936290000Sglebius VDC_INIT("mru_maxmem", "maximum kilobytes: ", NTP_STR), 3937290000Sglebius VDC_INIT(NULL, NULL, 0) 3938290000Sglebius }; 3939290000Sglebius 3940290000Sglebius collect_display_vdc(0, monstats_vdc, FALSE, fp); 3941290000Sglebius} 3942290000Sglebius 3943290000Sglebius 3944290000Sglebius/* 3945290000Sglebius * iostats - ntpq -c iostats - network input and output counters 3946290000Sglebius */ 3947290000Sglebiusstatic void 3948290000Sglebiusiostats( 3949290000Sglebius struct parse *pcmd, 3950290000Sglebius FILE *fp 3951290000Sglebius ) 3952290000Sglebius{ 3953290000Sglebius static vdc iostats_vdc[] = { 3954290000Sglebius VDC_INIT("iostats_reset", "time since reset: ", NTP_STR), 3955290000Sglebius VDC_INIT("total_rbuf", "receive buffers: ", NTP_STR), 3956290000Sglebius VDC_INIT("free_rbuf", "free receive buffers: ", NTP_STR), 3957290000Sglebius VDC_INIT("used_rbuf", "used receive buffers: ", NTP_STR), 3958290000Sglebius VDC_INIT("rbuf_lowater", "low water refills: ", NTP_STR), 3959290000Sglebius VDC_INIT("io_dropped", "dropped packets: ", NTP_STR), 3960290000Sglebius VDC_INIT("io_ignored", "ignored packets: ", NTP_STR), 3961290000Sglebius VDC_INIT("io_received", "received packets: ", NTP_STR), 3962290000Sglebius VDC_INIT("io_sent", "packets sent: ", NTP_STR), 3963290000Sglebius VDC_INIT("io_sendfailed", "packet send failures: ", NTP_STR), 3964290000Sglebius VDC_INIT("io_wakeups", "input wakeups: ", NTP_STR), 3965290000Sglebius VDC_INIT("io_goodwakeups", "useful input wakeups: ", NTP_STR), 3966290000Sglebius VDC_INIT(NULL, NULL, 0) 3967290000Sglebius }; 3968290000Sglebius 3969290000Sglebius collect_display_vdc(0, iostats_vdc, FALSE, fp); 3970290000Sglebius} 3971290000Sglebius 3972290000Sglebius 3973290000Sglebius/* 3974290000Sglebius * timerstats - ntpq -c timerstats - interval timer counters 3975290000Sglebius */ 3976290000Sglebiusstatic void 3977290000Sglebiustimerstats( 3978290000Sglebius struct parse *pcmd, 3979290000Sglebius FILE *fp 3980290000Sglebius ) 3981290000Sglebius{ 3982290000Sglebius static vdc timerstats_vdc[] = { 3983290000Sglebius VDC_INIT("timerstats_reset", "time since reset: ", NTP_STR), 3984290000Sglebius VDC_INIT("timer_overruns", "timer overruns: ", NTP_STR), 3985290000Sglebius VDC_INIT("timer_xmts", "calls to transmit: ", NTP_STR), 3986290000Sglebius VDC_INIT(NULL, NULL, 0) 3987290000Sglebius }; 3988290000Sglebius 3989290000Sglebius collect_display_vdc(0, timerstats_vdc, FALSE, fp); 3990290000Sglebius} 3991290000Sglebius 3992290000Sglebius 3993290000Sglebius/* 3994290000Sglebius * authinfo - implements ntpq -c authinfo 3995290000Sglebius */ 3996290000Sglebiusstatic void 3997290000Sglebiusauthinfo( 3998290000Sglebius struct parse *pcmd, 3999290000Sglebius FILE *fp 4000290000Sglebius ) 4001290000Sglebius{ 4002290000Sglebius static vdc authinfo_vdc[] = { 4003290000Sglebius VDC_INIT("authreset", "time since reset:", NTP_STR), 4004290000Sglebius VDC_INIT("authkeys", "stored keys: ", NTP_STR), 4005290000Sglebius VDC_INIT("authfreek", "free keys: ", NTP_STR), 4006290000Sglebius VDC_INIT("authklookups", "key lookups: ", NTP_STR), 4007290000Sglebius VDC_INIT("authknotfound", "keys not found: ", NTP_STR), 4008290000Sglebius VDC_INIT("authkuncached", "uncached keys: ", NTP_STR), 4009290000Sglebius VDC_INIT("authkexpired", "expired keys: ", NTP_STR), 4010290000Sglebius VDC_INIT("authencrypts", "encryptions: ", NTP_STR), 4011290000Sglebius VDC_INIT("authdecrypts", "decryptions: ", NTP_STR), 4012290000Sglebius VDC_INIT(NULL, NULL, 0) 4013290000Sglebius }; 4014290000Sglebius 4015290000Sglebius collect_display_vdc(0, authinfo_vdc, FALSE, fp); 4016290000Sglebius} 4017290000Sglebius 4018290000Sglebius 4019290000Sglebius/* 4020290000Sglebius * pstats - show statistics for a peer 4021290000Sglebius */ 4022290000Sglebiusstatic void 4023290000Sglebiuspstats( 4024290000Sglebius struct parse *pcmd, 4025290000Sglebius FILE *fp 4026290000Sglebius ) 4027290000Sglebius{ 4028290000Sglebius static vdc pstats_vdc[] = { 4029290000Sglebius VDC_INIT("src", "remote host: ", NTP_ADD), 4030290000Sglebius VDC_INIT("dst", "local address: ", NTP_ADD), 4031290000Sglebius VDC_INIT("timerec", "time last received: ", NTP_STR), 4032290000Sglebius VDC_INIT("timer", "time until next send:", NTP_STR), 4033290000Sglebius VDC_INIT("timereach", "reachability change: ", NTP_STR), 4034290000Sglebius VDC_INIT("sent", "packets sent: ", NTP_STR), 4035290000Sglebius VDC_INIT("received", "packets received: ", NTP_STR), 4036290000Sglebius VDC_INIT("badauth", "bad authentication: ", NTP_STR), 4037290000Sglebius VDC_INIT("bogusorg", "bogus origin: ", NTP_STR), 4038290000Sglebius VDC_INIT("oldpkt", "duplicate: ", NTP_STR), 4039290000Sglebius VDC_INIT("seldisp", "bad dispersion: ", NTP_STR), 4040290000Sglebius VDC_INIT("selbroken", "bad reference time: ", NTP_STR), 4041290000Sglebius VDC_INIT("candidate", "candidate order: ", NTP_STR), 4042290000Sglebius VDC_INIT(NULL, NULL, 0) 4043290000Sglebius }; 4044290000Sglebius associd_t associd; 4045290000Sglebius 4046290000Sglebius associd = checkassocid(pcmd->argval[0].uval); 4047290000Sglebius if (0 == associd) 4048290000Sglebius return; 4049290000Sglebius 4050290000Sglebius collect_display_vdc(associd, pstats_vdc, TRUE, fp); 4051290000Sglebius} 4052