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