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