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