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