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