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