4 * ntpq - query an NTP server using mode 6 commands
12 #include <sys/types.h>
16 #include "ntp_unixtime.h"
17 #include "ntp_calendar.h"
19 #include "ntp_select.h"
20 #include "ntp_stdlib.h"
21 #include "ntp_assert.h"
22 #include "ntp_lineedit.h"
23 #include "ntp_debug.h"
25 #include "isc/result.h"
26 #include <ssl_applink.c>
28 #include "ntpq-opts.h"
33 #endif /* SYS_WINNT */
36 /* vxWorks needs mode flag -casey*/
37 # define open(name, flags) open(name, flags, 0777)
38 # define SERVER_PORT_NUM 123
41 /* we use COMMAND as an autogen keyword */
47 * Because we potentially understand a lot of commands we will run
48 * interactive if connected to a terminal.
50 int interactive
= 0; /* set to 1 when we should prompt */
51 const char *prompt
= "ntpq> "; /* prompt to ask him about */
54 * use old readvars behavior? --old-rv processing in ntpq resets
55 * this value based on the presence or absence of --old-rv. It is
56 * initialized to 1 here to maintain backward compatibility with
57 * libntpq clients such as ntpsnmpd, which are free to reset it as
66 s_char sys_precision
; /* local clock precision (log2 s) */
69 * Keyid used for authenticated requests. Obtained on the fly.
71 u_long info_auth_keyid
= 0;
73 static int info_auth_keytype
= NID_md5
; /* MD5 */
74 static size_t info_auth_hashlen
= 16; /* MD5 */
75 u_long current_time
; /* needed by authkeys; not used */
78 * Flag which indicates we should always send authenticated requests
83 * Flag which indicates raw mode output.
88 * Packet version number we use
90 u_char pktversion
= NTP_OLDVERSION
+ 1;
93 * Don't jump if no set jmp.
95 volatile int jump
= 0;
101 #define TS 1 /* time stamp */
102 #define FL 2 /* l_fp type value */
103 #define FU 3 /* u_fp type value */
104 #define FS 4 /* s_fp type value */
105 #define UI 5 /* unsigned integer value */
106 #define SI 6 /* signed integer value */
107 #define HA 7 /* host address */
108 #define NA 8 /* network address */
109 #define ST 9 /* string value */
110 #define RF 10 /* refid (sometimes string, sometimes not) */
111 #define LP 11 /* leap (print in binary) */
112 #define OC 12 /* integer, print in octal */
113 #define MD 13 /* mode */
114 #define AR 14 /* array of times */
115 #define FX 15 /* test flags */
116 #define EOV 255 /* end of table */
120 * System variable values. The array can be indexed by
121 * the variable index to find the textual name.
123 struct ctl_var sys_var
[] = {
124 { 0, PADDING
, "" }, /* 0 */
125 { CS_LEAP
, LP
, "leap" }, /* 1 */
126 { CS_STRATUM
, UI
, "stratum" }, /* 2 */
127 { CS_PRECISION
, SI
, "precision" }, /* 3 */
128 { CS_ROOTDELAY
, FS
, "rootdelay" }, /* 4 */
129 { CS_ROOTDISPERSION
, FU
, "rootdispersion" }, /* 5 */
130 { CS_REFID
, RF
, "refid" }, /* 6 */
131 { CS_REFTIME
, TS
, "reftime" }, /* 7 */
132 { CS_POLL
, UI
, "poll" }, /* 8 */
133 { CS_PEERID
, UI
, "peer" }, /* 9 */
134 { CS_OFFSET
, FL
, "offset" }, /* 10 */
135 { CS_DRIFT
, FS
, "frequency" }, /* 11 */
136 { CS_JITTER
, FU
, "jitter" }, /* 12 */
137 { CS_CLOCK
, TS
, "clock" }, /* 13 */
138 { CS_PROCESSOR
, ST
, "processor" }, /* 14 */
139 { CS_SYSTEM
, ST
, "system" }, /* 15 */
140 { CS_VERSION
, ST
, "version" }, /* 16 */
141 { CS_STABIL
, FS
, "stability" }, /* 17 */
142 { CS_VARLIST
, ST
, "sys_var_list" }, /* 18 */
150 struct ctl_var peer_var
[] = {
151 { 0, PADDING
, "" }, /* 0 */
152 { CP_CONFIG
, UI
, "config" }, /* 1 */
153 { CP_AUTHENABLE
, UI
, "authenable" }, /* 2 */
154 { CP_AUTHENTIC
, UI
, "authentic" }, /* 3 */
155 { CP_SRCADR
, HA
, "srcadr" }, /* 4 */
156 { CP_SRCPORT
, UI
, "srcport" }, /* 5 */
157 { CP_DSTADR
, NA
, "dstadr" }, /* 6 */
158 { CP_DSTPORT
, UI
, "dstport" }, /* 7 */
159 { CP_LEAP
, LP
, "leap" }, /* 8 */
160 { CP_HMODE
, MD
, "hmode" }, /* 9 */
161 { CP_STRATUM
, UI
, "stratum" }, /* 10 */
162 { CP_PPOLL
, UI
, "ppoll" }, /* 11 */
163 { CP_HPOLL
, UI
, "hpoll" }, /* 12 */
164 { CP_PRECISION
, SI
, "precision" }, /* 13 */
165 { CP_ROOTDELAY
, FS
, "rootdelay" }, /* 14 */
166 { CP_ROOTDISPERSION
, FU
, "rootdisp" }, /* 15 */
167 { CP_REFID
, RF
, "refid" }, /* 16 */
168 { CP_REFTIME
, TS
, "reftime" }, /* 17 */
169 { CP_ORG
, TS
, "org" }, /* 18 */
170 { CP_REC
, TS
, "rec" }, /* 19 */
171 { CP_XMT
, TS
, "xmt" }, /* 20 */
172 { CP_REACH
, OC
, "reach" }, /* 21 */
173 { CP_UNREACH
, UI
, "unreach" }, /* 22 */
174 { CP_TIMER
, UI
, "timer" }, /* 23 */
175 { CP_DELAY
, FS
, "delay" }, /* 24 */
176 { CP_OFFSET
, FL
, "offset" }, /* 25 */
177 { CP_JITTER
, FU
, "jitter" }, /* 26 */
178 { CP_DISPERSION
, FU
, "dispersion" }, /* 27 */
179 { CP_KEYID
, UI
, "keyid" }, /* 28 */
180 { CP_FILTDELAY
, AR
, "filtdelay" }, /* 29 */
181 { CP_FILTOFFSET
, AR
, "filtoffset" }, /* 30 */
182 { CP_PMODE
, ST
, "pmode" }, /* 31 */
183 { CP_RECEIVED
, UI
, "received" }, /* 32 */
184 { CP_SENT
, UI
, "sent" }, /* 33 */
185 { CP_FILTERROR
, AR
, "filtdisp" }, /* 34 */
186 { CP_FLASH
, FX
, "flash" }, /* 35 */
187 { CP_TTL
, UI
, "ttl" }, /* 36 */
189 * These are duplicate entries so that we can
190 * process deviant version of the ntp protocol.
192 { CP_SRCADR
, HA
, "peeraddr" }, /* 4 */
193 { CP_SRCPORT
, UI
, "peerport" }, /* 5 */
194 { CP_PPOLL
, UI
, "peerpoll" }, /* 11 */
195 { CP_HPOLL
, UI
, "hostpoll" }, /* 12 */
196 { CP_FILTERROR
, AR
, "filterror" }, /* 34 */
202 * Clock variable list
204 struct ctl_var clock_var
[] = {
205 { 0, PADDING
, "" }, /* 0 */
206 { CC_TYPE
, UI
, "type" }, /* 1 */
207 { CC_TIMECODE
, ST
, "timecode" }, /* 2 */
208 { CC_POLL
, UI
, "poll" }, /* 3 */
209 { CC_NOREPLY
, UI
, "noreply" }, /* 4 */
210 { CC_BADFORMAT
, UI
, "badformat" }, /* 5 */
211 { CC_BADDATA
, UI
, "baddata" }, /* 6 */
212 { CC_FUDGETIME1
, FL
, "fudgetime1" }, /* 7 */
213 { CC_FUDGETIME2
, FL
, "fudgetime2" }, /* 8 */
214 { CC_FUDGEVAL1
, UI
, "stratum" }, /* 9 */
215 { CC_FUDGEVAL2
, RF
, "refid" }, /* 10 */
216 { CC_FLAGS
, UI
, "flags" }, /* 11 */
217 { CC_DEVICE
, ST
, "device" }, /* 12 */
225 static const char *tstflagnames
[] = {
226 "pkt_dup", /* TEST1 */
227 "pkt_bogus", /* TEST2 */
228 "pkt_unsync", /* TEST3 */
229 "pkt_denied", /* TEST4 */
230 "pkt_auth", /* TEST5 */
231 "pkt_stratum", /* TEST6 */
232 "pkt_header", /* TEST7 */
233 "pkt_autokey", /* TEST8 */
234 "pkt_crypto", /* TEST9 */
235 "peer_stratum", /* TEST10 */
236 "peer_dist", /* TEST11 */
237 "peer_loop", /* TEST12 */
238 "peer_unreach" /* TEST13 */
243 * Use getpassphrase() if configure.ac detected it, as Suns that
244 * have it truncate the password in getpass() to 8 characters.
246 #ifdef HAVE_GETPASSPHRASE
247 # define getpass(str) getpassphrase(str)
250 int ntpqmain (int, char **);
252 * Built in command handler declarations
254 static int openhost (const char *);
256 static int sendpkt (void *, size_t);
257 static int getresponse (int, int, u_short
*, int *, char **, int);
258 static int sendrequest (int, int, int, int, char *);
259 static char * tstflags (u_long
);
261 static void getcmds (void);
263 static RETSIGTYPE
abortcmd (int);
264 #endif /* SYS_WINNT */
265 static void docmd (const char *);
266 static void tokenize (const char *, char **, int *);
267 static int getarg (char *, int, arg_v
*);
268 #endif /* BUILD_AS_LIB */
269 static int findcmd (char *, struct xcmd
*, struct xcmd
*, struct xcmd
**);
270 static int rtdatetolfp (char *, l_fp
*);
271 static int decodearr (char *, int *, l_fp
*);
272 static void help (struct parse
*, FILE *);
273 #ifdef QSORT_USES_VOID_P
274 static int helpsort (const void *, const void *);
276 static int helpsort (char **, char **);
278 static void printusage (struct xcmd
*, FILE *);
279 static void timeout (struct parse
*, FILE *);
280 static void auth_delay (struct parse
*, FILE *);
281 static void host (struct parse
*, FILE *);
282 static void ntp_poll (struct parse
*, FILE *);
283 static void keyid (struct parse
*, FILE *);
284 static void keytype (struct parse
*, FILE *);
285 static void passwd (struct parse
*, FILE *);
286 static void hostnames (struct parse
*, FILE *);
287 static void setdebug (struct parse
*, FILE *);
288 static void quit (struct parse
*, FILE *);
289 static void version (struct parse
*, FILE *);
290 static void raw (struct parse
*, FILE *);
291 static void cooked (struct parse
*, FILE *);
292 static void authenticate (struct parse
*, FILE *);
293 static void ntpversion (struct parse
*, FILE *);
294 static void warning (const char *, const char *, const char *);
295 static void error (const char *, const char *, const char *);
296 static u_long
getkeyid (const char *);
297 static void atoascii (const char *, size_t, char *, size_t);
298 static void makeascii (int, char *, FILE *);
299 static void cookedprint (int, int, char *, int, int, FILE *);
300 static void rawprint (int, int, char *, int, int, FILE *);
301 static void startoutput (void);
302 static void output (FILE *, char *, char *);
303 static void endoutput (FILE *);
304 static void outputarr (FILE *, char *, int, l_fp
*);
305 #ifdef QSORT_USES_VOID_P
306 static int assoccmp (const void *, const void *);
308 static int assoccmp (struct association
*, struct association
*);
309 #endif /* sgi || bsdi */
310 void ntpq_custom_opt_handler (tOptions
*, tOptDesc
*);
314 * Built-in commands we understand
316 struct xcmd builtins
[] = {
317 { "?", help
, { OPT
|NTP_STR
, NO
, NO
, NO
},
318 { "command", "", "", "" },
319 "tell the use and syntax of commands" },
320 { "help", help
, { OPT
|NTP_STR
, NO
, NO
, NO
},
321 { "command", "", "", "" },
322 "tell the use and syntax of commands" },
323 { "timeout", timeout
, { OPT
|NTP_UINT
, NO
, NO
, NO
},
324 { "msec", "", "", "" },
325 "set the primary receive time out" },
326 { "delay", auth_delay
, { OPT
|NTP_INT
, NO
, NO
, NO
},
327 { "msec", "", "", "" },
328 "set the delay added to encryption time stamps" },
329 { "host", host
, { OPT
|NTP_STR
, OPT
|NTP_STR
, NO
, NO
},
330 { "-4|-6", "hostname", "", "" },
331 "specify the host whose NTP server we talk to" },
332 { "poll", ntp_poll
, { OPT
|NTP_UINT
, OPT
|NTP_STR
, NO
, NO
},
333 { "n", "verbose", "", "" },
334 "poll an NTP server in client mode `n' times" },
335 { "passwd", passwd
, { NO
, NO
, NO
, NO
},
337 "specify a password to use for authenticated requests"},
338 { "hostnames", hostnames
, { OPT
|NTP_STR
, NO
, NO
, NO
},
339 { "yes|no", "", "", "" },
340 "specify whether hostnames or net numbers are printed"},
341 { "debug", setdebug
, { OPT
|NTP_STR
, NO
, NO
, NO
},
342 { "no|more|less", "", "", "" },
343 "set/change debugging level" },
344 { "quit", quit
, { NO
, NO
, NO
, NO
},
347 { "exit", quit
, { NO
, NO
, NO
, NO
},
350 { "keyid", keyid
, { OPT
|NTP_UINT
, NO
, NO
, NO
},
351 { "key#", "", "", "" },
352 "set keyid to use for authenticated requests" },
353 { "version", version
, { NO
, NO
, NO
, NO
},
355 "print version number" },
356 { "raw", raw
, { NO
, NO
, NO
, NO
},
358 "do raw mode variable output" },
359 { "cooked", cooked
, { NO
, NO
, NO
, NO
},
361 "do cooked mode variable output" },
362 { "authenticate", authenticate
, { OPT
|NTP_STR
, NO
, NO
, NO
},
363 { "yes|no", "", "", "" },
364 "always authenticate requests to this server" },
365 { "ntpversion", ntpversion
, { OPT
|NTP_UINT
, NO
, NO
, NO
},
366 { "version number", "", "", "" },
367 "set the NTP version number to use for requests" },
368 { "keytype", keytype
, { OPT
|NTP_STR
, NO
, NO
, NO
},
369 { "key type (md5|des)", "", "", "" },
370 "set key type to use for authenticated requests (des|md5)" },
371 { 0, 0, { NO
, NO
, NO
, NO
},
372 { "", "", "", "" }, "" }
377 * Default values we use.
379 #define DEFHOST "localhost" /* default host name */
380 #define DEFTIMEOUT (5) /* 5 second time out */
381 #define DEFSTIMEOUT (2) /* 2 second time out after first */
382 #define DEFDELAY 0x51EB852 /* 20 milliseconds, l_fp fraction */
383 #define LENHOSTNAME 256 /* host name is 256 characters long */
384 #define MAXCMDS 100 /* maximum commands on cmd line */
385 #define MAXHOSTS 200 /* maximum hosts on cmd line */
386 #define MAXLINE 512 /* maximum line length */
387 #define MAXTOKENS (1+MAXARGS+2) /* maximum number of usable tokens */
388 #define MAXVARLEN 256 /* maximum length of a variable name */
389 #define MAXVALLEN 400 /* maximum length of a variable value */
390 #define MAXOUTLINE 72 /* maximum length of an output line */
391 #define SCREENWIDTH 76 /* nominal screen width in columns */
394 * Some variables used and manipulated locally
396 struct sock_timeval tvout
= { DEFTIMEOUT
, 0 }; /* time out for reads */
397 struct sock_timeval tvsout
= { DEFSTIMEOUT
, 0 };/* secondary time out */
398 l_fp delay_time
; /* delay time */
399 char currenthost
[LENHOSTNAME
]; /* current host name */
400 struct sockaddr_in hostaddr
= { 0 }; /* host address */
401 int showhostnames
= 1; /* show host names by default */
403 int ai_fam_templ
; /* address family */
404 int ai_fam_default
; /* default address family */
405 SOCKET sockfd
; /* fd socket is opened on */
406 int havehost
= 0; /* set to 1 when host open */
408 struct servent
*server_entry
= NULL
; /* server entry for ntp */
412 * Sequence number used for requests. It is incremented before
418 * Holds data returned from queries. Declare buffer long to be sure of
421 #define MAXFRAGS 24 /* maximum number of fragments */
422 #define DATASIZE (MAXFRAGS*480) /* maximum amount of data */
423 long pktdata
[DATASIZE
/sizeof(long)];
426 * Holds association data for use with the &n operator.
428 struct association assoc_cache
[MAXASSOC
];
429 int numassoc
= 0; /* number of cached associations */
432 * For commands typed on the command line (with the -c option)
435 const char *ccmds
[MAXCMDS
];
436 #define ADDCMD(cp) if (numcmds < MAXCMDS) ccmds[numcmds++] = (cp)
439 * When multiple hosts are specified.
442 const char *chosts
[MAXHOSTS
];
443 #define ADDHOST(cp) if (numhosts < MAXHOSTS) chosts[numhosts++] = (cp)
446 * Error codes for internal use
448 #define ERR_UNSPEC 256
449 #define ERR_INCOMPLETE 257
450 #define ERR_TIMEOUT 258
451 #define ERR_TOOMUCH 259
454 * Macro definitions we use
456 #define ISSPACE(c) ((c) == ' ' || (c) == '\t')
457 #define ISEOL(c) ((c) == '\n' || (c) == '\r' || (c) == '\0')
458 #define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0)
461 * Jump buffer for longjumping back to the command level
463 jmp_buf interrupt_buf
;
466 * Points at file being currently printed into
468 FILE *current_output
;
471 * Command table imported from ntpdc_ops.c
473 extern struct xcmd opcmds
[];
478 #ifdef NO_MAIN_ALLOWED
480 CALL(ntpq
,"ntpq",ntpqmain
);
482 void clear_globals(void)
484 extern int ntp_optind
;
485 showhostnames
= 0; /* don'tshow host names by default */
487 server_entry
= NULL
; /* server entry for ntp */
488 havehost
= 0; /* set to 1 when host open */
489 numassoc
= 0; /* number of cached associations */
493 #endif /* !BUILD_AS_LIB */
494 #endif /* NO_MAIN_ALLOWED */
497 * main - parse arguments and handle options
499 #ifndef NO_MAIN_ALLOWED
506 return ntpqmain(argc
, argv
);
517 extern int ntp_optind
;
521 taskPrioritySet(taskIdSelf(), 100 );
525 delay_time
.l_uf
= DEFDELAY
;
527 init_lib(); /* sets up ipv4_works, ipv6_works */
530 /* Check to see if we have IPv6. Otherwise default to IPv4 */
532 ai_fam_default
= AF_INET
;
537 int optct
= optionProcess(&ntpqOptions
, argc
, argv
);
543 * Process options other than -c and -p, which are specially
544 * handled by ntpq_custom_opt_handler().
547 debug
= DESC(DEBUG_LEVEL
).optOccCt
;
550 ai_fam_templ
= AF_INET
;
551 else if (HAVE_OPT(IPV6
))
552 ai_fam_templ
= AF_INET6
;
554 ai_fam_templ
= ai_fam_default
;
556 if (HAVE_OPT(INTERACTIVE
))
559 if (HAVE_OPT(NUMERIC
))
562 old_rv
= HAVE_OPT(OLD_RV
);
565 while ((c
= ntp_getopt(argc
, argv
, "46c:dinp")) != EOF
)
568 ai_fam_templ
= AF_INET
;
571 ai_fam_templ
= AF_INET6
;
593 (void) fprintf(stderr
,
594 "usage: %s [-46dinp] [-c cmd] host ...\n",
599 NTP_INSIST(ntp_optind
<= argc
);
600 if (ntp_optind
== argc
) {
603 for (; ntp_optind
< argc
; ntp_optind
++)
604 ADDHOST(argv
[ntp_optind
]);
607 if (numcmds
== 0 && interactive
== 0
608 && isatty(fileno(stdin
)) && isatty(fileno(stderr
))) {
612 #ifndef SYS_WINNT /* Under NT cannot handle SIGINT, WIN32 spawns a handler */
614 (void) signal_no_reset(SIGINT
, abortcmd
);
615 #endif /* SYS_WINNT */
618 (void) openhost(chosts
[0]);
624 for (ihost
= 0; ihost
< numhosts
; ihost
++) {
625 if (openhost(chosts
[ihost
]))
626 for (icmd
= 0; icmd
< numcmds
; icmd
++)
632 #endif /* SYS_WINNT */
635 #endif /* !BUILD_AS_LIB */
638 * openhost - open a socket to a host
645 char temphost
[LENHOSTNAME
];
647 struct addrinfo hints
, *ai
= NULL
;
648 register const char *cp
;
649 char name
[LENHOSTNAME
];
653 * We need to get by the [] if they were entered
660 for (i
= 0; *cp
&& *cp
!= ']'; cp
++, i
++)
671 * First try to resolve it as an ip address and if that fails,
672 * do a fullblown (dns) lookup. That way we only use the dns
673 * when it is needed and work around some implementations that
674 * will return an "IPv4-mapped IPv6 address" address if you
675 * give it an IPv4 address to lookup.
677 strcpy(service
, "ntp");
678 memset((char *)&hints
, 0, sizeof(struct addrinfo
));
679 hints
.ai_family
= ai_fam_templ
;
680 hints
.ai_protocol
= IPPROTO_UDP
;
681 hints
.ai_socktype
= SOCK_DGRAM
;
682 hints
.ai_flags
= AI_NUMERICHOST
;
684 a_info
= getaddrinfo(hname
, service
, &hints
, &ai
);
685 if (a_info
== EAI_NONAME
687 || a_info
== EAI_NODATA
690 hints
.ai_flags
= AI_CANONNAME
;
692 hints
.ai_flags
|= AI_ADDRCONFIG
;
694 a_info
= getaddrinfo(hname
, service
, &hints
, &ai
);
697 /* Some older implementations don't like AI_ADDRCONFIG. */
698 if (a_info
== EAI_BADFLAGS
) {
699 hints
.ai_flags
= AI_CANONNAME
;
700 a_info
= getaddrinfo(hname
, service
, &hints
, &ai
);
704 (void) fprintf(stderr
, "%s\n", gai_strerror(a_info
));
708 if (ai
->ai_canonname
== NULL
) {
710 stoa((sockaddr_u
*)ai
->ai_addr
),
714 strncpy(temphost
, ai
->ai_canonname
, LENHOSTNAME
);
716 temphost
[LENHOSTNAME
-1] = '\0';
719 printf("Opening host %s\n", temphost
);
723 printf("Closing old host %s\n", currenthost
);
724 (void) closesocket(sockfd
);
727 (void) strcpy(currenthost
, temphost
);
729 /* port maps to the same location in both families */
730 s_port
= ((struct sockaddr_in6
*)ai
->ai_addr
)->sin6_port
;
732 ((struct sockaddr_in6
*)&hostaddr
)->sin6_port
= htons(SERVER_PORT_NUM
);
733 if (ai
->ai_family
== AF_INET
)
734 *(struct sockaddr_in
*)&hostaddr
=
735 *((struct sockaddr_in
*)ai
->ai_addr
);
737 *(struct sockaddr_in6
*)&hostaddr
=
738 *((struct sockaddr_in6
*)ai
->ai_addr
);
739 #endif /* SYS_VXWORKS */
743 int optionValue
= SO_SYNCHRONOUS_NONALERT
;
746 err
= setsockopt(INVALID_SOCKET
, SOL_SOCKET
, SO_OPENTYPE
,
747 (char *)&optionValue
, sizeof(optionValue
));
749 err
= WSAGetLastError();
751 "setsockopt(SO_SYNCHRONOUS_NONALERT) "
752 "error: %s\n", strerror(err
));
756 #endif /* SYS_WINNT */
758 sockfd
= socket(ai
->ai_family
, SOCK_DGRAM
, 0);
759 if (sockfd
== INVALID_SOCKET
) {
760 error("socket", "", "");
764 #ifdef NEED_RCVBUF_SLOP
766 { int rbufsize
= DATASIZE
+ 2048; /* 2K for slop */
767 if (setsockopt(sockfd
, SOL_SOCKET
, SO_RCVBUF
,
768 &rbufsize
, sizeof(int)) == -1)
769 error("setsockopt", "", "");
775 if (connect(sockfd
, (struct sockaddr
*)&hostaddr
,
776 sizeof(hostaddr
)) == -1)
778 if (connect(sockfd
, (struct sockaddr
*)ai
->ai_addr
,
779 ai
->ai_addrlen
) == -1)
780 #endif /* SYS_VXWORKS */
781 error("connect", "", "");
789 /* XXX ELIMINATE sendpkt similar in ntpq.c, ntpdc.c, ntp_io.c, ntptrace.c */
791 * sendpkt - send a packet to the remote host
800 printf("Sending %u octets\n", xdatalen
);
802 if (send(sockfd
, xdata
, (size_t)xdatalen
, 0) == -1) {
803 warning("write to %s failed", currenthost
, "");
811 printf("Packet data:\n");
812 while (xdatalen
-- > 0) {
817 printf(" %02x", *cdata
++ & 0xff);
827 * getresponse - get a (series of) response packet(s) and return the data
839 struct ntp_control rpkt
;
840 struct sock_timeval tvo
;
841 u_short offsets
[MAXFRAGS
+1];
842 u_short counts
[MAXFRAGS
+1];
852 * This is pretty tricky. We may get between 1 and MAXFRAG packets
853 * back in response to the request. We peel the data out of
854 * each packet and collect it in one long block. When the last
855 * packet in the sequence is received we'll know how much data we
856 * should have had. Note we use one long time out, should reconsider.
861 *rdata
= (char *)pktdata
;
869 * Loop until we have an error or a complete response. Nearly all
870 * aths to loop again use continue.
879 FD_SET(sockfd
, &fds
);
880 n
= select(sockfd
+1, &fds
, (fd_set
*)0, (fd_set
*)0, &tvo
);
883 warning("select fails", "", "");
888 * Timed out. Return what we have
892 (void) fprintf(stderr
,
893 "%s: timed out, nothing received\n",
898 (void) fprintf(stderr
,
899 "%s: timed out with incomplete data\n",
902 printf("Received fragments:\n");
903 for (n
= 0; n
< numfrags
; n
++)
904 printf("%4d %d\n", offsets
[n
],
907 printf("last fragment received\n");
909 printf("last fragment not received\n");
911 return ERR_INCOMPLETE
;
915 n
= recv(sockfd
, (char *)&rpkt
, sizeof(rpkt
), 0);
917 warning("read", "", "");
922 int len
= n
, first
= 8;
923 char *data
= (char *)&rpkt
;
925 printf("Packet data:\n");
931 printf(" %02x", *data
++ & 0xff);
937 * Check for format errors. Bug proofing.
939 if (n
< CTL_HEADER_LEN
) {
941 printf("Short (%d byte) packet received\n", n
);
944 if (PKT_VERSION(rpkt
.li_vn_mode
) > NTP_VERSION
945 || PKT_VERSION(rpkt
.li_vn_mode
) < NTP_OLDVERSION
) {
947 printf("Packet received with version %d\n",
948 PKT_VERSION(rpkt
.li_vn_mode
));
951 if (PKT_MODE(rpkt
.li_vn_mode
) != MODE_CONTROL
) {
953 printf("Packet received with mode %d\n",
954 PKT_MODE(rpkt
.li_vn_mode
));
957 if (!CTL_ISRESPONSE(rpkt
.r_m_e_op
)) {
959 printf("Received request packet, wanted response\n");
964 * Check opcode and sequence number for a match.
965 * Could be old data getting to us.
967 if (ntohs(rpkt
.sequence
) != sequence
) {
970 "Received sequnce number %d, wanted %d\n",
971 ntohs(rpkt
.sequence
), sequence
);
974 if (CTL_OP(rpkt
.r_m_e_op
) != opcode
) {
977 "Received opcode %d, wanted %d (sequence number okay)\n",
978 CTL_OP(rpkt
.r_m_e_op
), opcode
);
983 * Check the error code. If non-zero, return it.
985 if (CTL_ISERROR(rpkt
.r_m_e_op
)) {
988 errcode
= (ntohs(rpkt
.status
) >> 8) & 0xff;
989 if (debug
&& CTL_ISMORE(rpkt
.r_m_e_op
)) {
990 printf("Error code %d received on not-final packet\n",
993 if (errcode
== CERR_UNSPEC
)
999 * Check the association ID to make sure it matches what
1002 if (ntohs(rpkt
.associd
) != associd
) {
1004 printf("Association ID %d doesn't match expected %d\n",
1005 ntohs(rpkt
.associd
), associd
);
1007 * Hack for silly fuzzballs which, at the time of writing,
1008 * return an assID of sys.peer when queried for system variables.
1016 * Collect offset and count. Make sure they make sense.
1018 offset
= ntohs(rpkt
.offset
);
1019 count
= ntohs(rpkt
.count
);
1022 * validate received payload size is padded to next 32-bit
1023 * boundary and no smaller than claimed by rpkt.count
1027 printf("Response packet not padded, "
1032 shouldbesize
= (CTL_HEADER_LEN
+ count
+ 3) & ~3;
1034 if (n
< shouldbesize
) {
1035 printf("Response packet claims %u octets "
1036 "payload, above %d received\n",
1040 return ERR_INCOMPLETE
;
1043 if (debug
>= 3 && shouldbesize
> n
) {
1049 * Usually we ignore authentication, but for debugging purposes
1052 /* round to 8 octet boundary */
1053 shouldbesize
= (shouldbesize
+ 7) & ~7;
1055 maclen
= n
- shouldbesize
;
1056 if (maclen
>= MIN_MAC_LEN
) {
1058 "Packet shows signs of authentication (total %d, data %d, mac %d)\n",
1059 n
, shouldbesize
, maclen
);
1060 lpkt
= (u_int32
*)&rpkt
;
1061 printf("%08lx %08lx %08lx %08lx %08lx %08lx\n",
1062 (u_long
)ntohl(lpkt
[(n
- maclen
)/sizeof(u_int32
) - 3]),
1063 (u_long
)ntohl(lpkt
[(n
- maclen
)/sizeof(u_int32
) - 2]),
1064 (u_long
)ntohl(lpkt
[(n
- maclen
)/sizeof(u_int32
) - 1]),
1065 (u_long
)ntohl(lpkt
[(n
- maclen
)/sizeof(u_int32
)]),
1066 (u_long
)ntohl(lpkt
[(n
- maclen
)/sizeof(u_int32
) + 1]),
1067 (u_long
)ntohl(lpkt
[(n
- maclen
)/sizeof(u_int32
) + 2]));
1068 key
= ntohl(lpkt
[(n
- maclen
) / sizeof(u_int32
)]);
1069 printf("Authenticated with keyid %lu\n", (u_long
)key
);
1070 if (key
!= 0 && key
!= info_auth_keyid
) {
1071 printf("We don't know that key\n");
1073 if (authdecrypt(key
, (u_int32
*)&rpkt
,
1074 n
- maclen
, maclen
)) {
1075 printf("Auth okay!\n");
1077 printf("Auth failed!\n");
1084 printf("Got packet, size = %d\n", n
);
1085 if ((int)count
> (n
- CTL_HEADER_LEN
)) {
1087 printf("Received count of %d octets, "
1088 "data in packet is %d\n",
1089 count
, n
-CTL_HEADER_LEN
);
1092 if (count
== 0 && CTL_ISMORE(rpkt
.r_m_e_op
)) {
1094 printf("Received count of 0 in non-final fragment\n");
1097 if (offset
+ count
> sizeof(pktdata
)) {
1099 printf("Offset %d, count %d, too big for buffer\n",
1103 if (seenlastfrag
&& !CTL_ISMORE(rpkt
.r_m_e_op
)) {
1105 printf("Received second last fragment packet\n");
1110 * So far, so good. Record this fragment, making sure it doesn't
1114 printf("Packet okay\n");;
1116 if (numfrags
> (MAXFRAGS
- 1)) {
1118 printf("Number of fragments exceeds maximum\n");
1123 * Find the position for the fragment relative to any
1124 * previously received.
1127 n
< numfrags
&& offsets
[n
] < offset
;
1132 if (n
< numfrags
&& offset
== offsets
[n
]) {
1134 printf("duplicate %u octets at %u "
1135 "ignored, prior %u at %u\n",
1144 if (n
> 0 && (offsets
[n
-1] + counts
[n
-1]) > offset
) {
1146 printf("received frag at %u overlaps "
1147 "with %u octet frag at %u\n",
1155 if (n
< numfrags
&& (offset
+ count
) > offsets
[n
]) {
1157 printf("received %u octet frag at %u "
1158 "overlaps with frag at %u\n",
1169 for (i
= numfrags
; i
> n
; i
--) {
1170 offsets
[i
] = offsets
[i
-1];
1171 counts
[i
] = counts
[i
-1];
1174 offsets
[n
] = offset
;
1179 * Got that stuffed in right. Figure out if this was the last.
1180 * Record status info out of the last packet.
1182 if (!CTL_ISMORE(rpkt
.r_m_e_op
)) {
1185 *rstatus
= ntohs(rpkt
.status
);
1189 * Copy the data into the data buffer.
1191 memmove((char *)pktdata
+ offset
, (char *)rpkt
.data
, count
);
1194 * If we've seen the last fragment, look for holes in the sequence.
1195 * If there aren't any, we're done.
1197 if (seenlastfrag
&& offsets
[0] == 0) {
1198 for (n
= 1; n
< numfrags
; n
++) {
1199 if (offsets
[n
-1] + counts
[n
-1] != offsets
[n
])
1202 if (n
== numfrags
) {
1203 *rsize
= offsets
[numfrags
-1] + counts
[numfrags
-1];
1207 } /* giant for (;;) collecting response packets */
1208 } /* getresponse() */
1212 * sendrequest - format and send a request packet
1223 struct ntp_control qpkt
;
1226 char pass_prompt
[32];
1231 * Check to make sure the data will fit in one packet
1233 if (qsize
> CTL_MAX_DATA_LEN
) {
1235 "***Internal error! qsize (%d) too large\n",
1241 * Fill in the packet
1243 qpkt
.li_vn_mode
= PKT_LI_VN_MODE(0, pktversion
, MODE_CONTROL
);
1244 qpkt
.r_m_e_op
= (u_char
)(opcode
& CTL_OP_MASK
);
1245 qpkt
.sequence
= htons(sequence
);
1247 qpkt
.associd
= htons((u_short
)associd
);
1249 qpkt
.count
= htons((u_short
)qsize
);
1251 pktsize
= CTL_HEADER_LEN
;
1254 * If we have data, copy and pad it out to a 32-bit boundary.
1257 memcpy(qpkt
.data
, qdata
, (size_t)qsize
);
1259 while (pktsize
& (sizeof(u_int32
) - 1)) {
1260 qpkt
.data
[qsize
++] = 0;
1266 * If it isn't authenticated we can just send it. Otherwise
1267 * we're going to have to think about it a little.
1269 if (!auth
&& !always_auth
) {
1270 return sendpkt(&qpkt
, pktsize
);
1274 * Pad out packet to a multiple of 8 octets to be sure
1275 * receiver can handle it.
1277 while (pktsize
& 7) {
1278 qpkt
.data
[qsize
++] = 0;
1283 * Get the keyid and the password if we don't have one.
1285 if (info_auth_keyid
== 0) {
1286 key_id
= getkeyid("Keyid: ");
1287 if (key_id
== 0 || key_id
> NTP_MAXKEY
) {
1289 "Invalid key identifier\n");
1292 info_auth_keyid
= key_id
;
1294 if (!authistrusted(info_auth_keyid
)) {
1295 snprintf(pass_prompt
, sizeof(pass_prompt
),
1297 keytype_name(info_auth_keytype
));
1298 pass
= getpass(pass_prompt
);
1299 if ('\0' == pass
[0]) {
1300 fprintf(stderr
, "Invalid password\n");
1303 authusekey(info_auth_keyid
, info_auth_keytype
,
1305 authtrust(info_auth_keyid
, 1);
1309 * Do the encryption.
1311 maclen
= authencrypt(info_auth_keyid
, (void *)&qpkt
, pktsize
);
1313 fprintf(stderr
, "Key not found\n");
1315 } else if ((size_t)maclen
!= (info_auth_hashlen
+ sizeof(keyid_t
))) {
1317 "%d octet MAC, %u expected with %u octet digest\n",
1318 maclen
, (info_auth_hashlen
+ sizeof(keyid_t
)),
1323 return sendpkt((char *)&qpkt
, pktsize
+ maclen
);
1328 * doquery - send a request and process the response
1346 * Check to make sure host is open
1349 (void) fprintf(stderr
, "***No host open, use `host' command\n");
1360 res
= sendrequest(opcode
, associd
, auth
, qsize
, qdata
);
1365 * Get the response. If we got a standard error, print a message
1367 res
= getresponse(opcode
, associd
, rstatus
, rsize
, rdata
, done
);
1370 if (!done
&& (res
== ERR_TIMEOUT
|| res
== ERR_INCOMPLETE
)) {
1371 if (res
== ERR_INCOMPLETE
) {
1373 * better bump the sequence so we don't
1374 * get confused about differing fragments.
1382 (void) fprintf(stderr
, "server=%s ", currenthost
);
1385 (void) fprintf(stderr
,
1386 "***Server reports a bad format request packet\n");
1388 case CERR_PERMISSION
:
1389 (void) fprintf(stderr
,
1390 "***Server disallowed request (authentication?)\n");
1393 (void) fprintf(stderr
,
1394 "***Server reports a bad opcode in request\n");
1397 (void) fprintf(stderr
,
1398 "***Association ID %d unknown to server\n",associd
);
1400 case CERR_UNKNOWNVAR
:
1401 (void) fprintf(stderr
,
1402 "***A request variable unknown to the server\n");
1405 (void) fprintf(stderr
,
1406 "***Server indicates a request variable was bad\n");
1409 (void) fprintf(stderr
,
1410 "***Server returned an unspecified error\n");
1413 (void) fprintf(stderr
, "***Request timed out\n");
1415 case ERR_INCOMPLETE
:
1416 (void) fprintf(stderr
,
1417 "***Response from server was incomplete\n");
1420 (void) fprintf(stderr
,
1421 "***Buffer size exceeded for returned data\n");
1424 (void) fprintf(stderr
,
1425 "***Server returns unknown error code %d\n", res
);
1433 #ifndef BUILD_AS_LIB
1435 * getcmds - read commands from the standard input and execute them
1443 ntp_readline_init(interactive
? prompt
: NULL
);
1446 line
= ntp_readline(&count
);
1453 ntp_readline_uninit();
1455 #endif /* !BUILD_AS_LIB */
1458 #if !defined(SYS_WINNT) && !defined(BUILD_AS_LIB)
1460 * abortcmd - catch interrupts and abort the current command
1467 if (current_output
== stdout
)
1468 (void) fflush(stdout
);
1470 (void) fflush(stderr
);
1471 if (jump
) longjmp(interrupt_buf
, 1);
1473 #endif /* !SYS_WINNT && !BUILD_AS_LIB */
1476 #ifndef BUILD_AS_LIB
1478 * docmd - decode the command line and execute a command
1485 char *tokens
[1+MAXARGS
+2];
1492 * Tokenize the command line. If nothing on it, return.
1494 tokenize(cmdline
, tokens
, &ntok
);
1499 * Find the appropriate command description.
1501 i
= findcmd(tokens
[0], builtins
, opcmds
, &xcmd
);
1503 (void) fprintf(stderr
, "***Command `%s' unknown\n",
1506 } else if (i
>= 2) {
1507 (void) fprintf(stderr
, "***Command `%s' ambiguous\n",
1513 * Save the keyword, then walk through the arguments, interpreting
1516 pcmd
.keyword
= tokens
[0];
1518 for (i
= 0; i
< MAXARGS
&& xcmd
->arg
[i
] != NO
; i
++) {
1519 if ((i
+1) >= ntok
) {
1520 if (!(xcmd
->arg
[i
] & OPT
)) {
1521 printusage(xcmd
, stderr
);
1526 if ((xcmd
->arg
[i
] & OPT
) && (*tokens
[i
+1] == '>'))
1528 if (!getarg(tokens
[i
+1], (int)xcmd
->arg
[i
], &pcmd
.argval
[i
]))
1534 if (i
< ntok
&& *tokens
[i
] == '>') {
1537 if (*(tokens
[i
]+1) != '\0')
1538 fname
= tokens
[i
]+1;
1539 else if ((i
+1) < ntok
)
1540 fname
= tokens
[i
+1];
1542 (void) fprintf(stderr
, "***No file for redirect\n");
1546 current_output
= fopen(fname
, "w");
1547 if (current_output
== NULL
) {
1548 (void) fprintf(stderr
, "***Error opening %s: ", fname
);
1552 i
= 1; /* flag we need a close */
1554 current_output
= stdout
;
1555 i
= 0; /* flag no close */
1558 if (interactive
&& setjmp(interrupt_buf
)) {
1563 (xcmd
->handler
)(&pcmd
, current_output
);
1564 jump
= 0; /* HMS: 961106: was after fclose() */
1565 if (i
) (void) fclose(current_output
);
1571 * tokenize - turn a command line into tokens
1573 * SK: Modified to allow a quoted string
1575 * HMS: If the first character of the first token is a ':' then (after
1576 * eating inter-token whitespace) the 2nd token is the rest of the line.
1586 register const char *cp
;
1588 static char tspace
[MAXLINE
];
1592 for (*ntok
= 0; *ntok
< MAXTOKENS
; (*ntok
)++) {
1595 /* Skip inter-token whitespace */
1596 while (ISSPACE(*cp
))
1599 /* If we're at EOL we're done */
1603 /* If this is the 2nd token and the first token begins
1604 * with a ':', then just grab to EOL.
1607 if (*ntok
== 1 && tokens
[0][0] == ':') {
1610 } while (!ISEOL(*cp
));
1613 /* Check if this token begins with a double quote.
1614 * If yes, continue reading till the next double quote
1616 else if (*cp
== '\"') {
1620 } while ((*cp
!= '\"') && !ISEOL(*cp
));
1621 /* HMS: a missing closing " should be an error */
1626 } while ((*cp
!= '\"') && !ISSPACE(*cp
) && !ISEOL(*cp
));
1627 /* HMS: Why check for a " in the previous line? */
1636 * getarg - interpret an argument token
1647 static const char *digits
= "0123456789";
1649 switch (code
& ~OPT
) {
1654 if (!getnetnum(str
, &(argp
->netnum
), (char *)0, 0)) {
1666 (void) fprintf(stderr
,
1667 "***Association value `%s' invalid/undecodable\n", str
);
1670 if (isneg
> numassoc
) {
1671 if (numassoc
== 0) {
1672 (void) fprintf(stderr
,
1673 "***Association for `%s' unknown (max &%d)\n",
1680 argp
->uval
= assoc_cache
[isneg
-1].assid
;
1691 cp
= strchr(digits
, *np
);
1693 (void) fprintf(stderr
,
1694 "***Illegal integer value %s\n", str
);
1698 argp
->uval
+= (cp
- digits
);
1699 } while (*(++np
) != '\0');
1702 if ((code
& ~OPT
) == NTP_UINT
) {
1703 (void) fprintf(stderr
,
1704 "***Value %s should be unsigned\n", str
);
1707 argp
->ival
= -argp
->ival
;
1711 if (!strcmp("-6", str
))
1713 else if (!strcmp("-4", str
))
1716 (void) fprintf(stderr
,
1717 "***Version must be either 4 or 6\n");
1725 #endif /* !BUILD_AS_LIB */
1729 * findcmd - find a command in a command description table
1734 struct xcmd
*clist1
,
1735 struct xcmd
*clist2
,
1739 register struct xcmd
*cl
;
1742 struct xcmd
*nearmatch
= NULL
;
1749 else if (clist2
!= 0)
1755 for (cl
= clist
; cl
->keyword
!= 0; cl
++) {
1756 /* do a first character check, for efficiency */
1757 if (*str
!= *(cl
->keyword
))
1759 if (strncmp(str
, cl
->keyword
, (unsigned)clen
) == 0) {
1761 * Could be extact match, could be approximate.
1762 * Is exact if the length of the keyword is the
1765 if (*((cl
->keyword
) + clen
) == '\0') {
1775 * See if there is more to do. If so, go again. Sorry about the
1776 * goto, too much looking at BSD sources...
1778 if (clist
== clist1
&& clist2
!= 0) {
1784 * If we got extactly 1 near match, use it, else return number
1796 * getnetnum - given a host name, return its net number
1797 * and (optional) full name
1808 struct addrinfo hints
, *ai
= NULL
;
1810 sockaddr_len
= SIZEOF_SOCKADDR(af
);
1811 memset(&hints
, 0, sizeof(hints
));
1812 hints
.ai_flags
= AI_CANONNAME
;
1813 #ifdef AI_ADDRCONFIG
1814 hints
.ai_flags
|= AI_ADDRCONFIG
;
1817 /* decodenetnum works with addresses only */
1818 if (decodenetnum(hname
, num
)) {
1819 if (fullhost
!= 0) {
1820 getnameinfo((struct sockaddr
*)num
, sockaddr_len
,
1821 fullhost
, sizeof(fullhost
), NULL
, 0,
1825 } else if (getaddrinfo(hname
, "ntp", &hints
, &ai
) == 0) {
1826 memmove((char *)num
, ai
->ai_addr
, ai
->ai_addrlen
);
1827 if (ai
->ai_canonname
!= 0)
1828 (void) strcpy(fullhost
, ai
->ai_canonname
);
1831 (void) fprintf(stderr
, "***Can't find host %s\n", hname
);
1838 * nntohost - convert network number to host name. This routine enforces
1839 * the showhostnames setting.
1847 return stoa(netnum
);
1848 else if (ISREFCLOCKADR(netnum
))
1849 return refnumtoa(netnum
);
1851 return socktohost(netnum
);
1856 * rtdatetolfp - decode an RT-11 date into an l_fp
1866 struct calendar cal
;
1868 static const char *months
[12] = {
1869 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
1870 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
1876 * An RT-11 date looks like:
1878 * d[d]-Mth-y[y] hh:mm:ss
1880 * (No docs, but assume 4-digit years are also legal...)
1882 * d[d]-Mth-y[y[y[y]]] hh:mm:ss
1885 if (!isdigit((int)*cp
)) {
1888 * Catch special case
1896 cal
.monthday
= (u_char
) (*cp
++ - '0'); /* ascii dependent */
1897 if (isdigit((int)*cp
)) {
1898 cal
.monthday
= (u_char
)((cal
.monthday
<< 3) + (cal
.monthday
<< 1));
1899 cal
.monthday
= (u_char
)(cal
.monthday
+ *cp
++ - '0');
1905 for (i
= 0; i
< 3; i
++)
1909 for (i
= 0; i
< 12; i
++)
1910 if (STREQ(buf
, months
[i
]))
1914 cal
.month
= (u_char
)(i
+ 1);
1919 if (!isdigit((int)*cp
))
1921 cal
.year
= (u_short
)(*cp
++ - '0');
1922 if (isdigit((int)*cp
)) {
1923 cal
.year
= (u_short
)((cal
.year
<< 3) + (cal
.year
<< 1));
1924 cal
.year
= (u_short
)(*cp
++ - '0');
1926 if (isdigit((int)*cp
)) {
1927 cal
.year
= (u_short
)((cal
.year
<< 3) + (cal
.year
<< 1));
1928 cal
.year
= (u_short
)(cal
.year
+ *cp
++ - '0');
1930 if (isdigit((int)*cp
)) {
1931 cal
.year
= (u_short
)((cal
.year
<< 3) + (cal
.year
<< 1));
1932 cal
.year
= (u_short
)(cal
.year
+ *cp
++ - '0');
1936 * Catch special case. If cal.year == 0 this is a zero timestamp.
1938 if (cal
.year
== 0) {
1943 if (*cp
++ != ' ' || !isdigit((int)*cp
))
1945 cal
.hour
= (u_char
)(*cp
++ - '0');
1946 if (isdigit((int)*cp
)) {
1947 cal
.hour
= (u_char
)((cal
.hour
<< 3) + (cal
.hour
<< 1));
1948 cal
.hour
= (u_char
)(cal
.hour
+ *cp
++ - '0');
1951 if (*cp
++ != ':' || !isdigit((int)*cp
))
1953 cal
.minute
= (u_char
)(*cp
++ - '0');
1954 if (isdigit((int)*cp
)) {
1955 cal
.minute
= (u_char
)((cal
.minute
<< 3) + (cal
.minute
<< 1));
1956 cal
.minute
= (u_char
)(cal
.minute
+ *cp
++ - '0');
1959 if (*cp
++ != ':' || !isdigit((int)*cp
))
1961 cal
.second
= (u_char
)(*cp
++ - '0');
1962 if (isdigit((int)*cp
)) {
1963 cal
.second
= (u_char
)((cal
.second
<< 3) + (cal
.second
<< 1));
1964 cal
.second
= (u_char
)(cal
.second
+ *cp
++ - '0');
1968 * For RT-11, 1972 seems to be the pivot year
1975 lfp
->l_ui
= caltontp(&cal
);
1982 * decodets - decode a timestamp into an l_fp format number, with
1983 * consideration of fuzzball formats.
1992 * If it starts with a 0x, decode as hex.
1994 if (*str
== '0' && (*(str
+1) == 'x' || *(str
+1) == 'X'))
1995 return hextolfp(str
+2, lfp
);
1998 * If it starts with a '"', try it as an RT-11 date.
2001 register char *cp
= str
+1;
2006 while (*cp
!= '"' && *cp
!= '\0' && bp
< &buf
[29])
2009 return rtdatetolfp(buf
, lfp
);
2013 * Might still be hex. Check out the first character. Talk
2016 if ((*str
>= 'A' && *str
<= 'F') || (*str
>= 'a' && *str
<= 'f'))
2017 return hextolfp(str
, lfp
);
2020 * Try it as a decimal. If this fails, try as an unquoted
2021 * RT-11 date. This code should go away eventually.
2023 if (atolfp(str
, lfp
))
2026 return rtdatetolfp(str
, lfp
);
2031 * decodetime - decode a time value. It should be in milliseconds
2039 return mstolfp(str
, lfp
);
2044 * decodeint - decode an integer
2053 if (*(str
+1) == 'x' || *(str
+1) == 'X')
2054 return hextoint(str
+2, (u_long
*)val
);
2055 return octtoint(str
, (u_long
*)val
);
2057 return atoint(str
, val
);
2062 * decodeuint - decode an unsigned integer
2071 if (*(str
+ 1) == 'x' || *(str
+ 1) == 'X')
2072 return (hextoint(str
+ 2, val
));
2073 return (octtoint(str
, val
));
2075 return (atouint(str
, val
));
2080 * decodearr - decode an array of time values
2089 register char *cp
, *bp
;
2098 while (isspace((int)*cp
))
2104 while (!isspace((int)*cp
) && *cp
!= '\0')
2108 if (!decodetime(buf
, lfp
))
2118 * Finally, the built in command handlers
2122 * help - tell about commands, or details of a particular command
2130 struct xcmd
*xcp
= NULL
; /* quiet warning */
2132 const char *list
[100];
2137 if (pcmd
->nargs
== 0) {
2139 for (xcp
= builtins
; xcp
->keyword
!= 0; xcp
++) {
2140 if (*(xcp
->keyword
) != '?')
2141 list
[words
++] = xcp
->keyword
;
2143 for (xcp
= opcmds
; xcp
->keyword
!= 0; xcp
++)
2144 list
[words
++] = xcp
->keyword
;
2147 #ifdef QSORT_USES_VOID_P
2152 (list
), (size_t)(words
), sizeof(char *), helpsort
);
2154 for (word
= 0; word
< words
; word
++) {
2155 int length
= strlen(list
[word
]);
2161 cols
= SCREENWIDTH
/ ++col
;
2162 rows
= (words
+ cols
- 1) / cols
;
2164 (void) fprintf(fp
, "ntpq commands:\n");
2166 for (row
= 0; row
< rows
; row
++) {
2167 for (word
= row
; word
< words
; word
+= rows
) {
2168 (void) fprintf(fp
, "%-*.*s", col
,
2171 (void) fprintf(fp
, "\n");
2174 cmd
= pcmd
->argval
[0].string
;
2175 words
= findcmd(cmd
, builtins
, opcmds
, &xcp
);
2177 (void) fprintf(stderr
,
2178 "Command `%s' is unknown\n", cmd
);
2180 } else if (words
>= 2) {
2181 (void) fprintf(stderr
,
2182 "Command `%s' is ambiguous\n", cmd
);
2185 (void) fprintf(fp
, "function: %s\n", xcp
->comment
);
2186 printusage(xcp
, fp
);
2192 * helpsort - do hostname qsort comparisons
2194 #ifdef QSORT_USES_VOID_P
2201 char const * const * name1
= (char const * const *)t1
;
2202 char const * const * name2
= (char const * const *)t2
;
2204 return strcmp(*name1
, *name2
);
2214 return strcmp(*name1
, *name2
);
2219 * printusage - print usage information for a command
2229 (void) fprintf(fp
, "usage: %s", xcp
->keyword
);
2230 for (i
= 0; i
< MAXARGS
&& xcp
->arg
[i
] != NO
; i
++) {
2231 if (xcp
->arg
[i
] & OPT
)
2232 (void) fprintf(fp
, " [ %s ]", xcp
->desc
[i
]);
2234 (void) fprintf(fp
, " %s", xcp
->desc
[i
]);
2236 (void) fprintf(fp
, "\n");
2241 * timeout - set time out time
2251 if (pcmd
->nargs
== 0) {
2252 val
= (int)tvout
.tv_sec
* 1000 + tvout
.tv_usec
/ 1000;
2253 (void) fprintf(fp
, "primary timeout %d ms\n", val
);
2255 tvout
.tv_sec
= pcmd
->argval
[0].uval
/ 1000;
2256 tvout
.tv_usec
= (pcmd
->argval
[0].uval
- ((long)tvout
.tv_sec
* 1000))
2263 * auth_delay - set delay for auth requests
2274 if (pcmd
->nargs
== 0) {
2275 val
= delay_time
.l_ui
* 1000 + delay_time
.l_uf
/ 4294967;
2276 (void) fprintf(fp
, "delay %lu ms\n", val
);
2278 if (pcmd
->argval
[0].ival
< 0) {
2280 val
= (u_long
)(-pcmd
->argval
[0].ival
);
2283 val
= (u_long
)pcmd
->argval
[0].ival
;
2286 delay_time
.l_ui
= val
/ 1000;
2288 delay_time
.l_uf
= val
* 4294967; /* 2**32/1000 */
2297 * host - set the host we are dealing with.
2307 if (pcmd
->nargs
== 0) {
2309 (void) fprintf(fp
, "current host is %s\n",
2312 (void) fprintf(fp
, "no current host\n");
2317 ai_fam_templ
= ai_fam_default
;
2318 if (pcmd
->nargs
== 2) {
2319 if (!strcmp("-4", pcmd
->argval
[i
].string
))
2320 ai_fam_templ
= AF_INET
;
2321 else if (!strcmp("-6", pcmd
->argval
[i
].string
))
2322 ai_fam_templ
= AF_INET6
;
2326 "current host remains %s\n",
2329 (void) fprintf(fp
, "still no current host\n");
2334 if (openhost(pcmd
->argval
[i
].string
)) {
2335 (void) fprintf(fp
, "current host set to %s\n", currenthost
);
2340 "current host remains %s\n",
2343 (void) fprintf(fp
, "still no current host\n");
2349 * poll - do one (or more) polls of the host via NTP
2358 (void) fprintf(fp
, "poll not implemented yet\n");
2363 * keyid - get a keyid to use for authenticating requests
2371 if (pcmd
->nargs
== 0) {
2372 if (info_auth_keyid
== 0)
2373 (void) fprintf(fp
, "no keyid defined\n");
2375 (void) fprintf(fp
, "keyid is %lu\n", (u_long
)info_auth_keyid
);
2377 /* allow zero so that keyid can be cleared. */
2378 if(pcmd
->argval
[0].uval
> NTP_MAXKEY
)
2379 (void) fprintf(fp
, "Invalid key identifier\n");
2380 info_auth_keyid
= pcmd
->argval
[0].uval
;
2385 * keytype - get type of key to use for authenticating requests
2393 const char * digest_name
;
2398 fprintf(fp
, "keytype is %s with %u octet digests\n",
2399 keytype_name(info_auth_keytype
),
2404 digest_name
= pcmd
->argval
[0].string
;
2406 key_type
= keytype_from_text(digest_name
, &digest_len
);
2409 fprintf(fp
, "keytype must be 'md5'%s\n",
2411 " or a digest type provided by OpenSSL");
2418 info_auth_keytype
= key_type
;
2419 info_auth_hashlen
= digest_len
;
2424 * passwd - get an authentication key
2435 if (info_auth_keyid
== 0) {
2436 int u_keyid
= getkeyid("Keyid: ");
2437 if (u_keyid
== 0 || u_keyid
> NTP_MAXKEY
) {
2438 (void)fprintf(fp
, "Invalid key identifier\n");
2441 info_auth_keyid
= u_keyid
;
2443 pass
= getpass("MD5 Password: ");
2445 (void) fprintf(fp
, "Password unchanged\n");
2447 authusekey(info_auth_keyid
, info_auth_keytype
, (u_char
*)pass
);
2448 authtrust(info_auth_keyid
, 1);
2454 * hostnames - set the showhostnames flag
2462 if (pcmd
->nargs
== 0) {
2464 (void) fprintf(fp
, "hostnames being shown\n");
2466 (void) fprintf(fp
, "hostnames not being shown\n");
2468 if (STREQ(pcmd
->argval
[0].string
, "yes"))
2470 else if (STREQ(pcmd
->argval
[0].string
, "no"))
2473 (void)fprintf(stderr
, "What?\n");
2480 * setdebug - set/change debugging level
2488 if (pcmd
->nargs
== 0) {
2489 (void) fprintf(fp
, "debug level is %d\n", debug
);
2491 } else if (STREQ(pcmd
->argval
[0].string
, "no")) {
2493 } else if (STREQ(pcmd
->argval
[0].string
, "more")) {
2495 } else if (STREQ(pcmd
->argval
[0].string
, "less")) {
2498 (void) fprintf(fp
, "What?\n");
2501 (void) fprintf(fp
, "debug level set to %d\n", debug
);
2506 * quit - stop this nonsense
2516 closesocket(sockfd
); /* cleanliness next to godliness */
2522 * version - print the current version number
2532 (void) fprintf(fp
, "%s\n", Version
);
2538 * raw - set raw mode output
2548 (void) fprintf(fp
, "Output set to raw\n");
2553 * cooked - set cooked mode output
2563 (void) fprintf(fp
, "Output set to cooked\n");
2569 * authenticate - always authenticate requests to this host
2577 if (pcmd
->nargs
== 0) {
2580 "authenticated requests being sent\n");
2583 "unauthenticated requests being sent\n");
2585 if (STREQ(pcmd
->argval
[0].string
, "yes")) {
2587 } else if (STREQ(pcmd
->argval
[0].string
, "no")) {
2590 (void)fprintf(stderr
, "What?\n");
2596 * ntpversion - choose the NTP version to use
2604 if (pcmd
->nargs
== 0) {
2606 "NTP version being claimed is %d\n", pktversion
);
2608 if (pcmd
->argval
[0].uval
< NTP_OLDVERSION
2609 || pcmd
->argval
[0].uval
> NTP_VERSION
) {
2610 (void) fprintf(stderr
, "versions %d to %d, please\n",
2611 NTP_OLDVERSION
, NTP_VERSION
);
2613 pktversion
= (u_char
) pcmd
->argval
[0].uval
;
2620 * warning - print a warning message
2629 (void) fprintf(stderr
, "%s: ", progname
);
2630 (void) fprintf(stderr
, fmt
, st1
, st2
);
2631 (void) fprintf(stderr
, ": ");
2637 * error - print a message and exit
2646 warning(fmt
, st1
, st2
);
2651 * getkeyid - prompt the user for a keyid to use
2655 const char *keyprompt
2664 if ((fi
= fdopen(open("/dev/tty", 2), "r")) == NULL
)
2666 if ((fi
= _fdopen(open("CONIN$", _O_TEXT
), "r")) == NULL
)
2667 #endif /* SYS_WINNT */
2670 setbuf(fi
, (char *)NULL
);
2671 fprintf(stderr
, "%s", keyprompt
); fflush(stderr
);
2672 for (p
=pbuf
; (c
= getc(fi
))!='\n' && c
!=EOF
;) {
2679 if (strcmp(pbuf
, "0") == 0)
2682 return (u_long
) atoi(pbuf
);
2687 * atoascii - printable-ize possibly ascii data using the character
2688 * transformations cat -v uses.
2698 register const u_char
* pchIn
;
2699 const u_char
* pchInLimit
;
2700 register u_char
* pchOut
;
2703 pchIn
= (const u_char
*)in
;
2704 pchInLimit
= pchIn
+ in_octets
;
2705 pchOut
= (u_char
*)out
;
2707 if (NULL
== pchIn
) {
2715 if (0 == --out_octets) { \
2722 for ( ; pchIn
< pchInLimit
; pchIn
++) {
2733 ONEOUT((u_char
)(c
+ '@'));
2734 } else if (0x7f == c
) {
2747 * makeascii - print possibly ascii data using the character
2748 * transformations that cat -v uses.
2757 register u_char
*cp
;
2760 for (cp
= (u_char
*)data
; cp
< (u_char
*)data
+ length
; cp
++) {
2771 } else if (0x7f == c
) {
2781 * asciize - same thing as makeascii except add a newline
2790 makeascii(length
, data
, fp
);
2796 * Some circular buffer space
2801 char circ_buf
[NUMCB
][CBLEN
];
2805 * nextvar - find the next variable in the buffer
2817 register char *cpend
;
2818 register char *npend
; /* character after last */
2820 static char name
[MAXVARLEN
];
2821 static char value
[MAXVALLEN
];
2824 cpend
= cp
+ *datalen
;
2827 * Space past commas and white space
2829 while (cp
< cpend
&& (*cp
== ',' || isspace((int)*cp
)))
2835 * Copy name until we hit a ',', an '=', a '\r' or a '\n'. Backspace
2836 * over any white space and terminate it.
2839 npend
= &name
[MAXVARLEN
];
2840 while (cp
< cpend
&& np
< npend
&& *cp
!= ',' && *cp
!= '='
2841 && *cp
!= '\r' && *cp
!= '\n')
2844 * Check if we ran out of name space, without reaching the end or a
2845 * terminating character
2847 if (np
== npend
&& !(cp
== cpend
|| *cp
== ',' || *cp
== '=' ||
2848 *cp
== '\r' || *cp
== '\n'))
2850 while (isspace((int)(*(np
-1))))
2856 * Check if we hit the end of the buffer or a ','. If so we are done.
2858 if (cp
== cpend
|| *cp
== ',' || *cp
== '\r' || *cp
== '\n') {
2862 *datalen
= cpend
- cp
;
2863 *vvalue
= (char *)0;
2868 * So far, so good. Copy out the value
2870 cp
++; /* past '=' */
2871 while (cp
< cpend
&& (isspace((int)*cp
) && *cp
!= '\r' && *cp
!= '\n'))
2874 npend
= &value
[MAXVALLEN
];
2875 while (cp
< cpend
&& np
< npend
&& ((*cp
!= ',') || quoted
))
2877 quoted
^= ((*np
++ = *cp
++) == '"');
2881 * Check if we overran the value buffer while still in a quoted string
2882 * or without finding a comma
2884 if (np
== npend
&& (quoted
|| *cp
!= ','))
2887 * Trim off any trailing whitespace
2889 while (np
> value
&& isspace((int)(*(np
-1))))
2894 * Return this. All done.
2899 *datalen
= cpend
- cp
;
2906 * findvar - see if this variable is known to us.
2907 * If "code" is 1, return ctl_var->code.
2908 * Otherwise return the ordinal position of the found variable.
2913 struct ctl_var
*varlist
,
2918 register struct ctl_var
*vl
;
2922 while (vl
->fmt
!= EOV
) {
2923 if (vl
->fmt
!= PADDING
&& STREQ(np
, vl
->text
))
2936 * printvars - print variables returned in response packet
2949 rawprint(sttype
, length
, data
, status
, quiet
, fp
);
2951 cookedprint(sttype
, length
, data
, status
, quiet
, fp
);
2956 * rawprint - do a printout of the data in raw mode
2969 register char *cpend
;
2972 * Essentially print the data as is. We reformat unprintables, though.
2975 cpend
= data
+ length
;
2978 (void) fprintf(fp
, "status=0x%04x,\n", status
);
2980 while (cp
< cpend
) {
2983 * If this is a \r and the next character is a
2984 * \n, supress this, else pretty print it. Otherwise
2985 * just output the character.
2987 if (cp
== (cpend
- 1) || *(cp
+ 1) != '\n')
2988 makeascii(1, cp
, fp
);
2989 } else if (isspace(*cp
) || isprint(*cp
))
2992 makeascii(1, cp
, fp
);
2999 * Global data used by the cooked output routines
3001 int out_chars
; /* number of characters output */
3002 int out_linecount
; /* number of characters output on this line */
3006 * startoutput - get ready to do cooked output
3017 * output - output a variable=value combination
3028 /* strlen of "name=value" */
3029 len
= strlen(name
) + 1 + strlen(value
);
3031 if (out_chars
!= 0) {
3033 if ((out_linecount
+ len
+ 2) > MAXOUTLINE
) {
3046 out_linecount
+= len
;
3051 * endoutput - terminate a block of cooked output
3064 * outputarr - output an array of values
3082 * Hack to align delay and offset values
3084 for (i
= (int)strlen(name
); i
< 11; i
++)
3087 for (i
= narr
; i
> 0; i
--) {
3090 cp
= lfptoms(lfp
, 2);
3105 output(fp
, name
, buf
);
3113 register char *cb
, *s
;
3115 register const char *sep
;
3119 s
= cb
= &circ_buf
[nextcb
][0];
3120 if (++nextcb
>= NUMCB
)
3123 sprintf(cb
, "%02lx", val
);
3130 for (i
= 0; i
< 13; i
++) {
3132 sprintf(cb
, "%s%s", sep
, tstflagnames
[i
]);
3144 * cookedprint - output variables in cooked mode
3161 struct ctl_var
*varlist
;
3177 varlist
= clock_var
;
3180 fprintf(stderr
, "Unknown datatype(0x%x) in cookedprint\n",
3186 fprintf(fp
, "status=%04x %s,\n", status
,
3187 statustoa(datatype
, status
));
3190 while (nextvar(&length
, &data
, &name
, &value
)) {
3191 varid
= findvar(name
, varlist
, 0);
3196 fmt
= varlist
[varid
].fmt
;
3199 if (!decodets(value
, &lfp
))
3202 output(fp
, name
, prettydate(&lfp
));
3207 if (!decodetime(value
, &lfp
))
3228 if (!decodeuint(value
, &uval
))
3231 output(fp
, name
, uinttoa(uval
));
3235 if (!decodeint(value
, &ival
))
3238 output(fp
, name
, inttoa(ival
));
3243 if (!decodenetnum(value
, &hval
))
3245 else if (fmt
== HA
){
3246 output(fp
, name
, nntohost(&hval
));
3248 output(fp
, name
, stoa(&hval
));
3257 if (decodenetnum(value
, &hval
)) {
3258 if (ISREFCLOCKADR(&hval
))
3262 output(fp
, name
, stoa(&hval
));
3263 } else if ((int)strlen(value
) <= 4)
3264 output(fp
, name
, value
);
3270 if (!decodeuint(value
, &uval
) || uval
> 3)
3280 output(fp
, name
, b
);
3285 if (!decodeuint(value
, &uval
))
3290 (void) snprintf(b
, sizeof b
, "%03lo", uval
);
3291 output(fp
, name
, b
);
3296 if (!decodeuint(value
, &uval
))
3299 output(fp
, name
, uinttoa(uval
));
3303 if (!decodearr(value
, &narr
, lfparr
))
3306 outputarr(fp
, name
, narr
, lfparr
);
3310 if (!decodeuint(value
, &uval
))
3313 output(fp
, name
, tstflags(uval
));
3317 (void) fprintf(stderr
,
3318 "Internal error in cookedprint, %s=%s, fmt %d\n",
3324 if (output_raw
!= 0) {
3329 atoascii(name
, MAXVARLEN
, bn
, sizeof(bn
));
3330 atoascii(value
, MAXVARLEN
, bv
, sizeof(bv
));
3331 if (output_raw
!= '*') {
3333 bv
[len
] = output_raw
;
3344 * sortassoc - sort associations in the cache into ascending order
3351 #ifdef QSORT_USES_VOID_P
3356 assoc_cache
, (size_t)numassoc
,
3357 sizeof(struct association
), assoccmp
);
3362 * assoccmp - compare two associations
3364 #ifdef QSORT_USES_VOID_P
3371 const struct association
*ass1
= (const struct association
*)t1
;
3372 const struct association
*ass2
= (const struct association
*)t2
;
3374 if (ass1
->assid
< ass2
->assid
)
3376 if (ass1
->assid
> ass2
->assid
)
3383 struct association
*ass1
,
3384 struct association
*ass2
3387 if (ass1
->assid
< ass2
->assid
)
3389 if (ass1
->assid
> ass2
->assid
)
3393 #endif /* not QSORT_USES_VOID_P */
3396 * ntpq_custom_opt_handler - autoopts handler for -c and -p
3398 * By default, autoopts loses the relative order of -c and -p options
3399 * on the command line. This routine replaces the default handler for
3400 * those routines and builds a list of commands to execute preserving
3404 ntpq_custom_opt_handler(
3409 switch (pOptDesc
->optValue
) {
3413 "ntpq_custom_opt_handler unexpected option '%c' (%d)\n",
3414 pOptDesc
->optValue
, pOptDesc
->optValue
);
3418 ADDCMD(pOptDesc
->pzLastArg
);