xref: /csrg-svn/usr.bin/tftp/main.c (revision 16382)
114553Ssam #ifndef lint
2*16382Ssam static char sccsid[] = "@(#)main.c	4.8 (Berkeley) 04/12/84";
314553Ssam #endif
47769Ssam 
57769Ssam /*
67769Ssam  * TFTP User Program -- Command Interface.
77769Ssam  */
87769Ssam #include <sys/types.h>
97769Ssam #include <sys/socket.h>
1013017Ssam #include <sys/file.h>
119219Ssam 
129219Ssam #include <netinet/in.h>
139219Ssam 
147769Ssam #include <signal.h>
157769Ssam #include <stdio.h>
167769Ssam #include <errno.h>
177769Ssam #include <setjmp.h>
187769Ssam #include <ctype.h>
198384Ssam #include <netdb.h>
207769Ssam 
2113017Ssam #define	TIMEOUT		5		/* secs between rexmt's */
2213017Ssam 
239219Ssam struct	sockaddr_in sin;
247769Ssam int	f;
257769Ssam int	trace;
267769Ssam int	verbose;
277769Ssam int	connected;
287769Ssam char	mode[32];
297769Ssam char	line[200];
307769Ssam int	margc;
317769Ssam char	*margv[20];
327769Ssam char	*prompt = "tftp";
337769Ssam jmp_buf	toplevel;
347769Ssam int	intr();
358384Ssam struct	servent *sp;
367769Ssam 
377769Ssam int	quit(), help(), setverbose(), settrace(), status();
3813017Ssam int	get(), put(), setpeer(), setmode(), setrexmt(), settimeout();
397769Ssam 
407769Ssam #define HELPINDENT (sizeof("connect"))
417769Ssam 
427769Ssam struct cmd {
437769Ssam 	char	*name;
447769Ssam 	char	*help;
457769Ssam 	int	(*handler)();
467769Ssam };
477769Ssam 
487769Ssam char	vhelp[] = "toggle verbose mode";
497769Ssam char	thelp[] = "toggle packet tracing";
507769Ssam char	chelp[] = "connect to remote tftp";
517769Ssam char	qhelp[] = "exit tftp";
527769Ssam char	hhelp[] = "print help information";
537769Ssam char	shelp[] = "send file";
547769Ssam char	rhelp[] = "receive file";
557769Ssam char	mhelp[] = "set file transfer mode";
567769Ssam char	sthelp[] = "show current status";
5713017Ssam char	xhelp[] = "set per-packet retransmission timeout";
5813017Ssam char	ihelp[] = "set total retransmission timeout";
597769Ssam 
607769Ssam struct cmd cmdtab[] = {
617769Ssam 	{ "connect",	chelp,		setpeer },
627769Ssam 	{ "mode",	mhelp,		setmode },
637769Ssam 	{ "put",	shelp,		put },
647769Ssam 	{ "get",	rhelp,		get },
657769Ssam 	{ "quit",	qhelp,		quit },
667769Ssam 	{ "verbose",	vhelp,		setverbose },
677769Ssam 	{ "trace",	thelp,		settrace },
687769Ssam 	{ "status",	sthelp,		status },
6913017Ssam 	{ "rexmt",	xhelp,		setrexmt },
7013017Ssam 	{ "timeout",	ihelp,		settimeout },
717769Ssam 	{ "?",		hhelp,		help },
727769Ssam 	0
737769Ssam };
747769Ssam 
757769Ssam struct	cmd *getcmd();
767769Ssam char	*tail();
777769Ssam char	*index();
787769Ssam char	*rindex();
797769Ssam 
807769Ssam main(argc, argv)
817769Ssam 	char *argv[];
827769Ssam {
8313017Ssam 	struct sockaddr_in sin;
8413017Ssam 	int top;
8513017Ssam 
868384Ssam 	sp = getservbyname("tftp", "udp");
878384Ssam 	if (sp == 0) {
888384Ssam 		fprintf(stderr, "tftp: udp/tftp: unknown service\n");
898384Ssam 		exit(1);
908384Ssam 	}
919262Ssam 	f = socket(AF_INET, SOCK_DGRAM, 0, 0);
927769Ssam 	if (f < 0) {
9313017Ssam 		perror("tftp: socket");
947769Ssam 		exit(3);
957769Ssam 	}
9613017Ssam 	bzero((char *)&sin, sizeof (sin));
9713017Ssam 	sin.sin_family = AF_INET;
9813017Ssam 	if (bind(f, &sin, sizeof (sin)) < 0) {
9913017Ssam 		perror("tftp: bind");
10013017Ssam 		exit(1);
10113017Ssam 	}
1027769Ssam 	strcpy(mode, "netascii");
10313017Ssam 	signal(SIGINT, intr);
1047769Ssam 	if (argc > 1) {
1057769Ssam 		if (setjmp(toplevel) != 0)
1067769Ssam 			exit(0);
1077769Ssam 		setpeer(argc, argv);
1087769Ssam 	}
10913017Ssam 	top = setjmp(toplevel) == 0;
1107769Ssam 	for (;;)
11113017Ssam 		command(top);
1127769Ssam }
1137769Ssam 
1148384Ssam char	*hostname;
1158384Ssam char	hnamebuf[32];
1167769Ssam 
1177769Ssam setpeer(argc, argv)
1187769Ssam 	int argc;
1197769Ssam 	char *argv[];
1207769Ssam {
1217769Ssam 	register int c;
1228384Ssam 	struct hostent *host;
1237769Ssam 
1247769Ssam 	if (argc < 2) {
1257769Ssam 		strcpy(line, "Connect ");
1267769Ssam 		printf("(to) ");
1277769Ssam 		gets(&line[strlen(line)]);
1287769Ssam 		makeargv();
1297769Ssam 		argc = margc;
1307769Ssam 		argv = margv;
1317769Ssam 	}
1327769Ssam 	if (argc > 3) {
1337769Ssam 		printf("usage: %s host-name [port]\n", argv[0]);
1347769Ssam 		return;
1357769Ssam 	}
1368384Ssam 	host = gethostbyname(argv[1]);
1378384Ssam 	if (host) {
1389219Ssam 		sin.sin_family = host->h_addrtype;
1398384Ssam 		bcopy(host->h_addr, &sin.sin_addr, host->h_length);
1408384Ssam 		hostname = host->h_name;
1418384Ssam 	} else {
1429219Ssam 		sin.sin_family = AF_INET;
1438384Ssam 		sin.sin_addr.s_addr = inet_addr(argv[1]);
1448384Ssam 		if (sin.sin_addr.s_addr == -1) {
1458384Ssam 			connected = 0;
1468384Ssam 			printf("%s: unknown host\n", argv[1]);
1478384Ssam 			return;
1488384Ssam 		}
1498384Ssam 		strcpy(hnamebuf, argv[1]);
1508384Ssam 		hostname = hnamebuf;
1517769Ssam 	}
1528384Ssam 	sin.sin_port = sp->s_port;
1537769Ssam 	if (argc == 3) {
1547769Ssam 		sin.sin_port = atoi(argv[2]);
1557769Ssam 		if (sin.sin_port < 0) {
1567769Ssam 			printf("%s: bad port number\n", argv[2]);
1577769Ssam 			connected = 0;
1587769Ssam 			return;
1597769Ssam 		}
1609971Ssam 		sin.sin_port = htons((u_short)sin.sin_port);
1618384Ssam 	}
1627769Ssam 	connected = 1;
1637769Ssam }
1647769Ssam 
1657769Ssam struct	modes {
1667769Ssam 	char *m_name;
1677769Ssam 	char *m_mode;
1687769Ssam } modes[] = {
1697769Ssam 	{ "ascii",	"netascii" },
1707769Ssam 	{ "binary",	"octect" },
1717769Ssam 	{ "mail",	"mail" },
1727769Ssam 	{ 0,		0 }
1737769Ssam };
1747769Ssam 
1757769Ssam setmode(argc, argv)
1767769Ssam 	char *argv[];
1777769Ssam {
1787769Ssam 	register struct modes *p;
1797769Ssam 
1807769Ssam 	if (argc > 2) {
1817769Ssam 		char *sep;
1827769Ssam 
1837769Ssam 		printf("usage: %s [", argv[0]);
1847769Ssam 		sep = " ";
1857769Ssam 		for (p = modes; p->m_name; p++) {
1867769Ssam 			printf("%s%s", sep, p->m_name);
1877769Ssam 			if (*sep == ' ')
1887769Ssam 				sep = " | ";
1897769Ssam 		}
1907769Ssam 		printf(" ]\n");
1917769Ssam 		return;
1927769Ssam 	}
1937769Ssam 	if (argc < 2) {
1947769Ssam 		printf("Using %s mode to transfer files.\n", mode);
1957769Ssam 		return;
1967769Ssam 	}
1977769Ssam 	for (p = modes; p->m_name; p++)
1987769Ssam 		if (strcmp(argv[1], p->m_name) == 0)
1997769Ssam 			break;
2007769Ssam 	if (p->m_name)
2017769Ssam 		strcpy(mode, p->m_mode);
2027769Ssam 	else
2037769Ssam 		printf("%s: unknown mode\n", argv[1]);
2047769Ssam }
2057769Ssam 
2067769Ssam /*
2077769Ssam  * Send file(s).
2087769Ssam  */
2097769Ssam put(argc, argv)
2107769Ssam 	char *argv[];
2117769Ssam {
2127769Ssam 	int fd;
2137769Ssam 	register int n, addr;
2147769Ssam 	register char *cp, *targ;
2157769Ssam 
2167769Ssam 	if (argc < 2) {
2177769Ssam 		strcpy(line, "send ");
2187769Ssam 		printf("(file) ");
2197769Ssam 		gets(&line[strlen(line)]);
2207769Ssam 		makeargv();
2217769Ssam 		argc = margc;
2227769Ssam 		argv = margv;
2237769Ssam 	}
2247769Ssam 	if (argc < 2) {
2257769Ssam 		putusage(argv[0]);
2267769Ssam 		return;
2277769Ssam 	}
2287769Ssam 	targ = argv[argc - 1];
2297769Ssam 	if (index(argv[argc - 1], ':')) {
2308384Ssam 		char *cp;
2318384Ssam 		struct hostent *hp;
2327769Ssam 
2337769Ssam 		for (n = 1; n < argc - 1; n++)
2347769Ssam 			if (index(argv[n], ':')) {
2357769Ssam 				putusage(argv[0]);
2367769Ssam 				return;
2377769Ssam 			}
2388384Ssam 		cp = argv[argc - 1];
2398384Ssam 		targ = index(cp, ':');
2407769Ssam 		*targ++ = 0;
2418384Ssam 		hp = gethostbyname(cp);
2428384Ssam 		if (hp == 0) {
2438384Ssam 			printf("%s: Unknown host.\n", cp);
2447769Ssam 			return;
2457769Ssam 		}
2469219Ssam 		bcopy(hp->h_addr, (caddr_t)&sin.sin_addr, hp->h_length);
2478384Ssam 		sin.sin_family = hp->h_addrtype;
2487769Ssam 		connected = 1;
2498384Ssam 		hostname = hp->h_name;
2507769Ssam 	}
2517769Ssam 	if (!connected) {
2527769Ssam 		printf("No target machine specified.\n");
2537769Ssam 		return;
2547769Ssam 	}
2557769Ssam 	if (argc < 4) {
2567769Ssam 		cp = argc == 2 ? tail(targ) : argv[1];
25713017Ssam 		fd = open(cp, O_RDONLY);
2587769Ssam 		if (fd < 0) {
25913017Ssam 			fprintf(stderr, "tftp: "); perror(cp);
2607769Ssam 			return;
2617769Ssam 		}
2627769Ssam 		sendfile(fd, targ);
2637769Ssam 		return;
2647769Ssam 	}
2657769Ssam 	cp = index(targ, '\0');
2667769Ssam 	*cp++ = '/';
2677769Ssam 	for (n = 1; n < argc - 1; n++) {
2687769Ssam 		strcpy(cp, tail(argv[n]));
26913017Ssam 		fd = open(argv[n], O_RDONLY);
2707769Ssam 		if (fd < 0) {
27113017Ssam 			fprintf(stderr, "tftp: "); perror(argv[n]);
2727769Ssam 			continue;
2737769Ssam 		}
2747769Ssam 		sendfile(fd, targ);
2757769Ssam 	}
2767769Ssam }
2777769Ssam 
2787769Ssam putusage(s)
2797769Ssam 	char *s;
2807769Ssam {
2817769Ssam 	printf("usage: %s file ... host:target, or\n", s);
2827769Ssam 	printf("       %s file ... target (when already connected)\n", s);
2837769Ssam }
2847769Ssam 
2857769Ssam /*
2867769Ssam  * Receive file(s).
2877769Ssam  */
2887769Ssam get(argc, argv)
2897769Ssam 	char *argv[];
2907769Ssam {
2917769Ssam 	int fd;
2927769Ssam 	register int n, addr;
2937769Ssam 	register char *cp;
2947769Ssam 	char *src;
2957769Ssam 
2967769Ssam 	if (argc < 2) {
2977769Ssam 		strcpy(line, "get ");
2987769Ssam 		printf("(files) ");
2997769Ssam 		gets(&line[strlen(line)]);
3007769Ssam 		makeargv();
3017769Ssam 		argc = margc;
3027769Ssam 		argv = margv;
3037769Ssam 	}
3047769Ssam 	if (argc < 2) {
3057769Ssam 		getusage(argv[0]);
3067769Ssam 		return;
3077769Ssam 	}
3087769Ssam 	if (!connected)
3097769Ssam 		for (n = 1; n < argc - 1; n++)
3107769Ssam 			if (index(argv[n], ':') == 0) {
3117769Ssam 				getusage(argv[0]);
3127769Ssam 				return;
3137769Ssam 			}
3147769Ssam 	for (n = 1; argc == 2 || n < argc - 1; n++) {
3157769Ssam 		src = index(argv[n], ':');
3167769Ssam 		if (src == NULL)
3177769Ssam 			src = argv[n];
3187769Ssam 		else {
3198384Ssam 			struct hostent *hp;
3208384Ssam 
3217769Ssam 			*src++ = 0;
3228384Ssam 			hp = gethostbyname(argv[n]);
3238384Ssam 			if (hp == 0) {
3247769Ssam 				printf("%s: Unknown host.\n", argv[n]);
3257769Ssam 				continue;
3267769Ssam 			}
3279219Ssam 			bcopy(hp->h_addr, (caddr_t)&sin.sin_addr, hp->h_length);
3288384Ssam 			sin.sin_family = hp->h_addrtype;
3297769Ssam 			connected = 1;
3308384Ssam 			hostname = hp->h_name;
3317769Ssam 		}
3327769Ssam 		if (argc < 4) {
3337769Ssam 			cp = argc == 3 ? argv[2] : tail(src);
3347769Ssam 			fd = creat(cp, 0644);
3357769Ssam 			if (fd < 0) {
33613017Ssam 				fprintf(stderr, "tftp: "); perror(cp);
3377769Ssam 				return;
3387769Ssam 			}
3397769Ssam 			recvfile(fd, src);
3407769Ssam 			break;
3417769Ssam 		}
3427769Ssam 		cp = index(argv[argc - 1], '\0');
3437769Ssam 		*cp++ = '/';
3447769Ssam 		strcpy(cp, tail(src));
3457769Ssam 		fd = creat(src, 0644);
3467769Ssam 		if (fd < 0) {
34713017Ssam 			fprintf(stderr, "tftp: "); perror(src);
3487769Ssam 			continue;
3497769Ssam 		}
3507769Ssam 		recvfile(fd, src);
3517769Ssam 	}
3527769Ssam }
3537769Ssam 
3547769Ssam getusage(s)
3557769Ssam {
3567769Ssam 	printf("usage: %s host:file host:file ... file, or\n", s);
3577769Ssam 	printf("       %s file file ... file if connected\n", s);
3587769Ssam }
3597769Ssam 
36013017Ssam int	rexmtval = TIMEOUT;
36113017Ssam 
36213017Ssam setrexmt(argc, argv)
36313017Ssam 	char *argv[];
36413017Ssam {
36513017Ssam 	int t;
36613017Ssam 
36713017Ssam 	if (argc < 2) {
36813017Ssam 		strcpy(line, "Rexmt-timeout ");
36913017Ssam 		printf("(value) ");
37013017Ssam 		gets(&line[strlen(line)]);
37113017Ssam 		makeargv();
37213017Ssam 		argc = margc;
37313017Ssam 		argv = margv;
37413017Ssam 	}
37513017Ssam 	if (argc != 2) {
37613017Ssam 		printf("usage: %s value\n", argv[0]);
37713017Ssam 		return;
37813017Ssam 	}
37913017Ssam 	t = atoi(argv[1]);
38013017Ssam 	if (t < 0)
38113017Ssam 		printf("%s: bad value\n", t);
38213017Ssam 	else
38313017Ssam 		rexmtval = t;
38413017Ssam }
38513017Ssam 
38613017Ssam int	maxtimeout = 5 * TIMEOUT;
38713017Ssam 
38813017Ssam settimeout(argc, argv)
38913017Ssam 	char *argv[];
39013017Ssam {
39113017Ssam 	int t;
39213017Ssam 
39313017Ssam 	if (argc < 2) {
39413017Ssam 		strcpy(line, "Maximum-timeout ");
39513017Ssam 		printf("(value) ");
39613017Ssam 		gets(&line[strlen(line)]);
39713017Ssam 		makeargv();
39813017Ssam 		argc = margc;
39913017Ssam 		argv = margv;
40013017Ssam 	}
40113017Ssam 	if (argc != 2) {
40213017Ssam 		printf("usage: %s value\n", argv[0]);
40313017Ssam 		return;
40413017Ssam 	}
40513017Ssam 	t = atoi(argv[1]);
40613017Ssam 	if (t < 0)
40713017Ssam 		printf("%s: bad value\n", t);
40813017Ssam 	else
40913017Ssam 		maxtimeout = t;
41013017Ssam }
41113017Ssam 
4127769Ssam status(argc, argv)
4137769Ssam 	char *argv[];
4147769Ssam {
4157769Ssam 	if (connected)
4168384Ssam 		printf("Connected to %s.\n", hostname);
4177769Ssam 	else
4187769Ssam 		printf("Not connected.\n");
4197769Ssam 	printf("Mode: %s Verbose: %s Tracing: %s\n", mode,
4207769Ssam 		verbose ? "on" : "off", trace ? "on" : "off");
42113017Ssam 	printf("Rexmt-interval: %d seconds, Max-timeout: %d seconds\n",
42213017Ssam 		rexmtval, maxtimeout);
4237769Ssam }
4247769Ssam 
4257769Ssam intr()
4267769Ssam {
42713017Ssam 
428*16382Ssam 	alarm(0);
4297769Ssam 	longjmp(toplevel, -1);
4307769Ssam }
4317769Ssam 
4327769Ssam char *
4337769Ssam tail(filename)
4347769Ssam 	char *filename;
4357769Ssam {
4367769Ssam 	register char *s;
4377769Ssam 
4387769Ssam 	while (*filename) {
4397769Ssam 		s = rindex(filename, '/');
4407769Ssam 		if (s == NULL)
4417769Ssam 			break;
4427769Ssam 		if (s[1])
4437769Ssam 			return (s + 1);
4447769Ssam 		*s = '\0';
4457769Ssam 	}
4467769Ssam 	return (filename);
4477769Ssam }
4487769Ssam 
4497769Ssam /*
4507769Ssam  * Command parser.
4517769Ssam  */
4527769Ssam command(top)
4537769Ssam 	int top;
4547769Ssam {
4557769Ssam 	register struct cmd *c;
4567769Ssam 
4577769Ssam 	if (!top)
4587769Ssam 		putchar('\n');
4597769Ssam 	for (;;) {
4607769Ssam 		printf("%s> ", prompt);
4617769Ssam 		if (gets(line) == 0)
46213017Ssam 			continue;
4637769Ssam 		if (line[0] == 0)
46413017Ssam 			continue;
4657769Ssam 		makeargv();
4667769Ssam 		c = getcmd(margv[0]);
4677769Ssam 		if (c == (struct cmd *)-1) {
4687769Ssam 			printf("?Ambiguous command\n");
4697769Ssam 			continue;
4707769Ssam 		}
4717769Ssam 		if (c == 0) {
4727769Ssam 			printf("?Invalid command\n");
4737769Ssam 			continue;
4747769Ssam 		}
4757769Ssam 		(*c->handler)(margc, margv);
4767769Ssam 	}
4777769Ssam }
4787769Ssam 
4797769Ssam struct cmd *
4807769Ssam getcmd(name)
4817769Ssam 	register char *name;
4827769Ssam {
4837769Ssam 	register char *p, *q;
4847769Ssam 	register struct cmd *c, *found;
4857769Ssam 	register int nmatches, longest;
4867769Ssam 
4877769Ssam 	longest = 0;
4887769Ssam 	nmatches = 0;
4897769Ssam 	found = 0;
4907769Ssam 	for (c = cmdtab; p = c->name; c++) {
4917769Ssam 		for (q = name; *q == *p++; q++)
4927769Ssam 			if (*q == 0)		/* exact match? */
4937769Ssam 				return (c);
4947769Ssam 		if (!*q) {			/* the name was a prefix */
4957769Ssam 			if (q - name > longest) {
4967769Ssam 				longest = q - name;
4977769Ssam 				nmatches = 1;
4987769Ssam 				found = c;
4997769Ssam 			} else if (q - name == longest)
5007769Ssam 				nmatches++;
5017769Ssam 		}
5027769Ssam 	}
5037769Ssam 	if (nmatches > 1)
5047769Ssam 		return ((struct cmd *)-1);
5057769Ssam 	return (found);
5067769Ssam }
5077769Ssam 
5087769Ssam /*
5097769Ssam  * Slice a string up into argc/argv.
5107769Ssam  */
5117769Ssam makeargv()
5127769Ssam {
5137769Ssam 	register char *cp;
5147769Ssam 	register char **argp = margv;
5157769Ssam 
5167769Ssam 	margc = 0;
5177769Ssam 	for (cp = line; *cp;) {
5187769Ssam 		while (isspace(*cp))
5197769Ssam 			cp++;
5207769Ssam 		if (*cp == '\0')
5217769Ssam 			break;
5227769Ssam 		*argp++ = cp;
5237769Ssam 		margc += 1;
5247769Ssam 		while (*cp != '\0' && !isspace(*cp))
5257769Ssam 			cp++;
5267769Ssam 		if (*cp == '\0')
5277769Ssam 			break;
5287769Ssam 		*cp++ = '\0';
5297769Ssam 	}
5307769Ssam 	*argp++ = 0;
5317769Ssam }
5327769Ssam 
5337769Ssam /*VARARGS*/
5347769Ssam quit()
5357769Ssam {
5367769Ssam 	exit(0);
5377769Ssam }
5387769Ssam 
5397769Ssam /*
5407769Ssam  * Help command.
5417769Ssam  */
5427769Ssam help(argc, argv)
5437769Ssam 	int argc;
5447769Ssam 	char *argv[];
5457769Ssam {
5467769Ssam 	register struct cmd *c;
5477769Ssam 
5487769Ssam 	if (argc == 1) {
5497769Ssam 		printf("Commands may be abbreviated.  Commands are:\n\n");
5507769Ssam 		for (c = cmdtab; c->name; c++)
5517769Ssam 			printf("%-*s\t%s\n", HELPINDENT, c->name, c->help);
5527769Ssam 		return;
5537769Ssam 	}
5547769Ssam 	while (--argc > 0) {
5557769Ssam 		register char *arg;
5567769Ssam 		arg = *++argv;
5577769Ssam 		c = getcmd(arg);
5587769Ssam 		if (c == (struct cmd *)-1)
5597769Ssam 			printf("?Ambiguous help command %s\n", arg);
5607769Ssam 		else if (c == (struct cmd *)0)
5617769Ssam 			printf("?Invalid help command %s\n", arg);
5627769Ssam 		else
5637769Ssam 			printf("%s\n", c->help);
5647769Ssam 	}
5657769Ssam }
5667769Ssam 
5677769Ssam /*
5687769Ssam  * Call routine with argc, argv set from args (terminated by 0).
5697769Ssam  */
5707769Ssam /* VARARGS2 */
5717769Ssam call(routine, args)
5727769Ssam 	int (*routine)();
5737769Ssam 	int args;
5747769Ssam {
5757769Ssam 	register int *argp;
5767769Ssam 	register int argc;
5777769Ssam 
5787769Ssam 	for (argc = 0, argp = &args; *argp++ != 0; argc++)
5797769Ssam 		;
5807769Ssam 	(*routine)(argc, &args);
5817769Ssam }
5827769Ssam 
5837769Ssam /*VARARGS*/
5847769Ssam settrace()
5857769Ssam {
5867769Ssam 	trace = !trace;
5877769Ssam 	printf("Packet tracing %s.\n", trace ? "on" : "off");
5887769Ssam }
5897769Ssam 
5907769Ssam /*VARARGS*/
5917769Ssam setverbose()
5927769Ssam {
5937769Ssam 	verbose = !verbose;
5947769Ssam 	printf("Verbose mode %s.\n", verbose ? "on" : "off");
5957769Ssam }
596