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