xref: /csrg-svn/usr.bin/tftp/main.c (revision 35788)
122403Sdist /*
233821Sbostic  * Copyright (c) 1983 Regents of the University of California.
333821Sbostic  * All rights reserved.
433821Sbostic  *
533821Sbostic  * Redistribution and use in source and binary forms are permitted
634903Sbostic  * provided that the above copyright notice and this paragraph are
734903Sbostic  * duplicated in all such forms and that any documentation,
834903Sbostic  * advertising materials, and other materials related to such
934903Sbostic  * distribution and use acknowledge that the software was developed
1034903Sbostic  * by the University of California, Berkeley.  The name of the
1134903Sbostic  * University may not be used to endorse or promote products derived
1234903Sbostic  * from this software without specific prior written permission.
1334903Sbostic  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1434903Sbostic  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1534903Sbostic  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1622403Sdist  */
1722403Sdist 
1814553Ssam #ifndef lint
1922403Sdist char copyright[] =
2022403Sdist "@(#) Copyright (c) 1983 Regents of the University of California.\n\
2122403Sdist  All rights reserved.\n";
2233821Sbostic #endif /* not lint */
237769Ssam 
2422403Sdist #ifndef lint
25*35788Sbostic static char sccsid[] = "@(#)main.c	5.8 (Berkeley) 10/11/88";
2633821Sbostic #endif /* not lint */
2722403Sdist 
2826095Sminshall /* Many bug fixes are from Jim Guyton <guyton@rand-unix> */
2926095Sminshall 
307769Ssam /*
317769Ssam  * TFTP User Program -- Command Interface.
327769Ssam  */
337769Ssam #include <sys/types.h>
347769Ssam #include <sys/socket.h>
3513017Ssam #include <sys/file.h>
369219Ssam 
379219Ssam #include <netinet/in.h>
389219Ssam 
397769Ssam #include <signal.h>
407769Ssam #include <stdio.h>
417769Ssam #include <errno.h>
427769Ssam #include <setjmp.h>
437769Ssam #include <ctype.h>
448384Ssam #include <netdb.h>
457769Ssam 
4613017Ssam #define	TIMEOUT		5		/* secs between rexmt's */
4713017Ssam 
4826095Sminshall struct	sockaddr_in sin;
497769Ssam int	f;
5026095Sminshall short   port;
517769Ssam int	trace;
5226095Sminshall int	verbose;
537769Ssam int	connected;
547769Ssam char	mode[32];
557769Ssam char	line[200];
567769Ssam int	margc;
577769Ssam char	*margv[20];
587769Ssam char	*prompt = "tftp";
597769Ssam jmp_buf	toplevel;
607769Ssam int	intr();
618384Ssam struct	servent *sp;
627769Ssam 
6326095Sminshall int	quit(), help(), setverbose(), settrace(), status();
6426095Sminshall int     get(), put(), setpeer(), modecmd(), setrexmt(), settimeout();
6526095Sminshall int     setbinary(), setascii();
667769Ssam 
677769Ssam #define HELPINDENT (sizeof("connect"))
687769Ssam 
697769Ssam struct cmd {
707769Ssam 	char	*name;
717769Ssam 	char	*help;
727769Ssam 	int	(*handler)();
737769Ssam };
747769Ssam 
7526095Sminshall char	vhelp[] = "toggle verbose mode";
767769Ssam char	thelp[] = "toggle packet tracing";
777769Ssam char	chelp[] = "connect to remote tftp";
787769Ssam char	qhelp[] = "exit tftp";
797769Ssam char	hhelp[] = "print help information";
807769Ssam char	shelp[] = "send file";
817769Ssam char	rhelp[] = "receive file";
827769Ssam char	mhelp[] = "set file transfer mode";
837769Ssam char	sthelp[] = "show current status";
8413017Ssam char	xhelp[] = "set per-packet retransmission timeout";
8513017Ssam char	ihelp[] = "set total retransmission timeout";
8626095Sminshall char    ashelp[] = "set mode to netascii";
8726095Sminshall char    bnhelp[] = "set mode to octet";
887769Ssam 
897769Ssam struct cmd cmdtab[] = {
907769Ssam 	{ "connect",	chelp,		setpeer },
9126095Sminshall 	{ "mode",       mhelp,          modecmd },
927769Ssam 	{ "put",	shelp,		put },
937769Ssam 	{ "get",	rhelp,		get },
947769Ssam 	{ "quit",	qhelp,		quit },
9526095Sminshall 	{ "verbose",	vhelp,		setverbose },
967769Ssam 	{ "trace",	thelp,		settrace },
977769Ssam 	{ "status",	sthelp,		status },
9826095Sminshall 	{ "binary",     bnhelp,         setbinary },
9926095Sminshall 	{ "ascii",      ashelp,         setascii },
10013017Ssam 	{ "rexmt",	xhelp,		setrexmt },
10113017Ssam 	{ "timeout",	ihelp,		settimeout },
1027769Ssam 	{ "?",		hhelp,		help },
1037769Ssam 	0
1047769Ssam };
1057769Ssam 
1067769Ssam struct	cmd *getcmd();
1077769Ssam char	*tail();
1087769Ssam char	*index();
1097769Ssam char	*rindex();
1107769Ssam 
1117769Ssam main(argc, argv)
1127769Ssam 	char *argv[];
1137769Ssam {
11426095Sminshall 	struct sockaddr_in sin;
11513017Ssam 	int top;
11613017Ssam 
1178384Ssam 	sp = getservbyname("tftp", "udp");
1188384Ssam 	if (sp == 0) {
1198384Ssam 		fprintf(stderr, "tftp: udp/tftp: unknown service\n");
1208384Ssam 		exit(1);
1218384Ssam 	}
12226110Sminshall 	f = socket(AF_INET, SOCK_DGRAM, 0);
1237769Ssam 	if (f < 0) {
12413017Ssam 		perror("tftp: socket");
1257769Ssam 		exit(3);
1267769Ssam 	}
12726095Sminshall 	bzero((char *)&sin, sizeof (sin));
12826095Sminshall 	sin.sin_family = AF_INET;
12913017Ssam 	if (bind(f, &sin, sizeof (sin)) < 0) {
13013017Ssam 		perror("tftp: bind");
13113017Ssam 		exit(1);
13213017Ssam 	}
13326095Sminshall 	strcpy(mode, "netascii");
13413017Ssam 	signal(SIGINT, intr);
1357769Ssam 	if (argc > 1) {
1367769Ssam 		if (setjmp(toplevel) != 0)
1377769Ssam 			exit(0);
1387769Ssam 		setpeer(argc, argv);
1397769Ssam 	}
14013017Ssam 	top = setjmp(toplevel) == 0;
1417769Ssam 	for (;;)
14213017Ssam 		command(top);
1437769Ssam }
1447769Ssam 
14526095Sminshall char    hostname[100];
1467769Ssam 
1477769Ssam setpeer(argc, argv)
1487769Ssam 	int argc;
1497769Ssam 	char *argv[];
1507769Ssam {
1518384Ssam 	struct hostent *host;
1527769Ssam 
1537769Ssam 	if (argc < 2) {
1547769Ssam 		strcpy(line, "Connect ");
1557769Ssam 		printf("(to) ");
1567769Ssam 		gets(&line[strlen(line)]);
1577769Ssam 		makeargv();
1587769Ssam 		argc = margc;
1597769Ssam 		argv = margv;
1607769Ssam 	}
1617769Ssam 	if (argc > 3) {
1627769Ssam 		printf("usage: %s host-name [port]\n", argv[0]);
1637769Ssam 		return;
1647769Ssam 	}
1658384Ssam 	host = gethostbyname(argv[1]);
1668384Ssam 	if (host) {
1679219Ssam 		sin.sin_family = host->h_addrtype;
1688384Ssam 		bcopy(host->h_addr, &sin.sin_addr, host->h_length);
16926095Sminshall 		strcpy(hostname, host->h_name);
1708384Ssam 	} else {
1719219Ssam 		sin.sin_family = AF_INET;
1728384Ssam 		sin.sin_addr.s_addr = inet_addr(argv[1]);
1738384Ssam 		if (sin.sin_addr.s_addr == -1) {
1748384Ssam 			connected = 0;
1758384Ssam 			printf("%s: unknown host\n", argv[1]);
1768384Ssam 			return;
1778384Ssam 		}
17826095Sminshall 		strcpy(hostname, argv[1]);
1797769Ssam 	}
18026095Sminshall 	port = sp->s_port;
1817769Ssam 	if (argc == 3) {
18226095Sminshall 		port = atoi(argv[2]);
18326095Sminshall 		if (port < 0) {
1847769Ssam 			printf("%s: bad port number\n", argv[2]);
1857769Ssam 			connected = 0;
1867769Ssam 			return;
1877769Ssam 		}
18826095Sminshall 		port = htons(port);
1898384Ssam 	}
1907769Ssam 	connected = 1;
1917769Ssam }
1927769Ssam 
1937769Ssam struct	modes {
1947769Ssam 	char *m_name;
1957769Ssam 	char *m_mode;
1967769Ssam } modes[] = {
19726095Sminshall 	{ "ascii",	"netascii" },
19826095Sminshall 	{ "netascii",   "netascii" },
19926095Sminshall 	{ "binary",     "octet" },
20026095Sminshall 	{ "image",      "octet" },
20126103Sminshall 	{ "octet",     "octet" },
20226095Sminshall /*      { "mail",       "mail" },       */
2037769Ssam 	{ 0,		0 }
2047769Ssam };
2057769Ssam 
20626095Sminshall modecmd(argc, argv)
2077769Ssam 	char *argv[];
2087769Ssam {
2097769Ssam 	register struct modes *p;
21026095Sminshall 	char *sep;
2117769Ssam 
2127769Ssam 	if (argc < 2) {
2137769Ssam 		printf("Using %s mode to transfer files.\n", mode);
2147769Ssam 		return;
2157769Ssam 	}
21626095Sminshall 	if (argc == 2) {
21726095Sminshall 		for (p = modes; p->m_name; p++)
21826095Sminshall 			if (strcmp(argv[1], p->m_name) == 0)
21926095Sminshall 				break;
22026095Sminshall 		if (p->m_name) {
22126095Sminshall 			setmode(p->m_mode);
22226095Sminshall 			return;
22326095Sminshall 		}
2247769Ssam 		printf("%s: unknown mode\n", argv[1]);
22526095Sminshall 		/* drop through and print usage message */
22626095Sminshall 	}
22726095Sminshall 
22826095Sminshall 	printf("usage: %s [", argv[0]);
22926095Sminshall 	sep = " ";
23026095Sminshall 	for (p = modes; p->m_name; p++) {
23126095Sminshall 		printf("%s%s", sep, p->m_name);
23226095Sminshall 		if (*sep == ' ')
23326095Sminshall 			sep = " | ";
23426095Sminshall 	}
23526095Sminshall 	printf(" ]\n");
23626095Sminshall 	return;
2377769Ssam }
2387769Ssam 
23926095Sminshall setbinary(argc, argv)
24026095Sminshall char *argv[];
24126095Sminshall {       setmode("octet");
24226095Sminshall }
24326095Sminshall 
24426095Sminshall setascii(argc, argv)
24526095Sminshall char *argv[];
24626095Sminshall {       setmode("netascii");
24726095Sminshall }
24826095Sminshall 
24926095Sminshall setmode(newmode)
25026095Sminshall char *newmode;
25126095Sminshall {
25226095Sminshall 	strcpy(mode, newmode);
25326095Sminshall 	if (verbose)
25426095Sminshall 		printf("mode set to %s\n", mode);
25526095Sminshall }
25626095Sminshall 
25726095Sminshall 
2587769Ssam /*
2597769Ssam  * Send file(s).
2607769Ssam  */
2617769Ssam put(argc, argv)
2627769Ssam 	char *argv[];
2637769Ssam {
2647769Ssam 	int fd;
26526095Sminshall 	register int n;
2667769Ssam 	register char *cp, *targ;
2677769Ssam 
2687769Ssam 	if (argc < 2) {
2697769Ssam 		strcpy(line, "send ");
2707769Ssam 		printf("(file) ");
2717769Ssam 		gets(&line[strlen(line)]);
2727769Ssam 		makeargv();
2737769Ssam 		argc = margc;
2747769Ssam 		argv = margv;
2757769Ssam 	}
2767769Ssam 	if (argc < 2) {
2777769Ssam 		putusage(argv[0]);
2787769Ssam 		return;
2797769Ssam 	}
2807769Ssam 	targ = argv[argc - 1];
2817769Ssam 	if (index(argv[argc - 1], ':')) {
2828384Ssam 		char *cp;
2838384Ssam 		struct hostent *hp;
2847769Ssam 
2857769Ssam 		for (n = 1; n < argc - 1; n++)
2867769Ssam 			if (index(argv[n], ':')) {
2877769Ssam 				putusage(argv[0]);
2887769Ssam 				return;
2897769Ssam 			}
2908384Ssam 		cp = argv[argc - 1];
2918384Ssam 		targ = index(cp, ':');
2927769Ssam 		*targ++ = 0;
2938384Ssam 		hp = gethostbyname(cp);
294*35788Sbostic 		if (hp == NULL) {
295*35788Sbostic 			fprintf(stderr, "tftp: %s: ", cp);
296*35788Sbostic 			herror((char *)NULL);
2977769Ssam 			return;
2987769Ssam 		}
2999219Ssam 		bcopy(hp->h_addr, (caddr_t)&sin.sin_addr, hp->h_length);
3008384Ssam 		sin.sin_family = hp->h_addrtype;
3017769Ssam 		connected = 1;
30226095Sminshall 		strcpy(hostname, hp->h_name);
3037769Ssam 	}
3047769Ssam 	if (!connected) {
3057769Ssam 		printf("No target machine specified.\n");
3067769Ssam 		return;
3077769Ssam 	}
3087769Ssam 	if (argc < 4) {
3097769Ssam 		cp = argc == 2 ? tail(targ) : argv[1];
31013017Ssam 		fd = open(cp, O_RDONLY);
3117769Ssam 		if (fd < 0) {
31213017Ssam 			fprintf(stderr, "tftp: "); perror(cp);
3137769Ssam 			return;
3147769Ssam 		}
31526095Sminshall 		if (verbose)
31626095Sminshall 			printf("putting %s to %s:%s [%s]\n",
31726095Sminshall 				cp, hostname, targ, mode);
31826095Sminshall 		sin.sin_port = port;
31926095Sminshall 		sendfile(fd, targ, mode);
3207769Ssam 		return;
3217769Ssam 	}
32226095Sminshall 				/* this assumes the target is a directory */
32326095Sminshall 				/* on a remote unix system.  hmmmm.  */
3247769Ssam 	cp = index(targ, '\0');
3257769Ssam 	*cp++ = '/';
3267769Ssam 	for (n = 1; n < argc - 1; n++) {
3277769Ssam 		strcpy(cp, tail(argv[n]));
32813017Ssam 		fd = open(argv[n], O_RDONLY);
3297769Ssam 		if (fd < 0) {
33013017Ssam 			fprintf(stderr, "tftp: "); perror(argv[n]);
3317769Ssam 			continue;
3327769Ssam 		}
33326095Sminshall 		if (verbose)
33426095Sminshall 			printf("putting %s to %s:%s [%s]\n",
33526095Sminshall 				argv[n], hostname, targ, mode);
33626095Sminshall 		sin.sin_port = port;
33726095Sminshall 		sendfile(fd, targ, mode);
3387769Ssam 	}
3397769Ssam }
3407769Ssam 
3417769Ssam putusage(s)
3427769Ssam 	char *s;
3437769Ssam {
3447769Ssam 	printf("usage: %s file ... host:target, or\n", s);
3457769Ssam 	printf("       %s file ... target (when already connected)\n", s);
3467769Ssam }
3477769Ssam 
3487769Ssam /*
3497769Ssam  * Receive file(s).
3507769Ssam  */
3517769Ssam get(argc, argv)
3527769Ssam 	char *argv[];
3537769Ssam {
3547769Ssam 	int fd;
35526095Sminshall 	register int n;
3567769Ssam 	register char *cp;
3577769Ssam 	char *src;
3587769Ssam 
3597769Ssam 	if (argc < 2) {
3607769Ssam 		strcpy(line, "get ");
3617769Ssam 		printf("(files) ");
3627769Ssam 		gets(&line[strlen(line)]);
3637769Ssam 		makeargv();
3647769Ssam 		argc = margc;
3657769Ssam 		argv = margv;
3667769Ssam 	}
3677769Ssam 	if (argc < 2) {
3687769Ssam 		getusage(argv[0]);
3697769Ssam 		return;
3707769Ssam 	}
37126095Sminshall 	if (!connected) {
37226095Sminshall 		for (n = 1; n < argc ; n++)
3737769Ssam 			if (index(argv[n], ':') == 0) {
3747769Ssam 				getusage(argv[0]);
3757769Ssam 				return;
3767769Ssam 			}
37726095Sminshall 	}
37826095Sminshall 	for (n = 1; n < argc ; n++) {
3797769Ssam 		src = index(argv[n], ':');
3807769Ssam 		if (src == NULL)
3817769Ssam 			src = argv[n];
3827769Ssam 		else {
3838384Ssam 			struct hostent *hp;
3848384Ssam 
3857769Ssam 			*src++ = 0;
3868384Ssam 			hp = gethostbyname(argv[n]);
387*35788Sbostic 			if (hp == NULL) {
388*35788Sbostic 				fprintf(stderr, "tftp: %s: ", argv[n]);
389*35788Sbostic 				herror((char *)NULL);
3907769Ssam 				continue;
3917769Ssam 			}
3929219Ssam 			bcopy(hp->h_addr, (caddr_t)&sin.sin_addr, hp->h_length);
3938384Ssam 			sin.sin_family = hp->h_addrtype;
3947769Ssam 			connected = 1;
39526095Sminshall 			strcpy(hostname, hp->h_name);
3967769Ssam 		}
3977769Ssam 		if (argc < 4) {
3987769Ssam 			cp = argc == 3 ? argv[2] : tail(src);
3997769Ssam 			fd = creat(cp, 0644);
4007769Ssam 			if (fd < 0) {
40113017Ssam 				fprintf(stderr, "tftp: "); perror(cp);
4027769Ssam 				return;
4037769Ssam 			}
40426095Sminshall 			if (verbose)
40526095Sminshall 				printf("getting from %s:%s to %s [%s]\n",
40626095Sminshall 					hostname, src, cp, mode);
40726095Sminshall 			sin.sin_port = port;
40826095Sminshall 			recvfile(fd, src, mode);
4097769Ssam 			break;
4107769Ssam 		}
41126095Sminshall 		cp = tail(src);         /* new .. jdg */
41226095Sminshall 		fd = creat(cp, 0644);
4137769Ssam 		if (fd < 0) {
41426095Sminshall 			fprintf(stderr, "tftp: "); perror(cp);
4157769Ssam 			continue;
4167769Ssam 		}
41726095Sminshall 		if (verbose)
41826095Sminshall 			printf("getting from %s:%s to %s [%s]\n",
41926095Sminshall 				hostname, src, cp, mode);
42026095Sminshall 		sin.sin_port = port;
42126095Sminshall 		recvfile(fd, src, mode);
4227769Ssam 	}
4237769Ssam }
4247769Ssam 
4257769Ssam getusage(s)
42626110Sminshall char * s;
4277769Ssam {
4287769Ssam 	printf("usage: %s host:file host:file ... file, or\n", s);
4297769Ssam 	printf("       %s file file ... file if connected\n", s);
4307769Ssam }
4317769Ssam 
43213017Ssam int	rexmtval = TIMEOUT;
43313017Ssam 
43413017Ssam setrexmt(argc, argv)
43513017Ssam 	char *argv[];
43613017Ssam {
43713017Ssam 	int t;
43813017Ssam 
43913017Ssam 	if (argc < 2) {
44013017Ssam 		strcpy(line, "Rexmt-timeout ");
44113017Ssam 		printf("(value) ");
44213017Ssam 		gets(&line[strlen(line)]);
44313017Ssam 		makeargv();
44413017Ssam 		argc = margc;
44513017Ssam 		argv = margv;
44613017Ssam 	}
44713017Ssam 	if (argc != 2) {
44813017Ssam 		printf("usage: %s value\n", argv[0]);
44913017Ssam 		return;
45013017Ssam 	}
45113017Ssam 	t = atoi(argv[1]);
45213017Ssam 	if (t < 0)
45313017Ssam 		printf("%s: bad value\n", t);
45413017Ssam 	else
45513017Ssam 		rexmtval = t;
45613017Ssam }
45713017Ssam 
45813017Ssam int	maxtimeout = 5 * TIMEOUT;
45913017Ssam 
46013017Ssam settimeout(argc, argv)
46113017Ssam 	char *argv[];
46213017Ssam {
46313017Ssam 	int t;
46413017Ssam 
46513017Ssam 	if (argc < 2) {
46613017Ssam 		strcpy(line, "Maximum-timeout ");
46713017Ssam 		printf("(value) ");
46813017Ssam 		gets(&line[strlen(line)]);
46913017Ssam 		makeargv();
47013017Ssam 		argc = margc;
47113017Ssam 		argv = margv;
47213017Ssam 	}
47313017Ssam 	if (argc != 2) {
47413017Ssam 		printf("usage: %s value\n", argv[0]);
47513017Ssam 		return;
47613017Ssam 	}
47713017Ssam 	t = atoi(argv[1]);
47813017Ssam 	if (t < 0)
47913017Ssam 		printf("%s: bad value\n", t);
48013017Ssam 	else
48113017Ssam 		maxtimeout = t;
48213017Ssam }
48313017Ssam 
4847769Ssam status(argc, argv)
4857769Ssam 	char *argv[];
4867769Ssam {
4877769Ssam 	if (connected)
4888384Ssam 		printf("Connected to %s.\n", hostname);
4897769Ssam 	else
4907769Ssam 		printf("Not connected.\n");
49126095Sminshall 	printf("Mode: %s Verbose: %s Tracing: %s\n", mode,
49226095Sminshall 		verbose ? "on" : "off", trace ? "on" : "off");
49313017Ssam 	printf("Rexmt-interval: %d seconds, Max-timeout: %d seconds\n",
49413017Ssam 		rexmtval, maxtimeout);
4957769Ssam }
4967769Ssam 
4977769Ssam intr()
4987769Ssam {
49926095Sminshall 	signal(SIGALRM, SIG_IGN);
50016382Ssam 	alarm(0);
5017769Ssam 	longjmp(toplevel, -1);
5027769Ssam }
5037769Ssam 
5047769Ssam char *
5057769Ssam tail(filename)
5067769Ssam 	char *filename;
5077769Ssam {
5087769Ssam 	register char *s;
5097769Ssam 
5107769Ssam 	while (*filename) {
5117769Ssam 		s = rindex(filename, '/');
5127769Ssam 		if (s == NULL)
5137769Ssam 			break;
5147769Ssam 		if (s[1])
5157769Ssam 			return (s + 1);
5167769Ssam 		*s = '\0';
5177769Ssam 	}
5187769Ssam 	return (filename);
5197769Ssam }
5207769Ssam 
5217769Ssam /*
5227769Ssam  * Command parser.
5237769Ssam  */
5247769Ssam command(top)
5257769Ssam 	int top;
5267769Ssam {
5277769Ssam 	register struct cmd *c;
5287769Ssam 
5297769Ssam 	if (!top)
5307769Ssam 		putchar('\n');
5317769Ssam 	for (;;) {
5327769Ssam 		printf("%s> ", prompt);
53326103Sminshall 		if (gets(line) == 0) {
53426103Sminshall 			if (feof(stdin)) {
53526103Sminshall 				quit();
53626103Sminshall 			} else {
53726103Sminshall 				continue;
53826103Sminshall 			}
53926103Sminshall 		}
5407769Ssam 		if (line[0] == 0)
54113017Ssam 			continue;
5427769Ssam 		makeargv();
5437769Ssam 		c = getcmd(margv[0]);
5447769Ssam 		if (c == (struct cmd *)-1) {
5457769Ssam 			printf("?Ambiguous command\n");
5467769Ssam 			continue;
5477769Ssam 		}
5487769Ssam 		if (c == 0) {
5497769Ssam 			printf("?Invalid command\n");
5507769Ssam 			continue;
5517769Ssam 		}
5527769Ssam 		(*c->handler)(margc, margv);
5537769Ssam 	}
5547769Ssam }
5557769Ssam 
5567769Ssam struct cmd *
5577769Ssam getcmd(name)
5587769Ssam 	register char *name;
5597769Ssam {
5607769Ssam 	register char *p, *q;
5617769Ssam 	register struct cmd *c, *found;
5627769Ssam 	register int nmatches, longest;
5637769Ssam 
5647769Ssam 	longest = 0;
5657769Ssam 	nmatches = 0;
5667769Ssam 	found = 0;
5677769Ssam 	for (c = cmdtab; p = c->name; c++) {
5687769Ssam 		for (q = name; *q == *p++; q++)
5697769Ssam 			if (*q == 0)		/* exact match? */
5707769Ssam 				return (c);
5717769Ssam 		if (!*q) {			/* the name was a prefix */
5727769Ssam 			if (q - name > longest) {
5737769Ssam 				longest = q - name;
5747769Ssam 				nmatches = 1;
5757769Ssam 				found = c;
5767769Ssam 			} else if (q - name == longest)
5777769Ssam 				nmatches++;
5787769Ssam 		}
5797769Ssam 	}
5807769Ssam 	if (nmatches > 1)
5817769Ssam 		return ((struct cmd *)-1);
5827769Ssam 	return (found);
5837769Ssam }
5847769Ssam 
5857769Ssam /*
5867769Ssam  * Slice a string up into argc/argv.
5877769Ssam  */
5887769Ssam makeargv()
5897769Ssam {
5907769Ssam 	register char *cp;
5917769Ssam 	register char **argp = margv;
5927769Ssam 
5937769Ssam 	margc = 0;
5947769Ssam 	for (cp = line; *cp;) {
5957769Ssam 		while (isspace(*cp))
5967769Ssam 			cp++;
5977769Ssam 		if (*cp == '\0')
5987769Ssam 			break;
5997769Ssam 		*argp++ = cp;
6007769Ssam 		margc += 1;
6017769Ssam 		while (*cp != '\0' && !isspace(*cp))
6027769Ssam 			cp++;
6037769Ssam 		if (*cp == '\0')
6047769Ssam 			break;
6057769Ssam 		*cp++ = '\0';
6067769Ssam 	}
6077769Ssam 	*argp++ = 0;
6087769Ssam }
6097769Ssam 
6107769Ssam /*VARARGS*/
6117769Ssam quit()
6127769Ssam {
6137769Ssam 	exit(0);
6147769Ssam }
6157769Ssam 
6167769Ssam /*
6177769Ssam  * Help command.
6187769Ssam  */
6197769Ssam help(argc, argv)
6207769Ssam 	int argc;
6217769Ssam 	char *argv[];
6227769Ssam {
6237769Ssam 	register struct cmd *c;
6247769Ssam 
6257769Ssam 	if (argc == 1) {
6267769Ssam 		printf("Commands may be abbreviated.  Commands are:\n\n");
6277769Ssam 		for (c = cmdtab; c->name; c++)
6287769Ssam 			printf("%-*s\t%s\n", HELPINDENT, c->name, c->help);
6297769Ssam 		return;
6307769Ssam 	}
6317769Ssam 	while (--argc > 0) {
6327769Ssam 		register char *arg;
6337769Ssam 		arg = *++argv;
6347769Ssam 		c = getcmd(arg);
6357769Ssam 		if (c == (struct cmd *)-1)
6367769Ssam 			printf("?Ambiguous help command %s\n", arg);
6377769Ssam 		else if (c == (struct cmd *)0)
6387769Ssam 			printf("?Invalid help command %s\n", arg);
6397769Ssam 		else
6407769Ssam 			printf("%s\n", c->help);
6417769Ssam 	}
6427769Ssam }
6437769Ssam 
6447769Ssam /*VARARGS*/
6457769Ssam settrace()
6467769Ssam {
6477769Ssam 	trace = !trace;
6487769Ssam 	printf("Packet tracing %s.\n", trace ? "on" : "off");
6497769Ssam }
65026095Sminshall 
65126095Sminshall /*VARARGS*/
65226095Sminshall setverbose()
65326095Sminshall {
65426095Sminshall 	verbose = !verbose;
65526095Sminshall 	printf("Verbose mode %s.\n", verbose ? "on" : "off");
65626095Sminshall }
657