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