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