You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

main.c 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684
  1. /*
  2. * Copyright (c) 1983 Regents of the University of California.
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms are permitted
  6. * provided that the above copyright notice and this paragraph are
  7. * duplicated in all such forms and that any documentation,
  8. * advertising materials, and other materials related to such
  9. * distribution and use acknowledge that the software was developed
  10. * by the University of California, Berkeley. The name of the
  11. * University may not be used to endorse or promote products derived
  12. * from this software without specific prior written permission.
  13. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  14. * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  15. * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  16. */
  17. #ifndef lint
  18. char copyright[] =
  19. "@(#) Copyright (c) 1983 Regents of the University of California.\n\
  20. All rights reserved.\n";
  21. #endif /* not lint */
  22. #ifndef lint
  23. static char sccsid[] = "@(#)main.c 5.8 (Berkeley) 10/11/88";
  24. #endif /* not lint */
  25. /* Many bug fixes are from Jim Guyton <guyton@rand-unix> */
  26. /*
  27. * TFTP User Program -- Command Interface.
  28. */
  29. #include <sys/types.h>
  30. #include <sys/socket.h>
  31. #include <sys/file.h>
  32. #include <netinet/in.h>
  33. #include <signal.h>
  34. #include <stdio.h>
  35. #include <errno.h>
  36. #include <setjmp.h>
  37. #include <ctype.h>
  38. #include <netdb.h>
  39. #define TIMEOUT 5 /* secs between rexmt's */
  40. struct sockaddr_in sin;
  41. int f;
  42. short port;
  43. int trace;
  44. int verbose;
  45. int connected;
  46. char mode[32];
  47. char line[200];
  48. int margc;
  49. char *margv[20];
  50. char *prompt = "tftp";
  51. jmp_buf toplevel;
  52. void intr(int);
  53. struct servent *sp;
  54. int segsize = 512;
  55. int quit(), help(), setverbose(), settrace(), status();
  56. int get(), put(), setpeer(), modecmd(), setrexmt(), settimeout();
  57. int setbinary(), setascii(), setblocksize();
  58. #define HELPINDENT (sizeof("connect"))
  59. struct cmd {
  60. char *name;
  61. char *help;
  62. int (*handler)();
  63. };
  64. char vhelp[] = "toggle verbose mode";
  65. char thelp[] = "toggle packet tracing";
  66. char chelp[] = "connect to remote tftp";
  67. char qhelp[] = "exit tftp";
  68. char hhelp[] = "print help information";
  69. char shelp[] = "send file";
  70. char rhelp[] = "receive file";
  71. char mhelp[] = "set file transfer mode";
  72. char sthelp[] = "show current status";
  73. char xhelp[] = "set per-packet retransmission timeout";
  74. char ihelp[] = "set total retransmission timeout";
  75. char ashelp[] = "set mode to netascii";
  76. char bnhelp[] = "set mode to octet";
  77. char bshelp[] = "set blocksize for next transfer";
  78. struct cmd cmdtab[] = {
  79. { "connect", chelp, setpeer },
  80. { "mode", mhelp, modecmd },
  81. { "put", shelp, put },
  82. { "get", rhelp, get },
  83. { "quit", qhelp, quit },
  84. { "verbose", vhelp, setverbose },
  85. { "trace", thelp, settrace },
  86. { "status", sthelp, status },
  87. { "binary", bnhelp, setbinary },
  88. { "ascii", ashelp, setascii },
  89. { "rexmt", xhelp, setrexmt },
  90. { "timeout", ihelp, settimeout },
  91. { "blocksize", bshelp, setblocksize },
  92. { "?", hhelp, help },
  93. 0
  94. };
  95. struct cmd *getcmd();
  96. char *tail();
  97. char *index();
  98. char *rindex();
  99. main(argc, argv)
  100. char *argv[];
  101. {
  102. struct sockaddr_in sin;
  103. int top;
  104. sp = getservbyname("tftp", "udp");
  105. if (sp == 0) {
  106. fprintf(stderr, "tftp: udp/tftp: unknown service\n");
  107. exit(1);
  108. }
  109. f = socket(AF_INET, SOCK_DGRAM, 0);
  110. if (f < 0) {
  111. perror("tftp: socket");
  112. exit(3);
  113. }
  114. bzero((char *)&sin, sizeof (sin));
  115. sin.sin_family = AF_INET;
  116. if (bind(f, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
  117. perror("tftp: bind");
  118. exit(1);
  119. }
  120. strcpy(mode, "netascii");
  121. signal(SIGINT, intr);
  122. if (argc > 1) {
  123. if (setjmp(toplevel) != 0)
  124. exit(0);
  125. setpeer(argc, argv);
  126. }
  127. top = setjmp(toplevel) == 0;
  128. for (;;)
  129. command(top);
  130. }
  131. char hostname[100];
  132. setpeer(argc, argv)
  133. int argc;
  134. char *argv[];
  135. {
  136. struct hostent *host;
  137. if (argc < 2) {
  138. strcpy(line, "Connect ");
  139. printf("(to) ");
  140. fgets(&line[strlen(line)], sizeof(line) - strlen(line) - 1, stdin);
  141. makeargv();
  142. argc = margc;
  143. argv = margv;
  144. }
  145. if (argc > 3) {
  146. printf("usage: %s host-name [port]\n", argv[0]);
  147. return;
  148. }
  149. host = gethostbyname(argv[1]);
  150. if (host) {
  151. sin.sin_family = host->h_addrtype;
  152. bcopy(host->h_addr, &sin.sin_addr, host->h_length);
  153. strcpy(hostname, host->h_name);
  154. } else {
  155. sin.sin_family = AF_INET;
  156. sin.sin_addr.s_addr = inet_addr(argv[1]);
  157. if (sin.sin_addr.s_addr == -1) {
  158. connected = 0;
  159. printf("%s: unknown host\n", argv[1]);
  160. return;
  161. }
  162. strcpy(hostname, argv[1]);
  163. }
  164. port = sp->s_port;
  165. if (argc == 3) {
  166. port = atoi(argv[2]);
  167. if (port < 0) {
  168. printf("%s: bad port number\n", argv[2]);
  169. connected = 0;
  170. return;
  171. }
  172. port = htons(port);
  173. }
  174. connected = 1;
  175. }
  176. struct modes {
  177. char *m_name;
  178. char *m_mode;
  179. } modes[] = {
  180. { "ascii", "netascii" },
  181. { "netascii", "netascii" },
  182. { "binary", "octet" },
  183. { "image", "octet" },
  184. { "octet", "octet" },
  185. /* { "mail", "mail" }, */
  186. { 0, 0 }
  187. };
  188. modecmd(argc, argv)
  189. char *argv[];
  190. {
  191. register struct modes *p;
  192. char *sep;
  193. if (argc < 2) {
  194. printf("Using %s mode to transfer files.\n", mode);
  195. return;
  196. }
  197. if (argc == 2) {
  198. for (p = modes; p->m_name; p++)
  199. if (strcmp(argv[1], p->m_name) == 0)
  200. break;
  201. if (p->m_name) {
  202. setmode(p->m_mode);
  203. return;
  204. }
  205. printf("%s: unknown mode\n", argv[1]);
  206. /* drop through and print usage message */
  207. }
  208. printf("usage: %s [", argv[0]);
  209. sep = " ";
  210. for (p = modes; p->m_name; p++) {
  211. printf("%s%s", sep, p->m_name);
  212. if (*sep == ' ')
  213. sep = " | ";
  214. }
  215. printf(" ]\n");
  216. return;
  217. }
  218. setbinary(argc, argv)
  219. char *argv[];
  220. { setmode("octet");
  221. }
  222. setascii(argc, argv)
  223. char *argv[];
  224. { setmode("netascii");
  225. }
  226. setmode(newmode)
  227. char *newmode;
  228. {
  229. strcpy(mode, newmode);
  230. if (verbose)
  231. printf("mode set to %s\n", mode);
  232. }
  233. /*
  234. * Send file(s).
  235. */
  236. put(argc, argv)
  237. char *argv[];
  238. {
  239. int fd;
  240. register int n;
  241. register char *cp, *targ;
  242. if (argc < 2) {
  243. strcpy(line, "send ");
  244. printf("(file) ");
  245. fgets(&line[strlen(line)], sizeof(line) - strlen(line) - 1, stdin);
  246. makeargv();
  247. argc = margc;
  248. argv = margv;
  249. }
  250. if (argc < 2) {
  251. putusage(argv[0]);
  252. return;
  253. }
  254. targ = argv[argc - 1];
  255. if (index(argv[argc - 1], ':')) {
  256. char *cp;
  257. struct hostent *hp;
  258. for (n = 1; n < argc - 1; n++)
  259. if (index(argv[n], ':')) {
  260. putusage(argv[0]);
  261. return;
  262. }
  263. cp = argv[argc - 1];
  264. targ = index(cp, ':');
  265. *targ++ = 0;
  266. hp = gethostbyname(cp);
  267. if (hp == NULL) {
  268. fprintf(stderr, "tftp: %s: ", cp);
  269. herror((char *)NULL);
  270. return;
  271. }
  272. bcopy(hp->h_addr, (caddr_t)&sin.sin_addr, hp->h_length);
  273. sin.sin_family = hp->h_addrtype;
  274. connected = 1;
  275. strcpy(hostname, hp->h_name);
  276. }
  277. if (!connected) {
  278. printf("No target machine specified.\n");
  279. return;
  280. }
  281. if (argc < 4) {
  282. cp = argc == 2 ? tail(targ) : argv[1];
  283. fd = open(cp, O_RDONLY);
  284. if (fd < 0) {
  285. fprintf(stderr, "tftp: "); perror(cp);
  286. return;
  287. }
  288. if (verbose)
  289. printf("putting %s to %s:%s [%s]\n",
  290. cp, hostname, targ, mode);
  291. sin.sin_port = port;
  292. sendfile(fd, targ, mode);
  293. return;
  294. }
  295. /* this assumes the target is a directory */
  296. /* on a remote unix system. hmmmm. */
  297. cp = index(targ, '\0');
  298. *cp++ = '/';
  299. for (n = 1; n < argc - 1; n++) {
  300. strcpy(cp, tail(argv[n]));
  301. fd = open(argv[n], O_RDONLY);
  302. if (fd < 0) {
  303. fprintf(stderr, "tftp: "); perror(argv[n]);
  304. continue;
  305. }
  306. if (verbose)
  307. printf("putting %s to %s:%s [%s]\n",
  308. argv[n], hostname, targ, mode);
  309. sin.sin_port = port;
  310. sendfile(fd, targ, mode);
  311. }
  312. }
  313. putusage(s)
  314. char *s;
  315. {
  316. printf("usage: %s file ... host:target, or\n", s);
  317. printf(" %s file ... target (when already connected)\n", s);
  318. }
  319. /*
  320. * Receive file(s).
  321. */
  322. get(argc, argv)
  323. char *argv[];
  324. {
  325. int fd;
  326. register int n;
  327. register char *cp;
  328. char *src;
  329. if (argc < 2) {
  330. strcpy(line, "get ");
  331. printf("(files) ");
  332. fgets(&line[strlen(line)], sizeof(line) - strlen(line) - 1, stdin);
  333. makeargv();
  334. argc = margc;
  335. argv = margv;
  336. }
  337. if (argc < 2) {
  338. getusage(argv[0]);
  339. return;
  340. }
  341. if (!connected) {
  342. for (n = 1; n < argc ; n++)
  343. if (index(argv[n], ':') == 0) {
  344. getusage(argv[0]);
  345. return;
  346. }
  347. }
  348. for (n = 1; n < argc ; n++) {
  349. src = index(argv[n], ':');
  350. if (src == NULL)
  351. src = argv[n];
  352. else {
  353. struct hostent *hp;
  354. *src++ = 0;
  355. hp = gethostbyname(argv[n]);
  356. if (hp == NULL) {
  357. fprintf(stderr, "tftp: %s: ", argv[n]);
  358. herror((char *)NULL);
  359. continue;
  360. }
  361. bcopy(hp->h_addr, (caddr_t)&sin.sin_addr, hp->h_length);
  362. sin.sin_family = hp->h_addrtype;
  363. connected = 1;
  364. strcpy(hostname, hp->h_name);
  365. }
  366. if (argc < 4) {
  367. cp = argc == 3 ? argv[2] : tail(src);
  368. fd = creat(cp, 0644);
  369. if (fd < 0) {
  370. fprintf(stderr, "tftp: "); perror(cp);
  371. return;
  372. }
  373. if (verbose)
  374. printf("getting from %s:%s to %s [%s]\n",
  375. hostname, src, cp, mode);
  376. sin.sin_port = port;
  377. recvfile(fd, src, mode);
  378. break;
  379. }
  380. cp = tail(src); /* new .. jdg */
  381. fd = creat(cp, 0644);
  382. if (fd < 0) {
  383. fprintf(stderr, "tftp: "); perror(cp);
  384. continue;
  385. }
  386. if (verbose)
  387. printf("getting from %s:%s to %s [%s]\n",
  388. hostname, src, cp, mode);
  389. sin.sin_port = port;
  390. recvfile(fd, src, mode);
  391. }
  392. }
  393. getusage(s)
  394. char * s;
  395. {
  396. printf("usage: %s host:file host:file ... file, or\n", s);
  397. printf(" %s file file ... file if connected\n", s);
  398. }
  399. int rexmtval = TIMEOUT;
  400. setrexmt(argc, argv)
  401. char *argv[];
  402. {
  403. int t;
  404. if (argc < 2) {
  405. strcpy(line, "Rexmt-timeout ");
  406. printf("(value) ");
  407. fgets(&line[strlen(line)], sizeof(line) - strlen(line) - 1, stdin);
  408. makeargv();
  409. argc = margc;
  410. argv = margv;
  411. }
  412. if (argc != 2) {
  413. printf("usage: %s value\n", argv[0]);
  414. return;
  415. }
  416. t = atoi(argv[1]);
  417. if (t < 0)
  418. printf("%d: bad value\n", t);
  419. else
  420. rexmtval = t;
  421. }
  422. int maxtimeout = 5 * TIMEOUT;
  423. settimeout(argc, argv)
  424. char *argv[];
  425. {
  426. int t;
  427. if (argc < 2) {
  428. strcpy(line, "Maximum-timeout ");
  429. printf("(value) ");
  430. fgets(&line[strlen(line)], sizeof(line) - strlen(line) - 1, stdin);
  431. makeargv();
  432. argc = margc;
  433. argv = margv;
  434. }
  435. if (argc != 2) {
  436. printf("usage: %s value\n", argv[0]);
  437. return;
  438. }
  439. t = atoi(argv[1]);
  440. if (t < 0)
  441. printf("%d: bad value\n", t);
  442. else
  443. maxtimeout = t;
  444. }
  445. status(argc, argv)
  446. char *argv[];
  447. {
  448. if (connected)
  449. printf("Connected to %s.\n", hostname);
  450. else
  451. printf("Not connected.\n");
  452. printf("Mode: %s Verbose: %s Tracing: %s\n", mode,
  453. verbose ? "on" : "off", trace ? "on" : "off");
  454. printf("Rexmt-interval: %d seconds, Max-timeout: %d seconds\n",
  455. rexmtval, maxtimeout);
  456. }
  457. void intr(int sig)
  458. {
  459. signal(SIGALRM, SIG_IGN);
  460. alarm(0);
  461. longjmp(toplevel, -1);
  462. }
  463. char *
  464. tail(filename)
  465. char *filename;
  466. {
  467. register char *s;
  468. while (*filename) {
  469. s = rindex(filename, '/');
  470. if (s == NULL)
  471. break;
  472. if (s[1])
  473. return (s + 1);
  474. *s = '\0';
  475. }
  476. return (filename);
  477. }
  478. /*
  479. * Command parser.
  480. */
  481. command(top)
  482. int top;
  483. {
  484. register struct cmd *c;
  485. if (!top)
  486. putchar('\n');
  487. for (;;) {
  488. printf("%s> ", prompt);
  489. if (fgets(line, sizeof(line), stdin) == 0) {
  490. if (feof(stdin)) {
  491. quit();
  492. } else {
  493. continue;
  494. }
  495. }
  496. if (line[0] == 0)
  497. continue;
  498. makeargv();
  499. c = getcmd(margv[0]);
  500. if (c == (struct cmd *)-1) {
  501. printf("?Ambiguous command\n");
  502. continue;
  503. }
  504. if (c == 0) {
  505. printf("?Invalid command\n");
  506. continue;
  507. }
  508. (*c->handler)(margc, margv);
  509. }
  510. }
  511. struct cmd *
  512. getcmd(name)
  513. register char *name;
  514. {
  515. register char *p, *q;
  516. register struct cmd *c, *found;
  517. register int nmatches, longest;
  518. longest = 0;
  519. nmatches = 0;
  520. found = 0;
  521. for (c = cmdtab; p = c->name; c++) {
  522. for (q = name; *q == *p++; q++)
  523. if (*q == 0) /* exact match? */
  524. return (c);
  525. if (!*q) { /* the name was a prefix */
  526. if (q - name > longest) {
  527. longest = q - name;
  528. nmatches = 1;
  529. found = c;
  530. } else if (q - name == longest)
  531. nmatches++;
  532. }
  533. }
  534. if (nmatches > 1)
  535. return ((struct cmd *)-1);
  536. return (found);
  537. }
  538. /*
  539. * Slice a string up into argc/argv.
  540. */
  541. makeargv()
  542. {
  543. register char *cp;
  544. register char **argp = margv;
  545. margc = 0;
  546. for (cp = line; *cp;) {
  547. while (isspace(*cp))
  548. cp++;
  549. if (*cp == '\0')
  550. break;
  551. *argp++ = cp;
  552. margc += 1;
  553. while (*cp != '\0' && !isspace(*cp))
  554. cp++;
  555. if (*cp == '\0')
  556. break;
  557. *cp++ = '\0';
  558. }
  559. *argp++ = 0;
  560. }
  561. /*VARARGS*/
  562. quit()
  563. {
  564. exit(0);
  565. }
  566. /*
  567. * Help command.
  568. */
  569. help(argc, argv)
  570. int argc;
  571. char *argv[];
  572. {
  573. register struct cmd *c;
  574. if (argc == 1) {
  575. printf("Commands may be abbreviated. Commands are:\n\n");
  576. for (c = cmdtab; c->name; c++)
  577. printf("%-*s\t%s\n", HELPINDENT, c->name, c->help);
  578. return;
  579. }
  580. while (--argc > 0) {
  581. register char *arg;
  582. arg = *++argv;
  583. c = getcmd(arg);
  584. if (c == (struct cmd *)-1)
  585. printf("?Ambiguous help command %s\n", arg);
  586. else if (c == (struct cmd *)0)
  587. printf("?Invalid help command %s\n", arg);
  588. else
  589. printf("%s\n", c->help);
  590. }
  591. }
  592. /*VARARGS*/
  593. settrace()
  594. {
  595. trace = !trace;
  596. printf("Packet tracing %s.\n", trace ? "on" : "off");
  597. }
  598. /*VARARGS*/
  599. setverbose()
  600. {
  601. verbose = !verbose;
  602. printf("Verbose mode %s.\n", verbose ? "on" : "off");
  603. }
  604. setblocksize(argc, argv)
  605. char *argv[];
  606. {
  607. int t;
  608. if (argc < 2) {
  609. strcpy(line, "blocksize ");
  610. printf("(value) ");
  611. fgets(&line[strlen(line)], sizeof(line) - strlen(line) - 1, stdin);
  612. makeargv();
  613. argc = margc;
  614. argv = margv;
  615. }
  616. if (argc != 2) {
  617. printf("usage: %s value\n", argv[0]);
  618. return;
  619. }
  620. t = atoi(argv[1]);
  621. if (t < 8 || t > 1432)
  622. printf("%d: bad value\n", t);
  623. else
  624. segsize = t;
  625. }