PageRenderTime 44ms CodeModel.GetById 2ms RepoModel.GetById 0ms app.codeStats 1ms

/contrib/ntp/ntpq/ntpq.c

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