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