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