ntpq.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* Copyright 1996-2003 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* ntpq - query an NTP server using mode 6 commands
*/
#include <stdio.h>
#include <ctype.h>
#include <signal.h>
#include <setjmp.h>
#include <netdb.h>
#ifdef SYS_WINNT
# include <io.h>
#else
#define closesocket close
#endif /* SYS_WINNT */
#include "ntpq.h"
#include "ntp_unixtime.h"
#include "ntp_calendar.h"
#include "ntp_io.h"
#include "ntp_select.h"
#include "ntp_stdlib.h"
#ifdef SYS_VXWORKS
/* vxWorks needs mode flag -casey*/
#define SERVER_PORT_NUM 123
#endif
#if defined(VMS)
extern char *getpass(const char *);
#endif
/*
* Because we potentially understand a lot of commands we will run
* interactive if connected to a terminal.
*/
int interactive = 0; /* set to 1 when we should prompt */
/*
* Keyid used for authenticated requests. Obtained on the fly.
*/
/*
* Type of key md5 or des
*/
#define KEY_TYPE_DES 3
#define KEY_TYPE_MD5 4
/*
* Flag which indicates we should always send authenticated requests
*/
int always_auth = 0;
/*
* Flag which indicates raw mode output.
*/
int rawmode = 0;
/*
* Packet version number we use
*/
/*
* Don't jump if no set jmp.
*/
volatile int jump = 0;
/*
* Format values
*/
#define PADDING 0
/*
* System variable values. The array can be indexed by
* the variable index to find the textual name.
*/
{ 0, EOV, "" }
};
/*
* Peer variable list
*/
/*
* These are duplicate entries so that we can
* process deviant version of the xntp protocal.
*/
{ 0, EOV, "" }
};
/*
* Clock variable list
*/
{ 0, EOV, "" }
};
/*
* flasher bits
*/
static const char *tstflagnames[] = {
"DUPLICATE PKT",
"BOGUS PKT",
"PROTO UNSYNC",
"PEER BOUNDS",
"BAD AUTH",
"PEER CLOCK UNSYNC",
"BAD STRATUM",
"ROOT BOUNDS"
};
/*
* Built in command handler declarations
*/
static int openhost P((char *));
static int sendpkt P((char *, int));
static int getresponse P((int, int, u_short *, int *, char **, int));
static int sendrequest P((int, int, int, int, char *));
static void getcmds P((void));
static RETSIGTYPE abortcmd P((int));
static void docmd P((char *));
static void tokenize P((char *, char **, int *));
static int rtdatetolfp P((char *, l_fp *));
#ifdef QSORT_USES_VOID_P
static int helpsort P((const void *, const void *));
#else
static int helpsort P((char **, char **));
#endif
static void warning P((char *, char *, char *));
static void error P((char *, char *, char *));
static void atoascii P((int, char *, char *));
static void startoutput P((void));
static void cookedprint P((int, int, char *, int, FILE *));
#ifdef QSORT_USES_VOID_P
static int assoccmp P((const void *, const void *));
#else
#endif /* sgi || bsdi */
/*
* Built-in commands we understand
*/
{ "command", "", "", "" },
"tell the use and syntax of commands" },
{ "command", "", "", "" },
"tell the use and syntax of commands" },
{ "msec", "", "", "" },
"set the primary receive time out" },
{ "msec", "", "", "" },
"set the delay added to encryption time stamps" },
{ "hostname", "", "", "" },
"specify the host whose NTP server we talk to" },
{ "n", "verbose", "", "" },
"poll an NTP server in client mode `n' times" },
{ "", "", "", "" },
"specify a password to use for authenticated requests"},
{ "yes|no", "", "", "" },
"specify whether hostnames or net numbers are printed"},
{ "no|more|less", "", "", "" },
{ "", "", "", "" },
"exit ntpq" },
{ "", "", "", "" },
"exit ntpq" },
{ "key#", "", "", "" },
"set keyid to use for authenticated requests" },
{ "", "", "", "" },
"print version number" },
{ "", "", "", "" },
"do raw mode variable output" },
{ "", "", "", "" },
"do cooked mode variable output" },
{ "yes|no", "", "", "" },
"always authenticate requests to this server" },
{ "version number", "", "", "" },
"set the NTP version number to use for requests" },
{ "key type (md5|des)", "", "", "" },
"set key type to use for authenticated requests (des|md5)" },
{ "", "", "", "" }, "" }
};
/*
* Default values we use.
*/
/*
* Some variables used and manipulated locally
*/
int sockfd; /* fd socket is opened on */
int havehost = 0; /* set to 1 when host open */
#ifdef SYS_WINNT
#endif /* SYS_WINNT */
/*
* Sequence number used for requests. It is incremented before
* it is used.
*/
/*
* Holds data returned from queries. Declare buffer long to be sure of
* alignment.
*/
/*
* Holds association data for use with the &n operator.
*/
int numassoc = 0; /* number of cached associations */
/*
* For commands typed on the command line (with the -c option)
*/
int numcmds = 0;
/*
* When multiple hosts are specified.
*/
int numhosts = 0;
/*
* Error codes for internal use
*/
#define ERR_UNSPEC 256
#define ERR_INCOMPLETE 257
#define ERR_TIMEOUT 258
#define ERR_TOOMUCH 259
/*
* Macro definitions we use
*/
/*
* Jump buffer for longjumping back to the command level
*/
/*
* Points at file being currently printed into
*/
/*
* Command table imported from ntpdc_ops.c
*/
char *progname;
int debug;
#ifdef NO_MAIN_ALLOWED
void ntpqmain P((int, char *[]));
void clear_globals()
{
extern int ntp_optind;
extern char *ntp_optarg;
showhostnames = 0; /* don'tshow host names by default */
ntp_optind = 0;
ntp_optarg = 0;
havehost = 0; /* set to 1 when host open */
numassoc = 0; /* number of cached associations */
numcmds = 0;
numhosts = 0;
}
#else
int main P((int, char *[]));
#endif
/*
* main - parse arguments and handle options
*/
#ifndef NO_MAIN_ALLOWED
int main
#else
void ntpqmain
#endif
int argc;
char *argv[];
{
int c;
int errflg = 0;
extern int ntp_optind;
extern char *ntp_optarg;
#ifdef NO_MAIN_ALLOWED
#endif
delay_time.l_ui = 0;
switch (c) {
case 'c':
break;
case 'd':
++debug;
break;
case 'i':
interactive = 1;
break;
case 'n':
showhostnames = 0;
break;
case 'p':
ADDCMD("peers");
break;
default:
errflg++;
break;
}
if (errflg) {
"usage: %s [-dinp] [-c cmd] host ...\n",
progname);
exit(2);
}
if (ntp_optind == argc) {
} else {
}
if (numcmds == 0 && interactive == 0
interactive = 1;
}
#ifndef SYS_WINNT /* Under NT cannot handle SIGINT, WIN32 spawns a handler */
if (interactive)
#endif /* SYS_WINNT */
#ifdef SYS_WINNT
exit(1);
}
#endif /* SYS_WINNT */
if (numcmds == 0) {
getcmds();
} else {
int ihost;
int icmd;
}
}
#ifdef SYS_WINNT
WSACleanup();
#endif /* SYS_WINNT */
#ifndef SYS_VXWORKS
exit(0);
#endif
}
/*
* openhost - open a socket to a host
*/
static int
char *hname;
{
char temphost[LENHOSTNAME];
if (server_entry == NULL) {
if (server_entry == NULL) {
#ifdef VMS /* UCX getservbyname() doesn't work [yet], but we do know better */
server_entry = (struct servent *)
#else
progname);
exit(1);
#endif /* VMS & UCX */
}
if (debug > 2)
}
return 0;
if (debug > 2)
if (havehost == 1) {
if (debug > 2)
(void) closesocket(sockfd);
havehost = 0;
}
#ifndef SYS_VXWORKS
#else
#endif
#ifdef SYS_WINNT
{
int err;
err = setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char *)&optionValue, sizeof(optionValue));
exit(1);
}
}
if (sockfd == INVALID_SOCKET) {
exit(-1);
}
#else
if (sockfd == -1)
#endif /* SYS_WINNT */
#ifdef NEED_RCVBUF_SLOP
# ifdef SO_RCVBUF
&rbufsize, sizeof(int)) == -1)
}
# endif
#endif
sizeof(hostaddr)) == -1)
havehost = 1;
return 1;
}
/* XXX ELIMINATE sendpkt similar in ntpq.c, ntpdc.c, ntp_io.c, ntptrace.c */
/*
* sendpkt - send a packet to the remote host
*/
static int
char *xdata;
int xdatalen;
{
if (debug >= 3)
return -1;
}
if (debug >= 4) {
int first = 8;
printf("Packet data:\n");
while (xdatalen-- > 0) {
if (first-- == 0) {
printf("\n");
first = 7;
}
}
printf("\n");
}
return 0;
}
/*
* getresponse - get a (series of) response packet(s) and return the data
*/
static int
int opcode;
int associd;
int *rsize;
char **rdata;
int timeo;
{
struct ntp_control rpkt;
int numfrags;
int seenlastfrag;
int n;
/*
* This is pretty tricky. We may get between 1 and MAXFRAG packets
* back in response to the request. We peel the data out of
* each packet and collect it in one long block. When the last
* packet in the sequence is received we'll know how much data we
* should have had. Note we use one long time out, should reconsider.
*/
*rsize = 0;
if (rstatus)
*rstatus = 0;
numfrags = 0;
seenlastfrag = 0;
if (numfrags == 0)
else
if (debug >= 1)
printf("select() returns %d\n", n);
if (n == -1) {
return -1;
}
if (n == 0) {
/*
* Timed out. Return what we have
*/
if (numfrags == 0) {
if (timeo)
"%s: timed out, nothing received\n",
return ERR_TIMEOUT;
} else {
if (timeo)
"%s: timed out with incomplete data\n",
if (debug) {
printf("Received fragments:\n");
for (n = 0; n < numfrags; n++)
counts[n]);
if (seenlastfrag)
printf("last fragment received\n");
else
printf("last fragment not received\n");
}
return ERR_INCOMPLETE;
}
}
if (n == -1) {
return -1;
}
if (debug >= 4) {
printf("Packet data:\n");
while (len-- > 0) {
if (first-- == 0) {
printf("\n");
first = 7;
}
}
printf("\n");
}
/*
* Check for format errors. Bug proofing.
*/
if (n < CTL_HEADER_LEN) {
if (debug)
printf("Short (%d byte) packet received\n", n);
goto again;
}
if (debug)
printf("Packet received with version %d\n",
goto again;
}
if (debug)
printf("Packet received with mode %d\n",
goto again;
}
if (debug)
printf("Received request packet, wanted response\n");
goto again;
}
/*
* Check opcode and sequence number for a match.
* Could be old data getting to us.
*/
if (debug)
"Received sequnce number %d, wanted %d\n",
goto again;
}
if (debug)
"Received opcode %d, wanted %d (sequence number okay)\n",
goto again;
}
/*
* Check the error code. If non-zero, return it.
*/
int errcode;
printf("Error code %d received on not-final packet\n",
errcode);
}
if (errcode == CERR_UNSPEC)
return ERR_UNSPEC;
return errcode;
}
/*
* Check the association ID to make sure it matches what
* we sent.
*/
if (debug)
printf("Association ID %d doesn't match expected %d\n",
/*
* Hack for silly fuzzballs which, at the time of writing,
* return an assID of sys.peer when queried for system variables.
*/
#ifdef notdef
goto again;
#endif
}
/*
* Collect offset and count. Make sure they make sense.
*/
if (debug >= 3) {
int shouldbesize;
int maclen;
/*
* Usually we ignore authentication, but for debugging purposes
* we watch it here.
*/
/* round to 8 octet boundary */
if (n & 0x3) {
printf("Packet not padded, size = %d\n", n);
"Packet shows signs of authentication (total %d, data %d, mac %d)\n",
n, shouldbesize, maclen);
printf("%08lx %08lx %08lx %08lx %08lx %08lx\n",
printf("We don't know that key\n");
} else {
(n - maclen))) {
printf("Auth okay!\n");
} else {
printf("Auth failed!\n");
}
}
}
}
if (debug >= 2)
printf("Got packet, size = %d\n", n);
if (debug)
"Received count of %d octets, data in packet is %d\n",
count, n-CTL_HEADER_LEN);
goto again;
}
if (debug)
printf("Received count of 0 in non-final fragment\n");
goto again;
}
if (debug)
printf("Offset %d, count %d, too big for buffer\n",
return ERR_TOOMUCH;
}
if (debug)
printf("Received second last fragment packet\n");
goto again;
}
/*
* So far, so good. Record this fragment, making sure it doesn't
* overlap anything.
*/
if (debug >= 2)
printf("Packet okay\n");;
if (debug)
printf("Number of fragments exceeds maximum\n");
return ERR_TOOMUCH;
}
for (n = 0; n < numfrags; n++) {
goto again; /* duplicate */
break;
}
goto overlap;
goto overlap;
{
register int i;
for (i = numfrags; i > n; i--) {
}
}
numfrags++;
/*
* Got that stuffed in right. Figure out if this was the last.
* Record status info out of the last packet.
*/
seenlastfrag = 1;
if (rstatus != 0)
}
/*
* Copy the data into the data buffer.
*/
/*
* If we've seen the last fragment, look for holes in the sequence.
* If there aren't any, we're done.
*/
if (seenlastfrag && offsets[0] == 0) {
for (n = 1; n < numfrags; n++) {
break;
}
if (n == numfrags) {
return 0;
}
}
goto again;
/*
* Print debugging message about overlapping fragments
*/
if (debug)
printf("Overlapping fragments returned in response\n");
goto again;
}
/*
* sendrequest - format and send a request packet
*/
static int
int opcode;
int associd;
int auth;
int qsize;
char *qdata;
{
struct ntp_control qpkt;
int pktsize;
/*
* Check to make sure the data will fit in one packet
*/
if (qsize > CTL_MAX_DATA_LEN) {
"***Internal error! qsize (%d) too large\n",
qsize);
return 1;
}
/*
* Fill in the packet
*/
/*
* If we have data, copy it in and pad it out to a 64
* bit boundary.
*/
if (qsize > 0) {
pktsize++;
}
} else {
}
/*
* If it isn't authenticated we can just send it. Otherwise
* we're going to have to think about it a little.
*/
if (!auth && !always_auth) {
} else {
char *pass;
/*
* Pad out packet to a multiple of 8 octets to be sure
* receiver can handle it.
*/
while (pktsize & 7) {
pktsize++;
}
/*
* Get the keyid and the password if we don't have one.
*/
if (info_auth_keyid == -1) {
if (info_auth_keyid == -1) {
"Keyid must be defined, request not sent\n");
return 1;
}
}
if (!auth_havekey(info_auth_keyid)) {
? "DES Password: "
: "MD5 Password: "
);
if (*pass != '\0')
}
if (auth_havekey(info_auth_keyid)) {
int maclen;
/*
* Stick the keyid in the packet where
* cp currently points. Cp should be aligned
* properly. Then do the encryptions.
*/
pktsize);
} else {
"No password, request not sent\n");
return 1;
}
}
/*NOTREACHED*/
}
/*
* doquery - send a request and process the response
*/
int
int opcode;
int associd;
int auth;
int qsize;
char *qdata;
int *rsize;
char **rdata;
{
int res;
int done;
/*
* Check to make sure host is open
*/
if (!havehost) {
return -1;
}
done = 0;
sequence++;
/*
* send a request
*/
if (res != 0)
return res;
/*
* Get the response. If we got a standard error, print a message
*/
if (res > 0) {
if (res == ERR_INCOMPLETE) {
/*
* better bump the sequence so we don't
* get confused about differing fragments.
*/
sequence++;
}
done = 1;
goto again;
}
switch(res) {
case CERR_BADFMT:
"***Server reports a bad format request packet\n");
break;
case CERR_PERMISSION:
"***Server disallowed request (authentication?)\n");
break;
case CERR_BADOP:
"***Server reports a bad opcode in request\n");
break;
case CERR_BADASSOC:
"***Association ID %d unknown to server\n",associd);
break;
case CERR_UNKNOWNVAR:
"***A request variable was unknown to the server\n");
break;
case CERR_BADVALUE:
"***Server indicates a request variable was bad\n");
break;
case ERR_UNSPEC:
"***Server returned an unspecified error\n");
break;
case ERR_TIMEOUT:
break;
case ERR_INCOMPLETE:
"***Response from server was incomplete\n");
break;
case ERR_TOOMUCH:
"***Buffer size exceeded for returned data\n");
break;
default:
"***Server returns unknown error code %d\n", res);
break;
}
}
return res;
}
/*
* getcmds - read commands from the standard input and execute them
*/
static void
getcmds()
{
for (;;) {
if (interactive) {
#ifdef VMS /* work around a problem with mixing stdout & stderr */
#endif
}
return;
}
}
/*
* abortcmd - catch interrupts and abort the current command
*/
static RETSIGTYPE
int sig;
{
if (current_output == stdout)
}
/*
* docmd - decode the command line and execute a command
*/
static void
char *cmdline;
{
int ntok;
static int i;
/*
* Tokenize the command line. If nothing on it, return.
*/
if (ntok == 0)
return;
/*
* Find the appropriate command description.
*/
if (i == 0) {
tokens[0]);
return;
} else if (i >= 2) {
tokens[0]);
return;
}
/*
* Save the keyword, then walk through the arguments, interpreting
* as we go.
*/
if ((i+1) >= ntok) {
return;
}
break;
}
break;
return;
}
i++;
char *fname;
else if ((i+1) < ntok)
else {
return;
}
if (current_output == NULL) {
perror("");
return;
}
i = 1; /* flag we need a close */
} else {
i = 0; /* flag no close */
}
jump = 0;
return;
} else {
jump++;
jump = 0; /* HMS: 961106: was after fclose() */
if (i) (void) fclose(current_output);
}
}
/*
* tokenize - turn a command line into tokens
*/
static void
char *line;
char **tokens;
int *ntok;
{
register char *cp;
register char *sp;
"***Error. Command (length=%d) is too long.\n",
cmdlen);
exit(1);
}
cp++;
break;
do {
*sp++ = '\0';
}
}
/*
* findcmd - find a command in a command description table
*/
static int
register char *str;
{
register int clen;
int nmatch;
nmatch = 0;
if (clist1 != 0)
else if (clist2 != 0)
else
return 0;
/* do a first character check, for efficiency */
continue;
/*
* Could be extact match, could be approximate.
* Is exact if the length of the keyword is the
* same as the str.
*/
return 1;
}
nmatch++;
}
}
/*
* See if there is more to do. If so, go again. Sorry about the
* goto, too much looking at BSD sources...
*/
goto again;
}
/*
* If we got extactly 1 near match, use it, else return number
* of matches.
*/
if (nmatch == 1) {
return 1;
}
return nmatch;
}
/*
* getarg - interpret an argument token
*/
static int
char *str;
int code;
{
int isneg;
static const char *digits = "0123456789";
case STR:
break;
case ADD:
return 0;
}
break;
case INT:
case UINT:
isneg = 0;
if (*np == '&') {
np++;
if (isneg <= 0) {
"***Association value `%s' invalid/undecodable\n", str);
return 0;
}
"***Association for `%s' unknown (max &%d)\n",
return 0;
}
break;
}
if (*np == '-') {
np++;
isneg = 1;
}
do {
"***Illegal integer value %s\n", str);
return 0;
}
} while (*(++np) != '\0');
if (isneg) {
"***Value %s should be unsigned\n", str);
return 0;
}
}
break;
}
return 1;
}
/*
* getnetnum - given a host name, return its net number
* and (optional) full name
*/
int
char *host;
char *fullhost;
{
if (fullhost != 0) {
}
return 1;
if (fullhost != 0)
return 1;
} else {
return 0;
}
/*NOTREACHED*/
}
/*
* nntohost - convert network number to host name. This routine enforces
* the showhostnames setting.
*/
char *
{
if (!showhostnames)
}
/*
* rtdatetolfp - decode an RT-11 date into an l_fp
*/
static int
char *str;
{
register char *cp;
register int i;
char buf[4];
static const char *months[12] = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
/*
* An RT-11 date looks like:
*
* d[d]-Mth-y[y] hh:mm:ss
*/
if (*cp == '-') {
/*
* Catch special case
*/
return 1;
}
return 0;
}
}
if (*cp++ != '-')
return 0;
for (i = 0; i < 3; i++)
for (i = 0; i < 12; i++)
break;
if (i == 12)
return 0;
if (*cp++ != '-')
return 0;
return 0;
}
/*
* Catch special case. If cal.year == 0 this is a zero timestamp.
*/
return 1;
}
return 0;
}
return 0;
}
return 0;
}
return 1;
}
/*
* decodets - decode a timestamp into an l_fp format number, with
* consideration of fuzzball formats.
*/
int
char *str;
{
/*
* If it starts with a 0x, decode as hex.
*/
/*
* If it starts with a '"', try it as an RT-11 date.
*/
if (*str == '"') {
register char *bp;
char buf[30];
*bp = '\0';
}
/*
* Might still be hex. Check out the first character. Talk
* about heuristics!
*/
/*
* Try it as a decimal. If this fails, try as an unquoted
* RT-11 date. This code should go away eventually.
*/
return 1;
}
/*
* decodetime - decode a time value. It should be in milliseconds
*/
int
char *str;
{
}
/*
* decodeint - decode an integer
*/
int
char *str;
long *val;
{
if (*str == '0') {
}
}
/*
* decodeuint - decode an unsigned integer
*/
int
char *str;
{
if (*str == '0') {
}
}
/*
* decodearr - decode an array of time values
*/
static int
char *str;
int *narr;
{
char buf[60];
*narr = 0;
while (*narr < 8) {
cp++;
if (*cp == '\0')
break;
*bp++ = '\0';
return 0;
(*narr)++;
lfp++;
}
return 1;
}
/*
* Finally, the built in command handlers
*/
/*
* help - tell about commands, or details of a particular command
*/
static void
{
int i;
int n;
char *cmd;
const char *cmdsort[100];
int length[100];
int maxlength;
int numperline;
n = 0;
}
#ifdef QSORT_USES_VOID_P
#else
#endif
maxlength = 0;
for (i = 0; i < n; i++) {
}
maxlength++;
for (i = 0; i < n; i++) {
|| i == (n-1))
else
}
} else {
if (n == 0) {
"Command `%s' is unknown\n", cmd);
return;
} else if (n >= 2) {
"Command `%s' is ambiguous\n", cmd);
return;
}
}
}
/*
* helpsort - do hostname qsort comparisons
*/
static int
#ifdef QSORT_USES_VOID_P
const void *t1;
const void *t2;
{
#else
char **name1;
char **name2;
{
#endif /* sgi || bsdi */
}
/*
* printusage - print usage information for a command
*/
static void
{
register int i;
else
}
}
/*
* timeout - set time out time
*/
static void
{
int val;
} else {
* 1000;
}
}
/*
* delay - set delay for auth requests
*/
static void
{
int isneg;
} else {
isneg = 1;
} else {
isneg = 0;
}
val %= 1000;
if (isneg)
L_NEG(&delay_time);
}
}
/*
* host - set the host we are dealing with.
*/
static void
{
if (havehost)
else
numassoc = 0;
} else {
if (havehost)
"current host remains %s\n", currenthost);
else
}
}
/*
* poll - do one (or more) polls of the host via NTP
*/
/*ARGSUSED*/
static void
{
}
/*
* keyid - get a keyid to use for authenticating requests
*/
static void
{
if (info_auth_keyid == -1)
else
} else {
}
}
/*
* keytype - get type of key to use for authenticating requests
*/
static void
{
else
case 'm':
case 'M':
break;
case 'd':
case 'D':
break;
default:
}
}
/*
* passwd - get an authentication key
*/
/*ARGSUSED*/
static void
{
char *pass;
if (info_auth_keyid == -1) {
if (info_auth_keyid == -1) {
return;
}
}
? "DES Password: "
: "MD5 Password: "
);
if (*pass == '\0')
else
}
/*
* hostnames - set the showhostnames flag
*/
static void
{
if (showhostnames)
else
} else {
showhostnames = 1;
showhostnames = 0;
else
}
}
/*
*/
static void
{
return;
debug = 0;
debug++;
debug--;
} else {
return;
}
}
/*
* quit - stop this nonsense
*/
/*ARGSUSED*/
static void
{
if (havehost)
exit(0);
}
/*
* version - print the current version number
*/
/*ARGSUSED*/
static void
{
extern char *Version;
}
/*
* raw - set raw mode output
*/
/*ARGSUSED*/
static void
{
rawmode = 1;
}
/*
* cooked - set cooked mode output
*/
/*ARGSUSED*/
static void
{
rawmode = 0;
return;
}
/*
* authenticate - always authenticate requests to this host
*/
static void
{
if (always_auth) {
"authenticated requests being sent\n");
} else
"unauthenticated requests being sent\n");
} else {
always_auth = 1;
always_auth = 0;
} else
}
}
/*
* ntpversion - choose the NTP version to use
*/
static void
{
"NTP version being claimed is %d\n", pktversion);
} else {
} else {
}
}
}
/*
* warning - print a warning message
*/
static void
char *fmt;
char *st1;
char *st2;
{
perror("");
}
/*
* error - print a message and exit
*/
static void
char *fmt;
char *st1;
char *st2;
{
exit(1);
}
/*
* getkeyid - prompt the user for a keyid to use
*/
static u_int32
char *prompt;
{
register char *p;
register int c;
char pbuf[20];
#ifndef SYS_WINNT
#else
#endif /* SYS_WINNT */
else
if (p < &pbuf[18])
*p++ = c;
}
*p = '\0';
return 0;
}
/*
* atoascii - printable-ize possibly ascii data using the character
* transformations cat -v uses.
*/
static void
int length;
char *data;
char *outdata;
{
register u_char c;
if (!data)
{
*outdata = '\0';
return;
}
c = *cp;
if (c == '\0')
break;
if (c == '\0')
break;
if (c > 0177) {
*ocp++ = 'M';
*ocp++ = '-';
c &= 0177;
}
if (c < ' ') {
*ocp++ = '^';
*ocp++ = c + '@';
} else if (c == 0177) {
*ocp++ = '^';
*ocp++ = '?';
} else {
*ocp++ = c;
}
break;
}
*ocp++ = '\0';
}
/*
* makeascii - print possibly ascii data using the character
* transformations that cat -v uses.
*/
static void
int length;
char *data;
{
register int c;
c = (int)*cp;
if (c > 0177) {
c &= 0177;
}
if (c < ' ') {
} else if (c == 0177) {
} else {
}
}
}
/*
* asciize - same thing as makeascii except add a newline
*/
void
int length;
char *data;
{
}
/*
* Some circular buffer space
*/
#define CBLEN 80
#define NUMCB 6
int nextcb = 0;
/*
* nextvar - find the next variable in the buffer
*/
int
int *datalen;
char **datap;
char **vname;
char **vvalue;
{
register char *cp;
register char *np;
register char *cpend;
register char *npend; /* character after last */
int quoted = 0;
/*
* Space past commas and white space
*/
cp++;
return 0;
/*
* Copy name until we hit a ',', an '=', a '\r' or a '\n'. Backspace
* over any white space and terminate it.
*/
/*
* Check if we ran out of name space, without reaching the end or a
* terminating character
*/
return 0;
np--;
*np = '\0';
/*
* Check if we hit the end of the buffer or a ','. If so we are done.
*/
cp++;
*vvalue = (char *)0;
return 1;
}
/*
* So far, so good. Copy out the value
*/
cp++; /* past '=' */
cp++;
{
}
/*
* Check if we overran the value buffer while still in a quoted string
* or without finding a comma
*/
return 0;
/*
* Trim off any trailing whitespace
*/
np--;
*np = '\0';
/*
* Return this. All done.
*/
cp++;
return 1;
}
/*
* findvar - see if this variable is known to us
*/
int
char *varname;
{
register char *np;
vl++;
}
return 0;
}
/*
* printvars - print variables returned in response packet
*/
void
int length;
char *data;
int status;
int sttype;
{
if (rawmode)
else
}
/*
* rawprint - do a printout of the data in raw mode
*/
static void
int datatype;
int length;
char *data;
int status;
{
register char *cp;
register char *cpend;
/*
* Essentially print the data as is. We reformat unprintables, though.
*/
if (*cp == '\r') {
/*
* If this is a \r and the next character is a
* \n, supress this, else pretty print it. Otherwise
* just output the character.
*/
} else {
}
cp++;
}
}
/*
* Global data used by the cooked output routines
*/
int out_chars; /* number of characters output */
int out_linecount; /* number of characters output on this line */
/*
* startoutput - get ready to do cooked output
*/
static void
{
out_chars = 0;
out_linecount = 0;
}
/*
* output - output a variable=value combination
*/
static void
char *name;
char *value;
{
int lenname;
int lenvalue;
if (out_chars != 0) {
out_chars++;
out_chars++;
out_linecount = 0;
} else {
out_chars++;
}
}
}
/*
* endoutput - terminate a block of cooked output
*/
static void
{
if (out_chars != 0)
}
/*
* outputarr - output an array of values
*/
static void
char *name;
int narr;
{
register char *bp;
register char *cp;
register int i;
register int len;
char buf[256];
/*
* Hack to align delay and offset values
*/
*bp++ = ' ';
for (i = narr; i > 0; i--) {
if (i != narr)
*bp++ = ' ';
while (len < 7) {
*bp++ = ' ';
len++;
}
while (*cp != '\0')
lfp++;
}
*bp = '\0';
}
static char *
{
register char *cb, *s;
register int i;
register char *sep;
sep = "";
i = 0;
nextcb = 0;
if (!val) {
} else {
*cb++ = '<';
while (val) {
if (val & 0x1) {
sep = ";";
}
i++;
val >>= 1;
}
*cb++ = '>';
}
} else {
*cb++ = '?';
}
*cb = '\0';
return s;
}
/*
* cookedprint - output variables in cooked mode
*/
static void
int datatype;
int length;
char *data;
int status;
{
register int varid;
char *name;
char *value;
int output_raw;
int fmt;
long ival;
int narr;
switch (datatype) {
case TYPE_PEER:
break;
case TYPE_SYS:
break;
case TYPE_CLOCK:
break;
default:
return;
}
startoutput();
if (varid == 0) {
output_raw = '*';
} else {
output_raw = 0;
case TS:
output_raw = '?';
else
break;
case FL:
case FU:
case FS:
output_raw = '?';
else {
switch (fmt) {
case FL:
break;
case FU:
break;
case FS:
break;
}
}
break;
case UI:
output_raw = '?';
else
break;
case SI:
output_raw = '?';
else
break;
case HA:
case NA:
output_raw = '?';
else
break;
case ST:
output_raw = '*';
break;
case RF:
else
output_raw = '?';
break;
case LP:
output_raw = '?';
else {
char b[3];
b[0] = b[1] = '0';
if (uval & 0x2)
b[0] = '1';
if (uval & 0x1)
b[1] = '1';
b[2] = '\0';
}
break;
case OC:
output_raw = '?';
else {
char b[10];
}
break;
case MD:
output_raw = '?';
else
break;
case AR:
output_raw = '?';
else
break;
case TST:
output_raw = '?';
else
break;
default:
"Internal error in cookedprint, %s=%s, fmt %d\n",
break;
}
}
if (output_raw != 0) {
char bn[401];
char bv[401];
int len;
if (output_raw != '*') {
}
}
}
}
/*
* sortassoc - sort associations in the cache into ascending order
*/
void
{
if (numassoc > 1)
#ifdef QSORT_USES_VOID_P
sizeof(struct association), assoccmp);
#else
sizeof(struct association), assoccmp);
#endif
}
/*
* assoccmp - compare two associations
*/
static int
#ifdef QSORT_USES_VOID_P
const void *t1;
const void *t2;
{
#else
struct association *ass1;
struct association *ass2;
{
#endif /* not QSORT_USES_VOID_P */
return -1;
return 1;
return 0;
}