xref: /freebsd/usr.bin/tftp/main.c (revision 1b0fa6fa40ecc6b97e9fbdea630ba2bdbe632077)
19b50d902SRodney W. Grimes /*
29b50d902SRodney W. Grimes  * Copyright (c) 1983, 1993
39b50d902SRodney W. Grimes  *	The Regents of the University of California.  All rights reserved.
49b50d902SRodney W. Grimes  *
59b50d902SRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
69b50d902SRodney W. Grimes  * modification, are permitted provided that the following conditions
79b50d902SRodney W. Grimes  * are met:
89b50d902SRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
99b50d902SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
109b50d902SRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
119b50d902SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
129b50d902SRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
139b50d902SRodney W. Grimes  * 3. All advertising materials mentioning features or use of this software
149b50d902SRodney W. Grimes  *    must display the following acknowledgement:
159b50d902SRodney W. Grimes  *	This product includes software developed by the University of
169b50d902SRodney W. Grimes  *	California, Berkeley and its contributors.
179b50d902SRodney W. Grimes  * 4. Neither the name of the University nor the names of its contributors
189b50d902SRodney W. Grimes  *    may be used to endorse or promote products derived from this software
199b50d902SRodney W. Grimes  *    without specific prior written permission.
209b50d902SRodney W. Grimes  *
219b50d902SRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
229b50d902SRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
239b50d902SRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
249b50d902SRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
259b50d902SRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
269b50d902SRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
279b50d902SRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
289b50d902SRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
299b50d902SRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
309b50d902SRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
319b50d902SRodney W. Grimes  * SUCH DAMAGE.
329b50d902SRodney W. Grimes  */
339b50d902SRodney W. Grimes 
349b50d902SRodney W. Grimes #ifndef lint
35fd129a02SPhilippe Charnier static const char copyright[] =
369b50d902SRodney W. Grimes "@(#) Copyright (c) 1983, 1993\n\
379b50d902SRodney W. Grimes 	The Regents of the University of California.  All rights reserved.\n";
388049f797SMark Murray #endif
399b50d902SRodney W. Grimes 
408f4c8256SDavid Malone #if 0
419b50d902SRodney W. Grimes #ifndef lint
428f4c8256SDavid Malone static char sccsid[] = "@(#)main.c	8.1 (Berkeley) 6/6/93";
43fd129a02SPhilippe Charnier #endif
448f4c8256SDavid Malone #endif
458f4c8256SDavid Malone 
468f4c8256SDavid Malone #include <sys/cdefs.h>
478f4c8256SDavid Malone __FBSDID("$FreeBSD$");
489b50d902SRodney W. Grimes 
499b50d902SRodney W. Grimes /* Many bug fixes are from Jim Guyton <guyton@rand-unix> */
509b50d902SRodney W. Grimes 
519b50d902SRodney W. Grimes /*
529b50d902SRodney W. Grimes  * TFTP User Program -- Command Interface.
539b50d902SRodney W. Grimes  */
54fd129a02SPhilippe Charnier #include <sys/param.h>
559b50d902SRodney W. Grimes #include <sys/types.h>
569b50d902SRodney W. Grimes #include <sys/socket.h>
579b50d902SRodney W. Grimes #include <sys/file.h>
58a716ad66SWarner Losh #include <sys/param.h>
599b50d902SRodney W. Grimes 
609b50d902SRodney W. Grimes #include <netinet/in.h>
619b50d902SRodney W. Grimes 
629b50d902SRodney W. Grimes #include <arpa/inet.h>
639b50d902SRodney W. Grimes 
649b50d902SRodney W. Grimes #include <ctype.h>
65fd129a02SPhilippe Charnier #include <err.h>
668979160aSBruce Evans #include <histedit.h>
679b50d902SRodney W. Grimes #include <netdb.h>
689b50d902SRodney W. Grimes #include <setjmp.h>
699b50d902SRodney W. Grimes #include <signal.h>
709b50d902SRodney W. Grimes #include <stdio.h>
719b50d902SRodney W. Grimes #include <stdlib.h>
729b50d902SRodney W. Grimes #include <string.h>
739b50d902SRodney W. Grimes #include <unistd.h>
749b50d902SRodney W. Grimes 
759b50d902SRodney W. Grimes #include "extern.h"
769b50d902SRodney W. Grimes 
77c33ed450SMatthew N. Dodd #define	MAXLINE		200
788979160aSBruce Evans #define	TIMEOUT		5		/* secs between rexmt's */
79c33ed450SMatthew N. Dodd 
804dac6235SHajimu UMEMOTO struct	sockaddr_storage peeraddr;
819b50d902SRodney W. Grimes int	f;
829b50d902SRodney W. Grimes int	trace;
839b50d902SRodney W. Grimes int	verbose;
849b50d902SRodney W. Grimes int	connected;
859b50d902SRodney W. Grimes char	mode[32];
86c33ed450SMatthew N. Dodd char	line[MAXLINE];
879b50d902SRodney W. Grimes int	margc;
887f3a5689STim J. Robbins #define	MAX_MARGV	20
897f3a5689STim J. Robbins char	*margv[MAX_MARGV];
909b50d902SRodney W. Grimes jmp_buf	toplevel;
9173f899caSBrian S. Dean volatile int txrx_error;
929b50d902SRodney W. Grimes 
933f330d7dSWarner Losh void	get(int, char **);
943f330d7dSWarner Losh void	help(int, char **);
953f330d7dSWarner Losh void	intr(int);
963f330d7dSWarner Losh void	modecmd(int, char **);
973f330d7dSWarner Losh void	put(int, char **);
983f330d7dSWarner Losh void	quit(int, char **);
993f330d7dSWarner Losh void	setascii(int, char **);
1003f330d7dSWarner Losh void	setbinary(int, char **);
1018da9a6b0SDavid Malone void	setpeer0(char *, const char *);
1023f330d7dSWarner Losh void	setpeer(int, char **);
1033f330d7dSWarner Losh void	setrexmt(int, char **);
1043f330d7dSWarner Losh void	settimeout(int, char **);
1053f330d7dSWarner Losh void	settrace(int, char **);
1063f330d7dSWarner Losh void	setverbose(int, char **);
1073f330d7dSWarner Losh void	status(int, char **);
1089b50d902SRodney W. Grimes 
1093f330d7dSWarner Losh static void command(void) __dead2;
1103f330d7dSWarner Losh static const char *command_prompt(void);
1119b50d902SRodney W. Grimes 
1121b0fa6faSXin LI static void getusage(const char *);
1133f330d7dSWarner Losh static void makeargv(void);
1141b0fa6faSXin LI static void putusage(const char *);
1153f330d7dSWarner Losh static void settftpmode(const char *);
1168049f797SMark Murray 
1173f330d7dSWarner Losh char	*tail(char *);
1183f330d7dSWarner Losh struct	cmd *getcmd(char *);
1199b50d902SRodney W. Grimes 
1209b50d902SRodney W. Grimes #define HELPINDENT (sizeof("connect"))
1219b50d902SRodney W. Grimes 
1229b50d902SRodney W. Grimes struct cmd {
1238049f797SMark Murray 	const char	*name;
1249b50d902SRodney W. Grimes 	char	*help;
1253f330d7dSWarner Losh 	void	(*handler)(int, char **);
1269b50d902SRodney W. Grimes };
1279b50d902SRodney W. Grimes 
1289b50d902SRodney W. Grimes char	vhelp[] = "toggle verbose mode";
1299b50d902SRodney W. Grimes char	thelp[] = "toggle packet tracing";
1309b50d902SRodney W. Grimes char	chelp[] = "connect to remote tftp";
1319b50d902SRodney W. Grimes char	qhelp[] = "exit tftp";
1329b50d902SRodney W. Grimes char	hhelp[] = "print help information";
1339b50d902SRodney W. Grimes char	shelp[] = "send file";
1349b50d902SRodney W. Grimes char	rhelp[] = "receive file";
1359b50d902SRodney W. Grimes char	mhelp[] = "set file transfer mode";
1369b50d902SRodney W. Grimes char	sthelp[] = "show current status";
1379b50d902SRodney W. Grimes char	xhelp[] = "set per-packet retransmission timeout";
1389b50d902SRodney W. Grimes char	ihelp[] = "set total retransmission timeout";
1399b50d902SRodney W. Grimes char    ashelp[] = "set mode to netascii";
1409b50d902SRodney W. Grimes char    bnhelp[] = "set mode to octet";
1419b50d902SRodney W. Grimes 
1429b50d902SRodney W. Grimes struct cmd cmdtab[] = {
1439b50d902SRodney W. Grimes 	{ "connect",	chelp,		setpeer },
1449b50d902SRodney W. Grimes 	{ "mode",       mhelp,          modecmd },
1459b50d902SRodney W. Grimes 	{ "put",	shelp,		put },
1469b50d902SRodney W. Grimes 	{ "get",	rhelp,		get },
1479b50d902SRodney W. Grimes 	{ "quit",	qhelp,		quit },
1489b50d902SRodney W. Grimes 	{ "verbose",	vhelp,		setverbose },
1499b50d902SRodney W. Grimes 	{ "trace",	thelp,		settrace },
1509b50d902SRodney W. Grimes 	{ "status",	sthelp,		status },
1519b50d902SRodney W. Grimes 	{ "binary",     bnhelp,         setbinary },
1529b50d902SRodney W. Grimes 	{ "ascii",      ashelp,         setascii },
1539b50d902SRodney W. Grimes 	{ "rexmt",	xhelp,		setrexmt },
1549b50d902SRodney W. Grimes 	{ "timeout",	ihelp,		settimeout },
1559b50d902SRodney W. Grimes 	{ "?",		hhelp,		help },
1568049f797SMark Murray 	{ NULL, NULL, NULL }
1579b50d902SRodney W. Grimes };
1589b50d902SRodney W. Grimes 
1599b50d902SRodney W. Grimes int
1601b0fa6faSXin LI main(int argc, char *argv[])
1619b50d902SRodney W. Grimes {
1624dac6235SHajimu UMEMOTO 	f = -1;
1639b50d902SRodney W. Grimes 	strcpy(mode, "netascii");
1649b50d902SRodney W. Grimes 	signal(SIGINT, intr);
1659b50d902SRodney W. Grimes 	if (argc > 1) {
1669b50d902SRodney W. Grimes 		if (setjmp(toplevel) != 0)
16773f899caSBrian S. Dean 			exit(txrx_error);
1689b50d902SRodney W. Grimes 		setpeer(argc, argv);
1699b50d902SRodney W. Grimes 	}
1709b50d902SRodney W. Grimes 	if (setjmp(toplevel) != 0)
1719b50d902SRodney W. Grimes 		(void)putchar('\n');
1729b50d902SRodney W. Grimes 	command();
1739b50d902SRodney W. Grimes }
1749b50d902SRodney W. Grimes 
175fd129a02SPhilippe Charnier char    hostname[MAXHOSTNAMELEN];
1769b50d902SRodney W. Grimes 
1779b50d902SRodney W. Grimes void
1781b0fa6faSXin LI setpeer0(char *host, const char *port)
1794dac6235SHajimu UMEMOTO {
1804dac6235SHajimu UMEMOTO 	struct addrinfo hints, *res0, *res;
1814dac6235SHajimu UMEMOTO 	int error;
1824dac6235SHajimu UMEMOTO 	struct sockaddr_storage ss;
1838da9a6b0SDavid Malone 	const char *cause = "unknown";
1844dac6235SHajimu UMEMOTO 
1854dac6235SHajimu UMEMOTO 	if (connected) {
1864dac6235SHajimu UMEMOTO 		close(f);
1874dac6235SHajimu UMEMOTO 		f = -1;
1884dac6235SHajimu UMEMOTO 	}
1894dac6235SHajimu UMEMOTO 	connected = 0;
1904dac6235SHajimu UMEMOTO 
1914dac6235SHajimu UMEMOTO 	memset(&hints, 0, sizeof(hints));
1924dac6235SHajimu UMEMOTO 	hints.ai_family = PF_UNSPEC;
1934dac6235SHajimu UMEMOTO 	hints.ai_socktype = SOCK_DGRAM;
1944dac6235SHajimu UMEMOTO 	hints.ai_protocol = IPPROTO_UDP;
1954dac6235SHajimu UMEMOTO 	hints.ai_flags = AI_CANONNAME;
1964dac6235SHajimu UMEMOTO 	if (!port)
1974dac6235SHajimu UMEMOTO 		port = "tftp";
1984dac6235SHajimu UMEMOTO 	error = getaddrinfo(host, port, &hints, &res0);
1994dac6235SHajimu UMEMOTO 	if (error) {
2004dac6235SHajimu UMEMOTO 		warnx("%s", gai_strerror(error));
2014dac6235SHajimu UMEMOTO 		return;
2024dac6235SHajimu UMEMOTO 	}
2034dac6235SHajimu UMEMOTO 
2044dac6235SHajimu UMEMOTO 	for (res = res0; res; res = res->ai_next) {
2054dac6235SHajimu UMEMOTO 		if (res->ai_addrlen > sizeof(peeraddr))
2064dac6235SHajimu UMEMOTO 			continue;
2074dac6235SHajimu UMEMOTO 		f = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
2084dac6235SHajimu UMEMOTO 		if (f < 0) {
2094dac6235SHajimu UMEMOTO 			cause = "socket";
2104dac6235SHajimu UMEMOTO 			continue;
2114dac6235SHajimu UMEMOTO 		}
2124dac6235SHajimu UMEMOTO 
2134dac6235SHajimu UMEMOTO 		memset(&ss, 0, sizeof(ss));
2144dac6235SHajimu UMEMOTO 		ss.ss_family = res->ai_family;
2154dac6235SHajimu UMEMOTO 		ss.ss_len = res->ai_addrlen;
2164dac6235SHajimu UMEMOTO 		if (bind(f, (struct sockaddr *)&ss, ss.ss_len) < 0) {
2174dac6235SHajimu UMEMOTO 			cause = "bind";
2184dac6235SHajimu UMEMOTO 			close(f);
2194dac6235SHajimu UMEMOTO 			f = -1;
2204dac6235SHajimu UMEMOTO 			continue;
2214dac6235SHajimu UMEMOTO 		}
2224dac6235SHajimu UMEMOTO 
2234dac6235SHajimu UMEMOTO 		break;
2244dac6235SHajimu UMEMOTO 	}
2254dac6235SHajimu UMEMOTO 
2264dac6235SHajimu UMEMOTO 	if (f < 0)
2274dac6235SHajimu UMEMOTO 		warn("%s", cause);
2284dac6235SHajimu UMEMOTO 	else {
2294dac6235SHajimu UMEMOTO 		/* res->ai_addr <= sizeof(peeraddr) is guaranteed */
2304dac6235SHajimu UMEMOTO 		memcpy(&peeraddr, res->ai_addr, res->ai_addrlen);
2314dac6235SHajimu UMEMOTO 		if (res->ai_canonname) {
2323a4e1f47SXin LI 			(void) strlcpy(hostname, res->ai_canonname,
2334dac6235SHajimu UMEMOTO 				sizeof(hostname));
2344dac6235SHajimu UMEMOTO 		} else
2353a4e1f47SXin LI 			(void) strlcpy(hostname, host, sizeof(hostname));
2364dac6235SHajimu UMEMOTO 		connected = 1;
2374dac6235SHajimu UMEMOTO 	}
2384dac6235SHajimu UMEMOTO 
2394dac6235SHajimu UMEMOTO 	freeaddrinfo(res0);
2404dac6235SHajimu UMEMOTO }
2414dac6235SHajimu UMEMOTO 
2424dac6235SHajimu UMEMOTO void
2431b0fa6faSXin LI setpeer(int argc, char *argv[])
2449b50d902SRodney W. Grimes {
2459b50d902SRodney W. Grimes 
2469b50d902SRodney W. Grimes 	if (argc < 2) {
2479b50d902SRodney W. Grimes 		strcpy(line, "Connect ");
2489b50d902SRodney W. Grimes 		printf("(to) ");
249ca22ff9eSJoerg Wunsch 		fgets(&line[strlen(line)], sizeof line - strlen(line), stdin);
2509b50d902SRodney W. Grimes 		makeargv();
2519b50d902SRodney W. Grimes 		argc = margc;
2529b50d902SRodney W. Grimes 		argv = margv;
2539b50d902SRodney W. Grimes 	}
254b50764b0SGuido van Rooij 	if ((argc < 2) || (argc > 3)) {
255891ca8cfSSimon L. B. Nielsen 		printf("usage: %s [host [port]]\n", argv[0]);
2569b50d902SRodney W. Grimes 		return;
2579b50d902SRodney W. Grimes 	}
2584dac6235SHajimu UMEMOTO 	if (argc == 3)
2594dac6235SHajimu UMEMOTO 		setpeer0(argv[1], argv[2]);
2602e34a0f4SJonathan Chen 	else
2612e34a0f4SJonathan Chen 		setpeer0(argv[1], NULL);
2629b50d902SRodney W. Grimes }
2639b50d902SRodney W. Grimes 
2649b50d902SRodney W. Grimes struct	modes {
2658049f797SMark Murray 	const char *m_name;
2668049f797SMark Murray 	const char *m_mode;
2679b50d902SRodney W. Grimes } modes[] = {
2689b50d902SRodney W. Grimes 	{ "ascii",	"netascii" },
2699b50d902SRodney W. Grimes 	{ "netascii",   "netascii" },
2709b50d902SRodney W. Grimes 	{ "binary",     "octet" },
2719b50d902SRodney W. Grimes 	{ "image",      "octet" },
2729b50d902SRodney W. Grimes 	{ "octet",     "octet" },
2739b50d902SRodney W. Grimes /*      { "mail",       "mail" },       */
2749b50d902SRodney W. Grimes 	{ 0,		0 }
2759b50d902SRodney W. Grimes };
2769b50d902SRodney W. Grimes 
2779b50d902SRodney W. Grimes void
2781b0fa6faSXin LI modecmd(int argc, char *argv[])
2799b50d902SRodney W. Grimes {
2808049f797SMark Murray 	struct modes *p;
2818049f797SMark Murray 	const char *sep;
2829b50d902SRodney W. Grimes 
2839b50d902SRodney W. Grimes 	if (argc < 2) {
2849b50d902SRodney W. Grimes 		printf("Using %s mode to transfer files.\n", mode);
2859b50d902SRodney W. Grimes 		return;
2869b50d902SRodney W. Grimes 	}
2879b50d902SRodney W. Grimes 	if (argc == 2) {
2889b50d902SRodney W. Grimes 		for (p = modes; p->m_name; p++)
2899b50d902SRodney W. Grimes 			if (strcmp(argv[1], p->m_name) == 0)
2909b50d902SRodney W. Grimes 				break;
2919b50d902SRodney W. Grimes 		if (p->m_name) {
2929b50d902SRodney W. Grimes 			settftpmode(p->m_mode);
2939b50d902SRodney W. Grimes 			return;
2949b50d902SRodney W. Grimes 		}
2959b50d902SRodney W. Grimes 		printf("%s: unknown mode\n", argv[1]);
2969b50d902SRodney W. Grimes 		/* drop through and print usage message */
2979b50d902SRodney W. Grimes 	}
2989b50d902SRodney W. Grimes 
2999b50d902SRodney W. Grimes 	printf("usage: %s [", argv[0]);
3009b50d902SRodney W. Grimes 	sep = " ";
3019b50d902SRodney W. Grimes 	for (p = modes; p->m_name; p++) {
3029b50d902SRodney W. Grimes 		printf("%s%s", sep, p->m_name);
3039b50d902SRodney W. Grimes 		if (*sep == ' ')
3049b50d902SRodney W. Grimes 			sep = " | ";
3059b50d902SRodney W. Grimes 	}
3069b50d902SRodney W. Grimes 	printf(" ]\n");
3079b50d902SRodney W. Grimes 	return;
3089b50d902SRodney W. Grimes }
3099b50d902SRodney W. Grimes 
3109b50d902SRodney W. Grimes void
3111b0fa6faSXin LI setbinary(int argc __unused, char *argv[] __unused)
3129b50d902SRodney W. Grimes {
3139b50d902SRodney W. Grimes 
3149b50d902SRodney W. Grimes 	settftpmode("octet");
3159b50d902SRodney W. Grimes }
3169b50d902SRodney W. Grimes 
3179b50d902SRodney W. Grimes void
3181b0fa6faSXin LI setascii(int argc __unused, char *argv[] __unused)
3199b50d902SRodney W. Grimes {
3209b50d902SRodney W. Grimes 
3219b50d902SRodney W. Grimes 	settftpmode("netascii");
3229b50d902SRodney W. Grimes }
3239b50d902SRodney W. Grimes 
3249b50d902SRodney W. Grimes static void
3251b0fa6faSXin LI settftpmode(const char *newmode)
3269b50d902SRodney W. Grimes {
3279b50d902SRodney W. Grimes 	strcpy(mode, newmode);
3289b50d902SRodney W. Grimes 	if (verbose)
3299b50d902SRodney W. Grimes 		printf("mode set to %s\n", mode);
3309b50d902SRodney W. Grimes }
3319b50d902SRodney W. Grimes 
3329b50d902SRodney W. Grimes 
3339b50d902SRodney W. Grimes /*
3349b50d902SRodney W. Grimes  * Send file(s).
3359b50d902SRodney W. Grimes  */
3369b50d902SRodney W. Grimes void
3371b0fa6faSXin LI put(int argc, char *argv[])
3389b50d902SRodney W. Grimes {
3399b50d902SRodney W. Grimes 	int fd;
3408049f797SMark Murray 	int n;
3418049f797SMark Murray 	char *cp, *targ;
3429b50d902SRodney W. Grimes 
3439b50d902SRodney W. Grimes 	if (argc < 2) {
3449b50d902SRodney W. Grimes 		strcpy(line, "send ");
3459b50d902SRodney W. Grimes 		printf("(file) ");
346ca22ff9eSJoerg Wunsch 		fgets(&line[strlen(line)], sizeof line - strlen(line), stdin);
3479b50d902SRodney W. Grimes 		makeargv();
3489b50d902SRodney W. Grimes 		argc = margc;
3499b50d902SRodney W. Grimes 		argv = margv;
3509b50d902SRodney W. Grimes 	}
3519b50d902SRodney W. Grimes 	if (argc < 2) {
3529b50d902SRodney W. Grimes 		putusage(argv[0]);
3539b50d902SRodney W. Grimes 		return;
3549b50d902SRodney W. Grimes 	}
3559b50d902SRodney W. Grimes 	targ = argv[argc - 1];
3564dac6235SHajimu UMEMOTO 	if (rindex(argv[argc - 1], ':')) {
3578049f797SMark Murray 		char *lcp;
3589b50d902SRodney W. Grimes 
3599b50d902SRodney W. Grimes 		for (n = 1; n < argc - 1; n++)
3609b50d902SRodney W. Grimes 			if (index(argv[n], ':')) {
3619b50d902SRodney W. Grimes 				putusage(argv[0]);
3629b50d902SRodney W. Grimes 				return;
3639b50d902SRodney W. Grimes 			}
3648049f797SMark Murray 		lcp = argv[argc - 1];
3654dac6235SHajimu UMEMOTO 		targ = rindex(lcp, ':');
3669b50d902SRodney W. Grimes 		*targ++ = 0;
3674dac6235SHajimu UMEMOTO 		if (lcp[0] == '[' && lcp[strlen(lcp) - 1] == ']') {
3684dac6235SHajimu UMEMOTO 			lcp[strlen(lcp) - 1] = '\0';
3694dac6235SHajimu UMEMOTO 			lcp++;
3709b50d902SRodney W. Grimes 		}
3714dac6235SHajimu UMEMOTO 		setpeer0(lcp, NULL);
3729b50d902SRodney W. Grimes 	}
3739b50d902SRodney W. Grimes 	if (!connected) {
3749b50d902SRodney W. Grimes 		printf("No target machine specified.\n");
3759b50d902SRodney W. Grimes 		return;
3769b50d902SRodney W. Grimes 	}
3779b50d902SRodney W. Grimes 	if (argc < 4) {
3789b50d902SRodney W. Grimes 		cp = argc == 2 ? tail(targ) : argv[1];
3799b50d902SRodney W. Grimes 		fd = open(cp, O_RDONLY);
3809b50d902SRodney W. Grimes 		if (fd < 0) {
381fd129a02SPhilippe Charnier 			warn("%s", cp);
3829b50d902SRodney W. Grimes 			return;
3839b50d902SRodney W. Grimes 		}
3849b50d902SRodney W. Grimes 		if (verbose)
3859b50d902SRodney W. Grimes 			printf("putting %s to %s:%s [%s]\n",
3869b50d902SRodney W. Grimes 				cp, hostname, targ, mode);
3878692ad46SDavid Greenman 		xmitfile(fd, targ, mode);
3889b50d902SRodney W. Grimes 		return;
3899b50d902SRodney W. Grimes 	}
3909b50d902SRodney W. Grimes 				/* this assumes the target is a directory */
3919b50d902SRodney W. Grimes 				/* on a remote unix system.  hmmmm.  */
3929b50d902SRodney W. Grimes 	cp = index(targ, '\0');
3939b50d902SRodney W. Grimes 	*cp++ = '/';
3949b50d902SRodney W. Grimes 	for (n = 1; n < argc - 1; n++) {
3959b50d902SRodney W. Grimes 		strcpy(cp, tail(argv[n]));
3969b50d902SRodney W. Grimes 		fd = open(argv[n], O_RDONLY);
3979b50d902SRodney W. Grimes 		if (fd < 0) {
398fd129a02SPhilippe Charnier 			warn("%s", argv[n]);
3999b50d902SRodney W. Grimes 			continue;
4009b50d902SRodney W. Grimes 		}
4019b50d902SRodney W. Grimes 		if (verbose)
4029b50d902SRodney W. Grimes 			printf("putting %s to %s:%s [%s]\n",
4039b50d902SRodney W. Grimes 				argv[n], hostname, targ, mode);
4048692ad46SDavid Greenman 		xmitfile(fd, targ, mode);
4059b50d902SRodney W. Grimes 	}
4069b50d902SRodney W. Grimes }
4079b50d902SRodney W. Grimes 
4089b50d902SRodney W. Grimes static void
4091b0fa6faSXin LI putusage(const char *s)
4109b50d902SRodney W. Grimes {
411891ca8cfSSimon L. B. Nielsen 	printf("usage: %s file [[host:]remotename]\n", s);
412891ca8cfSSimon L. B. Nielsen 	printf("       %s file1 file2 ... fileN [[host:]remote-directory]\n", s);
4139b50d902SRodney W. Grimes }
4149b50d902SRodney W. Grimes 
4159b50d902SRodney W. Grimes /*
4169b50d902SRodney W. Grimes  * Receive file(s).
4179b50d902SRodney W. Grimes  */
4189b50d902SRodney W. Grimes void
4191b0fa6faSXin LI get(int argc, char *argv[])
4209b50d902SRodney W. Grimes {
4219b50d902SRodney W. Grimes 	int fd;
4228049f797SMark Murray 	int n;
4238049f797SMark Murray 	char *cp;
4249b50d902SRodney W. Grimes 	char *src;
4259b50d902SRodney W. Grimes 
4269b50d902SRodney W. Grimes 	if (argc < 2) {
4279b50d902SRodney W. Grimes 		strcpy(line, "get ");
4289b50d902SRodney W. Grimes 		printf("(files) ");
429ca22ff9eSJoerg Wunsch 		fgets(&line[strlen(line)], sizeof line - strlen(line), stdin);
4309b50d902SRodney W. Grimes 		makeargv();
4319b50d902SRodney W. Grimes 		argc = margc;
4329b50d902SRodney W. Grimes 		argv = margv;
4339b50d902SRodney W. Grimes 	}
4349b50d902SRodney W. Grimes 	if (argc < 2) {
4359b50d902SRodney W. Grimes 		getusage(argv[0]);
4369b50d902SRodney W. Grimes 		return;
4379b50d902SRodney W. Grimes 	}
4389b50d902SRodney W. Grimes 	if (!connected) {
4399b50d902SRodney W. Grimes 		for (n = 1; n < argc ; n++)
4404dac6235SHajimu UMEMOTO 			if (rindex(argv[n], ':') == 0) {
4419b50d902SRodney W. Grimes 				getusage(argv[0]);
4429b50d902SRodney W. Grimes 				return;
4439b50d902SRodney W. Grimes 			}
4449b50d902SRodney W. Grimes 	}
4459b50d902SRodney W. Grimes 	for (n = 1; n < argc ; n++) {
4464dac6235SHajimu UMEMOTO 		src = rindex(argv[n], ':');
4479b50d902SRodney W. Grimes 		if (src == NULL)
4489b50d902SRodney W. Grimes 			src = argv[n];
4499b50d902SRodney W. Grimes 		else {
4504dac6235SHajimu UMEMOTO 			char *lcp;
4519b50d902SRodney W. Grimes 
4529b50d902SRodney W. Grimes 			*src++ = 0;
4534dac6235SHajimu UMEMOTO 			lcp = argv[n];
4544dac6235SHajimu UMEMOTO 			if (lcp[0] == '[' && lcp[strlen(lcp) - 1] == ']') {
4554dac6235SHajimu UMEMOTO 				lcp[strlen(lcp) - 1] = '\0';
4564dac6235SHajimu UMEMOTO 				lcp++;
4579b50d902SRodney W. Grimes 			}
4584dac6235SHajimu UMEMOTO 			setpeer0(lcp, NULL);
4594dac6235SHajimu UMEMOTO 			if (!connected)
4604dac6235SHajimu UMEMOTO 				continue;
4619b50d902SRodney W. Grimes 		}
4629b50d902SRodney W. Grimes 		if (argc < 4) {
4639b50d902SRodney W. Grimes 			cp = argc == 3 ? argv[2] : tail(src);
4649b50d902SRodney W. Grimes 			fd = creat(cp, 0644);
4659b50d902SRodney W. Grimes 			if (fd < 0) {
466fd129a02SPhilippe Charnier 				warn("%s", cp);
4679b50d902SRodney W. Grimes 				return;
4689b50d902SRodney W. Grimes 			}
4699b50d902SRodney W. Grimes 			if (verbose)
4709b50d902SRodney W. Grimes 				printf("getting from %s:%s to %s [%s]\n",
4719b50d902SRodney W. Grimes 					hostname, src, cp, mode);
4729b50d902SRodney W. Grimes 			recvfile(fd, src, mode);
4739b50d902SRodney W. Grimes 			break;
4749b50d902SRodney W. Grimes 		}
4759b50d902SRodney W. Grimes 		cp = tail(src);         /* new .. jdg */
4769b50d902SRodney W. Grimes 		fd = creat(cp, 0644);
4779b50d902SRodney W. Grimes 		if (fd < 0) {
478fd129a02SPhilippe Charnier 			warn("%s", cp);
4799b50d902SRodney W. Grimes 			continue;
4809b50d902SRodney W. Grimes 		}
4819b50d902SRodney W. Grimes 		if (verbose)
4829b50d902SRodney W. Grimes 			printf("getting from %s:%s to %s [%s]\n",
4839b50d902SRodney W. Grimes 				hostname, src, cp, mode);
4849b50d902SRodney W. Grimes 		recvfile(fd, src, mode);
4859b50d902SRodney W. Grimes 	}
4869b50d902SRodney W. Grimes }
4879b50d902SRodney W. Grimes 
4889b50d902SRodney W. Grimes static void
4891b0fa6faSXin LI getusage(const char *s)
4909b50d902SRodney W. Grimes {
491891ca8cfSSimon L. B. Nielsen 	printf("usage: %s [host:]file [localname]\n", s);
492891ca8cfSSimon L. B. Nielsen 	printf("       %s [host1:]file1 [host2:]file2 ... [hostN:]fileN\n", s);
4939b50d902SRodney W. Grimes }
4949b50d902SRodney W. Grimes 
4959b50d902SRodney W. Grimes int	rexmtval = TIMEOUT;
4969b50d902SRodney W. Grimes 
4979b50d902SRodney W. Grimes void
4981b0fa6faSXin LI setrexmt(int argc, char *argv[])
4999b50d902SRodney W. Grimes {
5009b50d902SRodney W. Grimes 	int t;
5019b50d902SRodney W. Grimes 
5029b50d902SRodney W. Grimes 	if (argc < 2) {
5039b50d902SRodney W. Grimes 		strcpy(line, "Rexmt-timeout ");
5049b50d902SRodney W. Grimes 		printf("(value) ");
505ca22ff9eSJoerg Wunsch 		fgets(&line[strlen(line)], sizeof line - strlen(line), stdin);
5069b50d902SRodney W. Grimes 		makeargv();
5079b50d902SRodney W. Grimes 		argc = margc;
5089b50d902SRodney W. Grimes 		argv = margv;
5099b50d902SRodney W. Grimes 	}
5109b50d902SRodney W. Grimes 	if (argc != 2) {
5119b50d902SRodney W. Grimes 		printf("usage: %s value\n", argv[0]);
5129b50d902SRodney W. Grimes 		return;
5139b50d902SRodney W. Grimes 	}
5149b50d902SRodney W. Grimes 	t = atoi(argv[1]);
5159b50d902SRodney W. Grimes 	if (t < 0)
5169b50d902SRodney W. Grimes 		printf("%s: bad value\n", argv[1]);
5179b50d902SRodney W. Grimes 	else
5189b50d902SRodney W. Grimes 		rexmtval = t;
5199b50d902SRodney W. Grimes }
5209b50d902SRodney W. Grimes 
5219b50d902SRodney W. Grimes int	maxtimeout = 5 * TIMEOUT;
5229b50d902SRodney W. Grimes 
5239b50d902SRodney W. Grimes void
5241b0fa6faSXin LI settimeout(int argc, char *argv[])
5259b50d902SRodney W. Grimes {
5269b50d902SRodney W. Grimes 	int t;
5279b50d902SRodney W. Grimes 
5289b50d902SRodney W. Grimes 	if (argc < 2) {
5299b50d902SRodney W. Grimes 		strcpy(line, "Maximum-timeout ");
5309b50d902SRodney W. Grimes 		printf("(value) ");
531ca22ff9eSJoerg Wunsch 		fgets(&line[strlen(line)], sizeof line - strlen(line), stdin);
5329b50d902SRodney W. Grimes 		makeargv();
5339b50d902SRodney W. Grimes 		argc = margc;
5349b50d902SRodney W. Grimes 		argv = margv;
5359b50d902SRodney W. Grimes 	}
5369b50d902SRodney W. Grimes 	if (argc != 2) {
5379b50d902SRodney W. Grimes 		printf("usage: %s value\n", argv[0]);
5389b50d902SRodney W. Grimes 		return;
5399b50d902SRodney W. Grimes 	}
5409b50d902SRodney W. Grimes 	t = atoi(argv[1]);
5419b50d902SRodney W. Grimes 	if (t < 0)
5429b50d902SRodney W. Grimes 		printf("%s: bad value\n", argv[1]);
5439b50d902SRodney W. Grimes 	else
5449b50d902SRodney W. Grimes 		maxtimeout = t;
5459b50d902SRodney W. Grimes }
5469b50d902SRodney W. Grimes 
5479b50d902SRodney W. Grimes void
5481b0fa6faSXin LI status(int argc __unused, char *argv[] __unused)
5499b50d902SRodney W. Grimes {
5509b50d902SRodney W. Grimes 	if (connected)
5519b50d902SRodney W. Grimes 		printf("Connected to %s.\n", hostname);
5529b50d902SRodney W. Grimes 	else
5539b50d902SRodney W. Grimes 		printf("Not connected.\n");
5549b50d902SRodney W. Grimes 	printf("Mode: %s Verbose: %s Tracing: %s\n", mode,
5559b50d902SRodney W. Grimes 		verbose ? "on" : "off", trace ? "on" : "off");
5569b50d902SRodney W. Grimes 	printf("Rexmt-interval: %d seconds, Max-timeout: %d seconds\n",
5579b50d902SRodney W. Grimes 		rexmtval, maxtimeout);
5589b50d902SRodney W. Grimes }
5599b50d902SRodney W. Grimes 
5609b50d902SRodney W. Grimes void
5611b0fa6faSXin LI intr(int dummy __unused)
5629b50d902SRodney W. Grimes {
5639b50d902SRodney W. Grimes 
5649b50d902SRodney W. Grimes 	signal(SIGALRM, SIG_IGN);
5659b50d902SRodney W. Grimes 	alarm(0);
5669b50d902SRodney W. Grimes 	longjmp(toplevel, -1);
5679b50d902SRodney W. Grimes }
5689b50d902SRodney W. Grimes 
5699b50d902SRodney W. Grimes char *
5701b0fa6faSXin LI tail(char *filename)
5719b50d902SRodney W. Grimes {
5728049f797SMark Murray 	char *s;
5739b50d902SRodney W. Grimes 
5749b50d902SRodney W. Grimes 	while (*filename) {
5759b50d902SRodney W. Grimes 		s = rindex(filename, '/');
5769b50d902SRodney W. Grimes 		if (s == NULL)
5779b50d902SRodney W. Grimes 			break;
5789b50d902SRodney W. Grimes 		if (s[1])
5799b50d902SRodney W. Grimes 			return (s + 1);
5809b50d902SRodney W. Grimes 		*s = '\0';
5819b50d902SRodney W. Grimes 	}
5829b50d902SRodney W. Grimes 	return (filename);
5839b50d902SRodney W. Grimes }
5849b50d902SRodney W. Grimes 
585c33ed450SMatthew N. Dodd static const char *
5861b0fa6faSXin LI command_prompt(void)
5878979160aSBruce Evans {
5888979160aSBruce Evans 
589c33ed450SMatthew N. Dodd 	return ("tftp> ");
590c33ed450SMatthew N. Dodd }
591c33ed450SMatthew N. Dodd 
5929b50d902SRodney W. Grimes /*
5939b50d902SRodney W. Grimes  * Command parser.
5949b50d902SRodney W. Grimes  */
595eaa86f9dSBruce Evans static void
5961b0fa6faSXin LI command(void)
5979b50d902SRodney W. Grimes {
598c33ed450SMatthew N. Dodd 	HistEvent he;
5998049f797SMark Murray 	struct cmd *c;
6008979160aSBruce Evans 	static EditLine *el;
6018979160aSBruce Evans 	static History *hist;
602c33ed450SMatthew N. Dodd 	const char *bp;
6038979160aSBruce Evans 	char *cp;
6048049f797SMark Murray 	int len, num, vrbose;
605c33ed450SMatthew N. Dodd 
6068049f797SMark Murray 	vrbose = isatty(0);
6078049f797SMark Murray 	if (vrbose) {
608c33ed450SMatthew N. Dodd 		el = el_init("tftp", stdin, stdout, stderr);
609c33ed450SMatthew N. Dodd 		hist = history_init();
6102110d9c3SStefan Farfeleder 		history(hist, &he, H_SETSIZE, 100);
611c33ed450SMatthew N. Dodd 		el_set(el, EL_HIST, history, hist);
612c33ed450SMatthew N. Dodd 		el_set(el, EL_EDITOR, "emacs");
613c33ed450SMatthew N. Dodd 		el_set(el, EL_PROMPT, command_prompt);
614c33ed450SMatthew N. Dodd 		el_set(el, EL_SIGNAL, 1);
615c33ed450SMatthew N. Dodd 		el_source(el, NULL);
616c33ed450SMatthew N. Dodd 	}
6179b50d902SRodney W. Grimes 	for (;;) {
6188049f797SMark Murray 		if (vrbose) {
619c33ed450SMatthew N. Dodd                         if ((bp = el_gets(el, &num)) == NULL || num == 0)
620c33ed450SMatthew N. Dodd                                 exit(0);
621c33ed450SMatthew N. Dodd                         len = (num > MAXLINE) ? MAXLINE : num;
622c33ed450SMatthew N. Dodd                         memcpy(line, bp, len);
623c33ed450SMatthew N. Dodd                         line[len] = '\0';
624c33ed450SMatthew N. Dodd                         history(hist, &he, H_ENTER, bp);
625c33ed450SMatthew N. Dodd 		} else {
626ca22ff9eSJoerg Wunsch 			if (fgets(line, sizeof line , stdin) == 0) {
6279b50d902SRodney W. Grimes 				if (feof(stdin)) {
62873f899caSBrian S. Dean 					exit(txrx_error);
6299b50d902SRodney W. Grimes 				} else {
6309b50d902SRodney W. Grimes 					continue;
6319b50d902SRodney W. Grimes 				}
6329b50d902SRodney W. Grimes 			}
633c33ed450SMatthew N. Dodd 		}
634ca22ff9eSJoerg Wunsch 		if ((cp = strchr(line, '\n')))
635ca22ff9eSJoerg Wunsch 			*cp = '\0';
6369b50d902SRodney W. Grimes 		if (line[0] == 0)
6379b50d902SRodney W. Grimes 			continue;
6389b50d902SRodney W. Grimes 		makeargv();
6399b50d902SRodney W. Grimes 		if (margc == 0)
6409b50d902SRodney W. Grimes 			continue;
6419b50d902SRodney W. Grimes 		c = getcmd(margv[0]);
6429b50d902SRodney W. Grimes 		if (c == (struct cmd *)-1) {
6439b50d902SRodney W. Grimes 			printf("?Ambiguous command\n");
6449b50d902SRodney W. Grimes 			continue;
6459b50d902SRodney W. Grimes 		}
6469b50d902SRodney W. Grimes 		if (c == 0) {
6479b50d902SRodney W. Grimes 			printf("?Invalid command\n");
6489b50d902SRodney W. Grimes 			continue;
6499b50d902SRodney W. Grimes 		}
6509b50d902SRodney W. Grimes 		(*c->handler)(margc, margv);
6519b50d902SRodney W. Grimes 	}
6529b50d902SRodney W. Grimes }
6539b50d902SRodney W. Grimes 
6549b50d902SRodney W. Grimes struct cmd *
6551b0fa6faSXin LI getcmd(char *name)
6569b50d902SRodney W. Grimes {
6578049f797SMark Murray 	const char *p, *q;
6588049f797SMark Murray 	struct cmd *c, *found;
6598049f797SMark Murray 	int nmatches, longest;
6609b50d902SRodney W. Grimes 
6619b50d902SRodney W. Grimes 	longest = 0;
6629b50d902SRodney W. Grimes 	nmatches = 0;
6639b50d902SRodney W. Grimes 	found = 0;
6649b50d902SRodney W. Grimes 	for (c = cmdtab; (p = c->name) != NULL; c++) {
6659b50d902SRodney W. Grimes 		for (q = name; *q == *p++; q++)
6669b50d902SRodney W. Grimes 			if (*q == 0)		/* exact match? */
6679b50d902SRodney W. Grimes 				return (c);
6689b50d902SRodney W. Grimes 		if (!*q) {			/* the name was a prefix */
6699b50d902SRodney W. Grimes 			if (q - name > longest) {
6709b50d902SRodney W. Grimes 				longest = q - name;
6719b50d902SRodney W. Grimes 				nmatches = 1;
6729b50d902SRodney W. Grimes 				found = c;
6739b50d902SRodney W. Grimes 			} else if (q - name == longest)
6749b50d902SRodney W. Grimes 				nmatches++;
6759b50d902SRodney W. Grimes 		}
6769b50d902SRodney W. Grimes 	}
6779b50d902SRodney W. Grimes 	if (nmatches > 1)
6789b50d902SRodney W. Grimes 		return ((struct cmd *)-1);
6799b50d902SRodney W. Grimes 	return (found);
6809b50d902SRodney W. Grimes }
6819b50d902SRodney W. Grimes 
6829b50d902SRodney W. Grimes /*
6839b50d902SRodney W. Grimes  * Slice a string up into argc/argv.
6849b50d902SRodney W. Grimes  */
6859b50d902SRodney W. Grimes static void
6861b0fa6faSXin LI makeargv(void)
6879b50d902SRodney W. Grimes {
6888049f797SMark Murray 	char *cp;
6898049f797SMark Murray 	char **argp = margv;
6909b50d902SRodney W. Grimes 
6919b50d902SRodney W. Grimes 	margc = 0;
692ca22ff9eSJoerg Wunsch 	if ((cp = strchr(line, '\n')))
693ca22ff9eSJoerg Wunsch 		*cp = '\0';
6947f3a5689STim J. Robbins 	for (cp = line; margc < MAX_MARGV - 1 && *cp;) {
6959b50d902SRodney W. Grimes 		while (isspace(*cp))
6969b50d902SRodney W. Grimes 			cp++;
6979b50d902SRodney W. Grimes 		if (*cp == '\0')
6989b50d902SRodney W. Grimes 			break;
6999b50d902SRodney W. Grimes 		*argp++ = cp;
7009b50d902SRodney W. Grimes 		margc += 1;
7019b50d902SRodney W. Grimes 		while (*cp != '\0' && !isspace(*cp))
7029b50d902SRodney W. Grimes 			cp++;
7039b50d902SRodney W. Grimes 		if (*cp == '\0')
7049b50d902SRodney W. Grimes 			break;
7059b50d902SRodney W. Grimes 		*cp++ = '\0';
7069b50d902SRodney W. Grimes 	}
7079b50d902SRodney W. Grimes 	*argp++ = 0;
7089b50d902SRodney W. Grimes }
7099b50d902SRodney W. Grimes 
7109b50d902SRodney W. Grimes void
7111b0fa6faSXin LI quit(int argc __unused, char *argv[] __unused)
7129b50d902SRodney W. Grimes {
71373f899caSBrian S. Dean 	exit(txrx_error);
7149b50d902SRodney W. Grimes }
7159b50d902SRodney W. Grimes 
7169b50d902SRodney W. Grimes /*
7179b50d902SRodney W. Grimes  * Help command.
7189b50d902SRodney W. Grimes  */
7199b50d902SRodney W. Grimes void
7201b0fa6faSXin LI help(int argc, char *argv[])
7219b50d902SRodney W. Grimes {
7228049f797SMark Murray 	struct cmd *c;
7239b50d902SRodney W. Grimes 
7249b50d902SRodney W. Grimes 	if (argc == 1) {
7259b50d902SRodney W. Grimes 		printf("Commands may be abbreviated.  Commands are:\n\n");
7269b50d902SRodney W. Grimes 		for (c = cmdtab; c->name; c++)
7279b50d902SRodney W. Grimes 			printf("%-*s\t%s\n", (int)HELPINDENT, c->name, c->help);
7289b50d902SRodney W. Grimes 		return;
7299b50d902SRodney W. Grimes 	}
7309b50d902SRodney W. Grimes 	while (--argc > 0) {
7318049f797SMark Murray 		char *arg;
7329b50d902SRodney W. Grimes 		arg = *++argv;
7339b50d902SRodney W. Grimes 		c = getcmd(arg);
7349b50d902SRodney W. Grimes 		if (c == (struct cmd *)-1)
7359b50d902SRodney W. Grimes 			printf("?Ambiguous help command %s\n", arg);
7369b50d902SRodney W. Grimes 		else if (c == (struct cmd *)0)
7379b50d902SRodney W. Grimes 			printf("?Invalid help command %s\n", arg);
7389b50d902SRodney W. Grimes 		else
7399b50d902SRodney W. Grimes 			printf("%s\n", c->help);
7409b50d902SRodney W. Grimes 	}
7419b50d902SRodney W. Grimes }
7429b50d902SRodney W. Grimes 
7439b50d902SRodney W. Grimes void
7441b0fa6faSXin LI settrace(int argc __unused, char **argv __unused)
7459b50d902SRodney W. Grimes {
7469b50d902SRodney W. Grimes 	trace = !trace;
7479b50d902SRodney W. Grimes 	printf("Packet tracing %s.\n", trace ? "on" : "off");
7489b50d902SRodney W. Grimes }
7499b50d902SRodney W. Grimes 
7509b50d902SRodney W. Grimes void
7511b0fa6faSXin LI setverbose(int argc __unused, char **argv __unused)
7529b50d902SRodney W. Grimes {
7539b50d902SRodney W. Grimes 	verbose = !verbose;
7549b50d902SRodney W. Grimes 	printf("Verbose mode %s.\n", verbose ? "on" : "off");
7559b50d902SRodney W. Grimes }
756