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