File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / ntp / ntpq / ntpq-subs.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue May 29 12:08:38 2012 UTC (12 years, 5 months ago) by misho
Branches: ntp, MAIN
CVS tags: v4_2_6p5p0, v4_2_6p5, HEAD
ntp 4.2.6p5

    1: /*
    2:  * ntpq_ops.c - subroutines which are called to perform operations by ntpq
    3:  */
    4: 
    5: #include <stdio.h>
    6: #include <ctype.h>
    7: #include <sys/types.h>
    8: #include <sys/time.h>
    9: 
   10: #include "ntp_stdlib.h"
   11: #include "ntpq.h"
   12: #include "ntpq-opts.h"
   13: 
   14: extern char *	chosts[];
   15: extern char currenthost[];
   16: extern int currenthostisnum;
   17: extern int	numhosts;
   18: int 	maxhostlen;
   19: 
   20: /*
   21:  * Declarations for command handlers in here
   22:  */
   23: static	associd_t checkassocid	(u_int32);
   24: static	struct varlist *findlistvar (struct varlist *, char *);
   25: static	void	doaddvlist	(struct varlist *, const char *);
   26: static	void	dormvlist	(struct varlist *, const char *);
   27: static	void	doclearvlist	(struct varlist *);
   28: static	void	makequerydata	(struct varlist *, int *, char *);
   29: static	int	doquerylist	(struct varlist *, int, associd_t, int,
   30: 				 u_short *, int *, const char **);
   31: static	void	doprintvlist	(struct varlist *, FILE *);
   32: static	void	addvars 	(struct parse *, FILE *);
   33: static	void	rmvars		(struct parse *, FILE *);
   34: static	void	clearvars	(struct parse *, FILE *);
   35: static	void	showvars	(struct parse *, FILE *);
   36: static	int	dolist		(struct varlist *, associd_t, int, int,
   37: 				 FILE *);
   38: static	void	readlist	(struct parse *, FILE *);
   39: static	void	writelist	(struct parse *, FILE *);
   40: static	void	readvar 	(struct parse *, FILE *);
   41: static	void	writevar	(struct parse *, FILE *);
   42: static	void	clocklist	(struct parse *, FILE *);
   43: static	void	clockvar	(struct parse *, FILE *);
   44: static	int	findassidrange	(u_int32, u_int32, int *, int *);
   45: static	void	mreadlist	(struct parse *, FILE *);
   46: static	void	mreadvar	(struct parse *, FILE *);
   47: static	int	dogetassoc	(FILE *);
   48: static	void	printassoc	(int, FILE *);
   49: static	void	associations	(struct parse *, FILE *);
   50: static	void	lassociations	(struct parse *, FILE *);
   51: static	void	passociations	(struct parse *, FILE *);
   52: static	void	lpassociations	(struct parse *, FILE *);
   53: 
   54: #ifdef	UNUSED
   55: static	void	radiostatus (struct parse *, FILE *);
   56: #endif	/* UNUSED */
   57: 
   58: static	void	pstatus 	(struct parse *, FILE *);
   59: static	long	when		(l_fp *, l_fp *, l_fp *);
   60: static	char *	prettyinterval	(char *, size_t, long);
   61: static	int	doprintpeers	(struct varlist *, int, int, int, const char *, FILE *, int);
   62: static	int	dogetpeers	(struct varlist *, associd_t, FILE *, int);
   63: static	void	dopeers 	(int, FILE *, int);
   64: static	void	peers		(struct parse *, FILE *);
   65: static	void	lpeers		(struct parse *, FILE *);
   66: static	void	doopeers	(int, FILE *, int);
   67: static	void	opeers		(struct parse *, FILE *);
   68: static	void	lopeers 	(struct parse *, FILE *);
   69: static  void	config		(struct parse *, FILE *);
   70: static 	void 	saveconfig	(struct parse *, FILE *);
   71: static  void	config_from_file(struct parse *, FILE *);
   72: 
   73: 
   74: /*
   75:  * Commands we understand.	Ntpdc imports this.
   76:  */
   77: struct xcmd opcmds[] = {
   78: 	{ "saveconfig", saveconfig, { NTP_STR, NO, NO, NO },
   79: 		{ "filename", "", "", ""}, 
   80: 		"save ntpd configuration to file, . for current config file"},
   81: 	{ "associations", associations, {  NO, NO, NO, NO },
   82: 	  { "", "", "", "" },
   83: 	  "print list of association ID's and statuses for the server's peers" },
   84: 	{ "passociations", passociations,   {  NO, NO, NO, NO },
   85: 	  { "", "", "", "" },
   86: 	  "print list of associations returned by last associations command" },
   87: 	{ "lassociations", lassociations,   {  NO, NO, NO, NO },
   88: 	  { "", "", "", "" },
   89: 	  "print list of associations including all client information" },
   90: 	{ "lpassociations", lpassociations, {  NO, NO, NO, NO },
   91: 	  { "", "", "", "" },
   92: 	  "print last obtained list of associations, including client information" },
   93: 	{ "addvars",    addvars,    { NTP_STR, NO, NO, NO },
   94: 	  { "name[=value][,...]", "", "", "" },
   95: 	  "add variables to the variable list or change their values" },
   96: 	{ "rmvars", rmvars,     { NTP_STR, NO, NO, NO },
   97: 	  { "name[,...]", "", "", "" },
   98: 	  "remove variables from the variable list" },
   99: 	{ "clearvars",  clearvars,  { NO, NO, NO, NO },
  100: 	  { "", "", "", "" },
  101: 	  "remove all variables from the variable list" },
  102: 	{ "showvars",   showvars,   { NO, NO, NO, NO },
  103: 	  { "", "", "", "" },
  104: 	  "print variables on the variable list" },
  105: 	{ "readlist",   readlist,   { OPT|NTP_UINT, NO, NO, NO },
  106: 	  { "assocID", "", "", "" },
  107: 	  "read the system or peer variables included in the variable list" },
  108: 	{ "rl",     readlist,   { OPT|NTP_UINT, NO, NO, NO },
  109: 	  { "assocID", "", "", "" },
  110: 	  "read the system or peer variables included in the variable list" },
  111: 	{ "writelist",  writelist,  { OPT|NTP_UINT, NO, NO, NO },
  112: 	  { "assocID", "", "", "" },
  113: 	  "write the system or peer variables included in the variable list" },
  114: 	{ "readvar",    readvar,    { OPT|NTP_UINT, OPT|NTP_STR, NO, NO },
  115: 	  { "assocID", "name=value[,...]", "", "" },
  116: 	  "read system or peer variables" },
  117: 	{ "rv",     readvar,    { OPT|NTP_UINT, OPT|NTP_STR, NO, NO },
  118: 	  { "assocID", "name=value[,...]", "", "" },
  119: 	  "read system or peer variables" },
  120: 	{ "writevar",   writevar,   { NTP_UINT, NTP_STR, NO, NO },
  121: 	  { "assocID", "name=value,[...]", "", "" },
  122: 	  "write system or peer variables" },
  123: 	{ "mreadlist",  mreadlist,  { NTP_UINT, NTP_UINT, NO, NO },
  124: 	  { "assocID", "assocID", "", "" },
  125: 	  "read the peer variables in the variable list for multiple peers" },
  126: 	{ "mrl",    mreadlist,  { NTP_UINT, NTP_UINT, NO, NO },
  127: 	  { "assocID", "assocID", "", "" },
  128: 	  "read the peer variables in the variable list for multiple peers" },
  129: 	{ "mreadvar",   mreadvar,   { NTP_UINT, NTP_UINT, OPT|NTP_STR, NO },
  130: 	  { "assocID", "assocID", "name=value[,...]", "" },
  131: 	  "read peer variables from multiple peers" },
  132: 	{ "mrv",    mreadvar,   { NTP_UINT, NTP_UINT, OPT|NTP_STR, NO },
  133: 	  { "assocID", "assocID", "name=value[,...]", "" },
  134: 	  "read peer variables from multiple peers" },
  135: 	{ "clocklist",  clocklist,  { OPT|NTP_UINT, NO, NO, NO },
  136: 	  { "assocID", "", "", "" },
  137: 	  "read the clock variables included in the variable list" },
  138: 	{ "cl",     clocklist,  { OPT|NTP_UINT, NO, NO, NO },
  139: 	  { "assocID", "", "", "" },
  140: 	  "read the clock variables included in the variable list" },
  141: 	{ "clockvar",   clockvar,   { OPT|NTP_UINT, OPT|NTP_STR, NO, NO },
  142: 	  { "assocID", "name=value[,...]", "", "" },
  143: 	  "read clock variables" },
  144: 	{ "cv",     clockvar,   { OPT|NTP_UINT, OPT|NTP_STR, NO, NO },
  145: 	  { "assocID", "name=value[,...]", "", "" },
  146: 	  "read clock variables" },
  147: 	{ "pstatus",    pstatus,    { NTP_UINT, NO, NO, NO },
  148: 	  { "assocID", "", "", "" },
  149: 	  "print status information returned for a peer" },
  150: 	{ "peers",  peers,      { OPT|IP_VERSION, NO, NO, NO },
  151: 	  { "-4|-6", "", "", "" },
  152: 	  "obtain and print a list of the server's peers [IP version]" },
  153: 	{ "lpeers", lpeers,     { OPT|IP_VERSION, NO, NO, NO },
  154: 	  { "-4|-6", "", "", "" },
  155: 	  "obtain and print a list of all peers and clients [IP version]" },
  156: 	{ "opeers", opeers,     { OPT|IP_VERSION, NO, NO, NO },
  157: 	  { "-4|-6", "", "", "" },
  158: 	  "print peer list the old way, with dstadr shown rather than refid [IP version]" },
  159: 	{ "lopeers", lopeers,   { OPT|IP_VERSION, NO, NO, NO },
  160: 	  { "-4|-6", "", "", "" },
  161: 	  "obtain and print a list of all peers and clients showing dstadr [IP version]" },
  162: 	{ ":config", config,   { NTP_STR, NO, NO, NO },
  163: 	  { "<configuration command line>", "", "", "" },
  164: 	  "send a remote configuration command to ntpd" },
  165: 	{ "config-from-file", config_from_file, { NTP_STR, NO, NO, NO },
  166: 	  { "<configuration filename>", "", "", "" },
  167: 	  "configure ntpd using the configuration filename" },
  168: 	{ 0,		0,		{ NO, NO, NO, NO },
  169: 	  { "-4|-6", "", "", "" }, "" }
  170: };
  171: 
  172: 
  173: /*
  174:  * Variable list data space
  175:  */
  176: #define MAXLINE     512  /* maximum length of a line */
  177: #define MAXLIST 	64	/* maximum number of variables in list */
  178: #define LENHOSTNAME 256 /* host name is 256 characters long */
  179: /*
  180:  * Old CTL_PST defines for version 2.
  181:  */
  182: #define OLD_CTL_PST_CONFIG		0x80
  183: #define OLD_CTL_PST_AUTHENABLE		0x40
  184: #define OLD_CTL_PST_AUTHENTIC		0x20
  185: #define OLD_CTL_PST_REACH		0x10
  186: #define OLD_CTL_PST_SANE		0x08
  187: #define OLD_CTL_PST_DISP		0x04
  188: 
  189: #define OLD_CTL_PST_SEL_REJECT		0
  190: #define OLD_CTL_PST_SEL_SELCAND 	1
  191: #define OLD_CTL_PST_SEL_SYNCCAND	2
  192: #define OLD_CTL_PST_SEL_SYSPEER 	3
  193: 
  194: char flash2[] = " .+*    "; /* flash decode for version 2 */
  195: char flash3[] = " x.-+#*o"; /* flash decode for peer status version 3 */
  196: 
  197: struct varlist {
  198: 	char *name;
  199: 	char *value;
  200: } g_varlist[MAXLIST] = { { 0, 0 } };
  201: 
  202: /*
  203:  * Imported from ntpq.c
  204:  */
  205: extern int showhostnames;
  206: extern int rawmode;
  207: extern struct servent *server_entry;
  208: extern struct association assoc_cache[];
  209: extern int numassoc;
  210: extern u_char pktversion;
  211: extern struct ctl_var peer_var[];
  212: 
  213: /*
  214:  * For quick string comparisons
  215:  */
  216: #define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0)
  217: 
  218: 
  219: /*
  220:  * checkassocid - return the association ID, checking to see if it is valid
  221:  */
  222: static associd_t
  223: checkassocid(
  224: 	u_int32 value
  225: 	)
  226: {
  227: 	associd_t	associd;
  228: 	u_long		ulvalue;
  229: 
  230: 	associd = (associd_t)value;
  231: 	if (0 == associd || value != associd) {
  232: 		ulvalue = value;
  233: 		fprintf(stderr,
  234: 			"***Invalid association ID %lu specified\n",
  235: 			ulvalue);
  236: 		return 0;
  237: 	}
  238: 
  239: 	return associd;
  240: }
  241: 
  242: 
  243: /*
  244:  * findlistvar - look for the named variable in a list and return if found
  245:  */
  246: static struct varlist *
  247: findlistvar(
  248: 	struct varlist *list,
  249: 	char *name
  250: 	)
  251: {
  252: 	register struct varlist *vl;
  253: 
  254: 	for (vl = list; vl < list + MAXLIST && vl->name != 0; vl++)
  255: 		if (STREQ(name, vl->name))
  256: 		return vl;
  257: 	if (vl < list + MAXLIST)
  258: 		return vl;
  259: 	return (struct varlist *)0;
  260: }
  261: 
  262: 
  263: /*
  264:  * doaddvlist - add variable(s) to the variable list
  265:  */
  266: static void
  267: doaddvlist(
  268: 	struct varlist *vlist,
  269: 	const char *vars
  270: 	)
  271: {
  272: 	register struct varlist *vl;
  273: 	int len;
  274: 	char *name;
  275: 	char *value;
  276: 
  277: 	len = strlen(vars);
  278: 	while (nextvar(&len, &vars, &name, &value)) {
  279: 		vl = findlistvar(vlist, name);
  280: 		if (vl == 0) {
  281: 			(void) fprintf(stderr, "Variable list full\n");
  282: 			return;
  283: 		}
  284: 
  285: 		if (vl->name == 0) {
  286: 			vl->name = estrdup(name);
  287: 		} else if (vl->value != 0) {
  288: 			free(vl->value);
  289: 			vl->value = 0;
  290: 		}
  291: 
  292: 		if (value != 0)
  293: 			vl->value = estrdup(value);
  294: 	}
  295: }
  296: 
  297: 
  298: /*
  299:  * dormvlist - remove variable(s) from the variable list
  300:  */
  301: static void
  302: dormvlist(
  303: 	struct varlist *vlist,
  304: 	const char *vars
  305: 	)
  306: {
  307: 	register struct varlist *vl;
  308: 	int len;
  309: 	char *name;
  310: 	char *value;
  311: 
  312: 	len = strlen(vars);
  313: 	while (nextvar(&len, &vars, &name, &value)) {
  314: 		vl = findlistvar(vlist, name);
  315: 		if (vl == 0 || vl->name == 0) {
  316: 			(void) fprintf(stderr, "Variable `%s' not found\n",
  317: 				       name);
  318: 		} else {
  319: 			free((void *)vl->name);
  320: 			if (vl->value != 0)
  321: 			    free(vl->value);
  322: 			for ( ; (vl+1) < (g_varlist + MAXLIST)
  323: 				      && (vl+1)->name != 0; vl++) {
  324: 				vl->name = (vl+1)->name;
  325: 				vl->value = (vl+1)->value;
  326: 			}
  327: 			vl->name = vl->value = 0;
  328: 		}
  329: 	}
  330: }
  331: 
  332: 
  333: /*
  334:  * doclearvlist - clear a variable list
  335:  */
  336: static void
  337: doclearvlist(
  338: 	struct varlist *vlist
  339: 	)
  340: {
  341: 	register struct varlist *vl;
  342: 
  343: 	for (vl = vlist; vl < vlist + MAXLIST && vl->name != 0; vl++) {
  344: 		free((void *)vl->name);
  345: 		vl->name = 0;
  346: 		if (vl->value != 0) {
  347: 			free(vl->value);
  348: 			vl->value = 0;
  349: 		}
  350: 	}
  351: }
  352: 
  353: 
  354: /*
  355:  * makequerydata - form a data buffer to be included with a query
  356:  */
  357: static void
  358: makequerydata(
  359: 	struct varlist *vlist,
  360: 	int *datalen,
  361: 	char *data
  362: 	)
  363: {
  364: 	register struct varlist *vl;
  365: 	register char *cp, *cpend;
  366: 	register int namelen, valuelen;
  367: 	register int totallen;
  368: 
  369: 	cp = data;
  370: 	cpend = data + *datalen;
  371: 
  372: 	for (vl = vlist; vl < vlist + MAXLIST && vl->name != 0; vl++) {
  373: 		namelen = strlen(vl->name);
  374: 		if (vl->value == 0)
  375: 			valuelen = 0;
  376: 		else
  377: 			valuelen = strlen(vl->value);
  378: 		totallen = namelen + valuelen + (valuelen != 0) + (cp != data);
  379: 		if (cp + totallen > cpend)
  380: 			break;
  381: 
  382: 		if (cp != data)
  383: 			*cp++ = ',';
  384: 		memmove(cp, vl->name, (unsigned)namelen);
  385: 		cp += namelen;
  386: 		if (valuelen != 0) {
  387: 			*cp++ = '=';
  388: 			memmove(cp, vl->value, (unsigned)valuelen);
  389: 			cp += valuelen;
  390: 		}
  391: 	}
  392: 	*datalen = cp - data;
  393: }
  394: 
  395: 
  396: /*
  397:  * doquerylist - send a message including variables in a list
  398:  */
  399: static int
  400: doquerylist(
  401: 	struct varlist *vlist,
  402: 	int op,
  403: 	associd_t associd,
  404: 	int auth,
  405: 	u_short *rstatus,
  406: 	int *dsize,
  407: 	const char **datap
  408: 	)
  409: {
  410: 	char data[CTL_MAX_DATA_LEN];
  411: 	int datalen;
  412: 
  413: 	datalen = sizeof(data);
  414: 	makequerydata(vlist, &datalen, data);
  415: 
  416: 	return doquery(op, associd, auth, datalen, data, rstatus,
  417: 			   dsize, datap);
  418: }
  419: 
  420: 
  421: /*
  422:  * doprintvlist - print the variables on a list
  423:  */
  424: static void
  425: doprintvlist(
  426: 	struct varlist *vlist,
  427: 	FILE *fp
  428: 	)
  429: {
  430: 	register struct varlist *vl;
  431: 
  432: 	if (vlist->name == 0) {
  433: 		(void) fprintf(fp, "No variables on list\n");
  434: 	} else {
  435: 		for (vl = vlist; vl < vlist + MAXLIST && vl->name != 0; vl++) {
  436: 			if (vl->value == 0) {
  437: 				(void) fprintf(fp, "%s\n", vl->name);
  438: 			} else {
  439: 				(void) fprintf(fp, "%s=%s\n",
  440: 						   vl->name, vl->value);
  441: 			}
  442: 		}
  443: 	}
  444: }
  445: 
  446: /*
  447:  * addvars - add variables to the variable list
  448:  */
  449: /*ARGSUSED*/
  450: static void
  451: addvars(
  452: 	struct parse *pcmd,
  453: 	FILE *fp
  454: 	)
  455: {
  456: 	doaddvlist(g_varlist, pcmd->argval[0].string);
  457: }
  458: 
  459: 
  460: /*
  461:  * rmvars - remove variables from the variable list
  462:  */
  463: /*ARGSUSED*/
  464: static void
  465: rmvars(
  466: 	struct parse *pcmd,
  467: 	FILE *fp
  468: 	)
  469: {
  470: 	dormvlist(g_varlist, pcmd->argval[0].string);
  471: }
  472: 
  473: 
  474: /*
  475:  * clearvars - clear the variable list
  476:  */
  477: /*ARGSUSED*/
  478: static void
  479: clearvars(
  480: 	struct parse *pcmd,
  481: 	FILE *fp
  482: 	)
  483: {
  484: 	doclearvlist(g_varlist);
  485: }
  486: 
  487: 
  488: /*
  489:  * showvars - show variables on the variable list
  490:  */
  491: /*ARGSUSED*/
  492: static void
  493: showvars(
  494: 	struct parse *pcmd,
  495: 	FILE *fp
  496: 	)
  497: {
  498: 	doprintvlist(g_varlist, fp);
  499: }
  500: 
  501: 
  502: /*
  503:  * dolist - send a request with the given list of variables
  504:  */
  505: static int
  506: dolist(
  507: 	struct varlist *vlist,
  508: 	associd_t associd,
  509: 	int op,
  510: 	int type,
  511: 	FILE *fp
  512: 	)
  513: {
  514: 	const char *datap;
  515: 	int res;
  516: 	int dsize;
  517: 	u_short rstatus;
  518: 	int quiet;
  519: 
  520: 	/*
  521: 	 * if we're asking for specific variables don't include the
  522: 	 * status header line in the output.
  523: 	 */
  524: 	if (old_rv)
  525: 		quiet = 0;
  526: 	else
  527: 		quiet = (vlist->name != NULL);
  528: 
  529: 	res = doquerylist(vlist, op, associd, 0, &rstatus, &dsize, &datap);
  530: 
  531: 	if (res != 0)
  532: 		return 0;
  533: 
  534: 	if (numhosts > 1)
  535: 		(void) fprintf(fp, "server=%s ", currenthost);
  536: 	if (dsize == 0) {
  537: 		if (associd == 0)
  538: 			(void) fprintf(fp, "No system%s variables returned\n",
  539: 				   (type == TYPE_CLOCK) ? " clock" : "");
  540: 		else
  541: 			(void) fprintf(fp,
  542: 				   "No information returned for%s association %u\n",
  543: 				   (type == TYPE_CLOCK) ? " clock" : "", associd);
  544: 		return 1;
  545: 	}
  546: 
  547: 	if (!quiet)
  548: 		fprintf(fp,"associd=%d ",associd);
  549: 	printvars(dsize, datap, (int)rstatus, type, quiet, fp);
  550: 	return 1;
  551: }
  552: 
  553: 
  554: /*
  555:  * readlist - send a read variables request with the variables on the list
  556:  */
  557: static void
  558: readlist(
  559: 	struct parse *pcmd,
  560: 	FILE *fp
  561: 	)
  562: {
  563: 	associd_t	associd;
  564: 	int		type;
  565: 
  566: 	if (pcmd->nargs == 0) {
  567: 		associd = 0;
  568: 	} else {
  569: 	  /* HMS: I think we want the u_int32 target here, not the u_long */
  570: 		if (pcmd->argval[0].uval == 0)
  571: 			associd = 0;
  572: 		else if ((associd = checkassocid(pcmd->argval[0].uval)) == 0)
  573: 			return;
  574: 	}
  575: 
  576: 	type = (0 == associd)
  577: 		   ? TYPE_SYS
  578: 		   : TYPE_PEER;
  579: 	dolist(g_varlist, associd, CTL_OP_READVAR, type, fp);
  580: }
  581: 
  582: 
  583: /*
  584:  * writelist - send a write variables request with the variables on the list
  585:  */
  586: static void
  587: writelist(
  588: 	struct parse *pcmd,
  589: 	FILE *fp
  590: 	)
  591: {
  592: 	const char *datap;
  593: 	int res;
  594: 	associd_t associd;
  595: 	int dsize;
  596: 	u_short rstatus;
  597: 
  598: 	if (pcmd->nargs == 0) {
  599: 		associd = 0;
  600: 	} else {
  601: 		/* HMS: Do we really want uval here? */
  602: 		if (pcmd->argval[0].uval == 0)
  603: 			associd = 0;
  604: 		else if ((associd = checkassocid(pcmd->argval[0].uval)) == 0)
  605: 			return;
  606: 	}
  607: 
  608: 	res = doquerylist(g_varlist, CTL_OP_WRITEVAR, associd, 1, &rstatus,
  609: 			  &dsize, &datap);
  610: 
  611: 	if (res != 0)
  612: 		return;
  613: 
  614: 	if (numhosts > 1)
  615: 		(void) fprintf(fp, "server=%s ", currenthost);
  616: 	if (dsize == 0)
  617: 		(void) fprintf(fp, "done! (no data returned)\n");
  618: 	else {
  619: 		(void) fprintf(fp,"associd=%d ",associd);
  620: 		printvars(dsize, datap, (int)rstatus,
  621: 			  (associd != 0) ? TYPE_PEER : TYPE_SYS, 0, fp);
  622: 	}
  623: 	return;
  624: }
  625: 
  626: 
  627: /*
  628:  * readvar - send a read variables request with the specified variables
  629:  */
  630: static void
  631: readvar(
  632: 	struct parse *pcmd,
  633: 	FILE *fp
  634: 	)
  635: {
  636: 	associd_t	associd;
  637: 	int		type;
  638: 	struct varlist	tmplist[MAXLIST];
  639: 
  640: 
  641: 	/* HMS: uval? */
  642: 	if (pcmd->nargs == 0 || pcmd->argval[0].uval == 0)
  643: 		associd = 0;
  644: 	else if ((associd = checkassocid(pcmd->argval[0].uval)) == 0)
  645: 		return;
  646: 
  647: 	memset(tmplist, 0, sizeof(tmplist));
  648: 	if (pcmd->nargs >= 2)
  649: 		doaddvlist(tmplist, pcmd->argval[1].string);
  650: 
  651: 	type = (0 == associd)
  652: 		   ? TYPE_SYS
  653: 		   : TYPE_PEER;
  654: 	dolist(tmplist, associd, CTL_OP_READVAR, type, fp);
  655: 
  656: 	doclearvlist(tmplist);
  657: }
  658: 
  659: 
  660: /*
  661:  * writevar - send a write variables request with the specified variables
  662:  */
  663: static void
  664: writevar(
  665: 	struct parse *pcmd,
  666: 	FILE *fp
  667: 	)
  668: {
  669: 	const char *datap;
  670: 	int res;
  671: 	associd_t associd;
  672: 	int type;
  673: 	int dsize;
  674: 	u_short rstatus;
  675: 	struct varlist tmplist[MAXLIST];
  676: 
  677: 	/* HMS: uval? */
  678: 	if (pcmd->argval[0].uval == 0)
  679: 		associd = 0;
  680: 	else if ((associd = checkassocid(pcmd->argval[0].uval)) == 0)
  681: 		return;
  682: 
  683: 	memset((char *)tmplist, 0, sizeof(tmplist));
  684: 	doaddvlist(tmplist, pcmd->argval[1].string);
  685: 
  686: 	res = doquerylist(tmplist, CTL_OP_WRITEVAR, associd, 1, &rstatus,
  687: 			  &dsize, &datap);
  688: 
  689: 	doclearvlist(tmplist);
  690: 
  691: 	if (res != 0)
  692: 		return;
  693: 
  694: 	if (numhosts > 1)
  695: 		fprintf(fp, "server=%s ", currenthost);
  696: 	if (dsize == 0)
  697: 		fprintf(fp, "done! (no data returned)\n");
  698: 	else {
  699: 		fprintf(fp,"associd=%d ",associd);
  700: 		type = (0 == associd)
  701: 			   ? TYPE_SYS
  702: 			   : TYPE_PEER;
  703: 		printvars(dsize, datap, (int)rstatus, type, 0, fp);
  704: 	}
  705: 	return;
  706: }
  707: 
  708: 
  709: /*
  710:  * clocklist - send a clock variables request with the variables on the list
  711:  */
  712: static void
  713: clocklist(
  714: 	struct parse *pcmd,
  715: 	FILE *fp
  716: 	)
  717: {
  718: 	associd_t associd;
  719: 
  720: 	/* HMS: uval? */
  721: 	if (pcmd->nargs == 0) {
  722: 		associd = 0;
  723: 	} else {
  724: 		if (pcmd->argval[0].uval == 0)
  725: 			associd = 0;
  726: 		else if ((associd = checkassocid(pcmd->argval[0].uval)) == 0)
  727: 			return;
  728: 	}
  729: 
  730: 	dolist(g_varlist, associd, CTL_OP_READCLOCK, TYPE_CLOCK, fp);
  731: }
  732: 
  733: 
  734: /*
  735:  * clockvar - send a clock variables request with the specified variables
  736:  */
  737: static void
  738: clockvar(
  739: 	struct parse *pcmd,
  740: 	FILE *fp
  741: 	)
  742: {
  743: 	associd_t associd;
  744: 	struct varlist tmplist[MAXLIST];
  745: 
  746: 	/* HMS: uval? */
  747: 	if (pcmd->nargs == 0 || pcmd->argval[0].uval == 0)
  748: 		associd = 0;
  749: 	else if ((associd = checkassocid(pcmd->argval[0].uval)) == 0)
  750: 		return;
  751: 
  752: 	memset(tmplist, 0, sizeof(tmplist));
  753: 	if (pcmd->nargs >= 2)
  754: 		doaddvlist(tmplist, pcmd->argval[1].string);
  755: 
  756: 	dolist(tmplist, associd, CTL_OP_READCLOCK, TYPE_CLOCK, fp);
  757: 
  758: 	doclearvlist(tmplist);
  759: }
  760: 
  761: 
  762: /*
  763:  * findassidrange - verify a range of association ID's
  764:  */
  765: static int
  766: findassidrange(
  767: 	u_int32 assid1,
  768: 	u_int32 assid2,
  769: 	int *from,
  770: 	int *to
  771: 	)
  772: {
  773: 	associd_t	assids[2];
  774: 	int		ind[COUNTOF(assids)];
  775: 	int		i;
  776: 	size_t		a;
  777: 
  778: 	assids[0] = checkassocid(assid1);
  779: 	if (0 == assids[0])
  780: 		return 0;
  781: 	assids[1] = checkassocid(assid2);
  782: 	if (0 == assids[1])
  783: 		return 0;
  784: 
  785: 	for (a = 0; a < COUNTOF(assids); a++) {
  786: 		ind[a] = -1;
  787: 		for (i = 0; i < numassoc; i++)
  788: 			if (assoc_cache[i].assid == assids[a])
  789: 				ind[a] = i;
  790: 	}
  791: 	for (a = 0; a < COUNTOF(assids); a++)
  792: 		if (-1 == ind[a]) {
  793: 			fprintf(stderr,
  794: 				"***Association ID %u not found in list\n",
  795: 				assids[a]);
  796: 			return 0;
  797: 		}
  798: 
  799: 	if (ind[0] < ind[1]) {
  800: 		*from = ind[0];
  801: 		*to = ind[1];
  802: 	} else {
  803: 		*to = ind[0];
  804: 		*from = ind[1];
  805: 	}
  806: 	return 1;
  807: }
  808: 
  809: 
  810: 
  811: /*
  812:  * mreadlist - send a read variables request for multiple associations
  813:  */
  814: static void
  815: mreadlist(
  816: 	struct parse *pcmd,
  817: 	FILE *fp
  818: 	)
  819: {
  820: 	int i;
  821: 	int from;
  822: 	int to;
  823: 
  824: 	/* HMS: uval? */
  825: 	if (!findassidrange(pcmd->argval[0].uval, pcmd->argval[1].uval,
  826: 				&from, &to))
  827: 		return;
  828: 
  829: 	for (i = from; i <= to; i++) {
  830: 		if (i != from)
  831: 			(void) fprintf(fp, "\n");
  832: 		if (!dolist(g_varlist, (int)assoc_cache[i].assid,
  833: 				CTL_OP_READVAR, TYPE_PEER, fp))
  834: 			return;
  835: 	}
  836: 	return;
  837: }
  838: 
  839: 
  840: /*
  841:  * mreadvar - send a read variables request for multiple associations
  842:  */
  843: static void
  844: mreadvar(
  845: 	struct parse *pcmd,
  846: 	FILE *fp
  847: 	)
  848: {
  849: 	int i;
  850: 	int from;
  851: 	int to;
  852: 	struct varlist tmplist[MAXLIST];
  853: 	struct varlist *pvars;
  854: 
  855: 	/* HMS: uval? */
  856: 	if (!findassidrange(pcmd->argval[0].uval, pcmd->argval[1].uval,
  857: 				&from, &to))
  858: 		return;
  859: 
  860: 	if (pcmd->nargs >= 3) {
  861: 		memset(tmplist, 0, sizeof(tmplist));
  862: 		doaddvlist(tmplist, pcmd->argval[2].string);
  863: 		pvars = tmplist;
  864: 	} else {
  865: 		pvars = g_varlist;
  866: 	}
  867: 
  868: 	for (i = from; i <= to; i++) {
  869: 		if (i != from)
  870: 			fprintf(fp, "\n");
  871: 		if (!dolist(pvars, (int)assoc_cache[i].assid,
  872: 			    CTL_OP_READVAR, TYPE_PEER, fp))
  873: 			break;
  874: 	}
  875: 	doclearvlist(tmplist);
  876: 	return;
  877: }
  878: 
  879: 
  880: /*
  881:  * dogetassoc - query the host for its list of associations
  882:  */
  883: static int
  884: dogetassoc(
  885: 	FILE *fp
  886: 	)
  887: {
  888: 	const char *datap;
  889: 	int res;
  890: 	int dsize;
  891: 	u_short rstatus;
  892: 
  893: 	res = doquery(CTL_OP_READSTAT, 0, 0, 0, (char *)0, &rstatus,
  894: 			  &dsize, &datap);
  895: 
  896: 	if (res != 0)
  897: 		return 0;
  898: 
  899: 	if (dsize == 0) {
  900: 		if (numhosts > 1)
  901: 			(void) fprintf(fp, "server=%s ", currenthost);
  902: 		(void) fprintf(fp, "No association ID's returned\n");
  903: 		return 0;
  904: 	}
  905: 
  906: 	if (dsize & 0x3) {
  907: 		if (numhosts > 1)
  908: 			(void) fprintf(stderr, "server=%s ", currenthost);
  909: 		(void) fprintf(stderr,
  910: 				   "***Server returned %d octets, should be multiple of 4\n",
  911: 				   dsize);
  912: 		return 0;
  913: 	}
  914: 
  915: 	numassoc = 0;
  916: 	while (dsize > 0) {
  917: 		assoc_cache[numassoc].assid = ntohs(*((const u_short *)datap));
  918: 		datap += sizeof(u_short);
  919: 		assoc_cache[numassoc].status = ntohs(*((const u_short *)datap));
  920: 		datap += sizeof(u_short);
  921: 		if (++numassoc >= MAXASSOC)
  922: 			break;
  923: 		dsize -= sizeof(u_short) + sizeof(u_short);
  924: 	}
  925: 	sortassoc();
  926: 	return 1;
  927: }
  928: 
  929: 
  930: /*
  931:  * printassoc - print the current list of associations
  932:  */
  933: static void
  934: printassoc(
  935: 	int showall,
  936: 	FILE *fp
  937: 	)
  938: {
  939: 	register char *bp;
  940: 	int i;
  941: 	u_char statval;
  942: 	int event;
  943: 	u_long event_count;
  944: 	const char *conf;
  945: 	const char *reach;
  946: 	const char *auth;
  947: 	const char *condition = "";
  948: 	const char *last_event;
  949: 	const char *cnt;
  950: 	char buf[128];
  951: 
  952: 	if (numassoc == 0) {
  953: 		(void) fprintf(fp, "No association ID's in list\n");
  954: 		return;
  955: 	}
  956: 
  957: 	/*
  958: 	 * Output a header
  959: 	 */
  960: 	(void) fprintf(fp,
  961: 			   "\nind assid status  conf reach auth condition  last_event cnt\n");
  962: 	(void) fprintf(fp,
  963: 			   "===========================================================\n");
  964: 	for (i = 0; i < numassoc; i++) {
  965: 		statval = (u_char) CTL_PEER_STATVAL(assoc_cache[i].status);
  966: 		if (!showall && !(statval & (CTL_PST_CONFIG|CTL_PST_REACH)))
  967: 			continue;
  968: 		event = CTL_PEER_EVENT(assoc_cache[i].status);
  969: 		event_count = CTL_PEER_NEVNT(assoc_cache[i].status);
  970: 		if (statval & CTL_PST_CONFIG)
  971: 			conf = "yes";
  972: 		else
  973: 			conf = "no";
  974: 		if (statval & CTL_PST_BCAST) {
  975: 			reach = "none";
  976: 			if (statval & CTL_PST_AUTHENABLE)
  977: 				auth = "yes";
  978: 			else
  979: 				auth = "none";
  980: 		} else {
  981: 			if (statval & CTL_PST_REACH)
  982: 				reach = "yes";
  983: 			else
  984: 				reach = "no";
  985: 			if (statval & CTL_PST_AUTHENABLE) {
  986: 				if (statval & CTL_PST_AUTHENTIC)
  987: 					auth = "ok ";
  988: 				else
  989: 					auth = "bad";
  990: 			} else {
  991: 				auth = "none";
  992: 			}
  993: 		}
  994: 		if (pktversion > NTP_OLDVERSION) {
  995: 			switch (statval & 0x7) {
  996: 
  997: 			case CTL_PST_SEL_REJECT:
  998: 				condition = "reject";
  999: 				break;
 1000: 
 1001: 			case CTL_PST_SEL_SANE:
 1002: 				condition = "falsetick";
 1003: 				break;
 1004: 
 1005: 			case CTL_PST_SEL_CORRECT:
 1006: 				condition = "excess";
 1007: 				break;
 1008: 
 1009: 			case CTL_PST_SEL_SELCAND:
 1010: 				condition = "outlyer";
 1011: 				break;
 1012: 
 1013: 			case CTL_PST_SEL_SYNCCAND:
 1014: 				condition = "candidate";
 1015: 				break;
 1016: 
 1017: 			case CTL_PST_SEL_EXCESS:
 1018: 				condition = "backup";
 1019: 				break;
 1020: 
 1021: 			case CTL_PST_SEL_SYSPEER:
 1022: 				condition = "sys.peer";
 1023: 				break;
 1024: 
 1025: 			case CTL_PST_SEL_PPS:
 1026: 				condition = "pps.peer";
 1027: 				break;
 1028: 			}
 1029: 		} else {
 1030: 			switch (statval & 0x3) {
 1031: 
 1032: 			case OLD_CTL_PST_SEL_REJECT:
 1033: 				if (!(statval & OLD_CTL_PST_SANE))
 1034: 					condition = "insane";
 1035: 				else if (!(statval & OLD_CTL_PST_DISP))
 1036: 					condition = "hi_disp";
 1037: 				else
 1038: 					condition = "";
 1039: 				break;
 1040: 
 1041: 			case OLD_CTL_PST_SEL_SELCAND:
 1042: 				condition = "sel_cand";
 1043: 				break;
 1044: 
 1045: 			case OLD_CTL_PST_SEL_SYNCCAND:
 1046: 				condition = "sync_cand";
 1047: 				break;
 1048: 
 1049: 			case OLD_CTL_PST_SEL_SYSPEER:
 1050: 				condition = "sys_peer";
 1051: 				break;
 1052: 			}
 1053: 		}
 1054: 		switch (PEER_EVENT|event) {
 1055: 
 1056: 		case PEVNT_MOBIL:
 1057: 			last_event = "mobilize";
 1058: 			break;
 1059: 
 1060: 		case PEVNT_DEMOBIL:
 1061: 			last_event = "demobilize";
 1062: 			break;
 1063: 
 1064: 		case PEVNT_REACH:
 1065: 			last_event = "reachable";
 1066: 			break;
 1067: 
 1068: 		case PEVNT_UNREACH:
 1069: 			last_event = "unreachable";
 1070: 			break;
 1071: 
 1072: 		case PEVNT_RESTART:
 1073: 			last_event = "restart";
 1074: 			break;
 1075: 
 1076: 		case PEVNT_REPLY:
 1077: 			last_event = "no_reply";
 1078: 			break;
 1079: 
 1080: 		case PEVNT_RATE:
 1081: 			last_event = "rate_exceeded";
 1082: 			break;
 1083: 
 1084: 		case PEVNT_DENY:
 1085: 			last_event = "access_denied";
 1086: 			break;
 1087: 
 1088: 		case PEVNT_ARMED:
 1089: 			last_event = "leap_armed";
 1090: 			break;
 1091: 
 1092: 		case PEVNT_NEWPEER:
 1093: 			last_event = "sys_peer";
 1094: 			break;
 1095: 
 1096: 		case PEVNT_CLOCK:
 1097: 			last_event = "clock_alarm";
 1098: 			break;
 1099: 
 1100: 		default:
 1101: 			last_event = "";
 1102: 			break;
 1103: 		}
 1104: 		cnt = uinttoa(event_count);
 1105: 		snprintf(buf, sizeof(buf),
 1106: 			 "%3d %5u  %04x   %3.3s  %4s  %4.4s %9.9s %11s %2s",
 1107: 			 i + 1, assoc_cache[i].assid,
 1108: 			 assoc_cache[i].status, conf, reach, auth,
 1109: 			 condition, last_event, cnt);
 1110: 		bp = buf + strlen(buf);
 1111: 		while (bp > buf && ' ' == bp[-1])
 1112: 			--bp;
 1113: 		bp[0] = '\0';
 1114: 		fprintf(fp, "%s\n", buf);
 1115: 	}
 1116: }
 1117: 
 1118: 
 1119: /*
 1120:  * associations - get, record and print a list of associations
 1121:  */
 1122: /*ARGSUSED*/
 1123: static void
 1124: associations(
 1125: 	struct parse *pcmd,
 1126: 	FILE *fp
 1127: 	)
 1128: {
 1129: 	if (dogetassoc(fp))
 1130: 		printassoc(0, fp);
 1131: }
 1132: 
 1133: 
 1134: /*
 1135:  * lassociations - get, record and print a long list of associations
 1136:  */
 1137: /*ARGSUSED*/
 1138: static void
 1139: lassociations(
 1140: 	struct parse *pcmd,
 1141: 	FILE *fp
 1142: 	)
 1143: {
 1144: 	if (dogetassoc(fp))
 1145: 		printassoc(1, fp);
 1146: }
 1147: 
 1148: 
 1149: /*
 1150:  * passociations - print the association list
 1151:  */
 1152: /*ARGSUSED*/
 1153: static void
 1154: passociations(
 1155: 	struct parse *pcmd,
 1156: 	FILE *fp
 1157: 	)
 1158: {
 1159: 	printassoc(0, fp);
 1160: }
 1161: 
 1162: 
 1163: /*
 1164:  * lpassociations - print the long association list
 1165:  */
 1166: /*ARGSUSED*/
 1167: static void
 1168: lpassociations(
 1169: 	struct parse *pcmd,
 1170: 	FILE *fp
 1171: 	)
 1172: {
 1173: 	printassoc(1, fp);
 1174: }
 1175: 
 1176: 
 1177: /*
 1178:  *  saveconfig - dump ntp server configuration to server file
 1179:  */
 1180: static void
 1181: saveconfig(
 1182: 	struct parse *pcmd,
 1183: 	FILE *fp
 1184: 	)
 1185: {
 1186: 	const char *datap;
 1187: 	int res;
 1188: 	int dsize;
 1189: 	u_short rstatus;
 1190: 
 1191: 	if (0 == pcmd->nargs)
 1192: 		return;
 1193: 	
 1194: 	res = doquery(CTL_OP_SAVECONFIG, 0, 1,
 1195: 		      strlen(pcmd->argval[0].string),
 1196: 		      pcmd->argval[0].string, &rstatus, &dsize,
 1197: 		      &datap);
 1198: 
 1199: 	if (res != 0)
 1200: 		return;
 1201: 
 1202: 	if (0 == dsize)
 1203: 		fprintf(fp, "(no response message, curiously)");
 1204: 	else
 1205: 		fprintf(fp, "%.*s", dsize, datap);
 1206: }
 1207: 
 1208: 
 1209: #ifdef	UNUSED
 1210: /*
 1211:  * radiostatus - print the radio status returned by the server
 1212:  */
 1213: /*ARGSUSED*/
 1214: static void
 1215: radiostatus(
 1216: 	struct parse *pcmd,
 1217: 	FILE *fp
 1218: 	)
 1219: {
 1220: 	char *datap;
 1221: 	int res;
 1222: 	int dsize;
 1223: 	u_short rstatus;
 1224: 
 1225: 	res = doquery(CTL_OP_READCLOCK, 0, 0, 0, (char *)0, &rstatus,
 1226: 			  &dsize, &datap);
 1227: 
 1228: 	if (res != 0)
 1229: 		return;
 1230: 
 1231: 	if (numhosts > 1)
 1232: 		(void) fprintf(fp, "server=%s ", currenthost);
 1233: 	if (dsize == 0) {
 1234: 		(void) fprintf(fp, "No radio status string returned\n");
 1235: 		return;
 1236: 	}
 1237: 
 1238: 	asciize(dsize, datap, fp);
 1239: }
 1240: #endif	/* UNUSED */
 1241: 
 1242: /*
 1243:  * pstatus - print peer status returned by the server
 1244:  */
 1245: static void
 1246: pstatus(
 1247: 	struct parse *pcmd,
 1248: 	FILE *fp
 1249: 	)
 1250: {
 1251: 	const char *datap;
 1252: 	int res;
 1253: 	associd_t associd;
 1254: 	int dsize;
 1255: 	u_short rstatus;
 1256: 
 1257: 	/* HMS: uval? */
 1258: 	if ((associd = checkassocid(pcmd->argval[0].uval)) == 0)
 1259: 		return;
 1260: 
 1261: 	res = doquery(CTL_OP_READSTAT, associd, 0, 0, NULL, &rstatus,
 1262: 		      &dsize, &datap);
 1263: 
 1264: 	if (res != 0)
 1265: 		return;
 1266: 
 1267: 	if (numhosts > 1)
 1268: 		fprintf(fp, "server=%s ", currenthost);
 1269: 	if (dsize == 0) {
 1270: 		fprintf(fp,
 1271: 			"No information returned for association %u\n",
 1272: 			associd);
 1273: 		return;
 1274: 	}
 1275: 
 1276: 	fprintf(fp, "associd=%u ", associd);
 1277: 	printvars(dsize, datap, (int)rstatus, TYPE_PEER, 0, fp);
 1278: }
 1279: 
 1280: 
 1281: /*
 1282:  * when - print how long its been since his last packet arrived
 1283:  */
 1284: static long
 1285: when(
 1286: 	l_fp *ts,
 1287: 	l_fp *rec,
 1288: 	l_fp *reftime
 1289: 	)
 1290: {
 1291: 	l_fp *lasttime;
 1292: 
 1293: 	if (rec->l_ui != 0)
 1294: 		lasttime = rec;
 1295: 	else if (reftime->l_ui != 0)
 1296: 		lasttime = reftime;
 1297: 	else
 1298: 		return 0;
 1299: 
 1300: 	return (ts->l_ui - lasttime->l_ui);
 1301: }
 1302: 
 1303: 
 1304: /*
 1305:  * Pretty-print an interval into the given buffer, in a human-friendly format.
 1306:  */
 1307: static char *
 1308: prettyinterval(
 1309: 	char *buf,
 1310: 	size_t cb,
 1311: 	long diff
 1312: 	)
 1313: {
 1314: 	if (diff <= 0) {
 1315: 		buf[0] = '-';
 1316: 		buf[1] = 0;
 1317: 		return buf;
 1318: 	}
 1319: 
 1320: 	if (diff <= 2048) {
 1321: 		snprintf(buf, cb, "%ld", diff);
 1322: 		return buf;
 1323: 	}
 1324: 
 1325: 	diff = (diff + 29) / 60;
 1326: 	if (diff <= 300) {
 1327: 		snprintf(buf, cb, "%ldm", diff);
 1328: 		return buf;
 1329: 	}
 1330: 
 1331: 	diff = (diff + 29) / 60;
 1332: 	if (diff <= 96) {
 1333: 		snprintf(buf, cb, "%ldh", diff);
 1334: 		return buf;
 1335: 	}
 1336: 
 1337: 	diff = (diff + 11) / 24;
 1338: 	snprintf(buf, cb, "%ldd", diff);
 1339: 	return buf;
 1340: }
 1341: 
 1342: static char
 1343: decodeaddrtype(
 1344: 	sockaddr_u *sock
 1345: 	)
 1346: {
 1347: 	char ch = '-';
 1348: 	u_int32 dummy;
 1349: 
 1350: 	switch(AF(sock)) {
 1351: 	case AF_INET:
 1352: 		dummy = SRCADR(sock);
 1353: 		ch = (char)(((dummy&0xf0000000)==0xe0000000) ? 'm' :
 1354: 			((dummy&0x000000ff)==0x000000ff) ? 'b' :
 1355: 			((dummy&0xffffffff)==0x7f000001) ? 'l' :
 1356: 			((dummy&0xffffffe0)==0x00000000) ? '-' :
 1357: 			'u');
 1358: 		break;
 1359: 	case AF_INET6:
 1360: 		if (IN6_IS_ADDR_MULTICAST(PSOCK_ADDR6(sock)))
 1361: 			ch = 'm';
 1362: 		else
 1363: 			ch = 'u';
 1364: 		break;
 1365: 	default:
 1366: 		ch = '-';
 1367: 		break;
 1368: 	}
 1369: 	return ch;
 1370: }
 1371: 
 1372: /*
 1373:  * A list of variables required by the peers command
 1374:  */
 1375: struct varlist opeervarlist[] = {
 1376: 	{ "srcadr", 0 },    /* 0 */
 1377: 	{ "dstadr", 0 },    /* 1 */
 1378: 	{ "stratum",    0 },    /* 2 */
 1379: 	{ "hpoll",  0 },    /* 3 */
 1380: 	{ "ppoll",  0 },    /* 4 */
 1381: 	{ "reach",  0 },    /* 5 */
 1382: 	{ "delay",  0 },    /* 6 */
 1383: 	{ "offset", 0 },    /* 7 */
 1384: 	{ "jitter", 0 },    /* 8 */
 1385: 	{ "dispersion", 0 },    /* 9 */
 1386: 	{ "rec",    0 },    /* 10 */
 1387: 	{ "reftime",    0 },    /* 11 */
 1388: 	{ "srcport",    0 },    /* 12 */
 1389: 	{ 0,		0 }
 1390: };
 1391: 
 1392: struct varlist peervarlist[] = {
 1393: 	{ "srcadr", 0 },    /* 0 */
 1394: 	{ "refid",  0 },    /* 1 */
 1395: 	{ "stratum",    0 },    /* 2 */
 1396: 	{ "hpoll",  0 },    /* 3 */
 1397: 	{ "ppoll",  0 },    /* 4 */
 1398: 	{ "reach",  0 },    /* 5 */
 1399: 	{ "delay",  0 },    /* 6 */
 1400: 	{ "offset", 0 },    /* 7 */
 1401: 	{ "jitter", 0 },    /* 8 */
 1402: 	{ "dispersion", 0 },    /* 9 */
 1403: 	{ "rec",    0 },    /* 10 */
 1404: 	{ "reftime",    0 },    /* 11 */
 1405: 	{ "srcport",    0 },    /* 12 */
 1406: 	{ 0,		0 }
 1407: };
 1408: 
 1409: #define HAVE_SRCADR 0
 1410: #define HAVE_DSTADR 1
 1411: #define HAVE_REFID	1
 1412: #define HAVE_STRATUM	2
 1413: #define HAVE_HPOLL	3
 1414: #define HAVE_PPOLL	4
 1415: #define HAVE_REACH	5
 1416: #define HAVE_DELAY	6
 1417: #define HAVE_OFFSET 7
 1418: #define HAVE_JITTER 8
 1419: #define HAVE_DISPERSION 9
 1420: #define HAVE_REC	10
 1421: #define HAVE_REFTIME	11
 1422: #define HAVE_SRCPORT	12
 1423: #define MAXHAVE 	13
 1424: 
 1425: /*
 1426:  * Decode an incoming data buffer and print a line in the peer list
 1427:  */
 1428: static int
 1429: doprintpeers(
 1430: 	struct varlist *pvl,
 1431: 	int associd,
 1432: 	int rstatus,
 1433: 	int datalen,
 1434: 	const char *data,
 1435: 	FILE *fp,
 1436: 	int af
 1437: 	)
 1438: {
 1439: 	char *name;
 1440: 	char *value = NULL;
 1441: 	int i;
 1442: 	int c;
 1443: 
 1444: 	sockaddr_u srcadr;
 1445: 	sockaddr_u dstadr;
 1446: 	sockaddr_u refidadr;
 1447: 	u_long srcport = 0;
 1448: 	char *dstadr_refid = "0.0.0.0";
 1449: 	char *serverlocal;
 1450: 	size_t drlen;
 1451: 	u_long stratum = 0;
 1452: 	long ppoll = 0;
 1453: 	long hpoll = 0;
 1454: 	u_long reach = 0;
 1455: 	l_fp estoffset;
 1456: 	l_fp estdelay;
 1457: 	l_fp estjitter;
 1458: 	l_fp estdisp;
 1459: 	l_fp reftime;
 1460: 	l_fp rec;
 1461: 	l_fp ts;
 1462: 	u_char havevar[MAXHAVE];
 1463: 	u_long poll_sec;
 1464: 	char type = '?';
 1465: 	char refid_string[10];
 1466: 	char whenbuf[8], pollbuf[8];
 1467: 	char clock_name[LENHOSTNAME];
 1468: 
 1469: 	memset((char *)havevar, 0, sizeof(havevar));
 1470: 	get_systime(&ts);
 1471: 	
 1472: 	ZERO_SOCK(&srcadr);
 1473: 	ZERO_SOCK(&dstadr);
 1474: 
 1475: 	/* Initialize by zeroing out estimate variables */
 1476: 	memset((char *)&estoffset, 0, sizeof(l_fp));
 1477: 	memset((char *)&estdelay, 0, sizeof(l_fp));
 1478: 	memset((char *)&estjitter, 0, sizeof(l_fp));
 1479: 	memset((char *)&estdisp, 0, sizeof(l_fp));
 1480: 
 1481: 	while (nextvar(&datalen, &data, &name, &value)) {
 1482: 		sockaddr_u dum_store;
 1483: 
 1484: 		i = findvar(name, peer_var, 1);
 1485: 		if (i == 0)
 1486: 			continue;	/* don't know this one */
 1487: 		switch (i) {
 1488: 			case CP_SRCADR:
 1489: 			if (decodenetnum(value, &srcadr)) {
 1490: 				havevar[HAVE_SRCADR] = 1;
 1491: 			}
 1492: 			break;
 1493: 			case CP_DSTADR:
 1494: 			if (decodenetnum(value, &dum_store)) {
 1495: 				type = decodeaddrtype(&dum_store);
 1496: 				havevar[HAVE_DSTADR] = 1;
 1497: 				dstadr = dum_store;
 1498: 				if (pvl == opeervarlist) {
 1499: 					dstadr_refid = trunc_left(stoa(&dstadr), 15);
 1500: 				}
 1501: 			}
 1502: 			break;
 1503: 			case CP_REFID:
 1504: 			if (pvl == peervarlist) {
 1505: 				havevar[HAVE_REFID] = 1;
 1506: 				if (*value == '\0') {
 1507: 					dstadr_refid = "";
 1508: 				} else if (strlen(value) <= 4) {
 1509: 					refid_string[0] = '.';
 1510: 					(void) strcpy(&refid_string[1], value);
 1511: 					i = strlen(refid_string);
 1512: 					refid_string[i] = '.';
 1513: 					refid_string[i+1] = '\0';
 1514: 					dstadr_refid = refid_string;
 1515: 				} else if (decodenetnum(value, &refidadr)) {
 1516: 					if (SOCK_UNSPEC(&refidadr))
 1517: 						dstadr_refid = "0.0.0.0";
 1518: 					else if (ISREFCLOCKADR(&refidadr))
 1519: 						dstadr_refid =
 1520: 						    refnumtoa(&refidadr);
 1521: 					else
 1522: 						dstadr_refid =
 1523: 						    stoa(&refidadr);
 1524: 				} else {
 1525: 					havevar[HAVE_REFID] = 0;
 1526: 				}
 1527: 			}
 1528: 			break;
 1529: 			case CP_STRATUM:
 1530: 			if (decodeuint(value, &stratum))
 1531: 				havevar[HAVE_STRATUM] = 1;
 1532: 			break;
 1533: 			case CP_HPOLL:
 1534: 			if (decodeint(value, &hpoll)) {
 1535: 				havevar[HAVE_HPOLL] = 1;
 1536: 				if (hpoll < 0)
 1537: 					hpoll = NTP_MINPOLL;
 1538: 			}
 1539: 			break;
 1540: 			case CP_PPOLL:
 1541: 			if (decodeint(value, &ppoll)) {
 1542: 				havevar[HAVE_PPOLL] = 1;
 1543: 				if (ppoll < 0)
 1544: 					ppoll = NTP_MINPOLL;
 1545: 			}
 1546: 			break;
 1547: 			case CP_REACH:
 1548: 			if (decodeuint(value, &reach))
 1549: 				havevar[HAVE_REACH] = 1;
 1550: 			break;
 1551: 			case CP_DELAY:
 1552: 			if (decodetime(value, &estdelay))
 1553: 				havevar[HAVE_DELAY] = 1;
 1554: 			break;
 1555: 			case CP_OFFSET:
 1556: 			if (decodetime(value, &estoffset))
 1557: 				havevar[HAVE_OFFSET] = 1;
 1558: 			break;
 1559: 			case CP_JITTER:
 1560: 			if (pvl == peervarlist)
 1561: 				if (decodetime(value, &estjitter))
 1562: 					havevar[HAVE_JITTER] = 1;
 1563: 			break;
 1564: 			case CP_DISPERSION:
 1565: 			if (decodetime(value, &estdisp))
 1566: 				havevar[HAVE_DISPERSION] = 1;
 1567: 			break;
 1568: 			case CP_REC:
 1569: 			if (decodets(value, &rec))
 1570: 				havevar[HAVE_REC] = 1;
 1571: 			break;
 1572: 			case CP_SRCPORT:
 1573: 			if (decodeuint(value, &srcport))
 1574: 				havevar[HAVE_SRCPORT] = 1;
 1575: 			break;
 1576: 			case CP_REFTIME:
 1577: 			havevar[HAVE_REFTIME] = 1;
 1578: 			if (!decodets(value, &reftime))
 1579: 				L_CLR(&reftime);
 1580: 			break;
 1581: 			default:
 1582: 			break;
 1583: 		}
 1584: 	}
 1585: 
 1586: 	/*
 1587: 	 * Check to see if the srcport is NTP's port.  If not this probably
 1588: 	 * isn't a valid peer association.
 1589: 	 */
 1590: 	if (havevar[HAVE_SRCPORT] && srcport != NTP_PORT)
 1591: 		return (1);
 1592: 
 1593: 	/*
 1594: 	 * Got everything, format the line
 1595: 	 */
 1596: 	poll_sec = 1<<max(min3(ppoll, hpoll, NTP_MAXPOLL), NTP_MINPOLL);
 1597: 	if (pktversion > NTP_OLDVERSION)
 1598: 		c = flash3[CTL_PEER_STATVAL(rstatus) & 0x7];
 1599: 	else
 1600: 		c = flash2[CTL_PEER_STATVAL(rstatus) & 0x3];
 1601: 	if (numhosts > 1) {
 1602: 		if (peervarlist == pvl && havevar[HAVE_DSTADR]) {
 1603: 			serverlocal = nntohost_col(&dstadr,
 1604: 			    (size_t)min(LIB_BUFLENGTH - 1, maxhostlen),
 1605: 			    TRUE);
 1606: 		} else {
 1607: 			if (currenthostisnum)
 1608: 				serverlocal = trunc_left(currenthost,
 1609: 							 maxhostlen);
 1610: 			else
 1611: 				serverlocal = currenthost;
 1612: 		}
 1613: 		fprintf(fp, "%-*s ", maxhostlen, serverlocal);
 1614: 	}
 1615: 	if (AF_UNSPEC == af || AF(&srcadr) == af) {
 1616: 		strncpy(clock_name, nntohost(&srcadr), sizeof(clock_name));		
 1617: 		fprintf(fp, "%c%-15.15s ", c, clock_name);
 1618: 		drlen = strlen(dstadr_refid);
 1619: 		makeascii(drlen, dstadr_refid, fp);
 1620: 		while (drlen++ < 15)
 1621: 			fputc(' ', fp);
 1622: 		fprintf(fp,
 1623: 			" %2ld %c %4.4s %4.4s  %3lo  %7.7s %8.7s %7.7s\n",
 1624: 			stratum, type,
 1625: 			prettyinterval(whenbuf, sizeof(whenbuf),
 1626: 				       when(&ts, &rec, &reftime)),
 1627: 			prettyinterval(pollbuf, sizeof(pollbuf), 
 1628: 				       (int)poll_sec),
 1629: 			reach, lfptoms(&estdelay, 3),
 1630: 			lfptoms(&estoffset, 3),
 1631: 			(havevar[HAVE_JITTER])
 1632: 			    ? lfptoms(&estjitter, 3)
 1633: 			    : lfptoms(&estdisp, 3));
 1634: 		return (1);
 1635: 	}
 1636: 	else
 1637: 		return(1);
 1638: }
 1639: 
 1640: #undef	HAVE_SRCADR
 1641: #undef	HAVE_DSTADR
 1642: #undef	HAVE_STRATUM
 1643: #undef	HAVE_PPOLL
 1644: #undef	HAVE_HPOLL
 1645: #undef	HAVE_REACH
 1646: #undef	HAVE_ESTDELAY
 1647: #undef	HAVE_ESTOFFSET
 1648: #undef	HAVE_JITTER
 1649: #undef	HAVE_ESTDISP
 1650: #undef	HAVE_REFID
 1651: #undef	HAVE_REC
 1652: #undef	HAVE_SRCPORT
 1653: #undef	HAVE_REFTIME
 1654: #undef	MAXHAVE
 1655: 
 1656: 
 1657: /*
 1658:  * dogetpeers - given an association ID, read and print the spreadsheet
 1659:  *		peer variables.
 1660:  */
 1661: static int
 1662: dogetpeers(
 1663: 	struct varlist *pvl,
 1664: 	associd_t associd,
 1665: 	FILE *fp,
 1666: 	int af
 1667: 	)
 1668: {
 1669: 	const char *datap;
 1670: 	int res;
 1671: 	int dsize;
 1672: 	u_short rstatus;
 1673: 
 1674: #ifdef notdef
 1675: 	res = doquerylist(pvl, CTL_OP_READVAR, associd, 0, &rstatus,
 1676: 			  &dsize, &datap);
 1677: #else
 1678: 	/*
 1679: 	 * Damn fuzzballs
 1680: 	 */
 1681: 	res = doquery(CTL_OP_READVAR, associd, 0, 0, NULL, &rstatus,
 1682: 			  &dsize, &datap);
 1683: #endif
 1684: 
 1685: 	if (res != 0)
 1686: 		return 0;
 1687: 
 1688: 	if (dsize == 0) {
 1689: 		if (numhosts > 1)
 1690: 			fprintf(stderr, "server=%s ", currenthost);
 1691: 		fprintf(stderr,
 1692: 			"***No information returned for association %u\n",
 1693: 			associd);
 1694: 		return 0;
 1695: 	}
 1696: 
 1697: 	return doprintpeers(pvl, associd, (int)rstatus, dsize, datap,
 1698: 			    fp, af);
 1699: }
 1700: 
 1701: 
 1702: /*
 1703:  * peers - print a peer spreadsheet
 1704:  */
 1705: static void
 1706: dopeers(
 1707: 	int showall,
 1708: 	FILE *fp,
 1709: 	int af
 1710: 	)
 1711: {
 1712: 	int		i;
 1713: 	char		fullname[LENHOSTNAME];
 1714: 	sockaddr_u	netnum;
 1715: 	char *		name_or_num;
 1716: 	size_t		sl;
 1717: 
 1718: 	if (!dogetassoc(fp))
 1719: 		return;
 1720: 
 1721: 	for (i = 0; i < numhosts; ++i) {
 1722: 		if (getnetnum(chosts[i], &netnum, fullname, af)) {
 1723: 			name_or_num = nntohost(&netnum);
 1724: 			sl = strlen(name_or_num);
 1725: 			maxhostlen = max(maxhostlen, (int)sl);
 1726: 		}
 1727: 	}
 1728: 	if (numhosts > 1)
 1729: 		fprintf(fp, "%-*.*s ", maxhostlen, maxhostlen,
 1730: 			"server (local)");
 1731: 	fprintf(fp,
 1732: 		"     remote           refid      st t when poll reach   delay   offset  jitter\n");
 1733: 	if (numhosts > 1)
 1734: 		for (i = 0; i <= maxhostlen; ++i)
 1735: 			fprintf(fp, "=");
 1736: 	fprintf(fp,
 1737: 		"==============================================================================\n");
 1738: 
 1739: 	for (i = 0; i < numassoc; i++) {
 1740: 		if (!showall &&
 1741: 			!(CTL_PEER_STATVAL(assoc_cache[i].status)
 1742: 			  & (CTL_PST_CONFIG|CTL_PST_REACH)))
 1743: 			continue;
 1744: 		if (!dogetpeers(peervarlist, (int)assoc_cache[i].assid, fp, af)) {
 1745: 			return;
 1746: 		}
 1747: 	}
 1748: 	return;
 1749: }
 1750: 
 1751: 
 1752: /*
 1753:  * peers - print a peer spreadsheet
 1754:  */
 1755: /*ARGSUSED*/
 1756: static void
 1757: peers(
 1758: 	struct parse *pcmd,
 1759: 	FILE *fp
 1760: 	)
 1761: {
 1762: 	int af = 0;
 1763: 
 1764: 	if (pcmd->nargs == 1) {
 1765: 		if (pcmd->argval->ival == 6)
 1766: 			af = AF_INET6;
 1767: 		else
 1768: 			af = AF_INET;
 1769: 	}
 1770: 	dopeers(0, fp, af);
 1771: }
 1772: 
 1773: 
 1774: /*
 1775:  * lpeers - print a peer spreadsheet including all fuzzball peers
 1776:  */
 1777: /*ARGSUSED*/
 1778: static void
 1779: lpeers(
 1780: 	struct parse *pcmd,
 1781: 	FILE *fp
 1782: 	)
 1783: {
 1784: 	int af = 0;
 1785: 
 1786: 	if (pcmd->nargs == 1) {
 1787: 		if (pcmd->argval->ival == 6)
 1788: 			af = AF_INET6;
 1789: 		else
 1790: 			af = AF_INET;
 1791: 	}
 1792: 	dopeers(1, fp, af);
 1793: }
 1794: 
 1795: 
 1796: /*
 1797:  * opeers - print a peer spreadsheet
 1798:  */
 1799: static void
 1800: doopeers(
 1801: 	int showall,
 1802: 	FILE *fp,
 1803: 	int af
 1804: 	)
 1805: {
 1806: 	register int i;
 1807: 	char fullname[LENHOSTNAME];
 1808: 	sockaddr_u netnum;
 1809: 
 1810: 	if (!dogetassoc(fp))
 1811: 		return;
 1812: 
 1813: 	for (i = 0; i < numhosts; ++i) {
 1814: 		if (getnetnum(chosts[i], &netnum, fullname, af))
 1815: 			if ((int)strlen(fullname) > maxhostlen)
 1816: 				maxhostlen = strlen(fullname);
 1817: 	}
 1818: 	if (numhosts > 1)
 1819: 		(void) fprintf(fp, "%-*.*s ", maxhostlen, maxhostlen, "server");
 1820: 	(void) fprintf(fp,
 1821: 			   "     remote           local      st t when poll reach   delay   offset    disp\n");
 1822: 	if (numhosts > 1)
 1823: 		for (i = 0; i <= maxhostlen; ++i)
 1824: 		(void) fprintf(fp, "=");
 1825: 	(void) fprintf(fp,
 1826: 			   "==============================================================================\n");
 1827: 
 1828: 	for (i = 0; i < numassoc; i++) {
 1829: 		if (!showall &&
 1830: 			!(CTL_PEER_STATVAL(assoc_cache[i].status)
 1831: 			  & (CTL_PST_CONFIG|CTL_PST_REACH)))
 1832: 			continue;
 1833: 		if (!dogetpeers(opeervarlist, (int)assoc_cache[i].assid, fp, af)) {
 1834: 			return;
 1835: 		}
 1836: 	}
 1837: 	return;
 1838: }
 1839: 
 1840: 
 1841: /*
 1842:  * opeers - print a peer spreadsheet the old way
 1843:  */
 1844: /*ARGSUSED*/
 1845: static void
 1846: opeers(
 1847: 	struct parse *pcmd,
 1848: 	FILE *fp
 1849: 	)
 1850: {
 1851: 	int af = 0;
 1852: 
 1853: 	if (pcmd->nargs == 1) {
 1854: 		if (pcmd->argval->ival == 6)
 1855: 			af = AF_INET6;
 1856: 		else
 1857: 			af = AF_INET;
 1858: 	}
 1859: 	doopeers(0, fp, af);
 1860: }
 1861: 
 1862: 
 1863: /*
 1864:  * lopeers - print a peer spreadsheet including all fuzzball peers
 1865:  */
 1866: /*ARGSUSED*/
 1867: static void
 1868: lopeers(
 1869: 	struct parse *pcmd,
 1870: 	FILE *fp
 1871: 	)
 1872: {
 1873: 	int af = 0;
 1874: 
 1875: 	if (pcmd->nargs == 1) {
 1876: 		if (pcmd->argval->ival == 6)
 1877: 			af = AF_INET6;
 1878: 		else
 1879: 			af = AF_INET;
 1880: 	}
 1881: 	doopeers(1, fp, af);
 1882: }
 1883: 
 1884: 
 1885: /* 
 1886:  * config - send a configuration command to a remote host
 1887:  */
 1888: static void 
 1889: config (
 1890: 	struct parse *pcmd,
 1891: 	FILE *fp
 1892: 	)
 1893: {
 1894: 	char *cfgcmd;
 1895: 	u_short rstatus;
 1896: 	int rsize;
 1897: 	const char *rdata;
 1898: 	char *resp;
 1899: 	int res;
 1900: 	int col;
 1901: 	int i;
 1902: 
 1903: 	cfgcmd = pcmd->argval[0].string;
 1904: 
 1905: 	if (debug > 2)
 1906: 		fprintf(stderr, 
 1907: 			"In Config\n"
 1908: 			"Keyword = %s\n"
 1909: 			"Command = %s\n", pcmd->keyword, cfgcmd);
 1910: 
 1911: 	res = doquery(CTL_OP_CONFIGURE, 0, 1, strlen(cfgcmd), cfgcmd,
 1912: 		      &rstatus, &rsize, &rdata);
 1913: 
 1914: 	if (res != 0)
 1915: 		return;
 1916: 
 1917: 	if (rsize > 0 && '\n' == rdata[rsize - 1])
 1918: 		rsize--;
 1919: 
 1920: 	resp = emalloc(rsize + 1);
 1921: 	memcpy(resp, rdata, rsize);
 1922: 	resp[rsize] = '\0';
 1923: 
 1924: 	col = -1;
 1925: 	if (1 == sscanf(resp, "column %d syntax error", &col)
 1926: 	    && col >= 0 && (size_t)col <= strlen(cfgcmd) + 1) {
 1927: 		if (interactive) {
 1928: 			printf("______");	/* "ntpq> " */
 1929: 			printf("________");	/* ":config " */
 1930: 		} else
 1931: 			printf("%s\n", cfgcmd);
 1932: 		for (i = 1; i < col; i++)
 1933: 			putchar('_');
 1934: 		printf("^\n");
 1935: 	}
 1936: 	printf("%s\n", resp);
 1937: 	free(resp);
 1938: }
 1939: 
 1940: 
 1941: /* 
 1942:  * config_from_file - remotely configure an ntpd daemon using the
 1943:  * specified configuration file
 1944:  * SK: This function is a kludge at best and is full of bad design
 1945:  * bugs:
 1946:  * 1. ntpq uses UDP, which means that there is no guarantee of in-order,
 1947:  *    error-free delivery. 
 1948:  * 2. The maximum length of a packet is constrained, and as a result, the
 1949:  *    maximum length of a line in a configuration file is constrained. 
 1950:  *    Longer lines will lead to unpredictable results.
 1951:  * 3. Since this function is sending a line at a time, we can't update
 1952:  *    the control key through the configuration file (YUCK!!)
 1953:  */
 1954: static void 
 1955: config_from_file (
 1956: 	struct parse *pcmd,
 1957: 	FILE *fp
 1958: 	)
 1959: {
 1960: 	u_short rstatus;
 1961: 	int rsize;
 1962: 	const char *rdata;
 1963: 	int res;
 1964: 	FILE *config_fd;
 1965: 	char config_cmd[MAXLINE];
 1966: 	size_t config_len;
 1967: 	int i;
 1968: 	int retry_limit;
 1969: 
 1970: 	if (debug > 2)
 1971: 		fprintf(stderr,
 1972: 			"In Config\n"
 1973: 			"Keyword = %s\n"
 1974: 			"Filename = %s\n", pcmd->keyword,
 1975: 			pcmd->argval[0].string);
 1976: 
 1977: 	config_fd = fopen(pcmd->argval[0].string, "r");
 1978: 	if (NULL == config_fd) {
 1979: 		printf("ERROR!! Couldn't open file: %s\n",
 1980: 		       pcmd->argval[0].string);
 1981: 		return;
 1982: 	}
 1983: 
 1984: 	printf("Sending configuration file, one line at a time.\n");
 1985: 	i = 0;
 1986: 	while (fgets(config_cmd, MAXLINE, config_fd) != NULL) {
 1987: 		config_len = strlen(config_cmd);
 1988: 		/* ensure even the last line has newline, if possible */
 1989: 		if (config_len > 0 && 
 1990: 		    config_len + 2 < sizeof(config_cmd) &&
 1991: 		    '\n' != config_cmd[config_len - 1])
 1992: 			config_cmd[config_len++] = '\n';
 1993: 		++i;
 1994: 		retry_limit = 2;
 1995: 		do 
 1996: 			res = doquery(CTL_OP_CONFIGURE, 0, 1,
 1997: 				      strlen(config_cmd), config_cmd,
 1998: 				      &rstatus, &rsize, &rdata);
 1999: 		while (res != 0 && retry_limit--);
 2000: 		if (res != 0) {
 2001: 			printf("Line No: %d query failed: %s", i,
 2002: 			       config_cmd);
 2003: 			printf("Subsequent lines not sent.\n");
 2004: 			fclose(config_fd);
 2005: 			return;
 2006: 		}
 2007: 
 2008: 		if (rsize > 0 && '\n' == rdata[rsize - 1])
 2009: 			rsize--;
 2010: 		if (rsize > 0 && '\r' == rdata[rsize - 1])
 2011: 			rsize--;
 2012: 		printf("Line No: %d %.*s: %s", i, rsize, rdata,
 2013: 		       config_cmd);
 2014: 	}
 2015: 	printf("Done sending file\n");
 2016: 	fclose(config_fd);
 2017: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>