/usr.bin/tftp/main.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 1054 lines · 869 code · 120 blank · 65 comment · 209 complexity · 415be53676a36967f392ad4e478e032e MD5 · raw file

  1. /*
  2. * Copyright (c) 1983, 1993
  3. * The Regents of the University of California. All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. * 4. Neither the name of the University nor the names of its contributors
  14. * may be used to endorse or promote products derived from this software
  15. * without specific prior written permission.
  16. *
  17. * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  18. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  19. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  20. * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  21. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  22. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  23. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  24. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  25. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  26. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  27. * SUCH DAMAGE.
  28. */
  29. #ifndef lint
  30. static const char copyright[] =
  31. "@(#) Copyright (c) 1983, 1993\n\
  32. The Regents of the University of California. All rights reserved.\n";
  33. #endif
  34. #if 0
  35. #ifndef lint
  36. static char sccsid[] = "@(#)main.c 8.1 (Berkeley) 6/6/93";
  37. #endif
  38. #endif
  39. #include <sys/cdefs.h>
  40. __FBSDID("$FreeBSD$");
  41. /* Many bug fixes are from Jim Guyton <guyton@rand-unix> */
  42. /*
  43. * TFTP User Program -- Command Interface.
  44. */
  45. #include <sys/param.h>
  46. #include <sys/types.h>
  47. #include <sys/socket.h>
  48. #include <sys/sysctl.h>
  49. #include <sys/file.h>
  50. #include <sys/stat.h>
  51. #include <netinet/in.h>
  52. #include <arpa/inet.h>
  53. #include <arpa/tftp.h>
  54. #include <ctype.h>
  55. #include <err.h>
  56. #include <histedit.h>
  57. #include <netdb.h>
  58. #include <setjmp.h>
  59. #include <signal.h>
  60. #include <stdio.h>
  61. #include <stdlib.h>
  62. #include <string.h>
  63. #include <unistd.h>
  64. #include "tftp-utils.h"
  65. #include "tftp-io.h"
  66. #include "tftp-options.h"
  67. #include "tftp.h"
  68. #define MAXLINE 200
  69. #define TIMEOUT 5 /* secs between rexmt's */
  70. typedef struct sockaddr_storage peeraddr;
  71. static int connected;
  72. static char mode[32];
  73. jmp_buf toplevel;
  74. volatile int txrx_error;
  75. static int peer;
  76. #define MAX_MARGV 20
  77. static int margc;
  78. static char *margv[MAX_MARGV];
  79. int verbose;
  80. char *port = NULL;
  81. static void get(int, char **);
  82. static void help(int, char **);
  83. static void intr(int);
  84. static void modecmd(int, char **);
  85. static void put(int, char **);
  86. static void quit(int, char **);
  87. static void setascii(int, char **);
  88. static void setbinary(int, char **);
  89. static void setpeer0(char *, const char *);
  90. static void setpeer(int, char **);
  91. static void settimeoutpacket(int, char **);
  92. static void settimeoutnetwork(int, char **);
  93. static void setdebug(int, char **);
  94. static void setverbose(int, char **);
  95. static void showstatus(int, char **);
  96. static void setblocksize(int, char **);
  97. static void setblocksize2(int, char **);
  98. static void setoptions(int, char **);
  99. static void setrollover(int, char **);
  100. static void setpacketdrop(int, char **);
  101. static void command(void) __dead2;
  102. static const char *command_prompt(void);
  103. static void urihandling(char *URI);
  104. static void getusage(char *);
  105. static void makeargv(char *line);
  106. static void putusage(char *);
  107. static void settftpmode(const char *);
  108. static char *tail(char *);
  109. static struct cmd *getcmd(char *);
  110. #define HELPINDENT (sizeof("connect"))
  111. struct cmd {
  112. const char *name;
  113. void (*handler)(int, char **);
  114. const char *help;
  115. };
  116. static struct cmd cmdtab[] = {
  117. { "connect", setpeer, "connect to remote tftp" },
  118. { "mode", modecmd, "set file transfer mode" },
  119. { "put", put, "send file" },
  120. { "get", get, "receive file" },
  121. { "quit", quit, "exit tftp" },
  122. { "verbose", setverbose, "toggle verbose mode" },
  123. { "status", showstatus, "show current status" },
  124. { "binary", setbinary, "set mode to octet" },
  125. { "ascii", setascii, "set mode to netascii" },
  126. { "rexmt", settimeoutpacket,
  127. "set per-packet retransmission timeout[-]" },
  128. { "timeout", settimeoutnetwork,
  129. "set total retransmission timeout" },
  130. { "trace", setdebug, "enable 'debug packet'[-]" },
  131. { "debug", setdebug, "enable verbose output" },
  132. { "blocksize", setblocksize, "set blocksize[*]" },
  133. { "blocksize2", setblocksize2, "set blocksize as a power of 2[**]" },
  134. { "rollover", setrollover, "rollover after 64K packets[**]" },
  135. { "options", setoptions,
  136. "enable or disable RFC2347 style options" },
  137. { "help", help, "print help information" },
  138. { "packetdrop", setpacketdrop, "artificial packetloss feature" },
  139. { "?", help, "print help information" },
  140. { NULL, NULL, NULL }
  141. };
  142. static struct modes {
  143. const char *m_name;
  144. const char *m_mode;
  145. } modes[] = {
  146. { "ascii", "netascii" },
  147. { "netascii", "netascii" },
  148. { "binary", "octet" },
  149. { "image", "octet" },
  150. { "octet", "octet" },
  151. { NULL, NULL }
  152. };
  153. int
  154. main(int argc, char *argv[])
  155. {
  156. acting_as_client = 1;
  157. peer = -1;
  158. strcpy(mode, "netascii");
  159. signal(SIGINT, intr);
  160. if (argc > 1) {
  161. if (setjmp(toplevel) != 0)
  162. exit(txrx_error);
  163. if (strncmp(argv[1], "tftp://", 7) == 0) {
  164. urihandling(argv[1]);
  165. exit(txrx_error);
  166. }
  167. setpeer(argc, argv);
  168. }
  169. if (setjmp(toplevel) != 0)
  170. (void)putchar('\n');
  171. init_options();
  172. command();
  173. }
  174. /*
  175. * RFC3617 handling of TFTP URIs:
  176. *
  177. * tftpURI = "tftp://" host "/" file [ mode ]
  178. * mode = ";" "mode=" ( "netascii" / "octet" )
  179. * file = *( unreserved / escaped )
  180. * host = <as specified by RFC 2732>
  181. * unreserved = <as specified in RFC 2396>
  182. * escaped = <as specified in RFC 2396>
  183. *
  184. * We are cheating a little bit by allowing any mode as specified in the
  185. * modes table defined earlier on in this file and mapping it on the real
  186. * mode.
  187. */
  188. static void
  189. urihandling(char *URI)
  190. {
  191. char uri[ARG_MAX];
  192. char *host = NULL;
  193. char *path = NULL;
  194. char *opts = NULL;
  195. const char *tmode = "octet";
  196. char *s;
  197. char line[MAXLINE];
  198. int i;
  199. strncpy(uri, URI, ARG_MAX);
  200. host = uri + 7;
  201. if ((s = strchr(host, '/')) == NULL) {
  202. fprintf(stderr,
  203. "Invalid URI: Couldn't find / after hostname\n");
  204. exit(1);
  205. }
  206. *s = '\0';
  207. path = s + 1;
  208. if ((s = strchr(path, ';')) != NULL) {
  209. *s = '\0';
  210. opts = s + 1;
  211. if (strncmp(opts, "mode=", 5) == 0) {
  212. tmode = opts;
  213. tmode += 5;
  214. for (i = 0; modes[i].m_name != NULL; i++) {
  215. if (strcmp(modes[i].m_name, tmode) == 0)
  216. break;
  217. }
  218. if (modes[i].m_name == NULL) {
  219. fprintf(stderr, "Invalid mode: '%s'\n", mode);
  220. exit(1);
  221. }
  222. settftpmode(modes[i].m_mode);
  223. }
  224. } else {
  225. settftpmode("octet");
  226. }
  227. setpeer0(host, NULL);
  228. sprintf(line, "get %s", path);
  229. makeargv(line);
  230. get(margc, margv);
  231. }
  232. static char hostname[MAXHOSTNAMELEN];
  233. static void
  234. setpeer0(char *host, const char *lport)
  235. {
  236. struct addrinfo hints, *res0, *res;
  237. int error;
  238. const char *cause = "unknown";
  239. if (connected) {
  240. close(peer);
  241. peer = -1;
  242. }
  243. connected = 0;
  244. memset(&hints, 0, sizeof(hints));
  245. hints.ai_family = PF_UNSPEC;
  246. hints.ai_socktype = SOCK_DGRAM;
  247. hints.ai_protocol = IPPROTO_UDP;
  248. hints.ai_flags = AI_CANONNAME;
  249. if (!lport)
  250. lport = "tftp";
  251. error = getaddrinfo(host, lport, &hints, &res0);
  252. if (error) {
  253. warnx("%s", gai_strerror(error));
  254. return;
  255. }
  256. for (res = res0; res; res = res->ai_next) {
  257. if (res->ai_addrlen > sizeof(peeraddr))
  258. continue;
  259. peer = socket(res->ai_family, res->ai_socktype,
  260. res->ai_protocol);
  261. if (peer < 0) {
  262. cause = "socket";
  263. continue;
  264. }
  265. memset(&peer_sock, 0, sizeof(peer_sock));
  266. peer_sock.ss_family = res->ai_family;
  267. peer_sock.ss_len = res->ai_addrlen;
  268. if (bind(peer, (struct sockaddr *)&peer_sock, peer_sock.ss_len) < 0) {
  269. cause = "bind";
  270. close(peer);
  271. peer = -1;
  272. continue;
  273. }
  274. break;
  275. }
  276. if (peer < 0)
  277. warn("%s", cause);
  278. else {
  279. /* res->ai_addr <= sizeof(peeraddr) is guaranteed */
  280. memcpy(&peer_sock, res->ai_addr, res->ai_addrlen);
  281. if (res->ai_canonname) {
  282. (void) strncpy(hostname, res->ai_canonname,
  283. sizeof(hostname));
  284. } else
  285. (void) strncpy(hostname, host, sizeof(hostname));
  286. hostname[sizeof(hostname)-1] = 0;
  287. connected = 1;
  288. }
  289. freeaddrinfo(res0);
  290. }
  291. static void
  292. setpeer(int argc, char *argv[])
  293. {
  294. char line[MAXLINE];
  295. if (argc < 2) {
  296. strcpy(line, "Connect ");
  297. printf("(to) ");
  298. fgets(&line[strlen(line)], sizeof line - strlen(line), stdin);
  299. makeargv(line);
  300. argc = margc;
  301. argv = margv;
  302. }
  303. if ((argc < 2) || (argc > 3)) {
  304. printf("usage: %s [host [port]]\n", argv[0]);
  305. return;
  306. }
  307. if (argc == 3) {
  308. port = argv[2];
  309. setpeer0(argv[1], argv[2]);
  310. } else
  311. setpeer0(argv[1], NULL);
  312. }
  313. static void
  314. modecmd(int argc, char *argv[])
  315. {
  316. struct modes *p;
  317. const char *sep;
  318. if (argc < 2) {
  319. printf("Using %s mode to transfer files.\n", mode);
  320. return;
  321. }
  322. if (argc == 2) {
  323. for (p = modes; p->m_name; p++)
  324. if (strcmp(argv[1], p->m_name) == 0)
  325. break;
  326. if (p->m_name) {
  327. settftpmode(p->m_mode);
  328. return;
  329. }
  330. printf("%s: unknown mode\n", argv[1]);
  331. /* drop through and print usage message */
  332. }
  333. printf("usage: %s [", argv[0]);
  334. sep = " ";
  335. for (p = modes; p->m_name != NULL; p++) {
  336. printf("%s%s", sep, p->m_name);
  337. if (*sep == ' ')
  338. sep = " | ";
  339. }
  340. printf(" ]\n");
  341. return;
  342. }
  343. static void
  344. setbinary(int argc __unused, char *argv[] __unused)
  345. {
  346. settftpmode("octet");
  347. }
  348. static void
  349. setascii(int argc __unused, char *argv[] __unused)
  350. {
  351. settftpmode("netascii");
  352. }
  353. static void
  354. settftpmode(const char *newmode)
  355. {
  356. strcpy(mode, newmode);
  357. if (verbose)
  358. printf("mode set to %s\n", mode);
  359. }
  360. /*
  361. * Send file(s).
  362. */
  363. static void
  364. put(int argc, char *argv[])
  365. {
  366. int fd;
  367. int n;
  368. char *cp, *targ;
  369. char line[MAXLINE];
  370. struct stat sb;
  371. if (argc < 2) {
  372. strcpy(line, "send ");
  373. printf("(file) ");
  374. fgets(&line[strlen(line)], sizeof line - strlen(line), stdin);
  375. makeargv(line);
  376. argc = margc;
  377. argv = margv;
  378. }
  379. if (argc < 2) {
  380. putusage(argv[0]);
  381. return;
  382. }
  383. targ = argv[argc - 1];
  384. if (strrchr(argv[argc - 1], ':')) {
  385. char *lcp;
  386. for (n = 1; n < argc - 1; n++)
  387. if (strchr(argv[n], ':')) {
  388. putusage(argv[0]);
  389. return;
  390. }
  391. lcp = argv[argc - 1];
  392. targ = strrchr(lcp, ':');
  393. *targ++ = 0;
  394. if (lcp[0] == '[' && lcp[strlen(lcp) - 1] == ']') {
  395. lcp[strlen(lcp) - 1] = '\0';
  396. lcp++;
  397. }
  398. setpeer0(lcp, NULL);
  399. }
  400. if (!connected) {
  401. printf("No target machine specified.\n");
  402. return;
  403. }
  404. if (argc < 4) {
  405. cp = argc == 2 ? tail(targ) : argv[1];
  406. fd = open(cp, O_RDONLY);
  407. if (fd < 0) {
  408. warn("%s", cp);
  409. return;
  410. }
  411. stat(cp, &sb);
  412. asprintf(&options[OPT_TSIZE].o_request, "%ju", sb.st_size);
  413. if (verbose)
  414. printf("putting %s to %s:%s [%s]\n",
  415. cp, hostname, targ, mode);
  416. xmitfile(peer, port, fd, targ, mode);
  417. return;
  418. }
  419. /* this assumes the target is a directory */
  420. /* on a remote unix system. hmmmm. */
  421. cp = strchr(targ, '\0');
  422. *cp++ = '/';
  423. for (n = 1; n < argc - 1; n++) {
  424. strcpy(cp, tail(argv[n]));
  425. fd = open(argv[n], O_RDONLY);
  426. if (fd < 0) {
  427. warn("%s", argv[n]);
  428. continue;
  429. }
  430. stat(cp, &sb);
  431. asprintf(&options[OPT_TSIZE].o_request, "%ju", sb.st_size);
  432. if (verbose)
  433. printf("putting %s to %s:%s [%s]\n",
  434. argv[n], hostname, targ, mode);
  435. xmitfile(peer, port, fd, targ, mode);
  436. }
  437. }
  438. static void
  439. putusage(char *s)
  440. {
  441. printf("usage: %s file [remotename]\n", s);
  442. printf(" %s file host:remotename\n", s);
  443. printf(" %s file1 file2 ... fileN [[host:]remote-directory]\n", s);
  444. }
  445. /*
  446. * Receive file(s).
  447. */
  448. static void
  449. get(int argc, char *argv[])
  450. {
  451. int fd;
  452. int n;
  453. char *cp;
  454. char *src;
  455. char line[MAXLINE];
  456. if (argc < 2) {
  457. strcpy(line, "get ");
  458. printf("(files) ");
  459. fgets(&line[strlen(line)], sizeof line - strlen(line), stdin);
  460. makeargv(line);
  461. argc = margc;
  462. argv = margv;
  463. }
  464. if (argc < 2) {
  465. getusage(argv[0]);
  466. return;
  467. }
  468. if (!connected) {
  469. for (n = 1; n < argc ; n++)
  470. if (strrchr(argv[n], ':') == 0) {
  471. printf("No remote host specified and "
  472. "no host given for file '%s'\n", argv[n]);
  473. getusage(argv[0]);
  474. return;
  475. }
  476. }
  477. for (n = 1; n < argc ; n++) {
  478. src = strrchr(argv[n], ':');
  479. if (src == NULL)
  480. src = argv[n];
  481. else {
  482. char *lcp;
  483. *src++ = 0;
  484. lcp = argv[n];
  485. if (lcp[0] == '[' && lcp[strlen(lcp) - 1] == ']') {
  486. lcp[strlen(lcp) - 1] = '\0';
  487. lcp++;
  488. }
  489. setpeer0(lcp, NULL);
  490. if (!connected)
  491. continue;
  492. }
  493. if (argc < 4) {
  494. cp = argc == 3 ? argv[2] : tail(src);
  495. fd = creat(cp, 0644);
  496. if (fd < 0) {
  497. warn("%s", cp);
  498. return;
  499. }
  500. if (verbose)
  501. printf("getting from %s:%s to %s [%s]\n",
  502. hostname, src, cp, mode);
  503. recvfile(peer, port, fd, src, mode);
  504. break;
  505. }
  506. cp = tail(src); /* new .. jdg */
  507. fd = creat(cp, 0644);
  508. if (fd < 0) {
  509. warn("%s", cp);
  510. continue;
  511. }
  512. if (verbose)
  513. printf("getting from %s:%s to %s [%s]\n",
  514. hostname, src, cp, mode);
  515. recvfile(peer, port, fd, src, mode);
  516. }
  517. }
  518. static void
  519. getusage(char *s)
  520. {
  521. printf("usage: %s file [localname]\n", s);
  522. printf(" %s [host:]file [localname]\n", s);
  523. printf(" %s [host1:]file1 [host2:]file2 ... [hostN:]fileN\n", s);
  524. }
  525. static void
  526. settimeoutpacket(int argc, char *argv[])
  527. {
  528. int t;
  529. char line[MAXLINE];
  530. if (argc < 2) {
  531. strcpy(line, "Packet timeout ");
  532. printf("(value) ");
  533. fgets(&line[strlen(line)], sizeof line - strlen(line), stdin);
  534. makeargv(line);
  535. argc = margc;
  536. argv = margv;
  537. }
  538. if (argc != 2) {
  539. printf("usage: %s value\n", argv[0]);
  540. return;
  541. }
  542. t = atoi(argv[1]);
  543. if (t < 0) {
  544. printf("%s: bad value\n", argv[1]);
  545. return;
  546. }
  547. settimeouts(t, timeoutnetwork, maxtimeouts);
  548. }
  549. static void
  550. settimeoutnetwork(int argc, char *argv[])
  551. {
  552. int t;
  553. char line[MAXLINE];
  554. if (argc < 2) {
  555. strcpy(line, "Network timeout ");
  556. printf("(value) ");
  557. fgets(&line[strlen(line)], sizeof line - strlen(line), stdin);
  558. makeargv(line);
  559. argc = margc;
  560. argv = margv;
  561. }
  562. if (argc != 2) {
  563. printf("usage: %s value\n", argv[0]);
  564. return;
  565. }
  566. t = atoi(argv[1]);
  567. if (t < 0) {
  568. printf("%s: bad value\n", argv[1]);
  569. return;
  570. }
  571. settimeouts(timeoutpacket, t, maxtimeouts);
  572. }
  573. static void
  574. showstatus(int argc __unused, char *argv[] __unused)
  575. {
  576. printf("Remote host: %s\n",
  577. connected ? hostname : "none specified yet");
  578. printf("RFC2347 Options support: %s\n",
  579. options_rfc_enabled ? "enabled" : "disabled");
  580. printf("Non-RFC defined options support: %s\n",
  581. options_extra_enabled ? "enabled" : "disabled");
  582. printf("Mode: %s\n", mode);
  583. printf("Verbose: %s\n", verbose ? "on" : "off");
  584. printf("Debug: %s\n", debug_show(debug));
  585. printf("Artificial packetloss: %d in 100 packets\n",
  586. packetdroppercentage);
  587. printf("Segment size: %d bytes\n", segsize);
  588. printf("Network timeout: %d seconds\n", timeoutpacket);
  589. printf("Maximum network timeout: %d seconds\n", timeoutnetwork);
  590. printf("Maximum timeouts: %d \n", maxtimeouts);
  591. }
  592. static void
  593. intr(int dummy __unused)
  594. {
  595. signal(SIGALRM, SIG_IGN);
  596. alarm(0);
  597. longjmp(toplevel, -1);
  598. }
  599. static char *
  600. tail(char *filename)
  601. {
  602. char *s;
  603. while (*filename) {
  604. s = strrchr(filename, '/');
  605. if (s == NULL)
  606. break;
  607. if (s[1])
  608. return (s + 1);
  609. *s = '\0';
  610. }
  611. return (filename);
  612. }
  613. static const char *
  614. command_prompt(void)
  615. {
  616. return ("tftp> ");
  617. }
  618. /*
  619. * Command parser.
  620. */
  621. static void
  622. command(void)
  623. {
  624. HistEvent he;
  625. struct cmd *c;
  626. static EditLine *el;
  627. static History *hist;
  628. const char *bp;
  629. char *cp;
  630. int len, num, vrbose;
  631. char line[MAXLINE];
  632. vrbose = isatty(0);
  633. if (vrbose) {
  634. el = el_init("tftp", stdin, stdout, stderr);
  635. hist = history_init();
  636. history(hist, &he, H_SETSIZE, 100);
  637. el_set(el, EL_HIST, history, hist);
  638. el_set(el, EL_EDITOR, "emacs");
  639. el_set(el, EL_PROMPT, command_prompt);
  640. el_set(el, EL_SIGNAL, 1);
  641. el_source(el, NULL);
  642. }
  643. for (;;) {
  644. if (vrbose) {
  645. if ((bp = el_gets(el, &num)) == NULL || num == 0)
  646. exit(0);
  647. len = (num > MAXLINE) ? MAXLINE : num;
  648. memcpy(line, bp, len);
  649. line[len] = '\0';
  650. history(hist, &he, H_ENTER, bp);
  651. } else {
  652. line[0] = 0;
  653. if (fgets(line, sizeof line , stdin) == NULL) {
  654. if (feof(stdin)) {
  655. exit(txrx_error);
  656. } else {
  657. continue;
  658. }
  659. }
  660. }
  661. if ((cp = strchr(line, '\n')))
  662. *cp = '\0';
  663. if (line[0] == 0)
  664. continue;
  665. makeargv(line);
  666. if (margc == 0)
  667. continue;
  668. c = getcmd(margv[0]);
  669. if (c == (struct cmd *)-1) {
  670. printf("?Ambiguous command\n");
  671. continue;
  672. }
  673. if (c == 0) {
  674. printf("?Invalid command\n");
  675. continue;
  676. }
  677. (*c->handler)(margc, margv);
  678. }
  679. }
  680. static struct cmd *
  681. getcmd(char *name)
  682. {
  683. const char *p, *q;
  684. struct cmd *c, *found;
  685. int nmatches, longest;
  686. longest = 0;
  687. nmatches = 0;
  688. found = 0;
  689. for (c = cmdtab; (p = c->name) != NULL; c++) {
  690. for (q = name; *q == *p++; q++)
  691. if (*q == 0) /* exact match? */
  692. return (c);
  693. if (!*q) { /* the name was a prefix */
  694. if (q - name > longest) {
  695. longest = q - name;
  696. nmatches = 1;
  697. found = c;
  698. } else if (q - name == longest)
  699. nmatches++;
  700. }
  701. }
  702. if (nmatches > 1)
  703. return ((struct cmd *)-1);
  704. return (found);
  705. }
  706. /*
  707. * Slice a string up into argc/argv.
  708. */
  709. static void
  710. makeargv(char *line)
  711. {
  712. char *cp;
  713. char **argp = margv;
  714. margc = 0;
  715. if ((cp = strchr(line, '\n')) != NULL)
  716. *cp = '\0';
  717. for (cp = line; margc < MAX_MARGV - 1 && *cp != '\0';) {
  718. while (isspace(*cp))
  719. cp++;
  720. if (*cp == '\0')
  721. break;
  722. *argp++ = cp;
  723. margc += 1;
  724. while (*cp != '\0' && !isspace(*cp))
  725. cp++;
  726. if (*cp == '\0')
  727. break;
  728. *cp++ = '\0';
  729. }
  730. *argp++ = 0;
  731. }
  732. static void
  733. quit(int argc __unused, char *argv[] __unused)
  734. {
  735. exit(txrx_error);
  736. }
  737. /*
  738. * Help command.
  739. */
  740. static void
  741. help(int argc, char *argv[])
  742. {
  743. struct cmd *c;
  744. if (argc == 1) {
  745. printf("Commands may be abbreviated. Commands are:\n\n");
  746. for (c = cmdtab; c->name; c++)
  747. printf("%-*s\t%s\n", (int)HELPINDENT, c->name, c->help);
  748. printf("\n[-] : You shouldn't use these ones anymore.\n");
  749. printf("[*] : RFC2347 options support required.\n");
  750. printf("[**] : Non-standard RFC2347 option.\n");
  751. return;
  752. }
  753. while (--argc > 0) {
  754. char *arg;
  755. arg = *++argv;
  756. c = getcmd(arg);
  757. if (c == (struct cmd *)-1)
  758. printf("?Ambiguous help command: %s\n", arg);
  759. else if (c == (struct cmd *)0)
  760. printf("?Invalid help command: %s\n", arg);
  761. else
  762. printf("%s\n", c->help);
  763. }
  764. }
  765. static void
  766. setverbose(int argc __unused, char *argv[] __unused)
  767. {
  768. verbose = !verbose;
  769. printf("Verbose mode %s.\n", verbose ? "on" : "off");
  770. }
  771. static void
  772. setoptions(int argc, char *argv[])
  773. {
  774. if (argc == 2) {
  775. if (strcasecmp(argv[1], "enable") == 0 ||
  776. strcasecmp(argv[1], "on") == 0) {
  777. options_extra_enabled = 1;
  778. options_rfc_enabled = 1;
  779. }
  780. if (strcasecmp(argv[1], "disable") == 0 ||
  781. strcasecmp(argv[1], "off") == 0) {
  782. options_extra_enabled = 0;
  783. options_rfc_enabled = 0;
  784. }
  785. if (strcasecmp(argv[1], "extra") == 0)
  786. options_extra_enabled = !options_extra_enabled;
  787. }
  788. printf("Support for RFC2347 style options are now %s.\n",
  789. options_rfc_enabled ? "enabled" : "disabled");
  790. printf("Support for non-RFC defined options are now %s.\n",
  791. options_extra_enabled ? "enabled" : "disabled");
  792. printf("\nThe following options are available:\n"
  793. "\toptions on : enable support for RFC2347 style options\n"
  794. "\toptions off : disable support for RFC2347 style options\n"
  795. "\toptions extra : toggle support for non-RFC defined options\n"
  796. );
  797. }
  798. static void
  799. setrollover(int argc, char *argv[])
  800. {
  801. if (argc == 2) {
  802. if (strcasecmp(argv[1], "never") == 0 ||
  803. strcasecmp(argv[1], "none") == 0) {
  804. free(options[OPT_ROLLOVER].o_request);
  805. options[OPT_ROLLOVER].o_request = NULL;
  806. }
  807. if (strcasecmp(argv[1], "1") == 0) {
  808. free(options[OPT_ROLLOVER].o_request);
  809. options[OPT_ROLLOVER].o_request = strdup("1");
  810. }
  811. if (strcasecmp(argv[1], "0") == 0) {
  812. free(options[OPT_ROLLOVER].o_request);
  813. options[OPT_ROLLOVER].o_request = strdup("0");
  814. }
  815. }
  816. printf("Support for the rollover options is %s.\n",
  817. options[OPT_ROLLOVER].o_request != NULL ? "enabled" : "disabled");
  818. if (options[OPT_ROLLOVER].o_request != NULL)
  819. printf("Block rollover will be to block %s.\n",
  820. options[OPT_ROLLOVER].o_request);
  821. printf("\nThe following rollover options are available:\n"
  822. "\trollover 0 : rollover to block zero (default)\n"
  823. "\trollover 1 : rollover to block one\n"
  824. "\trollover never : do not support the rollover option\n"
  825. "\trollover none : do not support the rollover option\n"
  826. );
  827. }
  828. static void
  829. setdebug(int argc, char *argv[])
  830. {
  831. int i;
  832. if (argc != 1) {
  833. i = 1;
  834. while (i < argc)
  835. debug ^= debug_find(argv[i++]);
  836. }
  837. printf("The following debugging is enabled: %s\n", debug_show(debug));
  838. printf("\nThe following debugs are available:\n");
  839. i = 0;
  840. while (debugs[i].name != NULL) {
  841. printf("\t%s\t%s\n", debugs[i].name, debugs[i].desc);
  842. i++;
  843. }
  844. }
  845. static void
  846. setblocksize(int argc, char *argv[])
  847. {
  848. if (!options_rfc_enabled)
  849. printf("RFC2347 style options are not enabled "
  850. "(but proceeding anyway)\n");
  851. if (argc != 1) {
  852. int size = atoi(argv[1]);
  853. size_t max;
  854. u_long maxdgram;
  855. max = sizeof(maxdgram);
  856. if (sysctlbyname("net.inet.udp.maxdgram",
  857. &maxdgram, &max, NULL, 0) < 0) {
  858. perror("sysctl: net.inet.udp.maxdgram");
  859. return;
  860. }
  861. if (size < BLKSIZE_MIN || size > BLKSIZE_MAX) {
  862. printf("Blocksize should be between %d and %d bytes.\n",
  863. BLKSIZE_MIN, BLKSIZE_MAX);
  864. return;
  865. } else if (size > (int)maxdgram - 4) {
  866. printf("Blocksize can't be bigger than %ld bytes due "
  867. "to the net.inet.udp.maxdgram sysctl limitation.\n",
  868. maxdgram - 4);
  869. asprintf(&options[OPT_BLKSIZE].o_request,
  870. "%ld", maxdgram - 4);
  871. } else {
  872. asprintf(&options[OPT_BLKSIZE].o_request, "%d", size);
  873. }
  874. }
  875. printf("Blocksize is now %s bytes.\n", options[OPT_BLKSIZE].o_request);
  876. }
  877. static void
  878. setblocksize2(int argc, char *argv[])
  879. {
  880. if (!options_rfc_enabled || !options_extra_enabled)
  881. printf(
  882. "RFC2347 style or non-RFC defined options are not enabled "
  883. "(but proceeding anyway)\n");
  884. if (argc != 1) {
  885. int size = atoi(argv[1]);
  886. int i;
  887. size_t max;
  888. u_long maxdgram;
  889. int sizes[] = {
  890. 8, 16, 32, 64, 128, 256, 512, 1024,
  891. 2048, 4096, 8192, 16384, 32768, 0
  892. };
  893. max = sizeof(maxdgram);
  894. if (sysctlbyname("net.inet.udp.maxdgram",
  895. &maxdgram, &max, NULL, 0) < 0) {
  896. perror("sysctl: net.inet.udp.maxdgram");
  897. return;
  898. }
  899. for (i = 0; sizes[i] != 0; i++) {
  900. if (sizes[i] == size) break;
  901. }
  902. if (sizes[i] == 0) {
  903. printf("Blocksize2 should be a power of two between "
  904. "8 and 32768.\n");
  905. return;
  906. }
  907. if (size < BLKSIZE_MIN || size > BLKSIZE_MAX) {
  908. printf("Blocksize2 should be between "
  909. "%d and %d bytes.\n", BLKSIZE_MIN, BLKSIZE_MAX);
  910. return;
  911. } else if (size > (int)maxdgram - 4) {
  912. printf("Blocksize2 can't be bigger than %ld bytes due "
  913. "to the net.inet.udp.maxdgram sysctl limitation.\n",
  914. maxdgram - 4);
  915. for (i = 0; sizes[i+1] != 0; i++) {
  916. if ((int)maxdgram < sizes[i+1]) break;
  917. }
  918. asprintf(&options[OPT_BLKSIZE2].o_request,
  919. "%d", sizes[i]);
  920. } else {
  921. asprintf(&options[OPT_BLKSIZE2].o_request, "%d", size);
  922. }
  923. }
  924. printf("Blocksize2 is now %s bytes.\n",
  925. options[OPT_BLKSIZE2].o_request);
  926. }
  927. static void
  928. setpacketdrop(int argc, char *argv[])
  929. {
  930. if (argc != 1)
  931. packetdroppercentage = atoi(argv[1]);
  932. printf("Randomly %d in 100 packets will be dropped\n",
  933. packetdroppercentage);
  934. }