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