xref: /csrg-svn/usr.bin/tftp/main.c (revision 46861)
122403Sdist /*
233821Sbostic  * Copyright (c) 1983 Regents of the University of California.
333821Sbostic  * All rights reserved.
433821Sbostic  *
542770Sbostic  * %sccs.include.redist.c%
622403Sdist  */
722403Sdist 
814553Ssam #ifndef lint
922403Sdist char copyright[] =
1022403Sdist "@(#) Copyright (c) 1983 Regents of the University of California.\n\
1122403Sdist  All rights reserved.\n";
1233821Sbostic #endif /* not lint */
137769Ssam 
1422403Sdist #ifndef lint
15*46861Sbostic static char sccsid[] = "@(#)main.c	5.10 (Berkeley) 03/01/91";
1633821Sbostic #endif /* not lint */
1722403Sdist 
1826095Sminshall /* Many bug fixes are from Jim Guyton <guyton@rand-unix> */
1926095Sminshall 
207769Ssam /*
217769Ssam  * TFTP User Program -- Command Interface.
227769Ssam  */
237769Ssam #include <sys/types.h>
247769Ssam #include <sys/socket.h>
2513017Ssam #include <sys/file.h>
269219Ssam 
279219Ssam #include <netinet/in.h>
289219Ssam 
297769Ssam #include <signal.h>
307769Ssam #include <stdio.h>
317769Ssam #include <errno.h>
327769Ssam #include <setjmp.h>
337769Ssam #include <ctype.h>
348384Ssam #include <netdb.h>
357769Ssam 
3613017Ssam #define	TIMEOUT		5		/* secs between rexmt's */
3713017Ssam 
3826095Sminshall struct	sockaddr_in sin;
397769Ssam int	f;
4026095Sminshall short   port;
417769Ssam int	trace;
4226095Sminshall int	verbose;
437769Ssam int	connected;
447769Ssam char	mode[32];
457769Ssam char	line[200];
467769Ssam int	margc;
477769Ssam char	*margv[20];
487769Ssam char	*prompt = "tftp";
497769Ssam jmp_buf	toplevel;
50*46861Sbostic void	intr();
518384Ssam struct	servent *sp;
527769Ssam 
5326095Sminshall int	quit(), help(), setverbose(), settrace(), status();
5426095Sminshall int     get(), put(), setpeer(), modecmd(), setrexmt(), settimeout();
5526095Sminshall int     setbinary(), setascii();
567769Ssam 
577769Ssam #define HELPINDENT (sizeof("connect"))
587769Ssam 
597769Ssam struct cmd {
607769Ssam 	char	*name;
617769Ssam 	char	*help;
627769Ssam 	int	(*handler)();
637769Ssam };
647769Ssam 
6526095Sminshall char	vhelp[] = "toggle verbose mode";
667769Ssam char	thelp[] = "toggle packet tracing";
677769Ssam char	chelp[] = "connect to remote tftp";
687769Ssam char	qhelp[] = "exit tftp";
697769Ssam char	hhelp[] = "print help information";
707769Ssam char	shelp[] = "send file";
717769Ssam char	rhelp[] = "receive file";
727769Ssam char	mhelp[] = "set file transfer mode";
737769Ssam char	sthelp[] = "show current status";
7413017Ssam char	xhelp[] = "set per-packet retransmission timeout";
7513017Ssam char	ihelp[] = "set total retransmission timeout";
7626095Sminshall char    ashelp[] = "set mode to netascii";
7726095Sminshall char    bnhelp[] = "set mode to octet";
787769Ssam 
797769Ssam struct cmd cmdtab[] = {
807769Ssam 	{ "connect",	chelp,		setpeer },
8126095Sminshall 	{ "mode",       mhelp,          modecmd },
827769Ssam 	{ "put",	shelp,		put },
837769Ssam 	{ "get",	rhelp,		get },
847769Ssam 	{ "quit",	qhelp,		quit },
8526095Sminshall 	{ "verbose",	vhelp,		setverbose },
867769Ssam 	{ "trace",	thelp,		settrace },
877769Ssam 	{ "status",	sthelp,		status },
8826095Sminshall 	{ "binary",     bnhelp,         setbinary },
8926095Sminshall 	{ "ascii",      ashelp,         setascii },
9013017Ssam 	{ "rexmt",	xhelp,		setrexmt },
9113017Ssam 	{ "timeout",	ihelp,		settimeout },
927769Ssam 	{ "?",		hhelp,		help },
937769Ssam 	0
947769Ssam };
957769Ssam 
967769Ssam struct	cmd *getcmd();
977769Ssam char	*tail();
987769Ssam char	*index();
997769Ssam char	*rindex();
1007769Ssam 
1017769Ssam main(argc, argv)
1027769Ssam 	char *argv[];
1037769Ssam {
10426095Sminshall 	struct sockaddr_in sin;
10513017Ssam 	int top;
10613017Ssam 
1078384Ssam 	sp = getservbyname("tftp", "udp");
1088384Ssam 	if (sp == 0) {
1098384Ssam 		fprintf(stderr, "tftp: udp/tftp: unknown service\n");
1108384Ssam 		exit(1);
1118384Ssam 	}
11226110Sminshall 	f = socket(AF_INET, SOCK_DGRAM, 0);
1137769Ssam 	if (f < 0) {
11413017Ssam 		perror("tftp: socket");
1157769Ssam 		exit(3);
1167769Ssam 	}
11726095Sminshall 	bzero((char *)&sin, sizeof (sin));
11826095Sminshall 	sin.sin_family = AF_INET;
119*46861Sbostic 	if (bind(f, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
12013017Ssam 		perror("tftp: bind");
12113017Ssam 		exit(1);
12213017Ssam 	}
12326095Sminshall 	strcpy(mode, "netascii");
12413017Ssam 	signal(SIGINT, intr);
1257769Ssam 	if (argc > 1) {
1267769Ssam 		if (setjmp(toplevel) != 0)
1277769Ssam 			exit(0);
1287769Ssam 		setpeer(argc, argv);
1297769Ssam 	}
13013017Ssam 	top = setjmp(toplevel) == 0;
1317769Ssam 	for (;;)
13213017Ssam 		command(top);
1337769Ssam }
1347769Ssam 
13526095Sminshall char    hostname[100];
1367769Ssam 
1377769Ssam setpeer(argc, argv)
1387769Ssam 	int argc;
1397769Ssam 	char *argv[];
1407769Ssam {
1418384Ssam 	struct hostent *host;
1427769Ssam 
1437769Ssam 	if (argc < 2) {
1447769Ssam 		strcpy(line, "Connect ");
1457769Ssam 		printf("(to) ");
1467769Ssam 		gets(&line[strlen(line)]);
1477769Ssam 		makeargv();
1487769Ssam 		argc = margc;
1497769Ssam 		argv = margv;
1507769Ssam 	}
1517769Ssam 	if (argc > 3) {
1527769Ssam 		printf("usage: %s host-name [port]\n", argv[0]);
1537769Ssam 		return;
1547769Ssam 	}
1558384Ssam 	host = gethostbyname(argv[1]);
1568384Ssam 	if (host) {
1579219Ssam 		sin.sin_family = host->h_addrtype;
1588384Ssam 		bcopy(host->h_addr, &sin.sin_addr, host->h_length);
15926095Sminshall 		strcpy(hostname, host->h_name);
1608384Ssam 	} else {
1619219Ssam 		sin.sin_family = AF_INET;
1628384Ssam 		sin.sin_addr.s_addr = inet_addr(argv[1]);
1638384Ssam 		if (sin.sin_addr.s_addr == -1) {
1648384Ssam 			connected = 0;
1658384Ssam 			printf("%s: unknown host\n", argv[1]);
1668384Ssam 			return;
1678384Ssam 		}
16826095Sminshall 		strcpy(hostname, argv[1]);
1697769Ssam 	}
17026095Sminshall 	port = sp->s_port;
1717769Ssam 	if (argc == 3) {
17226095Sminshall 		port = atoi(argv[2]);
17326095Sminshall 		if (port < 0) {
1747769Ssam 			printf("%s: bad port number\n", argv[2]);
1757769Ssam 			connected = 0;
1767769Ssam 			return;
1777769Ssam 		}
17826095Sminshall 		port = htons(port);
1798384Ssam 	}
1807769Ssam 	connected = 1;
1817769Ssam }
1827769Ssam 
1837769Ssam struct	modes {
1847769Ssam 	char *m_name;
1857769Ssam 	char *m_mode;
1867769Ssam } modes[] = {
18726095Sminshall 	{ "ascii",	"netascii" },
18826095Sminshall 	{ "netascii",   "netascii" },
18926095Sminshall 	{ "binary",     "octet" },
19026095Sminshall 	{ "image",      "octet" },
19126103Sminshall 	{ "octet",     "octet" },
19226095Sminshall /*      { "mail",       "mail" },       */
1937769Ssam 	{ 0,		0 }
1947769Ssam };
1957769Ssam 
19626095Sminshall modecmd(argc, argv)
1977769Ssam 	char *argv[];
1987769Ssam {
1997769Ssam 	register struct modes *p;
20026095Sminshall 	char *sep;
2017769Ssam 
2027769Ssam 	if (argc < 2) {
2037769Ssam 		printf("Using %s mode to transfer files.\n", mode);
2047769Ssam 		return;
2057769Ssam 	}
20626095Sminshall 	if (argc == 2) {
20726095Sminshall 		for (p = modes; p->m_name; p++)
20826095Sminshall 			if (strcmp(argv[1], p->m_name) == 0)
20926095Sminshall 				break;
21026095Sminshall 		if (p->m_name) {
21126095Sminshall 			setmode(p->m_mode);
21226095Sminshall 			return;
21326095Sminshall 		}
2147769Ssam 		printf("%s: unknown mode\n", argv[1]);
21526095Sminshall 		/* drop through and print usage message */
21626095Sminshall 	}
21726095Sminshall 
21826095Sminshall 	printf("usage: %s [", argv[0]);
21926095Sminshall 	sep = " ";
22026095Sminshall 	for (p = modes; p->m_name; p++) {
22126095Sminshall 		printf("%s%s", sep, p->m_name);
22226095Sminshall 		if (*sep == ' ')
22326095Sminshall 			sep = " | ";
22426095Sminshall 	}
22526095Sminshall 	printf(" ]\n");
22626095Sminshall 	return;
2277769Ssam }
2287769Ssam 
22926095Sminshall setbinary(argc, argv)
23026095Sminshall char *argv[];
23126095Sminshall {       setmode("octet");
23226095Sminshall }
23326095Sminshall 
23426095Sminshall setascii(argc, argv)
23526095Sminshall char *argv[];
23626095Sminshall {       setmode("netascii");
23726095Sminshall }
23826095Sminshall 
23926095Sminshall setmode(newmode)
24026095Sminshall char *newmode;
24126095Sminshall {
24226095Sminshall 	strcpy(mode, newmode);
24326095Sminshall 	if (verbose)
24426095Sminshall 		printf("mode set to %s\n", mode);
24526095Sminshall }
24626095Sminshall 
24726095Sminshall 
2487769Ssam /*
2497769Ssam  * Send file(s).
2507769Ssam  */
2517769Ssam put(argc, argv)
2527769Ssam 	char *argv[];
2537769Ssam {
2547769Ssam 	int fd;
25526095Sminshall 	register int n;
2567769Ssam 	register char *cp, *targ;
2577769Ssam 
2587769Ssam 	if (argc < 2) {
2597769Ssam 		strcpy(line, "send ");
2607769Ssam 		printf("(file) ");
2617769Ssam 		gets(&line[strlen(line)]);
2627769Ssam 		makeargv();
2637769Ssam 		argc = margc;
2647769Ssam 		argv = margv;
2657769Ssam 	}
2667769Ssam 	if (argc < 2) {
2677769Ssam 		putusage(argv[0]);
2687769Ssam 		return;
2697769Ssam 	}
2707769Ssam 	targ = argv[argc - 1];
2717769Ssam 	if (index(argv[argc - 1], ':')) {
2728384Ssam 		char *cp;
2738384Ssam 		struct hostent *hp;
2747769Ssam 
2757769Ssam 		for (n = 1; n < argc - 1; n++)
2767769Ssam 			if (index(argv[n], ':')) {
2777769Ssam 				putusage(argv[0]);
2787769Ssam 				return;
2797769Ssam 			}
2808384Ssam 		cp = argv[argc - 1];
2818384Ssam 		targ = index(cp, ':');
2827769Ssam 		*targ++ = 0;
2838384Ssam 		hp = gethostbyname(cp);
28435788Sbostic 		if (hp == NULL) {
28535788Sbostic 			fprintf(stderr, "tftp: %s: ", cp);
28635788Sbostic 			herror((char *)NULL);
2877769Ssam 			return;
2887769Ssam 		}
2899219Ssam 		bcopy(hp->h_addr, (caddr_t)&sin.sin_addr, hp->h_length);
2908384Ssam 		sin.sin_family = hp->h_addrtype;
2917769Ssam 		connected = 1;
29226095Sminshall 		strcpy(hostname, hp->h_name);
2937769Ssam 	}
2947769Ssam 	if (!connected) {
2957769Ssam 		printf("No target machine specified.\n");
2967769Ssam 		return;
2977769Ssam 	}
2987769Ssam 	if (argc < 4) {
2997769Ssam 		cp = argc == 2 ? tail(targ) : argv[1];
30013017Ssam 		fd = open(cp, O_RDONLY);
3017769Ssam 		if (fd < 0) {
30213017Ssam 			fprintf(stderr, "tftp: "); perror(cp);
3037769Ssam 			return;
3047769Ssam 		}
30526095Sminshall 		if (verbose)
30626095Sminshall 			printf("putting %s to %s:%s [%s]\n",
30726095Sminshall 				cp, hostname, targ, mode);
30826095Sminshall 		sin.sin_port = port;
30926095Sminshall 		sendfile(fd, targ, mode);
3107769Ssam 		return;
3117769Ssam 	}
31226095Sminshall 				/* this assumes the target is a directory */
31326095Sminshall 				/* on a remote unix system.  hmmmm.  */
3147769Ssam 	cp = index(targ, '\0');
3157769Ssam 	*cp++ = '/';
3167769Ssam 	for (n = 1; n < argc - 1; n++) {
3177769Ssam 		strcpy(cp, tail(argv[n]));
31813017Ssam 		fd = open(argv[n], O_RDONLY);
3197769Ssam 		if (fd < 0) {
32013017Ssam 			fprintf(stderr, "tftp: "); perror(argv[n]);
3217769Ssam 			continue;
3227769Ssam 		}
32326095Sminshall 		if (verbose)
32426095Sminshall 			printf("putting %s to %s:%s [%s]\n",
32526095Sminshall 				argv[n], hostname, targ, mode);
32626095Sminshall 		sin.sin_port = port;
32726095Sminshall 		sendfile(fd, targ, mode);
3287769Ssam 	}
3297769Ssam }
3307769Ssam 
3317769Ssam putusage(s)
3327769Ssam 	char *s;
3337769Ssam {
3347769Ssam 	printf("usage: %s file ... host:target, or\n", s);
3357769Ssam 	printf("       %s file ... target (when already connected)\n", s);
3367769Ssam }
3377769Ssam 
3387769Ssam /*
3397769Ssam  * Receive file(s).
3407769Ssam  */
3417769Ssam get(argc, argv)
3427769Ssam 	char *argv[];
3437769Ssam {
3447769Ssam 	int fd;
34526095Sminshall 	register int n;
3467769Ssam 	register char *cp;
3477769Ssam 	char *src;
3487769Ssam 
3497769Ssam 	if (argc < 2) {
3507769Ssam 		strcpy(line, "get ");
3517769Ssam 		printf("(files) ");
3527769Ssam 		gets(&line[strlen(line)]);
3537769Ssam 		makeargv();
3547769Ssam 		argc = margc;
3557769Ssam 		argv = margv;
3567769Ssam 	}
3577769Ssam 	if (argc < 2) {
3587769Ssam 		getusage(argv[0]);
3597769Ssam 		return;
3607769Ssam 	}
36126095Sminshall 	if (!connected) {
36226095Sminshall 		for (n = 1; n < argc ; n++)
3637769Ssam 			if (index(argv[n], ':') == 0) {
3647769Ssam 				getusage(argv[0]);
3657769Ssam 				return;
3667769Ssam 			}
36726095Sminshall 	}
36826095Sminshall 	for (n = 1; n < argc ; n++) {
3697769Ssam 		src = index(argv[n], ':');
3707769Ssam 		if (src == NULL)
3717769Ssam 			src = argv[n];
3727769Ssam 		else {
3738384Ssam 			struct hostent *hp;
3748384Ssam 
3757769Ssam 			*src++ = 0;
3768384Ssam 			hp = gethostbyname(argv[n]);
37735788Sbostic 			if (hp == NULL) {
37835788Sbostic 				fprintf(stderr, "tftp: %s: ", argv[n]);
37935788Sbostic 				herror((char *)NULL);
3807769Ssam 				continue;
3817769Ssam 			}
3829219Ssam 			bcopy(hp->h_addr, (caddr_t)&sin.sin_addr, hp->h_length);
3838384Ssam 			sin.sin_family = hp->h_addrtype;
3847769Ssam 			connected = 1;
38526095Sminshall 			strcpy(hostname, hp->h_name);
3867769Ssam 		}
3877769Ssam 		if (argc < 4) {
3887769Ssam 			cp = argc == 3 ? argv[2] : tail(src);
3897769Ssam 			fd = creat(cp, 0644);
3907769Ssam 			if (fd < 0) {
39113017Ssam 				fprintf(stderr, "tftp: "); perror(cp);
3927769Ssam 				return;
3937769Ssam 			}
39426095Sminshall 			if (verbose)
39526095Sminshall 				printf("getting from %s:%s to %s [%s]\n",
39626095Sminshall 					hostname, src, cp, mode);
39726095Sminshall 			sin.sin_port = port;
39826095Sminshall 			recvfile(fd, src, mode);
3997769Ssam 			break;
4007769Ssam 		}
40126095Sminshall 		cp = tail(src);         /* new .. jdg */
40226095Sminshall 		fd = creat(cp, 0644);
4037769Ssam 		if (fd < 0) {
40426095Sminshall 			fprintf(stderr, "tftp: "); perror(cp);
4057769Ssam 			continue;
4067769Ssam 		}
40726095Sminshall 		if (verbose)
40826095Sminshall 			printf("getting from %s:%s to %s [%s]\n",
40926095Sminshall 				hostname, src, cp, mode);
41026095Sminshall 		sin.sin_port = port;
41126095Sminshall 		recvfile(fd, src, mode);
4127769Ssam 	}
4137769Ssam }
4147769Ssam 
4157769Ssam getusage(s)
41626110Sminshall char * s;
4177769Ssam {
4187769Ssam 	printf("usage: %s host:file host:file ... file, or\n", s);
4197769Ssam 	printf("       %s file file ... file if connected\n", s);
4207769Ssam }
4217769Ssam 
42213017Ssam int	rexmtval = TIMEOUT;
42313017Ssam 
42413017Ssam setrexmt(argc, argv)
42513017Ssam 	char *argv[];
42613017Ssam {
42713017Ssam 	int t;
42813017Ssam 
42913017Ssam 	if (argc < 2) {
43013017Ssam 		strcpy(line, "Rexmt-timeout ");
43113017Ssam 		printf("(value) ");
43213017Ssam 		gets(&line[strlen(line)]);
43313017Ssam 		makeargv();
43413017Ssam 		argc = margc;
43513017Ssam 		argv = margv;
43613017Ssam 	}
43713017Ssam 	if (argc != 2) {
43813017Ssam 		printf("usage: %s value\n", argv[0]);
43913017Ssam 		return;
44013017Ssam 	}
44113017Ssam 	t = atoi(argv[1]);
44213017Ssam 	if (t < 0)
44313017Ssam 		printf("%s: bad value\n", t);
44413017Ssam 	else
44513017Ssam 		rexmtval = t;
44613017Ssam }
44713017Ssam 
44813017Ssam int	maxtimeout = 5 * TIMEOUT;
44913017Ssam 
45013017Ssam settimeout(argc, argv)
45113017Ssam 	char *argv[];
45213017Ssam {
45313017Ssam 	int t;
45413017Ssam 
45513017Ssam 	if (argc < 2) {
45613017Ssam 		strcpy(line, "Maximum-timeout ");
45713017Ssam 		printf("(value) ");
45813017Ssam 		gets(&line[strlen(line)]);
45913017Ssam 		makeargv();
46013017Ssam 		argc = margc;
46113017Ssam 		argv = margv;
46213017Ssam 	}
46313017Ssam 	if (argc != 2) {
46413017Ssam 		printf("usage: %s value\n", argv[0]);
46513017Ssam 		return;
46613017Ssam 	}
46713017Ssam 	t = atoi(argv[1]);
46813017Ssam 	if (t < 0)
46913017Ssam 		printf("%s: bad value\n", t);
47013017Ssam 	else
47113017Ssam 		maxtimeout = t;
47213017Ssam }
47313017Ssam 
4747769Ssam status(argc, argv)
4757769Ssam 	char *argv[];
4767769Ssam {
4777769Ssam 	if (connected)
4788384Ssam 		printf("Connected to %s.\n", hostname);
4797769Ssam 	else
4807769Ssam 		printf("Not connected.\n");
48126095Sminshall 	printf("Mode: %s Verbose: %s Tracing: %s\n", mode,
48226095Sminshall 		verbose ? "on" : "off", trace ? "on" : "off");
48313017Ssam 	printf("Rexmt-interval: %d seconds, Max-timeout: %d seconds\n",
48413017Ssam 		rexmtval, maxtimeout);
4857769Ssam }
4867769Ssam 
487*46861Sbostic void
4887769Ssam intr()
4897769Ssam {
49026095Sminshall 	signal(SIGALRM, SIG_IGN);
49116382Ssam 	alarm(0);
4927769Ssam 	longjmp(toplevel, -1);
4937769Ssam }
4947769Ssam 
4957769Ssam char *
4967769Ssam tail(filename)
4977769Ssam 	char *filename;
4987769Ssam {
4997769Ssam 	register char *s;
5007769Ssam 
5017769Ssam 	while (*filename) {
5027769Ssam 		s = rindex(filename, '/');
5037769Ssam 		if (s == NULL)
5047769Ssam 			break;
5057769Ssam 		if (s[1])
5067769Ssam 			return (s + 1);
5077769Ssam 		*s = '\0';
5087769Ssam 	}
5097769Ssam 	return (filename);
5107769Ssam }
5117769Ssam 
5127769Ssam /*
5137769Ssam  * Command parser.
5147769Ssam  */
5157769Ssam command(top)
5167769Ssam 	int top;
5177769Ssam {
5187769Ssam 	register struct cmd *c;
5197769Ssam 
5207769Ssam 	if (!top)
5217769Ssam 		putchar('\n');
5227769Ssam 	for (;;) {
5237769Ssam 		printf("%s> ", prompt);
52426103Sminshall 		if (gets(line) == 0) {
52526103Sminshall 			if (feof(stdin)) {
52626103Sminshall 				quit();
52726103Sminshall 			} else {
52826103Sminshall 				continue;
52926103Sminshall 			}
53026103Sminshall 		}
5317769Ssam 		if (line[0] == 0)
53213017Ssam 			continue;
5337769Ssam 		makeargv();
5347769Ssam 		c = getcmd(margv[0]);
5357769Ssam 		if (c == (struct cmd *)-1) {
5367769Ssam 			printf("?Ambiguous command\n");
5377769Ssam 			continue;
5387769Ssam 		}
5397769Ssam 		if (c == 0) {
5407769Ssam 			printf("?Invalid command\n");
5417769Ssam 			continue;
5427769Ssam 		}
5437769Ssam 		(*c->handler)(margc, margv);
5447769Ssam 	}
5457769Ssam }
5467769Ssam 
5477769Ssam struct cmd *
5487769Ssam getcmd(name)
5497769Ssam 	register char *name;
5507769Ssam {
5517769Ssam 	register char *p, *q;
5527769Ssam 	register struct cmd *c, *found;
5537769Ssam 	register int nmatches, longest;
5547769Ssam 
5557769Ssam 	longest = 0;
5567769Ssam 	nmatches = 0;
5577769Ssam 	found = 0;
5587769Ssam 	for (c = cmdtab; p = c->name; c++) {
5597769Ssam 		for (q = name; *q == *p++; q++)
5607769Ssam 			if (*q == 0)		/* exact match? */
5617769Ssam 				return (c);
5627769Ssam 		if (!*q) {			/* the name was a prefix */
5637769Ssam 			if (q - name > longest) {
5647769Ssam 				longest = q - name;
5657769Ssam 				nmatches = 1;
5667769Ssam 				found = c;
5677769Ssam 			} else if (q - name == longest)
5687769Ssam 				nmatches++;
5697769Ssam 		}
5707769Ssam 	}
5717769Ssam 	if (nmatches > 1)
5727769Ssam 		return ((struct cmd *)-1);
5737769Ssam 	return (found);
5747769Ssam }
5757769Ssam 
5767769Ssam /*
5777769Ssam  * Slice a string up into argc/argv.
5787769Ssam  */
5797769Ssam makeargv()
5807769Ssam {
5817769Ssam 	register char *cp;
5827769Ssam 	register char **argp = margv;
5837769Ssam 
5847769Ssam 	margc = 0;
5857769Ssam 	for (cp = line; *cp;) {
5867769Ssam 		while (isspace(*cp))
5877769Ssam 			cp++;
5887769Ssam 		if (*cp == '\0')
5897769Ssam 			break;
5907769Ssam 		*argp++ = cp;
5917769Ssam 		margc += 1;
5927769Ssam 		while (*cp != '\0' && !isspace(*cp))
5937769Ssam 			cp++;
5947769Ssam 		if (*cp == '\0')
5957769Ssam 			break;
5967769Ssam 		*cp++ = '\0';
5977769Ssam 	}
5987769Ssam 	*argp++ = 0;
5997769Ssam }
6007769Ssam 
6017769Ssam /*VARARGS*/
6027769Ssam quit()
6037769Ssam {
6047769Ssam 	exit(0);
6057769Ssam }
6067769Ssam 
6077769Ssam /*
6087769Ssam  * Help command.
6097769Ssam  */
6107769Ssam help(argc, argv)
6117769Ssam 	int argc;
6127769Ssam 	char *argv[];
6137769Ssam {
6147769Ssam 	register struct cmd *c;
6157769Ssam 
6167769Ssam 	if (argc == 1) {
6177769Ssam 		printf("Commands may be abbreviated.  Commands are:\n\n");
6187769Ssam 		for (c = cmdtab; c->name; c++)
6197769Ssam 			printf("%-*s\t%s\n", HELPINDENT, c->name, c->help);
6207769Ssam 		return;
6217769Ssam 	}
6227769Ssam 	while (--argc > 0) {
6237769Ssam 		register char *arg;
6247769Ssam 		arg = *++argv;
6257769Ssam 		c = getcmd(arg);
6267769Ssam 		if (c == (struct cmd *)-1)
6277769Ssam 			printf("?Ambiguous help command %s\n", arg);
6287769Ssam 		else if (c == (struct cmd *)0)
6297769Ssam 			printf("?Invalid help command %s\n", arg);
6307769Ssam 		else
6317769Ssam 			printf("%s\n", c->help);
6327769Ssam 	}
6337769Ssam }
6347769Ssam 
6357769Ssam /*VARARGS*/
6367769Ssam settrace()
6377769Ssam {
6387769Ssam 	trace = !trace;
6397769Ssam 	printf("Packet tracing %s.\n", trace ? "on" : "off");
6407769Ssam }
64126095Sminshall 
64226095Sminshall /*VARARGS*/
64326095Sminshall setverbose()
64426095Sminshall {
64526095Sminshall 	verbose = !verbose;
64626095Sminshall 	printf("Verbose mode %s.\n", verbose ? "on" : "off");
64726095Sminshall }
648