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