xref: /csrg-svn/usr.bin/tftp/main.c (revision 26095)
122403Sdist /*
2*26095Sminshall  * Copyright (c) 1985 Regents of the University of California.
322403Sdist  * All rights reserved.  The Berkeley software License Agreement
422403Sdist  * specifies the terms and conditions for redistribution.
522403Sdist  */
622403Sdist 
714553Ssam #ifndef lint
822403Sdist char copyright[] =
922403Sdist "@(#) Copyright (c) 1983 Regents of the University of California.\n\
1022403Sdist  All rights reserved.\n";
1122403Sdist #endif not lint
127769Ssam 
1322403Sdist #ifndef lint
14*26095Sminshall static char sccsid[] = "@(#)main.c	5.3 (Berkeley) 02/06/86";
1522403Sdist #endif not lint
1622403Sdist 
17*26095Sminshall /* Many bug fixes are from Jim Guyton <guyton@rand-unix> */
18*26095Sminshall 
197769Ssam /*
207769Ssam  * TFTP User Program -- Command Interface.
217769Ssam  */
227769Ssam #include <sys/types.h>
237769Ssam #include <sys/socket.h>
2413017Ssam #include <sys/file.h>
259219Ssam 
269219Ssam #include <netinet/in.h>
279219Ssam 
287769Ssam #include <signal.h>
297769Ssam #include <stdio.h>
307769Ssam #include <errno.h>
317769Ssam #include <setjmp.h>
327769Ssam #include <ctype.h>
338384Ssam #include <netdb.h>
347769Ssam 
3513017Ssam #define	TIMEOUT		5		/* secs between rexmt's */
3613017Ssam 
37*26095Sminshall struct	sockaddr_in sin;
387769Ssam int	f;
39*26095Sminshall short   port;
407769Ssam int	trace;
41*26095Sminshall int	verbose;
427769Ssam int	connected;
437769Ssam char	mode[32];
447769Ssam char	line[200];
457769Ssam int	margc;
467769Ssam char	*margv[20];
477769Ssam char	*prompt = "tftp";
487769Ssam jmp_buf	toplevel;
497769Ssam int	intr();
508384Ssam struct	servent *sp;
517769Ssam 
52*26095Sminshall int	quit(), help(), setverbose(), settrace(), status();
53*26095Sminshall int     get(), put(), setpeer(), modecmd(), setrexmt(), settimeout();
54*26095Sminshall int     setbinary(), setascii();
557769Ssam 
567769Ssam #define HELPINDENT (sizeof("connect"))
577769Ssam 
587769Ssam struct cmd {
597769Ssam 	char	*name;
607769Ssam 	char	*help;
617769Ssam 	int	(*handler)();
627769Ssam };
637769Ssam 
64*26095Sminshall char	vhelp[] = "toggle verbose mode";
657769Ssam char	thelp[] = "toggle packet tracing";
667769Ssam char	chelp[] = "connect to remote tftp";
677769Ssam char	qhelp[] = "exit tftp";
687769Ssam char	hhelp[] = "print help information";
697769Ssam char	shelp[] = "send file";
707769Ssam char	rhelp[] = "receive file";
717769Ssam char	mhelp[] = "set file transfer mode";
727769Ssam char	sthelp[] = "show current status";
7313017Ssam char	xhelp[] = "set per-packet retransmission timeout";
7413017Ssam char	ihelp[] = "set total retransmission timeout";
75*26095Sminshall char    ashelp[] = "set mode to netascii";
76*26095Sminshall char    bnhelp[] = "set mode to octet";
777769Ssam 
787769Ssam struct cmd cmdtab[] = {
797769Ssam 	{ "connect",	chelp,		setpeer },
80*26095Sminshall 	{ "mode",       mhelp,          modecmd },
817769Ssam 	{ "put",	shelp,		put },
827769Ssam 	{ "get",	rhelp,		get },
837769Ssam 	{ "quit",	qhelp,		quit },
84*26095Sminshall 	{ "verbose",	vhelp,		setverbose },
857769Ssam 	{ "trace",	thelp,		settrace },
867769Ssam 	{ "status",	sthelp,		status },
87*26095Sminshall 	{ "binary",     bnhelp,         setbinary },
88*26095Sminshall 	{ "ascii",      ashelp,         setascii },
8913017Ssam 	{ "rexmt",	xhelp,		setrexmt },
9013017Ssam 	{ "timeout",	ihelp,		settimeout },
917769Ssam 	{ "?",		hhelp,		help },
927769Ssam 	0
937769Ssam };
947769Ssam 
957769Ssam struct	cmd *getcmd();
967769Ssam char	*tail();
977769Ssam char	*index();
987769Ssam char	*rindex();
997769Ssam 
1007769Ssam main(argc, argv)
1017769Ssam 	char *argv[];
1027769Ssam {
103*26095Sminshall 	struct sockaddr_in sin;
10413017Ssam 	int top;
10513017Ssam 
1068384Ssam 	sp = getservbyname("tftp", "udp");
1078384Ssam 	if (sp == 0) {
1088384Ssam 		fprintf(stderr, "tftp: udp/tftp: unknown service\n");
1098384Ssam 		exit(1);
1108384Ssam 	}
1119262Ssam 	f = socket(AF_INET, SOCK_DGRAM, 0, 0);
1127769Ssam 	if (f < 0) {
11313017Ssam 		perror("tftp: socket");
1147769Ssam 		exit(3);
1157769Ssam 	}
116*26095Sminshall 	bzero((char *)&sin, sizeof (sin));
117*26095Sminshall 	sin.sin_family = AF_INET;
11813017Ssam 	if (bind(f, &sin, sizeof (sin)) < 0) {
11913017Ssam 		perror("tftp: bind");
12013017Ssam 		exit(1);
12113017Ssam 	}
122*26095Sminshall 	strcpy(mode, "netascii");
12313017Ssam 	signal(SIGINT, intr);
1247769Ssam 	if (argc > 1) {
1257769Ssam 		if (setjmp(toplevel) != 0)
1267769Ssam 			exit(0);
1277769Ssam 		setpeer(argc, argv);
1287769Ssam 	}
12913017Ssam 	top = setjmp(toplevel) == 0;
1307769Ssam 	for (;;)
13113017Ssam 		command(top);
1327769Ssam }
1337769Ssam 
134*26095Sminshall char    hostname[100];
1357769Ssam 
1367769Ssam setpeer(argc, argv)
1377769Ssam 	int argc;
1387769Ssam 	char *argv[];
1397769Ssam {
1408384Ssam 	struct hostent *host;
1417769Ssam 
1427769Ssam 	if (argc < 2) {
1437769Ssam 		strcpy(line, "Connect ");
1447769Ssam 		printf("(to) ");
1457769Ssam 		gets(&line[strlen(line)]);
1467769Ssam 		makeargv();
1477769Ssam 		argc = margc;
1487769Ssam 		argv = margv;
1497769Ssam 	}
1507769Ssam 	if (argc > 3) {
1517769Ssam 		printf("usage: %s host-name [port]\n", argv[0]);
1527769Ssam 		return;
1537769Ssam 	}
1548384Ssam 	host = gethostbyname(argv[1]);
1558384Ssam 	if (host) {
1569219Ssam 		sin.sin_family = host->h_addrtype;
1578384Ssam 		bcopy(host->h_addr, &sin.sin_addr, host->h_length);
158*26095Sminshall 		strcpy(hostname, host->h_name);
1598384Ssam 	} else {
1609219Ssam 		sin.sin_family = AF_INET;
1618384Ssam 		sin.sin_addr.s_addr = inet_addr(argv[1]);
1628384Ssam 		if (sin.sin_addr.s_addr == -1) {
1638384Ssam 			connected = 0;
1648384Ssam 			printf("%s: unknown host\n", argv[1]);
1658384Ssam 			return;
1668384Ssam 		}
167*26095Sminshall 		strcpy(hostname, argv[1]);
1687769Ssam 	}
169*26095Sminshall 	port = sp->s_port;
1707769Ssam 	if (argc == 3) {
171*26095Sminshall 		port = atoi(argv[2]);
172*26095Sminshall 		if (port < 0) {
1737769Ssam 			printf("%s: bad port number\n", argv[2]);
1747769Ssam 			connected = 0;
1757769Ssam 			return;
1767769Ssam 		}
177*26095Sminshall 		port = htons(port);
1788384Ssam 	}
1797769Ssam 	connected = 1;
1807769Ssam }
1817769Ssam 
1827769Ssam struct	modes {
1837769Ssam 	char *m_name;
1847769Ssam 	char *m_mode;
1857769Ssam } modes[] = {
186*26095Sminshall 	{ "ascii",	"netascii" },
187*26095Sminshall 	{ "netascii",   "netascii" },
188*26095Sminshall 	{ "binary",     "octet" },
189*26095Sminshall 	{ "image",      "octet" },
190*26095Sminshall 	{ "octect",     "octet" },
191*26095Sminshall /*      { "mail",       "mail" },       */
1927769Ssam 	{ 0,		0 }
1937769Ssam };
1947769Ssam 
195*26095Sminshall modecmd(argc, argv)
1967769Ssam 	char *argv[];
1977769Ssam {
1987769Ssam 	register struct modes *p;
199*26095Sminshall 	char *sep;
2007769Ssam 
2017769Ssam 	if (argc < 2) {
2027769Ssam 		printf("Using %s mode to transfer files.\n", mode);
2037769Ssam 		return;
2047769Ssam 	}
205*26095Sminshall 	if (argc == 2) {
206*26095Sminshall 		for (p = modes; p->m_name; p++)
207*26095Sminshall 			if (strcmp(argv[1], p->m_name) == 0)
208*26095Sminshall 				break;
209*26095Sminshall 		if (p->m_name) {
210*26095Sminshall 			setmode(p->m_mode);
211*26095Sminshall 			return;
212*26095Sminshall 		}
2137769Ssam 		printf("%s: unknown mode\n", argv[1]);
214*26095Sminshall 		/* drop through and print usage message */
215*26095Sminshall 	}
216*26095Sminshall 
217*26095Sminshall 	printf("usage: %s [", argv[0]);
218*26095Sminshall 	sep = " ";
219*26095Sminshall 	for (p = modes; p->m_name; p++) {
220*26095Sminshall 		printf("%s%s", sep, p->m_name);
221*26095Sminshall 		if (*sep == ' ')
222*26095Sminshall 			sep = " | ";
223*26095Sminshall 	}
224*26095Sminshall 	printf(" ]\n");
225*26095Sminshall 	return;
2267769Ssam }
2277769Ssam 
228*26095Sminshall setbinary(argc, argv)
229*26095Sminshall char *argv[];
230*26095Sminshall {       setmode("octet");
231*26095Sminshall }
232*26095Sminshall 
233*26095Sminshall setascii(argc, argv)
234*26095Sminshall char *argv[];
235*26095Sminshall {       setmode("netascii");
236*26095Sminshall }
237*26095Sminshall 
238*26095Sminshall setmode(newmode)
239*26095Sminshall char *newmode;
240*26095Sminshall {
241*26095Sminshall 	strcpy(mode, newmode);
242*26095Sminshall 	if (verbose)
243*26095Sminshall 		printf("mode set to %s\n", mode);
244*26095Sminshall }
245*26095Sminshall 
246*26095Sminshall 
2477769Ssam /*
2487769Ssam  * Send file(s).
2497769Ssam  */
2507769Ssam put(argc, argv)
2517769Ssam 	char *argv[];
2527769Ssam {
2537769Ssam 	int fd;
254*26095Sminshall 	register int n;
2557769Ssam 	register char *cp, *targ;
2567769Ssam 
2577769Ssam 	if (argc < 2) {
2587769Ssam 		strcpy(line, "send ");
2597769Ssam 		printf("(file) ");
2607769Ssam 		gets(&line[strlen(line)]);
2617769Ssam 		makeargv();
2627769Ssam 		argc = margc;
2637769Ssam 		argv = margv;
2647769Ssam 	}
2657769Ssam 	if (argc < 2) {
2667769Ssam 		putusage(argv[0]);
2677769Ssam 		return;
2687769Ssam 	}
2697769Ssam 	targ = argv[argc - 1];
2707769Ssam 	if (index(argv[argc - 1], ':')) {
2718384Ssam 		char *cp;
2728384Ssam 		struct hostent *hp;
2737769Ssam 
2747769Ssam 		for (n = 1; n < argc - 1; n++)
2757769Ssam 			if (index(argv[n], ':')) {
2767769Ssam 				putusage(argv[0]);
2777769Ssam 				return;
2787769Ssam 			}
2798384Ssam 		cp = argv[argc - 1];
2808384Ssam 		targ = index(cp, ':');
2817769Ssam 		*targ++ = 0;
2828384Ssam 		hp = gethostbyname(cp);
2838384Ssam 		if (hp == 0) {
2848384Ssam 			printf("%s: Unknown host.\n", cp);
2857769Ssam 			return;
2867769Ssam 		}
2879219Ssam 		bcopy(hp->h_addr, (caddr_t)&sin.sin_addr, hp->h_length);
2888384Ssam 		sin.sin_family = hp->h_addrtype;
2897769Ssam 		connected = 1;
290*26095Sminshall 		strcpy(hostname, hp->h_name);
2917769Ssam 	}
2927769Ssam 	if (!connected) {
2937769Ssam 		printf("No target machine specified.\n");
2947769Ssam 		return;
2957769Ssam 	}
2967769Ssam 	if (argc < 4) {
2977769Ssam 		cp = argc == 2 ? tail(targ) : argv[1];
29813017Ssam 		fd = open(cp, O_RDONLY);
2997769Ssam 		if (fd < 0) {
30013017Ssam 			fprintf(stderr, "tftp: "); perror(cp);
3017769Ssam 			return;
3027769Ssam 		}
303*26095Sminshall 		if (verbose)
304*26095Sminshall 			printf("putting %s to %s:%s [%s]\n",
305*26095Sminshall 				cp, hostname, targ, mode);
306*26095Sminshall 		sin.sin_port = port;
307*26095Sminshall 		sendfile(fd, targ, mode);
3087769Ssam 		return;
3097769Ssam 	}
310*26095Sminshall 				/* this assumes the target is a directory */
311*26095Sminshall 				/* on a remote unix system.  hmmmm.  */
3127769Ssam 	cp = index(targ, '\0');
3137769Ssam 	*cp++ = '/';
3147769Ssam 	for (n = 1; n < argc - 1; n++) {
3157769Ssam 		strcpy(cp, tail(argv[n]));
31613017Ssam 		fd = open(argv[n], O_RDONLY);
3177769Ssam 		if (fd < 0) {
31813017Ssam 			fprintf(stderr, "tftp: "); perror(argv[n]);
3197769Ssam 			continue;
3207769Ssam 		}
321*26095Sminshall 		if (verbose)
322*26095Sminshall 			printf("putting %s to %s:%s [%s]\n",
323*26095Sminshall 				argv[n], hostname, targ, mode);
324*26095Sminshall 		sin.sin_port = port;
325*26095Sminshall 		sendfile(fd, targ, mode);
3267769Ssam 	}
3277769Ssam }
3287769Ssam 
3297769Ssam putusage(s)
3307769Ssam 	char *s;
3317769Ssam {
3327769Ssam 	printf("usage: %s file ... host:target, or\n", s);
3337769Ssam 	printf("       %s file ... target (when already connected)\n", s);
3347769Ssam }
3357769Ssam 
3367769Ssam /*
3377769Ssam  * Receive file(s).
3387769Ssam  */
3397769Ssam get(argc, argv)
3407769Ssam 	char *argv[];
3417769Ssam {
3427769Ssam 	int fd;
343*26095Sminshall 	register int n;
3447769Ssam 	register char *cp;
3457769Ssam 	char *src;
3467769Ssam 
3477769Ssam 	if (argc < 2) {
3487769Ssam 		strcpy(line, "get ");
3497769Ssam 		printf("(files) ");
3507769Ssam 		gets(&line[strlen(line)]);
3517769Ssam 		makeargv();
3527769Ssam 		argc = margc;
3537769Ssam 		argv = margv;
3547769Ssam 	}
3557769Ssam 	if (argc < 2) {
3567769Ssam 		getusage(argv[0]);
3577769Ssam 		return;
3587769Ssam 	}
359*26095Sminshall 	if (!connected) {
360*26095Sminshall 		for (n = 1; n < argc ; n++)
3617769Ssam 			if (index(argv[n], ':') == 0) {
3627769Ssam 				getusage(argv[0]);
3637769Ssam 				return;
3647769Ssam 			}
365*26095Sminshall 	}
366*26095Sminshall 	for (n = 1; n < argc ; n++) {
3677769Ssam 		src = index(argv[n], ':');
3687769Ssam 		if (src == NULL)
3697769Ssam 			src = argv[n];
3707769Ssam 		else {
3718384Ssam 			struct hostent *hp;
3728384Ssam 
3737769Ssam 			*src++ = 0;
3748384Ssam 			hp = gethostbyname(argv[n]);
3758384Ssam 			if (hp == 0) {
3767769Ssam 				printf("%s: Unknown host.\n", argv[n]);
3777769Ssam 				continue;
3787769Ssam 			}
3799219Ssam 			bcopy(hp->h_addr, (caddr_t)&sin.sin_addr, hp->h_length);
3808384Ssam 			sin.sin_family = hp->h_addrtype;
3817769Ssam 			connected = 1;
382*26095Sminshall 			strcpy(hostname, hp->h_name);
3837769Ssam 		}
3847769Ssam 		if (argc < 4) {
3857769Ssam 			cp = argc == 3 ? argv[2] : tail(src);
3867769Ssam 			fd = creat(cp, 0644);
3877769Ssam 			if (fd < 0) {
38813017Ssam 				fprintf(stderr, "tftp: "); perror(cp);
3897769Ssam 				return;
3907769Ssam 			}
391*26095Sminshall 			if (verbose)
392*26095Sminshall 				printf("getting from %s:%s to %s [%s]\n",
393*26095Sminshall 					hostname, src, cp, mode);
394*26095Sminshall 			sin.sin_port = port;
395*26095Sminshall 			recvfile(fd, src, mode);
3967769Ssam 			break;
3977769Ssam 		}
398*26095Sminshall 		cp = tail(src);         /* new .. jdg */
399*26095Sminshall 		fd = creat(cp, 0644);
4007769Ssam 		if (fd < 0) {
401*26095Sminshall 			fprintf(stderr, "tftp: "); perror(cp);
4027769Ssam 			continue;
4037769Ssam 		}
404*26095Sminshall 		if (verbose)
405*26095Sminshall 			printf("getting from %s:%s to %s [%s]\n",
406*26095Sminshall 				hostname, src, cp, mode);
407*26095Sminshall 		sin.sin_port = port;
408*26095Sminshall 		recvfile(fd, src, mode);
4097769Ssam 	}
4107769Ssam }
4117769Ssam 
4127769Ssam getusage(s)
4137769Ssam {
4147769Ssam 	printf("usage: %s host:file host:file ... file, or\n", s);
4157769Ssam 	printf("       %s file file ... file if connected\n", s);
4167769Ssam }
4177769Ssam 
41813017Ssam int	rexmtval = TIMEOUT;
41913017Ssam 
42013017Ssam setrexmt(argc, argv)
42113017Ssam 	char *argv[];
42213017Ssam {
42313017Ssam 	int t;
42413017Ssam 
42513017Ssam 	if (argc < 2) {
42613017Ssam 		strcpy(line, "Rexmt-timeout ");
42713017Ssam 		printf("(value) ");
42813017Ssam 		gets(&line[strlen(line)]);
42913017Ssam 		makeargv();
43013017Ssam 		argc = margc;
43113017Ssam 		argv = margv;
43213017Ssam 	}
43313017Ssam 	if (argc != 2) {
43413017Ssam 		printf("usage: %s value\n", argv[0]);
43513017Ssam 		return;
43613017Ssam 	}
43713017Ssam 	t = atoi(argv[1]);
43813017Ssam 	if (t < 0)
43913017Ssam 		printf("%s: bad value\n", t);
44013017Ssam 	else
44113017Ssam 		rexmtval = t;
44213017Ssam }
44313017Ssam 
44413017Ssam int	maxtimeout = 5 * TIMEOUT;
44513017Ssam 
44613017Ssam settimeout(argc, argv)
44713017Ssam 	char *argv[];
44813017Ssam {
44913017Ssam 	int t;
45013017Ssam 
45113017Ssam 	if (argc < 2) {
45213017Ssam 		strcpy(line, "Maximum-timeout ");
45313017Ssam 		printf("(value) ");
45413017Ssam 		gets(&line[strlen(line)]);
45513017Ssam 		makeargv();
45613017Ssam 		argc = margc;
45713017Ssam 		argv = margv;
45813017Ssam 	}
45913017Ssam 	if (argc != 2) {
46013017Ssam 		printf("usage: %s value\n", argv[0]);
46113017Ssam 		return;
46213017Ssam 	}
46313017Ssam 	t = atoi(argv[1]);
46413017Ssam 	if (t < 0)
46513017Ssam 		printf("%s: bad value\n", t);
46613017Ssam 	else
46713017Ssam 		maxtimeout = t;
46813017Ssam }
46913017Ssam 
4707769Ssam status(argc, argv)
4717769Ssam 	char *argv[];
4727769Ssam {
4737769Ssam 	if (connected)
4748384Ssam 		printf("Connected to %s.\n", hostname);
4757769Ssam 	else
4767769Ssam 		printf("Not connected.\n");
477*26095Sminshall 	printf("Mode: %s Verbose: %s Tracing: %s\n", mode,
478*26095Sminshall 		verbose ? "on" : "off", trace ? "on" : "off");
47913017Ssam 	printf("Rexmt-interval: %d seconds, Max-timeout: %d seconds\n",
48013017Ssam 		rexmtval, maxtimeout);
4817769Ssam }
4827769Ssam 
4837769Ssam intr()
4847769Ssam {
485*26095Sminshall 	signal(SIGALRM, SIG_IGN);
48616382Ssam 	alarm(0);
4877769Ssam 	longjmp(toplevel, -1);
4887769Ssam }
4897769Ssam 
4907769Ssam char *
4917769Ssam tail(filename)
4927769Ssam 	char *filename;
4937769Ssam {
4947769Ssam 	register char *s;
4957769Ssam 
4967769Ssam 	while (*filename) {
4977769Ssam 		s = rindex(filename, '/');
4987769Ssam 		if (s == NULL)
4997769Ssam 			break;
5007769Ssam 		if (s[1])
5017769Ssam 			return (s + 1);
5027769Ssam 		*s = '\0';
5037769Ssam 	}
5047769Ssam 	return (filename);
5057769Ssam }
5067769Ssam 
5077769Ssam /*
5087769Ssam  * Command parser.
5097769Ssam  */
5107769Ssam command(top)
5117769Ssam 	int top;
5127769Ssam {
5137769Ssam 	register struct cmd *c;
5147769Ssam 
5157769Ssam 	if (!top)
5167769Ssam 		putchar('\n');
5177769Ssam 	for (;;) {
5187769Ssam 		printf("%s> ", prompt);
519*26095Sminshall 		if (gets(line) == 0)
520*26095Sminshall 			continue;
5217769Ssam 		if (line[0] == 0)
52213017Ssam 			continue;
5237769Ssam 		makeargv();
5247769Ssam 		c = getcmd(margv[0]);
5257769Ssam 		if (c == (struct cmd *)-1) {
5267769Ssam 			printf("?Ambiguous command\n");
5277769Ssam 			continue;
5287769Ssam 		}
5297769Ssam 		if (c == 0) {
5307769Ssam 			printf("?Invalid command\n");
5317769Ssam 			continue;
5327769Ssam 		}
5337769Ssam 		(*c->handler)(margc, margv);
5347769Ssam 	}
5357769Ssam }
5367769Ssam 
5377769Ssam struct cmd *
5387769Ssam getcmd(name)
5397769Ssam 	register char *name;
5407769Ssam {
5417769Ssam 	register char *p, *q;
5427769Ssam 	register struct cmd *c, *found;
5437769Ssam 	register int nmatches, longest;
5447769Ssam 
5457769Ssam 	longest = 0;
5467769Ssam 	nmatches = 0;
5477769Ssam 	found = 0;
5487769Ssam 	for (c = cmdtab; p = c->name; c++) {
5497769Ssam 		for (q = name; *q == *p++; q++)
5507769Ssam 			if (*q == 0)		/* exact match? */
5517769Ssam 				return (c);
5527769Ssam 		if (!*q) {			/* the name was a prefix */
5537769Ssam 			if (q - name > longest) {
5547769Ssam 				longest = q - name;
5557769Ssam 				nmatches = 1;
5567769Ssam 				found = c;
5577769Ssam 			} else if (q - name == longest)
5587769Ssam 				nmatches++;
5597769Ssam 		}
5607769Ssam 	}
5617769Ssam 	if (nmatches > 1)
5627769Ssam 		return ((struct cmd *)-1);
5637769Ssam 	return (found);
5647769Ssam }
5657769Ssam 
5667769Ssam /*
5677769Ssam  * Slice a string up into argc/argv.
5687769Ssam  */
5697769Ssam makeargv()
5707769Ssam {
5717769Ssam 	register char *cp;
5727769Ssam 	register char **argp = margv;
5737769Ssam 
5747769Ssam 	margc = 0;
5757769Ssam 	for (cp = line; *cp;) {
5767769Ssam 		while (isspace(*cp))
5777769Ssam 			cp++;
5787769Ssam 		if (*cp == '\0')
5797769Ssam 			break;
5807769Ssam 		*argp++ = cp;
5817769Ssam 		margc += 1;
5827769Ssam 		while (*cp != '\0' && !isspace(*cp))
5837769Ssam 			cp++;
5847769Ssam 		if (*cp == '\0')
5857769Ssam 			break;
5867769Ssam 		*cp++ = '\0';
5877769Ssam 	}
5887769Ssam 	*argp++ = 0;
5897769Ssam }
5907769Ssam 
5917769Ssam /*VARARGS*/
5927769Ssam quit()
5937769Ssam {
5947769Ssam 	exit(0);
5957769Ssam }
5967769Ssam 
5977769Ssam /*
5987769Ssam  * Help command.
5997769Ssam  */
6007769Ssam help(argc, argv)
6017769Ssam 	int argc;
6027769Ssam 	char *argv[];
6037769Ssam {
6047769Ssam 	register struct cmd *c;
6057769Ssam 
6067769Ssam 	if (argc == 1) {
6077769Ssam 		printf("Commands may be abbreviated.  Commands are:\n\n");
6087769Ssam 		for (c = cmdtab; c->name; c++)
6097769Ssam 			printf("%-*s\t%s\n", HELPINDENT, c->name, c->help);
6107769Ssam 		return;
6117769Ssam 	}
6127769Ssam 	while (--argc > 0) {
6137769Ssam 		register char *arg;
6147769Ssam 		arg = *++argv;
6157769Ssam 		c = getcmd(arg);
6167769Ssam 		if (c == (struct cmd *)-1)
6177769Ssam 			printf("?Ambiguous help command %s\n", arg);
6187769Ssam 		else if (c == (struct cmd *)0)
6197769Ssam 			printf("?Invalid help command %s\n", arg);
6207769Ssam 		else
6217769Ssam 			printf("%s\n", c->help);
6227769Ssam 	}
6237769Ssam }
6247769Ssam 
6257769Ssam /*VARARGS*/
6267769Ssam settrace()
6277769Ssam {
6287769Ssam 	trace = !trace;
6297769Ssam 	printf("Packet tracing %s.\n", trace ? "on" : "off");
6307769Ssam }
631*26095Sminshall 
632*26095Sminshall /*VARARGS*/
633*26095Sminshall setverbose()
634*26095Sminshall {
635*26095Sminshall 	verbose = !verbose;
636*26095Sminshall 	printf("Verbose mode %s.\n", verbose ? "on" : "off");
637*26095Sminshall }
638