xref: /csrg-svn/usr.bin/tftp/main.c (revision 26110)
122403Sdist /*
226095Sminshall  * 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*26110Sminshall static char sccsid[] = "@(#)main.c	5.5 (Berkeley) 02/07/86";
1522403Sdist #endif not lint
1622403Sdist 
1726095Sminshall /* Many bug fixes are from Jim Guyton <guyton@rand-unix> */
1826095Sminshall 
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 
3726095Sminshall struct	sockaddr_in sin;
387769Ssam int	f;
3926095Sminshall short   port;
407769Ssam int	trace;
4126095Sminshall 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 
5226095Sminshall int	quit(), help(), setverbose(), settrace(), status();
5326095Sminshall int     get(), put(), setpeer(), modecmd(), setrexmt(), settimeout();
5426095Sminshall int     setbinary(), setascii();
557769Ssam 
567769Ssam #define HELPINDENT (sizeof("connect"))
577769Ssam 
587769Ssam struct cmd {
597769Ssam 	char	*name;
607769Ssam 	char	*help;
617769Ssam 	int	(*handler)();
627769Ssam };
637769Ssam 
6426095Sminshall 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";
7526095Sminshall char    ashelp[] = "set mode to netascii";
7626095Sminshall char    bnhelp[] = "set mode to octet";
777769Ssam 
787769Ssam struct cmd cmdtab[] = {
797769Ssam 	{ "connect",	chelp,		setpeer },
8026095Sminshall 	{ "mode",       mhelp,          modecmd },
817769Ssam 	{ "put",	shelp,		put },
827769Ssam 	{ "get",	rhelp,		get },
837769Ssam 	{ "quit",	qhelp,		quit },
8426095Sminshall 	{ "verbose",	vhelp,		setverbose },
857769Ssam 	{ "trace",	thelp,		settrace },
867769Ssam 	{ "status",	sthelp,		status },
8726095Sminshall 	{ "binary",     bnhelp,         setbinary },
8826095Sminshall 	{ "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 {
10326095Sminshall 	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 	}
111*26110Sminshall 	f = socket(AF_INET, SOCK_DGRAM, 0);
1127769Ssam 	if (f < 0) {
11313017Ssam 		perror("tftp: socket");
1147769Ssam 		exit(3);
1157769Ssam 	}
11626095Sminshall 	bzero((char *)&sin, sizeof (sin));
11726095Sminshall 	sin.sin_family = AF_INET;
11813017Ssam 	if (bind(f, &sin, sizeof (sin)) < 0) {
11913017Ssam 		perror("tftp: bind");
12013017Ssam 		exit(1);
12113017Ssam 	}
12226095Sminshall 	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 
13426095Sminshall 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);
15826095Sminshall 		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 		}
16726095Sminshall 		strcpy(hostname, argv[1]);
1687769Ssam 	}
16926095Sminshall 	port = sp->s_port;
1707769Ssam 	if (argc == 3) {
17126095Sminshall 		port = atoi(argv[2]);
17226095Sminshall 		if (port < 0) {
1737769Ssam 			printf("%s: bad port number\n", argv[2]);
1747769Ssam 			connected = 0;
1757769Ssam 			return;
1767769Ssam 		}
17726095Sminshall 		port = htons(port);
1788384Ssam 	}
1797769Ssam 	connected = 1;
1807769Ssam }
1817769Ssam 
1827769Ssam struct	modes {
1837769Ssam 	char *m_name;
1847769Ssam 	char *m_mode;
1857769Ssam } modes[] = {
18626095Sminshall 	{ "ascii",	"netascii" },
18726095Sminshall 	{ "netascii",   "netascii" },
18826095Sminshall 	{ "binary",     "octet" },
18926095Sminshall 	{ "image",      "octet" },
19026103Sminshall 	{ "octet",     "octet" },
19126095Sminshall /*      { "mail",       "mail" },       */
1927769Ssam 	{ 0,		0 }
1937769Ssam };
1947769Ssam 
19526095Sminshall modecmd(argc, argv)
1967769Ssam 	char *argv[];
1977769Ssam {
1987769Ssam 	register struct modes *p;
19926095Sminshall 	char *sep;
2007769Ssam 
2017769Ssam 	if (argc < 2) {
2027769Ssam 		printf("Using %s mode to transfer files.\n", mode);
2037769Ssam 		return;
2047769Ssam 	}
20526095Sminshall 	if (argc == 2) {
20626095Sminshall 		for (p = modes; p->m_name; p++)
20726095Sminshall 			if (strcmp(argv[1], p->m_name) == 0)
20826095Sminshall 				break;
20926095Sminshall 		if (p->m_name) {
21026095Sminshall 			setmode(p->m_mode);
21126095Sminshall 			return;
21226095Sminshall 		}
2137769Ssam 		printf("%s: unknown mode\n", argv[1]);
21426095Sminshall 		/* drop through and print usage message */
21526095Sminshall 	}
21626095Sminshall 
21726095Sminshall 	printf("usage: %s [", argv[0]);
21826095Sminshall 	sep = " ";
21926095Sminshall 	for (p = modes; p->m_name; p++) {
22026095Sminshall 		printf("%s%s", sep, p->m_name);
22126095Sminshall 		if (*sep == ' ')
22226095Sminshall 			sep = " | ";
22326095Sminshall 	}
22426095Sminshall 	printf(" ]\n");
22526095Sminshall 	return;
2267769Ssam }
2277769Ssam 
22826095Sminshall setbinary(argc, argv)
22926095Sminshall char *argv[];
23026095Sminshall {       setmode("octet");
23126095Sminshall }
23226095Sminshall 
23326095Sminshall setascii(argc, argv)
23426095Sminshall char *argv[];
23526095Sminshall {       setmode("netascii");
23626095Sminshall }
23726095Sminshall 
23826095Sminshall setmode(newmode)
23926095Sminshall char *newmode;
24026095Sminshall {
24126095Sminshall 	strcpy(mode, newmode);
24226095Sminshall 	if (verbose)
24326095Sminshall 		printf("mode set to %s\n", mode);
24426095Sminshall }
24526095Sminshall 
24626095Sminshall 
2477769Ssam /*
2487769Ssam  * Send file(s).
2497769Ssam  */
2507769Ssam put(argc, argv)
2517769Ssam 	char *argv[];
2527769Ssam {
2537769Ssam 	int fd;
25426095Sminshall 	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;
29026095Sminshall 		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 		}
30326095Sminshall 		if (verbose)
30426095Sminshall 			printf("putting %s to %s:%s [%s]\n",
30526095Sminshall 				cp, hostname, targ, mode);
30626095Sminshall 		sin.sin_port = port;
30726095Sminshall 		sendfile(fd, targ, mode);
3087769Ssam 		return;
3097769Ssam 	}
31026095Sminshall 				/* this assumes the target is a directory */
31126095Sminshall 				/* 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 		}
32126095Sminshall 		if (verbose)
32226095Sminshall 			printf("putting %s to %s:%s [%s]\n",
32326095Sminshall 				argv[n], hostname, targ, mode);
32426095Sminshall 		sin.sin_port = port;
32526095Sminshall 		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;
34326095Sminshall 	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 	}
35926095Sminshall 	if (!connected) {
36026095Sminshall 		for (n = 1; n < argc ; n++)
3617769Ssam 			if (index(argv[n], ':') == 0) {
3627769Ssam 				getusage(argv[0]);
3637769Ssam 				return;
3647769Ssam 			}
36526095Sminshall 	}
36626095Sminshall 	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;
38226095Sminshall 			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 			}
39126095Sminshall 			if (verbose)
39226095Sminshall 				printf("getting from %s:%s to %s [%s]\n",
39326095Sminshall 					hostname, src, cp, mode);
39426095Sminshall 			sin.sin_port = port;
39526095Sminshall 			recvfile(fd, src, mode);
3967769Ssam 			break;
3977769Ssam 		}
39826095Sminshall 		cp = tail(src);         /* new .. jdg */
39926095Sminshall 		fd = creat(cp, 0644);
4007769Ssam 		if (fd < 0) {
40126095Sminshall 			fprintf(stderr, "tftp: "); perror(cp);
4027769Ssam 			continue;
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 	}
4107769Ssam }
4117769Ssam 
4127769Ssam getusage(s)
413*26110Sminshall char * s;
4147769Ssam {
4157769Ssam 	printf("usage: %s host:file host:file ... file, or\n", s);
4167769Ssam 	printf("       %s file file ... file if connected\n", s);
4177769Ssam }
4187769Ssam 
41913017Ssam int	rexmtval = TIMEOUT;
42013017Ssam 
42113017Ssam setrexmt(argc, argv)
42213017Ssam 	char *argv[];
42313017Ssam {
42413017Ssam 	int t;
42513017Ssam 
42613017Ssam 	if (argc < 2) {
42713017Ssam 		strcpy(line, "Rexmt-timeout ");
42813017Ssam 		printf("(value) ");
42913017Ssam 		gets(&line[strlen(line)]);
43013017Ssam 		makeargv();
43113017Ssam 		argc = margc;
43213017Ssam 		argv = margv;
43313017Ssam 	}
43413017Ssam 	if (argc != 2) {
43513017Ssam 		printf("usage: %s value\n", argv[0]);
43613017Ssam 		return;
43713017Ssam 	}
43813017Ssam 	t = atoi(argv[1]);
43913017Ssam 	if (t < 0)
44013017Ssam 		printf("%s: bad value\n", t);
44113017Ssam 	else
44213017Ssam 		rexmtval = t;
44313017Ssam }
44413017Ssam 
44513017Ssam int	maxtimeout = 5 * TIMEOUT;
44613017Ssam 
44713017Ssam settimeout(argc, argv)
44813017Ssam 	char *argv[];
44913017Ssam {
45013017Ssam 	int t;
45113017Ssam 
45213017Ssam 	if (argc < 2) {
45313017Ssam 		strcpy(line, "Maximum-timeout ");
45413017Ssam 		printf("(value) ");
45513017Ssam 		gets(&line[strlen(line)]);
45613017Ssam 		makeargv();
45713017Ssam 		argc = margc;
45813017Ssam 		argv = margv;
45913017Ssam 	}
46013017Ssam 	if (argc != 2) {
46113017Ssam 		printf("usage: %s value\n", argv[0]);
46213017Ssam 		return;
46313017Ssam 	}
46413017Ssam 	t = atoi(argv[1]);
46513017Ssam 	if (t < 0)
46613017Ssam 		printf("%s: bad value\n", t);
46713017Ssam 	else
46813017Ssam 		maxtimeout = t;
46913017Ssam }
47013017Ssam 
4717769Ssam status(argc, argv)
4727769Ssam 	char *argv[];
4737769Ssam {
4747769Ssam 	if (connected)
4758384Ssam 		printf("Connected to %s.\n", hostname);
4767769Ssam 	else
4777769Ssam 		printf("Not connected.\n");
47826095Sminshall 	printf("Mode: %s Verbose: %s Tracing: %s\n", mode,
47926095Sminshall 		verbose ? "on" : "off", trace ? "on" : "off");
48013017Ssam 	printf("Rexmt-interval: %d seconds, Max-timeout: %d seconds\n",
48113017Ssam 		rexmtval, maxtimeout);
4827769Ssam }
4837769Ssam 
4847769Ssam intr()
4857769Ssam {
48626095Sminshall 	signal(SIGALRM, SIG_IGN);
48716382Ssam 	alarm(0);
4887769Ssam 	longjmp(toplevel, -1);
4897769Ssam }
4907769Ssam 
4917769Ssam char *
4927769Ssam tail(filename)
4937769Ssam 	char *filename;
4947769Ssam {
4957769Ssam 	register char *s;
4967769Ssam 
4977769Ssam 	while (*filename) {
4987769Ssam 		s = rindex(filename, '/');
4997769Ssam 		if (s == NULL)
5007769Ssam 			break;
5017769Ssam 		if (s[1])
5027769Ssam 			return (s + 1);
5037769Ssam 		*s = '\0';
5047769Ssam 	}
5057769Ssam 	return (filename);
5067769Ssam }
5077769Ssam 
5087769Ssam /*
5097769Ssam  * Command parser.
5107769Ssam  */
5117769Ssam command(top)
5127769Ssam 	int top;
5137769Ssam {
5147769Ssam 	register struct cmd *c;
5157769Ssam 
5167769Ssam 	if (!top)
5177769Ssam 		putchar('\n');
5187769Ssam 	for (;;) {
5197769Ssam 		printf("%s> ", prompt);
52026103Sminshall 		if (gets(line) == 0) {
52126103Sminshall 			if (feof(stdin)) {
52226103Sminshall 				quit();
52326103Sminshall 			} else {
52426103Sminshall 				continue;
52526103Sminshall 			}
52626103Sminshall 		}
5277769Ssam 		if (line[0] == 0)
52813017Ssam 			continue;
5297769Ssam 		makeargv();
5307769Ssam 		c = getcmd(margv[0]);
5317769Ssam 		if (c == (struct cmd *)-1) {
5327769Ssam 			printf("?Ambiguous command\n");
5337769Ssam 			continue;
5347769Ssam 		}
5357769Ssam 		if (c == 0) {
5367769Ssam 			printf("?Invalid command\n");
5377769Ssam 			continue;
5387769Ssam 		}
5397769Ssam 		(*c->handler)(margc, margv);
5407769Ssam 	}
5417769Ssam }
5427769Ssam 
5437769Ssam struct cmd *
5447769Ssam getcmd(name)
5457769Ssam 	register char *name;
5467769Ssam {
5477769Ssam 	register char *p, *q;
5487769Ssam 	register struct cmd *c, *found;
5497769Ssam 	register int nmatches, longest;
5507769Ssam 
5517769Ssam 	longest = 0;
5527769Ssam 	nmatches = 0;
5537769Ssam 	found = 0;
5547769Ssam 	for (c = cmdtab; p = c->name; c++) {
5557769Ssam 		for (q = name; *q == *p++; q++)
5567769Ssam 			if (*q == 0)		/* exact match? */
5577769Ssam 				return (c);
5587769Ssam 		if (!*q) {			/* the name was a prefix */
5597769Ssam 			if (q - name > longest) {
5607769Ssam 				longest = q - name;
5617769Ssam 				nmatches = 1;
5627769Ssam 				found = c;
5637769Ssam 			} else if (q - name == longest)
5647769Ssam 				nmatches++;
5657769Ssam 		}
5667769Ssam 	}
5677769Ssam 	if (nmatches > 1)
5687769Ssam 		return ((struct cmd *)-1);
5697769Ssam 	return (found);
5707769Ssam }
5717769Ssam 
5727769Ssam /*
5737769Ssam  * Slice a string up into argc/argv.
5747769Ssam  */
5757769Ssam makeargv()
5767769Ssam {
5777769Ssam 	register char *cp;
5787769Ssam 	register char **argp = margv;
5797769Ssam 
5807769Ssam 	margc = 0;
5817769Ssam 	for (cp = line; *cp;) {
5827769Ssam 		while (isspace(*cp))
5837769Ssam 			cp++;
5847769Ssam 		if (*cp == '\0')
5857769Ssam 			break;
5867769Ssam 		*argp++ = cp;
5877769Ssam 		margc += 1;
5887769Ssam 		while (*cp != '\0' && !isspace(*cp))
5897769Ssam 			cp++;
5907769Ssam 		if (*cp == '\0')
5917769Ssam 			break;
5927769Ssam 		*cp++ = '\0';
5937769Ssam 	}
5947769Ssam 	*argp++ = 0;
5957769Ssam }
5967769Ssam 
5977769Ssam /*VARARGS*/
5987769Ssam quit()
5997769Ssam {
6007769Ssam 	exit(0);
6017769Ssam }
6027769Ssam 
6037769Ssam /*
6047769Ssam  * Help command.
6057769Ssam  */
6067769Ssam help(argc, argv)
6077769Ssam 	int argc;
6087769Ssam 	char *argv[];
6097769Ssam {
6107769Ssam 	register struct cmd *c;
6117769Ssam 
6127769Ssam 	if (argc == 1) {
6137769Ssam 		printf("Commands may be abbreviated.  Commands are:\n\n");
6147769Ssam 		for (c = cmdtab; c->name; c++)
6157769Ssam 			printf("%-*s\t%s\n", HELPINDENT, c->name, c->help);
6167769Ssam 		return;
6177769Ssam 	}
6187769Ssam 	while (--argc > 0) {
6197769Ssam 		register char *arg;
6207769Ssam 		arg = *++argv;
6217769Ssam 		c = getcmd(arg);
6227769Ssam 		if (c == (struct cmd *)-1)
6237769Ssam 			printf("?Ambiguous help command %s\n", arg);
6247769Ssam 		else if (c == (struct cmd *)0)
6257769Ssam 			printf("?Invalid help command %s\n", arg);
6267769Ssam 		else
6277769Ssam 			printf("%s\n", c->help);
6287769Ssam 	}
6297769Ssam }
6307769Ssam 
6317769Ssam /*VARARGS*/
6327769Ssam settrace()
6337769Ssam {
6347769Ssam 	trace = !trace;
6357769Ssam 	printf("Packet tracing %s.\n", trace ? "on" : "off");
6367769Ssam }
63726095Sminshall 
63826095Sminshall /*VARARGS*/
63926095Sminshall setverbose()
64026095Sminshall {
64126095Sminshall 	verbose = !verbose;
64226095Sminshall 	printf("Verbose mode %s.\n", verbose ? "on" : "off");
64326095Sminshall }
644