xref: /csrg-svn/usr.bin/tftp/main.c (revision 33821)
122403Sdist /*
2*33821Sbostic  * Copyright (c) 1983 Regents of the University of California.
3*33821Sbostic  * All rights reserved.
4*33821Sbostic  *
5*33821Sbostic  * Redistribution and use in source and binary forms are permitted
6*33821Sbostic  * provided that this notice is preserved and that due credit is given
7*33821Sbostic  * to the University of California at Berkeley. The name of the University
8*33821Sbostic  * may not be used to endorse or promote products derived from this
9*33821Sbostic  * software without specific prior written permission. This software
10*33821Sbostic  * is provided ``as is'' without express or implied warranty.
1122403Sdist  */
1222403Sdist 
1314553Ssam #ifndef lint
1422403Sdist char copyright[] =
1522403Sdist "@(#) Copyright (c) 1983 Regents of the University of California.\n\
1622403Sdist  All rights reserved.\n";
17*33821Sbostic #endif /* not lint */
187769Ssam 
1922403Sdist #ifndef lint
20*33821Sbostic static char sccsid[] = "@(#)main.c	5.6 (Berkeley) 03/28/88";
21*33821Sbostic #endif /* not lint */
2222403Sdist 
2326095Sminshall /* Many bug fixes are from Jim Guyton <guyton@rand-unix> */
2426095Sminshall 
257769Ssam /*
267769Ssam  * TFTP User Program -- Command Interface.
277769Ssam  */
287769Ssam #include <sys/types.h>
297769Ssam #include <sys/socket.h>
3013017Ssam #include <sys/file.h>
319219Ssam 
329219Ssam #include <netinet/in.h>
339219Ssam 
347769Ssam #include <signal.h>
357769Ssam #include <stdio.h>
367769Ssam #include <errno.h>
377769Ssam #include <setjmp.h>
387769Ssam #include <ctype.h>
398384Ssam #include <netdb.h>
407769Ssam 
4113017Ssam #define	TIMEOUT		5		/* secs between rexmt's */
4213017Ssam 
4326095Sminshall struct	sockaddr_in sin;
447769Ssam int	f;
4526095Sminshall short   port;
467769Ssam int	trace;
4726095Sminshall int	verbose;
487769Ssam int	connected;
497769Ssam char	mode[32];
507769Ssam char	line[200];
517769Ssam int	margc;
527769Ssam char	*margv[20];
537769Ssam char	*prompt = "tftp";
547769Ssam jmp_buf	toplevel;
557769Ssam int	intr();
568384Ssam struct	servent *sp;
577769Ssam 
5826095Sminshall int	quit(), help(), setverbose(), settrace(), status();
5926095Sminshall int     get(), put(), setpeer(), modecmd(), setrexmt(), settimeout();
6026095Sminshall int     setbinary(), setascii();
617769Ssam 
627769Ssam #define HELPINDENT (sizeof("connect"))
637769Ssam 
647769Ssam struct cmd {
657769Ssam 	char	*name;
667769Ssam 	char	*help;
677769Ssam 	int	(*handler)();
687769Ssam };
697769Ssam 
7026095Sminshall char	vhelp[] = "toggle verbose mode";
717769Ssam char	thelp[] = "toggle packet tracing";
727769Ssam char	chelp[] = "connect to remote tftp";
737769Ssam char	qhelp[] = "exit tftp";
747769Ssam char	hhelp[] = "print help information";
757769Ssam char	shelp[] = "send file";
767769Ssam char	rhelp[] = "receive file";
777769Ssam char	mhelp[] = "set file transfer mode";
787769Ssam char	sthelp[] = "show current status";
7913017Ssam char	xhelp[] = "set per-packet retransmission timeout";
8013017Ssam char	ihelp[] = "set total retransmission timeout";
8126095Sminshall char    ashelp[] = "set mode to netascii";
8226095Sminshall char    bnhelp[] = "set mode to octet";
837769Ssam 
847769Ssam struct cmd cmdtab[] = {
857769Ssam 	{ "connect",	chelp,		setpeer },
8626095Sminshall 	{ "mode",       mhelp,          modecmd },
877769Ssam 	{ "put",	shelp,		put },
887769Ssam 	{ "get",	rhelp,		get },
897769Ssam 	{ "quit",	qhelp,		quit },
9026095Sminshall 	{ "verbose",	vhelp,		setverbose },
917769Ssam 	{ "trace",	thelp,		settrace },
927769Ssam 	{ "status",	sthelp,		status },
9326095Sminshall 	{ "binary",     bnhelp,         setbinary },
9426095Sminshall 	{ "ascii",      ashelp,         setascii },
9513017Ssam 	{ "rexmt",	xhelp,		setrexmt },
9613017Ssam 	{ "timeout",	ihelp,		settimeout },
977769Ssam 	{ "?",		hhelp,		help },
987769Ssam 	0
997769Ssam };
1007769Ssam 
1017769Ssam struct	cmd *getcmd();
1027769Ssam char	*tail();
1037769Ssam char	*index();
1047769Ssam char	*rindex();
1057769Ssam 
1067769Ssam main(argc, argv)
1077769Ssam 	char *argv[];
1087769Ssam {
10926095Sminshall 	struct sockaddr_in sin;
11013017Ssam 	int top;
11113017Ssam 
1128384Ssam 	sp = getservbyname("tftp", "udp");
1138384Ssam 	if (sp == 0) {
1148384Ssam 		fprintf(stderr, "tftp: udp/tftp: unknown service\n");
1158384Ssam 		exit(1);
1168384Ssam 	}
11726110Sminshall 	f = socket(AF_INET, SOCK_DGRAM, 0);
1187769Ssam 	if (f < 0) {
11913017Ssam 		perror("tftp: socket");
1207769Ssam 		exit(3);
1217769Ssam 	}
12226095Sminshall 	bzero((char *)&sin, sizeof (sin));
12326095Sminshall 	sin.sin_family = AF_INET;
12413017Ssam 	if (bind(f, &sin, sizeof (sin)) < 0) {
12513017Ssam 		perror("tftp: bind");
12613017Ssam 		exit(1);
12713017Ssam 	}
12826095Sminshall 	strcpy(mode, "netascii");
12913017Ssam 	signal(SIGINT, intr);
1307769Ssam 	if (argc > 1) {
1317769Ssam 		if (setjmp(toplevel) != 0)
1327769Ssam 			exit(0);
1337769Ssam 		setpeer(argc, argv);
1347769Ssam 	}
13513017Ssam 	top = setjmp(toplevel) == 0;
1367769Ssam 	for (;;)
13713017Ssam 		command(top);
1387769Ssam }
1397769Ssam 
14026095Sminshall char    hostname[100];
1417769Ssam 
1427769Ssam setpeer(argc, argv)
1437769Ssam 	int argc;
1447769Ssam 	char *argv[];
1457769Ssam {
1468384Ssam 	struct hostent *host;
1477769Ssam 
1487769Ssam 	if (argc < 2) {
1497769Ssam 		strcpy(line, "Connect ");
1507769Ssam 		printf("(to) ");
1517769Ssam 		gets(&line[strlen(line)]);
1527769Ssam 		makeargv();
1537769Ssam 		argc = margc;
1547769Ssam 		argv = margv;
1557769Ssam 	}
1567769Ssam 	if (argc > 3) {
1577769Ssam 		printf("usage: %s host-name [port]\n", argv[0]);
1587769Ssam 		return;
1597769Ssam 	}
1608384Ssam 	host = gethostbyname(argv[1]);
1618384Ssam 	if (host) {
1629219Ssam 		sin.sin_family = host->h_addrtype;
1638384Ssam 		bcopy(host->h_addr, &sin.sin_addr, host->h_length);
16426095Sminshall 		strcpy(hostname, host->h_name);
1658384Ssam 	} else {
1669219Ssam 		sin.sin_family = AF_INET;
1678384Ssam 		sin.sin_addr.s_addr = inet_addr(argv[1]);
1688384Ssam 		if (sin.sin_addr.s_addr == -1) {
1698384Ssam 			connected = 0;
1708384Ssam 			printf("%s: unknown host\n", argv[1]);
1718384Ssam 			return;
1728384Ssam 		}
17326095Sminshall 		strcpy(hostname, argv[1]);
1747769Ssam 	}
17526095Sminshall 	port = sp->s_port;
1767769Ssam 	if (argc == 3) {
17726095Sminshall 		port = atoi(argv[2]);
17826095Sminshall 		if (port < 0) {
1797769Ssam 			printf("%s: bad port number\n", argv[2]);
1807769Ssam 			connected = 0;
1817769Ssam 			return;
1827769Ssam 		}
18326095Sminshall 		port = htons(port);
1848384Ssam 	}
1857769Ssam 	connected = 1;
1867769Ssam }
1877769Ssam 
1887769Ssam struct	modes {
1897769Ssam 	char *m_name;
1907769Ssam 	char *m_mode;
1917769Ssam } modes[] = {
19226095Sminshall 	{ "ascii",	"netascii" },
19326095Sminshall 	{ "netascii",   "netascii" },
19426095Sminshall 	{ "binary",     "octet" },
19526095Sminshall 	{ "image",      "octet" },
19626103Sminshall 	{ "octet",     "octet" },
19726095Sminshall /*      { "mail",       "mail" },       */
1987769Ssam 	{ 0,		0 }
1997769Ssam };
2007769Ssam 
20126095Sminshall modecmd(argc, argv)
2027769Ssam 	char *argv[];
2037769Ssam {
2047769Ssam 	register struct modes *p;
20526095Sminshall 	char *sep;
2067769Ssam 
2077769Ssam 	if (argc < 2) {
2087769Ssam 		printf("Using %s mode to transfer files.\n", mode);
2097769Ssam 		return;
2107769Ssam 	}
21126095Sminshall 	if (argc == 2) {
21226095Sminshall 		for (p = modes; p->m_name; p++)
21326095Sminshall 			if (strcmp(argv[1], p->m_name) == 0)
21426095Sminshall 				break;
21526095Sminshall 		if (p->m_name) {
21626095Sminshall 			setmode(p->m_mode);
21726095Sminshall 			return;
21826095Sminshall 		}
2197769Ssam 		printf("%s: unknown mode\n", argv[1]);
22026095Sminshall 		/* drop through and print usage message */
22126095Sminshall 	}
22226095Sminshall 
22326095Sminshall 	printf("usage: %s [", argv[0]);
22426095Sminshall 	sep = " ";
22526095Sminshall 	for (p = modes; p->m_name; p++) {
22626095Sminshall 		printf("%s%s", sep, p->m_name);
22726095Sminshall 		if (*sep == ' ')
22826095Sminshall 			sep = " | ";
22926095Sminshall 	}
23026095Sminshall 	printf(" ]\n");
23126095Sminshall 	return;
2327769Ssam }
2337769Ssam 
23426095Sminshall setbinary(argc, argv)
23526095Sminshall char *argv[];
23626095Sminshall {       setmode("octet");
23726095Sminshall }
23826095Sminshall 
23926095Sminshall setascii(argc, argv)
24026095Sminshall char *argv[];
24126095Sminshall {       setmode("netascii");
24226095Sminshall }
24326095Sminshall 
24426095Sminshall setmode(newmode)
24526095Sminshall char *newmode;
24626095Sminshall {
24726095Sminshall 	strcpy(mode, newmode);
24826095Sminshall 	if (verbose)
24926095Sminshall 		printf("mode set to %s\n", mode);
25026095Sminshall }
25126095Sminshall 
25226095Sminshall 
2537769Ssam /*
2547769Ssam  * Send file(s).
2557769Ssam  */
2567769Ssam put(argc, argv)
2577769Ssam 	char *argv[];
2587769Ssam {
2597769Ssam 	int fd;
26026095Sminshall 	register int n;
2617769Ssam 	register char *cp, *targ;
2627769Ssam 
2637769Ssam 	if (argc < 2) {
2647769Ssam 		strcpy(line, "send ");
2657769Ssam 		printf("(file) ");
2667769Ssam 		gets(&line[strlen(line)]);
2677769Ssam 		makeargv();
2687769Ssam 		argc = margc;
2697769Ssam 		argv = margv;
2707769Ssam 	}
2717769Ssam 	if (argc < 2) {
2727769Ssam 		putusage(argv[0]);
2737769Ssam 		return;
2747769Ssam 	}
2757769Ssam 	targ = argv[argc - 1];
2767769Ssam 	if (index(argv[argc - 1], ':')) {
2778384Ssam 		char *cp;
2788384Ssam 		struct hostent *hp;
2797769Ssam 
2807769Ssam 		for (n = 1; n < argc - 1; n++)
2817769Ssam 			if (index(argv[n], ':')) {
2827769Ssam 				putusage(argv[0]);
2837769Ssam 				return;
2847769Ssam 			}
2858384Ssam 		cp = argv[argc - 1];
2868384Ssam 		targ = index(cp, ':');
2877769Ssam 		*targ++ = 0;
2888384Ssam 		hp = gethostbyname(cp);
2898384Ssam 		if (hp == 0) {
2908384Ssam 			printf("%s: Unknown host.\n", cp);
2917769Ssam 			return;
2927769Ssam 		}
2939219Ssam 		bcopy(hp->h_addr, (caddr_t)&sin.sin_addr, hp->h_length);
2948384Ssam 		sin.sin_family = hp->h_addrtype;
2957769Ssam 		connected = 1;
29626095Sminshall 		strcpy(hostname, hp->h_name);
2977769Ssam 	}
2987769Ssam 	if (!connected) {
2997769Ssam 		printf("No target machine specified.\n");
3007769Ssam 		return;
3017769Ssam 	}
3027769Ssam 	if (argc < 4) {
3037769Ssam 		cp = argc == 2 ? tail(targ) : argv[1];
30413017Ssam 		fd = open(cp, O_RDONLY);
3057769Ssam 		if (fd < 0) {
30613017Ssam 			fprintf(stderr, "tftp: "); perror(cp);
3077769Ssam 			return;
3087769Ssam 		}
30926095Sminshall 		if (verbose)
31026095Sminshall 			printf("putting %s to %s:%s [%s]\n",
31126095Sminshall 				cp, hostname, targ, mode);
31226095Sminshall 		sin.sin_port = port;
31326095Sminshall 		sendfile(fd, targ, mode);
3147769Ssam 		return;
3157769Ssam 	}
31626095Sminshall 				/* this assumes the target is a directory */
31726095Sminshall 				/* on a remote unix system.  hmmmm.  */
3187769Ssam 	cp = index(targ, '\0');
3197769Ssam 	*cp++ = '/';
3207769Ssam 	for (n = 1; n < argc - 1; n++) {
3217769Ssam 		strcpy(cp, tail(argv[n]));
32213017Ssam 		fd = open(argv[n], O_RDONLY);
3237769Ssam 		if (fd < 0) {
32413017Ssam 			fprintf(stderr, "tftp: "); perror(argv[n]);
3257769Ssam 			continue;
3267769Ssam 		}
32726095Sminshall 		if (verbose)
32826095Sminshall 			printf("putting %s to %s:%s [%s]\n",
32926095Sminshall 				argv[n], hostname, targ, mode);
33026095Sminshall 		sin.sin_port = port;
33126095Sminshall 		sendfile(fd, targ, mode);
3327769Ssam 	}
3337769Ssam }
3347769Ssam 
3357769Ssam putusage(s)
3367769Ssam 	char *s;
3377769Ssam {
3387769Ssam 	printf("usage: %s file ... host:target, or\n", s);
3397769Ssam 	printf("       %s file ... target (when already connected)\n", s);
3407769Ssam }
3417769Ssam 
3427769Ssam /*
3437769Ssam  * Receive file(s).
3447769Ssam  */
3457769Ssam get(argc, argv)
3467769Ssam 	char *argv[];
3477769Ssam {
3487769Ssam 	int fd;
34926095Sminshall 	register int n;
3507769Ssam 	register char *cp;
3517769Ssam 	char *src;
3527769Ssam 
3537769Ssam 	if (argc < 2) {
3547769Ssam 		strcpy(line, "get ");
3557769Ssam 		printf("(files) ");
3567769Ssam 		gets(&line[strlen(line)]);
3577769Ssam 		makeargv();
3587769Ssam 		argc = margc;
3597769Ssam 		argv = margv;
3607769Ssam 	}
3617769Ssam 	if (argc < 2) {
3627769Ssam 		getusage(argv[0]);
3637769Ssam 		return;
3647769Ssam 	}
36526095Sminshall 	if (!connected) {
36626095Sminshall 		for (n = 1; n < argc ; n++)
3677769Ssam 			if (index(argv[n], ':') == 0) {
3687769Ssam 				getusage(argv[0]);
3697769Ssam 				return;
3707769Ssam 			}
37126095Sminshall 	}
37226095Sminshall 	for (n = 1; n < argc ; n++) {
3737769Ssam 		src = index(argv[n], ':');
3747769Ssam 		if (src == NULL)
3757769Ssam 			src = argv[n];
3767769Ssam 		else {
3778384Ssam 			struct hostent *hp;
3788384Ssam 
3797769Ssam 			*src++ = 0;
3808384Ssam 			hp = gethostbyname(argv[n]);
3818384Ssam 			if (hp == 0) {
3827769Ssam 				printf("%s: Unknown host.\n", argv[n]);
3837769Ssam 				continue;
3847769Ssam 			}
3859219Ssam 			bcopy(hp->h_addr, (caddr_t)&sin.sin_addr, hp->h_length);
3868384Ssam 			sin.sin_family = hp->h_addrtype;
3877769Ssam 			connected = 1;
38826095Sminshall 			strcpy(hostname, hp->h_name);
3897769Ssam 		}
3907769Ssam 		if (argc < 4) {
3917769Ssam 			cp = argc == 3 ? argv[2] : tail(src);
3927769Ssam 			fd = creat(cp, 0644);
3937769Ssam 			if (fd < 0) {
39413017Ssam 				fprintf(stderr, "tftp: "); perror(cp);
3957769Ssam 				return;
3967769Ssam 			}
39726095Sminshall 			if (verbose)
39826095Sminshall 				printf("getting from %s:%s to %s [%s]\n",
39926095Sminshall 					hostname, src, cp, mode);
40026095Sminshall 			sin.sin_port = port;
40126095Sminshall 			recvfile(fd, src, mode);
4027769Ssam 			break;
4037769Ssam 		}
40426095Sminshall 		cp = tail(src);         /* new .. jdg */
40526095Sminshall 		fd = creat(cp, 0644);
4067769Ssam 		if (fd < 0) {
40726095Sminshall 			fprintf(stderr, "tftp: "); perror(cp);
4087769Ssam 			continue;
4097769Ssam 		}
41026095Sminshall 		if (verbose)
41126095Sminshall 			printf("getting from %s:%s to %s [%s]\n",
41226095Sminshall 				hostname, src, cp, mode);
41326095Sminshall 		sin.sin_port = port;
41426095Sminshall 		recvfile(fd, src, mode);
4157769Ssam 	}
4167769Ssam }
4177769Ssam 
4187769Ssam getusage(s)
41926110Sminshall char * s;
4207769Ssam {
4217769Ssam 	printf("usage: %s host:file host:file ... file, or\n", s);
4227769Ssam 	printf("       %s file file ... file if connected\n", s);
4237769Ssam }
4247769Ssam 
42513017Ssam int	rexmtval = TIMEOUT;
42613017Ssam 
42713017Ssam setrexmt(argc, argv)
42813017Ssam 	char *argv[];
42913017Ssam {
43013017Ssam 	int t;
43113017Ssam 
43213017Ssam 	if (argc < 2) {
43313017Ssam 		strcpy(line, "Rexmt-timeout ");
43413017Ssam 		printf("(value) ");
43513017Ssam 		gets(&line[strlen(line)]);
43613017Ssam 		makeargv();
43713017Ssam 		argc = margc;
43813017Ssam 		argv = margv;
43913017Ssam 	}
44013017Ssam 	if (argc != 2) {
44113017Ssam 		printf("usage: %s value\n", argv[0]);
44213017Ssam 		return;
44313017Ssam 	}
44413017Ssam 	t = atoi(argv[1]);
44513017Ssam 	if (t < 0)
44613017Ssam 		printf("%s: bad value\n", t);
44713017Ssam 	else
44813017Ssam 		rexmtval = t;
44913017Ssam }
45013017Ssam 
45113017Ssam int	maxtimeout = 5 * TIMEOUT;
45213017Ssam 
45313017Ssam settimeout(argc, argv)
45413017Ssam 	char *argv[];
45513017Ssam {
45613017Ssam 	int t;
45713017Ssam 
45813017Ssam 	if (argc < 2) {
45913017Ssam 		strcpy(line, "Maximum-timeout ");
46013017Ssam 		printf("(value) ");
46113017Ssam 		gets(&line[strlen(line)]);
46213017Ssam 		makeargv();
46313017Ssam 		argc = margc;
46413017Ssam 		argv = margv;
46513017Ssam 	}
46613017Ssam 	if (argc != 2) {
46713017Ssam 		printf("usage: %s value\n", argv[0]);
46813017Ssam 		return;
46913017Ssam 	}
47013017Ssam 	t = atoi(argv[1]);
47113017Ssam 	if (t < 0)
47213017Ssam 		printf("%s: bad value\n", t);
47313017Ssam 	else
47413017Ssam 		maxtimeout = t;
47513017Ssam }
47613017Ssam 
4777769Ssam status(argc, argv)
4787769Ssam 	char *argv[];
4797769Ssam {
4807769Ssam 	if (connected)
4818384Ssam 		printf("Connected to %s.\n", hostname);
4827769Ssam 	else
4837769Ssam 		printf("Not connected.\n");
48426095Sminshall 	printf("Mode: %s Verbose: %s Tracing: %s\n", mode,
48526095Sminshall 		verbose ? "on" : "off", trace ? "on" : "off");
48613017Ssam 	printf("Rexmt-interval: %d seconds, Max-timeout: %d seconds\n",
48713017Ssam 		rexmtval, maxtimeout);
4887769Ssam }
4897769Ssam 
4907769Ssam intr()
4917769Ssam {
49226095Sminshall 	signal(SIGALRM, SIG_IGN);
49316382Ssam 	alarm(0);
4947769Ssam 	longjmp(toplevel, -1);
4957769Ssam }
4967769Ssam 
4977769Ssam char *
4987769Ssam tail(filename)
4997769Ssam 	char *filename;
5007769Ssam {
5017769Ssam 	register char *s;
5027769Ssam 
5037769Ssam 	while (*filename) {
5047769Ssam 		s = rindex(filename, '/');
5057769Ssam 		if (s == NULL)
5067769Ssam 			break;
5077769Ssam 		if (s[1])
5087769Ssam 			return (s + 1);
5097769Ssam 		*s = '\0';
5107769Ssam 	}
5117769Ssam 	return (filename);
5127769Ssam }
5137769Ssam 
5147769Ssam /*
5157769Ssam  * Command parser.
5167769Ssam  */
5177769Ssam command(top)
5187769Ssam 	int top;
5197769Ssam {
5207769Ssam 	register struct cmd *c;
5217769Ssam 
5227769Ssam 	if (!top)
5237769Ssam 		putchar('\n');
5247769Ssam 	for (;;) {
5257769Ssam 		printf("%s> ", prompt);
52626103Sminshall 		if (gets(line) == 0) {
52726103Sminshall 			if (feof(stdin)) {
52826103Sminshall 				quit();
52926103Sminshall 			} else {
53026103Sminshall 				continue;
53126103Sminshall 			}
53226103Sminshall 		}
5337769Ssam 		if (line[0] == 0)
53413017Ssam 			continue;
5357769Ssam 		makeargv();
5367769Ssam 		c = getcmd(margv[0]);
5377769Ssam 		if (c == (struct cmd *)-1) {
5387769Ssam 			printf("?Ambiguous command\n");
5397769Ssam 			continue;
5407769Ssam 		}
5417769Ssam 		if (c == 0) {
5427769Ssam 			printf("?Invalid command\n");
5437769Ssam 			continue;
5447769Ssam 		}
5457769Ssam 		(*c->handler)(margc, margv);
5467769Ssam 	}
5477769Ssam }
5487769Ssam 
5497769Ssam struct cmd *
5507769Ssam getcmd(name)
5517769Ssam 	register char *name;
5527769Ssam {
5537769Ssam 	register char *p, *q;
5547769Ssam 	register struct cmd *c, *found;
5557769Ssam 	register int nmatches, longest;
5567769Ssam 
5577769Ssam 	longest = 0;
5587769Ssam 	nmatches = 0;
5597769Ssam 	found = 0;
5607769Ssam 	for (c = cmdtab; p = c->name; c++) {
5617769Ssam 		for (q = name; *q == *p++; q++)
5627769Ssam 			if (*q == 0)		/* exact match? */
5637769Ssam 				return (c);
5647769Ssam 		if (!*q) {			/* the name was a prefix */
5657769Ssam 			if (q - name > longest) {
5667769Ssam 				longest = q - name;
5677769Ssam 				nmatches = 1;
5687769Ssam 				found = c;
5697769Ssam 			} else if (q - name == longest)
5707769Ssam 				nmatches++;
5717769Ssam 		}
5727769Ssam 	}
5737769Ssam 	if (nmatches > 1)
5747769Ssam 		return ((struct cmd *)-1);
5757769Ssam 	return (found);
5767769Ssam }
5777769Ssam 
5787769Ssam /*
5797769Ssam  * Slice a string up into argc/argv.
5807769Ssam  */
5817769Ssam makeargv()
5827769Ssam {
5837769Ssam 	register char *cp;
5847769Ssam 	register char **argp = margv;
5857769Ssam 
5867769Ssam 	margc = 0;
5877769Ssam 	for (cp = line; *cp;) {
5887769Ssam 		while (isspace(*cp))
5897769Ssam 			cp++;
5907769Ssam 		if (*cp == '\0')
5917769Ssam 			break;
5927769Ssam 		*argp++ = cp;
5937769Ssam 		margc += 1;
5947769Ssam 		while (*cp != '\0' && !isspace(*cp))
5957769Ssam 			cp++;
5967769Ssam 		if (*cp == '\0')
5977769Ssam 			break;
5987769Ssam 		*cp++ = '\0';
5997769Ssam 	}
6007769Ssam 	*argp++ = 0;
6017769Ssam }
6027769Ssam 
6037769Ssam /*VARARGS*/
6047769Ssam quit()
6057769Ssam {
6067769Ssam 	exit(0);
6077769Ssam }
6087769Ssam 
6097769Ssam /*
6107769Ssam  * Help command.
6117769Ssam  */
6127769Ssam help(argc, argv)
6137769Ssam 	int argc;
6147769Ssam 	char *argv[];
6157769Ssam {
6167769Ssam 	register struct cmd *c;
6177769Ssam 
6187769Ssam 	if (argc == 1) {
6197769Ssam 		printf("Commands may be abbreviated.  Commands are:\n\n");
6207769Ssam 		for (c = cmdtab; c->name; c++)
6217769Ssam 			printf("%-*s\t%s\n", HELPINDENT, c->name, c->help);
6227769Ssam 		return;
6237769Ssam 	}
6247769Ssam 	while (--argc > 0) {
6257769Ssam 		register char *arg;
6267769Ssam 		arg = *++argv;
6277769Ssam 		c = getcmd(arg);
6287769Ssam 		if (c == (struct cmd *)-1)
6297769Ssam 			printf("?Ambiguous help command %s\n", arg);
6307769Ssam 		else if (c == (struct cmd *)0)
6317769Ssam 			printf("?Invalid help command %s\n", arg);
6327769Ssam 		else
6337769Ssam 			printf("%s\n", c->help);
6347769Ssam 	}
6357769Ssam }
6367769Ssam 
6377769Ssam /*VARARGS*/
6387769Ssam settrace()
6397769Ssam {
6407769Ssam 	trace = !trace;
6417769Ssam 	printf("Packet tracing %s.\n", trace ? "on" : "off");
6427769Ssam }
64326095Sminshall 
64426095Sminshall /*VARARGS*/
64526095Sminshall setverbose()
64626095Sminshall {
64726095Sminshall 	verbose = !verbose;
64826095Sminshall 	printf("Verbose mode %s.\n", verbose ? "on" : "off");
64926095Sminshall }
650