xref: /freebsd/usr.bin/tftp/main.c (revision eaa86f9d7fcbe6b82b1defa62f31071324c836ed)
19b50d902SRodney W. Grimes /*
29b50d902SRodney W. Grimes  * Copyright (c) 1983, 1993
39b50d902SRodney W. Grimes  *	The Regents of the University of California.  All rights reserved.
49b50d902SRodney W. Grimes  *
59b50d902SRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
69b50d902SRodney W. Grimes  * modification, are permitted provided that the following conditions
79b50d902SRodney W. Grimes  * are met:
89b50d902SRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
99b50d902SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
109b50d902SRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
119b50d902SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
129b50d902SRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
139b50d902SRodney W. Grimes  * 3. All advertising materials mentioning features or use of this software
149b50d902SRodney W. Grimes  *    must display the following acknowledgement:
159b50d902SRodney W. Grimes  *	This product includes software developed by the University of
169b50d902SRodney W. Grimes  *	California, Berkeley and its contributors.
179b50d902SRodney W. Grimes  * 4. Neither the name of the University nor the names of its contributors
189b50d902SRodney W. Grimes  *    may be used to endorse or promote products derived from this software
199b50d902SRodney W. Grimes  *    without specific prior written permission.
209b50d902SRodney W. Grimes  *
219b50d902SRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
229b50d902SRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
239b50d902SRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
249b50d902SRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
259b50d902SRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
269b50d902SRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
279b50d902SRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
289b50d902SRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
299b50d902SRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
309b50d902SRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
319b50d902SRodney W. Grimes  * SUCH DAMAGE.
329b50d902SRodney W. Grimes  */
339b50d902SRodney W. Grimes 
349b50d902SRodney W. Grimes #ifndef lint
359b50d902SRodney W. Grimes static char copyright[] =
369b50d902SRodney W. Grimes "@(#) Copyright (c) 1983, 1993\n\
379b50d902SRodney W. Grimes 	The Regents of the University of California.  All rights reserved.\n";
389b50d902SRodney W. Grimes #endif /* not lint */
399b50d902SRodney W. Grimes 
409b50d902SRodney W. Grimes #ifndef lint
419b50d902SRodney W. Grimes static char sccsid[] = "@(#)main.c	8.1 (Berkeley) 6/6/93";
429b50d902SRodney W. Grimes #endif /* not lint */
439b50d902SRodney W. Grimes 
449b50d902SRodney W. Grimes /* Many bug fixes are from Jim Guyton <guyton@rand-unix> */
459b50d902SRodney W. Grimes 
469b50d902SRodney W. Grimes /*
479b50d902SRodney W. Grimes  * TFTP User Program -- Command Interface.
489b50d902SRodney W. Grimes  */
499b50d902SRodney W. Grimes #include <sys/types.h>
509b50d902SRodney W. Grimes #include <sys/socket.h>
519b50d902SRodney W. Grimes #include <sys/file.h>
529b50d902SRodney W. Grimes 
539b50d902SRodney W. Grimes #include <netinet/in.h>
549b50d902SRodney W. Grimes 
559b50d902SRodney W. Grimes #include <arpa/inet.h>
569b50d902SRodney W. Grimes 
579b50d902SRodney W. Grimes #include <ctype.h>
589b50d902SRodney W. Grimes #include <errno.h>
599b50d902SRodney W. Grimes #include <netdb.h>
609b50d902SRodney W. Grimes #include <setjmp.h>
619b50d902SRodney W. Grimes #include <signal.h>
629b50d902SRodney W. Grimes #include <stdio.h>
639b50d902SRodney W. Grimes #include <stdlib.h>
649b50d902SRodney W. Grimes #include <string.h>
659b50d902SRodney W. Grimes #include <unistd.h>
669b50d902SRodney W. Grimes 
679b50d902SRodney W. Grimes #include "extern.h"
689b50d902SRodney W. Grimes 
699b50d902SRodney W. Grimes #define	TIMEOUT		5		/* secs between rexmt's */
709b50d902SRodney W. Grimes 
719b50d902SRodney W. Grimes struct	sockaddr_in peeraddr;
729b50d902SRodney W. Grimes int	f;
739b50d902SRodney W. Grimes short   port;
749b50d902SRodney W. Grimes int	trace;
759b50d902SRodney W. Grimes int	verbose;
769b50d902SRodney W. Grimes int	connected;
779b50d902SRodney W. Grimes char	mode[32];
789b50d902SRodney W. Grimes char	line[200];
799b50d902SRodney W. Grimes int	margc;
809b50d902SRodney W. Grimes char	*margv[20];
819b50d902SRodney W. Grimes char	*prompt = "tftp";
829b50d902SRodney W. Grimes jmp_buf	toplevel;
839b50d902SRodney W. Grimes void	intr();
849b50d902SRodney W. Grimes struct	servent *sp;
859b50d902SRodney W. Grimes 
869b50d902SRodney W. Grimes void	get __P((int, char **));
879b50d902SRodney W. Grimes void	help __P((int, char **));
889b50d902SRodney W. Grimes void	modecmd __P((int, char **));
899b50d902SRodney W. Grimes void	put __P((int, char **));
909b50d902SRodney W. Grimes void	quit __P((int, char **));
919b50d902SRodney W. Grimes void	setascii __P((int, char **));
929b50d902SRodney W. Grimes void	setbinary __P((int, char **));
939b50d902SRodney W. Grimes void	setpeer __P((int, char **));
949b50d902SRodney W. Grimes void	setrexmt __P((int, char **));
959b50d902SRodney W. Grimes void	settimeout __P((int, char **));
969b50d902SRodney W. Grimes void	settrace __P((int, char **));
979b50d902SRodney W. Grimes void	setverbose __P((int, char **));
989b50d902SRodney W. Grimes void	status __P((int, char **));
999b50d902SRodney W. Grimes 
100eaa86f9dSBruce Evans static void command __P((void)) __dead2;
1019b50d902SRodney W. Grimes 
1029b50d902SRodney W. Grimes static void getusage __P((char *));
1039b50d902SRodney W. Grimes static void makeargv __P((void));
1049b50d902SRodney W. Grimes static void putusage __P((char *));
1059b50d902SRodney W. Grimes static void settftpmode __P((char *));
1069b50d902SRodney W. Grimes 
1079b50d902SRodney W. Grimes #define HELPINDENT (sizeof("connect"))
1089b50d902SRodney W. Grimes 
1099b50d902SRodney W. Grimes struct cmd {
1109b50d902SRodney W. Grimes 	char	*name;
1119b50d902SRodney W. Grimes 	char	*help;
1129b50d902SRodney W. Grimes 	void	(*handler) __P((int, char **));
1139b50d902SRodney W. Grimes };
1149b50d902SRodney W. Grimes 
1159b50d902SRodney W. Grimes char	vhelp[] = "toggle verbose mode";
1169b50d902SRodney W. Grimes char	thelp[] = "toggle packet tracing";
1179b50d902SRodney W. Grimes char	chelp[] = "connect to remote tftp";
1189b50d902SRodney W. Grimes char	qhelp[] = "exit tftp";
1199b50d902SRodney W. Grimes char	hhelp[] = "print help information";
1209b50d902SRodney W. Grimes char	shelp[] = "send file";
1219b50d902SRodney W. Grimes char	rhelp[] = "receive file";
1229b50d902SRodney W. Grimes char	mhelp[] = "set file transfer mode";
1239b50d902SRodney W. Grimes char	sthelp[] = "show current status";
1249b50d902SRodney W. Grimes char	xhelp[] = "set per-packet retransmission timeout";
1259b50d902SRodney W. Grimes char	ihelp[] = "set total retransmission timeout";
1269b50d902SRodney W. Grimes char    ashelp[] = "set mode to netascii";
1279b50d902SRodney W. Grimes char    bnhelp[] = "set mode to octet";
1289b50d902SRodney W. Grimes 
1299b50d902SRodney W. Grimes struct cmd cmdtab[] = {
1309b50d902SRodney W. Grimes 	{ "connect",	chelp,		setpeer },
1319b50d902SRodney W. Grimes 	{ "mode",       mhelp,          modecmd },
1329b50d902SRodney W. Grimes 	{ "put",	shelp,		put },
1339b50d902SRodney W. Grimes 	{ "get",	rhelp,		get },
1349b50d902SRodney W. Grimes 	{ "quit",	qhelp,		quit },
1359b50d902SRodney W. Grimes 	{ "verbose",	vhelp,		setverbose },
1369b50d902SRodney W. Grimes 	{ "trace",	thelp,		settrace },
1379b50d902SRodney W. Grimes 	{ "status",	sthelp,		status },
1389b50d902SRodney W. Grimes 	{ "binary",     bnhelp,         setbinary },
1399b50d902SRodney W. Grimes 	{ "ascii",      ashelp,         setascii },
1409b50d902SRodney W. Grimes 	{ "rexmt",	xhelp,		setrexmt },
1419b50d902SRodney W. Grimes 	{ "timeout",	ihelp,		settimeout },
1429b50d902SRodney W. Grimes 	{ "?",		hhelp,		help },
1439b50d902SRodney W. Grimes 	{ 0 }
1449b50d902SRodney W. Grimes };
1459b50d902SRodney W. Grimes 
1469b50d902SRodney W. Grimes struct	cmd *getcmd();
1479b50d902SRodney W. Grimes char	*tail();
1489b50d902SRodney W. Grimes char	*index();
1499b50d902SRodney W. Grimes char	*rindex();
1509b50d902SRodney W. Grimes 
1519b50d902SRodney W. Grimes int
1529b50d902SRodney W. Grimes main(argc, argv)
1539b50d902SRodney W. Grimes 	int argc;
1549b50d902SRodney W. Grimes 	char *argv[];
1559b50d902SRodney W. Grimes {
1569b50d902SRodney W. Grimes 	struct sockaddr_in sin;
1579b50d902SRodney W. Grimes 
1589b50d902SRodney W. Grimes 	sp = getservbyname("tftp", "udp");
1599b50d902SRodney W. Grimes 	if (sp == 0) {
1609b50d902SRodney W. Grimes 		fprintf(stderr, "tftp: udp/tftp: unknown service\n");
1619b50d902SRodney W. Grimes 		exit(1);
1629b50d902SRodney W. Grimes 	}
1639b50d902SRodney W. Grimes 	f = socket(AF_INET, SOCK_DGRAM, 0);
1649b50d902SRodney W. Grimes 	if (f < 0) {
1659b50d902SRodney W. Grimes 		perror("tftp: socket");
1669b50d902SRodney W. Grimes 		exit(3);
1679b50d902SRodney W. Grimes 	}
1689b50d902SRodney W. Grimes 	bzero((char *)&sin, sizeof(sin));
1699b50d902SRodney W. Grimes 	sin.sin_family = AF_INET;
1709b50d902SRodney W. Grimes 	if (bind(f, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
1719b50d902SRodney W. Grimes 		perror("tftp: bind");
1729b50d902SRodney W. Grimes 		exit(1);
1739b50d902SRodney W. Grimes 	}
1749b50d902SRodney W. Grimes 	strcpy(mode, "netascii");
1759b50d902SRodney W. Grimes 	signal(SIGINT, intr);
1769b50d902SRodney W. Grimes 	if (argc > 1) {
1779b50d902SRodney W. Grimes 		if (setjmp(toplevel) != 0)
1789b50d902SRodney W. Grimes 			exit(0);
1799b50d902SRodney W. Grimes 		setpeer(argc, argv);
1809b50d902SRodney W. Grimes 	}
1819b50d902SRodney W. Grimes 	if (setjmp(toplevel) != 0)
1829b50d902SRodney W. Grimes 		(void)putchar('\n');
1839b50d902SRodney W. Grimes 	command();
1849b50d902SRodney W. Grimes }
1859b50d902SRodney W. Grimes 
1869b50d902SRodney W. Grimes char    hostname[100];
1879b50d902SRodney W. Grimes 
1889b50d902SRodney W. Grimes void
1899b50d902SRodney W. Grimes setpeer(argc, argv)
1909b50d902SRodney W. Grimes 	int argc;
1919b50d902SRodney W. Grimes 	char *argv[];
1929b50d902SRodney W. Grimes {
1939b50d902SRodney W. Grimes 	struct hostent *host;
1949b50d902SRodney W. Grimes 
1959b50d902SRodney W. Grimes 	if (argc < 2) {
1969b50d902SRodney W. Grimes 		strcpy(line, "Connect ");
1979b50d902SRodney W. Grimes 		printf("(to) ");
198ca22ff9eSJoerg Wunsch 		fgets(&line[strlen(line)], sizeof line - strlen(line), stdin);
1999b50d902SRodney W. Grimes 		makeargv();
2009b50d902SRodney W. Grimes 		argc = margc;
2019b50d902SRodney W. Grimes 		argv = margv;
2029b50d902SRodney W. Grimes 	}
2039b50d902SRodney W. Grimes 	if (argc > 3) {
2049b50d902SRodney W. Grimes 		printf("usage: %s host-name [port]\n", argv[0]);
2059b50d902SRodney W. Grimes 		return;
2069b50d902SRodney W. Grimes 	}
2079b50d902SRodney W. Grimes 	host = gethostbyname(argv[1]);
2089b50d902SRodney W. Grimes 	if (host) {
2099b50d902SRodney W. Grimes 		peeraddr.sin_family = host->h_addrtype;
2109b50d902SRodney W. Grimes 		bcopy(host->h_addr, &peeraddr.sin_addr, host->h_length);
2119b50d902SRodney W. Grimes 		strcpy(hostname, host->h_name);
2129b50d902SRodney W. Grimes 	} else {
2139b50d902SRodney W. Grimes 		peeraddr.sin_family = AF_INET;
2149b50d902SRodney W. Grimes 		peeraddr.sin_addr.s_addr = inet_addr(argv[1]);
2159b50d902SRodney W. Grimes 		if (peeraddr.sin_addr.s_addr == -1) {
2169b50d902SRodney W. Grimes 			connected = 0;
2179b50d902SRodney W. Grimes 			printf("%s: unknown host\n", argv[1]);
2189b50d902SRodney W. Grimes 			return;
2199b50d902SRodney W. Grimes 		}
2209b50d902SRodney W. Grimes 		strcpy(hostname, argv[1]);
2219b50d902SRodney W. Grimes 	}
2229b50d902SRodney W. Grimes 	port = sp->s_port;
2239b50d902SRodney W. Grimes 	if (argc == 3) {
2249b50d902SRodney W. Grimes 		port = atoi(argv[2]);
2259b50d902SRodney W. Grimes 		if (port < 0) {
2269b50d902SRodney W. Grimes 			printf("%s: bad port number\n", argv[2]);
2279b50d902SRodney W. Grimes 			connected = 0;
2289b50d902SRodney W. Grimes 			return;
2299b50d902SRodney W. Grimes 		}
2309b50d902SRodney W. Grimes 		port = htons(port);
2319b50d902SRodney W. Grimes 	}
2329b50d902SRodney W. Grimes 	connected = 1;
2339b50d902SRodney W. Grimes }
2349b50d902SRodney W. Grimes 
2359b50d902SRodney W. Grimes struct	modes {
2369b50d902SRodney W. Grimes 	char *m_name;
2379b50d902SRodney W. Grimes 	char *m_mode;
2389b50d902SRodney W. Grimes } modes[] = {
2399b50d902SRodney W. Grimes 	{ "ascii",	"netascii" },
2409b50d902SRodney W. Grimes 	{ "netascii",   "netascii" },
2419b50d902SRodney W. Grimes 	{ "binary",     "octet" },
2429b50d902SRodney W. Grimes 	{ "image",      "octet" },
2439b50d902SRodney W. Grimes 	{ "octet",     "octet" },
2449b50d902SRodney W. Grimes /*      { "mail",       "mail" },       */
2459b50d902SRodney W. Grimes 	{ 0,		0 }
2469b50d902SRodney W. Grimes };
2479b50d902SRodney W. Grimes 
2489b50d902SRodney W. Grimes void
2499b50d902SRodney W. Grimes modecmd(argc, argv)
2509b50d902SRodney W. Grimes 	int argc;
2519b50d902SRodney W. Grimes 	char *argv[];
2529b50d902SRodney W. Grimes {
2539b50d902SRodney W. Grimes 	register struct modes *p;
2549b50d902SRodney W. Grimes 	char *sep;
2559b50d902SRodney W. Grimes 
2569b50d902SRodney W. Grimes 	if (argc < 2) {
2579b50d902SRodney W. Grimes 		printf("Using %s mode to transfer files.\n", mode);
2589b50d902SRodney W. Grimes 		return;
2599b50d902SRodney W. Grimes 	}
2609b50d902SRodney W. Grimes 	if (argc == 2) {
2619b50d902SRodney W. Grimes 		for (p = modes; p->m_name; p++)
2629b50d902SRodney W. Grimes 			if (strcmp(argv[1], p->m_name) == 0)
2639b50d902SRodney W. Grimes 				break;
2649b50d902SRodney W. Grimes 		if (p->m_name) {
2659b50d902SRodney W. Grimes 			settftpmode(p->m_mode);
2669b50d902SRodney W. Grimes 			return;
2679b50d902SRodney W. Grimes 		}
2689b50d902SRodney W. Grimes 		printf("%s: unknown mode\n", argv[1]);
2699b50d902SRodney W. Grimes 		/* drop through and print usage message */
2709b50d902SRodney W. Grimes 	}
2719b50d902SRodney W. Grimes 
2729b50d902SRodney W. Grimes 	printf("usage: %s [", argv[0]);
2739b50d902SRodney W. Grimes 	sep = " ";
2749b50d902SRodney W. Grimes 	for (p = modes; p->m_name; p++) {
2759b50d902SRodney W. Grimes 		printf("%s%s", sep, p->m_name);
2769b50d902SRodney W. Grimes 		if (*sep == ' ')
2779b50d902SRodney W. Grimes 			sep = " | ";
2789b50d902SRodney W. Grimes 	}
2799b50d902SRodney W. Grimes 	printf(" ]\n");
2809b50d902SRodney W. Grimes 	return;
2819b50d902SRodney W. Grimes }
2829b50d902SRodney W. Grimes 
2839b50d902SRodney W. Grimes void
2849b50d902SRodney W. Grimes setbinary(argc, argv)
2859b50d902SRodney W. Grimes 	int argc;
2869b50d902SRodney W. Grimes 	char *argv[];
2879b50d902SRodney W. Grimes {
2889b50d902SRodney W. Grimes 
2899b50d902SRodney W. Grimes 	settftpmode("octet");
2909b50d902SRodney W. Grimes }
2919b50d902SRodney W. Grimes 
2929b50d902SRodney W. Grimes void
2939b50d902SRodney W. Grimes setascii(argc, argv)
2949b50d902SRodney W. Grimes 	int argc;
2959b50d902SRodney W. Grimes 	char *argv[];
2969b50d902SRodney W. Grimes {
2979b50d902SRodney W. Grimes 
2989b50d902SRodney W. Grimes 	settftpmode("netascii");
2999b50d902SRodney W. Grimes }
3009b50d902SRodney W. Grimes 
3019b50d902SRodney W. Grimes static void
3029b50d902SRodney W. Grimes settftpmode(newmode)
3039b50d902SRodney W. Grimes 	char *newmode;
3049b50d902SRodney W. Grimes {
3059b50d902SRodney W. Grimes 	strcpy(mode, newmode);
3069b50d902SRodney W. Grimes 	if (verbose)
3079b50d902SRodney W. Grimes 		printf("mode set to %s\n", mode);
3089b50d902SRodney W. Grimes }
3099b50d902SRodney W. Grimes 
3109b50d902SRodney W. Grimes 
3119b50d902SRodney W. Grimes /*
3129b50d902SRodney W. Grimes  * Send file(s).
3139b50d902SRodney W. Grimes  */
3149b50d902SRodney W. Grimes void
3159b50d902SRodney W. Grimes put(argc, argv)
3169b50d902SRodney W. Grimes 	int argc;
3179b50d902SRodney W. Grimes 	char *argv[];
3189b50d902SRodney W. Grimes {
3199b50d902SRodney W. Grimes 	int fd;
3209b50d902SRodney W. Grimes 	register int n;
3219b50d902SRodney W. Grimes 	register char *cp, *targ;
3229b50d902SRodney W. Grimes 
3239b50d902SRodney W. Grimes 	if (argc < 2) {
3249b50d902SRodney W. Grimes 		strcpy(line, "send ");
3259b50d902SRodney W. Grimes 		printf("(file) ");
326ca22ff9eSJoerg Wunsch 		fgets(&line[strlen(line)], sizeof line - strlen(line), stdin);
3279b50d902SRodney W. Grimes 		makeargv();
3289b50d902SRodney W. Grimes 		argc = margc;
3299b50d902SRodney W. Grimes 		argv = margv;
3309b50d902SRodney W. Grimes 	}
3319b50d902SRodney W. Grimes 	if (argc < 2) {
3329b50d902SRodney W. Grimes 		putusage(argv[0]);
3339b50d902SRodney W. Grimes 		return;
3349b50d902SRodney W. Grimes 	}
3359b50d902SRodney W. Grimes 	targ = argv[argc - 1];
3369b50d902SRodney W. Grimes 	if (index(argv[argc - 1], ':')) {
3379b50d902SRodney W. Grimes 		char *cp;
3389b50d902SRodney W. Grimes 		struct hostent *hp;
3399b50d902SRodney W. Grimes 
3409b50d902SRodney W. Grimes 		for (n = 1; n < argc - 1; n++)
3419b50d902SRodney W. Grimes 			if (index(argv[n], ':')) {
3429b50d902SRodney W. Grimes 				putusage(argv[0]);
3439b50d902SRodney W. Grimes 				return;
3449b50d902SRodney W. Grimes 			}
3459b50d902SRodney W. Grimes 		cp = argv[argc - 1];
3469b50d902SRodney W. Grimes 		targ = index(cp, ':');
3479b50d902SRodney W. Grimes 		*targ++ = 0;
3489b50d902SRodney W. Grimes 		hp = gethostbyname(cp);
3499b50d902SRodney W. Grimes 		if (hp == NULL) {
3509b50d902SRodney W. Grimes 			fprintf(stderr, "tftp: %s: ", cp);
3519b50d902SRodney W. Grimes 			herror((char *)NULL);
3529b50d902SRodney W. Grimes 			return;
3539b50d902SRodney W. Grimes 		}
3549b50d902SRodney W. Grimes 		bcopy(hp->h_addr, (caddr_t)&peeraddr.sin_addr, hp->h_length);
3559b50d902SRodney W. Grimes 		peeraddr.sin_family = hp->h_addrtype;
3569b50d902SRodney W. Grimes 		connected = 1;
3579b50d902SRodney W. Grimes 		strcpy(hostname, hp->h_name);
3589b50d902SRodney W. Grimes 	}
3599b50d902SRodney W. Grimes 	if (!connected) {
3609b50d902SRodney W. Grimes 		printf("No target machine specified.\n");
3619b50d902SRodney W. Grimes 		return;
3629b50d902SRodney W. Grimes 	}
3639b50d902SRodney W. Grimes 	if (argc < 4) {
3649b50d902SRodney W. Grimes 		cp = argc == 2 ? tail(targ) : argv[1];
3659b50d902SRodney W. Grimes 		fd = open(cp, O_RDONLY);
3669b50d902SRodney W. Grimes 		if (fd < 0) {
3679b50d902SRodney W. Grimes 			fprintf(stderr, "tftp: "); perror(cp);
3689b50d902SRodney W. Grimes 			return;
3699b50d902SRodney W. Grimes 		}
3709b50d902SRodney W. Grimes 		if (verbose)
3719b50d902SRodney W. Grimes 			printf("putting %s to %s:%s [%s]\n",
3729b50d902SRodney W. Grimes 				cp, hostname, targ, mode);
3739b50d902SRodney W. Grimes 		peeraddr.sin_port = port;
3749b50d902SRodney W. Grimes 		sendfile(fd, targ, mode);
3759b50d902SRodney W. Grimes 		return;
3769b50d902SRodney W. Grimes 	}
3779b50d902SRodney W. Grimes 				/* this assumes the target is a directory */
3789b50d902SRodney W. Grimes 				/* on a remote unix system.  hmmmm.  */
3799b50d902SRodney W. Grimes 	cp = index(targ, '\0');
3809b50d902SRodney W. Grimes 	*cp++ = '/';
3819b50d902SRodney W. Grimes 	for (n = 1; n < argc - 1; n++) {
3829b50d902SRodney W. Grimes 		strcpy(cp, tail(argv[n]));
3839b50d902SRodney W. Grimes 		fd = open(argv[n], O_RDONLY);
3849b50d902SRodney W. Grimes 		if (fd < 0) {
3859b50d902SRodney W. Grimes 			fprintf(stderr, "tftp: "); perror(argv[n]);
3869b50d902SRodney W. Grimes 			continue;
3879b50d902SRodney W. Grimes 		}
3889b50d902SRodney W. Grimes 		if (verbose)
3899b50d902SRodney W. Grimes 			printf("putting %s to %s:%s [%s]\n",
3909b50d902SRodney W. Grimes 				argv[n], hostname, targ, mode);
3919b50d902SRodney W. Grimes 		peeraddr.sin_port = port;
3929b50d902SRodney W. Grimes 		sendfile(fd, targ, mode);
3939b50d902SRodney W. Grimes 	}
3949b50d902SRodney W. Grimes }
3959b50d902SRodney W. Grimes 
3969b50d902SRodney W. Grimes static void
3979b50d902SRodney W. Grimes putusage(s)
3989b50d902SRodney W. Grimes 	char *s;
3999b50d902SRodney W. Grimes {
4009b50d902SRodney W. Grimes 	printf("usage: %s file ... host:target, or\n", s);
4019b50d902SRodney W. Grimes 	printf("       %s file ... target (when already connected)\n", s);
4029b50d902SRodney W. Grimes }
4039b50d902SRodney W. Grimes 
4049b50d902SRodney W. Grimes /*
4059b50d902SRodney W. Grimes  * Receive file(s).
4069b50d902SRodney W. Grimes  */
4079b50d902SRodney W. Grimes void
4089b50d902SRodney W. Grimes get(argc, argv)
4099b50d902SRodney W. Grimes 	int argc;
4109b50d902SRodney W. Grimes 	char *argv[];
4119b50d902SRodney W. Grimes {
4129b50d902SRodney W. Grimes 	int fd;
4139b50d902SRodney W. Grimes 	register int n;
4149b50d902SRodney W. Grimes 	register char *cp;
4159b50d902SRodney W. Grimes 	char *src;
4169b50d902SRodney W. Grimes 
4179b50d902SRodney W. Grimes 	if (argc < 2) {
4189b50d902SRodney W. Grimes 		strcpy(line, "get ");
4199b50d902SRodney W. Grimes 		printf("(files) ");
420ca22ff9eSJoerg Wunsch 		fgets(&line[strlen(line)], sizeof line - strlen(line), stdin);
4219b50d902SRodney W. Grimes 		makeargv();
4229b50d902SRodney W. Grimes 		argc = margc;
4239b50d902SRodney W. Grimes 		argv = margv;
4249b50d902SRodney W. Grimes 	}
4259b50d902SRodney W. Grimes 	if (argc < 2) {
4269b50d902SRodney W. Grimes 		getusage(argv[0]);
4279b50d902SRodney W. Grimes 		return;
4289b50d902SRodney W. Grimes 	}
4299b50d902SRodney W. Grimes 	if (!connected) {
4309b50d902SRodney W. Grimes 		for (n = 1; n < argc ; n++)
4319b50d902SRodney W. Grimes 			if (index(argv[n], ':') == 0) {
4329b50d902SRodney W. Grimes 				getusage(argv[0]);
4339b50d902SRodney W. Grimes 				return;
4349b50d902SRodney W. Grimes 			}
4359b50d902SRodney W. Grimes 	}
4369b50d902SRodney W. Grimes 	for (n = 1; n < argc ; n++) {
4379b50d902SRodney W. Grimes 		src = index(argv[n], ':');
4389b50d902SRodney W. Grimes 		if (src == NULL)
4399b50d902SRodney W. Grimes 			src = argv[n];
4409b50d902SRodney W. Grimes 		else {
4419b50d902SRodney W. Grimes 			struct hostent *hp;
4429b50d902SRodney W. Grimes 
4439b50d902SRodney W. Grimes 			*src++ = 0;
4449b50d902SRodney W. Grimes 			hp = gethostbyname(argv[n]);
4459b50d902SRodney W. Grimes 			if (hp == NULL) {
4469b50d902SRodney W. Grimes 				fprintf(stderr, "tftp: %s: ", argv[n]);
4479b50d902SRodney W. Grimes 				herror((char *)NULL);
4489b50d902SRodney W. Grimes 				continue;
4499b50d902SRodney W. Grimes 			}
4509b50d902SRodney W. Grimes 			bcopy(hp->h_addr, (caddr_t)&peeraddr.sin_addr,
4519b50d902SRodney W. Grimes 			    hp->h_length);
4529b50d902SRodney W. Grimes 			peeraddr.sin_family = hp->h_addrtype;
4539b50d902SRodney W. Grimes 			connected = 1;
4549b50d902SRodney W. Grimes 			strcpy(hostname, hp->h_name);
4559b50d902SRodney W. Grimes 		}
4569b50d902SRodney W. Grimes 		if (argc < 4) {
4579b50d902SRodney W. Grimes 			cp = argc == 3 ? argv[2] : tail(src);
4589b50d902SRodney W. Grimes 			fd = creat(cp, 0644);
4599b50d902SRodney W. Grimes 			if (fd < 0) {
4609b50d902SRodney W. Grimes 				fprintf(stderr, "tftp: "); perror(cp);
4619b50d902SRodney W. Grimes 				return;
4629b50d902SRodney W. Grimes 			}
4639b50d902SRodney W. Grimes 			if (verbose)
4649b50d902SRodney W. Grimes 				printf("getting from %s:%s to %s [%s]\n",
4659b50d902SRodney W. Grimes 					hostname, src, cp, mode);
4669b50d902SRodney W. Grimes 			peeraddr.sin_port = port;
4679b50d902SRodney W. Grimes 			recvfile(fd, src, mode);
4689b50d902SRodney W. Grimes 			break;
4699b50d902SRodney W. Grimes 		}
4709b50d902SRodney W. Grimes 		cp = tail(src);         /* new .. jdg */
4719b50d902SRodney W. Grimes 		fd = creat(cp, 0644);
4729b50d902SRodney W. Grimes 		if (fd < 0) {
4739b50d902SRodney W. Grimes 			fprintf(stderr, "tftp: "); perror(cp);
4749b50d902SRodney W. Grimes 			continue;
4759b50d902SRodney W. Grimes 		}
4769b50d902SRodney W. Grimes 		if (verbose)
4779b50d902SRodney W. Grimes 			printf("getting from %s:%s to %s [%s]\n",
4789b50d902SRodney W. Grimes 				hostname, src, cp, mode);
4799b50d902SRodney W. Grimes 		peeraddr.sin_port = port;
4809b50d902SRodney W. Grimes 		recvfile(fd, src, mode);
4819b50d902SRodney W. Grimes 	}
4829b50d902SRodney W. Grimes }
4839b50d902SRodney W. Grimes 
4849b50d902SRodney W. Grimes static void
4859b50d902SRodney W. Grimes getusage(s)
4869b50d902SRodney W. Grimes 	char *s;
4879b50d902SRodney W. Grimes {
4889b50d902SRodney W. Grimes 	printf("usage: %s host:file host:file ... file, or\n", s);
4899b50d902SRodney W. Grimes 	printf("       %s file file ... file if connected\n", s);
4909b50d902SRodney W. Grimes }
4919b50d902SRodney W. Grimes 
4929b50d902SRodney W. Grimes int	rexmtval = TIMEOUT;
4939b50d902SRodney W. Grimes 
4949b50d902SRodney W. Grimes void
4959b50d902SRodney W. Grimes setrexmt(argc, argv)
4969b50d902SRodney W. Grimes 	int argc;
4979b50d902SRodney W. Grimes 	char *argv[];
4989b50d902SRodney W. Grimes {
4999b50d902SRodney W. Grimes 	int t;
5009b50d902SRodney W. Grimes 
5019b50d902SRodney W. Grimes 	if (argc < 2) {
5029b50d902SRodney W. Grimes 		strcpy(line, "Rexmt-timeout ");
5039b50d902SRodney W. Grimes 		printf("(value) ");
504ca22ff9eSJoerg Wunsch 		fgets(&line[strlen(line)], sizeof line - strlen(line), stdin);
5059b50d902SRodney W. Grimes 		makeargv();
5069b50d902SRodney W. Grimes 		argc = margc;
5079b50d902SRodney W. Grimes 		argv = margv;
5089b50d902SRodney W. Grimes 	}
5099b50d902SRodney W. Grimes 	if (argc != 2) {
5109b50d902SRodney W. Grimes 		printf("usage: %s value\n", argv[0]);
5119b50d902SRodney W. Grimes 		return;
5129b50d902SRodney W. Grimes 	}
5139b50d902SRodney W. Grimes 	t = atoi(argv[1]);
5149b50d902SRodney W. Grimes 	if (t < 0)
5159b50d902SRodney W. Grimes 		printf("%s: bad value\n", argv[1]);
5169b50d902SRodney W. Grimes 	else
5179b50d902SRodney W. Grimes 		rexmtval = t;
5189b50d902SRodney W. Grimes }
5199b50d902SRodney W. Grimes 
5209b50d902SRodney W. Grimes int	maxtimeout = 5 * TIMEOUT;
5219b50d902SRodney W. Grimes 
5229b50d902SRodney W. Grimes void
5239b50d902SRodney W. Grimes settimeout(argc, argv)
5249b50d902SRodney W. Grimes 	int argc;
5259b50d902SRodney W. Grimes 	char *argv[];
5269b50d902SRodney W. Grimes {
5279b50d902SRodney W. Grimes 	int t;
5289b50d902SRodney W. Grimes 
5299b50d902SRodney W. Grimes 	if (argc < 2) {
5309b50d902SRodney W. Grimes 		strcpy(line, "Maximum-timeout ");
5319b50d902SRodney W. Grimes 		printf("(value) ");
532ca22ff9eSJoerg Wunsch 		fgets(&line[strlen(line)], sizeof line - strlen(line), stdin);
5339b50d902SRodney W. Grimes 		makeargv();
5349b50d902SRodney W. Grimes 		argc = margc;
5359b50d902SRodney W. Grimes 		argv = margv;
5369b50d902SRodney W. Grimes 	}
5379b50d902SRodney W. Grimes 	if (argc != 2) {
5389b50d902SRodney W. Grimes 		printf("usage: %s value\n", argv[0]);
5399b50d902SRodney W. Grimes 		return;
5409b50d902SRodney W. Grimes 	}
5419b50d902SRodney W. Grimes 	t = atoi(argv[1]);
5429b50d902SRodney W. Grimes 	if (t < 0)
5439b50d902SRodney W. Grimes 		printf("%s: bad value\n", argv[1]);
5449b50d902SRodney W. Grimes 	else
5459b50d902SRodney W. Grimes 		maxtimeout = t;
5469b50d902SRodney W. Grimes }
5479b50d902SRodney W. Grimes 
5489b50d902SRodney W. Grimes void
5499b50d902SRodney W. Grimes status(argc, argv)
5509b50d902SRodney W. Grimes 	int argc;
5519b50d902SRodney W. Grimes 	char *argv[];
5529b50d902SRodney W. Grimes {
5539b50d902SRodney W. Grimes 	if (connected)
5549b50d902SRodney W. Grimes 		printf("Connected to %s.\n", hostname);
5559b50d902SRodney W. Grimes 	else
5569b50d902SRodney W. Grimes 		printf("Not connected.\n");
5579b50d902SRodney W. Grimes 	printf("Mode: %s Verbose: %s Tracing: %s\n", mode,
5589b50d902SRodney W. Grimes 		verbose ? "on" : "off", trace ? "on" : "off");
5599b50d902SRodney W. Grimes 	printf("Rexmt-interval: %d seconds, Max-timeout: %d seconds\n",
5609b50d902SRodney W. Grimes 		rexmtval, maxtimeout);
5619b50d902SRodney W. Grimes }
5629b50d902SRodney W. Grimes 
5639b50d902SRodney W. Grimes void
5649b50d902SRodney W. Grimes intr()
5659b50d902SRodney W. Grimes {
5669b50d902SRodney W. Grimes 
5679b50d902SRodney W. Grimes 	signal(SIGALRM, SIG_IGN);
5689b50d902SRodney W. Grimes 	alarm(0);
5699b50d902SRodney W. Grimes 	longjmp(toplevel, -1);
5709b50d902SRodney W. Grimes }
5719b50d902SRodney W. Grimes 
5729b50d902SRodney W. Grimes char *
5739b50d902SRodney W. Grimes tail(filename)
5749b50d902SRodney W. Grimes 	char *filename;
5759b50d902SRodney W. Grimes {
5769b50d902SRodney W. Grimes 	register char *s;
5779b50d902SRodney W. Grimes 
5789b50d902SRodney W. Grimes 	while (*filename) {
5799b50d902SRodney W. Grimes 		s = rindex(filename, '/');
5809b50d902SRodney W. Grimes 		if (s == NULL)
5819b50d902SRodney W. Grimes 			break;
5829b50d902SRodney W. Grimes 		if (s[1])
5839b50d902SRodney W. Grimes 			return (s + 1);
5849b50d902SRodney W. Grimes 		*s = '\0';
5859b50d902SRodney W. Grimes 	}
5869b50d902SRodney W. Grimes 	return (filename);
5879b50d902SRodney W. Grimes }
5889b50d902SRodney W. Grimes 
5899b50d902SRodney W. Grimes /*
5909b50d902SRodney W. Grimes  * Command parser.
5919b50d902SRodney W. Grimes  */
592eaa86f9dSBruce Evans static void
5939b50d902SRodney W. Grimes command()
5949b50d902SRodney W. Grimes {
5959b50d902SRodney W. Grimes 	register struct cmd *c;
596ca22ff9eSJoerg Wunsch 	char *cp;
5979b50d902SRodney W. Grimes 
5989b50d902SRodney W. Grimes 	for (;;) {
5999b50d902SRodney W. Grimes 		printf("%s> ", prompt);
600ca22ff9eSJoerg Wunsch 		if (fgets(line, sizeof line , stdin) == 0) {
6019b50d902SRodney W. Grimes 			if (feof(stdin)) {
6029b50d902SRodney W. Grimes 				exit(0);
6039b50d902SRodney W. Grimes 			} else {
6049b50d902SRodney W. Grimes 				continue;
6059b50d902SRodney W. Grimes 			}
6069b50d902SRodney W. Grimes 		}
607ca22ff9eSJoerg Wunsch 		if ((cp = strchr(line, '\n')))
608ca22ff9eSJoerg Wunsch 			*cp = '\0';
6099b50d902SRodney W. Grimes 		if (line[0] == 0)
6109b50d902SRodney W. Grimes 			continue;
6119b50d902SRodney W. Grimes 		makeargv();
6129b50d902SRodney W. Grimes 		if (margc == 0)
6139b50d902SRodney W. Grimes 			continue;
6149b50d902SRodney W. Grimes 		c = getcmd(margv[0]);
6159b50d902SRodney W. Grimes 		if (c == (struct cmd *)-1) {
6169b50d902SRodney W. Grimes 			printf("?Ambiguous command\n");
6179b50d902SRodney W. Grimes 			continue;
6189b50d902SRodney W. Grimes 		}
6199b50d902SRodney W. Grimes 		if (c == 0) {
6209b50d902SRodney W. Grimes 			printf("?Invalid command\n");
6219b50d902SRodney W. Grimes 			continue;
6229b50d902SRodney W. Grimes 		}
6239b50d902SRodney W. Grimes 		(*c->handler)(margc, margv);
6249b50d902SRodney W. Grimes 	}
6259b50d902SRodney W. Grimes }
6269b50d902SRodney W. Grimes 
6279b50d902SRodney W. Grimes struct cmd *
6289b50d902SRodney W. Grimes getcmd(name)
6299b50d902SRodney W. Grimes 	register char *name;
6309b50d902SRodney W. Grimes {
6319b50d902SRodney W. Grimes 	register char *p, *q;
6329b50d902SRodney W. Grimes 	register struct cmd *c, *found;
6339b50d902SRodney W. Grimes 	register int nmatches, longest;
6349b50d902SRodney W. Grimes 
6359b50d902SRodney W. Grimes 	longest = 0;
6369b50d902SRodney W. Grimes 	nmatches = 0;
6379b50d902SRodney W. Grimes 	found = 0;
6389b50d902SRodney W. Grimes 	for (c = cmdtab; (p = c->name) != NULL; c++) {
6399b50d902SRodney W. Grimes 		for (q = name; *q == *p++; q++)
6409b50d902SRodney W. Grimes 			if (*q == 0)		/* exact match? */
6419b50d902SRodney W. Grimes 				return (c);
6429b50d902SRodney W. Grimes 		if (!*q) {			/* the name was a prefix */
6439b50d902SRodney W. Grimes 			if (q - name > longest) {
6449b50d902SRodney W. Grimes 				longest = q - name;
6459b50d902SRodney W. Grimes 				nmatches = 1;
6469b50d902SRodney W. Grimes 				found = c;
6479b50d902SRodney W. Grimes 			} else if (q - name == longest)
6489b50d902SRodney W. Grimes 				nmatches++;
6499b50d902SRodney W. Grimes 		}
6509b50d902SRodney W. Grimes 	}
6519b50d902SRodney W. Grimes 	if (nmatches > 1)
6529b50d902SRodney W. Grimes 		return ((struct cmd *)-1);
6539b50d902SRodney W. Grimes 	return (found);
6549b50d902SRodney W. Grimes }
6559b50d902SRodney W. Grimes 
6569b50d902SRodney W. Grimes /*
6579b50d902SRodney W. Grimes  * Slice a string up into argc/argv.
6589b50d902SRodney W. Grimes  */
6599b50d902SRodney W. Grimes static void
6609b50d902SRodney W. Grimes makeargv()
6619b50d902SRodney W. Grimes {
6629b50d902SRodney W. Grimes 	register char *cp;
6639b50d902SRodney W. Grimes 	register char **argp = margv;
6649b50d902SRodney W. Grimes 
6659b50d902SRodney W. Grimes 	margc = 0;
666ca22ff9eSJoerg Wunsch 	if ((cp = strchr(line, '\n')))
667ca22ff9eSJoerg Wunsch 		*cp = '\0';
6689b50d902SRodney W. Grimes 	for (cp = line; *cp;) {
6699b50d902SRodney W. Grimes 		while (isspace(*cp))
6709b50d902SRodney W. Grimes 			cp++;
6719b50d902SRodney W. Grimes 		if (*cp == '\0')
6729b50d902SRodney W. Grimes 			break;
6739b50d902SRodney W. Grimes 		*argp++ = cp;
6749b50d902SRodney W. Grimes 		margc += 1;
6759b50d902SRodney W. Grimes 		while (*cp != '\0' && !isspace(*cp))
6769b50d902SRodney W. Grimes 			cp++;
6779b50d902SRodney W. Grimes 		if (*cp == '\0')
6789b50d902SRodney W. Grimes 			break;
6799b50d902SRodney W. Grimes 		*cp++ = '\0';
6809b50d902SRodney W. Grimes 	}
6819b50d902SRodney W. Grimes 	*argp++ = 0;
6829b50d902SRodney W. Grimes }
6839b50d902SRodney W. Grimes 
6849b50d902SRodney W. Grimes void
6859b50d902SRodney W. Grimes quit(argc, argv)
6869b50d902SRodney W. Grimes 	int argc;
6879b50d902SRodney W. Grimes 	char *argv[];
6889b50d902SRodney W. Grimes {
6899b50d902SRodney W. Grimes 
6909b50d902SRodney W. Grimes 	exit(0);
6919b50d902SRodney W. Grimes }
6929b50d902SRodney W. Grimes 
6939b50d902SRodney W. Grimes /*
6949b50d902SRodney W. Grimes  * Help command.
6959b50d902SRodney W. Grimes  */
6969b50d902SRodney W. Grimes void
6979b50d902SRodney W. Grimes help(argc, argv)
6989b50d902SRodney W. Grimes 	int argc;
6999b50d902SRodney W. Grimes 	char *argv[];
7009b50d902SRodney W. Grimes {
7019b50d902SRodney W. Grimes 	register struct cmd *c;
7029b50d902SRodney W. Grimes 
7039b50d902SRodney W. Grimes 	if (argc == 1) {
7049b50d902SRodney W. Grimes 		printf("Commands may be abbreviated.  Commands are:\n\n");
7059b50d902SRodney W. Grimes 		for (c = cmdtab; c->name; c++)
7069b50d902SRodney W. Grimes 			printf("%-*s\t%s\n", (int)HELPINDENT, c->name, c->help);
7079b50d902SRodney W. Grimes 		return;
7089b50d902SRodney W. Grimes 	}
7099b50d902SRodney W. Grimes 	while (--argc > 0) {
7109b50d902SRodney W. Grimes 		register char *arg;
7119b50d902SRodney W. Grimes 		arg = *++argv;
7129b50d902SRodney W. Grimes 		c = getcmd(arg);
7139b50d902SRodney W. Grimes 		if (c == (struct cmd *)-1)
7149b50d902SRodney W. Grimes 			printf("?Ambiguous help command %s\n", arg);
7159b50d902SRodney W. Grimes 		else if (c == (struct cmd *)0)
7169b50d902SRodney W. Grimes 			printf("?Invalid help command %s\n", arg);
7179b50d902SRodney W. Grimes 		else
7189b50d902SRodney W. Grimes 			printf("%s\n", c->help);
7199b50d902SRodney W. Grimes 	}
7209b50d902SRodney W. Grimes }
7219b50d902SRodney W. Grimes 
7229b50d902SRodney W. Grimes void
7239b50d902SRodney W. Grimes settrace(argc, argv)
7249b50d902SRodney W. Grimes 	int argc;
7259b50d902SRodney W. Grimes 	char **argv;
7269b50d902SRodney W. Grimes {
7279b50d902SRodney W. Grimes 	trace = !trace;
7289b50d902SRodney W. Grimes 	printf("Packet tracing %s.\n", trace ? "on" : "off");
7299b50d902SRodney W. Grimes }
7309b50d902SRodney W. Grimes 
7319b50d902SRodney W. Grimes void
7329b50d902SRodney W. Grimes setverbose(argc, argv)
7339b50d902SRodney W. Grimes 	int argc;
7349b50d902SRodney W. Grimes 	char **argv;
7359b50d902SRodney W. Grimes {
7369b50d902SRodney W. Grimes 	verbose = !verbose;
7379b50d902SRodney W. Grimes 	printf("Verbose mode %s.\n", verbose ? "on" : "off");
7389b50d902SRodney W. Grimes }
739