main.c revision 36792
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
3528202Scharnierstatic const 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
4128202Scharnier#if 0
421590Srgrimesstatic char sccsid[] = "@(#)main.c	8.1 (Berkeley) 6/6/93";
4328202Scharnier#endif
4428202Scharnierstatic const char rcsid[] =
4536792Simp	"$Id: main.c,v 1.5 1997/08/14 06:47:39 charnier Exp $";
461590Srgrimes#endif /* not lint */
471590Srgrimes
481590Srgrimes/* Many bug fixes are from Jim Guyton <guyton@rand-unix> */
491590Srgrimes
501590Srgrimes/*
511590Srgrimes * TFTP User Program -- Command Interface.
521590Srgrimes */
5328202Scharnier#include <sys/param.h>
541590Srgrimes#include <sys/types.h>
551590Srgrimes#include <sys/socket.h>
561590Srgrimes#include <sys/file.h>
5736792Simp#include <sys/param.h>
581590Srgrimes
591590Srgrimes#include <netinet/in.h>
601590Srgrimes
611590Srgrimes#include <arpa/inet.h>
621590Srgrimes
631590Srgrimes#include <ctype.h>
6428202Scharnier#include <err.h>
651590Srgrimes#include <netdb.h>
661590Srgrimes#include <setjmp.h>
671590Srgrimes#include <signal.h>
681590Srgrimes#include <stdio.h>
691590Srgrimes#include <stdlib.h>
701590Srgrimes#include <string.h>
711590Srgrimes#include <unistd.h>
721590Srgrimes
731590Srgrimes#include "extern.h"
741590Srgrimes
751590Srgrimes#define	TIMEOUT		5		/* secs between rexmt's */
761590Srgrimes
771590Srgrimesstruct	sockaddr_in peeraddr;
781590Srgrimesint	f;
791590Srgrimesshort   port;
801590Srgrimesint	trace;
811590Srgrimesint	verbose;
821590Srgrimesint	connected;
831590Srgrimeschar	mode[32];
841590Srgrimeschar	line[200];
851590Srgrimesint	margc;
861590Srgrimeschar	*margv[20];
871590Srgrimeschar	*prompt = "tftp";
881590Srgrimesjmp_buf	toplevel;
891590Srgrimesvoid	intr();
901590Srgrimesstruct	servent *sp;
911590Srgrimes
921590Srgrimesvoid	get __P((int, char **));
931590Srgrimesvoid	help __P((int, char **));
941590Srgrimesvoid	modecmd __P((int, char **));
951590Srgrimesvoid	put __P((int, char **));
961590Srgrimesvoid	quit __P((int, char **));
971590Srgrimesvoid	setascii __P((int, char **));
981590Srgrimesvoid	setbinary __P((int, char **));
991590Srgrimesvoid	setpeer __P((int, char **));
1001590Srgrimesvoid	setrexmt __P((int, char **));
1011590Srgrimesvoid	settimeout __P((int, char **));
1021590Srgrimesvoid	settrace __P((int, char **));
1031590Srgrimesvoid	setverbose __P((int, char **));
1041590Srgrimesvoid	status __P((int, char **));
1051590Srgrimes
10618286Sbdestatic void command __P((void)) __dead2;
1071590Srgrimes
1081590Srgrimesstatic void getusage __P((char *));
1091590Srgrimesstatic void makeargv __P((void));
1101590Srgrimesstatic void putusage __P((char *));
1111590Srgrimesstatic void settftpmode __P((char *));
1121590Srgrimes
1131590Srgrimes#define HELPINDENT (sizeof("connect"))
1141590Srgrimes
1151590Srgrimesstruct cmd {
1161590Srgrimes	char	*name;
1171590Srgrimes	char	*help;
1181590Srgrimes	void	(*handler) __P((int, char **));
1191590Srgrimes};
1201590Srgrimes
1211590Srgrimeschar	vhelp[] = "toggle verbose mode";
1221590Srgrimeschar	thelp[] = "toggle packet tracing";
1231590Srgrimeschar	chelp[] = "connect to remote tftp";
1241590Srgrimeschar	qhelp[] = "exit tftp";
1251590Srgrimeschar	hhelp[] = "print help information";
1261590Srgrimeschar	shelp[] = "send file";
1271590Srgrimeschar	rhelp[] = "receive file";
1281590Srgrimeschar	mhelp[] = "set file transfer mode";
1291590Srgrimeschar	sthelp[] = "show current status";
1301590Srgrimeschar	xhelp[] = "set per-packet retransmission timeout";
1311590Srgrimeschar	ihelp[] = "set total retransmission timeout";
1321590Srgrimeschar    ashelp[] = "set mode to netascii";
1331590Srgrimeschar    bnhelp[] = "set mode to octet";
1341590Srgrimes
1351590Srgrimesstruct cmd cmdtab[] = {
1361590Srgrimes	{ "connect",	chelp,		setpeer },
1371590Srgrimes	{ "mode",       mhelp,          modecmd },
1381590Srgrimes	{ "put",	shelp,		put },
1391590Srgrimes	{ "get",	rhelp,		get },
1401590Srgrimes	{ "quit",	qhelp,		quit },
1411590Srgrimes	{ "verbose",	vhelp,		setverbose },
1421590Srgrimes	{ "trace",	thelp,		settrace },
1431590Srgrimes	{ "status",	sthelp,		status },
1441590Srgrimes	{ "binary",     bnhelp,         setbinary },
1451590Srgrimes	{ "ascii",      ashelp,         setascii },
1461590Srgrimes	{ "rexmt",	xhelp,		setrexmt },
1471590Srgrimes	{ "timeout",	ihelp,		settimeout },
1481590Srgrimes	{ "?",		hhelp,		help },
1491590Srgrimes	{ 0 }
1501590Srgrimes};
1511590Srgrimes
1521590Srgrimesstruct	cmd *getcmd();
1531590Srgrimeschar	*tail();
1541590Srgrimes
1551590Srgrimesint
1561590Srgrimesmain(argc, argv)
1571590Srgrimes	int argc;
1581590Srgrimes	char *argv[];
1591590Srgrimes{
1601590Srgrimes	struct sockaddr_in sin;
1611590Srgrimes
1621590Srgrimes	sp = getservbyname("tftp", "udp");
16328202Scharnier	if (sp == 0)
16428202Scharnier		errx(1, "udp/tftp: unknown service");
1651590Srgrimes	f = socket(AF_INET, SOCK_DGRAM, 0);
16628202Scharnier	if (f < 0)
16728202Scharnier		err(3, "socket");
1681590Srgrimes	bzero((char *)&sin, sizeof(sin));
1691590Srgrimes	sin.sin_family = AF_INET;
17028202Scharnier	if (bind(f, (struct sockaddr *)&sin, sizeof(sin)) < 0)
17128202Scharnier		err(1, "bind");
1721590Srgrimes	strcpy(mode, "netascii");
1731590Srgrimes	signal(SIGINT, intr);
1741590Srgrimes	if (argc > 1) {
1751590Srgrimes		if (setjmp(toplevel) != 0)
1761590Srgrimes			exit(0);
1771590Srgrimes		setpeer(argc, argv);
1781590Srgrimes	}
1791590Srgrimes	if (setjmp(toplevel) != 0)
1801590Srgrimes		(void)putchar('\n');
1811590Srgrimes	command();
1821590Srgrimes}
1831590Srgrimes
18428202Scharnierchar    hostname[MAXHOSTNAMELEN];
1851590Srgrimes
1861590Srgrimesvoid
1871590Srgrimessetpeer(argc, argv)
1881590Srgrimes	int argc;
1891590Srgrimes	char *argv[];
1901590Srgrimes{
1911590Srgrimes	struct hostent *host;
1921590Srgrimes
1931590Srgrimes	if (argc < 2) {
1941590Srgrimes		strcpy(line, "Connect ");
1951590Srgrimes		printf("(to) ");
19613068Sjoerg		fgets(&line[strlen(line)], sizeof line - strlen(line), stdin);
1971590Srgrimes		makeargv();
1981590Srgrimes		argc = margc;
1991590Srgrimes		argv = margv;
2001590Srgrimes	}
2011590Srgrimes	if (argc > 3) {
2021590Srgrimes		printf("usage: %s host-name [port]\n", argv[0]);
2031590Srgrimes		return;
2041590Srgrimes	}
2051590Srgrimes	host = gethostbyname(argv[1]);
2061590Srgrimes	if (host) {
2071590Srgrimes		peeraddr.sin_family = host->h_addrtype;
20836792Simp		bcopy(host->h_addr, &peeraddr.sin_addr,
20936792Simp			MIN(sizeof(peeraddr.sin_addr), host->h_length));
21036792Simp		strncpy(hostname, host->h_name, sizeof(hostname));
2111590Srgrimes	} else {
2121590Srgrimes		peeraddr.sin_family = AF_INET;
2131590Srgrimes		peeraddr.sin_addr.s_addr = inet_addr(argv[1]);
2141590Srgrimes		if (peeraddr.sin_addr.s_addr == -1) {
2151590Srgrimes			connected = 0;
2161590Srgrimes			printf("%s: unknown host\n", argv[1]);
2171590Srgrimes			return;
2181590Srgrimes		}
21936792Simp		strncpy(hostname, argv[1], sizeof(hostname));
2201590Srgrimes	}
22136792Simp	hostname[sizeof(hostname) - 1] = '\0';
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		}
35436792Simp		bcopy(hp->h_addr, (caddr_t)&peeraddr.sin_addr,
35536792Simp			MIN(sizeof(peeraddr.sin_addr), hp->h_length));
3561590Srgrimes		peeraddr.sin_family = hp->h_addrtype;
3571590Srgrimes		connected = 1;
35836792Simp		strncpy(hostname, hp->h_name, sizeof(hostname));
35936792Simp		hostname[sizeof(hostname) - 1] = '\0';
3601590Srgrimes	}
3611590Srgrimes	if (!connected) {
3621590Srgrimes		printf("No target machine specified.\n");
3631590Srgrimes		return;
3641590Srgrimes	}
3651590Srgrimes	if (argc < 4) {
3661590Srgrimes		cp = argc == 2 ? tail(targ) : argv[1];
3671590Srgrimes		fd = open(cp, O_RDONLY);
3681590Srgrimes		if (fd < 0) {
36928202Scharnier			warn("%s", cp);
3701590Srgrimes			return;
3711590Srgrimes		}
3721590Srgrimes		if (verbose)
3731590Srgrimes			printf("putting %s to %s:%s [%s]\n",
3741590Srgrimes				cp, hostname, targ, mode);
3751590Srgrimes		peeraddr.sin_port = port;
3761590Srgrimes		sendfile(fd, targ, mode);
3771590Srgrimes		return;
3781590Srgrimes	}
3791590Srgrimes				/* this assumes the target is a directory */
3801590Srgrimes				/* on a remote unix system.  hmmmm.  */
3818874Srgrimes	cp = index(targ, '\0');
3821590Srgrimes	*cp++ = '/';
3831590Srgrimes	for (n = 1; n < argc - 1; n++) {
3841590Srgrimes		strcpy(cp, tail(argv[n]));
3851590Srgrimes		fd = open(argv[n], O_RDONLY);
3861590Srgrimes		if (fd < 0) {
38728202Scharnier			warn("%s", argv[n]);
3881590Srgrimes			continue;
3891590Srgrimes		}
3901590Srgrimes		if (verbose)
3911590Srgrimes			printf("putting %s to %s:%s [%s]\n",
3921590Srgrimes				argv[n], hostname, targ, mode);
3931590Srgrimes		peeraddr.sin_port = port;
3941590Srgrimes		sendfile(fd, targ, mode);
3951590Srgrimes	}
3961590Srgrimes}
3971590Srgrimes
3981590Srgrimesstatic void
3991590Srgrimesputusage(s)
4001590Srgrimes	char *s;
4011590Srgrimes{
4021590Srgrimes	printf("usage: %s file ... host:target, or\n", s);
4031590Srgrimes	printf("       %s file ... target (when already connected)\n", s);
4041590Srgrimes}
4051590Srgrimes
4061590Srgrimes/*
4071590Srgrimes * Receive file(s).
4081590Srgrimes */
4091590Srgrimesvoid
4101590Srgrimesget(argc, argv)
4111590Srgrimes	int argc;
4121590Srgrimes	char *argv[];
4131590Srgrimes{
4141590Srgrimes	int fd;
4151590Srgrimes	register int n;
4161590Srgrimes	register char *cp;
4171590Srgrimes	char *src;
4181590Srgrimes
4191590Srgrimes	if (argc < 2) {
4201590Srgrimes		strcpy(line, "get ");
4211590Srgrimes		printf("(files) ");
42213068Sjoerg		fgets(&line[strlen(line)], sizeof line - strlen(line), stdin);
4231590Srgrimes		makeargv();
4241590Srgrimes		argc = margc;
4251590Srgrimes		argv = margv;
4261590Srgrimes	}
4271590Srgrimes	if (argc < 2) {
4281590Srgrimes		getusage(argv[0]);
4291590Srgrimes		return;
4301590Srgrimes	}
4311590Srgrimes	if (!connected) {
4321590Srgrimes		for (n = 1; n < argc ; n++)
4331590Srgrimes			if (index(argv[n], ':') == 0) {
4341590Srgrimes				getusage(argv[0]);
4351590Srgrimes				return;
4361590Srgrimes			}
4371590Srgrimes	}
4381590Srgrimes	for (n = 1; n < argc ; n++) {
4391590Srgrimes		src = index(argv[n], ':');
4401590Srgrimes		if (src == NULL)
4411590Srgrimes			src = argv[n];
4421590Srgrimes		else {
4431590Srgrimes			struct hostent *hp;
4441590Srgrimes
4451590Srgrimes			*src++ = 0;
4461590Srgrimes			hp = gethostbyname(argv[n]);
4471590Srgrimes			if (hp == NULL) {
4481590Srgrimes				fprintf(stderr, "tftp: %s: ", argv[n]);
4491590Srgrimes				herror((char *)NULL);
4501590Srgrimes				continue;
4511590Srgrimes			}
4521590Srgrimes			bcopy(hp->h_addr, (caddr_t)&peeraddr.sin_addr,
45336792Simp			    MIN(sizeof(peeraddr.sin_addr), hp->h_length));
4541590Srgrimes			peeraddr.sin_family = hp->h_addrtype;
4551590Srgrimes			connected = 1;
45636792Simp			strncpy(hostname, hp->h_name, sizeof(hostname));
45736792Simp			hostname[sizeof(hostname) - 1] = '\0';
4581590Srgrimes		}
4591590Srgrimes		if (argc < 4) {
4601590Srgrimes			cp = argc == 3 ? argv[2] : tail(src);
4611590Srgrimes			fd = creat(cp, 0644);
4621590Srgrimes			if (fd < 0) {
46328202Scharnier				warn("%s", cp);
4641590Srgrimes				return;
4651590Srgrimes			}
4661590Srgrimes			if (verbose)
4671590Srgrimes				printf("getting from %s:%s to %s [%s]\n",
4681590Srgrimes					hostname, src, cp, mode);
4691590Srgrimes			peeraddr.sin_port = port;
4701590Srgrimes			recvfile(fd, src, mode);
4711590Srgrimes			break;
4721590Srgrimes		}
4731590Srgrimes		cp = tail(src);         /* new .. jdg */
4741590Srgrimes		fd = creat(cp, 0644);
4751590Srgrimes		if (fd < 0) {
47628202Scharnier			warn("%s", cp);
4771590Srgrimes			continue;
4781590Srgrimes		}
4791590Srgrimes		if (verbose)
4801590Srgrimes			printf("getting from %s:%s to %s [%s]\n",
4811590Srgrimes				hostname, src, cp, mode);
4821590Srgrimes		peeraddr.sin_port = port;
4831590Srgrimes		recvfile(fd, src, mode);
4841590Srgrimes	}
4851590Srgrimes}
4861590Srgrimes
4871590Srgrimesstatic void
4881590Srgrimesgetusage(s)
4891590Srgrimes	char *s;
4901590Srgrimes{
4911590Srgrimes	printf("usage: %s host:file host:file ... file, or\n", s);
4921590Srgrimes	printf("       %s file file ... file if connected\n", s);
4931590Srgrimes}
4941590Srgrimes
4951590Srgrimesint	rexmtval = TIMEOUT;
4961590Srgrimes
4971590Srgrimesvoid
4981590Srgrimessetrexmt(argc, argv)
4991590Srgrimes	int argc;
5001590Srgrimes	char *argv[];
5011590Srgrimes{
5021590Srgrimes	int t;
5031590Srgrimes
5041590Srgrimes	if (argc < 2) {
5051590Srgrimes		strcpy(line, "Rexmt-timeout ");
5061590Srgrimes		printf("(value) ");
50713068Sjoerg		fgets(&line[strlen(line)], sizeof line - strlen(line), stdin);
5081590Srgrimes		makeargv();
5091590Srgrimes		argc = margc;
5101590Srgrimes		argv = margv;
5111590Srgrimes	}
5121590Srgrimes	if (argc != 2) {
5131590Srgrimes		printf("usage: %s value\n", argv[0]);
5141590Srgrimes		return;
5151590Srgrimes	}
5161590Srgrimes	t = atoi(argv[1]);
5171590Srgrimes	if (t < 0)
5181590Srgrimes		printf("%s: bad value\n", argv[1]);
5191590Srgrimes	else
5201590Srgrimes		rexmtval = t;
5211590Srgrimes}
5221590Srgrimes
5231590Srgrimesint	maxtimeout = 5 * TIMEOUT;
5241590Srgrimes
5251590Srgrimesvoid
5261590Srgrimessettimeout(argc, argv)
5271590Srgrimes	int argc;
5281590Srgrimes	char *argv[];
5291590Srgrimes{
5301590Srgrimes	int t;
5311590Srgrimes
5321590Srgrimes	if (argc < 2) {
5331590Srgrimes		strcpy(line, "Maximum-timeout ");
5341590Srgrimes		printf("(value) ");
53513068Sjoerg		fgets(&line[strlen(line)], sizeof line - strlen(line), stdin);
5361590Srgrimes		makeargv();
5371590Srgrimes		argc = margc;
5381590Srgrimes		argv = margv;
5391590Srgrimes	}
5401590Srgrimes	if (argc != 2) {
5411590Srgrimes		printf("usage: %s value\n", argv[0]);
5421590Srgrimes		return;
5431590Srgrimes	}
5441590Srgrimes	t = atoi(argv[1]);
5451590Srgrimes	if (t < 0)
5461590Srgrimes		printf("%s: bad value\n", argv[1]);
5471590Srgrimes	else
5481590Srgrimes		maxtimeout = t;
5491590Srgrimes}
5501590Srgrimes
5511590Srgrimesvoid
5521590Srgrimesstatus(argc, argv)
5531590Srgrimes	int argc;
5541590Srgrimes	char *argv[];
5551590Srgrimes{
5561590Srgrimes	if (connected)
5571590Srgrimes		printf("Connected to %s.\n", hostname);
5581590Srgrimes	else
5591590Srgrimes		printf("Not connected.\n");
5601590Srgrimes	printf("Mode: %s Verbose: %s Tracing: %s\n", mode,
5611590Srgrimes		verbose ? "on" : "off", trace ? "on" : "off");
5621590Srgrimes	printf("Rexmt-interval: %d seconds, Max-timeout: %d seconds\n",
5631590Srgrimes		rexmtval, maxtimeout);
5641590Srgrimes}
5651590Srgrimes
5661590Srgrimesvoid
5671590Srgrimesintr()
5681590Srgrimes{
5691590Srgrimes
5701590Srgrimes	signal(SIGALRM, SIG_IGN);
5711590Srgrimes	alarm(0);
5721590Srgrimes	longjmp(toplevel, -1);
5731590Srgrimes}
5741590Srgrimes
5751590Srgrimeschar *
5761590Srgrimestail(filename)
5771590Srgrimes	char *filename;
5781590Srgrimes{
5791590Srgrimes	register char *s;
5808874Srgrimes
5811590Srgrimes	while (*filename) {
5821590Srgrimes		s = rindex(filename, '/');
5831590Srgrimes		if (s == NULL)
5841590Srgrimes			break;
5851590Srgrimes		if (s[1])
5861590Srgrimes			return (s + 1);
5871590Srgrimes		*s = '\0';
5881590Srgrimes	}
5891590Srgrimes	return (filename);
5901590Srgrimes}
5911590Srgrimes
5921590Srgrimes/*
5931590Srgrimes * Command parser.
5941590Srgrimes */
59518286Sbdestatic void
5961590Srgrimescommand()
5971590Srgrimes{
5981590Srgrimes	register struct cmd *c;
59913068Sjoerg	char *cp;
6001590Srgrimes
6011590Srgrimes	for (;;) {
6021590Srgrimes		printf("%s> ", prompt);
60313068Sjoerg		if (fgets(line, sizeof line , stdin) == 0) {
6041590Srgrimes			if (feof(stdin)) {
6051590Srgrimes				exit(0);
6061590Srgrimes			} else {
6071590Srgrimes				continue;
6081590Srgrimes			}
6091590Srgrimes		}
61013068Sjoerg		if ((cp = strchr(line, '\n')))
61113068Sjoerg			*cp = '\0';
6121590Srgrimes		if (line[0] == 0)
6131590Srgrimes			continue;
6141590Srgrimes		makeargv();
6151590Srgrimes		if (margc == 0)
6161590Srgrimes			continue;
6171590Srgrimes		c = getcmd(margv[0]);
6181590Srgrimes		if (c == (struct cmd *)-1) {
6191590Srgrimes			printf("?Ambiguous command\n");
6201590Srgrimes			continue;
6211590Srgrimes		}
6221590Srgrimes		if (c == 0) {
6231590Srgrimes			printf("?Invalid command\n");
6241590Srgrimes			continue;
6251590Srgrimes		}
6261590Srgrimes		(*c->handler)(margc, margv);
6271590Srgrimes	}
6281590Srgrimes}
6291590Srgrimes
6301590Srgrimesstruct cmd *
6311590Srgrimesgetcmd(name)
6321590Srgrimes	register char *name;
6331590Srgrimes{
6341590Srgrimes	register char *p, *q;
6351590Srgrimes	register struct cmd *c, *found;
6361590Srgrimes	register int nmatches, longest;
6371590Srgrimes
6381590Srgrimes	longest = 0;
6391590Srgrimes	nmatches = 0;
6401590Srgrimes	found = 0;
6411590Srgrimes	for (c = cmdtab; (p = c->name) != NULL; c++) {
6421590Srgrimes		for (q = name; *q == *p++; q++)
6431590Srgrimes			if (*q == 0)		/* exact match? */
6441590Srgrimes				return (c);
6451590Srgrimes		if (!*q) {			/* the name was a prefix */
6461590Srgrimes			if (q - name > longest) {
6471590Srgrimes				longest = q - name;
6481590Srgrimes				nmatches = 1;
6491590Srgrimes				found = c;
6501590Srgrimes			} else if (q - name == longest)
6511590Srgrimes				nmatches++;
6521590Srgrimes		}
6531590Srgrimes	}
6541590Srgrimes	if (nmatches > 1)
6551590Srgrimes		return ((struct cmd *)-1);
6561590Srgrimes	return (found);
6571590Srgrimes}
6581590Srgrimes
6591590Srgrimes/*
6601590Srgrimes * Slice a string up into argc/argv.
6611590Srgrimes */
6621590Srgrimesstatic void
6631590Srgrimesmakeargv()
6641590Srgrimes{
6651590Srgrimes	register char *cp;
6661590Srgrimes	register char **argp = margv;
6671590Srgrimes
6681590Srgrimes	margc = 0;
66913068Sjoerg	if ((cp = strchr(line, '\n')))
67013068Sjoerg		*cp = '\0';
6711590Srgrimes	for (cp = line; *cp;) {
6721590Srgrimes		while (isspace(*cp))
6731590Srgrimes			cp++;
6741590Srgrimes		if (*cp == '\0')
6751590Srgrimes			break;
6761590Srgrimes		*argp++ = cp;
6771590Srgrimes		margc += 1;
6781590Srgrimes		while (*cp != '\0' && !isspace(*cp))
6791590Srgrimes			cp++;
6801590Srgrimes		if (*cp == '\0')
6811590Srgrimes			break;
6821590Srgrimes		*cp++ = '\0';
6831590Srgrimes	}
6841590Srgrimes	*argp++ = 0;
6851590Srgrimes}
6861590Srgrimes
6871590Srgrimesvoid
6881590Srgrimesquit(argc, argv)
6891590Srgrimes	int argc;
6901590Srgrimes	char *argv[];
6911590Srgrimes{
6921590Srgrimes
6931590Srgrimes	exit(0);
6941590Srgrimes}
6951590Srgrimes
6961590Srgrimes/*
6971590Srgrimes * Help command.
6981590Srgrimes */
6991590Srgrimesvoid
7001590Srgrimeshelp(argc, argv)
7011590Srgrimes	int argc;
7021590Srgrimes	char *argv[];
7031590Srgrimes{
7041590Srgrimes	register struct cmd *c;
7051590Srgrimes
7061590Srgrimes	if (argc == 1) {
7071590Srgrimes		printf("Commands may be abbreviated.  Commands are:\n\n");
7081590Srgrimes		for (c = cmdtab; c->name; c++)
7091590Srgrimes			printf("%-*s\t%s\n", (int)HELPINDENT, c->name, c->help);
7101590Srgrimes		return;
7111590Srgrimes	}
7121590Srgrimes	while (--argc > 0) {
7131590Srgrimes		register char *arg;
7141590Srgrimes		arg = *++argv;
7151590Srgrimes		c = getcmd(arg);
7161590Srgrimes		if (c == (struct cmd *)-1)
7171590Srgrimes			printf("?Ambiguous help command %s\n", arg);
7181590Srgrimes		else if (c == (struct cmd *)0)
7191590Srgrimes			printf("?Invalid help command %s\n", arg);
7201590Srgrimes		else
7211590Srgrimes			printf("%s\n", c->help);
7221590Srgrimes	}
7231590Srgrimes}
7241590Srgrimes
7251590Srgrimesvoid
7261590Srgrimessettrace(argc, argv)
7271590Srgrimes	int argc;
7281590Srgrimes	char **argv;
7291590Srgrimes{
7301590Srgrimes	trace = !trace;
7311590Srgrimes	printf("Packet tracing %s.\n", trace ? "on" : "off");
7321590Srgrimes}
7331590Srgrimes
7341590Srgrimesvoid
7351590Srgrimessetverbose(argc, argv)
7361590Srgrimes	int argc;
7371590Srgrimes	char **argv;
7381590Srgrimes{
7391590Srgrimes	verbose = !verbose;
7401590Srgrimes	printf("Verbose mode %s.\n", verbose ? "on" : "off");
7411590Srgrimes}
742