xref: /netbsd-src/usr.bin/tftp/main.c (revision 8e6ab8837d8d6b9198e67c1c445300b483e2f304)
1 /*	$NetBSD: main.c,v 1.16 2003/07/12 13:38:10 itojun Exp $	*/
2 
3 /*
4  * Copyright (c) 1983, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *	This product includes software developed by the University of
18  *	California, Berkeley and its contributors.
19  * 4. Neither the name of the University nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  */
35 
36 #include <sys/cdefs.h>
37 #ifndef lint
38 __COPYRIGHT("@(#) Copyright (c) 1983, 1993\n\
39 	The Regents of the University of California.  All rights reserved.\n");
40 #if 0
41 static char sccsid[] = "@(#)main.c	8.1 (Berkeley) 6/6/93";
42 #else
43 __RCSID("$NetBSD: main.c,v 1.16 2003/07/12 13:38:10 itojun Exp $");
44 #endif
45 #endif /* not lint */
46 
47 /* Many bug fixes are from Jim Guyton <guyton@rand-unix> */
48 
49 /*
50  * TFTP User Program -- Command Interface.
51  */
52 #include <sys/types.h>
53 #include <sys/socket.h>
54 
55 #include <netinet/in.h>
56 
57 #include <arpa/inet.h>
58 #include <arpa/tftp.h>
59 
60 #include <ctype.h>
61 #include <fcntl.h>
62 #include <err.h>
63 #include <errno.h>
64 #include <netdb.h>
65 #include <setjmp.h>
66 #include <signal.h>
67 #include <stdio.h>
68 #include <stdlib.h>
69 #include <string.h>
70 #include <unistd.h>
71 
72 #include "extern.h"
73 
74 #define	TIMEOUT		5		/* secs between rexmt's */
75 #define	LBUFLEN		200		/* size of input buffer */
76 
77 struct	sockaddr_storage peeraddr;
78 int	f;
79 int	trace;
80 int	verbose;
81 int	tsize=0;
82 int	tout=0;
83 int	def_blksize=SEGSIZE;
84 int	blksize=SEGSIZE;
85 int	connected;
86 char	mode[32];
87 char	line[LBUFLEN];
88 int	margc;
89 char	*margv[20];
90 char	*prompt = "tftp";
91 jmp_buf	toplevel;
92 
93 void	get __P((int, char **));
94 void	help __P((int, char **));
95 void	modecmd __P((int, char **));
96 void	put __P((int, char **));
97 void	quit __P((int, char **));
98 void	setascii __P((int, char **));
99 void	setbinary __P((int, char **));
100 void	setpeer0 __P((char *, char *));
101 void	setpeer __P((int, char **));
102 void	setrexmt __P((int, char **));
103 void	settimeout __P((int, char **));
104 void	settrace __P((int, char **));
105 void	setverbose __P((int, char **));
106 void	setblksize __P((int, char **));
107 void	settsize __P((int, char **));
108 void	settimeoutopt __P((int, char **));
109 void	status __P((int, char **));
110 char	*tail __P((char *));
111 int	main __P((int, char *[]));
112 void	intr __P((int));
113 struct cmd *getcmd __P((char *));
114 
115 static __dead void command __P((void));
116 
117 static void getusage __P((char *));
118 static void makeargv __P((void));
119 static void putusage __P((char *));
120 static void settftpmode __P((char *));
121 
122 #define HELPINDENT (sizeof("connect"))
123 
124 struct cmd {
125 	char	*name;
126 	char	*help;
127 	void	(*handler) __P((int, char **));
128 };
129 
130 char	vhelp[] = "toggle verbose mode";
131 char	thelp[] = "toggle packet tracing";
132 char	tshelp[] = "toggle extended tsize option";
133 char	tohelp[] = "toggle extended timeout option";
134 char	blhelp[] = "set an alternative blocksize (def. 512)";
135 char	chelp[] = "connect to remote tftp";
136 char	qhelp[] = "exit tftp";
137 char	hhelp[] = "print help information";
138 char	shelp[] = "send file";
139 char	rhelp[] = "receive file";
140 char	mhelp[] = "set file transfer mode";
141 char	sthelp[] = "show current status";
142 char	xhelp[] = "set per-packet retransmission timeout";
143 char	ihelp[] = "set total retransmission timeout";
144 char    ashelp[] = "set mode to netascii";
145 char    bnhelp[] = "set mode to octet";
146 
147 struct cmd cmdtab[] = {
148 	{ "connect",	chelp,		setpeer },
149 	{ "mode",       mhelp,          modecmd },
150 	{ "put",	shelp,		put },
151 	{ "get",	rhelp,		get },
152 	{ "quit",	qhelp,		quit },
153 	{ "verbose",	vhelp,		setverbose },
154 	{ "blksize",	blhelp,		setblksize },
155 	{ "tsize",	tshelp,		settsize },
156 	{ "trace",	thelp,		settrace },
157 	{ "status",	sthelp,		status },
158 	{ "binary",     bnhelp,         setbinary },
159 	{ "ascii",      ashelp,         setascii },
160 	{ "rexmt",	xhelp,		setrexmt },
161 	{ "timeout",	ihelp,		settimeout },
162 	{ "tout",	tohelp,		settimeoutopt },
163 	{ "?",		hhelp,		help },
164 	{ 0 }
165 };
166 
167 int
168 main(argc, argv)
169 	int argc;
170 	char *argv[];
171 {
172 	int	c;
173 
174 	f = -1;
175 	strcpy(mode, "netascii");
176 	signal(SIGINT, intr);
177 
178 	setprogname(argv[0]);
179 	while ((c = getopt(argc, argv, "e")) != -1) {
180 		switch (c) {
181 		case 'e':
182 			blksize = MAXSEGSIZE;
183 			strcpy(mode, "octet");
184 			tsize = 1;
185 			tout = 1;
186 			break;
187 		default:
188 			printf("usage: %s [-e] host-name [port]\n",
189 				getprogname());
190 			exit(1);
191 		}
192 	}
193 	argc -= optind;
194 	argv += optind;
195 
196 	if (argc >= 1) {
197 		if (setjmp(toplevel) != 0)
198 			exit(0);
199 		setpeer(argc, argv);
200 	}
201 	if (setjmp(toplevel) != 0)
202 		(void)putchar('\n');
203 	command();
204 	return (0);
205 }
206 
207 char    hostname[100];
208 
209 void
210 setpeer0(host, port)
211 	char *host;
212 	char *port;
213 {
214 	struct addrinfo hints, *res0, *res;
215 	int error, soopt;
216 	struct sockaddr_storage ss;
217 	char *cause = "unknown";
218 
219 	if (connected) {
220 		close(f);
221 		f = -1;
222 	}
223 	connected = 0;
224 
225 	memset(&hints, 0, sizeof(hints));
226 	hints.ai_family = PF_UNSPEC;
227 	hints.ai_socktype = SOCK_DGRAM;
228 	hints.ai_protocol = IPPROTO_UDP;
229 	hints.ai_flags = AI_CANONNAME;
230 	if (!port)
231 		port = "tftp";
232 	error = getaddrinfo(host, port, &hints, &res0);
233 	if (error) {
234 		warnx("%s", gai_strerror(error));
235 		return;
236 	}
237 
238 	for (res = res0; res; res = res->ai_next) {
239 		if (res->ai_addrlen > sizeof(peeraddr))
240 			continue;
241 		f = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
242 		if (f < 0) {
243 			cause = "socket";
244 			continue;
245 		}
246 
247 		memset(&ss, 0, sizeof(ss));
248 		ss.ss_family = res->ai_family;
249 		ss.ss_len = res->ai_addrlen;
250 		if (bind(f, (struct sockaddr *)&ss, ss.ss_len) < 0) {
251 			cause = "bind";
252 			close(f);
253 			f = -1;
254 			continue;
255 		}
256 
257 		break;
258 	}
259 
260 	if (f >= 0) {
261 		soopt = 65536;
262 		if (setsockopt(f, SOL_SOCKET, SO_SNDBUF, &soopt, sizeof(soopt))
263 		    < 0) {
264 			close(f);
265 			f = -1;
266 			cause = "setsockopt SNDBUF";
267 		}
268 		if (setsockopt(f, SOL_SOCKET, SO_RCVBUF, &soopt, sizeof(soopt))
269 		    < 0) {
270 			close(f);
271 			f = -1;
272 			cause = "setsockopt RCVBUF";
273 		}
274 	}
275 
276 	if (f < 0)
277 		warn("%s", cause);
278 	else {
279 		/* res->ai_addr <= sizeof(peeraddr) is guaranteed */
280 		memcpy(&peeraddr, res->ai_addr, res->ai_addrlen);
281 		if (res->ai_canonname) {
282 			(void) strlcpy(hostname, res->ai_canonname,
283 			    sizeof(hostname));
284 		} else
285 			(void) strlcpy(hostname, host, sizeof(hostname));
286 		connected = 1;
287 	}
288 
289 	freeaddrinfo(res0);
290 }
291 
292 void
293 setpeer(argc, argv)
294 	int argc;
295 	char *argv[];
296 {
297 
298 	if (argc < 1) {
299 		strcpy(line, "Connect ");
300 		printf("(to) ");
301 		fgets(&line[strlen(line)], LBUFLEN-strlen(line), stdin);
302 		makeargv();
303 		argc = margc;
304 		argv = margv;
305 	}
306 	if ((argc < 1) || (argc > 2)) {
307 		printf("usage: %s [-e] host-name [port]\n", getprogname());
308 		return;
309 	}
310 	if (argc == 1)
311 		setpeer0(argv[0], NULL);
312 	else
313 		setpeer0(argv[0], argv[1]);
314 }
315 
316 struct	modes {
317 	char *m_name;
318 	char *m_mode;
319 } modes[] = {
320 	{ "ascii",	"netascii" },
321 	{ "netascii",   "netascii" },
322 	{ "binary",     "octet" },
323 	{ "image",      "octet" },
324 	{ "octet",     "octet" },
325 /*      { "mail",       "mail" },       */
326 	{ 0,		0 }
327 };
328 
329 void
330 modecmd(argc, argv)
331 	int argc;
332 	char *argv[];
333 {
334 	struct modes *p;
335 	char *sep;
336 
337 	if (argc < 2) {
338 		printf("Using %s mode to transfer files.\n", mode);
339 		return;
340 	}
341 	if (argc == 2) {
342 		for (p = modes; p->m_name; p++)
343 			if (strcmp(argv[1], p->m_name) == 0)
344 				break;
345 		if (p->m_name) {
346 			settftpmode(p->m_mode);
347 			return;
348 		}
349 		printf("%s: unknown mode\n", argv[1]);
350 		/* drop through and print usage message */
351 	}
352 
353 	printf("usage: %s [", argv[0]);
354 	sep = " ";
355 	for (p = modes; p->m_name; p++) {
356 		printf("%s%s", sep, p->m_name);
357 		if (*sep == ' ')
358 			sep = " | ";
359 	}
360 	printf(" ]\n");
361 	return;
362 }
363 
364 void
365 setbinary(argc, argv)
366 	int argc;
367 	char *argv[];
368 {
369 
370 	settftpmode("octet");
371 }
372 
373 void
374 setascii(argc, argv)
375 	int argc;
376 	char *argv[];
377 {
378 
379 	settftpmode("netascii");
380 }
381 
382 static void
383 settftpmode(newmode)
384 	char *newmode;
385 {
386 	strcpy(mode, newmode);
387 	if (verbose)
388 		printf("mode set to %s\n", mode);
389 }
390 
391 
392 /*
393  * Send file(s).
394  */
395 void
396 put(argc, argv)
397 	int argc;
398 	char *argv[];
399 {
400 	int fd;
401 	int n;
402 	char *cp, *targ;
403 
404 	if (argc < 2) {
405 		strcpy(line, "send ");
406 		printf("(file) ");
407 		fgets(&line[strlen(line)], LBUFLEN-strlen(line), stdin);
408 		makeargv();
409 		argc = margc;
410 		argv = margv;
411 	}
412 	if (argc < 2) {
413 		putusage(argv[0]);
414 		return;
415 	}
416 	targ = argv[argc - 1];
417 	if (strrchr(argv[argc - 1], ':')) {
418 		char *cp;
419 
420 		for (n = 1; n < argc - 1; n++)
421 			if (strchr(argv[n], ':')) {
422 				putusage(argv[0]);
423 				return;
424 			}
425 		cp = argv[argc - 1];
426 		targ = strrchr(cp, ':');
427 		*targ++ = 0;
428 		if (cp[0] == '[' && cp[strlen(cp) - 1] == ']') {
429 			cp[strlen(cp) - 1] = '\0';
430 			cp++;
431 		}
432 		setpeer0(cp, NULL);
433 	}
434 	if (!connected) {
435 		printf("No target machine specified.\n");
436 		return;
437 	}
438 	if (argc < 4) {
439 		cp = argc == 2 ? tail(targ) : argv[1];
440 		fd = open(cp, O_RDONLY);
441 		if (fd < 0) {
442 			warn("%s", cp);
443 			return;
444 		}
445 		if (verbose)
446 			printf("putting %s to %s:%s [%s]\n",
447 				cp, hostname, targ, mode);
448 		sendfile(fd, targ, mode);
449 		return;
450 	}
451 				/* this assumes the target is a directory */
452 				/* on a remote unix system.  hmmmm.  */
453 	cp = strchr(targ, '\0');
454 	*cp++ = '/';
455 	for (n = 1; n < argc - 1; n++) {
456 		strcpy(cp, tail(argv[n]));
457 		fd = open(argv[n], O_RDONLY);
458 		if (fd < 0) {
459 			warn("%s", argv[n]);
460 			continue;
461 		}
462 		if (verbose)
463 			printf("putting %s to %s:%s [%s]\n",
464 				argv[n], hostname, targ, mode);
465 		sendfile(fd, targ, mode);
466 	}
467 }
468 
469 static void
470 putusage(s)
471 	char *s;
472 {
473 	printf("usage: %s file ... host:target, or\n", s);
474 	printf("       %s file ... target (when already connected)\n", s);
475 }
476 
477 /*
478  * Receive file(s).
479  */
480 void
481 get(argc, argv)
482 	int argc;
483 	char *argv[];
484 {
485 	int fd;
486 	int n;
487 	char *cp;
488 	char *src;
489 
490 	if (argc < 2) {
491 		strcpy(line, "get ");
492 		printf("(files) ");
493 		fgets(&line[strlen(line)], LBUFLEN-strlen(line), stdin);
494 		makeargv();
495 		argc = margc;
496 		argv = margv;
497 	}
498 	if (argc < 2) {
499 		getusage(argv[0]);
500 		return;
501 	}
502 	if (!connected) {
503 		for (n = 1; n < argc ; n++)
504 			if (strrchr(argv[n], ':') == 0) {
505 				getusage(argv[0]);
506 				return;
507 			}
508 	}
509 	for (n = 1; n < argc ; n++) {
510 		src = strrchr(argv[n], ':');
511 		if (src == NULL)
512 			src = argv[n];
513 		else {
514 			char *cp;
515 			*src++ = 0;
516 			cp = argv[n];
517 			if (cp[0] == '[' && cp[strlen(cp) - 1] == ']') {
518 				cp[strlen(cp) - 1] = '\0';
519 				cp++;
520 			}
521 			setpeer0(cp, NULL);
522 			if (!connected)
523 				continue;
524 		}
525 		if (argc < 4) {
526 			cp = argc == 3 ? argv[2] : tail(src);
527 			fd = creat(cp, 0644);
528 			if (fd < 0) {
529 				warn("%s", cp);
530 				return;
531 			}
532 			if (verbose)
533 				printf("getting from %s:%s to %s [%s]\n",
534 					hostname, src, cp, mode);
535 			recvfile(fd, src, mode);
536 			break;
537 		}
538 		cp = tail(src);         /* new .. jdg */
539 		fd = creat(cp, 0644);
540 		if (fd < 0) {
541 			warn("%s", cp);
542 			continue;
543 		}
544 		if (verbose)
545 			printf("getting from %s:%s to %s [%s]\n",
546 				hostname, src, cp, mode);
547 		recvfile(fd, src, mode);
548 	}
549 }
550 
551 static void
552 getusage(s)
553 	char *s;
554 {
555 	printf("usage: %s host:file host:file ... file, or\n", s);
556 	printf("       %s file file ... file if connected\n", s);
557 }
558 
559 void
560 setblksize(argc, argv)
561 	int argc;
562 	char *argv[];
563 {
564 	int t;
565 
566 	if (argc < 2) {
567 		strcpy(line, "blksize ");
568 		printf("(blksize) ");
569 		fgets(&line[strlen(line)], LBUFLEN-strlen(line), stdin);
570 		makeargv();
571 		argc = margc;
572 		argv = margv;
573 	}
574 	if (argc != 2) {
575 		printf("usage: %s value\n", argv[0]);
576 		return;
577 	}
578 	t = atoi(argv[1]);
579 	if (t < 8 || t > 65464)
580 		printf("%s: bad value\n", argv[1]);
581 	else
582 		blksize = t;
583 }
584 
585 int	def_rexmtval = TIMEOUT;
586 int	rexmtval = TIMEOUT;
587 
588 void
589 setrexmt(argc, argv)
590 	int argc;
591 	char *argv[];
592 {
593 	int t;
594 
595 	if (argc < 2) {
596 		strcpy(line, "Rexmt-timeout ");
597 		printf("(value) ");
598 		fgets(&line[strlen(line)], LBUFLEN-strlen(line), stdin);
599 		makeargv();
600 		argc = margc;
601 		argv = margv;
602 	}
603 	if (argc != 2) {
604 		printf("usage: %s value\n", argv[0]);
605 		return;
606 	}
607 	t = atoi(argv[1]);
608 	if (t < 0)
609 		printf("%s: bad value\n", argv[1]);
610 	else
611 		rexmtval = t;
612 }
613 
614 int	maxtimeout = 5 * TIMEOUT;
615 
616 void
617 settimeout(argc, argv)
618 	int argc;
619 	char *argv[];
620 {
621 	int t;
622 
623 	if (argc < 2) {
624 		strcpy(line, "Maximum-timeout ");
625 		printf("(value) ");
626 		fgets(&line[strlen(line)], LBUFLEN-strlen(line), stdin);
627 		makeargv();
628 		argc = margc;
629 		argv = margv;
630 	}
631 	if (argc != 2) {
632 		printf("usage: %s value\n", argv[0]);
633 		return;
634 	}
635 	t = atoi(argv[1]);
636 	if (t < 0)
637 		printf("%s: bad value\n", argv[1]);
638 	else
639 		maxtimeout = t;
640 }
641 
642 void
643 status(argc, argv)
644 	int argc;
645 	char *argv[];
646 {
647 	if (connected)
648 		printf("Connected to %s.\n", hostname);
649 	else
650 		printf("Not connected.\n");
651 	printf("Mode: %s Verbose: %s Tracing: %s\n", mode,
652 		verbose ? "on" : "off", trace ? "on" : "off");
653 	printf("Rexmt-interval: %d seconds, Max-timeout: %d seconds\n",
654 		rexmtval, maxtimeout);
655 }
656 
657 void
658 intr(dummy)
659 	int dummy;
660 {
661 
662 	signal(SIGALRM, SIG_IGN);
663 	alarm(0);
664 	longjmp(toplevel, -1);
665 }
666 
667 char *
668 tail(filename)
669 	char *filename;
670 {
671 	char *s;
672 
673 	while (*filename) {
674 		s = strrchr(filename, '/');
675 		if (s == NULL)
676 			break;
677 		if (s[1])
678 			return (s + 1);
679 		*s = '\0';
680 	}
681 	return (filename);
682 }
683 
684 /*
685  * Command parser.
686  */
687 static __dead void
688 command()
689 {
690 	struct cmd *c;
691 
692 	for (;;) {
693 		printf("%s> ", prompt);
694 		if (fgets(line, LBUFLEN, stdin) == 0) {
695 			if (feof(stdin)) {
696 				exit(0);
697 			} else {
698 				continue;
699 			}
700 		}
701 		if ((line[0] == 0) || (line[0] == '\n'))
702 			continue;
703 		makeargv();
704 		if (margc == 0)
705 			continue;
706 		c = getcmd(margv[0]);
707 		if (c == (struct cmd *)-1) {
708 			printf("?Ambiguous command\n");
709 			continue;
710 		}
711 		if (c == 0) {
712 			printf("?Invalid command\n");
713 			continue;
714 		}
715 		(*c->handler)(margc, margv);
716 	}
717 }
718 
719 struct cmd *
720 getcmd(name)
721 	char *name;
722 {
723 	char *p, *q;
724 	struct cmd *c, *found;
725 	int nmatches, longest;
726 
727 	longest = 0;
728 	nmatches = 0;
729 	found = 0;
730 	for (c = cmdtab; (p = c->name) != NULL; c++) {
731 		for (q = name; *q == *p++; q++)
732 			if (*q == 0)		/* exact match? */
733 				return (c);
734 		if (!*q) {			/* the name was a prefix */
735 			if (q - name > longest) {
736 				longest = q - name;
737 				nmatches = 1;
738 				found = c;
739 			} else if (q - name == longest)
740 				nmatches++;
741 		}
742 	}
743 	if (nmatches > 1)
744 		return ((struct cmd *)-1);
745 	return (found);
746 }
747 
748 /*
749  * Slice a string up into argc/argv.
750  */
751 static void
752 makeargv()
753 {
754 	char *cp;
755 	char **argp = margv;
756 
757 	margc = 0;
758 	for (cp = line; *cp;) {
759 		while (isspace((unsigned char)*cp))
760 			cp++;
761 		if (*cp == '\0')
762 			break;
763 		*argp++ = cp;
764 		margc += 1;
765 		while (*cp != '\0' && !isspace((unsigned char)*cp))
766 			cp++;
767 		if (*cp == '\0')
768 			break;
769 		*cp++ = '\0';
770 	}
771 	*argp++ = 0;
772 }
773 
774 void
775 quit(argc, argv)
776 	int argc;
777 	char *argv[];
778 {
779 
780 	exit(0);
781 }
782 
783 /*
784  * Help command.
785  */
786 void
787 help(argc, argv)
788 	int argc;
789 	char *argv[];
790 {
791 	struct cmd *c;
792 
793 	if (argc == 1) {
794 		printf("Commands may be abbreviated.  Commands are:\n\n");
795 		for (c = cmdtab; c->name; c++)
796 			printf("%-*s\t%s\n", (int)HELPINDENT, c->name, c->help);
797 		return;
798 	}
799 	while (--argc > 0) {
800 		char *arg;
801 		arg = *++argv;
802 		c = getcmd(arg);
803 		if (c == (struct cmd *)-1)
804 			printf("?Ambiguous help command %s\n", arg);
805 		else if (c == (struct cmd *)0)
806 			printf("?Invalid help command %s\n", arg);
807 		else
808 			printf("%s\n", c->help);
809 	}
810 }
811 
812 void
813 settrace(argc, argv)
814 	int argc;
815 	char **argv;
816 {
817 	trace = !trace;
818 	printf("Packet tracing %s.\n", trace ? "on" : "off");
819 }
820 
821 void
822 setverbose(argc, argv)
823 	int argc;
824 	char **argv;
825 {
826 	verbose = !verbose;
827 	printf("Verbose mode %s.\n", verbose ? "on" : "off");
828 }
829 
830 void
831 settsize(argc, argv)
832 	int argc;
833 	char **argv;
834 {
835 	tsize = !tsize;
836 	printf("Tsize mode %s.\n", tsize ? "on" : "off");
837 }
838 
839 void
840 settimeoutopt(argc, argv)
841 	int argc;
842 	char **argv;
843 {
844 	tout = !tout;
845 	printf("Timeout option %s.\n", tout ? "on" : "off");
846 }
847