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