File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / ntp / ntpq / ntpq.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, 1 month ago) by misho
Branches: ntp, MAIN
CVS tags: v4_2_6p5p0, v4_2_6p5, HEAD
ntp 4.2.6p5

    1: /*
    2:  * ntpq - query an NTP server using mode 6 commands
    3:  */
    4: 
    5: #include <stdio.h>
    6: 
    7: #include <ctype.h>
    8: #include <signal.h>
    9: #include <setjmp.h>
   10: #include <sys/types.h>
   11: #include <sys/time.h>
   12: 
   13: #include "ntpq.h"
   14: #include "ntp_unixtime.h"
   15: #include "ntp_calendar.h"
   16: #include "ntp_io.h"
   17: #include "ntp_select.h"
   18: #include "ntp_stdlib.h"
   19: #include "ntp_assert.h"
   20: #include "ntp_lineedit.h"
   21: #include "ntp_debug.h"
   22: #include "isc/net.h"
   23: #include "isc/result.h"
   24: #include <ssl_applink.c>
   25: 
   26: #include "ntp_libopts.h"
   27: #include "ntpq-opts.h"
   28: 
   29: #ifdef SYS_WINNT
   30: # include <Mswsock.h>
   31: # include <io.h>
   32: #endif /* SYS_WINNT */
   33: 
   34: #ifdef SYS_VXWORKS
   35: 				/* vxWorks needs mode flag -casey*/
   36: # define open(name, flags)   open(name, flags, 0777)
   37: # define SERVER_PORT_NUM     123
   38: #endif
   39: 
   40: /* we use COMMAND as an autogen keyword */
   41: #ifdef COMMAND
   42: # undef COMMAND
   43: #endif
   44: 
   45: /*
   46:  * Because we potentially understand a lot of commands we will run
   47:  * interactive if connected to a terminal.
   48:  */
   49: int interactive = 0;		/* set to 1 when we should prompt */
   50: const char *prompt = "ntpq> ";	/* prompt to ask him about */
   51: 
   52: /*
   53:  * use old readvars behavior?  --old-rv processing in ntpq resets
   54:  * this value based on the presence or absence of --old-rv.  It is
   55:  * initialized to 1 here to maintain backward compatibility with
   56:  * libntpq clients such as ntpsnmpd, which are free to reset it as
   57:  * desired.
   58:  */
   59: int	old_rv = 1;
   60: 
   61: 
   62: /*
   63:  * for get_systime()
   64:  */
   65: s_char	sys_precision;		/* local clock precision (log2 s) */
   66: 
   67: /*
   68:  * Keyid used for authenticated requests.  Obtained on the fly.
   69:  */
   70: u_long info_auth_keyid = 0;
   71: 
   72: static	int	info_auth_keytype = NID_md5;	/* MD5 */
   73: static	size_t	info_auth_hashlen = 16;		/* MD5 */
   74: u_long	current_time;		/* needed by authkeys; not used */
   75: 
   76: /*
   77:  * Flag which indicates we should always send authenticated requests
   78:  */
   79: int always_auth = 0;
   80: 
   81: /*
   82:  * Flag which indicates raw mode output.
   83:  */
   84: int rawmode = 0;
   85: 
   86: /*
   87:  * Packet version number we use
   88:  */
   89: u_char pktversion = NTP_OLDVERSION + 1;
   90: 
   91: /*
   92:  * Don't jump if no set jmp.
   93:  */
   94: volatile int jump = 0;
   95: 
   96: /*
   97:  * Format values
   98:  */
   99: #define	PADDING	0
  100: #define	TS	1	/* time stamp */
  101: #define	FL	2	/* l_fp type value */
  102: #define	FU	3	/* u_fp type value */
  103: #define	FS	4	/* s_fp type value */
  104: #define	UI	5	/* unsigned integer value */
  105: #define	SI	6	/* signed integer value */
  106: #define	HA	7	/* host address */
  107: #define	NA	8	/* network address */
  108: #define	ST	9	/* string value */
  109: #define	RF	10	/* refid (sometimes string, sometimes not) */
  110: #define	LP	11	/* leap (print in binary) */
  111: #define	OC	12	/* integer, print in octal */
  112: #define	MD	13	/* mode */
  113: #define	AR	14	/* array of times */
  114: #define FX	15	/* test flags */
  115: #define	EOV	255	/* end of table */
  116: 
  117: 
  118: /*
  119:  * System variable values.  The array can be indexed by
  120:  * the variable index to find the textual name.
  121:  */
  122: struct ctl_var sys_var[] = {
  123: 	{ 0,		PADDING, "" },		/* 0 */
  124: 	{ CS_LEAP,	LP,	"leap" },	/* 1 */
  125: 	{ CS_STRATUM,	UI,	"stratum" },	/* 2 */
  126: 	{ CS_PRECISION,	SI,	"precision" },	/* 3 */
  127: 	{ CS_ROOTDELAY,	FS,	"rootdelay" },	/* 4 */
  128: 	{ CS_ROOTDISPERSION, FU, "rootdispersion" }, /* 5 */
  129: 	{ CS_REFID,	RF,	"refid" },	/* 6 */
  130: 	{ CS_REFTIME,	TS,	"reftime" },	/* 7 */
  131: 	{ CS_POLL,	UI,	"poll" },	/* 8 */
  132: 	{ CS_PEERID,	UI,	"peer" },	/* 9 */
  133: 	{ CS_OFFSET,	FL,	"offset" },	/* 10 */
  134: 	{ CS_DRIFT,	FS,	"frequency" },	/* 11 */
  135: 	{ CS_JITTER,	FU,	"jitter" },	/* 12 */
  136: 	{ CS_CLOCK,	TS,	"clock" },	/* 13 */
  137: 	{ CS_PROCESSOR,	ST,	"processor" },	/* 14 */
  138: 	{ CS_SYSTEM,	ST,	"system" },	/* 15 */
  139: 	{ CS_VERSION,	ST,	"version" },	/* 16 */
  140: 	{ CS_STABIL,	FS,	"stability" },	/* 17 */
  141: 	{ CS_VARLIST,	ST,	"sys_var_list" }, /* 18 */
  142: 	{ 0,		EOV,	""	}
  143: };
  144: 
  145: 
  146: /*
  147:  * Peer variable list
  148:  */
  149: struct ctl_var peer_var[] = {
  150: 	{ 0,		PADDING, "" },		/* 0 */
  151: 	{ CP_CONFIG,	UI,	"config" },	/* 1 */
  152: 	{ CP_AUTHENABLE, UI,	"authenable" },	/* 2 */
  153: 	{ CP_AUTHENTIC,	UI,	"authentic" },	/* 3 */
  154: 	{ CP_SRCADR,	HA,	"srcadr" },	/* 4 */
  155: 	{ CP_SRCPORT,	UI,	"srcport" },	/* 5 */
  156: 	{ CP_DSTADR,	NA,	"dstadr" },	/* 6 */
  157: 	{ CP_DSTPORT,	UI,	"dstport" },	/* 7 */
  158: 	{ CP_LEAP,	LP,	"leap" },	/* 8 */
  159: 	{ CP_HMODE,	MD,	"hmode" },	/* 9 */
  160: 	{ CP_STRATUM,	UI,	"stratum" },	/* 10 */
  161: 	{ CP_PPOLL,	UI,	"ppoll" },	/* 11 */
  162: 	{ CP_HPOLL,	UI,	"hpoll" },	/* 12 */
  163: 	{ CP_PRECISION,	SI,	"precision" },	/* 13 */
  164: 	{ CP_ROOTDELAY,	FS,	"rootdelay" },	/* 14 */
  165: 	{ CP_ROOTDISPERSION, FU, "rootdisp" },	/* 15 */
  166: 	{ CP_REFID,	RF,	"refid" },	/* 16 */
  167: 	{ CP_REFTIME,	TS,	"reftime" },	/* 17 */
  168: 	{ CP_ORG,	TS,	"org" },	/* 18 */
  169: 	{ CP_REC,	TS,	"rec" },	/* 19 */
  170: 	{ CP_XMT,	TS,	"xmt" },	/* 20 */
  171: 	{ CP_REACH,	OC,	"reach" },	/* 21 */
  172: 	{ CP_UNREACH,	UI,	"unreach" },	/* 22 */
  173: 	{ CP_TIMER,	UI,	"timer" },	/* 23 */
  174: 	{ CP_DELAY,	FS,	"delay" },	/* 24 */
  175: 	{ CP_OFFSET,	FL,	"offset" },	/* 25 */
  176: 	{ CP_JITTER,	FU,	"jitter" },	/* 26 */
  177: 	{ CP_DISPERSION, FU,	"dispersion" },	/* 27 */
  178: 	{ CP_KEYID,	UI,	"keyid" },	/* 28 */
  179: 	{ CP_FILTDELAY,	AR,	"filtdelay" },	/* 29 */
  180: 	{ CP_FILTOFFSET, AR,	"filtoffset" },	/* 30 */
  181: 	{ CP_PMODE,	ST,	"pmode" },	/* 31 */
  182: 	{ CP_RECEIVED,	UI,	"received" },	/* 32 */
  183: 	{ CP_SENT,	UI,	"sent" },	/* 33 */
  184: 	{ CP_FILTERROR,	AR,	"filtdisp" },	/* 34 */
  185: 	{ CP_FLASH,     FX,	"flash" },	/* 35 */ 
  186: 	{ CP_TTL,	UI,	"ttl" },	/* 36 */
  187: 	/*
  188: 	 * These are duplicate entries so that we can
  189: 	 * process deviant version of the ntp protocol.
  190: 	 */
  191: 	{ CP_SRCADR,	HA,	"peeraddr" },	/* 4 */
  192: 	{ CP_SRCPORT,	UI,	"peerport" },	/* 5 */
  193: 	{ CP_PPOLL,	UI,	"peerpoll" },	/* 11 */
  194: 	{ CP_HPOLL,	UI,	"hostpoll" },	/* 12 */
  195: 	{ CP_FILTERROR,	AR,	"filterror" },	/* 34 */
  196: 	{ 0,		EOV,	""	}
  197: };
  198: 
  199: 
  200: /*
  201:  * Clock variable list
  202:  */
  203: struct ctl_var clock_var[] = {
  204: 	{ 0,		PADDING, "" },		/* 0 */
  205: 	{ CC_TYPE,	UI,	"type" },	/* 1 */
  206: 	{ CC_TIMECODE,	ST,	"timecode" },	/* 2 */
  207: 	{ CC_POLL,	UI,	"poll" },	/* 3 */
  208: 	{ CC_NOREPLY,	UI,	"noreply" },	/* 4 */
  209: 	{ CC_BADFORMAT,	UI,	"badformat" },	/* 5 */
  210: 	{ CC_BADDATA,	UI,	"baddata" },	/* 6 */
  211: 	{ CC_FUDGETIME1, FL,	"fudgetime1" },	/* 7 */
  212: 	{ CC_FUDGETIME2, FL,	"fudgetime2" },	/* 8 */
  213: 	{ CC_FUDGEVAL1,	UI,	"stratum" },	/* 9 */
  214: 	{ CC_FUDGEVAL2,	RF,	"refid" },	/* 10 */
  215: 	{ CC_FLAGS,	UI,	"flags" },	/* 11 */
  216: 	{ CC_DEVICE,	ST,	"device" },	/* 12 */
  217: 	{ 0,		EOV,	""	}
  218: };
  219: 
  220: 
  221: /*
  222:  * flasher bits
  223:  */
  224: static const char *tstflagnames[] = {
  225: 	"pkt_dup",		/* TEST1 */
  226: 	"pkt_bogus",		/* TEST2 */
  227: 	"pkt_unsync",		/* TEST3 */
  228: 	"pkt_denied",		/* TEST4 */
  229: 	"pkt_auth",		/* TEST5 */
  230: 	"pkt_stratum",		/* TEST6 */
  231: 	"pkt_header",		/* TEST7 */
  232: 	"pkt_autokey",		/* TEST8 */
  233: 	"pkt_crypto",		/* TEST9 */
  234: 	"peer_stratum",		/* TEST10 */
  235: 	"peer_dist",		/* TEST11 */
  236: 	"peer_loop",		/* TEST12 */
  237: 	"peer_unreach"		/* TEST13 */
  238: };
  239: 
  240: 
  241: int		ntpqmain	(int,	char **);
  242: /*
  243:  * Built in command handler declarations
  244:  */
  245: static	int	openhost	(const char *);
  246: 
  247: static	int	sendpkt		(void *, size_t);
  248: static	int	getresponse	(int, int, u_short *, int *, const char **, int);
  249: static	int	sendrequest	(int, int, int, int, char *);
  250: static	char *	tstflags	(u_long);
  251: #ifndef BUILD_AS_LIB
  252: static	void	getcmds		(void);
  253: #ifndef SYS_WINNT
  254: static	RETSIGTYPE abortcmd	(int);
  255: #endif	/* SYS_WINNT */
  256: static	void	docmd		(const char *);
  257: static	void	tokenize	(const char *, char **, int *);
  258: static	int	getarg		(char *, int, arg_v *);
  259: #endif	/* BUILD_AS_LIB */
  260: static	int	findcmd		(char *, struct xcmd *, struct xcmd *, struct xcmd **);
  261: static	int	rtdatetolfp	(char *, l_fp *);
  262: static	int	decodearr	(char *, int *, l_fp *);
  263: static	void	help		(struct parse *, FILE *);
  264: static	int	helpsort	(const void *, const void *);
  265: static	void	printusage	(struct xcmd *, FILE *);
  266: static	void	timeout		(struct parse *, FILE *);
  267: static	void	auth_delay	(struct parse *, FILE *);
  268: static	void	host		(struct parse *, FILE *);
  269: static	void	ntp_poll	(struct parse *, FILE *);
  270: static	void	keyid		(struct parse *, FILE *);
  271: static	void	keytype		(struct parse *, FILE *);
  272: static	void	passwd		(struct parse *, FILE *);
  273: static	void	hostnames	(struct parse *, FILE *);
  274: static	void	setdebug	(struct parse *, FILE *);
  275: static	void	quit		(struct parse *, FILE *);
  276: static	void	version		(struct parse *, FILE *);
  277: static	void	raw		(struct parse *, FILE *);
  278: static	void	cooked		(struct parse *, FILE *);
  279: static	void	authenticate	(struct parse *, FILE *);
  280: static	void	ntpversion	(struct parse *, FILE *);
  281: static	void	warning		(const char *, const char *, const char *);
  282: static	void	error		(const char *, const char *, const char *);
  283: static	u_long	getkeyid	(const char *);
  284: static	void	atoascii	(const char *, size_t, char *, size_t);
  285: static	void	cookedprint	(int, int, const char *, int, int, FILE *);
  286: static	void	rawprint	(int, int, const char *, int, int, FILE *);
  287: static	void	startoutput	(void);
  288: static	void	output		(FILE *, char *, char *);
  289: static	void	endoutput	(FILE *);
  290: static	void	outputarr	(FILE *, char *, int, l_fp *);
  291: static	int	assoccmp	(const void *, const void *);
  292: void	ntpq_custom_opt_handler	(tOptions *, tOptDesc *);
  293: 
  294: 
  295: /*
  296:  * Built-in commands we understand
  297:  */
  298: struct xcmd builtins[] = {
  299: 	{ "?",		help,		{  OPT|NTP_STR, NO, NO, NO },
  300: 	  { "command", "", "", "" },
  301: 	  "tell the use and syntax of commands" },
  302: 	{ "help",	help,		{  OPT|NTP_STR, NO, NO, NO },
  303: 	  { "command", "", "", "" },
  304: 	  "tell the use and syntax of commands" },
  305: 	{ "timeout",	timeout,	{ OPT|NTP_UINT, NO, NO, NO },
  306: 	  { "msec", "", "", "" },
  307: 	  "set the primary receive time out" },
  308: 	{ "delay",	auth_delay,	{ OPT|NTP_INT, NO, NO, NO },
  309: 	  { "msec", "", "", "" },
  310: 	  "set the delay added to encryption time stamps" },
  311: 	{ "host",	host,		{ OPT|NTP_STR, OPT|NTP_STR, NO, NO },
  312: 	  { "-4|-6", "hostname", "", "" },
  313: 	  "specify the host whose NTP server we talk to" },
  314: 	{ "poll",	ntp_poll,	{ OPT|NTP_UINT, OPT|NTP_STR, NO, NO },
  315: 	  { "n", "verbose", "", "" },
  316: 	  "poll an NTP server in client mode `n' times" },
  317: 	{ "passwd",	passwd,		{ NO, NO, NO, NO },
  318: 	  { "", "", "", "" },
  319: 	  "specify a password to use for authenticated requests"},
  320: 	{ "hostnames",	hostnames,	{ OPT|NTP_STR, NO, NO, NO },
  321: 	  { "yes|no", "", "", "" },
  322: 	  "specify whether hostnames or net numbers are printed"},
  323: 	{ "debug",	setdebug,	{ OPT|NTP_STR, NO, NO, NO },
  324: 	  { "no|more|less", "", "", "" },
  325: 	  "set/change debugging level" },
  326: 	{ "quit",	quit,		{ NO, NO, NO, NO },
  327: 	  { "", "", "", "" },
  328: 	  "exit ntpq" },
  329: 	{ "exit",	quit,		{ NO, NO, NO, NO },
  330: 	  { "", "", "", "" },
  331: 	  "exit ntpq" },
  332: 	{ "keyid",	keyid,		{ OPT|NTP_UINT, NO, NO, NO },
  333: 	  { "key#", "", "", "" },
  334: 	  "set keyid to use for authenticated requests" },
  335: 	{ "version",	version,	{ NO, NO, NO, NO },
  336: 	  { "", "", "", "" },
  337: 	  "print version number" },
  338: 	{ "raw",	raw,		{ NO, NO, NO, NO },
  339: 	  { "", "", "", "" },
  340: 	  "do raw mode variable output" },
  341: 	{ "cooked",	cooked,		{ NO, NO, NO, NO },
  342: 	  { "", "", "", "" },
  343: 	  "do cooked mode variable output" },
  344: 	{ "authenticate", authenticate,	{ OPT|NTP_STR, NO, NO, NO },
  345: 	  { "yes|no", "", "", "" },
  346: 	  "always authenticate requests to this server" },
  347: 	{ "ntpversion",	ntpversion,	{ OPT|NTP_UINT, NO, NO, NO },
  348: 	  { "version number", "", "", "" },
  349: 	  "set the NTP version number to use for requests" },
  350: 	{ "keytype",	keytype,	{ OPT|NTP_STR, NO, NO, NO },
  351: 	  { "key type (md5|des)", "", "", "" },
  352: 	  "set key type to use for authenticated requests (des|md5)" },
  353: 	{ 0,		0,		{ NO, NO, NO, NO },
  354: 	  { "", "", "", "" }, "" }
  355: };
  356: 
  357: 
  358: /*
  359:  * Default values we use.
  360:  */
  361: #define	DEFHOST		"localhost"	/* default host name */
  362: #define	DEFTIMEOUT	(5)		/* 5 second time out */
  363: #define	DEFSTIMEOUT	(2)		/* 2 second time out after first */
  364: #define	DEFDELAY	0x51EB852	/* 20 milliseconds, l_fp fraction */
  365: #define	LENHOSTNAME	256		/* host name is 256 characters long */
  366: #define	MAXCMDS		100		/* maximum commands on cmd line */
  367: #define	MAXHOSTS	200		/* maximum hosts on cmd line */
  368: #define	MAXLINE		512		/* maximum line length */
  369: #define	MAXTOKENS	(1+MAXARGS+2)	/* maximum number of usable tokens */
  370: #define	MAXVARLEN	256		/* maximum length of a variable name */
  371: #define	MAXVALLEN	400		/* maximum length of a variable value */
  372: #define	MAXOUTLINE	72		/* maximum length of an output line */
  373: #define SCREENWIDTH	76		/* nominal screen width in columns */
  374: 
  375: /*
  376:  * Some variables used and manipulated locally
  377:  */
  378: struct sock_timeval tvout = { DEFTIMEOUT, 0 };	/* time out for reads */
  379: struct sock_timeval tvsout = { DEFSTIMEOUT, 0 };/* secondary time out */
  380: l_fp delay_time;				/* delay time */
  381: char currenthost[LENHOSTNAME];			/* current host name */
  382: int currenthostisnum;				/* is prior text from IP? */
  383: struct sockaddr_in hostaddr = { 0 };		/* host address */
  384: int showhostnames = 1;				/* show host names by default */
  385: 
  386: int ai_fam_templ;				/* address family */
  387: int ai_fam_default;				/* default address family */
  388: SOCKET sockfd;					/* fd socket is opened on */
  389: int havehost = 0;				/* set to 1 when host open */
  390: int s_port = 0;
  391: struct servent *server_entry = NULL;		/* server entry for ntp */
  392: 
  393: 
  394: /*
  395:  * Sequence number used for requests.  It is incremented before
  396:  * it is used.
  397:  */
  398: u_short sequence;
  399: 
  400: /*
  401:  * Holds data returned from queries.  Declare buffer long to be sure of
  402:  * alignment.
  403:  */
  404: #define	MAXFRAGS	24		/* maximum number of fragments */
  405: #define	DATASIZE	(MAXFRAGS*480)	/* maximum amount of data */
  406: long pktdata[DATASIZE/sizeof(long)];
  407: 
  408: /*
  409:  * Holds association data for use with the &n operator.
  410:  */
  411: struct association assoc_cache[MAXASSOC];
  412: int numassoc = 0;		/* number of cached associations */
  413: 
  414: /*
  415:  * For commands typed on the command line (with the -c option)
  416:  */
  417: int numcmds = 0;
  418: const char *ccmds[MAXCMDS];
  419: #define	ADDCMD(cp)	if (numcmds < MAXCMDS) ccmds[numcmds++] = (cp)
  420: 
  421: /*
  422:  * When multiple hosts are specified.
  423:  */
  424: int numhosts = 0;
  425: const char *chosts[MAXHOSTS];
  426: #define	ADDHOST(cp)	if (numhosts < MAXHOSTS) chosts[numhosts++] = (cp)
  427: 
  428: /*
  429:  * Error codes for internal use
  430:  */
  431: #define	ERR_UNSPEC		256
  432: #define	ERR_INCOMPLETE	257
  433: #define	ERR_TIMEOUT		258
  434: #define	ERR_TOOMUCH		259
  435: 
  436: /*
  437:  * Macro definitions we use
  438:  */
  439: #define	ISSPACE(c)	((c) == ' ' || (c) == '\t')
  440: #define	ISEOL(c)	((c) == '\n' || (c) == '\r' || (c) == '\0')
  441: #define	STREQ(a, b)	(*(a) == *(b) && strcmp((a), (b)) == 0)
  442: 
  443: /*
  444:  * Jump buffer for longjumping back to the command level
  445:  */
  446: jmp_buf interrupt_buf;
  447: 
  448: /*
  449:  * Points at file being currently printed into
  450:  */
  451: FILE *current_output;
  452: 
  453: /*
  454:  * Command table imported from ntpdc_ops.c
  455:  */
  456: extern struct xcmd opcmds[];
  457: 
  458: char *progname;
  459: volatile int debug;
  460: 
  461: #ifdef NO_MAIN_ALLOWED
  462: #ifndef BUILD_AS_LIB
  463: CALL(ntpq,"ntpq",ntpqmain);
  464: 
  465: void clear_globals(void)
  466: {
  467: 	extern int ntp_optind;
  468: 	showhostnames = 0;	/* don'tshow host names by default */
  469: 	ntp_optind = 0;
  470: 	server_entry = NULL;	/* server entry for ntp */
  471: 	havehost = 0;		/* set to 1 when host open */
  472: 	numassoc = 0;		/* number of cached associations */
  473: 	numcmds = 0;
  474: 	numhosts = 0;
  475: }
  476: #endif /* !BUILD_AS_LIB */
  477: #endif /* NO_MAIN_ALLOWED */
  478: 
  479: /*
  480:  * main - parse arguments and handle options
  481:  */
  482: #ifndef NO_MAIN_ALLOWED
  483: int
  484: main(
  485: 	int argc,
  486: 	char *argv[]
  487: 	)
  488: {
  489: 	return ntpqmain(argc, argv);
  490: }
  491: #endif
  492: 
  493: #ifndef BUILD_AS_LIB
  494: int
  495: ntpqmain(
  496: 	int argc,
  497: 	char *argv[]
  498: 	)
  499: {
  500: 	extern int ntp_optind;
  501: 
  502: #ifdef SYS_VXWORKS
  503: 	clear_globals();
  504: 	taskPrioritySet(taskIdSelf(), 100 );
  505: #endif
  506: 
  507: 	delay_time.l_ui = 0;
  508: 	delay_time.l_uf = DEFDELAY;
  509: 
  510: 	init_lib();	/* sets up ipv4_works, ipv6_works */
  511: 	ssl_applink();
  512: 
  513: 	/* Check to see if we have IPv6. Otherwise default to IPv4 */
  514: 	if (!ipv6_works)
  515: 		ai_fam_default = AF_INET;
  516: 
  517: 	progname = argv[0];
  518: 
  519: 	{
  520: 		int optct = ntpOptionProcess(&ntpqOptions, argc, argv);
  521: 		argc -= optct;
  522: 		argv += optct;
  523: 	}
  524: 
  525: 	/*
  526: 	 * Process options other than -c and -p, which are specially
  527: 	 * handled by ntpq_custom_opt_handler().
  528: 	 */
  529: 
  530: 	debug = DESC(DEBUG_LEVEL).optOccCt;
  531: 
  532: 	if (HAVE_OPT(IPV4))
  533: 		ai_fam_templ = AF_INET;
  534: 	else if (HAVE_OPT(IPV6))
  535: 		ai_fam_templ = AF_INET6;
  536: 	else
  537: 		ai_fam_templ = ai_fam_default;
  538: 
  539: 	if (HAVE_OPT(INTERACTIVE))
  540: 		interactive = 1;
  541: 
  542: 	if (HAVE_OPT(NUMERIC))
  543: 		showhostnames = 0;
  544: 
  545: 	old_rv = HAVE_OPT(OLD_RV);
  546: 
  547: #if 0
  548: 	while ((c = ntp_getopt(argc, argv, "46c:dinp")) != EOF)
  549: 	    switch (c) {
  550: 		case '4':
  551: 		    ai_fam_templ = AF_INET;
  552: 		    break;
  553: 		case '6':
  554: 		    ai_fam_templ = AF_INET6;
  555: 		    break;
  556: 		case 'c':
  557: 		    ADDCMD(ntp_optarg);
  558: 		    break;
  559: 		case 'd':
  560: 		    ++debug;
  561: 		    break;
  562: 		case 'i':
  563: 		    interactive = 1;
  564: 		    break;
  565: 		case 'n':
  566: 		    showhostnames = 0;
  567: 		    break;
  568: 		case 'p':
  569: 		    ADDCMD("peers");
  570: 		    break;
  571: 		default:
  572: 		    errflg++;
  573: 		    break;
  574: 	    }
  575: 	if (errflg) {
  576: 		(void) fprintf(stderr,
  577: 			       "usage: %s [-46dinp] [-c cmd] host ...\n",
  578: 			       progname);
  579: 		exit(2);
  580: 	}
  581: #endif
  582: 	NTP_INSIST(ntp_optind <= argc);
  583: 	if (ntp_optind == argc) {
  584: 		ADDHOST(DEFHOST);
  585: 	} else {
  586: 		for (; ntp_optind < argc; ntp_optind++)
  587: 			ADDHOST(argv[ntp_optind]);
  588: 	}
  589: 
  590: 	if (numcmds == 0 && interactive == 0
  591: 	    && isatty(fileno(stdin)) && isatty(fileno(stderr))) {
  592: 		interactive = 1;
  593: 	}
  594: 
  595: #ifndef SYS_WINNT /* Under NT cannot handle SIGINT, WIN32 spawns a handler */
  596: 	if (interactive)
  597: 	    (void) signal_no_reset(SIGINT, abortcmd);
  598: #endif /* SYS_WINNT */
  599: 
  600: 	if (numcmds == 0) {
  601: 		(void) openhost(chosts[0]);
  602: 		getcmds();
  603: 	} else {
  604: 		int ihost;
  605: 		int icmd;
  606: 
  607: 		for (ihost = 0; ihost < numhosts; ihost++) {
  608: 			if (openhost(chosts[ihost]))
  609: 				for (icmd = 0; icmd < numcmds; icmd++)
  610: 					docmd(ccmds[icmd]);
  611: 		}
  612: 	}
  613: #ifdef SYS_WINNT
  614: 	WSACleanup();
  615: #endif /* SYS_WINNT */
  616: 	return 0;
  617: }
  618: #endif /* !BUILD_AS_LIB */
  619: 
  620: /*
  621:  * openhost - open a socket to a host
  622:  */
  623: static	int
  624: openhost(
  625: 	const char *hname
  626: 	)
  627: {
  628: 	char temphost[LENHOSTNAME];
  629: 	int a_info, i;
  630: 	struct addrinfo hints, *ai = NULL;
  631: 	register const char *cp;
  632: 	char name[LENHOSTNAME];
  633: 	char service[5];
  634: 
  635: 	/*
  636: 	 * We need to get by the [] if they were entered
  637: 	 */
  638: 	
  639: 	cp = hname;
  640: 	
  641: 	if (*cp == '[') {
  642: 		cp++;
  643: 		for (i = 0; *cp && *cp != ']'; cp++, i++)
  644: 			name[i] = *cp;
  645: 		if (*cp == ']') {
  646: 			name[i] = '\0';
  647: 			hname = name;
  648: 		} else {
  649: 			return 0;
  650: 		}
  651: 	}
  652: 
  653: 	/*
  654: 	 * First try to resolve it as an ip address and if that fails,
  655: 	 * do a fullblown (dns) lookup. That way we only use the dns
  656: 	 * when it is needed and work around some implementations that
  657: 	 * will return an "IPv4-mapped IPv6 address" address if you
  658: 	 * give it an IPv4 address to lookup.
  659: 	 */
  660: 	strcpy(service, "ntp");
  661: 	ZERO(hints);
  662: 	hints.ai_family = ai_fam_templ;
  663: 	hints.ai_protocol = IPPROTO_UDP;
  664: 	hints.ai_socktype = SOCK_DGRAM;
  665: 	hints.ai_flags = Z_AI_NUMERICHOST;
  666: 
  667: 	a_info = getaddrinfo(hname, service, &hints, &ai);
  668: 	if (a_info == EAI_NONAME
  669: #ifdef EAI_NODATA
  670: 	    || a_info == EAI_NODATA
  671: #endif
  672: 	   ) {
  673: 		hints.ai_flags = AI_CANONNAME;
  674: #ifdef AI_ADDRCONFIG
  675: 		hints.ai_flags |= AI_ADDRCONFIG;
  676: #endif
  677: 		a_info = getaddrinfo(hname, service, &hints, &ai);	
  678: 	}
  679: #ifdef AI_ADDRCONFIG
  680: 	/* Some older implementations don't like AI_ADDRCONFIG. */
  681: 	if (a_info == EAI_BADFLAGS) {
  682: 		hints.ai_flags = AI_CANONNAME;
  683: 		a_info = getaddrinfo(hname, service, &hints, &ai);	
  684: 	}
  685: #endif
  686: 	if (a_info != 0) {
  687: 		(void) fprintf(stderr, "%s\n", gai_strerror(a_info));
  688: 		return 0;
  689: 	}
  690: 
  691: 	if (!showhostnames || ai->ai_canonname == NULL) {
  692: 		strncpy(temphost, 
  693: 			stoa((sockaddr_u *)ai->ai_addr),
  694: 			LENHOSTNAME);
  695: 		currenthostisnum = TRUE;
  696: 	} else {
  697: 		strncpy(temphost, ai->ai_canonname, LENHOSTNAME);
  698: 		currenthostisnum = FALSE;
  699: 	}
  700: 	temphost[LENHOSTNAME-1] = '\0';
  701: 
  702: 	if (debug > 2)
  703: 		printf("Opening host %s\n", temphost);
  704: 
  705: 	if (havehost == 1) {
  706: 		if (debug > 2)
  707: 			printf("Closing old host %s\n", currenthost);
  708: 		(void) closesocket(sockfd);
  709: 		havehost = 0;
  710: 	}
  711: 	(void) strcpy(currenthost, temphost);
  712: 
  713: 	/* port maps to the same location in both families */
  714: 	s_port = ((struct sockaddr_in6 *)ai->ai_addr)->sin6_port;
  715: #ifdef SYS_VXWORKS
  716: 	((struct sockaddr_in6 *)&hostaddr)->sin6_port = htons(SERVER_PORT_NUM);
  717: 	if (ai->ai_family == AF_INET)
  718: 		*(struct sockaddr_in *)&hostaddr=
  719: 			*((struct sockaddr_in *)ai->ai_addr);
  720: 	else
  721: 		*(struct sockaddr_in6 *)&hostaddr=
  722: 			*((struct sockaddr_in6 *)ai->ai_addr);
  723: #endif /* SYS_VXWORKS */
  724: 
  725: #ifdef SYS_WINNT
  726: 	{
  727: 		int optionValue = SO_SYNCHRONOUS_NONALERT;
  728: 		int err;
  729: 
  730: 		err = setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE,
  731: 				 (char *)&optionValue, sizeof(optionValue));
  732: 		if (err) {
  733: 			err = WSAGetLastError();
  734: 			fprintf(stderr,
  735: 				"setsockopt(SO_SYNCHRONOUS_NONALERT) "
  736: 				"error: %s\n", strerror(err));
  737: 			exit(1);
  738: 		}
  739: 	}
  740: #endif /* SYS_WINNT */
  741: 
  742: 	sockfd = socket(ai->ai_family, SOCK_DGRAM, 0);
  743: 	if (sockfd == INVALID_SOCKET) {
  744: 		error("socket", "", "");
  745: 	}
  746: 
  747: 	
  748: #ifdef NEED_RCVBUF_SLOP
  749: # ifdef SO_RCVBUF
  750: 	{ int rbufsize = DATASIZE + 2048;	/* 2K for slop */
  751: 	if (setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF,
  752: 		       &rbufsize, sizeof(int)) == -1)
  753: 	    error("setsockopt", "", "");
  754: 	}
  755: # endif
  756: #endif
  757: 
  758: #ifdef SYS_VXWORKS
  759: 	if (connect(sockfd, (struct sockaddr *)&hostaddr,
  760: 		    sizeof(hostaddr)) == -1)
  761: #else
  762: 	if (connect(sockfd, (struct sockaddr *)ai->ai_addr,
  763: 		    ai->ai_addrlen) == -1)
  764: #endif /* SYS_VXWORKS */
  765: 	    error("connect", "", "");
  766: 	if (a_info == 0)
  767: 		freeaddrinfo(ai);
  768: 	havehost = 1;
  769: 	return 1;
  770: }
  771: 
  772: 
  773: /* XXX ELIMINATE sendpkt similar in ntpq.c, ntpdc.c, ntp_io.c, ntptrace.c */
  774: /*
  775:  * sendpkt - send a packet to the remote host
  776:  */
  777: static int
  778: sendpkt(
  779: 	void *	xdata,
  780: 	size_t	xdatalen
  781: 	)
  782: {
  783: 	if (debug >= 3)
  784: 		printf("Sending %lu octets\n", (u_long)xdatalen);
  785: 
  786: 	if (send(sockfd, xdata, (size_t)xdatalen, 0) == -1) {
  787: 		warning("write to %s failed", currenthost, "");
  788: 		return -1;
  789: 	}
  790: 
  791: 	if (debug >= 4) {
  792: 		int first = 8;
  793: 		char *cdata = xdata;
  794: 
  795: 		printf("Packet data:\n");
  796: 		while (xdatalen-- > 0) {
  797: 			if (first-- == 0) {
  798: 				printf("\n");
  799: 				first = 7;
  800: 			}
  801: 			printf(" %02x", *cdata++ & 0xff);
  802: 		}
  803: 		printf("\n");
  804: 	}
  805: 	return 0;
  806: }
  807: 
  808: 
  809: 
  810: /*
  811:  * getresponse - get a (series of) response packet(s) and return the data
  812:  */
  813: static int
  814: getresponse(
  815: 	int opcode,
  816: 	int associd,
  817: 	u_short *rstatus,
  818: 	int *rsize,
  819: 	const char **rdata,
  820: 	int timeo
  821: 	)
  822: {
  823: 	struct ntp_control rpkt;
  824: 	struct sock_timeval tvo;
  825: 	u_short offsets[MAXFRAGS+1];
  826: 	u_short counts[MAXFRAGS+1];
  827: 	u_short offset;
  828: 	u_short count;
  829: 	size_t numfrags;
  830: 	size_t f;
  831: 	size_t ff;
  832: 	int seenlastfrag;
  833: 	int shouldbesize;
  834: 	fd_set fds;
  835: 	int n;
  836: 	int len;
  837: 	int first;
  838: 	char *data;
  839: 
  840: 	/*
  841: 	 * This is pretty tricky.  We may get between 1 and MAXFRAG packets
  842: 	 * back in response to the request.  We peel the data out of
  843: 	 * each packet and collect it in one long block.  When the last
  844: 	 * packet in the sequence is received we'll know how much data we
  845: 	 * should have had.  Note we use one long time out, should reconsider.
  846: 	 */
  847: 	*rsize = 0;
  848: 	if (rstatus)
  849: 		*rstatus = 0;
  850: 	*rdata = (char *)pktdata;
  851: 
  852: 	numfrags = 0;
  853: 	seenlastfrag = 0;
  854: 
  855: 	FD_ZERO(&fds);
  856: 
  857: 	/*
  858: 	 * Loop until we have an error or a complete response.  Nearly all
  859: 	 * code paths to loop again use continue.
  860: 	 */
  861: 	for (;;) {
  862: 
  863: 		if (numfrags == 0)
  864: 			tvo = tvout;
  865: 		else
  866: 			tvo = tvsout;
  867: 		
  868: 		FD_SET(sockfd, &fds);
  869: 		n = select(sockfd + 1, &fds, NULL, NULL, &tvo);
  870: 
  871: 		if (n == -1) {
  872: 			warning("select fails", "", "");
  873: 			return -1;
  874: 		}
  875: 		if (n == 0) {
  876: 			/*
  877: 			 * Timed out.  Return what we have
  878: 			 */
  879: 			if (numfrags == 0) {
  880: 				if (timeo)
  881: 					fprintf(stderr,
  882: 						"%s: timed out, nothing received\n",
  883: 						currenthost);
  884: 				return ERR_TIMEOUT;
  885: 			}
  886: 			if (timeo)
  887: 				fprintf(stderr,
  888: 					"%s: timed out with incomplete data\n",
  889: 					currenthost);
  890: 			if (debug) {
  891: 				fprintf(stderr,
  892: 					"ERR_INCOMPLETE: Received fragments:\n");
  893: 				for (f = 0; f < numfrags; f++)
  894: 					fprintf(stderr,
  895: 						"%2u: %5d %5d\t%3d octets\n",
  896: 						f, offsets[f],
  897: 						offsets[f] +
  898: 						counts[f],
  899: 						counts[f]);
  900: 				fprintf(stderr,
  901: 					"last fragment %sreceived\n",
  902: 					(seenlastfrag)
  903: 					    ? ""
  904: 					    : "not ");
  905: 			}
  906: 			return ERR_INCOMPLETE;
  907: 		}
  908: 
  909: 		n = recv(sockfd, (char *)&rpkt, sizeof(rpkt), 0);
  910: 		if (n == -1) {
  911: 			warning("read", "", "");
  912: 			return -1;
  913: 		}
  914: 
  915: 		if (debug >= 4) {
  916: 			len = n;
  917: 			first = 8;
  918: 			data = (char *)&rpkt;
  919: 
  920: 			printf("Packet data:\n");
  921: 			while (len-- > 0) {
  922: 				if (first-- == 0) {
  923: 					printf("\n");
  924: 					first = 7;
  925: 				}
  926: 				printf(" %02x", *data++ & 0xff);
  927: 			}
  928: 			printf("\n");
  929: 		}
  930: 
  931: 		/*
  932: 		 * Check for format errors.  Bug proofing.
  933: 		 */
  934: 		if (n < CTL_HEADER_LEN) {
  935: 			if (debug)
  936: 				printf("Short (%d byte) packet received\n", n);
  937: 			continue;
  938: 		}
  939: 		if (PKT_VERSION(rpkt.li_vn_mode) > NTP_VERSION
  940: 		    || PKT_VERSION(rpkt.li_vn_mode) < NTP_OLDVERSION) {
  941: 			if (debug)
  942: 				printf("Packet received with version %d\n",
  943: 				       PKT_VERSION(rpkt.li_vn_mode));
  944: 			continue;
  945: 		}
  946: 		if (PKT_MODE(rpkt.li_vn_mode) != MODE_CONTROL) {
  947: 			if (debug)
  948: 				printf("Packet received with mode %d\n",
  949: 				       PKT_MODE(rpkt.li_vn_mode));
  950: 			continue;
  951: 		}
  952: 		if (!CTL_ISRESPONSE(rpkt.r_m_e_op)) {
  953: 			if (debug)
  954: 				printf("Received request packet, wanted response\n");
  955: 			continue;
  956: 		}
  957: 
  958: 		/*
  959: 		 * Check opcode and sequence number for a match.
  960: 		 * Could be old data getting to us.
  961: 		 */
  962: 		if (ntohs(rpkt.sequence) != sequence) {
  963: 			if (debug)
  964: 				printf("Received sequnce number %d, wanted %d\n",
  965: 				       ntohs(rpkt.sequence), sequence);
  966: 			continue;
  967: 		}
  968: 		if (CTL_OP(rpkt.r_m_e_op) != opcode) {
  969: 			if (debug)
  970: 			    printf(
  971: 				    "Received opcode %d, wanted %d (sequence number okay)\n",
  972: 				    CTL_OP(rpkt.r_m_e_op), opcode);
  973: 			continue;
  974: 		}
  975: 
  976: 		/*
  977: 		 * Check the error code.  If non-zero, return it.
  978: 		 */
  979: 		if (CTL_ISERROR(rpkt.r_m_e_op)) {
  980: 			int errcode;
  981: 
  982: 			errcode = (ntohs(rpkt.status) >> 8) & 0xff;
  983: 			if (debug && CTL_ISMORE(rpkt.r_m_e_op)) {
  984: 				printf("Error code %d received on not-final packet\n",
  985: 				       errcode);
  986: 			}
  987: 			if (errcode == CERR_UNSPEC)
  988: 			    return ERR_UNSPEC;
  989: 			return errcode;
  990: 		}
  991: 
  992: 		/*
  993: 		 * Check the association ID to make sure it matches what
  994: 		 * we sent.
  995: 		 */
  996: 		if (ntohs(rpkt.associd) != associd) {
  997: 			if (debug)
  998: 			    printf("Association ID %d doesn't match expected %d\n",
  999: 				   ntohs(rpkt.associd), associd);
 1000: 			/*
 1001: 			 * Hack for silly fuzzballs which, at the time of writing,
 1002: 			 * return an assID of sys.peer when queried for system variables.
 1003: 			 */
 1004: #ifdef notdef
 1005: 			continue;
 1006: #endif
 1007: 		}
 1008: 
 1009: 		/*
 1010: 		 * Collect offset and count.  Make sure they make sense.
 1011: 		 */
 1012: 		offset = ntohs(rpkt.offset);
 1013: 		count = ntohs(rpkt.count);
 1014: 
 1015: 		/*
 1016: 		 * validate received payload size is padded to next 32-bit
 1017: 		 * boundary and no smaller than claimed by rpkt.count
 1018: 		 */
 1019: 		if (n & 0x3) {
 1020: 			if (debug)
 1021: 				printf("Response packet not padded, "
 1022: 					"size = %d\n", n);
 1023: 			continue;
 1024: 		}
 1025: 
 1026: 		shouldbesize = (CTL_HEADER_LEN + count + 3) & ~3;
 1027: 
 1028: 		if (n < shouldbesize) {
 1029: 			printf("Response packet claims %u octets "
 1030: 				"payload, above %d received\n",
 1031: 				count,
 1032: 				n - CTL_HEADER_LEN
 1033: 				);
 1034: 			return ERR_INCOMPLETE;
 1035: 		}
 1036: 
 1037: 		if (debug >= 3 && shouldbesize > n) {
 1038: 			u_int32 key;
 1039: 			u_int32 *lpkt;
 1040: 			int maclen;
 1041: 
 1042: 			/*
 1043: 			 * Usually we ignore authentication, but for debugging purposes
 1044: 			 * we watch it here.
 1045: 			 */
 1046: 			/* round to 8 octet boundary */
 1047: 			shouldbesize = (shouldbesize + 7) & ~7;
 1048: 
 1049: 			maclen = n - shouldbesize;
 1050: 			if (maclen >= MIN_MAC_LEN) {
 1051: 				printf(
 1052: 					"Packet shows signs of authentication (total %d, data %d, mac %d)\n",
 1053: 					n, shouldbesize, maclen);
 1054: 				lpkt = (u_int32 *)&rpkt;
 1055: 				printf("%08lx %08lx %08lx %08lx %08lx %08lx\n",
 1056: 				       (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) - 3]),
 1057: 				       (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) - 2]),
 1058: 				       (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) - 1]),
 1059: 				       (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32)]),
 1060: 				       (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) + 1]),
 1061: 				       (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_int32) + 2]));
 1062: 				key = ntohl(lpkt[(n - maclen) / sizeof(u_int32)]);
 1063: 				printf("Authenticated with keyid %lu\n", (u_long)key);
 1064: 				if (key != 0 && key != info_auth_keyid) {
 1065: 					printf("We don't know that key\n");
 1066: 				} else {
 1067: 					if (authdecrypt(key, (u_int32 *)&rpkt,
 1068: 					    n - maclen, maclen)) {
 1069: 						printf("Auth okay!\n");
 1070: 					} else {
 1071: 						printf("Auth failed!\n");
 1072: 					}
 1073: 				}
 1074: 			}
 1075: 		}
 1076: 
 1077: 		if (debug >= 2)
 1078: 			printf("Got packet, size = %d\n", n);
 1079: 		if ((int)count > (n - CTL_HEADER_LEN)) {
 1080: 			if (debug)
 1081: 				printf("Received count of %d octets, "
 1082: 					"data in packet is %d\n",
 1083: 					count, n-CTL_HEADER_LEN);
 1084: 			continue;
 1085: 		}
 1086: 		if (count == 0 && CTL_ISMORE(rpkt.r_m_e_op)) {
 1087: 			if (debug)
 1088: 				printf("Received count of 0 in non-final fragment\n");
 1089: 			continue;
 1090: 		}
 1091: 		if (offset + count > sizeof(pktdata)) {
 1092: 			if (debug)
 1093: 				printf("Offset %d, count %d, too big for buffer\n",
 1094: 				       offset, count);
 1095: 			return ERR_TOOMUCH;
 1096: 		}
 1097: 		if (seenlastfrag && !CTL_ISMORE(rpkt.r_m_e_op)) {
 1098: 			if (debug)
 1099: 				printf("Received second last fragment packet\n");
 1100: 			continue;
 1101: 		}
 1102: 
 1103: 		/*
 1104: 		 * So far, so good.  Record this fragment, making sure it doesn't
 1105: 		 * overlap anything.
 1106: 		 */
 1107: 		if (debug >= 2)
 1108: 			printf("Packet okay\n");;
 1109: 
 1110: 		if (numfrags > (MAXFRAGS - 1)) {
 1111: 			if (debug)
 1112: 				printf("Number of fragments exceeds maximum %d\n",
 1113: 				       MAXFRAGS - 1);
 1114: 			return ERR_TOOMUCH;
 1115: 		}
 1116: 
 1117: 		/*
 1118: 		 * Find the position for the fragment relative to any
 1119: 		 * previously received.
 1120: 		 */
 1121: 		for (f = 0; 
 1122: 		     f < numfrags && offsets[f] < offset; 
 1123: 		     f++) {
 1124: 			/* empty body */ ;
 1125: 		}
 1126: 
 1127: 		if (f < numfrags && offset == offsets[f]) {
 1128: 			if (debug)
 1129: 				printf("duplicate %u octets at %u ignored, prior %u at %u\n",
 1130: 				       count, offset, counts[f],
 1131: 				       offsets[f]);
 1132: 			continue;
 1133: 		}
 1134: 
 1135: 		if (f > 0 && (offsets[f-1] + counts[f-1]) > offset) {
 1136: 			if (debug)
 1137: 				printf("received frag at %u overlaps with %u octet frag at %u\n",
 1138: 				       offset, counts[f-1],
 1139: 				       offsets[f-1]);
 1140: 			continue;
 1141: 		}
 1142: 
 1143: 		if (f < numfrags && (offset + count) > offsets[f]) {
 1144: 			if (debug)
 1145: 				printf("received %u octet frag at %u overlaps with frag at %u\n",
 1146: 				       count, offset, offsets[f]);
 1147: 			continue;
 1148: 		}
 1149: 
 1150: 		for (ff = numfrags; ff > f; ff--) {
 1151: 			offsets[ff] = offsets[ff-1];
 1152: 			counts[ff] = counts[ff-1];
 1153: 		}
 1154: 		offsets[f] = offset;
 1155: 		counts[f] = count;
 1156: 		numfrags++;
 1157: 
 1158: 		/*
 1159: 		 * Got that stuffed in right.  Figure out if this was the last.
 1160: 		 * Record status info out of the last packet.
 1161: 		 */
 1162: 		if (!CTL_ISMORE(rpkt.r_m_e_op)) {
 1163: 			seenlastfrag = 1;
 1164: 			if (rstatus != 0)
 1165: 				*rstatus = ntohs(rpkt.status);
 1166: 		}
 1167: 
 1168: 		/*
 1169: 		 * Copy the data into the data buffer.
 1170: 		 */
 1171: 		memcpy((char *)pktdata + offset, rpkt.data, count);
 1172: 
 1173: 		/*
 1174: 		 * If we've seen the last fragment, look for holes in the sequence.
 1175: 		 * If there aren't any, we're done.
 1176: 		 */
 1177: 		if (seenlastfrag && offsets[0] == 0) {
 1178: 			for (f = 1; f < numfrags; f++)
 1179: 				if (offsets[f-1] + counts[f-1] !=
 1180: 				    offsets[f])
 1181: 					break;
 1182: 			if (f == numfrags) {
 1183: 				*rsize = offsets[f-1] + counts[f-1];
 1184: 				if (debug)
 1185: 					fprintf(stderr,
 1186: 						"%u packets reassembled into response\n",
 1187: 						numfrags);
 1188: 				return 0;
 1189: 			}
 1190: 		}
 1191: 	}  /* giant for (;;) collecting response packets */
 1192: }  /* getresponse() */
 1193: 
 1194: 
 1195: /*
 1196:  * sendrequest - format and send a request packet
 1197:  */
 1198: static int
 1199: sendrequest(
 1200: 	int opcode,
 1201: 	int associd,
 1202: 	int auth,
 1203: 	int qsize,
 1204: 	char *qdata
 1205: 	)
 1206: {
 1207: 	struct ntp_control qpkt;
 1208: 	int	pktsize;
 1209: 	u_long	key_id;
 1210: 	char *	pass;
 1211: 	int	maclen;
 1212: 
 1213: 	/*
 1214: 	 * Check to make sure the data will fit in one packet
 1215: 	 */
 1216: 	if (qsize > CTL_MAX_DATA_LEN) {
 1217: 		fprintf(stderr,
 1218: 			"***Internal error!  qsize (%d) too large\n",
 1219: 			qsize);
 1220: 		return 1;
 1221: 	}
 1222: 
 1223: 	/*
 1224: 	 * Fill in the packet
 1225: 	 */
 1226: 	qpkt.li_vn_mode = PKT_LI_VN_MODE(0, pktversion, MODE_CONTROL);
 1227: 	qpkt.r_m_e_op = (u_char)(opcode & CTL_OP_MASK);
 1228: 	qpkt.sequence = htons(sequence);
 1229: 	qpkt.status = 0;
 1230: 	qpkt.associd = htons((u_short)associd);
 1231: 	qpkt.offset = 0;
 1232: 	qpkt.count = htons((u_short)qsize);
 1233: 
 1234: 	pktsize = CTL_HEADER_LEN;
 1235: 
 1236: 	/*
 1237: 	 * If we have data, copy and pad it out to a 32-bit boundary.
 1238: 	 */
 1239: 	if (qsize > 0) {
 1240: 		memcpy(qpkt.data, qdata, (size_t)qsize);
 1241: 		pktsize += qsize;
 1242: 		while (pktsize & (sizeof(u_int32) - 1)) {
 1243: 			qpkt.data[qsize++] = 0;
 1244: 			pktsize++;
 1245: 		}
 1246: 	}
 1247: 
 1248: 	/*
 1249: 	 * If it isn't authenticated we can just send it.  Otherwise
 1250: 	 * we're going to have to think about it a little.
 1251: 	 */
 1252: 	if (!auth && !always_auth) {
 1253: 		return sendpkt(&qpkt, pktsize);
 1254: 	} 
 1255: 
 1256: 	/*
 1257: 	 * Pad out packet to a multiple of 8 octets to be sure
 1258: 	 * receiver can handle it.
 1259: 	 */
 1260: 	while (pktsize & 7) {
 1261: 		qpkt.data[qsize++] = 0;
 1262: 		pktsize++;
 1263: 	}
 1264: 
 1265: 	/*
 1266: 	 * Get the keyid and the password if we don't have one.
 1267: 	 */
 1268: 	if (info_auth_keyid == 0) {
 1269: 		key_id = getkeyid("Keyid: ");
 1270: 		if (key_id == 0 || key_id > NTP_MAXKEY) {
 1271: 			fprintf(stderr, 
 1272: 				"Invalid key identifier\n");
 1273: 			return 1;
 1274: 		}
 1275: 		info_auth_keyid = key_id;
 1276: 	}
 1277: 	if (!authistrusted(info_auth_keyid)) {
 1278: 		pass = getpass_keytype(info_auth_keytype);
 1279: 		if ('\0' == pass[0]) {
 1280: 			fprintf(stderr, "Invalid password\n");
 1281: 			return 1;
 1282: 		}
 1283: 		authusekey(info_auth_keyid, info_auth_keytype,
 1284: 			   (u_char *)pass);
 1285: 		authtrust(info_auth_keyid, 1);
 1286: 	}
 1287: 
 1288: 	/*
 1289: 	 * Do the encryption.
 1290: 	 */
 1291: 	maclen = authencrypt(info_auth_keyid, (void *)&qpkt, pktsize);
 1292: 	if (!maclen) {  
 1293: 		fprintf(stderr, "Key not found\n");
 1294: 		return 1;
 1295: 	} else if ((size_t)maclen != (info_auth_hashlen + sizeof(keyid_t))) {
 1296: 		fprintf(stderr,
 1297: 			"%d octet MAC, %lu expected with %lu octet digest\n",
 1298: 			maclen, (u_long)(info_auth_hashlen + sizeof(keyid_t)),
 1299: 			(u_long)info_auth_hashlen);
 1300: 		return 1;
 1301: 	}
 1302: 	
 1303: 	return sendpkt((char *)&qpkt, pktsize + maclen);
 1304: }
 1305: 
 1306: 
 1307: /*
 1308:  * show_error_msg - display the error text for a mode 6 error response.
 1309:  */
 1310: void
 1311: show_error_msg(
 1312: 	int		m6resp,
 1313: 	associd_t	associd
 1314: 	)
 1315: {
 1316: 	if (numhosts > 1)
 1317: 		fprintf(stderr, "server=%s ", currenthost);
 1318: 
 1319: 	switch(m6resp) {
 1320: 
 1321: 	case CERR_BADFMT:
 1322: 		fprintf(stderr,
 1323: 		    "***Server reports a bad format request packet\n");
 1324: 		break;
 1325: 
 1326: 	case CERR_PERMISSION:
 1327: 		fprintf(stderr,
 1328: 		    "***Server disallowed request (authentication?)\n");
 1329: 		break;
 1330: 
 1331: 	case CERR_BADOP:
 1332: 		fprintf(stderr,
 1333: 		    "***Server reports a bad opcode in request\n");
 1334: 		break;
 1335: 
 1336: 	case CERR_BADASSOC:
 1337: 		fprintf(stderr,
 1338: 		    "***Association ID %d unknown to server\n",
 1339: 		    associd);
 1340: 		break;
 1341: 
 1342: 	case CERR_UNKNOWNVAR:
 1343: 		fprintf(stderr,
 1344: 		    "***A request variable unknown to the server\n");
 1345: 		break;
 1346: 
 1347: 	case CERR_BADVALUE:
 1348: 		fprintf(stderr,
 1349: 		    "***Server indicates a request variable was bad\n");
 1350: 		break;
 1351: 
 1352: 	case ERR_UNSPEC:
 1353: 		fprintf(stderr,
 1354: 		    "***Server returned an unspecified error\n");
 1355: 		break;
 1356: 
 1357: 	case ERR_TIMEOUT:
 1358: 		fprintf(stderr, "***Request timed out\n");
 1359: 		break;
 1360: 
 1361: 	case ERR_INCOMPLETE:
 1362: 		fprintf(stderr,
 1363: 		    "***Response from server was incomplete\n");
 1364: 		break;
 1365: 
 1366: 	case ERR_TOOMUCH:
 1367: 		fprintf(stderr,
 1368: 		    "***Buffer size exceeded for returned data\n");
 1369: 		break;
 1370: 
 1371: 	default:
 1372: 		fprintf(stderr,
 1373: 		    "***Server returns unknown error code %d\n",
 1374: 		    m6resp);
 1375: 	}
 1376: }
 1377: 
 1378: /*
 1379:  * doquery - send a request and process the response, displaying
 1380:  *	     error messages for any error responses.
 1381:  */
 1382: int
 1383: doquery(
 1384: 	int opcode,
 1385: 	associd_t associd,
 1386: 	int auth,
 1387: 	int qsize,
 1388: 	char *qdata,
 1389: 	u_short *rstatus,
 1390: 	int *rsize,
 1391: 	const char **rdata
 1392: 	)
 1393: {
 1394: 	return doqueryex(opcode, associd, auth, qsize, qdata, rstatus,
 1395: 			 rsize, rdata, FALSE);
 1396: }
 1397: 
 1398: 
 1399: /*
 1400:  * doqueryex - send a request and process the response, optionally
 1401:  *	       displaying error messages for any error responses.
 1402:  */
 1403: int
 1404: doqueryex(
 1405: 	int opcode,
 1406: 	associd_t associd,
 1407: 	int auth,
 1408: 	int qsize,
 1409: 	char *qdata,
 1410: 	u_short *rstatus,
 1411: 	int *rsize,
 1412: 	const char **rdata,
 1413: 	int quiet
 1414: 	)
 1415: {
 1416: 	int res;
 1417: 	int done;
 1418: 
 1419: 	/*
 1420: 	 * Check to make sure host is open
 1421: 	 */
 1422: 	if (!havehost) {
 1423: 		fprintf(stderr, "***No host open, use `host' command\n");
 1424: 		return -1;
 1425: 	}
 1426: 
 1427: 	done = 0;
 1428: 	sequence++;
 1429: 
 1430:     again:
 1431: 	/*
 1432: 	 * send a request
 1433: 	 */
 1434: 	res = sendrequest(opcode, associd, auth, qsize, qdata);
 1435: 	if (res != 0)
 1436: 		return res;
 1437: 	
 1438: 	/*
 1439: 	 * Get the response.  If we got a standard error, print a message
 1440: 	 */
 1441: 	res = getresponse(opcode, associd, rstatus, rsize, rdata, done);
 1442: 
 1443: 	if (res > 0) {
 1444: 		if (!done && (res == ERR_TIMEOUT || res == ERR_INCOMPLETE)) {
 1445: 			if (res == ERR_INCOMPLETE) {
 1446: 				/*
 1447: 				 * better bump the sequence so we don't
 1448: 				 * get confused about differing fragments.
 1449: 				 */
 1450: 				sequence++;
 1451: 			}
 1452: 			done = 1;
 1453: 			goto again;
 1454: 		}
 1455: 		if (!quiet)
 1456: 			show_error_msg(res, associd);
 1457: 
 1458: 	}
 1459: 	return res;
 1460: }
 1461: 
 1462: 
 1463: #ifndef BUILD_AS_LIB
 1464: /*
 1465:  * getcmds - read commands from the standard input and execute them
 1466:  */
 1467: static void
 1468: getcmds(void)
 1469: {
 1470: 	char *	line;
 1471: 	int	count;
 1472: 
 1473: 	ntp_readline_init(interactive ? prompt : NULL);
 1474: 
 1475: 	for (;;) {
 1476: 		line = ntp_readline(&count);
 1477: 		if (NULL == line)
 1478: 			break;
 1479: 		docmd(line);
 1480: 		free(line);
 1481: 	}
 1482: 
 1483: 	ntp_readline_uninit();
 1484: }
 1485: #endif /* !BUILD_AS_LIB */
 1486: 
 1487: 
 1488: #if !defined(SYS_WINNT) && !defined(BUILD_AS_LIB)
 1489: /*
 1490:  * abortcmd - catch interrupts and abort the current command
 1491:  */
 1492: static RETSIGTYPE
 1493: abortcmd(
 1494: 	int sig
 1495: 	)
 1496: {
 1497: 	if (current_output == stdout)
 1498: 	    (void) fflush(stdout);
 1499: 	putc('\n', stderr);
 1500: 	(void) fflush(stderr);
 1501: 	if (jump) longjmp(interrupt_buf, 1);
 1502: }
 1503: #endif	/* !SYS_WINNT && !BUILD_AS_LIB */
 1504: 
 1505: 
 1506: #ifndef	BUILD_AS_LIB
 1507: /*
 1508:  * docmd - decode the command line and execute a command
 1509:  */
 1510: static void
 1511: docmd(
 1512: 	const char *cmdline
 1513: 	)
 1514: {
 1515: 	char *tokens[1+MAXARGS+2];
 1516: 	struct parse pcmd;
 1517: 	int ntok;
 1518: 	static int i;
 1519: 	struct xcmd *xcmd;
 1520: 
 1521: 	/*
 1522: 	 * Tokenize the command line.  If nothing on it, return.
 1523: 	 */
 1524: 	tokenize(cmdline, tokens, &ntok);
 1525: 	if (ntok == 0)
 1526: 	    return;
 1527: 	
 1528: 	/*
 1529: 	 * Find the appropriate command description.
 1530: 	 */
 1531: 	i = findcmd(tokens[0], builtins, opcmds, &xcmd);
 1532: 	if (i == 0) {
 1533: 		(void) fprintf(stderr, "***Command `%s' unknown\n",
 1534: 			       tokens[0]);
 1535: 		return;
 1536: 	} else if (i >= 2) {
 1537: 		(void) fprintf(stderr, "***Command `%s' ambiguous\n",
 1538: 			       tokens[0]);
 1539: 		return;
 1540: 	}
 1541: 	
 1542: 	/*
 1543: 	 * Save the keyword, then walk through the arguments, interpreting
 1544: 	 * as we go.
 1545: 	 */
 1546: 	pcmd.keyword = tokens[0];
 1547: 	pcmd.nargs = 0;
 1548: 	for (i = 0; i < MAXARGS && xcmd->arg[i] != NO; i++) {
 1549: 		if ((i+1) >= ntok) {
 1550: 			if (!(xcmd->arg[i] & OPT)) {
 1551: 				printusage(xcmd, stderr);
 1552: 				return;
 1553: 			}
 1554: 			break;
 1555: 		}
 1556: 		if ((xcmd->arg[i] & OPT) && (*tokens[i+1] == '>'))
 1557: 			break;
 1558: 		if (!getarg(tokens[i+1], (int)xcmd->arg[i], &pcmd.argval[i]))
 1559: 			return;
 1560: 		pcmd.nargs++;
 1561: 	}
 1562: 
 1563: 	i++;
 1564: 	if (i < ntok && *tokens[i] == '>') {
 1565: 		char *fname;
 1566: 
 1567: 		if (*(tokens[i]+1) != '\0')
 1568: 			fname = tokens[i]+1;
 1569: 		else if ((i+1) < ntok)
 1570: 			fname = tokens[i+1];
 1571: 		else {
 1572: 			(void) fprintf(stderr, "***No file for redirect\n");
 1573: 			return;
 1574: 		}
 1575: 
 1576: 		current_output = fopen(fname, "w");
 1577: 		if (current_output == NULL) {
 1578: 			(void) fprintf(stderr, "***Error opening %s: ", fname);
 1579: 			perror("");
 1580: 			return;
 1581: 		}
 1582: 		i = 1;		/* flag we need a close */
 1583: 	} else {
 1584: 		current_output = stdout;
 1585: 		i = 0;		/* flag no close */
 1586: 	}
 1587: 
 1588: 	if (interactive && setjmp(interrupt_buf)) {
 1589: 		jump = 0;
 1590: 		return;
 1591: 	} else {
 1592: 		jump++;
 1593: 		(xcmd->handler)(&pcmd, current_output);
 1594: 		jump = 0;	/* HMS: 961106: was after fclose() */
 1595: 		if (i) (void) fclose(current_output);
 1596: 	}
 1597: }
 1598: 
 1599: 
 1600: /*
 1601:  * tokenize - turn a command line into tokens
 1602:  *
 1603:  * SK: Modified to allow a quoted string 
 1604:  *
 1605:  * HMS: If the first character of the first token is a ':' then (after
 1606:  * eating inter-token whitespace) the 2nd token is the rest of the line.
 1607:  */
 1608: 
 1609: static void
 1610: tokenize(
 1611: 	const char *line,
 1612: 	char **tokens,
 1613: 	int *ntok
 1614: 	)
 1615: {
 1616: 	register const char *cp;
 1617: 	register char *sp;
 1618: 	static char tspace[MAXLINE];
 1619: 
 1620: 	sp = tspace;
 1621: 	cp = line;
 1622: 	for (*ntok = 0; *ntok < MAXTOKENS; (*ntok)++) {
 1623: 		tokens[*ntok] = sp;
 1624: 
 1625: 		/* Skip inter-token whitespace */
 1626: 		while (ISSPACE(*cp))
 1627: 		    cp++;
 1628: 
 1629: 		/* If we're at EOL we're done */
 1630: 		if (ISEOL(*cp))
 1631: 		    break;
 1632: 
 1633: 		/* If this is the 2nd token and the first token begins
 1634: 		 * with a ':', then just grab to EOL.
 1635: 		 */
 1636: 
 1637: 		if (*ntok == 1 && tokens[0][0] == ':') {
 1638: 			do {
 1639: 				*sp++ = *cp++;
 1640: 			} while (!ISEOL(*cp));
 1641: 		}
 1642: 
 1643: 		/* Check if this token begins with a double quote.
 1644: 		 * If yes, continue reading till the next double quote
 1645: 		 */
 1646: 		else if (*cp == '\"') {
 1647: 			++cp;
 1648: 			do {
 1649: 				*sp++ = *cp++;
 1650: 			} while ((*cp != '\"') && !ISEOL(*cp));
 1651: 			/* HMS: a missing closing " should be an error */
 1652: 		}
 1653: 		else {
 1654: 			do {
 1655: 				*sp++ = *cp++;
 1656: 			} while ((*cp != '\"') && !ISSPACE(*cp) && !ISEOL(*cp));
 1657: 			/* HMS: Why check for a " in the previous line? */
 1658: 		}
 1659: 
 1660: 		*sp++ = '\0';
 1661: 	}
 1662: }
 1663: 
 1664: 
 1665: /*
 1666:  * getarg - interpret an argument token
 1667:  */
 1668: static int
 1669: getarg(
 1670: 	char *str,
 1671: 	int code,
 1672: 	arg_v *argp
 1673: 	)
 1674: {
 1675: 	int isneg;
 1676: 	char *cp, *np;
 1677: 	static const char *digits = "0123456789";
 1678: 
 1679: 	switch (code & ~OPT) {
 1680: 	    case NTP_STR:
 1681: 		argp->string = str;
 1682: 		break;
 1683: 	    case NTP_ADD:
 1684: 		if (!getnetnum(str, &(argp->netnum), (char *)0, 0)) {
 1685: 			return 0;
 1686: 		}
 1687: 		break;
 1688: 	    case NTP_INT:
 1689: 	    case NTP_UINT:
 1690: 		isneg = 0;
 1691: 		np = str;
 1692: 		if (*np == '&') {
 1693: 			np++;
 1694: 			isneg = atoi(np);
 1695: 			if (isneg <= 0) {
 1696: 				(void) fprintf(stderr,
 1697: 					       "***Association value `%s' invalid/undecodable\n", str);
 1698: 				return 0;
 1699: 			}
 1700: 			if (isneg > numassoc) {
 1701: 				if (numassoc == 0) {
 1702: 					(void) fprintf(stderr,
 1703: 						       "***Association for `%s' unknown (max &%d)\n",
 1704: 						       str, numassoc);
 1705: 					return 0;
 1706: 				} else {
 1707: 					isneg = numassoc;
 1708: 				}
 1709: 			}
 1710: 			argp->uval = assoc_cache[isneg-1].assid;
 1711: 			break;
 1712: 		}
 1713: 
 1714: 		if (*np == '-') {
 1715: 			np++;
 1716: 			isneg = 1;
 1717: 		}
 1718: 
 1719: 		argp->uval = 0;
 1720: 		do {
 1721: 			cp = strchr(digits, *np);
 1722: 			if (cp == NULL) {
 1723: 				(void) fprintf(stderr,
 1724: 					       "***Illegal integer value %s\n", str);
 1725: 				return 0;
 1726: 			}
 1727: 			argp->uval *= 10;
 1728: 			argp->uval += (cp - digits);
 1729: 		} while (*(++np) != '\0');
 1730: 
 1731: 		if (isneg) {
 1732: 			if ((code & ~OPT) == NTP_UINT) {
 1733: 				(void) fprintf(stderr,
 1734: 					       "***Value %s should be unsigned\n", str);
 1735: 				return 0;
 1736: 			}
 1737: 			argp->ival = -argp->ival;
 1738: 		}
 1739: 		break;
 1740: 	     case IP_VERSION:
 1741: 		if (!strcmp("-6", str))
 1742: 			argp->ival = 6 ;
 1743: 		else if (!strcmp("-4", str))
 1744: 			argp->ival = 4 ;
 1745: 		else {
 1746: 			(void) fprintf(stderr,
 1747: 			    "***Version must be either 4 or 6\n");
 1748: 			return 0;
 1749: 		}
 1750: 		break;
 1751: 	}
 1752: 
 1753: 	return 1;
 1754: }
 1755: #endif	/* !BUILD_AS_LIB */
 1756: 
 1757: 
 1758: /*
 1759:  * findcmd - find a command in a command description table
 1760:  */
 1761: static int
 1762: findcmd(
 1763: 	register char *str,
 1764: 	struct xcmd *clist1,
 1765: 	struct xcmd *clist2,
 1766: 	struct xcmd **cmd
 1767: 	)
 1768: {
 1769: 	register struct xcmd *cl;
 1770: 	register int clen;
 1771: 	int nmatch;
 1772: 	struct xcmd *nearmatch = NULL;
 1773: 	struct xcmd *clist;
 1774: 
 1775: 	clen = strlen(str);
 1776: 	nmatch = 0;
 1777: 	if (clist1 != 0)
 1778: 	    clist = clist1;
 1779: 	else if (clist2 != 0)
 1780: 	    clist = clist2;
 1781: 	else
 1782: 	    return 0;
 1783: 
 1784:     again:
 1785: 	for (cl = clist; cl->keyword != 0; cl++) {
 1786: 		/* do a first character check, for efficiency */
 1787: 		if (*str != *(cl->keyword))
 1788: 		    continue;
 1789: 		if (strncmp(str, cl->keyword, (unsigned)clen) == 0) {
 1790: 			/*
 1791: 			 * Could be extact match, could be approximate.
 1792: 			 * Is exact if the length of the keyword is the
 1793: 			 * same as the str.
 1794: 			 */
 1795: 			if (*((cl->keyword) + clen) == '\0') {
 1796: 				*cmd = cl;
 1797: 				return 1;
 1798: 			}
 1799: 			nmatch++;
 1800: 			nearmatch = cl;
 1801: 		}
 1802: 	}
 1803: 
 1804: 	/*
 1805: 	 * See if there is more to do.  If so, go again.  Sorry about the
 1806: 	 * goto, too much looking at BSD sources...
 1807: 	 */
 1808: 	if (clist == clist1 && clist2 != 0) {
 1809: 		clist = clist2;
 1810: 		goto again;
 1811: 	}
 1812: 
 1813: 	/*
 1814: 	 * If we got extactly 1 near match, use it, else return number
 1815: 	 * of matches.
 1816: 	 */
 1817: 	if (nmatch == 1) {
 1818: 		*cmd = nearmatch;
 1819: 		return 1;
 1820: 	}
 1821: 	return nmatch;
 1822: }
 1823: 
 1824: 
 1825: /*
 1826:  * getnetnum - given a host name, return its net number
 1827:  *	       and (optional) full name
 1828:  */
 1829: int
 1830: getnetnum(
 1831: 	const char *hname,
 1832: 	sockaddr_u *num,
 1833: 	char *fullhost,
 1834: 	int af
 1835: 	)
 1836: {
 1837: 	struct addrinfo hints, *ai = NULL;
 1838: 
 1839: 	ZERO(hints);
 1840: 	hints.ai_flags = AI_CANONNAME;
 1841: #ifdef AI_ADDRCONFIG
 1842: 	hints.ai_flags |= AI_ADDRCONFIG;
 1843: #endif
 1844: 	
 1845: 	/*
 1846: 	 * decodenetnum only works with addresses, but handles syntax
 1847: 	 * that getaddrinfo doesn't:  [2001::1]:1234
 1848: 	 */
 1849: 	if (decodenetnum(hname, num)) {
 1850: 		if (fullhost != NULL)
 1851: 			getnameinfo(&num->sa, SOCKLEN(num), fullhost,
 1852: 				    LENHOSTNAME, NULL, 0, 0);
 1853: 		return 1;
 1854: 	} else if (getaddrinfo(hname, "ntp", &hints, &ai) == 0) {
 1855: 		NTP_INSIST(sizeof(*num) >= ai->ai_addrlen);
 1856: 		memcpy(num, ai->ai_addr, ai->ai_addrlen);
 1857: 		if (fullhost != NULL) {
 1858: 			if (ai->ai_canonname != NULL) {
 1859: 				strncpy(fullhost, ai->ai_canonname,
 1860: 					LENHOSTNAME);
 1861: 				fullhost[LENHOSTNAME - 1] = '\0';
 1862: 			} else {
 1863: 				getnameinfo(&num->sa, SOCKLEN(num),
 1864: 					    fullhost, LENHOSTNAME, NULL,
 1865: 					    0, 0);
 1866: 			}
 1867: 		}
 1868: 		return 1;
 1869: 	}
 1870: 	fprintf(stderr, "***Can't find host %s\n", hname);
 1871: 
 1872: 	return 0;
 1873: }
 1874: 
 1875: /*
 1876:  * nntohost - convert network number to host name.  This routine enforces
 1877:  *	       the showhostnames setting.
 1878:  */
 1879: char *
 1880: nntohost(
 1881: 	sockaddr_u *netnum
 1882: 	)
 1883: {
 1884: 	return nntohost_col(netnum, LIB_BUFLENGTH - 1, FALSE);
 1885: }
 1886: 
 1887: 
 1888: /*
 1889:  * nntohost_col - convert network number to host name in fixed width.
 1890:  *		  This routine enforces the showhostnames setting.
 1891:  *		  When displaying hostnames longer than the width,
 1892:  *		  the first part of the hostname is displayed.  When
 1893:  *		  displaying numeric addresses longer than the width,
 1894:  *		  Such as IPv6 addresses, the caller decides whether
 1895:  *		  the first or last of the numeric address is used.
 1896:  */
 1897: char *
 1898: nntohost_col(
 1899: 	sockaddr_u *	addr,
 1900: 	size_t		width,
 1901: 	int		preserve_lowaddrbits
 1902: 	)
 1903: {
 1904: 	const char *	out;
 1905: 
 1906: 	if (!showhostnames) {
 1907: 		if (preserve_lowaddrbits)
 1908: 			out = trunc_left(stoa(addr), width);
 1909: 		else
 1910: 			out = trunc_right(stoa(addr), width);
 1911: 	} else if (ISREFCLOCKADR(addr)) {
 1912: 		out = refnumtoa(addr);
 1913: 	} else {
 1914: 		out = trunc_right(socktohost(addr), width);
 1915: 	}
 1916: 	return out;
 1917: }
 1918: 
 1919: 
 1920: /*
 1921:  * rtdatetolfp - decode an RT-11 date into an l_fp
 1922:  */
 1923: static int
 1924: rtdatetolfp(
 1925: 	char *str,
 1926: 	l_fp *lfp
 1927: 	)
 1928: {
 1929: 	register char *cp;
 1930: 	register int i;
 1931: 	struct calendar cal;
 1932: 	char buf[4];
 1933: 	static const char *months[12] = {
 1934: 		"Jan", "Feb", "Mar", "Apr", "May", "Jun",
 1935: 		"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
 1936: 	};
 1937: 
 1938: 	cal.yearday = 0;
 1939: 
 1940: 	/*
 1941: 	 * An RT-11 date looks like:
 1942: 	 *
 1943: 	 * d[d]-Mth-y[y] hh:mm:ss
 1944: 	 *
 1945: 	 * (No docs, but assume 4-digit years are also legal...)
 1946: 	 *
 1947: 	 * d[d]-Mth-y[y[y[y]]] hh:mm:ss
 1948: 	 */
 1949: 	cp = str;
 1950: 	if (!isdigit((int)*cp)) {
 1951: 		if (*cp == '-') {
 1952: 			/*
 1953: 			 * Catch special case
 1954: 			 */
 1955: 			L_CLR(lfp);
 1956: 			return 1;
 1957: 		}
 1958: 		return 0;
 1959: 	}
 1960: 
 1961: 	cal.monthday = (u_char) (*cp++ - '0');	/* ascii dependent */
 1962: 	if (isdigit((int)*cp)) {
 1963: 		cal.monthday = (u_char)((cal.monthday << 3) + (cal.monthday << 1));
 1964: 		cal.monthday = (u_char)(cal.monthday + *cp++ - '0');
 1965: 	}
 1966: 
 1967: 	if (*cp++ != '-')
 1968: 	    return 0;
 1969: 	
 1970: 	for (i = 0; i < 3; i++)
 1971: 	    buf[i] = *cp++;
 1972: 	buf[3] = '\0';
 1973: 
 1974: 	for (i = 0; i < 12; i++)
 1975: 	    if (STREQ(buf, months[i]))
 1976: 		break;
 1977: 	if (i == 12)
 1978: 	    return 0;
 1979: 	cal.month = (u_char)(i + 1);
 1980: 
 1981: 	if (*cp++ != '-')
 1982: 	    return 0;
 1983: 	
 1984: 	if (!isdigit((int)*cp))
 1985: 	    return 0;
 1986: 	cal.year = (u_short)(*cp++ - '0');
 1987: 	if (isdigit((int)*cp)) {
 1988: 		cal.year = (u_short)((cal.year << 3) + (cal.year << 1));
 1989: 		cal.year = (u_short)(*cp++ - '0');
 1990: 	}
 1991: 	if (isdigit((int)*cp)) {
 1992: 		cal.year = (u_short)((cal.year << 3) + (cal.year << 1));
 1993: 		cal.year = (u_short)(cal.year + *cp++ - '0');
 1994: 	}
 1995: 	if (isdigit((int)*cp)) {
 1996: 		cal.year = (u_short)((cal.year << 3) + (cal.year << 1));
 1997: 		cal.year = (u_short)(cal.year + *cp++ - '0');
 1998: 	}
 1999: 
 2000: 	/*
 2001: 	 * Catch special case.  If cal.year == 0 this is a zero timestamp.
 2002: 	 */
 2003: 	if (cal.year == 0) {
 2004: 		L_CLR(lfp);
 2005: 		return 1;
 2006: 	}
 2007: 
 2008: 	if (*cp++ != ' ' || !isdigit((int)*cp))
 2009: 	    return 0;
 2010: 	cal.hour = (u_char)(*cp++ - '0');
 2011: 	if (isdigit((int)*cp)) {
 2012: 		cal.hour = (u_char)((cal.hour << 3) + (cal.hour << 1));
 2013: 		cal.hour = (u_char)(cal.hour + *cp++ - '0');
 2014: 	}
 2015: 
 2016: 	if (*cp++ != ':' || !isdigit((int)*cp))
 2017: 	    return 0;
 2018: 	cal.minute = (u_char)(*cp++ - '0');
 2019: 	if (isdigit((int)*cp)) {
 2020: 		cal.minute = (u_char)((cal.minute << 3) + (cal.minute << 1));
 2021: 		cal.minute = (u_char)(cal.minute + *cp++ - '0');
 2022: 	}
 2023: 
 2024: 	if (*cp++ != ':' || !isdigit((int)*cp))
 2025: 	    return 0;
 2026: 	cal.second = (u_char)(*cp++ - '0');
 2027: 	if (isdigit((int)*cp)) {
 2028: 		cal.second = (u_char)((cal.second << 3) + (cal.second << 1));
 2029: 		cal.second = (u_char)(cal.second + *cp++ - '0');
 2030: 	}
 2031: 
 2032: 	/*
 2033: 	 * For RT-11, 1972 seems to be the pivot year
 2034: 	 */
 2035: 	if (cal.year < 72)
 2036: 		cal.year += 2000;
 2037: 	if (cal.year < 100)
 2038: 		cal.year += 1900;
 2039: 
 2040: 	lfp->l_ui = caltontp(&cal);
 2041: 	lfp->l_uf = 0;
 2042: 	return 1;
 2043: }
 2044: 
 2045: 
 2046: /*
 2047:  * decodets - decode a timestamp into an l_fp format number, with
 2048:  *	      consideration of fuzzball formats.
 2049:  */
 2050: int
 2051: decodets(
 2052: 	char *str,
 2053: 	l_fp *lfp
 2054: 	)
 2055: {
 2056: 	char *cp;
 2057: 	char buf[30];
 2058: 	size_t b;
 2059: 
 2060: 	/*
 2061: 	 * If it starts with a 0x, decode as hex.
 2062: 	 */
 2063: 	if (*str == '0' && (*(str+1) == 'x' || *(str+1) == 'X'))
 2064: 		return hextolfp(str+2, lfp);
 2065: 
 2066: 	/*
 2067: 	 * If it starts with a '"', try it as an RT-11 date.
 2068: 	 */
 2069: 	if (*str == '"') {
 2070: 		cp = str + 1;
 2071: 		b = 0;
 2072: 		while ('"' != *cp && '\0' != *cp &&
 2073: 		       b < COUNTOF(buf) - 1)
 2074: 			buf[b++] = *cp++;
 2075: 		buf[b] = '\0';
 2076: 		return rtdatetolfp(buf, lfp);
 2077: 	}
 2078: 
 2079: 	/*
 2080: 	 * Might still be hex.  Check out the first character.  Talk
 2081: 	 * about heuristics!
 2082: 	 */
 2083: 	if ((*str >= 'A' && *str <= 'F') || (*str >= 'a' && *str <= 'f'))
 2084: 		return hextolfp(str, lfp);
 2085: 
 2086: 	/*
 2087: 	 * Try it as a decimal.  If this fails, try as an unquoted
 2088: 	 * RT-11 date.  This code should go away eventually.
 2089: 	 */
 2090: 	if (atolfp(str, lfp))
 2091: 		return 1;
 2092: 
 2093: 	return rtdatetolfp(str, lfp);
 2094: }
 2095: 
 2096: 
 2097: /*
 2098:  * decodetime - decode a time value.  It should be in milliseconds
 2099:  */
 2100: int
 2101: decodetime(
 2102: 	char *str,
 2103: 	l_fp *lfp
 2104: 	)
 2105: {
 2106: 	return mstolfp(str, lfp);
 2107: }
 2108: 
 2109: 
 2110: /*
 2111:  * decodeint - decode an integer
 2112:  */
 2113: int
 2114: decodeint(
 2115: 	char *str,
 2116: 	long *val
 2117: 	)
 2118: {
 2119: 	if (*str == '0') {
 2120: 		if (*(str+1) == 'x' || *(str+1) == 'X')
 2121: 		    return hextoint(str+2, (u_long *)val);
 2122: 		return octtoint(str, (u_long *)val);
 2123: 	}
 2124: 	return atoint(str, val);
 2125: }
 2126: 
 2127: 
 2128: /*
 2129:  * decodeuint - decode an unsigned integer
 2130:  */
 2131: int
 2132: decodeuint(
 2133: 	char *str,
 2134: 	u_long *val
 2135: 	)
 2136: {
 2137: 	if (*str == '0') {
 2138: 		if (*(str + 1) == 'x' || *(str + 1) == 'X')
 2139: 			return (hextoint(str + 2, val));
 2140: 		return (octtoint(str, val));
 2141: 	}
 2142: 	return (atouint(str, val));
 2143: }
 2144: 
 2145: 
 2146: /*
 2147:  * decodearr - decode an array of time values
 2148:  */
 2149: static int
 2150: decodearr(
 2151: 	char *str,
 2152: 	int *narr,
 2153: 	l_fp *lfparr
 2154: 	)
 2155: {
 2156: 	register char *cp, *bp;
 2157: 	register l_fp *lfp;
 2158: 	char buf[60];
 2159: 
 2160: 	lfp = lfparr;
 2161: 	cp = str;
 2162: 	*narr = 0;
 2163: 
 2164: 	while (*narr < 8) {
 2165: 		while (isspace((int)*cp))
 2166: 		    cp++;
 2167: 		if (*cp == '\0')
 2168: 		    break;
 2169: 
 2170: 		bp = buf;
 2171: 		while (!isspace((int)*cp) && *cp != '\0')
 2172: 		    *bp++ = *cp++;
 2173: 		*bp++ = '\0';
 2174: 
 2175: 		if (!decodetime(buf, lfp))
 2176: 		    return 0;
 2177: 		(*narr)++;
 2178: 		lfp++;
 2179: 	}
 2180: 	return 1;
 2181: }
 2182: 
 2183: 
 2184: /*
 2185:  * Finally, the built in command handlers
 2186:  */
 2187: 
 2188: /*
 2189:  * help - tell about commands, or details of a particular command
 2190:  */
 2191: static void
 2192: help(
 2193: 	struct parse *pcmd,
 2194: 	FILE *fp
 2195: 	)
 2196: {
 2197: 	struct xcmd *xcp = NULL;	/* quiet warning */
 2198: 	char *cmd;
 2199: 	const char *list[100];
 2200: 	size_t word, words;
 2201: 	size_t row, rows;
 2202: 	size_t col, cols;
 2203: 	size_t length;
 2204: 
 2205: 	if (pcmd->nargs == 0) {
 2206: 		words = 0;
 2207: 		for (xcp = builtins; xcp->keyword != NULL; xcp++) {
 2208: 			if (*(xcp->keyword) != '?')
 2209: 				list[words++] = xcp->keyword;
 2210: 		}
 2211: 		for (xcp = opcmds; xcp->keyword != NULL; xcp++)
 2212: 			list[words++] = xcp->keyword;
 2213: 
 2214: 		qsort((void *)list, (size_t)words, sizeof(list[0]),
 2215: 		      helpsort);
 2216: 		col = 0;
 2217: 		for (word = 0; word < words; word++) {
 2218: 		 	length = strlen(list[word]);
 2219: 			col = max(col, length);
 2220: 		}
 2221: 
 2222: 		cols = SCREENWIDTH / ++col;
 2223: 		rows = (words + cols - 1) / cols;
 2224: 
 2225: 		fprintf(fp, "ntpq commands:\n");
 2226: 
 2227: 		for (row = 0; row < rows; row++) {
 2228: 			for (word = row; word < words; word += rows)
 2229: 				fprintf(fp, "%-*.*s", col,  col-1,
 2230: 					list[word]);
 2231: 			fprintf(fp, "\n");
 2232: 		}
 2233: 	} else {
 2234: 		cmd = pcmd->argval[0].string;
 2235: 		words = findcmd(cmd, builtins, opcmds, &xcp);
 2236: 		if (words == 0) {
 2237: 			fprintf(stderr,
 2238: 				"Command `%s' is unknown\n", cmd);
 2239: 			return;
 2240: 		} else if (words >= 2) {
 2241: 			fprintf(stderr,
 2242: 				"Command `%s' is ambiguous\n", cmd);
 2243: 			return;
 2244: 		}
 2245: 		fprintf(fp, "function: %s\n", xcp->comment);
 2246: 		printusage(xcp, fp);
 2247: 	}
 2248: }
 2249: 
 2250: 
 2251: /*
 2252:  * helpsort - do hostname qsort comparisons
 2253:  */
 2254: static int
 2255: helpsort(
 2256: 	const void *t1,
 2257: 	const void *t2
 2258: 	)
 2259: {
 2260: 	const char * const *	name1 = t1;
 2261: 	const char * const *	name2 = t2;
 2262: 
 2263: 	return strcmp(*name1, *name2);
 2264: }
 2265: 
 2266: 
 2267: /*
 2268:  * printusage - print usage information for a command
 2269:  */
 2270: static void
 2271: printusage(
 2272: 	struct xcmd *xcp,
 2273: 	FILE *fp
 2274: 	)
 2275: {
 2276: 	register int i;
 2277: 
 2278: 	(void) fprintf(fp, "usage: %s", xcp->keyword);
 2279: 	for (i = 0; i < MAXARGS && xcp->arg[i] != NO; i++) {
 2280: 		if (xcp->arg[i] & OPT)
 2281: 		    (void) fprintf(fp, " [ %s ]", xcp->desc[i]);
 2282: 		else
 2283: 		    (void) fprintf(fp, " %s", xcp->desc[i]);
 2284: 	}
 2285: 	(void) fprintf(fp, "\n");
 2286: }
 2287: 
 2288: 
 2289: /*
 2290:  * timeout - set time out time
 2291:  */
 2292: static void
 2293: timeout(
 2294: 	struct parse *pcmd,
 2295: 	FILE *fp
 2296: 	)
 2297: {
 2298: 	int val;
 2299: 
 2300: 	if (pcmd->nargs == 0) {
 2301: 		val = (int)tvout.tv_sec * 1000 + tvout.tv_usec / 1000;
 2302: 		(void) fprintf(fp, "primary timeout %d ms\n", val);
 2303: 	} else {
 2304: 		tvout.tv_sec = pcmd->argval[0].uval / 1000;
 2305: 		tvout.tv_usec = (pcmd->argval[0].uval - ((long)tvout.tv_sec * 1000))
 2306: 			* 1000;
 2307: 	}
 2308: }
 2309: 
 2310: 
 2311: /*
 2312:  * auth_delay - set delay for auth requests
 2313:  */
 2314: static void
 2315: auth_delay(
 2316: 	struct parse *pcmd,
 2317: 	FILE *fp
 2318: 	)
 2319: {
 2320: 	int isneg;
 2321: 	u_long val;
 2322: 
 2323: 	if (pcmd->nargs == 0) {
 2324: 		val = delay_time.l_ui * 1000 + delay_time.l_uf / 4294967;
 2325: 		(void) fprintf(fp, "delay %lu ms\n", val);
 2326: 	} else {
 2327: 		if (pcmd->argval[0].ival < 0) {
 2328: 			isneg = 1;
 2329: 			val = (u_long)(-pcmd->argval[0].ival);
 2330: 		} else {
 2331: 			isneg = 0;
 2332: 			val = (u_long)pcmd->argval[0].ival;
 2333: 		}
 2334: 
 2335: 		delay_time.l_ui = val / 1000;
 2336: 		val %= 1000;
 2337: 		delay_time.l_uf = val * 4294967;	/* 2**32/1000 */
 2338: 
 2339: 		if (isneg)
 2340: 		    L_NEG(&delay_time);
 2341: 	}
 2342: }
 2343: 
 2344: 
 2345: /*
 2346:  * host - set the host we are dealing with.
 2347:  */
 2348: static void
 2349: host(
 2350: 	struct parse *pcmd,
 2351: 	FILE *fp
 2352: 	)
 2353: {
 2354: 	int i;
 2355: 
 2356: 	if (pcmd->nargs == 0) {
 2357: 		if (havehost)
 2358: 			(void) fprintf(fp, "current host is %s\n",
 2359: 					   currenthost);
 2360: 		else
 2361: 			(void) fprintf(fp, "no current host\n");
 2362: 		return;
 2363: 	}
 2364: 
 2365: 	i = 0;
 2366: 	ai_fam_templ = ai_fam_default;
 2367: 	if (pcmd->nargs == 2) {
 2368: 		if (!strcmp("-4", pcmd->argval[i].string))
 2369: 			ai_fam_templ = AF_INET;
 2370: 		else if (!strcmp("-6", pcmd->argval[i].string))
 2371: 			ai_fam_templ = AF_INET6;
 2372: 		else {
 2373: 			if (havehost)
 2374: 				(void) fprintf(fp,
 2375: 					       "current host remains %s\n",
 2376: 					       currenthost);
 2377: 			else
 2378: 				(void) fprintf(fp, "still no current host\n");
 2379: 			return;
 2380: 		}
 2381: 		i = 1;
 2382: 	}
 2383: 	if (openhost(pcmd->argval[i].string)) {
 2384: 		(void) fprintf(fp, "current host set to %s\n", currenthost);
 2385: 		numassoc = 0;
 2386: 	} else {
 2387: 		if (havehost)
 2388: 			(void) fprintf(fp,
 2389: 				       "current host remains %s\n", 
 2390: 				       currenthost);
 2391: 		else
 2392: 			(void) fprintf(fp, "still no current host\n");
 2393: 	}
 2394: }
 2395: 
 2396: 
 2397: /*
 2398:  * poll - do one (or more) polls of the host via NTP
 2399:  */
 2400: /*ARGSUSED*/
 2401: static void
 2402: ntp_poll(
 2403: 	struct parse *pcmd,
 2404: 	FILE *fp
 2405: 	)
 2406: {
 2407: 	(void) fprintf(fp, "poll not implemented yet\n");
 2408: }
 2409: 
 2410: 
 2411: /*
 2412:  * keyid - get a keyid to use for authenticating requests
 2413:  */
 2414: static void
 2415: keyid(
 2416: 	struct parse *pcmd,
 2417: 	FILE *fp
 2418: 	)
 2419: {
 2420: 	if (pcmd->nargs == 0) {
 2421: 		if (info_auth_keyid == 0)
 2422: 		    (void) fprintf(fp, "no keyid defined\n");
 2423: 		else
 2424: 		    (void) fprintf(fp, "keyid is %lu\n", (u_long)info_auth_keyid);
 2425: 	} else {
 2426: 		/* allow zero so that keyid can be cleared. */
 2427: 		if(pcmd->argval[0].uval > NTP_MAXKEY)
 2428: 		    (void) fprintf(fp, "Invalid key identifier\n");
 2429: 		info_auth_keyid = pcmd->argval[0].uval;
 2430: 	}
 2431: }
 2432: 
 2433: /*
 2434:  * keytype - get type of key to use for authenticating requests
 2435:  */
 2436: static void
 2437: keytype(
 2438: 	struct parse *pcmd,
 2439: 	FILE *fp
 2440: 	)
 2441: {
 2442: 	const char *	digest_name;
 2443: 	size_t		digest_len;
 2444: 	int		key_type;
 2445: 
 2446: 	if (!pcmd->nargs) {
 2447: 		fprintf(fp, "keytype is %s with %lu octet digests\n",
 2448: 			keytype_name(info_auth_keytype),
 2449: 			(u_long)info_auth_hashlen);
 2450: 		return;
 2451: 	}
 2452: 
 2453: 	digest_name = pcmd->argval[0].string;
 2454: 	digest_len = 0;
 2455: 	key_type = keytype_from_text(digest_name, &digest_len);
 2456: 
 2457: 	if (!key_type) {
 2458: 		fprintf(fp, "keytype must be 'md5'%s\n",
 2459: #ifdef OPENSSL
 2460: 			" or a digest type provided by OpenSSL");
 2461: #else
 2462: 			"");
 2463: #endif
 2464: 		return;
 2465: 	}
 2466: 
 2467: 	info_auth_keytype = key_type;
 2468: 	info_auth_hashlen = digest_len;
 2469: }
 2470: 
 2471: 
 2472: /*
 2473:  * passwd - get an authentication key
 2474:  */
 2475: /*ARGSUSED*/
 2476: static void
 2477: passwd(
 2478: 	struct parse *pcmd,
 2479: 	FILE *fp
 2480: 	)
 2481: {
 2482: 	char *pass;
 2483: 
 2484: 	if (info_auth_keyid == 0) {
 2485: 		int u_keyid = getkeyid("Keyid: ");
 2486: 		if (u_keyid == 0 || u_keyid > NTP_MAXKEY) {
 2487: 			(void)fprintf(fp, "Invalid key identifier\n");
 2488: 			return;
 2489: 		}
 2490: 		info_auth_keyid = u_keyid;
 2491: 	}
 2492: 	if (pcmd->nargs >= 1)
 2493: 		pass = pcmd->argval[0].string;
 2494: 	else {
 2495: 		pass = getpass_keytype(info_auth_keytype);
 2496: 		if ('\0' == pass[0]) {
 2497: 			fprintf(fp, "Password unchanged\n");
 2498: 			return;
 2499: 		}
 2500: 	}
 2501: 	authusekey(info_auth_keyid, info_auth_keytype, (u_char *)pass);
 2502: 	authtrust(info_auth_keyid, 1);
 2503: }
 2504: 
 2505: 
 2506: /*
 2507:  * hostnames - set the showhostnames flag
 2508:  */
 2509: static void
 2510: hostnames(
 2511: 	struct parse *pcmd,
 2512: 	FILE *fp
 2513: 	)
 2514: {
 2515: 	if (pcmd->nargs == 0) {
 2516: 		if (showhostnames)
 2517: 		    (void) fprintf(fp, "hostnames being shown\n");
 2518: 		else
 2519: 		    (void) fprintf(fp, "hostnames not being shown\n");
 2520: 	} else {
 2521: 		if (STREQ(pcmd->argval[0].string, "yes"))
 2522: 		    showhostnames = 1;
 2523: 		else if (STREQ(pcmd->argval[0].string, "no"))
 2524: 		    showhostnames = 0;
 2525: 		else
 2526: 		    (void)fprintf(stderr, "What?\n");
 2527: 	}
 2528: }
 2529: 
 2530: 
 2531: 
 2532: /*
 2533:  * setdebug - set/change debugging level
 2534:  */
 2535: static void
 2536: setdebug(
 2537: 	struct parse *pcmd,
 2538: 	FILE *fp
 2539: 	)
 2540: {
 2541: 	if (pcmd->nargs == 0) {
 2542: 		(void) fprintf(fp, "debug level is %d\n", debug);
 2543: 		return;
 2544: 	} else if (STREQ(pcmd->argval[0].string, "no")) {
 2545: 		debug = 0;
 2546: 	} else if (STREQ(pcmd->argval[0].string, "more")) {
 2547: 		debug++;
 2548: 	} else if (STREQ(pcmd->argval[0].string, "less")) {
 2549: 		debug--;
 2550: 	} else {
 2551: 		(void) fprintf(fp, "What?\n");
 2552: 		return;
 2553: 	}
 2554: 	(void) fprintf(fp, "debug level set to %d\n", debug);
 2555: }
 2556: 
 2557: 
 2558: /*
 2559:  * quit - stop this nonsense
 2560:  */
 2561: /*ARGSUSED*/
 2562: static void
 2563: quit(
 2564: 	struct parse *pcmd,
 2565: 	FILE *fp
 2566: 	)
 2567: {
 2568: 	if (havehost)
 2569: 	    closesocket(sockfd);	/* cleanliness next to godliness */
 2570: 	exit(0);
 2571: }
 2572: 
 2573: 
 2574: /*
 2575:  * version - print the current version number
 2576:  */
 2577: /*ARGSUSED*/
 2578: static void
 2579: version(
 2580: 	struct parse *pcmd,
 2581: 	FILE *fp
 2582: 	)
 2583: {
 2584: 
 2585: 	(void) fprintf(fp, "%s\n", Version);
 2586: 	return;
 2587: }
 2588: 
 2589: 
 2590: /*
 2591:  * raw - set raw mode output
 2592:  */
 2593: /*ARGSUSED*/
 2594: static void
 2595: raw(
 2596: 	struct parse *pcmd,
 2597: 	FILE *fp
 2598: 	)
 2599: {
 2600: 	rawmode = 1;
 2601: 	(void) fprintf(fp, "Output set to raw\n");
 2602: }
 2603: 
 2604: 
 2605: /*
 2606:  * cooked - set cooked mode output
 2607:  */
 2608: /*ARGSUSED*/
 2609: static void
 2610: cooked(
 2611: 	struct parse *pcmd,
 2612: 	FILE *fp
 2613: 	)
 2614: {
 2615: 	rawmode = 0;
 2616: 	(void) fprintf(fp, "Output set to cooked\n");
 2617: 	return;
 2618: }
 2619: 
 2620: 
 2621: /*
 2622:  * authenticate - always authenticate requests to this host
 2623:  */
 2624: static void
 2625: authenticate(
 2626: 	struct parse *pcmd,
 2627: 	FILE *fp
 2628: 	)
 2629: {
 2630: 	if (pcmd->nargs == 0) {
 2631: 		if (always_auth) {
 2632: 			(void) fprintf(fp,
 2633: 				       "authenticated requests being sent\n");
 2634: 		} else
 2635: 		    (void) fprintf(fp,
 2636: 				   "unauthenticated requests being sent\n");
 2637: 	} else {
 2638: 		if (STREQ(pcmd->argval[0].string, "yes")) {
 2639: 			always_auth = 1;
 2640: 		} else if (STREQ(pcmd->argval[0].string, "no")) {
 2641: 			always_auth = 0;
 2642: 		} else
 2643: 		    (void)fprintf(stderr, "What?\n");
 2644: 	}
 2645: }
 2646: 
 2647: 
 2648: /*
 2649:  * ntpversion - choose the NTP version to use
 2650:  */
 2651: static void
 2652: ntpversion(
 2653: 	struct parse *pcmd,
 2654: 	FILE *fp
 2655: 	)
 2656: {
 2657: 	if (pcmd->nargs == 0) {
 2658: 		(void) fprintf(fp,
 2659: 			       "NTP version being claimed is %d\n", pktversion);
 2660: 	} else {
 2661: 		if (pcmd->argval[0].uval < NTP_OLDVERSION
 2662: 		    || pcmd->argval[0].uval > NTP_VERSION) {
 2663: 			(void) fprintf(stderr, "versions %d to %d, please\n",
 2664: 				       NTP_OLDVERSION, NTP_VERSION);
 2665: 		} else {
 2666: 			pktversion = (u_char) pcmd->argval[0].uval;
 2667: 		}
 2668: 	}
 2669: }
 2670: 
 2671: 
 2672: /*
 2673:  * warning - print a warning message
 2674:  */
 2675: static void
 2676: warning(
 2677: 	const char *fmt,
 2678: 	const char *st1,
 2679: 	const char *st2
 2680: 	)
 2681: {
 2682: 	(void) fprintf(stderr, "%s: ", progname);
 2683: 	(void) fprintf(stderr, fmt, st1, st2);
 2684: 	(void) fprintf(stderr, ": ");
 2685: 	perror("");
 2686: }
 2687: 
 2688: 
 2689: /*
 2690:  * error - print a message and exit
 2691:  */
 2692: static void
 2693: error(
 2694: 	const char *fmt,
 2695: 	const char *st1,
 2696: 	const char *st2
 2697: 	)
 2698: {
 2699: 	warning(fmt, st1, st2);
 2700: 	exit(1);
 2701: }
 2702: 
 2703: /*
 2704:  * getkeyid - prompt the user for a keyid to use
 2705:  */
 2706: static u_long
 2707: getkeyid(
 2708: 	const char *keyprompt
 2709: 	)
 2710: {
 2711: 	int c;
 2712: 	FILE *fi;
 2713: 	char pbuf[20];
 2714: 	size_t i;
 2715: 	size_t ilim;
 2716: 
 2717: #ifndef SYS_WINNT
 2718: 	if ((fi = fdopen(open("/dev/tty", 2), "r")) == NULL)
 2719: #else
 2720: 	if ((fi = _fdopen(open("CONIN$", _O_TEXT), "r")) == NULL)
 2721: #endif /* SYS_WINNT */
 2722: 		fi = stdin;
 2723: 	else
 2724: 		setbuf(fi, (char *)NULL);
 2725: 	fprintf(stderr, "%s", keyprompt); fflush(stderr);
 2726: 	for (i = 0, ilim = COUNTOF(pbuf) - 1;
 2727: 	     i < ilim && (c = getc(fi)) != '\n' && c != EOF;
 2728: 	     )
 2729: 		pbuf[i++] = (char)c;
 2730: 	pbuf[i] = '\0';
 2731: 	if (fi != stdin)
 2732: 		fclose(fi);
 2733: 
 2734: 	return (u_long) atoi(pbuf);
 2735: }
 2736: 
 2737: 
 2738: /*
 2739:  * atoascii - printable-ize possibly ascii data using the character
 2740:  *	      transformations cat -v uses.
 2741:  */
 2742: static void
 2743: atoascii(
 2744: 	const char *in,
 2745: 	size_t in_octets,
 2746: 	char *out,
 2747: 	size_t out_octets
 2748: 	)
 2749: {
 2750: 	register const u_char *	pchIn;
 2751: 		 const u_char *	pchInLimit;
 2752: 	register u_char *	pchOut;
 2753: 	register u_char		c;
 2754: 
 2755: 	pchIn = (const u_char *)in;
 2756: 	pchInLimit = pchIn + in_octets;
 2757: 	pchOut = (u_char *)out;
 2758: 
 2759: 	if (NULL == pchIn) {
 2760: 		if (0 < out_octets)
 2761: 			*pchOut = '\0';
 2762: 		return;
 2763: 	}
 2764: 
 2765: #define	ONEOUT(c)					\
 2766: do {							\
 2767: 	if (0 == --out_octets) {			\
 2768: 		*pchOut = '\0';				\
 2769: 		return;					\
 2770: 	}						\
 2771: 	*pchOut++ = (c);				\
 2772: } while (0)
 2773: 
 2774: 	for (	; pchIn < pchInLimit; pchIn++) {
 2775: 		c = *pchIn;
 2776: 		if ('\0' == c)
 2777: 			break;
 2778: 		if (c & 0x80) {
 2779: 			ONEOUT('M');
 2780: 			ONEOUT('-');
 2781: 			c &= 0x7f;
 2782: 		}
 2783: 		if (c < ' ') {
 2784: 			ONEOUT('^');
 2785: 			ONEOUT((u_char)(c + '@'));
 2786: 		} else if (0x7f == c) {
 2787: 			ONEOUT('^');
 2788: 			ONEOUT('?');
 2789: 		} else
 2790: 			ONEOUT(c);
 2791: 	}
 2792: 	ONEOUT('\0');
 2793: 
 2794: #undef ONEOUT
 2795: }
 2796: 
 2797: 
 2798: /*
 2799:  * makeascii - print possibly ascii data using the character
 2800:  *	       transformations that cat -v uses.
 2801:  */
 2802: void
 2803: makeascii(
 2804: 	int length,
 2805: 	const char *data,
 2806: 	FILE *fp
 2807: 	)
 2808: {
 2809: 	const u_char *data_u_char;
 2810: 	const u_char *cp;
 2811: 	int c;
 2812: 
 2813: 	data_u_char = (const u_char *)data;
 2814: 
 2815: 	for (cp = data_u_char; cp < data_u_char + length; cp++) {
 2816: 		c = (int)*cp;
 2817: 		if (c & 0x80) {
 2818: 			putc('M', fp);
 2819: 			putc('-', fp);
 2820: 			c &= 0x7f;
 2821: 		}
 2822: 
 2823: 		if (c < ' ') {
 2824: 			putc('^', fp);
 2825: 			putc(c + '@', fp);
 2826: 		} else if (0x7f == c) {
 2827: 			putc('^', fp);
 2828: 			putc('?', fp);
 2829: 		} else
 2830: 			putc(c, fp);
 2831: 	}
 2832: }
 2833: 
 2834: 
 2835: /*
 2836:  * asciize - same thing as makeascii except add a newline
 2837:  */
 2838: void
 2839: asciize(
 2840: 	int length,
 2841: 	char *data,
 2842: 	FILE *fp
 2843: 	)
 2844: {
 2845: 	makeascii(length, data, fp);
 2846: 	putc('\n', fp);
 2847: }
 2848: 
 2849: 
 2850: /*
 2851:  * truncate string to fit clipping excess at end.
 2852:  *	"too long"	->	"too l"
 2853:  * Used for hostnames.
 2854:  */
 2855: char *
 2856: trunc_right(
 2857: 	const char *	src,
 2858: 	size_t		width
 2859: 	)
 2860: {
 2861: 	size_t	sl;
 2862: 	char *	out;
 2863: 
 2864: 	
 2865: 	sl = strlen(src);
 2866: 	if (sl > width && LIB_BUFLENGTH - 1 > width && width > 0) {
 2867: 		LIB_GETBUF(out);
 2868: 		memcpy(out, src, width);
 2869: 		out[width] = '\0';
 2870: 
 2871: 		return out;
 2872: 	}
 2873: 
 2874: 	return src;
 2875: }
 2876: 
 2877: 
 2878: /*
 2879:  * truncate string to fit by preserving right side and using '_' to hint
 2880:  *	"too long"	->	"_long"
 2881:  * Used for local IPv6 addresses, where low bits differentiate.
 2882:  */
 2883: char *
 2884: trunc_left(
 2885: 	const char *	src,
 2886: 	size_t		width
 2887: 	)
 2888: {
 2889: 	size_t	sl;
 2890: 	char *	out;
 2891: 
 2892: 
 2893: 	sl = strlen(src);
 2894: 	if (sl > width && LIB_BUFLENGTH - 1 > width && width > 1) {
 2895: 		LIB_GETBUF(out);
 2896: 		out[0] = '_';
 2897: 		memcpy(&out[1], &src[sl + 1 - width], width);
 2898: 
 2899: 		return out;
 2900: 	}
 2901: 
 2902: 	return src;
 2903: }
 2904: 
 2905: 
 2906: /*
 2907:  * Some circular buffer space
 2908:  */
 2909: #define	CBLEN	80
 2910: #define	NUMCB	6
 2911: 
 2912: char circ_buf[NUMCB][CBLEN];
 2913: int nextcb = 0;
 2914: 
 2915: /*
 2916:  * nextvar - find the next variable in the buffer
 2917:  */
 2918: int
 2919: nextvar(
 2920: 	int *datalen,
 2921: 	const char **datap,
 2922: 	char **vname,
 2923: 	char **vvalue
 2924: 	)
 2925: {
 2926: 	const char *cp;
 2927: 	char *np;
 2928: 	const char *cpend;
 2929: 	char *npend;	/* character after last */
 2930: 	int quoted = 0;
 2931: 	static char name[MAXVARLEN];
 2932: 	static char value[MAXVALLEN];
 2933: 
 2934: 	cp = *datap;
 2935: 	cpend = cp + *datalen;
 2936: 
 2937: 	/*
 2938: 	 * Space past commas and white space
 2939: 	 */
 2940: 	while (cp < cpend && (*cp == ',' || isspace((int)*cp)))
 2941: 		cp++;
 2942: 	if (cp == cpend)
 2943: 		return 0;
 2944: 	
 2945: 	/*
 2946: 	 * Copy name until we hit a ',', an '=', a '\r' or a '\n'.  Backspace
 2947: 	 * over any white space and terminate it.
 2948: 	 */
 2949: 	np = name;
 2950: 	npend = &name[MAXVARLEN];
 2951: 	while (cp < cpend && np < npend && *cp != ',' && *cp != '='
 2952: 	       && *cp != '\r' && *cp != '\n')
 2953: 	    *np++ = *cp++;
 2954: 	/*
 2955: 	 * Check if we ran out of name space, without reaching the end or a
 2956: 	 * terminating character
 2957: 	 */
 2958: 	if (np == npend && !(cp == cpend || *cp == ',' || *cp == '=' ||
 2959: 			     *cp == '\r' || *cp == '\n'))
 2960: 	    return 0;
 2961: 	while (isspace((int)(*(np-1))))
 2962: 	    np--;
 2963: 	*np = '\0';
 2964: 	*vname = name;
 2965: 
 2966: 	/*
 2967: 	 * Check if we hit the end of the buffer or a ','.  If so we are done.
 2968: 	 */
 2969: 	if (cp == cpend || *cp == ',' || *cp == '\r' || *cp == '\n') {
 2970: 		if (cp != cpend)
 2971: 		    cp++;
 2972: 		*datap = cp;
 2973: 		*datalen = cpend - cp;
 2974: 		*vvalue = (char *)0;
 2975: 		return 1;
 2976: 	}
 2977: 
 2978: 	/*
 2979: 	 * So far, so good.  Copy out the value
 2980: 	 */
 2981: 	cp++;	/* past '=' */
 2982: 	while (cp < cpend && (isspace((int)*cp) && *cp != '\r' && *cp != '\n'))
 2983: 	    cp++;
 2984: 	np = value;
 2985: 	npend = &value[MAXVALLEN];
 2986: 	while (cp < cpend && np < npend && ((*cp != ',') || quoted))
 2987: 	{
 2988: 		quoted ^= ((*np++ = *cp++) == '"');
 2989: 	}
 2990: 
 2991: 	/*
 2992: 	 * Check if we overran the value buffer while still in a quoted string
 2993: 	 * or without finding a comma
 2994: 	 */
 2995: 	if (np == npend && (quoted || *cp != ','))
 2996: 	    return 0;
 2997: 	/*
 2998: 	 * Trim off any trailing whitespace
 2999: 	 */
 3000: 	while (np > value && isspace((int)(*(np-1))))
 3001: 	    np--;
 3002: 	*np = '\0';
 3003: 
 3004: 	/*
 3005: 	 * Return this.  All done.
 3006: 	 */
 3007: 	if (cp != cpend)
 3008: 	    cp++;
 3009: 	*datap = cp;
 3010: 	*datalen = cpend - cp;
 3011: 	*vvalue = value;
 3012: 	return 1;
 3013: }
 3014: 
 3015: 
 3016: /*
 3017:  * findvar - see if this variable is known to us.
 3018:  * If "code" is 1, return ctl_var->code.
 3019:  * Otherwise return the ordinal position of the found variable.
 3020:  */
 3021: int
 3022: findvar(
 3023: 	char *varname,
 3024: 	struct ctl_var *varlist,
 3025: 	int code
 3026: 	)
 3027: {
 3028: 	register char *np;
 3029: 	register struct ctl_var *vl;
 3030: 
 3031: 	vl = varlist;
 3032: 	np = varname;
 3033: 	while (vl->fmt != EOV) {
 3034: 		if (vl->fmt != PADDING && STREQ(np, vl->text))
 3035: 		    return (code)
 3036: 				? vl->code
 3037: 				: (vl - varlist)
 3038: 			    ;
 3039: 		vl++;
 3040: 	}
 3041: 	return 0;
 3042: }
 3043: 
 3044: 
 3045: 
 3046: /*
 3047:  * printvars - print variables returned in response packet
 3048:  */
 3049: void
 3050: printvars(
 3051: 	int length,
 3052: 	const char *data,
 3053: 	int status,
 3054: 	int sttype,
 3055: 	int quiet,
 3056: 	FILE *fp
 3057: 	)
 3058: {
 3059: 	if (rawmode)
 3060: 	    rawprint(sttype, length, data, status, quiet, fp);
 3061: 	else
 3062: 	    cookedprint(sttype, length, data, status, quiet, fp);
 3063: }
 3064: 
 3065: 
 3066: /*
 3067:  * rawprint - do a printout of the data in raw mode
 3068:  */
 3069: static void
 3070: rawprint(
 3071: 	int datatype,
 3072: 	int length,
 3073: 	const char *data,
 3074: 	int status,
 3075: 	int quiet,
 3076: 	FILE *fp
 3077: 	)
 3078: {
 3079: 	const char *cp;
 3080: 	const char *cpend;
 3081: 
 3082: 	/*
 3083: 	 * Essentially print the data as is.  We reformat unprintables, though.
 3084: 	 */
 3085: 	cp = data;
 3086: 	cpend = data + length;
 3087: 
 3088: 	if (!quiet)
 3089: 		(void) fprintf(fp, "status=0x%04x,\n", status);
 3090: 
 3091: 	while (cp < cpend) {
 3092: 		if (*cp == '\r') {
 3093: 			/*
 3094: 			 * If this is a \r and the next character is a
 3095: 			 * \n, supress this, else pretty print it.  Otherwise
 3096: 			 * just output the character.
 3097: 			 */
 3098: 			if (cp == (cpend - 1) || *(cp + 1) != '\n')
 3099: 			    makeascii(1, cp, fp);
 3100: 		} else if (isspace(*cp) || isprint(*cp))
 3101: 			putc(*cp, fp);
 3102: 		else
 3103: 			makeascii(1, cp, fp);
 3104: 		cp++;
 3105: 	}
 3106: }
 3107: 
 3108: 
 3109: /*
 3110:  * Global data used by the cooked output routines
 3111:  */
 3112: int out_chars;		/* number of characters output */
 3113: int out_linecount;	/* number of characters output on this line */
 3114: 
 3115: 
 3116: /*
 3117:  * startoutput - get ready to do cooked output
 3118:  */
 3119: static void
 3120: startoutput(void)
 3121: {
 3122: 	out_chars = 0;
 3123: 	out_linecount = 0;
 3124: }
 3125: 
 3126: 
 3127: /*
 3128:  * output - output a variable=value combination
 3129:  */
 3130: static void
 3131: output(
 3132: 	FILE *fp,
 3133: 	char *name,
 3134: 	char *value
 3135: 	)
 3136: {
 3137: 	size_t len;
 3138: 
 3139: 	/* strlen of "name=value" */
 3140: 	len = strlen(name) + 1 + strlen(value);
 3141: 
 3142: 	if (out_chars != 0) {
 3143: 		out_chars += 2;
 3144: 		if ((out_linecount + len + 2) > MAXOUTLINE) {
 3145: 			fputs(",\n", fp);
 3146: 			out_linecount = 0;
 3147: 		} else {
 3148: 			fputs(", ", fp);
 3149: 			out_linecount += 2;
 3150: 		}
 3151: 	}
 3152: 
 3153: 	fputs(name, fp);
 3154: 	putc('=', fp);
 3155: 	fputs(value, fp);
 3156: 	out_chars += len;
 3157: 	out_linecount += len;
 3158: }
 3159: 
 3160: 
 3161: /*
 3162:  * endoutput - terminate a block of cooked output
 3163:  */
 3164: static void
 3165: endoutput(
 3166: 	FILE *fp
 3167: 	)
 3168: {
 3169: 	if (out_chars != 0)
 3170: 		putc('\n', fp);
 3171: }
 3172: 
 3173: 
 3174: /*
 3175:  * outputarr - output an array of values
 3176:  */
 3177: static void
 3178: outputarr(
 3179: 	FILE *fp,
 3180: 	char *name,
 3181: 	int narr,
 3182: 	l_fp *lfp
 3183: 	)
 3184: {
 3185: 	register char *bp;
 3186: 	register char *cp;
 3187: 	register int i;
 3188: 	register int len;
 3189: 	char buf[256];
 3190: 
 3191: 	bp = buf;
 3192: 	/*
 3193: 	 * Hack to align delay and offset values
 3194: 	 */
 3195: 	for (i = (int)strlen(name); i < 11; i++)
 3196: 	    *bp++ = ' ';
 3197: 	
 3198: 	for (i = narr; i > 0; i--) {
 3199: 		if (i != narr)
 3200: 		    *bp++ = ' ';
 3201: 		cp = lfptoms(lfp, 2);
 3202: 		len = strlen(cp);
 3203: 		if (len > 7) {
 3204: 			cp[7] = '\0';
 3205: 			len = 7;
 3206: 		}
 3207: 		while (len < 7) {
 3208: 			*bp++ = ' ';
 3209: 			len++;
 3210: 		}
 3211: 		while (*cp != '\0')
 3212: 		    *bp++ = *cp++;
 3213: 		lfp++;
 3214: 	}
 3215: 	*bp = '\0';
 3216: 	output(fp, name, buf);
 3217: }
 3218: 
 3219: static char *
 3220: tstflags(
 3221: 	u_long val
 3222: 	)
 3223: {
 3224: 	register char *cp, *s;
 3225: 	size_t cb;
 3226: 	register int i;
 3227: 	register const char *sep;
 3228: 
 3229: 	sep = "";
 3230: 	i = 0;
 3231: 	s = cp = circ_buf[nextcb];
 3232: 	if (++nextcb >= NUMCB)
 3233: 		nextcb = 0;
 3234: 	cb = sizeof(circ_buf[0]);
 3235: 
 3236: 	snprintf(cp, cb, "%02lx", val);
 3237: 	cp += strlen(cp);
 3238: 	cb -= strlen(cp);
 3239: 	if (!val) {
 3240: 		strncat(cp, " ok", cb);
 3241: 		cp += strlen(cp);
 3242: 		cb -= strlen(cp);
 3243: 	} else {
 3244: 		if (cb) {
 3245: 			*cp++ = ' ';
 3246: 			cb--;
 3247: 		}
 3248: 		for (i = 0; i < COUNTOF(tstflagnames); i++) {
 3249: 			if (val & 0x1) {
 3250: 				snprintf(cp, cb, "%s%s", sep,
 3251: 					 tstflagnames[i]);
 3252: 				sep = ", ";
 3253: 				cp += strlen(cp);
 3254: 				cb -= strlen(cp);
 3255: 			}
 3256: 			val >>= 1;
 3257: 		}
 3258: 	}
 3259: 	if (cb)
 3260: 		*cp = '\0';
 3261: 
 3262: 	return s;
 3263: }
 3264: 
 3265: /*
 3266:  * cookedprint - output variables in cooked mode
 3267:  */
 3268: static void
 3269: cookedprint(
 3270: 	int datatype,
 3271: 	int length,
 3272: 	const char *data,
 3273: 	int status,
 3274: 	int quiet,
 3275: 	FILE *fp
 3276: 	)
 3277: {
 3278: 	register int varid;
 3279: 	char *name;
 3280: 	char *value;
 3281: 	char output_raw;
 3282: 	int fmt;
 3283: 	struct ctl_var *varlist;
 3284: 	l_fp lfp;
 3285: 	long ival;
 3286: 	sockaddr_u hval;
 3287: 	u_long uval;
 3288: 	l_fp lfparr[8];
 3289: 	int narr;
 3290: 
 3291: 	switch (datatype) {
 3292: 	case TYPE_PEER:
 3293: 		varlist = peer_var;
 3294: 		break;
 3295: 	case TYPE_SYS:
 3296: 		varlist = sys_var;
 3297: 		break;
 3298: 	case TYPE_CLOCK:
 3299: 		varlist = clock_var;
 3300: 		break;
 3301: 	default:
 3302: 		fprintf(stderr, "Unknown datatype(0x%x) in cookedprint\n",
 3303: 			datatype);
 3304: 		return;
 3305: 	}
 3306: 
 3307: 	if (!quiet)
 3308: 		fprintf(fp, "status=%04x %s,\n", status,
 3309: 			statustoa(datatype, status));
 3310: 
 3311: 	startoutput();
 3312: 	while (nextvar(&length, &data, &name, &value)) {
 3313: 		varid = findvar(name, varlist, 0);
 3314: 		if (varid == 0) {
 3315: 			output_raw = '*';
 3316: 		} else {
 3317: 			output_raw = 0;
 3318: 			fmt = varlist[varid].fmt;
 3319: 			switch(fmt) {
 3320: 			    case TS:
 3321: 				if (!decodets(value, &lfp))
 3322: 				    output_raw = '?';
 3323: 				else
 3324: 				    output(fp, name, prettydate(&lfp));
 3325: 				break;
 3326: 			    case FL:
 3327: 			    case FU:
 3328: 			    case FS:
 3329: 				if (!decodetime(value, &lfp))
 3330: 				    output_raw = '?';
 3331: 				else {
 3332: 					switch (fmt) {
 3333: 					    case FL:
 3334: 						output(fp, name,
 3335: 						       lfptoms(&lfp, 3));
 3336: 						break;
 3337: 					    case FU:
 3338: 						output(fp, name,
 3339: 						       ulfptoms(&lfp, 3));
 3340: 						break;
 3341: 					    case FS:
 3342: 						output(fp, name,
 3343: 						       lfptoms(&lfp, 3));
 3344: 						break;
 3345: 					}
 3346: 				}
 3347: 				break;
 3348: 			
 3349: 			    case UI:
 3350: 				if (!decodeuint(value, &uval))
 3351: 				    output_raw = '?';
 3352: 				else
 3353: 				    output(fp, name, uinttoa(uval));
 3354: 				break;
 3355: 			
 3356: 			    case SI:
 3357: 				if (!decodeint(value, &ival))
 3358: 				    output_raw = '?';
 3359: 				else
 3360: 				    output(fp, name, inttoa(ival));
 3361: 				break;
 3362: 
 3363: 			    case HA:
 3364: 			    case NA:
 3365: 				if (!decodenetnum(value, &hval))
 3366: 				    output_raw = '?';
 3367: 				else if (fmt == HA){
 3368: 				    output(fp, name, nntohost(&hval));
 3369: 				} else {
 3370: 				    output(fp, name, stoa(&hval));
 3371: 				}
 3372: 				break;
 3373: 			
 3374: 			    case ST:
 3375: 				output_raw = '*';
 3376: 				break;
 3377: 			
 3378: 			    case RF:
 3379: 				if (decodenetnum(value, &hval)) {
 3380: 					if (ISREFCLOCKADR(&hval))
 3381:     						output(fp, name,
 3382: 						    refnumtoa(&hval));
 3383: 					else
 3384: 				    		output(fp, name, stoa(&hval));
 3385: 				} else if ((int)strlen(value) <= 4)
 3386: 				    output(fp, name, value);
 3387: 				else
 3388: 				    output_raw = '?';
 3389: 				break;
 3390: 
 3391: 			    case LP:
 3392: 				if (!decodeuint(value, &uval) || uval > 3)
 3393: 				    output_raw = '?';
 3394: 				else {
 3395: 					char b[3];
 3396: 					b[0] = b[1] = '0';
 3397: 					if (uval & 0x2)
 3398: 					    b[0] = '1';
 3399: 					if (uval & 0x1)
 3400: 					    b[1] = '1';
 3401: 					b[2] = '\0';
 3402: 					output(fp, name, b);
 3403: 				}
 3404: 				break;
 3405: 
 3406: 			    case OC:
 3407: 				if (!decodeuint(value, &uval))
 3408: 				    output_raw = '?';
 3409: 				else {
 3410: 					char b[12];
 3411: 
 3412: 					(void) snprintf(b, sizeof b, "%03lo", uval);
 3413: 					output(fp, name, b);
 3414: 				}
 3415: 				break;
 3416: 			
 3417: 			    case MD:
 3418: 				if (!decodeuint(value, &uval))
 3419: 				    output_raw = '?';
 3420: 				else
 3421: 				    output(fp, name, uinttoa(uval));
 3422: 				break;
 3423: 			
 3424: 			    case AR:
 3425: 				if (!decodearr(value, &narr, lfparr))
 3426: 				    output_raw = '?';
 3427: 				else
 3428: 				    outputarr(fp, name, narr, lfparr);
 3429: 				break;
 3430: 
 3431: 			    case FX:
 3432: 				if (!decodeuint(value, &uval))
 3433: 				    output_raw = '?';
 3434: 				else
 3435: 				    output(fp, name, tstflags(uval));
 3436: 				break;
 3437: 			
 3438: 			    default:
 3439: 				(void) fprintf(stderr,
 3440: 				    "Internal error in cookedprint, %s=%s, fmt %d\n",
 3441: 				    name, value, fmt);
 3442: 				break;
 3443: 			}
 3444: 
 3445: 		}
 3446: 		if (output_raw != 0) {
 3447: 			char bn[401];
 3448: 			char bv[401];
 3449: 			int len;
 3450: 
 3451: 			atoascii(name, MAXVARLEN, bn, sizeof(bn));
 3452: 			atoascii(value, MAXVARLEN, bv, sizeof(bv));
 3453: 			if (output_raw != '*') {
 3454: 				len = strlen(bv);
 3455: 				bv[len] = output_raw;
 3456: 				bv[len+1] = '\0';
 3457: 			}
 3458: 			output(fp, bn, bv);
 3459: 		}
 3460: 	}
 3461: 	endoutput(fp);
 3462: }
 3463: 
 3464: 
 3465: /*
 3466:  * sortassoc - sort associations in the cache into ascending order
 3467:  */
 3468: void
 3469: sortassoc(void)
 3470: {
 3471: 	if (numassoc > 1)
 3472: 		qsort((void *)assoc_cache, (size_t)numassoc,
 3473: 		    sizeof(assoc_cache[0]), assoccmp);
 3474: }
 3475: 
 3476: 
 3477: /*
 3478:  * assoccmp - compare two associations
 3479:  */
 3480: static int
 3481: assoccmp(
 3482: 	const void *t1,
 3483: 	const void *t2
 3484: 	)
 3485: {
 3486: 	const struct association *ass1 = t1;
 3487: 	const struct association *ass2 = t2;
 3488: 
 3489: 	if (ass1->assid < ass2->assid)
 3490: 		return -1;
 3491: 	if (ass1->assid > ass2->assid)
 3492: 		return 1;
 3493: 	return 0;
 3494: }
 3495: 
 3496: 
 3497: /*
 3498:  * ntpq_custom_opt_handler - autoopts handler for -c and -p
 3499:  *
 3500:  * By default, autoopts loses the relative order of -c and -p options
 3501:  * on the command line.  This routine replaces the default handler for
 3502:  * those routines and builds a list of commands to execute preserving
 3503:  * the order.
 3504:  */
 3505: void
 3506: ntpq_custom_opt_handler(
 3507: 	tOptions *pOptions,
 3508: 	tOptDesc *pOptDesc
 3509: 	)
 3510: {
 3511: 	switch (pOptDesc->optValue) {
 3512: 	
 3513: 	default:
 3514: 		fprintf(stderr, 
 3515: 			"ntpq_custom_opt_handler unexpected option '%c' (%d)\n",
 3516: 			pOptDesc->optValue, pOptDesc->optValue);
 3517: 		exit(-1);
 3518: 
 3519: 	case 'c':
 3520: 		ADDCMD(pOptDesc->pzLastArg);
 3521: 		break;
 3522: 
 3523: 	case 'p':
 3524: 		ADDCMD("peers");
 3525: 		break;
 3526: 	}
 3527: }

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