main.c revision 13068
11590Srgrimes/*
21590Srgrimes * Copyright (c) 1983, 1993
31590Srgrimes *	The Regents of the University of California.  All rights reserved.
41590Srgrimes *
51590Srgrimes * Redistribution and use in source and binary forms, with or without
61590Srgrimes * modification, are permitted provided that the following conditions
71590Srgrimes * are met:
81590Srgrimes * 1. Redistributions of source code must retain the above copyright
91590Srgrimes *    notice, this list of conditions and the following disclaimer.
101590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111590Srgrimes *    notice, this list of conditions and the following disclaimer in the
121590Srgrimes *    documentation and/or other materials provided with the distribution.
131590Srgrimes * 3. All advertising materials mentioning features or use of this software
141590Srgrimes *    must display the following acknowledgement:
151590Srgrimes *	This product includes software developed by the University of
161590Srgrimes *	California, Berkeley and its contributors.
171590Srgrimes * 4. Neither the name of the University nor the names of its contributors
181590Srgrimes *    may be used to endorse or promote products derived from this software
191590Srgrimes *    without specific prior written permission.
201590Srgrimes *
211590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
221590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
231590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
241590Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
251590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
261590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
271590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
281590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
291590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
301590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
311590Srgrimes * SUCH DAMAGE.
321590Srgrimes */
331590Srgrimes
341590Srgrimes#ifndef lint
351590Srgrimesstatic char copyright[] =
361590Srgrimes"@(#) Copyright (c) 1983, 1993\n\
371590Srgrimes	The Regents of the University of California.  All rights reserved.\n";
381590Srgrimes#endif /* not lint */
391590Srgrimes
401590Srgrimes#ifndef lint
411590Srgrimesstatic char sccsid[] = "@(#)main.c	8.1 (Berkeley) 6/6/93";
421590Srgrimes#endif /* not lint */
431590Srgrimes
441590Srgrimes/* Many bug fixes are from Jim Guyton <guyton@rand-unix> */
451590Srgrimes
461590Srgrimes/*
471590Srgrimes * TFTP User Program -- Command Interface.
481590Srgrimes */
491590Srgrimes#include <sys/types.h>
501590Srgrimes#include <sys/socket.h>
511590Srgrimes#include <sys/file.h>
521590Srgrimes
531590Srgrimes#include <netinet/in.h>
541590Srgrimes
551590Srgrimes#include <arpa/inet.h>
561590Srgrimes
571590Srgrimes#include <ctype.h>
581590Srgrimes#include <errno.h>
591590Srgrimes#include <netdb.h>
601590Srgrimes#include <setjmp.h>
611590Srgrimes#include <signal.h>
621590Srgrimes#include <stdio.h>
631590Srgrimes#include <stdlib.h>
641590Srgrimes#include <string.h>
651590Srgrimes#include <unistd.h>
661590Srgrimes
671590Srgrimes#include "extern.h"
681590Srgrimes
691590Srgrimes#define	TIMEOUT		5		/* secs between rexmt's */
701590Srgrimes
711590Srgrimesstruct	sockaddr_in peeraddr;
721590Srgrimesint	f;
731590Srgrimesshort   port;
741590Srgrimesint	trace;
751590Srgrimesint	verbose;
761590Srgrimesint	connected;
771590Srgrimeschar	mode[32];
781590Srgrimeschar	line[200];
791590Srgrimesint	margc;
801590Srgrimeschar	*margv[20];
811590Srgrimeschar	*prompt = "tftp";
821590Srgrimesjmp_buf	toplevel;
831590Srgrimesvoid	intr();
841590Srgrimesstruct	servent *sp;
851590Srgrimes
861590Srgrimesvoid	get __P((int, char **));
871590Srgrimesvoid	help __P((int, char **));
881590Srgrimesvoid	modecmd __P((int, char **));
891590Srgrimesvoid	put __P((int, char **));
901590Srgrimesvoid	quit __P((int, char **));
911590Srgrimesvoid	setascii __P((int, char **));
921590Srgrimesvoid	setbinary __P((int, char **));
931590Srgrimesvoid	setpeer __P((int, char **));
941590Srgrimesvoid	setrexmt __P((int, char **));
951590Srgrimesvoid	settimeout __P((int, char **));
961590Srgrimesvoid	settrace __P((int, char **));
971590Srgrimesvoid	setverbose __P((int, char **));
981590Srgrimesvoid	status __P((int, char **));
991590Srgrimes
1001590Srgrimesstatic __dead void command __P((void));
1011590Srgrimes
1021590Srgrimesstatic void getusage __P((char *));
1031590Srgrimesstatic void makeargv __P((void));
1041590Srgrimesstatic void putusage __P((char *));
1051590Srgrimesstatic void settftpmode __P((char *));
1061590Srgrimes
1071590Srgrimes#define HELPINDENT (sizeof("connect"))
1081590Srgrimes
1091590Srgrimesstruct cmd {
1101590Srgrimes	char	*name;
1111590Srgrimes	char	*help;
1121590Srgrimes	void	(*handler) __P((int, char **));
1131590Srgrimes};
1141590Srgrimes
1151590Srgrimeschar	vhelp[] = "toggle verbose mode";
1161590Srgrimeschar	thelp[] = "toggle packet tracing";
1171590Srgrimeschar	chelp[] = "connect to remote tftp";
1181590Srgrimeschar	qhelp[] = "exit tftp";
1191590Srgrimeschar	hhelp[] = "print help information";
1201590Srgrimeschar	shelp[] = "send file";
1211590Srgrimeschar	rhelp[] = "receive file";
1221590Srgrimeschar	mhelp[] = "set file transfer mode";
1231590Srgrimeschar	sthelp[] = "show current status";
1241590Srgrimeschar	xhelp[] = "set per-packet retransmission timeout";
1251590Srgrimeschar	ihelp[] = "set total retransmission timeout";
1261590Srgrimeschar    ashelp[] = "set mode to netascii";
1271590Srgrimeschar    bnhelp[] = "set mode to octet";
1281590Srgrimes
1291590Srgrimesstruct cmd cmdtab[] = {
1301590Srgrimes	{ "connect",	chelp,		setpeer },
1311590Srgrimes	{ "mode",       mhelp,          modecmd },
1321590Srgrimes	{ "put",	shelp,		put },
1331590Srgrimes	{ "get",	rhelp,		get },
1341590Srgrimes	{ "quit",	qhelp,		quit },
1351590Srgrimes	{ "verbose",	vhelp,		setverbose },
1361590Srgrimes	{ "trace",	thelp,		settrace },
1371590Srgrimes	{ "status",	sthelp,		status },
1381590Srgrimes	{ "binary",     bnhelp,         setbinary },
1391590Srgrimes	{ "ascii",      ashelp,         setascii },
1401590Srgrimes	{ "rexmt",	xhelp,		setrexmt },
1411590Srgrimes	{ "timeout",	ihelp,		settimeout },
1421590Srgrimes	{ "?",		hhelp,		help },
1431590Srgrimes	{ 0 }
1441590Srgrimes};
1451590Srgrimes
1461590Srgrimesstruct	cmd *getcmd();
1471590Srgrimeschar	*tail();
1481590Srgrimeschar	*index();
1491590Srgrimeschar	*rindex();
1501590Srgrimes
1511590Srgrimesint
1521590Srgrimesmain(argc, argv)
1531590Srgrimes	int argc;
1541590Srgrimes	char *argv[];
1551590Srgrimes{
1561590Srgrimes	struct sockaddr_in sin;
1571590Srgrimes
1581590Srgrimes	sp = getservbyname("tftp", "udp");
1591590Srgrimes	if (sp == 0) {
1601590Srgrimes		fprintf(stderr, "tftp: udp/tftp: unknown service\n");
1611590Srgrimes		exit(1);
1621590Srgrimes	}
1631590Srgrimes	f = socket(AF_INET, SOCK_DGRAM, 0);
1641590Srgrimes	if (f < 0) {
1651590Srgrimes		perror("tftp: socket");
1661590Srgrimes		exit(3);
1671590Srgrimes	}
1681590Srgrimes	bzero((char *)&sin, sizeof(sin));
1691590Srgrimes	sin.sin_family = AF_INET;
1701590Srgrimes	if (bind(f, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
1711590Srgrimes		perror("tftp: bind");
1721590Srgrimes		exit(1);
1731590Srgrimes	}
1741590Srgrimes	strcpy(mode, "netascii");
1751590Srgrimes	signal(SIGINT, intr);
1761590Srgrimes	if (argc > 1) {
1771590Srgrimes		if (setjmp(toplevel) != 0)
1781590Srgrimes			exit(0);
1791590Srgrimes		setpeer(argc, argv);
1801590Srgrimes	}
1811590Srgrimes	if (setjmp(toplevel) != 0)
1821590Srgrimes		(void)putchar('\n');
1831590Srgrimes	command();
1841590Srgrimes}
1851590Srgrimes
1861590Srgrimeschar    hostname[100];
1871590Srgrimes
1881590Srgrimesvoid
1891590Srgrimessetpeer(argc, argv)
1901590Srgrimes	int argc;
1911590Srgrimes	char *argv[];
1921590Srgrimes{
1931590Srgrimes	struct hostent *host;
1941590Srgrimes
1951590Srgrimes	if (argc < 2) {
1961590Srgrimes		strcpy(line, "Connect ");
1971590Srgrimes		printf("(to) ");
19813068Sjoerg		fgets(&line[strlen(line)], sizeof line - strlen(line), stdin);
1991590Srgrimes		makeargv();
2001590Srgrimes		argc = margc;
2011590Srgrimes		argv = margv;
2021590Srgrimes	}
2031590Srgrimes	if (argc > 3) {
2041590Srgrimes		printf("usage: %s host-name [port]\n", argv[0]);
2051590Srgrimes		return;
2061590Srgrimes	}
2071590Srgrimes	host = gethostbyname(argv[1]);
2081590Srgrimes	if (host) {
2091590Srgrimes		peeraddr.sin_family = host->h_addrtype;
2101590Srgrimes		bcopy(host->h_addr, &peeraddr.sin_addr, host->h_length);
2111590Srgrimes		strcpy(hostname, host->h_name);
2121590Srgrimes	} else {
2131590Srgrimes		peeraddr.sin_family = AF_INET;
2141590Srgrimes		peeraddr.sin_addr.s_addr = inet_addr(argv[1]);
2151590Srgrimes		if (peeraddr.sin_addr.s_addr == -1) {
2161590Srgrimes			connected = 0;
2171590Srgrimes			printf("%s: unknown host\n", argv[1]);
2181590Srgrimes			return;
2191590Srgrimes		}
2201590Srgrimes		strcpy(hostname, argv[1]);
2211590Srgrimes	}
2221590Srgrimes	port = sp->s_port;
2231590Srgrimes	if (argc == 3) {
2241590Srgrimes		port = atoi(argv[2]);
2251590Srgrimes		if (port < 0) {
2261590Srgrimes			printf("%s: bad port number\n", argv[2]);
2271590Srgrimes			connected = 0;
2281590Srgrimes			return;
2291590Srgrimes		}
2301590Srgrimes		port = htons(port);
2311590Srgrimes	}
2321590Srgrimes	connected = 1;
2331590Srgrimes}
2341590Srgrimes
2351590Srgrimesstruct	modes {
2361590Srgrimes	char *m_name;
2371590Srgrimes	char *m_mode;
2381590Srgrimes} modes[] = {
2391590Srgrimes	{ "ascii",	"netascii" },
2401590Srgrimes	{ "netascii",   "netascii" },
2411590Srgrimes	{ "binary",     "octet" },
2421590Srgrimes	{ "image",      "octet" },
2431590Srgrimes	{ "octet",     "octet" },
2441590Srgrimes/*      { "mail",       "mail" },       */
2451590Srgrimes	{ 0,		0 }
2461590Srgrimes};
2471590Srgrimes
2481590Srgrimesvoid
2491590Srgrimesmodecmd(argc, argv)
2501590Srgrimes	int argc;
2511590Srgrimes	char *argv[];
2521590Srgrimes{
2531590Srgrimes	register struct modes *p;
2541590Srgrimes	char *sep;
2551590Srgrimes
2561590Srgrimes	if (argc < 2) {
2571590Srgrimes		printf("Using %s mode to transfer files.\n", mode);
2581590Srgrimes		return;
2591590Srgrimes	}
2601590Srgrimes	if (argc == 2) {
2611590Srgrimes		for (p = modes; p->m_name; p++)
2621590Srgrimes			if (strcmp(argv[1], p->m_name) == 0)
2631590Srgrimes				break;
2641590Srgrimes		if (p->m_name) {
2651590Srgrimes			settftpmode(p->m_mode);
2661590Srgrimes			return;
2671590Srgrimes		}
2681590Srgrimes		printf("%s: unknown mode\n", argv[1]);
2691590Srgrimes		/* drop through and print usage message */
2701590Srgrimes	}
2711590Srgrimes
2721590Srgrimes	printf("usage: %s [", argv[0]);
2731590Srgrimes	sep = " ";
2741590Srgrimes	for (p = modes; p->m_name; p++) {
2751590Srgrimes		printf("%s%s", sep, p->m_name);
2761590Srgrimes		if (*sep == ' ')
2771590Srgrimes			sep = " | ";
2781590Srgrimes	}
2791590Srgrimes	printf(" ]\n");
2801590Srgrimes	return;
2811590Srgrimes}
2821590Srgrimes
2831590Srgrimesvoid
2841590Srgrimessetbinary(argc, argv)
2851590Srgrimes	int argc;
2861590Srgrimes	char *argv[];
2878874Srgrimes{
2881590Srgrimes
2891590Srgrimes	settftpmode("octet");
2901590Srgrimes}
2911590Srgrimes
2921590Srgrimesvoid
2931590Srgrimessetascii(argc, argv)
2941590Srgrimes	int argc;
2951590Srgrimes	char *argv[];
2961590Srgrimes{
2971590Srgrimes
2981590Srgrimes	settftpmode("netascii");
2991590Srgrimes}
3001590Srgrimes
3011590Srgrimesstatic void
3021590Srgrimessettftpmode(newmode)
3031590Srgrimes	char *newmode;
3041590Srgrimes{
3051590Srgrimes	strcpy(mode, newmode);
3061590Srgrimes	if (verbose)
3071590Srgrimes		printf("mode set to %s\n", mode);
3081590Srgrimes}
3091590Srgrimes
3101590Srgrimes
3111590Srgrimes/*
3121590Srgrimes * Send file(s).
3131590Srgrimes */
3141590Srgrimesvoid
3151590Srgrimesput(argc, argv)
3161590Srgrimes	int argc;
3171590Srgrimes	char *argv[];
3181590Srgrimes{
3191590Srgrimes	int fd;
3201590Srgrimes	register int n;
3211590Srgrimes	register char *cp, *targ;
3221590Srgrimes
3231590Srgrimes	if (argc < 2) {
3241590Srgrimes		strcpy(line, "send ");
3251590Srgrimes		printf("(file) ");
32613068Sjoerg		fgets(&line[strlen(line)], sizeof line - strlen(line), stdin);
3271590Srgrimes		makeargv();
3281590Srgrimes		argc = margc;
3291590Srgrimes		argv = margv;
3301590Srgrimes	}
3311590Srgrimes	if (argc < 2) {
3321590Srgrimes		putusage(argv[0]);
3331590Srgrimes		return;
3341590Srgrimes	}
3351590Srgrimes	targ = argv[argc - 1];
3361590Srgrimes	if (index(argv[argc - 1], ':')) {
3371590Srgrimes		char *cp;
3381590Srgrimes		struct hostent *hp;
3391590Srgrimes
3401590Srgrimes		for (n = 1; n < argc - 1; n++)
3411590Srgrimes			if (index(argv[n], ':')) {
3421590Srgrimes				putusage(argv[0]);
3431590Srgrimes				return;
3441590Srgrimes			}
3451590Srgrimes		cp = argv[argc - 1];
3461590Srgrimes		targ = index(cp, ':');
3471590Srgrimes		*targ++ = 0;
3481590Srgrimes		hp = gethostbyname(cp);
3491590Srgrimes		if (hp == NULL) {
3501590Srgrimes			fprintf(stderr, "tftp: %s: ", cp);
3511590Srgrimes			herror((char *)NULL);
3521590Srgrimes			return;
3531590Srgrimes		}
3541590Srgrimes		bcopy(hp->h_addr, (caddr_t)&peeraddr.sin_addr, hp->h_length);
3551590Srgrimes		peeraddr.sin_family = hp->h_addrtype;
3561590Srgrimes		connected = 1;
3571590Srgrimes		strcpy(hostname, hp->h_name);
3581590Srgrimes	}
3591590Srgrimes	if (!connected) {
3601590Srgrimes		printf("No target machine specified.\n");
3611590Srgrimes		return;
3621590Srgrimes	}
3631590Srgrimes	if (argc < 4) {
3641590Srgrimes		cp = argc == 2 ? tail(targ) : argv[1];
3651590Srgrimes		fd = open(cp, O_RDONLY);
3661590Srgrimes		if (fd < 0) {
3671590Srgrimes			fprintf(stderr, "tftp: "); perror(cp);
3681590Srgrimes			return;
3691590Srgrimes		}
3701590Srgrimes		if (verbose)
3711590Srgrimes			printf("putting %s to %s:%s [%s]\n",
3721590Srgrimes				cp, hostname, targ, mode);
3731590Srgrimes		peeraddr.sin_port = port;
3741590Srgrimes		sendfile(fd, targ, mode);
3751590Srgrimes		return;
3761590Srgrimes	}
3771590Srgrimes				/* this assumes the target is a directory */
3781590Srgrimes				/* on a remote unix system.  hmmmm.  */
3798874Srgrimes	cp = index(targ, '\0');
3801590Srgrimes	*cp++ = '/';
3811590Srgrimes	for (n = 1; n < argc - 1; n++) {
3821590Srgrimes		strcpy(cp, tail(argv[n]));
3831590Srgrimes		fd = open(argv[n], O_RDONLY);
3841590Srgrimes		if (fd < 0) {
3851590Srgrimes			fprintf(stderr, "tftp: "); perror(argv[n]);
3861590Srgrimes			continue;
3871590Srgrimes		}
3881590Srgrimes		if (verbose)
3891590Srgrimes			printf("putting %s to %s:%s [%s]\n",
3901590Srgrimes				argv[n], hostname, targ, mode);
3911590Srgrimes		peeraddr.sin_port = port;
3921590Srgrimes		sendfile(fd, targ, mode);
3931590Srgrimes	}
3941590Srgrimes}
3951590Srgrimes
3961590Srgrimesstatic void
3971590Srgrimesputusage(s)
3981590Srgrimes	char *s;
3991590Srgrimes{
4001590Srgrimes	printf("usage: %s file ... host:target, or\n", s);
4011590Srgrimes	printf("       %s file ... target (when already connected)\n", s);
4021590Srgrimes}
4031590Srgrimes
4041590Srgrimes/*
4051590Srgrimes * Receive file(s).
4061590Srgrimes */
4071590Srgrimesvoid
4081590Srgrimesget(argc, argv)
4091590Srgrimes	int argc;
4101590Srgrimes	char *argv[];
4111590Srgrimes{
4121590Srgrimes	int fd;
4131590Srgrimes	register int n;
4141590Srgrimes	register char *cp;
4151590Srgrimes	char *src;
4161590Srgrimes
4171590Srgrimes	if (argc < 2) {
4181590Srgrimes		strcpy(line, "get ");
4191590Srgrimes		printf("(files) ");
42013068Sjoerg		fgets(&line[strlen(line)], sizeof line - strlen(line), stdin);
4211590Srgrimes		makeargv();
4221590Srgrimes		argc = margc;
4231590Srgrimes		argv = margv;
4241590Srgrimes	}
4251590Srgrimes	if (argc < 2) {
4261590Srgrimes		getusage(argv[0]);
4271590Srgrimes		return;
4281590Srgrimes	}
4291590Srgrimes	if (!connected) {
4301590Srgrimes		for (n = 1; n < argc ; n++)
4311590Srgrimes			if (index(argv[n], ':') == 0) {
4321590Srgrimes				getusage(argv[0]);
4331590Srgrimes				return;
4341590Srgrimes			}
4351590Srgrimes	}
4361590Srgrimes	for (n = 1; n < argc ; n++) {
4371590Srgrimes		src = index(argv[n], ':');
4381590Srgrimes		if (src == NULL)
4391590Srgrimes			src = argv[n];
4401590Srgrimes		else {
4411590Srgrimes			struct hostent *hp;
4421590Srgrimes
4431590Srgrimes			*src++ = 0;
4441590Srgrimes			hp = gethostbyname(argv[n]);
4451590Srgrimes			if (hp == NULL) {
4461590Srgrimes				fprintf(stderr, "tftp: %s: ", argv[n]);
4471590Srgrimes				herror((char *)NULL);
4481590Srgrimes				continue;
4491590Srgrimes			}
4501590Srgrimes			bcopy(hp->h_addr, (caddr_t)&peeraddr.sin_addr,
4511590Srgrimes			    hp->h_length);
4521590Srgrimes			peeraddr.sin_family = hp->h_addrtype;
4531590Srgrimes			connected = 1;
4541590Srgrimes			strcpy(hostname, hp->h_name);
4551590Srgrimes		}
4561590Srgrimes		if (argc < 4) {
4571590Srgrimes			cp = argc == 3 ? argv[2] : tail(src);
4581590Srgrimes			fd = creat(cp, 0644);
4591590Srgrimes			if (fd < 0) {
4601590Srgrimes				fprintf(stderr, "tftp: "); perror(cp);
4611590Srgrimes				return;
4621590Srgrimes			}
4631590Srgrimes			if (verbose)
4641590Srgrimes				printf("getting from %s:%s to %s [%s]\n",
4651590Srgrimes					hostname, src, cp, mode);
4661590Srgrimes			peeraddr.sin_port = port;
4671590Srgrimes			recvfile(fd, src, mode);
4681590Srgrimes			break;
4691590Srgrimes		}
4701590Srgrimes		cp = tail(src);         /* new .. jdg */
4711590Srgrimes		fd = creat(cp, 0644);
4721590Srgrimes		if (fd < 0) {
4731590Srgrimes			fprintf(stderr, "tftp: "); perror(cp);
4741590Srgrimes			continue;
4751590Srgrimes		}
4761590Srgrimes		if (verbose)
4771590Srgrimes			printf("getting from %s:%s to %s [%s]\n",
4781590Srgrimes				hostname, src, cp, mode);
4791590Srgrimes		peeraddr.sin_port = port;
4801590Srgrimes		recvfile(fd, src, mode);
4811590Srgrimes	}
4821590Srgrimes}
4831590Srgrimes
4841590Srgrimesstatic void
4851590Srgrimesgetusage(s)
4861590Srgrimes	char *s;
4871590Srgrimes{
4881590Srgrimes	printf("usage: %s host:file host:file ... file, or\n", s);
4891590Srgrimes	printf("       %s file file ... file if connected\n", s);
4901590Srgrimes}
4911590Srgrimes
4921590Srgrimesint	rexmtval = TIMEOUT;
4931590Srgrimes
4941590Srgrimesvoid
4951590Srgrimessetrexmt(argc, argv)
4961590Srgrimes	int argc;
4971590Srgrimes	char *argv[];
4981590Srgrimes{
4991590Srgrimes	int t;
5001590Srgrimes
5011590Srgrimes	if (argc < 2) {
5021590Srgrimes		strcpy(line, "Rexmt-timeout ");
5031590Srgrimes		printf("(value) ");
50413068Sjoerg		fgets(&line[strlen(line)], sizeof line - strlen(line), stdin);
5051590Srgrimes		makeargv();
5061590Srgrimes		argc = margc;
5071590Srgrimes		argv = margv;
5081590Srgrimes	}
5091590Srgrimes	if (argc != 2) {
5101590Srgrimes		printf("usage: %s value\n", argv[0]);
5111590Srgrimes		return;
5121590Srgrimes	}
5131590Srgrimes	t = atoi(argv[1]);
5141590Srgrimes	if (t < 0)
5151590Srgrimes		printf("%s: bad value\n", argv[1]);
5161590Srgrimes	else
5171590Srgrimes		rexmtval = t;
5181590Srgrimes}
5191590Srgrimes
5201590Srgrimesint	maxtimeout = 5 * TIMEOUT;
5211590Srgrimes
5221590Srgrimesvoid
5231590Srgrimessettimeout(argc, argv)
5241590Srgrimes	int argc;
5251590Srgrimes	char *argv[];
5261590Srgrimes{
5271590Srgrimes	int t;
5281590Srgrimes
5291590Srgrimes	if (argc < 2) {
5301590Srgrimes		strcpy(line, "Maximum-timeout ");
5311590Srgrimes		printf("(value) ");
53213068Sjoerg		fgets(&line[strlen(line)], sizeof line - strlen(line), stdin);
5331590Srgrimes		makeargv();
5341590Srgrimes		argc = margc;
5351590Srgrimes		argv = margv;
5361590Srgrimes	}
5371590Srgrimes	if (argc != 2) {
5381590Srgrimes		printf("usage: %s value\n", argv[0]);
5391590Srgrimes		return;
5401590Srgrimes	}
5411590Srgrimes	t = atoi(argv[1]);
5421590Srgrimes	if (t < 0)
5431590Srgrimes		printf("%s: bad value\n", argv[1]);
5441590Srgrimes	else
5451590Srgrimes		maxtimeout = t;
5461590Srgrimes}
5471590Srgrimes
5481590Srgrimesvoid
5491590Srgrimesstatus(argc, argv)
5501590Srgrimes	int argc;
5511590Srgrimes	char *argv[];
5521590Srgrimes{
5531590Srgrimes	if (connected)
5541590Srgrimes		printf("Connected to %s.\n", hostname);
5551590Srgrimes	else
5561590Srgrimes		printf("Not connected.\n");
5571590Srgrimes	printf("Mode: %s Verbose: %s Tracing: %s\n", mode,
5581590Srgrimes		verbose ? "on" : "off", trace ? "on" : "off");
5591590Srgrimes	printf("Rexmt-interval: %d seconds, Max-timeout: %d seconds\n",
5601590Srgrimes		rexmtval, maxtimeout);
5611590Srgrimes}
5621590Srgrimes
5631590Srgrimesvoid
5641590Srgrimesintr()
5651590Srgrimes{
5661590Srgrimes
5671590Srgrimes	signal(SIGALRM, SIG_IGN);
5681590Srgrimes	alarm(0);
5691590Srgrimes	longjmp(toplevel, -1);
5701590Srgrimes}
5711590Srgrimes
5721590Srgrimeschar *
5731590Srgrimestail(filename)
5741590Srgrimes	char *filename;
5751590Srgrimes{
5761590Srgrimes	register char *s;
5778874Srgrimes
5781590Srgrimes	while (*filename) {
5791590Srgrimes		s = rindex(filename, '/');
5801590Srgrimes		if (s == NULL)
5811590Srgrimes			break;
5821590Srgrimes		if (s[1])
5831590Srgrimes			return (s + 1);
5841590Srgrimes		*s = '\0';
5851590Srgrimes	}
5861590Srgrimes	return (filename);
5871590Srgrimes}
5881590Srgrimes
5891590Srgrimes/*
5901590Srgrimes * Command parser.
5911590Srgrimes */
5921590Srgrimesstatic __dead void
5931590Srgrimescommand()
5941590Srgrimes{
5951590Srgrimes	register struct cmd *c;
59613068Sjoerg	char *cp;
5971590Srgrimes
5981590Srgrimes	for (;;) {
5991590Srgrimes		printf("%s> ", prompt);
60013068Sjoerg		if (fgets(line, sizeof line , stdin) == 0) {
6011590Srgrimes			if (feof(stdin)) {
6021590Srgrimes				exit(0);
6031590Srgrimes			} else {
6041590Srgrimes				continue;
6051590Srgrimes			}
6061590Srgrimes		}
60713068Sjoerg		if ((cp = strchr(line, '\n')))
60813068Sjoerg			*cp = '\0';
6091590Srgrimes		if (line[0] == 0)
6101590Srgrimes			continue;
6111590Srgrimes		makeargv();
6121590Srgrimes		if (margc == 0)
6131590Srgrimes			continue;
6141590Srgrimes		c = getcmd(margv[0]);
6151590Srgrimes		if (c == (struct cmd *)-1) {
6161590Srgrimes			printf("?Ambiguous command\n");
6171590Srgrimes			continue;
6181590Srgrimes		}
6191590Srgrimes		if (c == 0) {
6201590Srgrimes			printf("?Invalid command\n");
6211590Srgrimes			continue;
6221590Srgrimes		}
6231590Srgrimes		(*c->handler)(margc, margv);
6241590Srgrimes	}
6251590Srgrimes}
6261590Srgrimes
6271590Srgrimesstruct cmd *
6281590Srgrimesgetcmd(name)
6291590Srgrimes	register char *name;
6301590Srgrimes{
6311590Srgrimes	register char *p, *q;
6321590Srgrimes	register struct cmd *c, *found;
6331590Srgrimes	register int nmatches, longest;
6341590Srgrimes
6351590Srgrimes	longest = 0;
6361590Srgrimes	nmatches = 0;
6371590Srgrimes	found = 0;
6381590Srgrimes	for (c = cmdtab; (p = c->name) != NULL; c++) {
6391590Srgrimes		for (q = name; *q == *p++; q++)
6401590Srgrimes			if (*q == 0)		/* exact match? */
6411590Srgrimes				return (c);
6421590Srgrimes		if (!*q) {			/* the name was a prefix */
6431590Srgrimes			if (q - name > longest) {
6441590Srgrimes				longest = q - name;
6451590Srgrimes				nmatches = 1;
6461590Srgrimes				found = c;
6471590Srgrimes			} else if (q - name == longest)
6481590Srgrimes				nmatches++;
6491590Srgrimes		}
6501590Srgrimes	}
6511590Srgrimes	if (nmatches > 1)
6521590Srgrimes		return ((struct cmd *)-1);
6531590Srgrimes	return (found);
6541590Srgrimes}
6551590Srgrimes
6561590Srgrimes/*
6571590Srgrimes * Slice a string up into argc/argv.
6581590Srgrimes */
6591590Srgrimesstatic void
6601590Srgrimesmakeargv()
6611590Srgrimes{
6621590Srgrimes	register char *cp;
6631590Srgrimes	register char **argp = margv;
6641590Srgrimes
6651590Srgrimes	margc = 0;
66613068Sjoerg	if ((cp = strchr(line, '\n')))
66713068Sjoerg		*cp = '\0';
6681590Srgrimes	for (cp = line; *cp;) {
6691590Srgrimes		while (isspace(*cp))
6701590Srgrimes			cp++;
6711590Srgrimes		if (*cp == '\0')
6721590Srgrimes			break;
6731590Srgrimes		*argp++ = cp;
6741590Srgrimes		margc += 1;
6751590Srgrimes		while (*cp != '\0' && !isspace(*cp))
6761590Srgrimes			cp++;
6771590Srgrimes		if (*cp == '\0')
6781590Srgrimes			break;
6791590Srgrimes		*cp++ = '\0';
6801590Srgrimes	}
6811590Srgrimes	*argp++ = 0;
6821590Srgrimes}
6831590Srgrimes
6841590Srgrimesvoid
6851590Srgrimesquit(argc, argv)
6861590Srgrimes	int argc;
6871590Srgrimes	char *argv[];
6881590Srgrimes{
6891590Srgrimes
6901590Srgrimes	exit(0);
6911590Srgrimes}
6921590Srgrimes
6931590Srgrimes/*
6941590Srgrimes * Help command.
6951590Srgrimes */
6961590Srgrimesvoid
6971590Srgrimeshelp(argc, argv)
6981590Srgrimes	int argc;
6991590Srgrimes	char *argv[];
7001590Srgrimes{
7011590Srgrimes	register struct cmd *c;
7021590Srgrimes
7031590Srgrimes	if (argc == 1) {
7041590Srgrimes		printf("Commands may be abbreviated.  Commands are:\n\n");
7051590Srgrimes		for (c = cmdtab; c->name; c++)
7061590Srgrimes			printf("%-*s\t%s\n", (int)HELPINDENT, c->name, c->help);
7071590Srgrimes		return;
7081590Srgrimes	}
7091590Srgrimes	while (--argc > 0) {
7101590Srgrimes		register char *arg;
7111590Srgrimes		arg = *++argv;
7121590Srgrimes		c = getcmd(arg);
7131590Srgrimes		if (c == (struct cmd *)-1)
7141590Srgrimes			printf("?Ambiguous help command %s\n", arg);
7151590Srgrimes		else if (c == (struct cmd *)0)
7161590Srgrimes			printf("?Invalid help command %s\n", arg);
7171590Srgrimes		else
7181590Srgrimes			printf("%s\n", c->help);
7191590Srgrimes	}
7201590Srgrimes}
7211590Srgrimes
7221590Srgrimesvoid
7231590Srgrimessettrace(argc, argv)
7241590Srgrimes	int argc;
7251590Srgrimes	char **argv;
7261590Srgrimes{
7271590Srgrimes	trace = !trace;
7281590Srgrimes	printf("Packet tracing %s.\n", trace ? "on" : "off");
7291590Srgrimes}
7301590Srgrimes
7311590Srgrimesvoid
7321590Srgrimessetverbose(argc, argv)
7331590Srgrimes	int argc;
7341590Srgrimes	char **argv;
7351590Srgrimes{
7361590Srgrimes	verbose = !verbose;
7371590Srgrimes	printf("Verbose mode %s.\n", verbose ? "on" : "off");
7381590Srgrimes}
739