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