aboutsummaryrefslogtreecommitdiff
path: root/contrib/ntp/ntpq/ntpq-subs.c
diff options
context:
space:
mode:
authorXin LI <delphij@FreeBSD.org>2015-07-15 19:21:26 +0000
committerXin LI <delphij@FreeBSD.org>2015-07-15 19:21:26 +0000
commit07267002fe1d040435330820b8a86cad74c6f5c3 (patch)
treeb0302ac4be59e104f4e1e54014561a1389397192 /contrib/ntp/ntpq/ntpq-subs.c
parente57f86038ca56b3be7d0d81eab57e135da3fbe72 (diff)
downloadsrc-07267002fe1d040435330820b8a86cad74c6f5c3.tar.gz
src-07267002fe1d040435330820b8a86cad74c6f5c3.zip
MFC r280849,280915-280916,281015-281016,282097,282408,282415,283542,
284864,285169-285170,285435: ntp 4.2.8p3. Relnotes: yes Approved by: re (?)
Notes
Notes: svn path=/stable/10/; revision=285612
Diffstat (limited to 'contrib/ntp/ntpq/ntpq-subs.c')
-rw-r--r--contrib/ntp/ntpq/ntpq-subs.c3438
1 files changed, 2842 insertions, 596 deletions
diff --git a/contrib/ntp/ntpq/ntpq-subs.c b/contrib/ntp/ntpq/ntpq-subs.c
index 07f25cecefda..c6478701eb27 100644
--- a/contrib/ntp/ntpq/ntpq-subs.c
+++ b/contrib/ntp/ntpq/ntpq-subs.c
@@ -1,74 +1,91 @@
/*
- * ntpq_ops.c - subroutines which are called to perform operations by ntpq
+ * ntpq-subs.c - subroutines which are called to perform ntpq commands.
*/
-
+#include <config.h>
#include <stdio.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/time.h>
#include "ntpq.h"
-#include "ntp_stdlib.h"
+#include "ntpq-opts.h"
-extern char * chosts[];
-extern char currenthost[];
-extern int numhosts;
-int maxhostlen;
+extern char currenthost[];
+extern int currenthostisnum;
+size_t maxhostlen;
/*
* Declarations for command handlers in here
*/
-static int checkassocid P((u_int32));
-static char * strsave P((char *));
-static struct varlist *findlistvar P((struct varlist *, char *));
-static void doaddvlist P((struct varlist *, char *));
-static void dormvlist P((struct varlist *, char *));
-static void doclearvlist P((struct varlist *));
-static void makequerydata P((struct varlist *, int *, char *));
-static int doquerylist P((struct varlist *, int, int, int, u_short *, int *, char **));
-static void doprintvlist P((struct varlist *, FILE *));
-static void addvars P((struct parse *, FILE *));
-static void rmvars P((struct parse *, FILE *));
-static void clearvars P((struct parse *, FILE *));
-static void showvars P((struct parse *, FILE *));
-static int dolist P((struct varlist *, int, int, int, FILE *));
-static void readlist P((struct parse *, FILE *));
-static void writelist P((struct parse *, FILE *));
-static void readvar P((struct parse *, FILE *));
-static void writevar P((struct parse *, FILE *));
-static void clocklist P((struct parse *, FILE *));
-static void clockvar P((struct parse *, FILE *));
-static int findassidrange P((u_int32, u_int32, int *, int *));
-static void mreadlist P((struct parse *, FILE *));
-static void mreadvar P((struct parse *, FILE *));
-static int dogetassoc P((FILE *));
-static void printassoc P((int, FILE *));
-static void associations P((struct parse *, FILE *));
-static void lassociations P((struct parse *, FILE *));
-static void passociations P((struct parse *, FILE *));
-static void lpassociations P((struct parse *, FILE *));
+static associd_t checkassocid (u_int32);
+static struct varlist *findlistvar (struct varlist *, char *);
+static void doaddvlist (struct varlist *, const char *);
+static void dormvlist (struct varlist *, const char *);
+static void doclearvlist (struct varlist *);
+static void makequerydata (struct varlist *, int *, char *);
+static int doquerylist (struct varlist *, int, associd_t, int,
+ u_short *, int *, const char **);
+static void doprintvlist (struct varlist *, FILE *);
+static void addvars (struct parse *, FILE *);
+static void rmvars (struct parse *, FILE *);
+static void clearvars (struct parse *, FILE *);
+static void showvars (struct parse *, FILE *);
+static int dolist (struct varlist *, associd_t, int, int,
+ FILE *);
+static void readlist (struct parse *, FILE *);
+static void writelist (struct parse *, FILE *);
+static void readvar (struct parse *, FILE *);
+static void writevar (struct parse *, FILE *);
+static void clocklist (struct parse *, FILE *);
+static void clockvar (struct parse *, FILE *);
+static int findassidrange (u_int32, u_int32, int *, int *,
+ FILE *);
+static void mreadlist (struct parse *, FILE *);
+static void mreadvar (struct parse *, FILE *);
+static void printassoc (int, FILE *);
+static void associations (struct parse *, FILE *);
+static void lassociations (struct parse *, FILE *);
+static void passociations (struct parse *, FILE *);
+static void lpassociations (struct parse *, FILE *);
#ifdef UNUSED
-static void radiostatus P((struct parse *, FILE *));
+static void radiostatus (struct parse *, FILE *);
#endif /* UNUSED */
-static void pstatus P((struct parse *, FILE *));
-static long when P((l_fp *, l_fp *, l_fp *));
-static char * prettyinterval P((char *, long));
-static int doprintpeers P((struct varlist *, int, int, int, char *, FILE *, int));
-static int dogetpeers P((struct varlist *, int, FILE *, int));
-static void dopeers P((int, FILE *, int));
-static void peers P((struct parse *, FILE *));
-static void lpeers P((struct parse *, FILE *));
-static void doopeers P((int, FILE *, int));
-static void opeers P((struct parse *, FILE *));
-static void lopeers P((struct parse *, FILE *));
-
+static void authinfo (struct parse *, FILE *);
+static void pstats (struct parse *, FILE *);
+static long when (l_fp *, l_fp *, l_fp *);
+static char * prettyinterval (char *, size_t, long);
+static int doprintpeers (struct varlist *, int, int, int, const char *, FILE *, int);
+static int dogetpeers (struct varlist *, associd_t, FILE *, int);
+static void dopeers (int, FILE *, int);
+static void peers (struct parse *, FILE *);
+static void doapeers (int, FILE *, int);
+static void apeers (struct parse *, FILE *);
+static void lpeers (struct parse *, FILE *);
+static void doopeers (int, FILE *, int);
+static void opeers (struct parse *, FILE *);
+static void lopeers (struct parse *, FILE *);
+static void config (struct parse *, FILE *);
+static void saveconfig (struct parse *, FILE *);
+static void config_from_file(struct parse *, FILE *);
+static void mrulist (struct parse *, FILE *);
+static void ifstats (struct parse *, FILE *);
+static void reslist (struct parse *, FILE *);
+static void sysstats (struct parse *, FILE *);
+static void sysinfo (struct parse *, FILE *);
+static void kerninfo (struct parse *, FILE *);
+static void monstats (struct parse *, FILE *);
+static void iostats (struct parse *, FILE *);
+static void timerstats (struct parse *, FILE *);
/*
* Commands we understand. Ntpdc imports this.
*/
struct xcmd opcmds[] = {
+ { "saveconfig", saveconfig, { NTP_STR, NO, NO, NO },
+ { "filename", "", "", ""},
+ "save ntpd configuration to file, . for current config file"},
{ "associations", associations, { NO, NO, NO, NO },
{ "", "", "", "" },
"print list of association ID's and statuses for the server's peers" },
@@ -102,26 +119,26 @@ struct xcmd opcmds[] = {
{ "writelist", writelist, { OPT|NTP_UINT, NO, NO, NO },
{ "assocID", "", "", "" },
"write the system or peer variables included in the variable list" },
- { "readvar", readvar, { OPT|NTP_UINT, OPT|NTP_STR, NO, NO },
- { "assocID", "name=value[,...]", "", "" },
+ { "readvar", readvar, { OPT|NTP_UINT, OPT|NTP_STR, OPT|NTP_STR, OPT|NTP_STR, },
+ { "assocID", "varname1", "varname2", "varname3" },
"read system or peer variables" },
- { "rv", readvar, { OPT|NTP_UINT, OPT|NTP_STR, NO, NO },
- { "assocID", "name=value[,...]", "", "" },
+ { "rv", readvar, { OPT|NTP_UINT, OPT|NTP_STR, OPT|NTP_STR, OPT|NTP_STR, },
+ { "assocID", "varname1", "varname2", "varname3" },
"read system or peer variables" },
{ "writevar", writevar, { NTP_UINT, NTP_STR, NO, NO },
{ "assocID", "name=value,[...]", "", "" },
"write system or peer variables" },
{ "mreadlist", mreadlist, { NTP_UINT, NTP_UINT, NO, NO },
- { "assocID", "assocID", "", "" },
+ { "assocIDlow", "assocIDhigh", "", "" },
"read the peer variables in the variable list for multiple peers" },
{ "mrl", mreadlist, { NTP_UINT, NTP_UINT, NO, NO },
- { "assocID", "assocID", "", "" },
+ { "assocIDlow", "assocIDhigh", "", "" },
"read the peer variables in the variable list for multiple peers" },
{ "mreadvar", mreadvar, { NTP_UINT, NTP_UINT, OPT|NTP_STR, NO },
- { "assocID", "assocID", "name=value[,...]", "" },
+ { "assocIDlow", "assocIDhigh", "name=value[,...]", "" },
"read peer variables from multiple peers" },
{ "mrv", mreadvar, { NTP_UINT, NTP_UINT, OPT|NTP_STR, NO },
- { "assocID", "assocID", "name=value[,...]", "" },
+ { "assocIDlow", "assocIDhigh", "name=value[,...]", "" },
"read peer variables from multiple peers" },
{ "clocklist", clocklist, { OPT|NTP_UINT, NO, NO, NO },
{ "assocID", "", "", "" },
@@ -135,12 +152,15 @@ struct xcmd opcmds[] = {
{ "cv", clockvar, { OPT|NTP_UINT, OPT|NTP_STR, NO, NO },
{ "assocID", "name=value[,...]", "", "" },
"read clock variables" },
- { "pstatus", pstatus, { NTP_UINT, NO, NO, NO },
+ { "pstats", pstats, { NTP_UINT, NO, NO, NO },
{ "assocID", "", "", "" },
- "print status information returned for a peer" },
+ "show statistics for a peer" },
{ "peers", peers, { OPT|IP_VERSION, NO, NO, NO },
{ "-4|-6", "", "", "" },
"obtain and print a list of the server's peers [IP version]" },
+ { "apeers", apeers, { OPT|IP_VERSION, NO, NO, NO },
+ { "-4|-6", "", "", "" },
+ "obtain and print a list of the server's peers and their assocIDs [IP version]" },
{ "lpeers", lpeers, { OPT|IP_VERSION, NO, NO, NO },
{ "-4|-6", "", "", "" },
"obtain and print a list of all peers and clients [IP version]" },
@@ -150,6 +170,42 @@ struct xcmd opcmds[] = {
{ "lopeers", lopeers, { OPT|IP_VERSION, NO, NO, NO },
{ "-4|-6", "", "", "" },
"obtain and print a list of all peers and clients showing dstadr [IP version]" },
+ { ":config", config, { NTP_STR, NO, NO, NO },
+ { "<configuration command line>", "", "", "" },
+ "send a remote configuration command to ntpd" },
+ { "config-from-file", config_from_file, { NTP_STR, NO, NO, NO },
+ { "<configuration filename>", "", "", "" },
+ "configure ntpd using the configuration filename" },
+ { "mrulist", mrulist, { OPT|NTP_STR, OPT|NTP_STR, OPT|NTP_STR, OPT|NTP_STR },
+ { "tag=value", "tag=value", "tag=value", "tag=value" },
+ "display the list of most recently seen source addresses, tags mincount=... resall=0x... resany=0x..." },
+ { "ifstats", ifstats, { NO, NO, NO, NO },
+ { "", "", "", "" },
+ "show statistics for each local address ntpd is using" },
+ { "reslist", reslist, { NO, NO, NO, NO },
+ { "", "", "", "" },
+ "show ntpd access control list" },
+ { "sysinfo", sysinfo, { NO, NO, NO, NO },
+ { "", "", "", "" },
+ "display system summary" },
+ { "kerninfo", kerninfo, { NO, NO, NO, NO },
+ { "", "", "", "" },
+ "display kernel loop and PPS statistics" },
+ { "sysstats", sysstats, { NO, NO, NO, NO },
+ { "", "", "", "" },
+ "display system uptime and packet counts" },
+ { "monstats", monstats, { NO, NO, NO, NO },
+ { "", "", "", "" },
+ "display monitor (mrulist) counters and limits" },
+ { "authinfo", authinfo, { NO, NO, NO, NO },
+ { "", "", "", "" },
+ "display symmetric authentication counters" },
+ { "iostats", iostats, { NO, NO, NO, NO },
+ { "", "", "", "" },
+ "display network input and output counters" },
+ { "timerstats", timerstats, { NO, NO, NO, NO },
+ { "", "", "", "" },
+ "display interval timer counters" },
{ 0, 0, { NO, NO, NO, NO },
{ "-4|-6", "", "", "" }, "" }
};
@@ -158,89 +214,203 @@ struct xcmd opcmds[] = {
/*
* Variable list data space
*/
-#define MAXLIST 64 /* maximum number of variables in list */
-#define LENHOSTNAME 256 /* host name is 256 characters long */
+#define MAXLINE 512 /* maximum length of a line */
+#define MAXLIST 128 /* maximum variables in list */
+#define LENHOSTNAME 256 /* host name limit */
+
+#define MRU_GOT_COUNT 0x1
+#define MRU_GOT_LAST 0x2
+#define MRU_GOT_FIRST 0x4
+#define MRU_GOT_MV 0x8
+#define MRU_GOT_RS 0x10
+#define MRU_GOT_ADDR 0x20
+#define MRU_GOT_ALL (MRU_GOT_COUNT | MRU_GOT_LAST | MRU_GOT_FIRST \
+ | MRU_GOT_MV | MRU_GOT_RS | MRU_GOT_ADDR)
+
+/*
+ * mrulist() depends on MRUSORT_DEF and MRUSORT_RDEF being the first two
+ */
+typedef enum mru_sort_order_tag {
+ MRUSORT_DEF = 0, /* lstint ascending */
+ MRUSORT_R_DEF, /* lstint descending */
+ MRUSORT_AVGINT, /* avgint ascending */
+ MRUSORT_R_AVGINT, /* avgint descending */
+ MRUSORT_ADDR, /* IPv4 asc. then IPv6 asc. */
+ MRUSORT_R_ADDR, /* IPv6 desc. then IPv4 desc. */
+ MRUSORT_COUNT, /* hit count ascending */
+ MRUSORT_R_COUNT, /* hit count descending */
+ MRUSORT_MAX, /* special: count of this enum */
+} mru_sort_order;
+
+const char * const mru_sort_keywords[MRUSORT_MAX] = {
+ "lstint", /* MRUSORT_DEF */
+ "-lstint", /* MRUSORT_R_DEF */
+ "avgint", /* MRUSORT_AVGINT */
+ "-avgint", /* MRUSORT_R_AVGINT */
+ "addr", /* MRUSORT_ADDR */
+ "-addr", /* MRUSORT_R_ADDR */
+ "count", /* MRUSORT_COUNT */
+ "-count", /* MRUSORT_R_COUNT */
+};
+
+typedef int (*qsort_cmp)(const void *, const void *);
+
/*
* Old CTL_PST defines for version 2.
*/
-#define OLD_CTL_PST_CONFIG 0x80
+#define OLD_CTL_PST_CONFIG 0x80
#define OLD_CTL_PST_AUTHENABLE 0x40
#define OLD_CTL_PST_AUTHENTIC 0x20
-#define OLD_CTL_PST_REACH 0x10
-#define OLD_CTL_PST_SANE 0x08
-#define OLD_CTL_PST_DISP 0x04
+#define OLD_CTL_PST_REACH 0x10
+#define OLD_CTL_PST_SANE 0x08
+#define OLD_CTL_PST_DISP 0x04
+
#define OLD_CTL_PST_SEL_REJECT 0
#define OLD_CTL_PST_SEL_SELCAND 1
#define OLD_CTL_PST_SEL_SYNCCAND 2
#define OLD_CTL_PST_SEL_SYSPEER 3
-
char flash2[] = " .+* "; /* flash decode for version 2 */
char flash3[] = " x.-+#*o"; /* flash decode for peer status version 3 */
struct varlist {
- char *name;
+ const char *name;
char *value;
-} varlist[MAXLIST] = { { 0, 0 } };
+} g_varlist[MAXLIST] = { { 0, 0 } };
/*
* Imported from ntpq.c
*/
extern int showhostnames;
+extern int wideremote;
extern int rawmode;
extern struct servent *server_entry;
-extern struct association assoc_cache[];
-extern int numassoc;
+extern struct association *assoc_cache;
extern u_char pktversion;
-extern struct ctl_var peer_var[];
+
+typedef struct mru_tag mru;
+struct mru_tag {
+ mru * hlink; /* next in hash table bucket */
+ DECL_DLIST_LINK(mru, mlink);
+ int count;
+ l_fp last;
+ l_fp first;
+ u_char mode;
+ u_char ver;
+ u_short rs;
+ sockaddr_u addr;
+};
+
+typedef struct ifstats_row_tag {
+ u_int ifnum;
+ sockaddr_u addr;
+ sockaddr_u bcast;
+ int enabled;
+ u_int flags;
+ int mcast_count;
+ char name[32];
+ int peer_count;
+ int received;
+ int sent;
+ int send_errors;
+ u_int ttl;
+ u_int uptime;
+} ifstats_row;
+
+typedef struct reslist_row_tag {
+ u_int idx;
+ sockaddr_u addr;
+ sockaddr_u mask;
+ u_long hits;
+ char flagstr[128];
+} reslist_row;
+
+typedef struct var_display_collection_tag {
+ const char * const tag; /* system variable */
+ const char * const display; /* descriptive text */
+ u_char type; /* NTP_STR, etc */
+ union {
+ char * str;
+ sockaddr_u sau; /* NTP_ADD */
+ l_fp lfp; /* NTP_LFP */
+ } v; /* retrieved value */
+} vdc;
+#if !defined(MISSING_C99_STRUCT_INIT)
+# define VDC_INIT(a, b, c) { .tag = a, .display = b, .type = c }
+#else
+# define VDC_INIT(a, b, c) { a, b, c }
+#endif
+/*
+ * other local function prototypes
+ */
+void mrulist_ctrl_c_hook(void);
+static mru * add_mru(mru *);
+static int collect_mru_list(const char *, l_fp *);
+static int fetch_nonce(char *, size_t);
+static int qcmp_mru_avgint(const void *, const void *);
+static int qcmp_mru_r_avgint(const void *, const void *);
+static int qcmp_mru_addr(const void *, const void *);
+static int qcmp_mru_r_addr(const void *, const void *);
+static int qcmp_mru_count(const void *, const void *);
+static int qcmp_mru_r_count(const void *, const void *);
+static void validate_ifnum(FILE *, u_int, int *, ifstats_row *);
+static void another_ifstats_field(int *, ifstats_row *, FILE *);
+static void collect_display_vdc(associd_t as, vdc *table,
+ int decodestatus, FILE *fp);
/*
- * For quick string comparisons
+ * static globals
*/
-#define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0)
+static u_int mru_count;
+static u_int mru_dupes;
+volatile int mrulist_interrupted;
+static mru mru_list; /* listhead */
+static mru ** hash_table;
+/*
+ * qsort comparison function table for mrulist(). The first two
+ * entries are NULL because they are handled without qsort().
+ */
+static const qsort_cmp mru_qcmp_table[MRUSORT_MAX] = {
+ NULL, /* MRUSORT_DEF unused */
+ NULL, /* MRUSORT_R_DEF unused */
+ &qcmp_mru_avgint, /* MRUSORT_AVGINT */
+ &qcmp_mru_r_avgint, /* MRUSORT_R_AVGINT */
+ &qcmp_mru_addr, /* MRUSORT_ADDR */
+ &qcmp_mru_r_addr, /* MRUSORT_R_ADDR */
+ &qcmp_mru_count, /* MRUSORT_COUNT */
+ &qcmp_mru_r_count, /* MRUSORT_R_COUNT */
+};
/*
* checkassocid - return the association ID, checking to see if it is valid
*/
-static int
+static associd_t
checkassocid(
u_int32 value
)
{
- if (value == 0 || value >= 65536) {
- (void) fprintf(stderr, "***Invalid association ID specified\n");
+ associd_t associd;
+ u_long ulvalue;
+
+ associd = (associd_t)value;
+ if (0 == associd || value != associd) {
+ ulvalue = value;
+ fprintf(stderr,
+ "***Invalid association ID %lu specified\n",
+ ulvalue);
return 0;
}
- return (int)value;
-}
-
-
-/*
- * strsave - save a string
- * XXX - should be in libntp.a
- */
-static char *
-strsave(
- char *str
- )
-{
- char *cp;
- u_int len;
-
- len = strlen(str) + 1;
- if ((cp = (char *)malloc(len)) == NULL) {
- (void) fprintf(stderr, "Malloc failed!!\n");
- exit(1);
- }
- memmove(cp, str, len);
- return (cp);
+ return associd;
}
/*
- * findlistvar - look for the named variable in a list and return if found
+ * findlistvar - Look for the named variable in a varlist. If found,
+ * return a pointer to it. Otherwise, if the list has
+ * slots available, return the pointer to the first free
+ * slot, or NULL if it's full.
*/
static struct varlist *
findlistvar(
@@ -248,14 +418,15 @@ findlistvar(
char *name
)
{
- register struct varlist *vl;
+ struct varlist *vl;
- for (vl = list; vl < list + MAXLIST && vl->name != 0; vl++)
- if (STREQ(name, vl->name))
- return vl;
+ for (vl = list; vl < list + MAXLIST && vl->name != NULL; vl++)
+ if (!strcmp(name, vl->name))
+ return vl;
if (vl < list + MAXLIST)
return vl;
- return (struct varlist *)0;
+
+ return NULL;
}
@@ -265,10 +436,10 @@ findlistvar(
static void
doaddvlist(
struct varlist *vlist,
- char *vars
+ const char *vars
)
{
- register struct varlist *vl;
+ struct varlist *vl;
int len;
char *name;
char *value;
@@ -276,20 +447,20 @@ doaddvlist(
len = strlen(vars);
while (nextvar(&len, &vars, &name, &value)) {
vl = findlistvar(vlist, name);
- if (vl == 0) {
- (void) fprintf(stderr, "Variable list full\n");
+ if (NULL == vl) {
+ fprintf(stderr, "Variable list full\n");
return;
}
- if (vl->name == 0) {
- vl->name = strsave(name);
- } else if (vl->value != 0) {
+ if (NULL == vl->name) {
+ vl->name = estrdup(name);
+ } else if (vl->value != NULL) {
free(vl->value);
- vl->value = 0;
+ vl->value = NULL;
}
- if (value != 0)
- vl->value = strsave(value);
+ if (value != NULL)
+ vl->value = estrdup(value);
}
}
@@ -300,10 +471,10 @@ doaddvlist(
static void
dormvlist(
struct varlist *vlist,
- char *vars
+ const char *vars
)
{
- register struct varlist *vl;
+ struct varlist *vl;
int len;
char *name;
char *value;
@@ -315,10 +486,10 @@ dormvlist(
(void) fprintf(stderr, "Variable `%s' not found\n",
name);
} else {
- free((void *)vl->name);
+ free((void *)(intptr_t)vl->name);
if (vl->value != 0)
free(vl->value);
- for ( ; (vl+1) < (varlist+MAXLIST)
+ for ( ; (vl+1) < (g_varlist + MAXLIST)
&& (vl+1)->name != 0; vl++) {
vl->name = (vl+1)->name;
vl->value = (vl+1)->value;
@@ -340,7 +511,7 @@ doclearvlist(
register struct varlist *vl;
for (vl = vlist; vl < vlist + MAXLIST && vl->name != 0; vl++) {
- free((void *)vl->name);
+ free((void *)(intptr_t)vl->name);
vl->name = 0;
if (vl->value != 0) {
free(vl->value);
@@ -375,16 +546,20 @@ makequerydata(
else
valuelen = strlen(vl->value);
totallen = namelen + valuelen + (valuelen != 0) + (cp != data);
- if (cp + totallen > cpend)
- break;
+ if (cp + totallen > cpend) {
+ fprintf(stderr,
+ "***Ignoring variables starting with `%s'\n",
+ vl->name);
+ break;
+ }
if (cp != data)
*cp++ = ',';
- memmove(cp, vl->name, (unsigned)namelen);
+ memcpy(cp, vl->name, (size_t)namelen);
cp += namelen;
if (valuelen != 0) {
*cp++ = '=';
- memmove(cp, vl->value, (unsigned)valuelen);
+ memcpy(cp, vl->value, (size_t)valuelen);
cp += valuelen;
}
}
@@ -399,11 +574,11 @@ static int
doquerylist(
struct varlist *vlist,
int op,
- int associd,
+ associd_t associd,
int auth,
u_short *rstatus,
int *dsize,
- char **datap
+ const char **datap
)
{
char data[CTL_MAX_DATA_LEN];
@@ -412,8 +587,8 @@ doquerylist(
datalen = sizeof(data);
makequerydata(vlist, &datalen, data);
- return doquery(op, associd, auth, datalen, data, rstatus,
- dsize, datap);
+ return doquery(op, associd, auth, datalen, data, rstatus, dsize,
+ datap);
}
@@ -426,23 +601,21 @@ doprintvlist(
FILE *fp
)
{
- register struct varlist *vl;
+ size_t n;
- if (vlist->name == 0) {
- (void) fprintf(fp, "No variables on list\n");
- } else {
- for (vl = vlist; vl < vlist + MAXLIST && vl->name != 0; vl++) {
- if (vl->value == 0) {
- (void) fprintf(fp, "%s\n", vl->name);
- } else {
- (void) fprintf(fp, "%s=%s\n",
- vl->name, vl->value);
- }
- }
+ if (NULL == vlist->name) {
+ fprintf(fp, "No variables on list\n");
+ return;
+ }
+ for (n = 0; n < MAXLIST && vlist[n].name != NULL; n++) {
+ if (NULL == vlist[n].value)
+ fprintf(fp, "%s\n", vlist[n].name);
+ else
+ fprintf(fp, "%s=%s\n", vlist[n].name,
+ vlist[n].value);
}
}
-
/*
* addvars - add variables to the variable list
*/
@@ -453,7 +626,7 @@ addvars(
FILE *fp
)
{
- doaddvlist(varlist, pcmd->argval[0].string);
+ doaddvlist(g_varlist, pcmd->argval[0].string);
}
@@ -467,7 +640,7 @@ rmvars(
FILE *fp
)
{
- dormvlist(varlist, pcmd->argval[0].string);
+ dormvlist(g_varlist, pcmd->argval[0].string);
}
@@ -481,7 +654,7 @@ clearvars(
FILE *fp
)
{
- doclearvlist(varlist);
+ doclearvlist(g_varlist);
}
@@ -495,7 +668,7 @@ showvars(
FILE *fp
)
{
- doprintvlist(varlist, fp);
+ doprintvlist(g_varlist, fp);
}
@@ -505,16 +678,26 @@ showvars(
static int
dolist(
struct varlist *vlist,
- int associd,
+ associd_t associd,
int op,
int type,
FILE *fp
)
{
- char *datap;
+ const char *datap;
int res;
int dsize;
u_short rstatus;
+ int quiet;
+
+ /*
+ * if we're asking for specific variables don't include the
+ * status header line in the output.
+ */
+ if (old_rv)
+ quiet = 0;
+ else
+ quiet = (vlist->name != NULL);
res = doquerylist(vlist, op, associd, 0, &rstatus, &dsize, &datap);
@@ -522,20 +705,22 @@ dolist(
return 0;
if (numhosts > 1)
- (void) fprintf(fp, "server=%s ", currenthost);
+ fprintf(fp, "server=%s ", currenthost);
if (dsize == 0) {
if (associd == 0)
- (void) fprintf(fp, "No system%s variables returned\n",
- (type == TYPE_CLOCK) ? " clock" : "");
+ fprintf(fp, "No system%s variables returned\n",
+ (type == TYPE_CLOCK) ? " clock" : "");
else
- (void) fprintf(fp,
- "No information returned for%s association %u\n",
- (type == TYPE_CLOCK) ? " clock" : "", associd);
+ fprintf(fp,
+ "No information returned for%s association %u\n",
+ (type == TYPE_CLOCK) ? " clock" : "",
+ associd);
return 1;
}
- (void) fprintf(fp,"assID=%d ",associd);
- printvars(dsize, datap, (int)rstatus, type, fp);
+ if (!quiet)
+ fprintf(fp, "associd=%u ", associd);
+ printvars(dsize, datap, (int)rstatus, type, quiet, fp);
return 1;
}
@@ -549,7 +734,8 @@ readlist(
FILE *fp
)
{
- int associd;
+ associd_t associd;
+ int type;
if (pcmd->nargs == 0) {
associd = 0;
@@ -561,8 +747,10 @@ readlist(
return;
}
- (void) dolist(varlist, associd, CTL_OP_READVAR,
- (associd == 0) ? TYPE_SYS : TYPE_PEER, fp);
+ type = (0 == associd)
+ ? TYPE_SYS
+ : TYPE_PEER;
+ dolist(g_varlist, associd, CTL_OP_READVAR, type, fp);
}
@@ -575,9 +763,9 @@ writelist(
FILE *fp
)
{
- char *datap;
+ const char *datap;
int res;
- int associd;
+ associd_t associd;
int dsize;
u_short rstatus;
@@ -591,7 +779,7 @@ writelist(
return;
}
- res = doquerylist(varlist, CTL_OP_WRITEVAR, associd, 1, &rstatus,
+ res = doquerylist(g_varlist, CTL_OP_WRITEVAR, associd, 1, &rstatus,
&dsize, &datap);
if (res != 0)
@@ -602,9 +790,9 @@ writelist(
if (dsize == 0)
(void) fprintf(fp, "done! (no data returned)\n");
else {
- (void) fprintf(fp,"assID=%d ",associd);
+ (void) fprintf(fp,"associd=%u ", associd);
printvars(dsize, datap, (int)rstatus,
- (associd != 0) ? TYPE_PEER : TYPE_SYS, fp);
+ (associd != 0) ? TYPE_PEER : TYPE_SYS, 0, fp);
}
return;
}
@@ -619,8 +807,12 @@ readvar(
FILE *fp
)
{
- int associd;
- struct varlist tmplist[MAXLIST];
+ associd_t associd;
+ u_int tmpcount;
+ u_int u;
+ int type;
+ struct varlist tmplist[MAXLIST];
+
/* HMS: uval? */
if (pcmd->nargs == 0 || pcmd->argval[0].uval == 0)
@@ -628,12 +820,17 @@ readvar(
else if ((associd = checkassocid(pcmd->argval[0].uval)) == 0)
return;
- memset((char *)tmplist, 0, sizeof(tmplist));
- if (pcmd->nargs >= 2)
- doaddvlist(tmplist, pcmd->argval[1].string);
+ ZERO(tmplist);
+ if (pcmd->nargs > 1) {
+ tmpcount = pcmd->nargs - 1;
+ for (u = 0; u < tmpcount; u++)
+ doaddvlist(tmplist, pcmd->argval[1 + u].string);
+ }
- (void) dolist(tmplist, associd, CTL_OP_READVAR,
- (associd == 0) ? TYPE_SYS : TYPE_PEER, fp);
+ type = (0 == associd)
+ ? TYPE_SYS
+ : TYPE_PEER;
+ dolist(tmplist, associd, CTL_OP_READVAR, type, fp);
doclearvlist(tmplist);
}
@@ -648,9 +845,10 @@ writevar(
FILE *fp
)
{
- char *datap;
+ const char *datap;
int res;
- int associd;
+ associd_t associd;
+ int type;
int dsize;
u_short rstatus;
struct varlist tmplist[MAXLIST];
@@ -661,7 +859,7 @@ writevar(
else if ((associd = checkassocid(pcmd->argval[0].uval)) == 0)
return;
- memset((char *)tmplist, 0, sizeof(tmplist));
+ ZERO(tmplist);
doaddvlist(tmplist, pcmd->argval[1].string);
res = doquerylist(tmplist, CTL_OP_WRITEVAR, associd, 1, &rstatus,
@@ -673,13 +871,15 @@ writevar(
return;
if (numhosts > 1)
- (void) fprintf(fp, "server=%s ", currenthost);
+ fprintf(fp, "server=%s ", currenthost);
if (dsize == 0)
- (void) fprintf(fp, "done! (no data returned)\n");
+ fprintf(fp, "done! (no data returned)\n");
else {
- (void) fprintf(fp,"assID=%d ",associd);
- printvars(dsize, datap, (int)rstatus,
- (associd != 0) ? TYPE_PEER : TYPE_SYS, fp);
+ fprintf(fp,"associd=%u ", associd);
+ type = (0 == associd)
+ ? TYPE_SYS
+ : TYPE_PEER;
+ printvars(dsize, datap, (int)rstatus, type, 0, fp);
}
return;
}
@@ -694,7 +894,7 @@ clocklist(
FILE *fp
)
{
- int associd;
+ associd_t associd;
/* HMS: uval? */
if (pcmd->nargs == 0) {
@@ -706,7 +906,7 @@ clocklist(
return;
}
- (void) dolist(varlist, associd, CTL_OP_READCLOCK, TYPE_CLOCK, fp);
+ dolist(g_varlist, associd, CTL_OP_READCLOCK, TYPE_CLOCK, fp);
}
@@ -719,7 +919,7 @@ clockvar(
FILE *fp
)
{
- int associd;
+ associd_t associd;
struct varlist tmplist[MAXLIST];
/* HMS: uval? */
@@ -728,11 +928,11 @@ clockvar(
else if ((associd = checkassocid(pcmd->argval[0].uval)) == 0)
return;
- memset((char *)tmplist, 0, sizeof(tmplist));
+ ZERO(tmplist);
if (pcmd->nargs >= 2)
doaddvlist(tmplist, pcmd->argval[1].string);
- (void) dolist(tmplist, associd, CTL_OP_READCLOCK, TYPE_CLOCK, fp);
+ dolist(tmplist, associd, CTL_OP_READCLOCK, TYPE_CLOCK, fp);
doclearvlist(tmplist);
}
@@ -743,54 +943,49 @@ clockvar(
*/
static int
findassidrange(
- u_int32 assid1,
- u_int32 assid2,
- int *from,
- int *to
+ u_int32 assid1,
+ u_int32 assid2,
+ int * from,
+ int * to,
+ FILE * fp
)
{
- register int i;
- int f, t;
-
- if (assid1 == 0 || assid1 > 65535) {
- (void) fprintf(stderr,
- "***Invalid association ID %lu specified\n", (u_long)assid1);
- return 0;
- }
+ associd_t assids[2];
+ int ind[COUNTOF(assids)];
+ u_int i;
+ size_t a;
- if (assid2 == 0 || assid2 > 65535) {
- (void) fprintf(stderr,
- "***Invalid association ID %lu specified\n", (u_long)assid2);
- return 0;
- }
- f = t = -1;
- for (i = 0; i < numassoc; i++) {
- if (assoc_cache[i].assid == assid1) {
- f = i;
- if (t != -1)
- break;
- }
- if (assoc_cache[i].assid == assid2) {
- t = i;
- if (f != -1)
- break;
- }
- }
+ if (0 == numassoc)
+ dogetassoc(fp);
- if (f == -1 || t == -1) {
- (void) fprintf(stderr,
- "***Association ID %lu not found in list\n",
- (f == -1) ? (u_long)assid1 : (u_long)assid2);
+ assids[0] = checkassocid(assid1);
+ if (0 == assids[0])
return 0;
+ assids[1] = checkassocid(assid2);
+ if (0 == assids[1])
+ return 0;
+
+ for (a = 0; a < COUNTOF(assids); a++) {
+ ind[a] = -1;
+ for (i = 0; i < numassoc; i++)
+ if (assoc_cache[i].assid == assids[a])
+ ind[a] = i;
}
+ for (a = 0; a < COUNTOF(assids); a++)
+ if (-1 == ind[a]) {
+ fprintf(stderr,
+ "***Association ID %u not found in list\n",
+ assids[a]);
+ return 0;
+ }
- if (f < t) {
- *from = f;
- *to = t;
+ if (ind[0] < ind[1]) {
+ *from = ind[0];
+ *to = ind[1];
} else {
- *from = t;
- *to = f;
+ *to = ind[0];
+ *from = ind[1];
}
return 1;
}
@@ -810,16 +1005,15 @@ mreadlist(
int from;
int to;
- /* HMS: uval? */
if (!findassidrange(pcmd->argval[0].uval, pcmd->argval[1].uval,
- &from, &to))
+ &from, &to, fp))
return;
for (i = from; i <= to; i++) {
if (i != from)
- (void) fprintf(fp, "\n");
- if (!dolist(varlist, (int)assoc_cache[i].assid,
- CTL_OP_READVAR, TYPE_PEER, fp))
+ fprintf(fp, "\n");
+ if (!dolist(g_varlist, assoc_cache[i].assid,
+ CTL_OP_READVAR, TYPE_PEER, fp))
return;
}
return;
@@ -839,24 +1033,29 @@ mreadvar(
int from;
int to;
struct varlist tmplist[MAXLIST];
+ struct varlist *pvars;
- /* HMS: uval? */
if (!findassidrange(pcmd->argval[0].uval, pcmd->argval[1].uval,
- &from, &to))
+ &from, &to, fp))
return;
- memset((char *)tmplist, 0, sizeof(tmplist));
- if (pcmd->nargs >= 3)
+ ZERO(tmplist);
+ if (pcmd->nargs >= 3) {
doaddvlist(tmplist, pcmd->argval[2].string);
+ pvars = tmplist;
+ } else {
+ pvars = g_varlist;
+ }
for (i = from; i <= to; i++) {
- if (i != from)
- (void) fprintf(fp, "\n");
- if (!dolist(varlist, (int)assoc_cache[i].assid,
- CTL_OP_READVAR, TYPE_PEER, fp))
+ if (!dolist(pvars, assoc_cache[i].assid, CTL_OP_READVAR,
+ TYPE_PEER, fp))
break;
}
- doclearvlist(tmplist);
+
+ if (pvars == tmplist)
+ doclearvlist(tmplist);
+
return;
}
@@ -864,12 +1063,13 @@ mreadvar(
/*
* dogetassoc - query the host for its list of associations
*/
-static int
+int
dogetassoc(
FILE *fp
)
{
- char *datap;
+ const char *datap;
+ const u_short *pus;
int res;
int dsize;
u_short rstatus;
@@ -882,29 +1082,41 @@ dogetassoc(
if (dsize == 0) {
if (numhosts > 1)
- (void) fprintf(fp, "server=%s ", currenthost);
- (void) fprintf(fp, "No association ID's returned\n");
+ fprintf(fp, "server=%s ", currenthost);
+ fprintf(fp, "No association ID's returned\n");
return 0;
}
if (dsize & 0x3) {
if (numhosts > 1)
- (void) fprintf(stderr, "server=%s ", currenthost);
- (void) fprintf(stderr,
- "***Server returned %d octets, should be multiple of 4\n",
- dsize);
+ fprintf(stderr, "server=%s ", currenthost);
+ fprintf(stderr,
+ "***Server returned %d octets, should be multiple of 4\n",
+ dsize);
return 0;
}
numassoc = 0;
+
while (dsize > 0) {
- assoc_cache[numassoc].assid = ntohs(*((u_short *)datap));
- datap += sizeof(u_short);
- assoc_cache[numassoc].status = ntohs(*((u_short *)datap));
- datap += sizeof(u_short);
- if (++numassoc >= MAXASSOC)
- break;
- dsize -= sizeof(u_short) + sizeof(u_short);
+ if (numassoc >= assoc_cache_slots) {
+ grow_assoc_cache();
+ }
+ pus = (const void *)datap;
+ assoc_cache[numassoc].assid = ntohs(*pus);
+ datap += sizeof(*pus);
+ pus = (const void *)datap;
+ assoc_cache[numassoc].status = ntohs(*pus);
+ datap += sizeof(*pus);
+ dsize -= 2 * sizeof(*pus);
+ if (debug) {
+ fprintf(stderr, "[%u] ",
+ assoc_cache[numassoc].assid);
+ }
+ numassoc++;
+ }
+ if (debug) {
+ fprintf(stderr, "\n%d associations total\n", numassoc);
}
sortassoc();
return 1;
@@ -921,7 +1133,7 @@ printassoc(
)
{
register char *bp;
- int i;
+ u_int i;
u_char statval;
int event;
u_long event_count;
@@ -930,7 +1142,6 @@ printassoc(
const char *auth;
const char *condition = "";
const char *last_event;
- const char *cnt;
char buf[128];
if (numassoc == 0) {
@@ -942,7 +1153,7 @@ printassoc(
* Output a header
*/
(void) fprintf(fp,
- "\nind assID status conf reach auth condition last_event cnt\n");
+ "\nind assid status conf reach auth condition last_event cnt\n");
(void) fprintf(fp,
"===========================================================\n");
for (i = 0; i < numassoc; i++) {
@@ -955,112 +1166,150 @@ printassoc(
conf = "yes";
else
conf = "no";
- if (statval & CTL_PST_REACH || 1) {
- reach = "yes";
+ if (statval & CTL_PST_BCAST) {
+ reach = "none";
+ if (statval & CTL_PST_AUTHENABLE)
+ auth = "yes";
+ else
+ auth = "none";
+ } else {
+ if (statval & CTL_PST_REACH)
+ reach = "yes";
+ else
+ reach = "no";
if (statval & CTL_PST_AUTHENABLE) {
if (statval & CTL_PST_AUTHENTIC)
auth = "ok ";
else
auth = "bad";
- } else
+ } else {
auth = "none";
+ }
+ }
+ if (pktversion > NTP_OLDVERSION) {
+ switch (statval & 0x7) {
- if (pktversion > NTP_OLDVERSION)
- switch (statval & 0x7) {
- case CTL_PST_SEL_REJECT:
- condition = "reject";
- break;
- case CTL_PST_SEL_SANE:
- condition = "falsetick";
- break;
- case CTL_PST_SEL_CORRECT:
- condition = "excess";
- break;
- case CTL_PST_SEL_SELCAND:
- condition = "outlyer";
- break;
- case CTL_PST_SEL_SYNCCAND:
- condition = "candidat";
- break;
- case CTL_PST_SEL_DISTSYSPEER:
- condition = "selected";
- break;
- case CTL_PST_SEL_SYSPEER:
- condition = "sys.peer";
- break;
- case CTL_PST_SEL_PPS:
- condition = "pps.peer";
- break;
- }
- else
- switch (statval & 0x3) {
- case OLD_CTL_PST_SEL_REJECT:
- if (!(statval & OLD_CTL_PST_SANE))
+ case CTL_PST_SEL_REJECT:
+ condition = "reject";
+ break;
+
+ case CTL_PST_SEL_SANE:
+ condition = "falsetick";
+ break;
+
+ case CTL_PST_SEL_CORRECT:
+ condition = "excess";
+ break;
+
+ case CTL_PST_SEL_SELCAND:
+ condition = "outlyer";
+ break;
+
+ case CTL_PST_SEL_SYNCCAND:
+ condition = "candidate";
+ break;
+
+ case CTL_PST_SEL_EXCESS:
+ condition = "backup";
+ break;
+
+ case CTL_PST_SEL_SYSPEER:
+ condition = "sys.peer";
+ break;
+
+ case CTL_PST_SEL_PPS:
+ condition = "pps.peer";
+ break;
+ }
+ } else {
+ switch (statval & 0x3) {
+
+ case OLD_CTL_PST_SEL_REJECT:
+ if (!(statval & OLD_CTL_PST_SANE))
condition = "insane";
- else if (!(statval & OLD_CTL_PST_DISP))
+ else if (!(statval & OLD_CTL_PST_DISP))
condition = "hi_disp";
- else
+ else
condition = "";
- break;
- case OLD_CTL_PST_SEL_SELCAND:
- condition = "sel_cand";
- break;
- case OLD_CTL_PST_SEL_SYNCCAND:
- condition = "sync_cand";
- break;
- case OLD_CTL_PST_SEL_SYSPEER:
- condition = "sys_peer";
- break;
- }
+ break;
- } else {
- reach = "no";
- auth = condition = "";
- }
+ case OLD_CTL_PST_SEL_SELCAND:
+ condition = "sel_cand";
+ break;
+ case OLD_CTL_PST_SEL_SYNCCAND:
+ condition = "sync_cand";
+ break;
+
+ case OLD_CTL_PST_SEL_SYSPEER:
+ condition = "sys_peer";
+ break;
+ }
+ }
switch (PEER_EVENT|event) {
- case EVNT_PEERIPERR:
- last_event = "IP error";
- break;
- case EVNT_PEERAUTH:
- last_event = "auth fail";
+
+ case PEVNT_MOBIL:
+ last_event = "mobilize";
break;
- case EVNT_UNREACH:
- last_event = "lost reach";
+
+ case PEVNT_DEMOBIL:
+ last_event = "demobilize";
break;
- case EVNT_REACH:
+
+ case PEVNT_REACH:
last_event = "reachable";
break;
- case EVNT_PEERCLOCK:
- last_event = "clock expt";
+
+ case PEVNT_UNREACH:
+ last_event = "unreachable";
break;
-#if 0
- case EVNT_PEERSTRAT:
- last_event = "stratum chg";
+
+ case PEVNT_RESTART:
+ last_event = "restart";
break;
-#endif
- default:
+
+ case PEVNT_REPLY:
+ last_event = "no_reply";
+ break;
+
+ case PEVNT_RATE:
+ last_event = "rate_exceeded";
+ break;
+
+ case PEVNT_DENY:
+ last_event = "access_denied";
+ break;
+
+ case PEVNT_ARMED:
+ last_event = "leap_armed";
+ break;
+
+ case PEVNT_NEWPEER:
+ last_event = "sys_peer";
+ break;
+
+ case PEVNT_CLOCK:
+ last_event = "clock_alarm";
+ break;
+
+ default:
last_event = "";
break;
}
-
- if (event_count != 0)
- cnt = uinttoa(event_count);
- else
- cnt = "";
- (void) sprintf(buf,
- "%3d %5u %04x %3.3s %4s %4.4s %9.9s %11s %2s",
- i+1, assoc_cache[i].assid, assoc_cache[i].status,
- conf, reach, auth, condition, last_event, cnt);
- bp = &buf[strlen(buf)];
- while (bp > buf && *(bp-1) == ' ')
- *(--bp) = '\0';
- (void) fprintf(fp, "%s\n", buf);
+ snprintf(buf, sizeof(buf),
+ "%3d %5u %04x %3.3s %4s %4.4s %9.9s %11s %2lu",
+ i + 1, assoc_cache[i].assid,
+ assoc_cache[i].status, conf, reach, auth,
+ condition, last_event, event_count);
+ bp = buf + strlen(buf);
+ while (bp > buf && ' ' == bp[-1])
+ --bp;
+ bp[0] = '\0';
+ fprintf(fp, "%s\n", buf);
}
}
-
/*
* associations - get, record and print a list of associations
*/
@@ -1119,59 +1368,55 @@ lpassociations(
}
-#ifdef UNUSED
/*
- * radiostatus - print the radio status returned by the server
+ * saveconfig - dump ntp server configuration to server file
*/
-/*ARGSUSED*/
static void
-radiostatus(
+saveconfig(
struct parse *pcmd,
FILE *fp
)
{
- char *datap;
+ const char *datap;
int res;
int dsize;
u_short rstatus;
- res = doquery(CTL_OP_READCLOCK, 0, 0, 0, (char *)0, &rstatus,
- &dsize, &datap);
-
- if (res != 0)
+ if (0 == pcmd->nargs)
return;
+
+ res = doquery(CTL_OP_SAVECONFIG, 0, 1,
+ strlen(pcmd->argval[0].string),
+ pcmd->argval[0].string, &rstatus, &dsize,
+ &datap);
- if (numhosts > 1)
- (void) fprintf(fp, "server=%s ", currenthost);
- if (dsize == 0) {
- (void) fprintf(fp, "No radio status string returned\n");
+ if (res != 0)
return;
- }
- asciize(dsize, datap, fp);
+ if (0 == dsize)
+ fprintf(fp, "(no response message, curiously)");
+ else
+ fprintf(fp, "%.*s", dsize, datap);
}
-#endif /* UNUSED */
+
+#ifdef UNUSED
/*
- * pstatus - print peer status returned by the server
+ * radiostatus - print the radio status returned by the server
*/
+/*ARGSUSED*/
static void
-pstatus(
+radiostatus(
struct parse *pcmd,
FILE *fp
)
{
char *datap;
int res;
- int associd;
int dsize;
u_short rstatus;
- /* HMS: uval? */
- if ((associd = checkassocid(pcmd->argval[0].uval)) == 0)
- return;
-
- res = doquery(CTL_OP_READSTAT, associd, 0, 0, (char *)0, &rstatus,
+ res = doquery(CTL_OP_READCLOCK, 0, 0, 0, (char *)0, &rstatus,
&dsize, &datap);
if (res != 0)
@@ -1180,16 +1425,13 @@ pstatus(
if (numhosts > 1)
(void) fprintf(fp, "server=%s ", currenthost);
if (dsize == 0) {
- (void) fprintf(fp,
- "No information returned for association %u\n",
- associd);
+ (void) fprintf(fp, "No radio status string returned\n");
return;
}
- (void) fprintf(fp,"assID=%d ",associd);
- printvars(dsize, datap, (int)rstatus, TYPE_PEER, fp);
+ asciize(dsize, datap, fp);
}
-
+#endif /* UNUSED */
/*
* when - print how long its been since his last packet arrived
@@ -1220,6 +1462,7 @@ when(
static char *
prettyinterval(
char *buf,
+ size_t cb,
long diff
)
{
@@ -1230,40 +1473,38 @@ prettyinterval(
}
if (diff <= 2048) {
- (void) sprintf(buf, "%ld", (long int)diff);
+ snprintf(buf, cb, "%ld", diff);
return buf;
}
diff = (diff + 29) / 60;
if (diff <= 300) {
- (void) sprintf(buf, "%ldm", (long int)diff);
+ snprintf(buf, cb, "%ldm", diff);
return buf;
}
diff = (diff + 29) / 60;
if (diff <= 96) {
- (void) sprintf(buf, "%ldh", (long int)diff);
+ snprintf(buf, cb, "%ldh", diff);
return buf;
}
diff = (diff + 11) / 24;
- (void) sprintf(buf, "%ldd", (long int)diff);
+ snprintf(buf, cb, "%ldd", diff);
return buf;
}
static char
decodeaddrtype(
- struct sockaddr_storage *sock
+ sockaddr_u *sock
)
{
char ch = '-';
u_int32 dummy;
- struct sockaddr_in6 *sin6;
- switch(sock->ss_family) {
+ switch(AF(sock)) {
case AF_INET:
- dummy = ((struct sockaddr_in *)sock)->sin_addr.s_addr;
- dummy = ntohl(dummy);
+ dummy = SRCADR(sock);
ch = (char)(((dummy&0xf0000000)==0xe0000000) ? 'm' :
((dummy&0x000000ff)==0x000000ff) ? 'b' :
((dummy&0xffffffff)==0x7f000001) ? 'l' :
@@ -1271,8 +1512,7 @@ decodeaddrtype(
'u');
break;
case AF_INET6:
- sin6 = (struct sockaddr_in6 *)sock;
- if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
+ if (IN6_IS_ADDR_MULTICAST(PSOCK_ADDR6(sock)))
ch = 'm';
else
ch = 'u';
@@ -1288,54 +1528,62 @@ decodeaddrtype(
* A list of variables required by the peers command
*/
struct varlist opeervarlist[] = {
- { "srcadr", 0 }, /* 0 */
- { "dstadr", 0 }, /* 1 */
- { "stratum", 0 }, /* 2 */
- { "hpoll", 0 }, /* 3 */
- { "ppoll", 0 }, /* 4 */
- { "reach", 0 }, /* 5 */
- { "delay", 0 }, /* 6 */
- { "offset", 0 }, /* 7 */
- { "jitter", 0 }, /* 8 */
- { "dispersion", 0 }, /* 9 */
- { "rec", 0 }, /* 10 */
- { "reftime", 0 }, /* 11 */
- { "srcport", 0 }, /* 12 */
+ { "srcadr", 0 }, /* 0 */
+ { "dstadr", 0 }, /* 1 */
+ { "stratum", 0 }, /* 2 */
+ { "hpoll", 0 }, /* 3 */
+ { "ppoll", 0 }, /* 4 */
+ { "reach", 0 }, /* 5 */
+ { "delay", 0 }, /* 6 */
+ { "offset", 0 }, /* 7 */
+ { "jitter", 0 }, /* 8 */
+ { "dispersion", 0 }, /* 9 */
+ { "rec", 0 }, /* 10 */
+ { "reftime", 0 }, /* 11 */
+ { "srcport", 0 }, /* 12 */
+ { "hmode", 0 }, /* 13 */
{ 0, 0 }
};
struct varlist peervarlist[] = {
- { "srcadr", 0 }, /* 0 */
- { "refid", 0 }, /* 1 */
- { "stratum", 0 }, /* 2 */
- { "hpoll", 0 }, /* 3 */
- { "ppoll", 0 }, /* 4 */
- { "reach", 0 }, /* 5 */
- { "delay", 0 }, /* 6 */
- { "offset", 0 }, /* 7 */
- { "jitter", 0 }, /* 8 */
- { "dispersion", 0 }, /* 9 */
- { "rec", 0 }, /* 10 */
- { "reftime", 0 }, /* 11 */
- { "srcport", 0 }, /* 12 */
+ { "srcadr", 0 }, /* 0 */
+ { "refid", 0 }, /* 1 */
+ { "stratum", 0 }, /* 2 */
+ { "hpoll", 0 }, /* 3 */
+ { "ppoll", 0 }, /* 4 */
+ { "reach", 0 }, /* 5 */
+ { "delay", 0 }, /* 6 */
+ { "offset", 0 }, /* 7 */
+ { "jitter", 0 }, /* 8 */
+ { "dispersion", 0 }, /* 9 */
+ { "rec", 0 }, /* 10 */
+ { "reftime", 0 }, /* 11 */
+ { "srcport", 0 }, /* 12 */
+ { "hmode", 0 }, /* 13 */
+ { "srchost", 0 }, /* 14 */
+ { 0, 0 }
+};
+
+struct varlist apeervarlist[] = {
+ { "srcadr", 0 }, /* 0 */
+ { "refid", 0 }, /* 1 */
+ { "assid", 0 }, /* 2 */
+ { "stratum", 0 }, /* 3 */
+ { "hpoll", 0 }, /* 4 */
+ { "ppoll", 0 }, /* 5 */
+ { "reach", 0 }, /* 6 */
+ { "delay", 0 }, /* 7 */
+ { "offset", 0 }, /* 8 */
+ { "jitter", 0 }, /* 9 */
+ { "dispersion", 0 }, /* 10 */
+ { "rec", 0 }, /* 11 */
+ { "reftime", 0 }, /* 12 */
+ { "srcport", 0 }, /* 13 */
+ { "hmode", 0 }, /* 14 */
+ { "srchost", 0 }, /* 15 */
{ 0, 0 }
};
-#define HAVE_SRCADR 0
-#define HAVE_DSTADR 1
-#define HAVE_REFID 1
-#define HAVE_STRATUM 2
-#define HAVE_HPOLL 3
-#define HAVE_PPOLL 4
-#define HAVE_REACH 5
-#define HAVE_DELAY 6
-#define HAVE_OFFSET 7
-#define HAVE_JITTER 8
-#define HAVE_DISPERSION 9
-#define HAVE_REC 10
-#define HAVE_REFTIME 11
-#define HAVE_SRCPORT 12
-#define MAXHAVE 13
/*
* Decode an incoming data buffer and print a line in the peer list
@@ -1346,20 +1594,29 @@ doprintpeers(
int associd,
int rstatus,
int datalen,
- char *data,
+ const char *data,
FILE *fp,
int af
)
{
char *name;
char *value = NULL;
- int i;
int c;
-
- struct sockaddr_storage srcadr;
- struct sockaddr_storage dstadr;
+ int len;
+ int have_srchost;
+ int have_dstadr;
+ int have_da_rid;
+ int have_jitter;
+ sockaddr_u srcadr;
+ sockaddr_u dstadr;
+ sockaddr_u dum_store;
+ sockaddr_u refidadr;
+ long hmode = 0;
u_long srcport = 0;
- char *dstadr_refid = "0.0.0.0";
+ u_int32 u32;
+ const char *dstadr_refid = "0.0.0.0";
+ const char *serverlocal;
+ size_t drlen;
u_long stratum = 0;
long ppoll = 0;
long hpoll = 0;
@@ -1371,180 +1628,244 @@ doprintpeers(
l_fp reftime;
l_fp rec;
l_fp ts;
- u_char havevar[MAXHAVE];
u_long poll_sec;
char type = '?';
- char refid_string[10];
char whenbuf[8], pollbuf[8];
char clock_name[LENHOSTNAME];
- memset((char *)havevar, 0, sizeof(havevar));
get_systime(&ts);
- memset((char *)&srcadr, 0, sizeof(struct sockaddr_storage));
- memset((char *)&dstadr, 0, sizeof(struct sockaddr_storage));
-
- /* Initialize by zeroing out estimate variables */
- memset((char *)&estoffset, 0, sizeof(l_fp));
- memset((char *)&estdelay, 0, sizeof(l_fp));
- memset((char *)&estjitter, 0, sizeof(l_fp));
- memset((char *)&estdisp, 0, sizeof(l_fp));
+ have_srchost = FALSE;
+ have_dstadr = FALSE;
+ have_da_rid = FALSE;
+ have_jitter = FALSE;
+ ZERO_SOCK(&srcadr);
+ ZERO_SOCK(&dstadr);
+ clock_name[0] = '\0';
+ ZERO(estoffset);
+ ZERO(estdelay);
+ ZERO(estjitter);
+ ZERO(estdisp);
while (nextvar(&datalen, &data, &name, &value)) {
- struct sockaddr_storage dum_store;
-
- i = findvar(name, peer_var, 1);
- if (i == 0)
- continue; /* don't know this one */
- switch (i) {
- case CP_SRCADR:
- if (decodenetnum(value, &srcadr))
- havevar[HAVE_SRCADR] = 1;
- break;
- case CP_DSTADR:
- if (decodenetnum(value, &dum_store))
+ if (!strcmp("srcadr", name) ||
+ !strcmp("peeradr", name)) {
+ if (!decodenetnum(value, &srcadr))
+ fprintf(stderr, "malformed %s=%s\n",
+ name, value);
+ } else if (!strcmp("srchost", name)) {
+ if (pvl == peervarlist || pvl == apeervarlist) {
+ len = strlen(value);
+ if (2 < len &&
+ (size_t)len < sizeof(clock_name)) {
+ /* strip quotes */
+ value++;
+ len -= 2;
+ memcpy(clock_name, value, len);
+ clock_name[len] = '\0';
+ have_srchost = TRUE;
+ }
+ }
+ } else if (!strcmp("dstadr", name)) {
+ if (decodenetnum(value, &dum_store)) {
type = decodeaddrtype(&dum_store);
- if (pvl == opeervarlist) {
- if (decodenetnum(value, &dstadr)) {
- havevar[HAVE_DSTADR] = 1;
- dstadr_refid = stoa(&dstadr);
+ have_dstadr = TRUE;
+ dstadr = dum_store;
+ if (pvl == opeervarlist) {
+ have_da_rid = TRUE;
+ dstadr_refid = trunc_left(stoa(&dstadr), 15);
}
}
- break;
- case CP_REFID:
+ } else if (!strcmp("hmode", name)) {
+ decodeint(value, &hmode);
+ } else if (!strcmp("refid", name)) {
if (pvl == peervarlist) {
- havevar[HAVE_REFID] = 1;
- if (*value == '\0') {
- dstadr_refid = "0.0.0.0";
- } else if ((int)strlen(value) <= 4) {
- refid_string[0] = '.';
- (void) strcpy(&refid_string[1], value);
- i = strlen(refid_string);
- refid_string[i] = '.';
- refid_string[i+1] = '\0';
- dstadr_refid = refid_string;
- } else if (decodenetnum(value, &dstadr)) {
- if (SOCKNUL(&dstadr))
+ have_da_rid = TRUE;
+ drlen = strlen(value);
+ if (0 == drlen) {
+ dstadr_refid = "";
+ } else if (drlen <= 4) {
+ ZERO(u32);
+ memcpy(&u32, value, drlen);
+ dstadr_refid = refid_str(u32, 1);
+ } else if (decodenetnum(value, &refidadr)) {
+ if (SOCK_UNSPEC(&refidadr))
dstadr_refid = "0.0.0.0";
- else if ((dstadr.ss_family == AF_INET)
- && ISREFCLOCKADR(&dstadr))
- dstadr_refid =
- refnumtoa(&dstadr);
+ else if (ISREFCLOCKADR(&refidadr))
+ dstadr_refid =
+ refnumtoa(&refidadr);
else
dstadr_refid =
- stoa(&dstadr);
+ stoa(&refidadr);
} else {
- havevar[HAVE_REFID] = 0;
+ have_da_rid = FALSE;
+ }
+ } else if (pvl == apeervarlist) {
+ have_da_rid = TRUE;
+ drlen = strlen(value);
+ if (0 == drlen) {
+ dstadr_refid = "";
+ } else if (drlen <= 4) {
+ ZERO(u32);
+ memcpy(&u32, value, drlen);
+ dstadr_refid = refid_str(u32, 1);
+ //fprintf(stderr, "apeervarlist S1 refid: value=<%s>\n", value);
+ } else if (decodenetnum(value, &refidadr)) {
+ if (SOCK_UNSPEC(&refidadr))
+ dstadr_refid = "0.0.0.0";
+ else if (ISREFCLOCKADR(&refidadr))
+ dstadr_refid =
+ refnumtoa(&refidadr);
+ else {
+ char *buf = emalloc(10);
+ int i = ntohl(refidadr.sa4.sin_addr.s_addr);
+
+ snprintf(buf, 10,
+ "%0x", i);
+ dstadr_refid = buf;
+ //fprintf(stderr, "apeervarlist refid: value=<%x>\n", i);
+ }
+ //fprintf(stderr, "apeervarlist refid: value=<%s>\n", value);
+ } else {
+ have_da_rid = FALSE;
}
}
- break;
- case CP_STRATUM:
- if (decodeuint(value, &stratum))
- havevar[HAVE_STRATUM] = 1;
- break;
- case CP_HPOLL:
- if (decodeint(value, &hpoll)) {
- havevar[HAVE_HPOLL] = 1;
- if (hpoll < 0)
- hpoll = NTP_MINPOLL;
- }
- break;
- case CP_PPOLL:
- if (decodeint(value, &ppoll)) {
- havevar[HAVE_PPOLL] = 1;
- if (ppoll < 0)
- ppoll = NTP_MINPOLL;
- }
- break;
- case CP_REACH:
- if (decodeuint(value, &reach))
- havevar[HAVE_REACH] = 1;
- break;
- case CP_DELAY:
- if (decodetime(value, &estdelay))
- havevar[HAVE_DELAY] = 1;
- break;
- case CP_OFFSET:
- if (decodetime(value, &estoffset))
- havevar[HAVE_OFFSET] = 1;
- break;
- case CP_JITTER:
- if (pvl == peervarlist)
- if (decodetime(value, &estjitter))
- havevar[HAVE_JITTER] = 1;
- break;
- case CP_DISPERSION:
- if (decodetime(value, &estdisp))
- havevar[HAVE_DISPERSION] = 1;
- break;
- case CP_REC:
- if (decodets(value, &rec))
- havevar[HAVE_REC] = 1;
- break;
- case CP_SRCPORT:
- if (decodeuint(value, &srcport))
- havevar[HAVE_SRCPORT] = 1;
- break;
- case CP_REFTIME:
- havevar[HAVE_REFTIME] = 1;
+ } else if (!strcmp("stratum", name)) {
+ decodeuint(value, &stratum);
+ } else if (!strcmp("hpoll", name)) {
+ if (decodeint(value, &hpoll) && hpoll < 0)
+ hpoll = NTP_MINPOLL;
+ } else if (!strcmp("ppoll", name)) {
+ if (decodeint(value, &ppoll) && ppoll < 0)
+ ppoll = NTP_MINPOLL;
+ } else if (!strcmp("reach", name)) {
+ decodeuint(value, &reach);
+ } else if (!strcmp("delay", name)) {
+ decodetime(value, &estdelay);
+ } else if (!strcmp("offset", name)) {
+ decodetime(value, &estoffset);
+ } else if (!strcmp("jitter", name)) {
+ if ((pvl == peervarlist || pvl == apeervarlist)
+ && decodetime(value, &estjitter))
+ have_jitter = 1;
+ } else if (!strcmp("rootdisp", name) ||
+ !strcmp("dispersion", name)) {
+ decodetime(value, &estdisp);
+ } else if (!strcmp("rec", name)) {
+ decodets(value, &rec);
+ } else if (!strcmp("srcport", name) ||
+ !strcmp("peerport", name)) {
+ decodeuint(value, &srcport);
+ } else if (!strcmp("reftime", name)) {
if (!decodets(value, &reftime))
L_CLR(&reftime);
- break;
- default:
- break;
+ } else {
+ // fprintf(stderr, "UNRECOGNIZED name=%s ", name);
}
}
/*
- * Check to see if the srcport is NTP's port. If not this probably
- * isn't a valid peer association.
+ * hmode gives the best guidance for the t column. If the response
+ * did not include hmode we'll use the old decodeaddrtype() result.
*/
- if (havevar[HAVE_SRCPORT] && srcport != NTP_PORT)
- return (1);
+ switch (hmode) {
+
+ case MODE_BCLIENT:
+ /* broadcastclient or multicastclient */
+ type = 'b';
+ break;
+
+ case MODE_BROADCAST:
+ /* broadcast or multicast server */
+ if (IS_MCAST(&srcadr))
+ type = 'M';
+ else
+ type = 'B';
+ break;
+
+ case MODE_CLIENT:
+ if (ISREFCLOCKADR(&srcadr))
+ type = 'l'; /* local refclock*/
+ else if (SOCK_UNSPEC(&srcadr))
+ type = 'p'; /* pool */
+ else if (IS_MCAST(&srcadr))
+ type = 'a'; /* manycastclient */
+ else
+ type = 'u'; /* unicast */
+ break;
+
+ case MODE_ACTIVE:
+ type = 's'; /* symmetric active */
+ break; /* configured */
+
+ case MODE_PASSIVE:
+ type = 'S'; /* symmetric passive */
+ break; /* ephemeral */
+ }
/*
* Got everything, format the line
*/
- poll_sec = 1<<max(min3(ppoll, hpoll, NTP_MAXPOLL), NTP_MINPOLL);
+ poll_sec = 1 << min(ppoll, hpoll);
if (pktversion > NTP_OLDVERSION)
c = flash3[CTL_PEER_STATVAL(rstatus) & 0x7];
else
c = flash2[CTL_PEER_STATVAL(rstatus) & 0x3];
- if (numhosts > 1)
- (void) fprintf(fp, "%-*s ", maxhostlen, currenthost);
- if (af == 0 || srcadr.ss_family == af){
- strcpy(clock_name, nntohost(&srcadr));
-
- (void) fprintf(fp,
- "%c%-15.15s %-15.15s %2ld %c %4.4s %4.4s %3lo %7.7s %8.7s %7.7s\n",
- c, clock_name, dstadr_refid, stratum, type,
- prettyinterval(whenbuf, when(&ts, &rec, &reftime)),
- prettyinterval(pollbuf, (int)poll_sec), reach,
- lfptoms(&estdelay, 3), lfptoms(&estoffset, 3),
- havevar[HAVE_JITTER] ? lfptoms(&estjitter, 3) :
- lfptoms(&estdisp, 3));
+ if (numhosts > 1) {
+ if ((pvl == peervarlist || pvl == apeervarlist)
+ && have_dstadr) {
+ serverlocal = nntohost_col(&dstadr,
+ (size_t)min(LIB_BUFLENGTH - 1, maxhostlen),
+ TRUE);
+ } else {
+ if (currenthostisnum)
+ serverlocal = trunc_left(currenthost,
+ maxhostlen);
+ else
+ serverlocal = currenthost;
+ }
+ fprintf(fp, "%-*s ", (int)maxhostlen, serverlocal);
+ }
+ if (AF_UNSPEC == af || AF(&srcadr) == af) {
+ if (!have_srchost)
+ strlcpy(clock_name, nntohost(&srcadr),
+ sizeof(clock_name));
+ if (wideremote && 15 < strlen(clock_name))
+ fprintf(fp, "%c%s\n ", c, clock_name);
+ else
+ fprintf(fp, "%c%-15.15s ", c, clock_name);
+ if (!have_da_rid) {
+ drlen = 0;
+ } else {
+ drlen = strlen(dstadr_refid);
+ makeascii(drlen, dstadr_refid, fp);
+ }
+ if (pvl == apeervarlist) {
+ while (drlen++ < 9)
+ fputc(' ', fp);
+ fprintf(fp, "%-6d", associd);
+ } else {
+ while (drlen++ < 15)
+ fputc(' ', fp);
+ }
+ fprintf(fp,
+ " %2ld %c %4.4s %4.4s %3lo %7.7s %8.7s %7.7s\n",
+ stratum, type,
+ prettyinterval(whenbuf, sizeof(whenbuf),
+ when(&ts, &rec, &reftime)),
+ prettyinterval(pollbuf, sizeof(pollbuf),
+ (int)poll_sec),
+ reach, lfptoms(&estdelay, 3),
+ lfptoms(&estoffset, 3),
+ (have_jitter)
+ ? lfptoms(&estjitter, 3)
+ : lfptoms(&estdisp, 3));
return (1);
}
else
return(1);
}
-#undef HAVE_SRCADR
-#undef HAVE_DSTADR
-#undef HAVE_STRATUM
-#undef HAVE_PPOLL
-#undef HAVE_HPOLL
-#undef HAVE_REACH
-#undef HAVE_ESTDELAY
-#undef HAVE_ESTOFFSET
-#undef HAVE_JITTER
-#undef HAVE_ESTDISP
-#undef HAVE_REFID
-#undef HAVE_REC
-#undef HAVE_SRCPORT
-#undef HAVE_REFTIME
-#undef MAXHAVE
-
/*
* dogetpeers - given an association ID, read and print the spreadsheet
@@ -1553,12 +1874,12 @@ doprintpeers(
static int
dogetpeers(
struct varlist *pvl,
- int associd,
+ associd_t associd,
FILE *fp,
int af
)
{
- char *datap;
+ const char *datap;
int res;
int dsize;
u_short rstatus;
@@ -1570,7 +1891,7 @@ dogetpeers(
/*
* Damn fuzzballs
*/
- res = doquery(CTL_OP_READVAR, associd, 0, 0, (char *)0, &rstatus,
+ res = doquery(CTL_OP_READVAR, associd, 0, 0, NULL, &rstatus,
&dsize, &datap);
#endif
@@ -1579,14 +1900,15 @@ dogetpeers(
if (dsize == 0) {
if (numhosts > 1)
- (void) fprintf(stderr, "server=%s ", currenthost);
- (void) fprintf(stderr,
- "***No information returned for association %d\n",
- associd);
+ fprintf(stderr, "server=%s ", currenthost);
+ fprintf(stderr,
+ "***No information returned for association %u\n",
+ associd);
return 0;
}
- return doprintpeers(pvl, associd, (int)rstatus, dsize, datap, fp, af);
+ return doprintpeers(pvl, associd, (int)rstatus, dsize, datap,
+ fp, af);
}
@@ -1600,36 +1922,99 @@ dopeers(
int af
)
{
- register int i;
- char fullname[LENHOSTNAME];
- struct sockaddr_storage netnum;
+ u_int u;
+ char fullname[LENHOSTNAME];
+ sockaddr_u netnum;
+ const char * name_or_num;
+ size_t sl;
if (!dogetassoc(fp))
return;
- for (i = 0; i < numhosts; ++i) {
- if (getnetnum(chosts[i], &netnum, fullname, af))
- if ((int)strlen(fullname) > maxhostlen)
- maxhostlen = strlen(fullname);
+ for (u = 0; u < numhosts; u++) {
+ if (getnetnum(chosts[u].name, &netnum, fullname, af)) {
+ name_or_num = nntohost(&netnum);
+ sl = strlen(name_or_num);
+ maxhostlen = max(maxhostlen, sl);
+ }
}
if (numhosts > 1)
- (void) fprintf(fp, "%-*.*s ", maxhostlen, maxhostlen, "server");
- (void) fprintf(fp,
- " remote refid st t when poll reach delay offset jitter\n");
+ fprintf(fp, "%-*.*s ", (int)maxhostlen, (int)maxhostlen,
+ "server (local)");
+ fprintf(fp,
+ " remote refid st t when poll reach delay offset jitter\n");
if (numhosts > 1)
- for (i = 0; i <= maxhostlen; ++i)
- (void) fprintf(fp, "=");
- (void) fprintf(fp,
- "==============================================================================\n");
+ for (u = 0; u <= maxhostlen; u++)
+ fprintf(fp, "=");
+ fprintf(fp,
+ "==============================================================================\n");
- for (i = 0; i < numassoc; i++) {
+ for (u = 0; u < numassoc; u++) {
if (!showall &&
- !(CTL_PEER_STATVAL(assoc_cache[i].status)
- & (CTL_PST_CONFIG|CTL_PST_REACH)))
+ !(CTL_PEER_STATVAL(assoc_cache[u].status)
+ & (CTL_PST_CONFIG|CTL_PST_REACH))) {
+ if (debug)
+ fprintf(stderr, "eliding [%d]\n",
+ (int)assoc_cache[u].assid);
continue;
- if (!dogetpeers(peervarlist, (int)assoc_cache[i].assid, fp, af)) {
+ }
+ if (!dogetpeers(peervarlist, (int)assoc_cache[u].assid,
+ fp, af))
return;
+ }
+ return;
+}
+
+
+/*
+ * doapeers - print a peer spreadsheet with assocIDs
+ */
+static void
+doapeers(
+ int showall,
+ FILE *fp,
+ int af
+ )
+{
+ u_int u;
+ char fullname[LENHOSTNAME];
+ sockaddr_u netnum;
+ const char * name_or_num;
+ size_t sl;
+
+ if (!dogetassoc(fp))
+ return;
+
+ for (u = 0; u < numhosts; u++) {
+ if (getnetnum(chosts[u].name, &netnum, fullname, af)) {
+ name_or_num = nntohost(&netnum);
+ sl = strlen(name_or_num);
+ maxhostlen = max(maxhostlen, sl);
+ }
+ }
+ if (numhosts > 1)
+ fprintf(fp, "%-*.*s ", (int)maxhostlen, (int)maxhostlen,
+ "server (local)");
+ fprintf(fp,
+ " remote refid assid st t when poll reach delay offset jitter\n");
+ if (numhosts > 1)
+ for (u = 0; u <= maxhostlen; u++)
+ fprintf(fp, "=");
+ fprintf(fp,
+ "==============================================================================\n");
+
+ for (u = 0; u < numassoc; u++) {
+ if (!showall &&
+ !(CTL_PEER_STATVAL(assoc_cache[u].status)
+ & (CTL_PST_CONFIG|CTL_PST_REACH))) {
+ if (debug)
+ fprintf(stderr, "eliding [%d]\n",
+ (int)assoc_cache[u].assid);
+ continue;
}
+ if (!dogetpeers(apeervarlist, (int)assoc_cache[u].assid,
+ fp, af))
+ return;
}
return;
}
@@ -1658,6 +2043,28 @@ peers(
/*
+ * apeers - print a peer spreadsheet, with assocIDs
+ */
+/*ARGSUSED*/
+static void
+apeers(
+ struct parse *pcmd,
+ FILE *fp
+ )
+{
+ int af = 0;
+
+ if (pcmd->nargs == 1) {
+ if (pcmd->argval->ival == 6)
+ af = AF_INET6;
+ else
+ af = AF_INET;
+ }
+ doapeers(0, fp, af);
+}
+
+
+/*
* lpeers - print a peer spreadsheet including all fuzzball peers
*/
/*ARGSUSED*/
@@ -1689,36 +2096,36 @@ doopeers(
int af
)
{
- register int i;
+ u_int i;
char fullname[LENHOSTNAME];
- struct sockaddr_storage netnum;
+ sockaddr_u netnum;
if (!dogetassoc(fp))
return;
for (i = 0; i < numhosts; ++i) {
- if (getnetnum(chosts[i], &netnum, fullname, af))
- if ((int)strlen(fullname) > maxhostlen)
+ if (getnetnum(chosts[i].name, &netnum, fullname, af))
+ if (strlen(fullname) > maxhostlen)
maxhostlen = strlen(fullname);
}
if (numhosts > 1)
- (void) fprintf(fp, "%-*.*s ", maxhostlen, maxhostlen, "server");
- (void) fprintf(fp,
- " remote local st t when poll reach delay offset disp\n");
+ fprintf(fp, "%-*.*s ", (int)maxhostlen, (int)maxhostlen,
+ "server");
+ fprintf(fp,
+ " remote local st t when poll reach delay offset disp\n");
if (numhosts > 1)
for (i = 0; i <= maxhostlen; ++i)
- (void) fprintf(fp, "=");
- (void) fprintf(fp,
- "==============================================================================\n");
+ fprintf(fp, "=");
+ fprintf(fp,
+ "==============================================================================\n");
for (i = 0; i < numassoc; i++) {
if (!showall &&
- !(CTL_PEER_STATVAL(assoc_cache[i].status)
- & (CTL_PST_CONFIG|CTL_PST_REACH)))
+ !(CTL_PEER_STATVAL(assoc_cache[i].status) &
+ (CTL_PST_CONFIG | CTL_PST_REACH)))
continue;
- if (!dogetpeers(opeervarlist, (int)assoc_cache[i].assid, fp, af)) {
+ if (!dogetpeers(opeervarlist, assoc_cache[i].assid, fp, af))
return;
- }
}
return;
}
@@ -1766,3 +2173,1842 @@ lopeers(
}
doopeers(1, fp, af);
}
+
+
+/*
+ * config - send a configuration command to a remote host
+ */
+static void
+config (
+ struct parse *pcmd,
+ FILE *fp
+ )
+{
+ const char *cfgcmd;
+ u_short rstatus;
+ int rsize;
+ const char *rdata;
+ char *resp;
+ int res;
+ int col;
+ int i;
+
+ cfgcmd = pcmd->argval[0].string;
+
+ if (debug > 2)
+ fprintf(stderr,
+ "In Config\n"
+ "Keyword = %s\n"
+ "Command = %s\n", pcmd->keyword, cfgcmd);
+
+ res = doquery(CTL_OP_CONFIGURE, 0, 1, strlen(cfgcmd), cfgcmd,
+ &rstatus, &rsize, &rdata);
+
+ if (res != 0)
+ return;
+
+ if (rsize > 0 && '\n' == rdata[rsize - 1])
+ rsize--;
+
+ resp = emalloc(rsize + 1);
+ memcpy(resp, rdata, rsize);
+ resp[rsize] = '\0';
+
+ col = -1;
+ if (1 == sscanf(resp, "column %d syntax error", &col)
+ && col >= 0 && (size_t)col <= strlen(cfgcmd) + 1) {
+ if (interactive) {
+ printf("______"); /* "ntpq> " */
+ printf("________"); /* ":config " */
+ } else
+ printf("%s\n", cfgcmd);
+ for (i = 1; i < col; i++)
+ putchar('_');
+ printf("^\n");
+ }
+ printf("%s\n", resp);
+ free(resp);
+}
+
+
+/*
+ * config_from_file - remotely configure an ntpd daemon using the
+ * specified configuration file
+ * SK: This function is a kludge at best and is full of bad design
+ * bugs:
+ * 1. ntpq uses UDP, which means that there is no guarantee of in-order,
+ * error-free delivery.
+ * 2. The maximum length of a packet is constrained, and as a result, the
+ * maximum length of a line in a configuration file is constrained.
+ * Longer lines will lead to unpredictable results.
+ * 3. Since this function is sending a line at a time, we can't update
+ * the control key through the configuration file (YUCK!!)
+ */
+static void
+config_from_file (
+ struct parse *pcmd,
+ FILE *fp
+ )
+{
+ u_short rstatus;
+ int rsize;
+ const char *rdata;
+ int res;
+ FILE *config_fd;
+ char config_cmd[MAXLINE];
+ size_t config_len;
+ int i;
+ int retry_limit;
+
+ if (debug > 2)
+ fprintf(stderr,
+ "In Config\n"
+ "Keyword = %s\n"
+ "Filename = %s\n", pcmd->keyword,
+ pcmd->argval[0].string);
+
+ config_fd = fopen(pcmd->argval[0].string, "r");
+ if (NULL == config_fd) {
+ printf("ERROR!! Couldn't open file: %s\n",
+ pcmd->argval[0].string);
+ return;
+ }
+
+ printf("Sending configuration file, one line at a time.\n");
+ i = 0;
+ while (fgets(config_cmd, MAXLINE, config_fd) != NULL) {
+ config_len = strlen(config_cmd);
+ /* ensure even the last line has newline, if possible */
+ if (config_len > 0 &&
+ config_len + 2 < sizeof(config_cmd) &&
+ '\n' != config_cmd[config_len - 1])
+ config_cmd[config_len++] = '\n';
+ ++i;
+ retry_limit = 2;
+ do
+ res = doquery(CTL_OP_CONFIGURE, 0, 1,
+ strlen(config_cmd), config_cmd,
+ &rstatus, &rsize, &rdata);
+ while (res != 0 && retry_limit--);
+ if (res != 0) {
+ printf("Line No: %d query failed: %s", i,
+ config_cmd);
+ printf("Subsequent lines not sent.\n");
+ fclose(config_fd);
+ return;
+ }
+
+ if (rsize > 0 && '\n' == rdata[rsize - 1])
+ rsize--;
+ if (rsize > 0 && '\r' == rdata[rsize - 1])
+ rsize--;
+ printf("Line No: %d %.*s: %s", i, rsize, rdata,
+ config_cmd);
+ }
+ printf("Done sending file\n");
+ fclose(config_fd);
+}
+
+
+static int
+fetch_nonce(
+ char * nonce,
+ size_t cb_nonce
+ )
+{
+ const char nonce_eq[] = "nonce=";
+ int qres;
+ u_short rstatus;
+ int rsize;
+ const char * rdata;
+ int chars;
+
+ /*
+ * Retrieve a nonce specific to this client to demonstrate to
+ * ntpd that we're capable of receiving responses to our source
+ * IP address, and thereby unlikely to be forging the source.
+ */
+ qres = doquery(CTL_OP_REQ_NONCE, 0, 0, 0, NULL, &rstatus,
+ &rsize, &rdata);
+ if (qres) {
+ fprintf(stderr, "nonce request failed\n");
+ return FALSE;
+ }
+
+ if ((size_t)rsize <= sizeof(nonce_eq) - 1 ||
+ strncmp(rdata, nonce_eq, sizeof(nonce_eq) - 1)) {
+ fprintf(stderr, "unexpected nonce response format: %.*s\n",
+ rsize, rdata);
+ return FALSE;
+ }
+ chars = rsize - (sizeof(nonce_eq) - 1);
+ if (chars >= (int)cb_nonce)
+ return FALSE;
+ memcpy(nonce, rdata + sizeof(nonce_eq) - 1, chars);
+ nonce[chars] = '\0';
+ while (chars > 0 &&
+ ('\r' == nonce[chars - 1] || '\n' == nonce[chars - 1])) {
+ chars--;
+ nonce[chars] = '\0';
+ }
+
+ return TRUE;
+}
+
+
+/*
+ * add_mru Add and entry to mru list, hash table, and allocate
+ * and return a replacement.
+ * This is a helper for collect_mru_list().
+ */
+static mru *
+add_mru(
+ mru *add
+ )
+{
+ u_short hash;
+ mru *mon;
+ mru *unlinked;
+
+
+ hash = NTP_HASH_ADDR(&add->addr);
+ /* see if we have it among previously received entries */
+ for (mon = hash_table[hash]; mon != NULL; mon = mon->hlink)
+ if (SOCK_EQ(&mon->addr, &add->addr))
+ break;
+ if (mon != NULL) {
+ if (!L_ISGEQ(&add->first, &mon->first)) {
+ fprintf(stderr,
+ "add_mru duplicate %s new first ts %08x.%08x precedes prior %08x.%08x\n",
+ sptoa(&add->addr), add->last.l_ui,
+ add->last.l_uf, mon->last.l_ui,
+ mon->last.l_uf);
+ exit(1);
+ }
+ UNLINK_DLIST(mon, mlink);
+ UNLINK_SLIST(unlinked, hash_table[hash], mon, hlink, mru);
+ NTP_INSIST(unlinked == mon);
+ mru_dupes++;
+ TRACE(2, ("(updated from %08x.%08x) ", mon->last.l_ui,
+ mon->last.l_uf));
+ }
+ LINK_DLIST(mru_list, add, mlink);
+ LINK_SLIST(hash_table[hash], add, hlink);
+ TRACE(2, ("add_mru %08x.%08x c %d m %d v %d rest %x first %08x.%08x %s\n",
+ add->last.l_ui, add->last.l_uf, add->count,
+ (int)add->mode, (int)add->ver, (u_int)add->rs,
+ add->first.l_ui, add->first.l_uf, sptoa(&add->addr)));
+ /* if we didn't update an existing entry, alloc replacement */
+ if (NULL == mon) {
+ mon = emalloc(sizeof(*mon));
+ mru_count++;
+ }
+ ZERO(*mon);
+
+ return mon;
+}
+
+
+/* MGOT macro is specific to collect_mru_list() */
+#define MGOT(bit) \
+ do { \
+ got |= (bit); \
+ if (MRU_GOT_ALL == got) { \
+ got = 0; \
+ mon = add_mru(mon); \
+ ci++; \
+ } \
+ } while (0)
+
+
+void
+mrulist_ctrl_c_hook(void)
+{
+ mrulist_interrupted = TRUE;
+}
+
+
+static int
+collect_mru_list(
+ const char * parms,
+ l_fp * pnow
+ )
+{
+ const u_int sleep_msecs = 5;
+ static int ntpd_row_limit = MRU_ROW_LIMIT;
+ int c_mru_l_rc; /* this function's return code */
+ u_char got; /* MRU_GOT_* bits */
+ time_t next_report;
+ size_t cb;
+ mru *mon;
+ mru *head;
+ mru *recent;
+ int list_complete;
+ char nonce[128];
+ char buf[128];
+ char req_buf[CTL_MAX_DATA_LEN];
+ char *req;
+ char *req_end;
+ int chars;
+ int qres;
+ u_short rstatus;
+ int rsize;
+ const char *rdata;
+ int limit;
+ int frags;
+ int cap_frags;
+ char *tag;
+ char *val;
+ int si; /* server index in response */
+ int ci; /* client (our) index for validation */
+ int ri; /* request index (.# suffix) */
+ int mv;
+ l_fp newest;
+ l_fp last_older;
+ sockaddr_u addr_older;
+ int have_now;
+ int have_addr_older;
+ int have_last_older;
+ u_int restarted_count;
+ u_int nonce_uses;
+ u_short hash;
+ mru *unlinked;
+
+ if (!fetch_nonce(nonce, sizeof(nonce)))
+ return FALSE;
+
+ nonce_uses = 0;
+ restarted_count = 0;
+ mru_count = 0;
+ INIT_DLIST(mru_list, mlink);
+ cb = NTP_HASH_SIZE * sizeof(*hash_table);
+ NTP_INSIST(NULL == hash_table);
+ hash_table = emalloc_zero(cb);
+
+ c_mru_l_rc = FALSE;
+ list_complete = FALSE;
+ have_now = FALSE;
+ cap_frags = TRUE;
+ got = 0;
+ ri = 0;
+ cb = sizeof(*mon);
+ mon = emalloc_zero(cb);
+ ZERO(*pnow);
+ ZERO(last_older);
+ mrulist_interrupted = FALSE;
+ set_ctrl_c_hook(&mrulist_ctrl_c_hook);
+ fprintf(stderr,
+ "Ctrl-C will stop MRU retrieval and display partial results.\n");
+ fflush(stderr);
+ next_report = time(NULL) + MRU_REPORT_SECS;
+
+ limit = min(3 * MAXFRAGS, ntpd_row_limit);
+ frags = MAXFRAGS;
+ snprintf(req_buf, sizeof(req_buf), "nonce=%s, frags=%d%s",
+ nonce, frags, parms);
+ nonce_uses++;
+
+ while (TRUE) {
+ if (debug)
+ fprintf(stderr, "READ_MRU parms: %s\n", req_buf);
+
+ qres = doqueryex(CTL_OP_READ_MRU, 0, 0, strlen(req_buf),
+ req_buf, &rstatus, &rsize, &rdata, TRUE);
+
+ if (CERR_UNKNOWNVAR == qres && ri > 0) {
+ /*
+ * None of the supplied prior entries match, so
+ * toss them from our list and try again.
+ */
+ if (debug)
+ fprintf(stderr,
+ "no overlap between %d prior entries and server MRU list\n",
+ ri);
+ while (ri--) {
+ recent = HEAD_DLIST(mru_list, mlink);
+ NTP_INSIST(recent != NULL);
+ if (debug)
+ fprintf(stderr,
+ "tossing prior entry %s to resync\n",
+ sptoa(&recent->addr));
+ UNLINK_DLIST(recent, mlink);
+ hash = NTP_HASH_ADDR(&recent->addr);
+ UNLINK_SLIST(unlinked, hash_table[hash],
+ recent, hlink, mru);
+ NTP_INSIST(unlinked == recent);
+ free(recent);
+ mru_count--;
+ }
+ if (NULL == HEAD_DLIST(mru_list, mlink)) {
+ restarted_count++;
+ if (restarted_count > 8) {
+ fprintf(stderr,
+ "Giving up after 8 restarts from the beginning.\n"
+ "With high-traffic NTP servers, this can occur if the\n"
+ "MRU list is limited to less than about 16 seconds' of\n"
+ "entries. See the 'mru' ntp.conf directive to adjust.\n");
+ goto cleanup_return;
+ }
+ if (debug)
+ fprintf(stderr,
+ "---> Restarting from the beginning, retry #%u\n",
+ restarted_count);
+ }
+ } else if (CERR_UNKNOWNVAR == qres) {
+ fprintf(stderr,
+ "CERR_UNKNOWNVAR from ntpd but no priors given.\n");
+ goto cleanup_return;
+ } else if (CERR_BADVALUE == qres) {
+ if (cap_frags) {
+ cap_frags = FALSE;
+ if (debug)
+ fprintf(stderr,
+ "Reverted to row limit from fragments limit.\n");
+ } else {
+ /* ntpd has lower cap on row limit */
+ ntpd_row_limit--;
+ limit = min(limit, ntpd_row_limit);
+ if (debug)
+ fprintf(stderr,
+ "Row limit reduced to %d following CERR_BADVALUE.\n",
+ limit);
+ }
+ } else if (ERR_INCOMPLETE == qres ||
+ ERR_TIMEOUT == qres) {
+ /*
+ * Reduce the number of rows/frags requested by
+ * half to recover from lost response fragments.
+ */
+ if (cap_frags) {
+ frags = max(2, frags / 2);
+ if (debug)
+ fprintf(stderr,
+ "Frag limit reduced to %d following incomplete response.\n",
+ frags);
+ } else {
+ limit = max(2, limit / 2);
+ if (debug)
+ fprintf(stderr,
+ "Row limit reduced to %d following incomplete response.\n",
+ limit);
+ }
+ } else if (qres) {
+ show_error_msg(qres, 0);
+ goto cleanup_return;
+ }
+ /*
+ * This is a cheap cop-out implementation of rawmode
+ * output for mrulist. A better approach would be to
+ * dump similar output after the list is collected by
+ * ntpq with a continuous sequence of indexes. This
+ * cheap approach has indexes resetting to zero for
+ * each query/response, and duplicates are not
+ * coalesced.
+ */
+ if (!qres && rawmode)
+ printvars(rsize, rdata, rstatus, TYPE_SYS, 1, stdout);
+ ci = 0;
+ have_addr_older = FALSE;
+ have_last_older = FALSE;
+ while (!qres && nextvar(&rsize, &rdata, &tag, &val)) {
+ if (debug > 1)
+ fprintf(stderr, "nextvar gave: %s = %s\n",
+ tag, val);
+ switch(tag[0]) {
+
+ case 'a':
+ if (!strcmp(tag, "addr.older")) {
+ if (!have_last_older) {
+ fprintf(stderr,
+ "addr.older %s before last.older\n",
+ val);
+ goto cleanup_return;
+ }
+ if (!decodenetnum(val, &addr_older)) {
+ fprintf(stderr,
+ "addr.older %s garbled\n",
+ val);
+ goto cleanup_return;
+ }
+ hash = NTP_HASH_ADDR(&addr_older);
+ for (recent = hash_table[hash];
+ recent != NULL;
+ recent = recent->hlink)
+ if (ADDR_PORT_EQ(
+ &addr_older,
+ &recent->addr))
+ break;
+ if (NULL == recent) {
+ fprintf(stderr,
+ "addr.older %s not in hash table\n",
+ val);
+ goto cleanup_return;
+ }
+ if (!L_ISEQU(&last_older,
+ &recent->last)) {
+ fprintf(stderr,
+ "last.older %08x.%08x mismatches %08x.%08x expected.\n",
+ last_older.l_ui,
+ last_older.l_uf,
+ recent->last.l_ui,
+ recent->last.l_uf);
+ goto cleanup_return;
+ }
+ have_addr_older = TRUE;
+ } else if (1 != sscanf(tag, "addr.%d", &si)
+ || si != ci)
+ goto nomatch;
+ else if (decodenetnum(val, &mon->addr))
+ MGOT(MRU_GOT_ADDR);
+ break;
+
+ case 'l':
+ if (!strcmp(tag, "last.older")) {
+ if ('0' != val[0] ||
+ 'x' != val[1] ||
+ !hextolfp(val + 2, &last_older)) {
+ fprintf(stderr,
+ "last.older %s garbled\n",
+ val);
+ goto cleanup_return;
+ }
+ have_last_older = TRUE;
+ } else if (!strcmp(tag, "last.newest")) {
+ if (0 != got) {
+ fprintf(stderr,
+ "last.newest %s before complete row, got = 0x%x\n",
+ val, (u_int)got);
+ goto cleanup_return;
+ }
+ if (!have_now) {
+ fprintf(stderr,
+ "last.newest %s before now=\n",
+ val);
+ goto cleanup_return;
+ }
+ head = HEAD_DLIST(mru_list, mlink);
+ if (NULL != head) {
+ if ('0' != val[0] ||
+ 'x' != val[1] ||
+ !hextolfp(val + 2, &newest) ||
+ !L_ISEQU(&newest,
+ &head->last)) {
+ fprintf(stderr,
+ "last.newest %s mismatches %08x.%08x",
+ val,
+ head->last.l_ui,
+ head->last.l_uf);
+ goto cleanup_return;
+ }
+ }
+ list_complete = TRUE;
+ } else if (1 != sscanf(tag, "last.%d", &si) ||
+ si != ci || '0' != val[0] ||
+ 'x' != val[1] ||
+ !hextolfp(val + 2, &mon->last)) {
+ goto nomatch;
+ } else {
+ MGOT(MRU_GOT_LAST);
+ /*
+ * allow interrupted retrieval,
+ * using most recent retrieved
+ * entry's last seen timestamp
+ * as the end of operation.
+ */
+ *pnow = mon->last;
+ }
+ break;
+
+ case 'f':
+ if (1 != sscanf(tag, "first.%d", &si) ||
+ si != ci || '0' != val[0] ||
+ 'x' != val[1] ||
+ !hextolfp(val + 2, &mon->first))
+ goto nomatch;
+ MGOT(MRU_GOT_FIRST);
+ break;
+
+ case 'n':
+ if (!strcmp(tag, "nonce")) {
+ strlcpy(nonce, val, sizeof(nonce));
+ nonce_uses = 0;
+ break; /* case */
+ } else if (strcmp(tag, "now") ||
+ '0' != val[0] ||
+ 'x' != val[1] ||
+ !hextolfp(val + 2, pnow))
+ goto nomatch;
+ have_now = TRUE;
+ break;
+
+ case 'c':
+ if (1 != sscanf(tag, "ct.%d", &si) ||
+ si != ci ||
+ 1 != sscanf(val, "%d", &mon->count)
+ || mon->count < 1)
+ goto nomatch;
+ MGOT(MRU_GOT_COUNT);
+ break;
+
+ case 'm':
+ if (1 != sscanf(tag, "mv.%d", &si) ||
+ si != ci ||
+ 1 != sscanf(val, "%d", &mv))
+ goto nomatch;
+ mon->mode = PKT_MODE(mv);
+ mon->ver = PKT_VERSION(mv);
+ MGOT(MRU_GOT_MV);
+ break;
+
+ case 'r':
+ if (1 != sscanf(tag, "rs.%d", &si) ||
+ si != ci ||
+ 1 != sscanf(val, "0x%hx", &mon->rs))
+ goto nomatch;
+ MGOT(MRU_GOT_RS);
+ break;
+
+ default:
+ nomatch:
+ /* empty stmt */ ;
+ /* ignore unknown tags */
+ }
+ }
+ if (have_now)
+ list_complete = TRUE;
+ if (list_complete) {
+ NTP_INSIST(0 == ri || have_addr_older);
+ }
+ if (mrulist_interrupted) {
+ printf("mrulist retrieval interrupted by operator.\n"
+ "Displaying partial client list.\n");
+ fflush(stdout);
+ }
+ if (list_complete || mrulist_interrupted) {
+ fprintf(stderr,
+ "\rRetrieved %u unique MRU entries and %u updates.\n",
+ mru_count, mru_dupes);
+ fflush(stderr);
+ break;
+ }
+ if (time(NULL) >= next_report) {
+ next_report += MRU_REPORT_SECS;
+ fprintf(stderr, "\r%u (%u updates) ", mru_count,
+ mru_dupes);
+ fflush(stderr);
+ }
+
+ /*
+ * Snooze for a bit between queries to let ntpd catch
+ * up with other duties.
+ */
+#ifdef SYS_WINNT
+ Sleep(sleep_msecs);
+#elif !defined(HAVE_NANOSLEEP)
+ sleep((sleep_msecs / 1000) + 1);
+#else
+ {
+ struct timespec interv = { 0,
+ 1000 * sleep_msecs };
+ nanosleep(&interv, NULL);
+ }
+#endif
+ /*
+ * If there were no errors, increase the number of rows
+ * to a maximum of 3 * MAXFRAGS (the most packets ntpq
+ * can handle in one response), on the assumption that
+ * no less than 3 rows fit in each packet, capped at
+ * our best guess at the server's row limit.
+ */
+ if (!qres) {
+ if (cap_frags) {
+ frags = min(MAXFRAGS, frags + 1);
+ } else {
+ limit = min3(3 * MAXFRAGS,
+ ntpd_row_limit,
+ max(limit + 1,
+ limit * 33 / 32));
+ }
+ }
+ /*
+ * prepare next query with as many address and last-seen
+ * timestamps as will fit in a single packet.
+ */
+ req = req_buf;
+ req_end = req_buf + sizeof(req_buf);
+#define REQ_ROOM (req_end - req)
+ snprintf(req, REQ_ROOM, "nonce=%s, %s=%d%s", nonce,
+ (cap_frags)
+ ? "frags"
+ : "limit",
+ (cap_frags)
+ ? frags
+ : limit,
+ parms);
+ req += strlen(req);
+ nonce_uses++;
+ if (nonce_uses >= 4) {
+ if (!fetch_nonce(nonce, sizeof(nonce)))
+ goto cleanup_return;
+ nonce_uses = 0;
+ }
+
+
+ for (ri = 0, recent = HEAD_DLIST(mru_list, mlink);
+ recent != NULL;
+ ri++, recent = NEXT_DLIST(mru_list, recent, mlink)) {
+
+ snprintf(buf, sizeof(buf),
+ ", addr.%d=%s, last.%d=0x%08x.%08x",
+ ri, sptoa(&recent->addr), ri,
+ recent->last.l_ui, recent->last.l_uf);
+ chars = strlen(buf);
+ if (REQ_ROOM - chars < 1)
+ break;
+ memcpy(req, buf, chars + 1);
+ req += chars;
+ }
+ }
+
+ set_ctrl_c_hook(NULL);
+ c_mru_l_rc = TRUE;
+ goto retain_hash_table;
+
+cleanup_return:
+ free(hash_table);
+ hash_table = NULL;
+
+retain_hash_table:
+ if (mon != NULL)
+ free(mon);
+
+ return c_mru_l_rc;
+}
+
+
+/*
+ * qcmp_mru_addr - sort MRU entries by remote address.
+ *
+ * All IPv4 addresses sort before any IPv6, addresses are sorted by
+ * value within address family.
+ */
+static int
+qcmp_mru_addr(
+ const void *v1,
+ const void *v2
+ )
+{
+ const mru * const * ppm1 = v1;
+ const mru * const * ppm2 = v2;
+ const mru * pm1;
+ const mru * pm2;
+ u_short af1;
+ u_short af2;
+ size_t cmplen;
+ size_t addr_off;
+
+ pm1 = *ppm1;
+ pm2 = *ppm2;
+
+ af1 = AF(&pm1->addr);
+ af2 = AF(&pm2->addr);
+
+ if (af1 != af2)
+ return (AF_INET == af1)
+ ? -1
+ : 1;
+
+ cmplen = SIZEOF_INADDR(af1);
+ addr_off = (AF_INET == af1)
+ ? offsetof(struct sockaddr_in, sin_addr)
+ : offsetof(struct sockaddr_in6, sin6_addr);
+
+ return memcmp((const char *)&pm1->addr + addr_off,
+ (const char *)&pm2->addr + addr_off,
+ cmplen);
+}
+
+
+static int
+qcmp_mru_r_addr(
+ const void *v1,
+ const void *v2
+ )
+{
+ return -qcmp_mru_addr(v1, v2);
+}
+
+
+/*
+ * qcmp_mru_count - sort MRU entries by times seen (hit count).
+ */
+static int
+qcmp_mru_count(
+ const void *v1,
+ const void *v2
+ )
+{
+ const mru * const * ppm1 = v1;
+ const mru * const * ppm2 = v2;
+ const mru * pm1;
+ const mru * pm2;
+
+ pm1 = *ppm1;
+ pm2 = *ppm2;
+
+ return (pm1->count < pm2->count)
+ ? -1
+ : ((pm1->count == pm2->count)
+ ? 0
+ : 1);
+}
+
+
+static int
+qcmp_mru_r_count(
+ const void *v1,
+ const void *v2
+ )
+{
+ return -qcmp_mru_count(v1, v2);
+}
+
+
+/*
+ * qcmp_mru_avgint - sort MRU entries by average interval.
+ */
+static int
+qcmp_mru_avgint(
+ const void *v1,
+ const void *v2
+ )
+{
+ const mru * const * ppm1 = v1;
+ const mru * const * ppm2 = v2;
+ const mru * pm1;
+ const mru * pm2;
+ l_fp interval;
+ double avg1;
+ double avg2;
+
+ pm1 = *ppm1;
+ pm2 = *ppm2;
+
+ interval = pm1->last;
+ L_SUB(&interval, &pm1->first);
+ LFPTOD(&interval, avg1);
+ avg1 /= pm1->count;
+
+ interval = pm2->last;
+ L_SUB(&interval, &pm2->first);
+ LFPTOD(&interval, avg2);
+ avg2 /= pm2->count;
+
+ if (avg1 < avg2)
+ return -1;
+ else if (avg1 > avg2)
+ return 1;
+
+ /* secondary sort on lstint - rarely tested */
+ if (L_ISEQU(&pm1->last, &pm2->last))
+ return 0;
+ else if (L_ISGEQ(&pm1->last, &pm2->last))
+ return -1;
+ else
+ return 1;
+}
+
+
+static int
+qcmp_mru_r_avgint(
+ const void *v1,
+ const void *v2
+ )
+{
+ return -qcmp_mru_avgint(v1, v2);
+}
+
+
+/*
+ * mrulist - ntpq's mrulist command to fetch an arbitrarily large Most
+ * Recently Used (seen) remote address list from ntpd.
+ *
+ * Similar to ntpdc's monlist command, but not limited to a single
+ * request/response, and thereby not limited to a few hundred remote
+ * addresses.
+ *
+ * See ntpd/ntp_control.c read_mru_list() for comments on the way
+ * CTL_OP_READ_MRU is designed to be used.
+ *
+ * mrulist intentionally differs from monlist in the way the avgint
+ * column is calculated. monlist includes the time after the last
+ * packet from the client until the monlist query time in the average,
+ * while mrulist excludes it. That is, monlist's average interval grows
+ * over time for remote addresses not heard from in some time, while it
+ * remains unchanged in mrulist. This also affects the avgint value for
+ * entries representing a single packet, with identical first and last
+ * timestamps. mrulist shows 0 avgint, monlist shows a value identical
+ * to lstint.
+ */
+static void
+mrulist(
+ struct parse * pcmd,
+ FILE * fp
+ )
+{
+ const char mincount_eq[] = "mincount=";
+ const char resall_eq[] = "resall=";
+ const char resany_eq[] = "resany=";
+ const char maxlstint_eq[] = "maxlstint=";
+ const char laddr_eq[] = "laddr=";
+ const char sort_eq[] = "sort=";
+ mru_sort_order order;
+ size_t n;
+ char parms_buf[128];
+ char buf[24];
+ char *parms;
+ const char *arg;
+ size_t cb;
+ mru **sorted;
+ mru **ppentry;
+ mru *recent;
+ l_fp now;
+ l_fp interval;
+ double favgint;
+ double flstint;
+ int avgint;
+ int lstint;
+ size_t i;
+
+ order = MRUSORT_DEF;
+ parms_buf[0] = '\0';
+ parms = parms_buf;
+ for (i = 0; i < pcmd->nargs; i++) {
+ arg = pcmd->argval[i].string;
+ if (arg != NULL) {
+ cb = strlen(arg) + 1;
+ if ((!strncmp(resall_eq, arg, sizeof(resall_eq)
+ - 1) || !strncmp(resany_eq, arg,
+ sizeof(resany_eq) - 1) || !strncmp(
+ mincount_eq, arg, sizeof(mincount_eq) - 1)
+ || !strncmp(laddr_eq, arg, sizeof(laddr_eq)
+ - 1) || !strncmp(maxlstint_eq, arg,
+ sizeof(laddr_eq) - 1)) && parms + cb + 2 <=
+ parms_buf + sizeof(parms_buf)) {
+ /* these are passed intact to ntpd */
+ memcpy(parms, ", ", 2);
+ parms += 2;
+ memcpy(parms, arg, cb);
+ parms += cb - 1;
+ } else if (!strncmp(sort_eq, arg,
+ sizeof(sort_eq) - 1)) {
+ arg += sizeof(sort_eq) - 1;
+ for (n = 0;
+ n < COUNTOF(mru_sort_keywords);
+ n++)
+ if (!strcmp(mru_sort_keywords[n],
+ arg))
+ break;
+ if (n < COUNTOF(mru_sort_keywords))
+ order = n;
+ } else if (!strcmp("limited", arg) ||
+ !strcmp("kod", arg)) {
+ /* transform to resany=... */
+ snprintf(buf, sizeof(buf),
+ ", resany=0x%x",
+ ('k' == arg[0])
+ ? RES_KOD
+ : RES_LIMITED);
+ cb = 1 + strlen(buf);
+ if (parms + cb <
+ parms_buf + sizeof(parms_buf)) {
+ memcpy(parms, buf, cb);
+ parms += cb - 1;
+ }
+ } else
+ fprintf(stderr,
+ "ignoring unrecognized mrulist parameter: %s\n",
+ arg);
+ }
+ }
+ parms = parms_buf;
+
+ if (!collect_mru_list(parms, &now))
+ return;
+
+ /* display the results */
+ if (rawmode)
+ goto cleanup_return;
+
+ /* construct an array of entry pointers in default order */
+ sorted = eallocarray(mru_count, sizeof(*sorted));
+ ppentry = sorted;
+ if (MRUSORT_R_DEF != order) {
+ ITER_DLIST_BEGIN(mru_list, recent, mlink, mru)
+ NTP_INSIST(ppentry < sorted + mru_count);
+ *ppentry = recent;
+ ppentry++;
+ ITER_DLIST_END()
+ } else {
+ REV_ITER_DLIST_BEGIN(mru_list, recent, mlink, mru)
+ NTP_INSIST(ppentry < sorted + mru_count);
+ *ppentry = recent;
+ ppentry++;
+ REV_ITER_DLIST_END()
+ }
+
+ if (ppentry - sorted != (int)mru_count) {
+ fprintf(stderr,
+ "mru_count %u should match MRU list depth %ld.\n",
+ mru_count, (long)(ppentry - sorted));
+ free(sorted);
+ goto cleanup_return;
+ }
+
+ /* re-sort sorted[] if not default or reverse default */
+ if (MRUSORT_R_DEF < order)
+ qsort(sorted, mru_count, sizeof(sorted[0]),
+ mru_qcmp_table[order]);
+
+ printf( "lstint avgint rstr r m v count rport remote address\n"
+ "==============================================================================\n");
+ /* '=' x 78 */
+ for (ppentry = sorted; ppentry < sorted + mru_count; ppentry++) {
+ recent = *ppentry;
+ interval = now;
+ L_SUB(&interval, &recent->last);
+ LFPTOD(&interval, flstint);
+ lstint = (int)(flstint + 0.5);
+ interval = recent->last;
+ L_SUB(&interval, &recent->first);
+ LFPTOD(&interval, favgint);
+ favgint /= recent->count;
+ avgint = (int)(favgint + 0.5);
+ fprintf(fp, "%6d %6d %4hx %c %d %d %6d %5u %s\n",
+ lstint, avgint, recent->rs,
+ (RES_KOD & recent->rs)
+ ? 'K'
+ : (RES_LIMITED & recent->rs)
+ ? 'L'
+ : '.',
+ (int)recent->mode, (int)recent->ver,
+ recent->count, SRCPORT(&recent->addr),
+ nntohost(&recent->addr));
+ if (showhostnames)
+ fflush(fp);
+ }
+ fflush(fp);
+ if (debug) {
+ fprintf(stderr,
+ "--- completed, freeing sorted[] pointers\n");
+ fflush(stderr);
+ }
+ free(sorted);
+
+cleanup_return:
+ if (debug) {
+ fprintf(stderr, "... freeing MRU entries\n");
+ fflush(stderr);
+ }
+ ITER_DLIST_BEGIN(mru_list, recent, mlink, mru)
+ free(recent);
+ ITER_DLIST_END()
+ if (debug) {
+ fprintf(stderr, "... freeing hash_table[]\n");
+ fflush(stderr);
+ }
+ free(hash_table);
+ hash_table = NULL;
+ INIT_DLIST(mru_list, mlink);
+}
+
+
+/*
+ * validate_ifnum - helper for ifstats()
+ *
+ * Ensures rows are received in order and complete.
+ */
+static void
+validate_ifnum(
+ FILE * fp,
+ u_int ifnum,
+ int * pfields,
+ ifstats_row * prow
+ )
+{
+ if (prow->ifnum == ifnum)
+ return;
+ if (prow->ifnum + 1 <= ifnum) {
+ if (*pfields < IFSTATS_FIELDS)
+ fprintf(fp, "Warning: incomplete row with %d (of %d) fields",
+ *pfields, IFSTATS_FIELDS);
+ *pfields = 0;
+ prow->ifnum = ifnum;
+ return;
+ }
+ fprintf(stderr,
+ "received if index %u, have %d of %d fields for index %u, aborting.\n",
+ ifnum, *pfields, IFSTATS_FIELDS, prow->ifnum);
+ exit(1);
+}
+
+
+/*
+ * another_ifstats_field - helper for ifstats()
+ *
+ * If all fields for the row have been received, print it.
+ */
+static void
+another_ifstats_field(
+ int * pfields,
+ ifstats_row * prow,
+ FILE * fp
+ )
+{
+ u_int ifnum;
+
+ (*pfields)++;
+ /* we understand 12 tags */
+ if (IFSTATS_FIELDS > *pfields)
+ return;
+ /*
+ " interface name send\n"
+ " # address/broadcast drop flag ttl mc received sent failed peers uptime\n"
+ "==============================================================================\n");
+ */
+ fprintf(fp,
+ "%3u %-24.24s %c %4x %3d %2d %6d %6d %6d %5d %8d\n"
+ " %s\n",
+ prow->ifnum, prow->name,
+ (prow->enabled)
+ ? '.'
+ : 'D',
+ prow->flags, prow->ttl, prow->mcast_count,
+ prow->received, prow->sent, prow->send_errors,
+ prow->peer_count, prow->uptime, sptoa(&prow->addr));
+ if (!SOCK_UNSPEC(&prow->bcast))
+ fprintf(fp, " %s\n", sptoa(&prow->bcast));
+ ifnum = prow->ifnum;
+ ZERO(*prow);
+ prow->ifnum = ifnum;
+}
+
+
+/*
+ * ifstats - ntpq -c ifstats modeled on ntpdc -c ifstats.
+ */
+static void
+ifstats(
+ struct parse * pcmd,
+ FILE * fp
+ )
+{
+ const char addr_fmt[] = "addr.%u";
+ const char bcast_fmt[] = "bcast.%u";
+ const char en_fmt[] = "en.%u"; /* enabled */
+ const char flags_fmt[] = "flags.%u";
+ const char mc_fmt[] = "mc.%u"; /* mcast count */
+ const char name_fmt[] = "name.%u";
+ const char pc_fmt[] = "pc.%u"; /* peer count */
+ const char rx_fmt[] = "rx.%u";
+ const char tl_fmt[] = "tl.%u"; /* ttl */
+ const char tx_fmt[] = "tx.%u";
+ const char txerr_fmt[] = "txerr.%u";
+ const char up_fmt[] = "up.%u"; /* uptime */
+ const char * datap;
+ int qres;
+ int dsize;
+ u_short rstatus;
+ char * tag;
+ char * val;
+ int fields;
+ u_int ui;
+ ifstats_row row;
+ int comprende;
+ size_t len;
+
+ qres = doquery(CTL_OP_READ_ORDLIST_A, 0, TRUE, 0, NULL, &rstatus,
+ &dsize, &datap);
+ if (qres) /* message already displayed */
+ return;
+
+ fprintf(fp,
+ " interface name send\n"
+ " # address/broadcast drop flag ttl mc received sent failed peers uptime\n"
+ "==============================================================================\n");
+ /* '=' x 78 */
+
+ ZERO(row);
+ fields = 0;
+ ui = 0;
+ while (nextvar(&dsize, &datap, &tag, &val)) {
+ if (debug > 1)
+ fprintf(stderr, "nextvar gave: %s = %s\n", tag,
+ (NULL == val)
+ ? ""
+ : val);
+ comprende = FALSE;
+ switch(tag[0]) {
+
+ case 'a':
+ if (1 == sscanf(tag, addr_fmt, &ui) &&
+ decodenetnum(val, &row.addr))
+ comprende = TRUE;
+ break;
+
+ case 'b':
+ if (1 == sscanf(tag, bcast_fmt, &ui) &&
+ (NULL == val ||
+ decodenetnum(val, &row.bcast)))
+ comprende = TRUE;
+ break;
+
+ case 'e':
+ if (1 == sscanf(tag, en_fmt, &ui) &&
+ 1 == sscanf(val, "%d", &row.enabled))
+ comprende = TRUE;
+ break;
+
+ case 'f':
+ if (1 == sscanf(tag, flags_fmt, &ui) &&
+ 1 == sscanf(val, "0x%x", &row.flags))
+ comprende = TRUE;
+ break;
+
+ case 'm':
+ if (1 == sscanf(tag, mc_fmt, &ui) &&
+ 1 == sscanf(val, "%d", &row.mcast_count))
+ comprende = TRUE;
+ break;
+
+ case 'n':
+ if (1 == sscanf(tag, name_fmt, &ui)) {
+ /* strip quotes */
+ INSIST(val);
+ len = strlen(val);
+ if (len >= 2 &&
+ len - 2 < sizeof(row.name)) {
+ len -= 2;
+ memcpy(row.name, val + 1, len);
+ row.name[len] = '\0';
+ comprende = TRUE;
+ }
+ }
+ break;
+
+ case 'p':
+ if (1 == sscanf(tag, pc_fmt, &ui) &&
+ 1 == sscanf(val, "%d", &row.peer_count))
+ comprende = TRUE;
+ break;
+
+ case 'r':
+ if (1 == sscanf(tag, rx_fmt, &ui) &&
+ 1 == sscanf(val, "%d", &row.received))
+ comprende = TRUE;
+ break;
+
+ case 't':
+ if (1 == sscanf(tag, tl_fmt, &ui) &&
+ 1 == sscanf(val, "%d", &row.ttl))
+ comprende = TRUE;
+ else if (1 == sscanf(tag, tx_fmt, &ui) &&
+ 1 == sscanf(val, "%d", &row.sent))
+ comprende = TRUE;
+ else if (1 == sscanf(tag, txerr_fmt, &ui) &&
+ 1 == sscanf(val, "%d", &row.send_errors))
+ comprende = TRUE;
+ break;
+
+ case 'u':
+ if (1 == sscanf(tag, up_fmt, &ui) &&
+ 1 == sscanf(val, "%d", &row.uptime))
+ comprende = TRUE;
+ break;
+ }
+
+ if (comprende) {
+ /* error out if rows out of order */
+ validate_ifnum(fp, ui, &fields, &row);
+ /* if the row is complete, print it */
+ another_ifstats_field(&fields, &row, fp);
+ }
+ }
+ if (fields != IFSTATS_FIELDS)
+ fprintf(fp, "Warning: incomplete row with %d (of %d) fields",
+ fields, IFSTATS_FIELDS);
+
+ fflush(fp);
+}
+
+
+/*
+ * validate_reslist_idx - helper for reslist()
+ *
+ * Ensures rows are received in order and complete.
+ */
+static void
+validate_reslist_idx(
+ FILE * fp,
+ u_int idx,
+ int * pfields,
+ reslist_row * prow
+ )
+{
+ if (prow->idx == idx)
+ return;
+ if (prow->idx + 1 == idx) {
+ if (*pfields < RESLIST_FIELDS)
+ fprintf(fp, "Warning: incomplete row with %d (of %d) fields",
+ *pfields, RESLIST_FIELDS);
+ *pfields = 0;
+ prow->idx = idx;
+ return;
+ }
+ fprintf(stderr,
+ "received reslist index %u, have %d of %d fields for index %u, aborting.\n",
+ idx, *pfields, RESLIST_FIELDS, prow->idx);
+ exit(1);
+}
+
+
+/*
+ * another_reslist_field - helper for reslist()
+ *
+ * If all fields for the row have been received, print it.
+ */
+static void
+another_reslist_field(
+ int * pfields,
+ reslist_row * prow,
+ FILE * fp
+ )
+{
+ char addrmaskstr[128];
+ int prefix; /* subnet mask as prefix bits count */
+ u_int idx;
+
+ (*pfields)++;
+ /* we understand 4 tags */
+ if (RESLIST_FIELDS > *pfields)
+ return;
+
+ prefix = sockaddr_masktoprefixlen(&prow->mask);
+ if (prefix >= 0)
+ snprintf(addrmaskstr, sizeof(addrmaskstr), "%s/%d",
+ stoa(&prow->addr), prefix);
+ else
+ snprintf(addrmaskstr, sizeof(addrmaskstr), "%s %s",
+ stoa(&prow->addr), stoa(&prow->mask));
+
+ /*
+ " hits addr/prefix or addr mask\n"
+ " restrictions\n"
+ "==============================================================================\n");
+ */
+ fprintf(fp,
+ "%10lu %s\n"
+ " %s\n",
+ prow->hits, addrmaskstr, prow->flagstr);
+ idx = prow->idx;
+ ZERO(*prow);
+ prow->idx = idx;
+}
+
+
+/*
+ * reslist - ntpq -c reslist modeled on ntpdc -c reslist.
+ */
+static void
+reslist(
+ struct parse * pcmd,
+ FILE * fp
+ )
+{
+ const char addr_fmtu[] = "addr.%u";
+ const char mask_fmtu[] = "mask.%u";
+ const char hits_fmt[] = "hits.%u";
+ const char flags_fmt[] = "flags.%u";
+ const char qdata[] = "addr_restrictions";
+ const int qdata_chars = COUNTOF(qdata) - 1;
+ const char * datap;
+ int qres;
+ int dsize;
+ u_short rstatus;
+ char * tag;
+ char * val;
+ int fields;
+ u_int ui;
+ reslist_row row;
+ int comprende;
+ size_t len;
+
+ qres = doquery(CTL_OP_READ_ORDLIST_A, 0, TRUE, qdata_chars,
+ qdata, &rstatus, &dsize, &datap);
+ if (qres) /* message already displayed */
+ return;
+
+ fprintf(fp,
+ " hits addr/prefix or addr mask\n"
+ " restrictions\n"
+ "==============================================================================\n");
+ /* '=' x 78 */
+
+ ZERO(row);
+ fields = 0;
+ ui = 0;
+ while (nextvar(&dsize, &datap, &tag, &val)) {
+ if (debug > 1)
+ fprintf(stderr, "nextvar gave: %s = %s\n", tag,
+ (NULL == val)
+ ? ""
+ : val);
+ comprende = FALSE;
+ switch(tag[0]) {
+
+ case 'a':
+ if (1 == sscanf(tag, addr_fmtu, &ui) &&
+ decodenetnum(val, &row.addr))
+ comprende = TRUE;
+ break;
+
+ case 'f':
+ if (1 == sscanf(tag, flags_fmt, &ui)) {
+ if (NULL == val) {
+ row.flagstr[0] = '\0';
+ comprende = TRUE;
+ } else {
+ len = strlen(val);
+ memcpy(row.flagstr, val, len);
+ row.flagstr[len] = '\0';
+ comprende = TRUE;
+ }
+ }
+ break;
+
+ case 'h':
+ if (1 == sscanf(tag, hits_fmt, &ui) &&
+ 1 == sscanf(val, "%lu", &row.hits))
+ comprende = TRUE;
+ break;
+
+ case 'm':
+ if (1 == sscanf(tag, mask_fmtu, &ui) &&
+ decodenetnum(val, &row.mask))
+ comprende = TRUE;
+ break;
+ }
+
+ if (comprende) {
+ /* error out if rows out of order */
+ validate_reslist_idx(fp, ui, &fields, &row);
+ /* if the row is complete, print it */
+ another_reslist_field(&fields, &row, fp);
+ }
+ }
+ if (fields != RESLIST_FIELDS)
+ fprintf(fp, "Warning: incomplete row with %d (of %d) fields",
+ fields, RESLIST_FIELDS);
+
+ fflush(fp);
+}
+
+
+/*
+ * collect_display_vdc
+ */
+static void
+collect_display_vdc(
+ associd_t as,
+ vdc * table,
+ int decodestatus,
+ FILE * fp
+ )
+{
+ static const char * const suf[2] = { "adr", "port" };
+ static const char * const leapbits[4] = { "00", "01",
+ "10", "11" };
+ struct varlist vl[MAXLIST];
+ char tagbuf[32];
+ vdc *pvdc;
+ u_short rstatus;
+ int rsize;
+ const char *rdata;
+ int qres;
+ char *tag;
+ char *val;
+ u_int n;
+ size_t len;
+ int match;
+ u_long ul;
+ int vtype;
+
+ ZERO(vl);
+ for (pvdc = table; pvdc->tag != NULL; pvdc++) {
+ ZERO(pvdc->v);
+ if (NTP_ADD != pvdc->type) {
+ doaddvlist(vl, pvdc->tag);
+ } else {
+ for (n = 0; n < COUNTOF(suf); n++) {
+ snprintf(tagbuf, sizeof(tagbuf), "%s%s",
+ pvdc->tag, suf[n]);
+ doaddvlist(vl, tagbuf);
+ }
+ }
+ }
+ qres = doquerylist(vl, CTL_OP_READVAR, as, 0, &rstatus, &rsize,
+ &rdata);
+ doclearvlist(vl);
+ if (qres)
+ return; /* error msg already displayed */
+
+ /*
+ * iterate over the response variables filling vdc_table with
+ * the retrieved values.
+ */
+ while (nextvar(&rsize, &rdata, &tag, &val)) {
+ if (NULL == val)
+ continue;
+ n = 0;
+ for (pvdc = table; pvdc->tag != NULL; pvdc++) {
+ len = strlen(pvdc->tag);
+ if (strncmp(tag, pvdc->tag, len))
+ continue;
+ if (NTP_ADD != pvdc->type) {
+ if ('\0' != tag[len])
+ continue;
+ break;
+ }
+ match = FALSE;
+ for (n = 0; n < COUNTOF(suf); n++) {
+ if (strcmp(tag + len, suf[n]))
+ continue;
+ match = TRUE;
+ break;
+ }
+ if (match)
+ break;
+ }
+ if (NULL == pvdc->tag)
+ continue;
+ switch (pvdc->type) {
+
+ case NTP_STR:
+ /* strip surrounding double quotes */
+ if ('"' == val[0]) {
+ len = strlen(val);
+ if (len > 0 && '"' == val[len - 1]) {
+ val[len - 1] = '\0';
+ val++;
+ }
+ }
+ /* fallthru */
+ case NTP_MODE: /* fallthru */
+ case NTP_2BIT:
+ pvdc->v.str = estrdup(val);
+ break;
+
+ case NTP_LFP:
+ decodets(val, &pvdc->v.lfp);
+ break;
+
+ case NTP_ADP:
+ if (!decodenetnum(val, &pvdc->v.sau))
+ fprintf(stderr, "malformed %s=%s\n",
+ pvdc->tag, val);
+ break;
+
+ case NTP_ADD:
+ if (0 == n) { /* adr */
+ if (!decodenetnum(val, &pvdc->v.sau))
+ fprintf(stderr,
+ "malformed %s=%s\n",
+ pvdc->tag, val);
+ } else { /* port */
+ if (atouint(val, &ul))
+ SET_PORT(&pvdc->v.sau,
+ (u_short)ul);
+ }
+ break;
+ }
+ }
+
+ /* and display */
+ if (decodestatus) {
+ vtype = (0 == as)
+ ? TYPE_SYS
+ : TYPE_PEER;
+ fprintf(fp, "associd=%u status=%04x %s,\n", as, rstatus,
+ statustoa(vtype, rstatus));
+ }
+
+ for (pvdc = table; pvdc->tag != NULL; pvdc++) {
+ switch (pvdc->type) {
+
+ case NTP_STR:
+ if (pvdc->v.str != NULL) {
+ fprintf(fp, "%s %s\n", pvdc->display,
+ pvdc->v.str);
+ free(pvdc->v.str);
+ pvdc->v.str = NULL;
+ }
+ break;
+
+ case NTP_ADD: /* fallthru */
+ case NTP_ADP:
+ fprintf(fp, "%s %s\n", pvdc->display,
+ nntohostp(&pvdc->v.sau));
+ break;
+
+ case NTP_LFP:
+ fprintf(fp, "%s %s\n", pvdc->display,
+ prettydate(&pvdc->v.lfp));
+ break;
+
+ case NTP_MODE:
+ atouint(pvdc->v.str, &ul);
+ fprintf(fp, "%s %s\n", pvdc->display,
+ modetoa((int)ul));
+ break;
+
+ case NTP_2BIT:
+ atouint(pvdc->v.str, &ul);
+ fprintf(fp, "%s %s\n", pvdc->display,
+ leapbits[ul & 0x3]);
+ break;
+
+ default:
+ fprintf(stderr, "unexpected vdc type %d for %s\n",
+ pvdc->type, pvdc->tag);
+ break;
+ }
+ }
+}
+
+
+/*
+ * sysstats - implements ntpq -c sysstats modeled on ntpdc -c sysstats
+ */
+static void
+sysstats(
+ struct parse *pcmd,
+ FILE *fp
+ )
+{
+ static vdc sysstats_vdc[] = {
+ VDC_INIT("ss_uptime", "uptime: ", NTP_STR),
+ VDC_INIT("ss_reset", "sysstats reset: ", NTP_STR),
+ VDC_INIT("ss_received", "packets received: ", NTP_STR),
+ VDC_INIT("ss_thisver", "current version: ", NTP_STR),
+ VDC_INIT("ss_oldver", "older version: ", NTP_STR),
+ VDC_INIT("ss_badformat", "bad length or format: ", NTP_STR),
+ VDC_INIT("ss_badauth", "authentication failed:", NTP_STR),
+ VDC_INIT("ss_declined", "declined: ", NTP_STR),
+ VDC_INIT("ss_restricted", "restricted: ", NTP_STR),
+ VDC_INIT("ss_limited", "rate limited: ", NTP_STR),
+ VDC_INIT("ss_kodsent", "KoD responses: ", NTP_STR),
+ VDC_INIT("ss_processed", "processed for time: ", NTP_STR),
+ VDC_INIT(NULL, NULL, 0)
+ };
+
+ collect_display_vdc(0, sysstats_vdc, FALSE, fp);
+}
+
+
+/*
+ * sysinfo - modeled on ntpdc's sysinfo
+ */
+static void
+sysinfo(
+ struct parse *pcmd,
+ FILE *fp
+ )
+{
+ static vdc sysinfo_vdc[] = {
+ VDC_INIT("peeradr", "system peer: ", NTP_ADP),
+ VDC_INIT("peermode", "system peer mode: ", NTP_MODE),
+ VDC_INIT("leap", "leap indicator: ", NTP_2BIT),
+ VDC_INIT("stratum", "stratum: ", NTP_STR),
+ VDC_INIT("precision", "log2 precision: ", NTP_STR),
+ VDC_INIT("rootdelay", "root delay: ", NTP_STR),
+ VDC_INIT("rootdisp", "root dispersion: ", NTP_STR),
+ VDC_INIT("refid", "reference ID: ", NTP_STR),
+ VDC_INIT("reftime", "reference time: ", NTP_LFP),
+ VDC_INIT("sys_jitter", "system jitter: ", NTP_STR),
+ VDC_INIT("clk_jitter", "clock jitter: ", NTP_STR),
+ VDC_INIT("clk_wander", "clock wander: ", NTP_STR),
+ VDC_INIT("bcastdelay", "broadcast delay: ", NTP_STR),
+ VDC_INIT("authdelay", "symm. auth. delay:", NTP_STR),
+ VDC_INIT(NULL, NULL, 0)
+ };
+
+ collect_display_vdc(0, sysinfo_vdc, TRUE, fp);
+}
+
+
+/*
+ * kerninfo - modeled on ntpdc's kerninfo
+ */
+static void
+kerninfo(
+ struct parse *pcmd,
+ FILE *fp
+ )
+{
+ static vdc kerninfo_vdc[] = {
+ VDC_INIT("koffset", "pll offset: ", NTP_STR),
+ VDC_INIT("kfreq", "pll frequency: ", NTP_STR),
+ VDC_INIT("kmaxerr", "maximum error: ", NTP_STR),
+ VDC_INIT("kesterr", "estimated error: ", NTP_STR),
+ VDC_INIT("kstflags", "kernel status: ", NTP_STR),
+ VDC_INIT("ktimeconst", "pll time constant: ", NTP_STR),
+ VDC_INIT("kprecis", "precision: ", NTP_STR),
+ VDC_INIT("kfreqtol", "frequency tolerance: ", NTP_STR),
+ VDC_INIT("kppsfreq", "pps frequency: ", NTP_STR),
+ VDC_INIT("kppsstab", "pps stability: ", NTP_STR),
+ VDC_INIT("kppsjitter", "pps jitter: ", NTP_STR),
+ VDC_INIT("kppscalibdur", "calibration interval ", NTP_STR),
+ VDC_INIT("kppscalibs", "calibration cycles: ", NTP_STR),
+ VDC_INIT("kppsjitexc", "jitter exceeded: ", NTP_STR),
+ VDC_INIT("kppsstbexc", "stability exceeded: ", NTP_STR),
+ VDC_INIT("kppscaliberrs", "calibration errors: ", NTP_STR),
+ VDC_INIT(NULL, NULL, 0)
+ };
+
+ collect_display_vdc(0, kerninfo_vdc, TRUE, fp);
+}
+
+
+/*
+ * monstats - implements ntpq -c monstats
+ */
+static void
+monstats(
+ struct parse *pcmd,
+ FILE *fp
+ )
+{
+ static vdc monstats_vdc[] = {
+ VDC_INIT("mru_enabled", "enabled: ", NTP_STR),
+ VDC_INIT("mru_depth", "addresses: ", NTP_STR),
+ VDC_INIT("mru_deepest", "peak addresses: ", NTP_STR),
+ VDC_INIT("mru_maxdepth", "maximum addresses: ", NTP_STR),
+ VDC_INIT("mru_mindepth", "reclaim above count:", NTP_STR),
+ VDC_INIT("mru_maxage", "reclaim older than: ", NTP_STR),
+ VDC_INIT("mru_mem", "kilobytes: ", NTP_STR),
+ VDC_INIT("mru_maxmem", "maximum kilobytes: ", NTP_STR),
+ VDC_INIT(NULL, NULL, 0)
+ };
+
+ collect_display_vdc(0, monstats_vdc, FALSE, fp);
+}
+
+
+/*
+ * iostats - ntpq -c iostats - network input and output counters
+ */
+static void
+iostats(
+ struct parse *pcmd,
+ FILE *fp
+ )
+{
+ static vdc iostats_vdc[] = {
+ VDC_INIT("iostats_reset", "time since reset: ", NTP_STR),
+ VDC_INIT("total_rbuf", "receive buffers: ", NTP_STR),
+ VDC_INIT("free_rbuf", "free receive buffers: ", NTP_STR),
+ VDC_INIT("used_rbuf", "used receive buffers: ", NTP_STR),
+ VDC_INIT("rbuf_lowater", "low water refills: ", NTP_STR),
+ VDC_INIT("io_dropped", "dropped packets: ", NTP_STR),
+ VDC_INIT("io_ignored", "ignored packets: ", NTP_STR),
+ VDC_INIT("io_received", "received packets: ", NTP_STR),
+ VDC_INIT("io_sent", "packets sent: ", NTP_STR),
+ VDC_INIT("io_sendfailed", "packet send failures: ", NTP_STR),
+ VDC_INIT("io_wakeups", "input wakeups: ", NTP_STR),
+ VDC_INIT("io_goodwakeups", "useful input wakeups: ", NTP_STR),
+ VDC_INIT(NULL, NULL, 0)
+ };
+
+ collect_display_vdc(0, iostats_vdc, FALSE, fp);
+}
+
+
+/*
+ * timerstats - ntpq -c timerstats - interval timer counters
+ */
+static void
+timerstats(
+ struct parse *pcmd,
+ FILE *fp
+ )
+{
+ static vdc timerstats_vdc[] = {
+ VDC_INIT("timerstats_reset", "time since reset: ", NTP_STR),
+ VDC_INIT("timer_overruns", "timer overruns: ", NTP_STR),
+ VDC_INIT("timer_xmts", "calls to transmit: ", NTP_STR),
+ VDC_INIT(NULL, NULL, 0)
+ };
+
+ collect_display_vdc(0, timerstats_vdc, FALSE, fp);
+}
+
+
+/*
+ * authinfo - implements ntpq -c authinfo
+ */
+static void
+authinfo(
+ struct parse *pcmd,
+ FILE *fp
+ )
+{
+ static vdc authinfo_vdc[] = {
+ VDC_INIT("authreset", "time since reset:", NTP_STR),
+ VDC_INIT("authkeys", "stored keys: ", NTP_STR),
+ VDC_INIT("authfreek", "free keys: ", NTP_STR),
+ VDC_INIT("authklookups", "key lookups: ", NTP_STR),
+ VDC_INIT("authknotfound", "keys not found: ", NTP_STR),
+ VDC_INIT("authkuncached", "uncached keys: ", NTP_STR),
+ VDC_INIT("authkexpired", "expired keys: ", NTP_STR),
+ VDC_INIT("authencrypts", "encryptions: ", NTP_STR),
+ VDC_INIT("authdecrypts", "decryptions: ", NTP_STR),
+ VDC_INIT(NULL, NULL, 0)
+ };
+
+ collect_display_vdc(0, authinfo_vdc, FALSE, fp);
+}
+
+
+/*
+ * pstats - show statistics for a peer
+ */
+static void
+pstats(
+ struct parse *pcmd,
+ FILE *fp
+ )
+{
+ static vdc pstats_vdc[] = {
+ VDC_INIT("src", "remote host: ", NTP_ADD),
+ VDC_INIT("dst", "local address: ", NTP_ADD),
+ VDC_INIT("timerec", "time last received: ", NTP_STR),
+ VDC_INIT("timer", "time until next send:", NTP_STR),
+ VDC_INIT("timereach", "reachability change: ", NTP_STR),
+ VDC_INIT("sent", "packets sent: ", NTP_STR),
+ VDC_INIT("received", "packets received: ", NTP_STR),
+ VDC_INIT("badauth", "bad authentication: ", NTP_STR),
+ VDC_INIT("bogusorg", "bogus origin: ", NTP_STR),
+ VDC_INIT("oldpkt", "duplicate: ", NTP_STR),
+ VDC_INIT("seldisp", "bad dispersion: ", NTP_STR),
+ VDC_INIT("selbroken", "bad reference time: ", NTP_STR),
+ VDC_INIT("candidate", "candidate order: ", NTP_STR),
+ VDC_INIT(NULL, NULL, 0)
+ };
+ associd_t associd;
+
+ associd = checkassocid(pcmd->argval[0].uval);
+ if (0 == associd)
+ return;
+
+ collect_display_vdc(associd, pstats_vdc, TRUE, fp);
+}