Home | History | Annotate | Line # | Download | only in tftp
main.c revision 1.25.18.1
      1  1.25.18.1  wrstuden /*	$NetBSD: main.c,v 1.25.18.1 2008/09/18 04:29:22 wrstuden Exp $	*/
      2        1.5       jtc 
      3        1.1       cgd /*
      4        1.5       jtc  * Copyright (c) 1983, 1993
      5        1.5       jtc  *	The Regents of the University of California.  All rights reserved.
      6        1.1       cgd  *
      7        1.1       cgd  * Redistribution and use in source and binary forms, with or without
      8        1.1       cgd  * modification, are permitted provided that the following conditions
      9        1.1       cgd  * are met:
     10        1.1       cgd  * 1. Redistributions of source code must retain the above copyright
     11        1.1       cgd  *    notice, this list of conditions and the following disclaimer.
     12        1.1       cgd  * 2. Redistributions in binary form must reproduce the above copyright
     13        1.1       cgd  *    notice, this list of conditions and the following disclaimer in the
     14        1.1       cgd  *    documentation and/or other materials provided with the distribution.
     15       1.17       agc  * 3. Neither the name of the University nor the names of its contributors
     16        1.1       cgd  *    may be used to endorse or promote products derived from this software
     17        1.1       cgd  *    without specific prior written permission.
     18        1.1       cgd  *
     19        1.1       cgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     20        1.1       cgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     21        1.1       cgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     22        1.1       cgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     23        1.1       cgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     24        1.1       cgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     25        1.1       cgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     26        1.1       cgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     27        1.1       cgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     28        1.1       cgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     29        1.1       cgd  * SUCH DAMAGE.
     30        1.1       cgd  */
     31        1.1       cgd 
     32        1.8       mrg #include <sys/cdefs.h>
     33        1.1       cgd #ifndef lint
     34  1.25.18.1  wrstuden __COPYRIGHT("@(#) Copyright (c) 1983, 1993\
     35  1.25.18.1  wrstuden  The Regents of the University of California.  All rights reserved.");
     36        1.5       jtc #if 0
     37        1.5       jtc static char sccsid[] = "@(#)main.c	8.1 (Berkeley) 6/6/93";
     38        1.8       mrg #else
     39  1.25.18.1  wrstuden __RCSID("$NetBSD: main.c,v 1.25.18.1 2008/09/18 04:29:22 wrstuden Exp $");
     40        1.5       jtc #endif
     41        1.1       cgd #endif /* not lint */
     42        1.1       cgd 
     43        1.1       cgd /* Many bug fixes are from Jim Guyton <guyton@rand-unix> */
     44        1.1       cgd 
     45        1.1       cgd /*
     46        1.1       cgd  * TFTP User Program -- Command Interface.
     47        1.1       cgd  */
     48        1.1       cgd #include <sys/types.h>
     49        1.1       cgd #include <sys/socket.h>
     50        1.1       cgd 
     51        1.1       cgd #include <netinet/in.h>
     52        1.1       cgd 
     53        1.5       jtc #include <arpa/inet.h>
     54       1.15    briggs #include <arpa/tftp.h>
     55        1.5       jtc 
     56        1.5       jtc #include <ctype.h>
     57       1.10  christos #include <fcntl.h>
     58        1.9     lukem #include <err.h>
     59        1.5       jtc #include <errno.h>
     60        1.5       jtc #include <netdb.h>
     61        1.5       jtc #include <setjmp.h>
     62        1.1       cgd #include <signal.h>
     63        1.1       cgd #include <stdio.h>
     64        1.5       jtc #include <stdlib.h>
     65        1.5       jtc #include <string.h>
     66        1.5       jtc #include <unistd.h>
     67        1.5       jtc 
     68        1.5       jtc #include "extern.h"
     69        1.1       cgd 
     70        1.1       cgd #define	TIMEOUT		5		/* secs between rexmt's */
     71        1.4       cgd #define	LBUFLEN		200		/* size of input buffer */
     72        1.1       cgd 
     73       1.11    itojun struct	sockaddr_storage peeraddr;
     74        1.1       cgd int	f;
     75       1.24  jmcneill int	mf;
     76        1.1       cgd int	trace;
     77        1.1       cgd int	verbose;
     78       1.15    briggs int	tsize=0;
     79       1.15    briggs int	tout=0;
     80       1.21  christos size_t	def_blksize=SEGSIZE;
     81       1.21  christos size_t	blksize=SEGSIZE;
     82       1.24  jmcneill in_addr_t	mcaddr = INADDR_NONE;
     83       1.24  jmcneill uint16_t	mcport;
     84       1.24  jmcneill ushort	mcmasterslave;
     85        1.1       cgd int	connected;
     86        1.1       cgd char	mode[32];
     87        1.4       cgd char	line[LBUFLEN];
     88        1.1       cgd int	margc;
     89        1.1       cgd char	*margv[20];
     90       1.20      ross const	char *prompt = "tftp";
     91        1.1       cgd jmp_buf	toplevel;
     92        1.1       cgd 
     93        1.5       jtc void	get __P((int, char **));
     94        1.5       jtc void	help __P((int, char **));
     95        1.5       jtc void	modecmd __P((int, char **));
     96        1.5       jtc void	put __P((int, char **));
     97        1.5       jtc void	quit __P((int, char **));
     98        1.5       jtc void	setascii __P((int, char **));
     99        1.5       jtc void	setbinary __P((int, char **));
    100       1.20      ross void	setpeer0 __P((const char *, const char *));
    101        1.5       jtc void	setpeer __P((int, char **));
    102        1.5       jtc void	setrexmt __P((int, char **));
    103        1.5       jtc void	settimeout __P((int, char **));
    104        1.5       jtc void	settrace __P((int, char **));
    105        1.5       jtc void	setverbose __P((int, char **));
    106       1.15    briggs void	setblksize __P((int, char **));
    107       1.15    briggs void	settsize __P((int, char **));
    108       1.15    briggs void	settimeoutopt __P((int, char **));
    109        1.5       jtc void	status __P((int, char **));
    110        1.8       mrg char	*tail __P((char *));
    111        1.8       mrg int	main __P((int, char *[]));
    112        1.8       mrg void	intr __P((int));
    113       1.20      ross const	struct cmd *getcmd __P((char *));
    114        1.5       jtc 
    115        1.5       jtc static __dead void command __P((void));
    116        1.5       jtc 
    117        1.5       jtc static void getusage __P((char *));
    118        1.5       jtc static void makeargv __P((void));
    119        1.5       jtc static void putusage __P((char *));
    120       1.20      ross static void settftpmode __P((const char *));
    121        1.1       cgd 
    122        1.1       cgd #define HELPINDENT (sizeof("connect"))
    123        1.1       cgd 
    124        1.1       cgd struct cmd {
    125       1.20      ross 	const char *name;
    126       1.20      ross 	const char *help;
    127        1.5       jtc 	void	(*handler) __P((int, char **));
    128        1.1       cgd };
    129        1.1       cgd 
    130       1.20      ross const char vhelp[] = "toggle verbose mode";
    131       1.20      ross const char thelp[] = "toggle packet tracing";
    132       1.20      ross const char tshelp[] = "toggle extended tsize option";
    133       1.20      ross const char tohelp[] = "toggle extended timeout option";
    134       1.20      ross const char blhelp[] = "set an alternative blocksize (def. 512)";
    135       1.20      ross const char chelp[] = "connect to remote tftp";
    136       1.20      ross const char qhelp[] = "exit tftp";
    137       1.20      ross const char hhelp[] = "print help information";
    138       1.20      ross const char shelp[] = "send file";
    139       1.20      ross const char rhelp[] = "receive file";
    140       1.20      ross const char mhelp[] = "set file transfer mode";
    141       1.20      ross const char sthelp[] = "show current status";
    142       1.20      ross const char xhelp[] = "set per-packet retransmission timeout";
    143       1.20      ross const char ihelp[] = "set total retransmission timeout";
    144       1.20      ross const char ashelp[] = "set mode to netascii";
    145       1.20      ross const char bnhelp[] = "set mode to octet";
    146        1.1       cgd 
    147       1.20      ross const struct cmd cmdtab[] = {
    148        1.1       cgd 	{ "connect",	chelp,		setpeer },
    149        1.1       cgd 	{ "mode",       mhelp,          modecmd },
    150        1.1       cgd 	{ "put",	shelp,		put },
    151        1.1       cgd 	{ "get",	rhelp,		get },
    152        1.1       cgd 	{ "quit",	qhelp,		quit },
    153        1.1       cgd 	{ "verbose",	vhelp,		setverbose },
    154       1.15    briggs 	{ "blksize",	blhelp,		setblksize },
    155       1.15    briggs 	{ "tsize",	tshelp,		settsize },
    156        1.1       cgd 	{ "trace",	thelp,		settrace },
    157        1.1       cgd 	{ "status",	sthelp,		status },
    158        1.1       cgd 	{ "binary",     bnhelp,         setbinary },
    159        1.1       cgd 	{ "ascii",      ashelp,         setascii },
    160        1.1       cgd 	{ "rexmt",	xhelp,		setrexmt },
    161        1.1       cgd 	{ "timeout",	ihelp,		settimeout },
    162       1.15    briggs 	{ "tout",	tohelp,		settimeoutopt },
    163        1.1       cgd 	{ "?",		hhelp,		help },
    164       1.25  christos 	{ .name = NULL }
    165        1.1       cgd };
    166        1.1       cgd 
    167        1.5       jtc int
    168        1.1       cgd main(argc, argv)
    169        1.5       jtc 	int argc;
    170        1.1       cgd 	char *argv[];
    171        1.1       cgd {
    172       1.15    briggs 	int	c;
    173       1.15    briggs 
    174       1.24  jmcneill 	f = mf = -1;
    175       1.22  christos 	(void)strlcpy(mode, "netascii", sizeof(mode));
    176       1.22  christos 	(void)signal(SIGINT, intr);
    177       1.15    briggs 
    178       1.15    briggs 	setprogname(argv[0]);
    179       1.15    briggs 	while ((c = getopt(argc, argv, "e")) != -1) {
    180       1.15    briggs 		switch (c) {
    181       1.15    briggs 		case 'e':
    182       1.15    briggs 			blksize = MAXSEGSIZE;
    183       1.22  christos 			(void)strlcpy(mode, "octet", sizeof(mode));
    184       1.15    briggs 			tsize = 1;
    185       1.15    briggs 			tout = 1;
    186       1.15    briggs 			break;
    187       1.15    briggs 		default:
    188       1.22  christos 			(void)printf("usage: %s [-e] host-name [port]\n",
    189       1.15    briggs 				getprogname());
    190       1.15    briggs 			exit(1);
    191       1.15    briggs 		}
    192       1.15    briggs 	}
    193       1.15    briggs 	argc -= optind;
    194       1.15    briggs 	argv += optind;
    195       1.15    briggs 
    196       1.15    briggs 	if (argc >= 1) {
    197        1.1       cgd 		if (setjmp(toplevel) != 0)
    198        1.1       cgd 			exit(0);
    199       1.19    itojun 		argc++;
    200       1.19    itojun 		argv--;
    201        1.1       cgd 		setpeer(argc, argv);
    202        1.1       cgd 	}
    203        1.5       jtc 	if (setjmp(toplevel) != 0)
    204        1.5       jtc 		(void)putchar('\n');
    205        1.5       jtc 	command();
    206        1.8       mrg 	return (0);
    207        1.1       cgd }
    208        1.1       cgd 
    209        1.1       cgd char    hostname[100];
    210        1.1       cgd 
    211        1.5       jtc void
    212       1.11    itojun setpeer0(host, port)
    213       1.20      ross 	const char *host;
    214       1.20      ross 	const char *port;
    215       1.11    itojun {
    216       1.11    itojun 	struct addrinfo hints, *res0, *res;
    217       1.15    briggs 	int error, soopt;
    218       1.11    itojun 	struct sockaddr_storage ss;
    219       1.20      ross 	const char *cause = "unknown";
    220       1.11    itojun 
    221       1.11    itojun 	if (connected) {
    222       1.21  christos 		(void)close(f);
    223       1.11    itojun 		f = -1;
    224       1.11    itojun 	}
    225       1.12    itojun 	connected = 0;
    226       1.11    itojun 
    227       1.22  christos 	(void)memset(&hints, 0, sizeof(hints));
    228       1.11    itojun 	hints.ai_family = PF_UNSPEC;
    229       1.11    itojun 	hints.ai_socktype = SOCK_DGRAM;
    230       1.11    itojun 	hints.ai_protocol = IPPROTO_UDP;
    231       1.11    itojun 	hints.ai_flags = AI_CANONNAME;
    232       1.11    itojun 	if (!port)
    233       1.11    itojun 		port = "tftp";
    234       1.11    itojun 	error = getaddrinfo(host, port, &hints, &res0);
    235       1.11    itojun 	if (error) {
    236       1.11    itojun 		warnx("%s", gai_strerror(error));
    237       1.11    itojun 		return;
    238       1.11    itojun 	}
    239       1.11    itojun 
    240       1.11    itojun 	for (res = res0; res; res = res->ai_next) {
    241       1.13    itojun 		if (res->ai_addrlen > sizeof(peeraddr))
    242       1.13    itojun 			continue;
    243       1.11    itojun 		f = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
    244       1.11    itojun 		if (f < 0) {
    245       1.11    itojun 			cause = "socket";
    246       1.11    itojun 			continue;
    247       1.11    itojun 		}
    248       1.11    itojun 
    249       1.22  christos 		(void)memset(&ss, 0, sizeof(ss));
    250       1.11    itojun 		ss.ss_family = res->ai_family;
    251       1.11    itojun 		ss.ss_len = res->ai_addrlen;
    252       1.21  christos 		if (bind(f, (struct sockaddr *)(void *)&ss,
    253       1.21  christos 		    (socklen_t)ss.ss_len) < 0) {
    254       1.11    itojun 			cause = "bind";
    255       1.22  christos 			(void)close(f);
    256       1.11    itojun 			f = -1;
    257       1.11    itojun 			continue;
    258       1.11    itojun 		}
    259       1.11    itojun 
    260       1.11    itojun 		break;
    261       1.11    itojun 	}
    262       1.11    itojun 
    263       1.15    briggs 	if (f >= 0) {
    264       1.15    briggs 		soopt = 65536;
    265       1.15    briggs 		if (setsockopt(f, SOL_SOCKET, SO_SNDBUF, &soopt, sizeof(soopt))
    266       1.15    briggs 		    < 0) {
    267       1.22  christos 			(void)close(f);
    268       1.15    briggs 			f = -1;
    269       1.15    briggs 			cause = "setsockopt SNDBUF";
    270       1.15    briggs 		}
    271       1.22  christos 		else if (setsockopt(f, SOL_SOCKET, SO_RCVBUF, &soopt, sizeof(soopt))
    272       1.15    briggs 		    < 0) {
    273       1.22  christos 			(void)close(f);
    274       1.15    briggs 			f = -1;
    275       1.15    briggs 			cause = "setsockopt RCVBUF";
    276       1.15    briggs 		}
    277       1.15    briggs 	}
    278       1.15    briggs 
    279       1.23  christos 	if (f < 0 || res == NULL)
    280       1.11    itojun 		warn("%s", cause);
    281       1.11    itojun 	else {
    282       1.13    itojun 		/* res->ai_addr <= sizeof(peeraddr) is guaranteed */
    283       1.22  christos 		(void)memcpy(&peeraddr, res->ai_addr, res->ai_addrlen);
    284       1.11    itojun 		if (res->ai_canonname) {
    285       1.22  christos 			(void)strlcpy(hostname, res->ai_canonname,
    286       1.16    itojun 			    sizeof(hostname));
    287       1.11    itojun 		} else
    288       1.22  christos 			(void)strlcpy(hostname, host, sizeof(hostname));
    289       1.11    itojun 		connected = 1;
    290       1.11    itojun 	}
    291       1.12    itojun 
    292       1.12    itojun 	freeaddrinfo(res0);
    293       1.11    itojun }
    294       1.11    itojun 
    295       1.11    itojun void
    296        1.1       cgd setpeer(argc, argv)
    297        1.1       cgd 	int argc;
    298        1.1       cgd 	char *argv[];
    299        1.1       cgd {
    300        1.1       cgd 
    301       1.18    itojun 	if (argc < 2) {
    302       1.22  christos 		(void)strlcpy(line, "Connect ", sizeof(line));
    303       1.22  christos 		(void)printf("(to) ");
    304       1.22  christos 		(void)fgets(&line[strlen(line)], (int)(LBUFLEN-strlen(line)), stdin);
    305        1.1       cgd 		makeargv();
    306        1.1       cgd 		argc = margc;
    307        1.1       cgd 		argv = margv;
    308        1.1       cgd 	}
    309       1.18    itojun 	if ((argc < 2) || (argc > 3)) {
    310       1.22  christos 		(void)printf("usage: %s [-e] host-name [port]\n", getprogname());
    311        1.1       cgd 		return;
    312        1.1       cgd 	}
    313       1.18    itojun 	if (argc == 2)
    314       1.18    itojun 		setpeer0(argv[1], NULL);
    315       1.11    itojun 	else
    316       1.18    itojun 		setpeer0(argv[1], argv[2]);
    317        1.1       cgd }
    318        1.1       cgd 
    319        1.1       cgd struct	modes {
    320       1.20      ross 	const char *m_name;
    321       1.20      ross 	const char *m_mode;
    322        1.1       cgd } modes[] = {
    323        1.1       cgd 	{ "ascii",	"netascii" },
    324        1.1       cgd 	{ "netascii",   "netascii" },
    325        1.1       cgd 	{ "binary",     "octet" },
    326        1.1       cgd 	{ "image",      "octet" },
    327        1.1       cgd 	{ "octet",     "octet" },
    328        1.1       cgd /*      { "mail",       "mail" },       */
    329        1.1       cgd 	{ 0,		0 }
    330        1.1       cgd };
    331        1.1       cgd 
    332        1.5       jtc void
    333        1.1       cgd modecmd(argc, argv)
    334        1.5       jtc 	int argc;
    335        1.1       cgd 	char *argv[];
    336        1.1       cgd {
    337        1.9     lukem 	struct modes *p;
    338       1.20      ross 	const char *sep;
    339        1.1       cgd 
    340        1.1       cgd 	if (argc < 2) {
    341       1.22  christos 		(void)printf("Using %s mode to transfer files.\n", mode);
    342        1.1       cgd 		return;
    343        1.1       cgd 	}
    344        1.1       cgd 	if (argc == 2) {
    345        1.1       cgd 		for (p = modes; p->m_name; p++)
    346        1.1       cgd 			if (strcmp(argv[1], p->m_name) == 0)
    347        1.1       cgd 				break;
    348        1.1       cgd 		if (p->m_name) {
    349        1.5       jtc 			settftpmode(p->m_mode);
    350        1.1       cgd 			return;
    351        1.1       cgd 		}
    352       1.22  christos 		(void)printf("%s: unknown mode\n", argv[1]);
    353        1.1       cgd 		/* drop through and print usage message */
    354        1.1       cgd 	}
    355        1.1       cgd 
    356       1.22  christos 	(void)printf("usage: %s [", argv[0]);
    357        1.1       cgd 	sep = " ";
    358        1.1       cgd 	for (p = modes; p->m_name; p++) {
    359       1.22  christos 		(void)printf("%s%s", sep, p->m_name);
    360        1.1       cgd 		if (*sep == ' ')
    361        1.1       cgd 			sep = " | ";
    362        1.1       cgd 	}
    363       1.22  christos 	(void)printf(" ]\n");
    364        1.1       cgd 	return;
    365        1.1       cgd }
    366        1.1       cgd 
    367        1.5       jtc void
    368       1.21  christos /*ARGSUSED*/
    369        1.1       cgd setbinary(argc, argv)
    370        1.5       jtc 	int argc;
    371        1.5       jtc 	char *argv[];
    372        1.5       jtc {
    373        1.5       jtc 
    374        1.5       jtc 	settftpmode("octet");
    375        1.1       cgd }
    376        1.1       cgd 
    377        1.5       jtc void
    378       1.21  christos /*ARGSUSED*/
    379        1.1       cgd setascii(argc, argv)
    380        1.5       jtc 	int argc;
    381        1.5       jtc 	char *argv[];
    382        1.5       jtc {
    383        1.5       jtc 
    384        1.5       jtc 	settftpmode("netascii");
    385        1.1       cgd }
    386        1.1       cgd 
    387        1.5       jtc static void
    388        1.5       jtc settftpmode(newmode)
    389       1.20      ross 	const char *newmode;
    390        1.1       cgd {
    391       1.22  christos 	(void)strlcpy(mode, newmode, sizeof(mode));
    392        1.1       cgd 	if (verbose)
    393       1.22  christos 		(void)printf("mode set to %s\n", mode);
    394        1.1       cgd }
    395        1.1       cgd 
    396        1.1       cgd 
    397        1.1       cgd /*
    398        1.1       cgd  * Send file(s).
    399        1.1       cgd  */
    400        1.5       jtc void
    401        1.1       cgd put(argc, argv)
    402        1.5       jtc 	int argc;
    403        1.1       cgd 	char *argv[];
    404        1.1       cgd {
    405        1.1       cgd 	int fd;
    406        1.9     lukem 	int n;
    407       1.20      ross 	char *targ, *p;
    408        1.1       cgd 
    409        1.1       cgd 	if (argc < 2) {
    410       1.22  christos 		(void)strlcpy(line, "send ", sizeof(line));
    411       1.22  christos 		(void)printf("(file) ");
    412       1.22  christos 		(void)fgets(&line[strlen(line)], (int)(LBUFLEN-strlen(line)), stdin);
    413        1.1       cgd 		makeargv();
    414        1.1       cgd 		argc = margc;
    415        1.1       cgd 		argv = margv;
    416        1.1       cgd 	}
    417        1.1       cgd 	if (argc < 2) {
    418        1.1       cgd 		putusage(argv[0]);
    419        1.1       cgd 		return;
    420        1.1       cgd 	}
    421        1.1       cgd 	targ = argv[argc - 1];
    422       1.11    itojun 	if (strrchr(argv[argc - 1], ':')) {
    423        1.1       cgd 		char *cp;
    424        1.1       cgd 
    425        1.1       cgd 		for (n = 1; n < argc - 1; n++)
    426        1.9     lukem 			if (strchr(argv[n], ':')) {
    427        1.1       cgd 				putusage(argv[0]);
    428        1.1       cgd 				return;
    429        1.1       cgd 			}
    430        1.1       cgd 		cp = argv[argc - 1];
    431       1.11    itojun 		targ = strrchr(cp, ':');
    432        1.1       cgd 		*targ++ = 0;
    433       1.11    itojun 		if (cp[0] == '[' && cp[strlen(cp) - 1] == ']') {
    434       1.11    itojun 			cp[strlen(cp) - 1] = '\0';
    435       1.11    itojun 			cp++;
    436        1.1       cgd 		}
    437       1.11    itojun 		setpeer0(cp, NULL);
    438        1.1       cgd 	}
    439        1.1       cgd 	if (!connected) {
    440       1.22  christos 		(void)printf("No target machine specified.\n");
    441        1.1       cgd 		return;
    442        1.1       cgd 	}
    443        1.1       cgd 	if (argc < 4) {
    444       1.20      ross 		char *cp = argc == 2 ? tail(targ) : argv[1];
    445        1.1       cgd 		fd = open(cp, O_RDONLY);
    446        1.1       cgd 		if (fd < 0) {
    447        1.9     lukem 			warn("%s", cp);
    448        1.1       cgd 			return;
    449        1.1       cgd 		}
    450        1.1       cgd 		if (verbose)
    451       1.22  christos 			(void)printf("putting %s to %s:%s [%s]\n",
    452        1.1       cgd 				cp, hostname, targ, mode);
    453        1.1       cgd 		sendfile(fd, targ, mode);
    454        1.1       cgd 		return;
    455        1.1       cgd 	}
    456        1.1       cgd 				/* this assumes the target is a directory */
    457        1.1       cgd 				/* on a remote unix system.  hmmmm.  */
    458       1.20      ross 	p = strchr(targ, '\0');
    459       1.20      ross 	*p++ = '/';
    460        1.1       cgd 	for (n = 1; n < argc - 1; n++) {
    461       1.22  christos 		(void)strcpy(p, tail(argv[n]));
    462        1.1       cgd 		fd = open(argv[n], O_RDONLY);
    463        1.1       cgd 		if (fd < 0) {
    464        1.9     lukem 			warn("%s", argv[n]);
    465        1.1       cgd 			continue;
    466        1.1       cgd 		}
    467        1.1       cgd 		if (verbose)
    468       1.22  christos 			(void)printf("putting %s to %s:%s [%s]\n",
    469        1.1       cgd 				argv[n], hostname, targ, mode);
    470        1.1       cgd 		sendfile(fd, targ, mode);
    471        1.1       cgd 	}
    472        1.1       cgd }
    473        1.1       cgd 
    474        1.5       jtc static void
    475        1.1       cgd putusage(s)
    476        1.1       cgd 	char *s;
    477        1.1       cgd {
    478       1.22  christos 	(void)printf("usage: %s file ... host:target, or\n", s);
    479       1.22  christos 	(void)printf("       %s file ... target (when already connected)\n", s);
    480        1.1       cgd }
    481        1.1       cgd 
    482        1.1       cgd /*
    483        1.1       cgd  * Receive file(s).
    484        1.1       cgd  */
    485        1.5       jtc void
    486        1.1       cgd get(argc, argv)
    487        1.5       jtc 	int argc;
    488        1.1       cgd 	char *argv[];
    489        1.1       cgd {
    490        1.1       cgd 	int fd;
    491        1.9     lukem 	int n;
    492       1.20      ross 	char *p;
    493        1.1       cgd 	char *src;
    494        1.1       cgd 
    495        1.1       cgd 	if (argc < 2) {
    496       1.22  christos 		(void)strlcpy(line, "get ", sizeof(line));
    497       1.22  christos 		(void)printf("(files) ");
    498       1.22  christos 		(void)fgets(&line[strlen(line)], (int)(LBUFLEN-strlen(line)), stdin);
    499        1.1       cgd 		makeargv();
    500        1.1       cgd 		argc = margc;
    501        1.1       cgd 		argv = margv;
    502        1.1       cgd 	}
    503        1.1       cgd 	if (argc < 2) {
    504        1.1       cgd 		getusage(argv[0]);
    505        1.1       cgd 		return;
    506        1.1       cgd 	}
    507        1.1       cgd 	if (!connected) {
    508        1.1       cgd 		for (n = 1; n < argc ; n++)
    509       1.11    itojun 			if (strrchr(argv[n], ':') == 0) {
    510        1.1       cgd 				getusage(argv[0]);
    511        1.1       cgd 				return;
    512        1.1       cgd 			}
    513        1.1       cgd 	}
    514        1.1       cgd 	for (n = 1; n < argc ; n++) {
    515       1.11    itojun 		src = strrchr(argv[n], ':');
    516        1.1       cgd 		if (src == NULL)
    517        1.1       cgd 			src = argv[n];
    518        1.1       cgd 		else {
    519       1.11    itojun 			char *cp;
    520        1.1       cgd 			*src++ = 0;
    521       1.11    itojun 			cp = argv[n];
    522       1.11    itojun 			if (cp[0] == '[' && cp[strlen(cp) - 1] == ']') {
    523       1.11    itojun 				cp[strlen(cp) - 1] = '\0';
    524       1.11    itojun 				cp++;
    525       1.11    itojun 			}
    526       1.11    itojun 			setpeer0(cp, NULL);
    527       1.11    itojun 			if (!connected)
    528        1.1       cgd 				continue;
    529        1.1       cgd 		}
    530        1.1       cgd 		if (argc < 4) {
    531       1.20      ross 			char *cp = argc == 3 ? argv[2] : tail(src);
    532        1.1       cgd 			fd = creat(cp, 0644);
    533        1.1       cgd 			if (fd < 0) {
    534        1.9     lukem 				warn("%s", cp);
    535        1.1       cgd 				return;
    536        1.1       cgd 			}
    537        1.1       cgd 			if (verbose)
    538       1.22  christos 				(void)printf("getting from %s:%s to %s [%s]\n",
    539        1.1       cgd 					hostname, src, cp, mode);
    540        1.1       cgd 			recvfile(fd, src, mode);
    541        1.1       cgd 			break;
    542        1.1       cgd 		}
    543       1.20      ross 		p = tail(src);         /* new .. jdg */
    544       1.20      ross 		fd = creat(p, 0644);
    545        1.1       cgd 		if (fd < 0) {
    546       1.20      ross 			warn("%s", p);
    547        1.1       cgd 			continue;
    548        1.1       cgd 		}
    549        1.1       cgd 		if (verbose)
    550       1.22  christos 			(void)printf("getting from %s:%s to %s [%s]\n",
    551       1.20      ross 				hostname, src, p, mode);
    552        1.1       cgd 		recvfile(fd, src, mode);
    553        1.1       cgd 	}
    554        1.1       cgd }
    555        1.1       cgd 
    556        1.5       jtc static void
    557        1.1       cgd getusage(s)
    558        1.5       jtc 	char *s;
    559        1.1       cgd {
    560       1.22  christos 	(void)printf("usage: %s host:file host:file ... file, or\n", s);
    561       1.22  christos 	(void)printf("       %s file file ... file if connected\n", s);
    562        1.1       cgd }
    563        1.1       cgd 
    564       1.15    briggs void
    565       1.15    briggs setblksize(argc, argv)
    566       1.15    briggs 	int argc;
    567       1.15    briggs 	char *argv[];
    568       1.15    briggs {
    569       1.15    briggs 	int t;
    570       1.15    briggs 
    571       1.15    briggs 	if (argc < 2) {
    572       1.22  christos 		(void)strlcpy(line, "blksize ", sizeof(line));
    573       1.22  christos 		(void)printf("(blksize) ");
    574       1.22  christos 		(void)fgets(&line[strlen(line)], (int)(LBUFLEN-strlen(line)), stdin);
    575       1.15    briggs 		makeargv();
    576       1.15    briggs 		argc = margc;
    577       1.15    briggs 		argv = margv;
    578       1.15    briggs 	}
    579       1.15    briggs 	if (argc != 2) {
    580       1.22  christos 		(void)printf("usage: %s value\n", argv[0]);
    581       1.15    briggs 		return;
    582       1.15    briggs 	}
    583       1.15    briggs 	t = atoi(argv[1]);
    584       1.15    briggs 	if (t < 8 || t > 65464)
    585       1.22  christos 		(void)printf("%s: bad value\n", argv[1]);
    586       1.15    briggs 	else
    587       1.15    briggs 		blksize = t;
    588       1.15    briggs }
    589       1.15    briggs 
    590       1.21  christos unsigned int	def_rexmtval = TIMEOUT;
    591       1.21  christos unsigned int	rexmtval = TIMEOUT;
    592        1.1       cgd 
    593        1.5       jtc void
    594        1.1       cgd setrexmt(argc, argv)
    595        1.5       jtc 	int argc;
    596        1.1       cgd 	char *argv[];
    597        1.1       cgd {
    598        1.1       cgd 	int t;
    599        1.1       cgd 
    600        1.1       cgd 	if (argc < 2) {
    601       1.22  christos 		(void)strlcpy(line, "Rexmt-timeout ", sizeof(line));
    602       1.22  christos 		(void)printf("(value) ");
    603       1.22  christos 		(void)fgets(&line[strlen(line)], (int)(LBUFLEN-strlen(line)), stdin);
    604        1.1       cgd 		makeargv();
    605        1.1       cgd 		argc = margc;
    606        1.1       cgd 		argv = margv;
    607        1.1       cgd 	}
    608        1.1       cgd 	if (argc != 2) {
    609       1.22  christos 		(void)printf("usage: %s value\n", argv[0]);
    610        1.1       cgd 		return;
    611        1.1       cgd 	}
    612        1.1       cgd 	t = atoi(argv[1]);
    613        1.1       cgd 	if (t < 0)
    614       1.22  christos 		(void)printf("%s: bad value\n", argv[1]);
    615        1.1       cgd 	else
    616        1.1       cgd 		rexmtval = t;
    617        1.1       cgd }
    618        1.1       cgd 
    619        1.1       cgd int	maxtimeout = 5 * TIMEOUT;
    620        1.1       cgd 
    621        1.5       jtc void
    622        1.1       cgd settimeout(argc, argv)
    623        1.5       jtc 	int argc;
    624        1.1       cgd 	char *argv[];
    625        1.1       cgd {
    626        1.1       cgd 	int t;
    627        1.1       cgd 
    628        1.1       cgd 	if (argc < 2) {
    629       1.22  christos 		(void)strlcpy(line, "Maximum-timeout ", sizeof(line));
    630       1.22  christos 		(void)printf("(value) ");
    631       1.22  christos 		(void)fgets(&line[strlen(line)], (int)(LBUFLEN-strlen(line)), stdin);
    632        1.1       cgd 		makeargv();
    633        1.1       cgd 		argc = margc;
    634        1.1       cgd 		argv = margv;
    635        1.1       cgd 	}
    636        1.1       cgd 	if (argc != 2) {
    637       1.22  christos 		(void)printf("usage: %s value\n", argv[0]);
    638        1.1       cgd 		return;
    639        1.1       cgd 	}
    640        1.1       cgd 	t = atoi(argv[1]);
    641        1.1       cgd 	if (t < 0)
    642       1.22  christos 		(void)printf("%s: bad value\n", argv[1]);
    643        1.1       cgd 	else
    644        1.1       cgd 		maxtimeout = t;
    645        1.1       cgd }
    646        1.1       cgd 
    647        1.5       jtc void
    648       1.21  christos /*ARGSUSED*/
    649        1.1       cgd status(argc, argv)
    650        1.5       jtc 	int argc;
    651        1.1       cgd 	char *argv[];
    652        1.1       cgd {
    653        1.1       cgd 	if (connected)
    654       1.22  christos 		(void)printf("Connected to %s.\n", hostname);
    655        1.1       cgd 	else
    656       1.22  christos 		(void)printf("Not connected.\n");
    657       1.22  christos 	(void)printf("Mode: %s Verbose: %s Tracing: %s\n", mode,
    658        1.1       cgd 		verbose ? "on" : "off", trace ? "on" : "off");
    659       1.22  christos 	(void)printf("Rexmt-interval: %d seconds, Max-timeout: %d seconds\n",
    660        1.1       cgd 		rexmtval, maxtimeout);
    661        1.1       cgd }
    662        1.1       cgd 
    663        1.1       cgd void
    664       1.21  christos /*ARGSUSED*/
    665        1.8       mrg intr(dummy)
    666        1.8       mrg 	int dummy;
    667        1.1       cgd {
    668        1.5       jtc 
    669       1.22  christos 	(void)signal(SIGALRM, SIG_IGN);
    670       1.22  christos 	(void)alarm(0);
    671        1.1       cgd 	longjmp(toplevel, -1);
    672        1.1       cgd }
    673        1.1       cgd 
    674        1.1       cgd char *
    675        1.1       cgd tail(filename)
    676        1.1       cgd 	char *filename;
    677        1.1       cgd {
    678        1.9     lukem 	char *s;
    679        1.1       cgd 
    680        1.1       cgd 	while (*filename) {
    681        1.9     lukem 		s = strrchr(filename, '/');
    682        1.1       cgd 		if (s == NULL)
    683        1.1       cgd 			break;
    684        1.1       cgd 		if (s[1])
    685        1.1       cgd 			return (s + 1);
    686        1.1       cgd 		*s = '\0';
    687        1.1       cgd 	}
    688        1.1       cgd 	return (filename);
    689        1.1       cgd }
    690        1.1       cgd 
    691        1.1       cgd /*
    692        1.1       cgd  * Command parser.
    693        1.1       cgd  */
    694        1.5       jtc static __dead void
    695        1.5       jtc command()
    696        1.1       cgd {
    697       1.20      ross 	const struct cmd *c;
    698        1.1       cgd 
    699        1.1       cgd 	for (;;) {
    700       1.22  christos 		(void)printf("%s> ", prompt);
    701        1.4       cgd 		if (fgets(line, LBUFLEN, stdin) == 0) {
    702        1.1       cgd 			if (feof(stdin)) {
    703        1.5       jtc 				exit(0);
    704        1.1       cgd 			} else {
    705        1.1       cgd 				continue;
    706        1.1       cgd 			}
    707        1.1       cgd 		}
    708        1.4       cgd 		if ((line[0] == 0) || (line[0] == '\n'))
    709        1.1       cgd 			continue;
    710        1.1       cgd 		makeargv();
    711        1.5       jtc 		if (margc == 0)
    712        1.5       jtc 			continue;
    713        1.1       cgd 		c = getcmd(margv[0]);
    714        1.1       cgd 		if (c == (struct cmd *)-1) {
    715       1.22  christos 			(void)printf("?Ambiguous command\n");
    716        1.1       cgd 			continue;
    717        1.1       cgd 		}
    718        1.1       cgd 		if (c == 0) {
    719       1.22  christos 			(void)printf("?Invalid command\n");
    720        1.1       cgd 			continue;
    721        1.1       cgd 		}
    722        1.1       cgd 		(*c->handler)(margc, margv);
    723        1.1       cgd 	}
    724        1.1       cgd }
    725        1.1       cgd 
    726       1.20      ross const struct cmd *
    727        1.1       cgd getcmd(name)
    728        1.9     lukem 	char *name;
    729        1.1       cgd {
    730       1.20      ross 	const char *p, *q;
    731       1.20      ross 	const struct cmd *c, *found;
    732        1.9     lukem 	int nmatches, longest;
    733        1.1       cgd 
    734        1.1       cgd 	longest = 0;
    735        1.1       cgd 	nmatches = 0;
    736        1.1       cgd 	found = 0;
    737        1.5       jtc 	for (c = cmdtab; (p = c->name) != NULL; c++) {
    738        1.1       cgd 		for (q = name; *q == *p++; q++)
    739        1.1       cgd 			if (*q == 0)		/* exact match? */
    740        1.1       cgd 				return (c);
    741        1.1       cgd 		if (!*q) {			/* the name was a prefix */
    742        1.1       cgd 			if (q - name > longest) {
    743        1.1       cgd 				longest = q - name;
    744        1.1       cgd 				nmatches = 1;
    745        1.1       cgd 				found = c;
    746        1.1       cgd 			} else if (q - name == longest)
    747        1.1       cgd 				nmatches++;
    748        1.1       cgd 		}
    749        1.1       cgd 	}
    750        1.1       cgd 	if (nmatches > 1)
    751        1.1       cgd 		return ((struct cmd *)-1);
    752        1.1       cgd 	return (found);
    753        1.1       cgd }
    754        1.1       cgd 
    755        1.1       cgd /*
    756        1.1       cgd  * Slice a string up into argc/argv.
    757        1.1       cgd  */
    758        1.5       jtc static void
    759        1.1       cgd makeargv()
    760        1.1       cgd {
    761        1.9     lukem 	char *cp;
    762        1.9     lukem 	char **argp = margv;
    763        1.1       cgd 
    764        1.1       cgd 	margc = 0;
    765        1.1       cgd 	for (cp = line; *cp;) {
    766       1.10  christos 		while (isspace((unsigned char)*cp))
    767        1.1       cgd 			cp++;
    768        1.1       cgd 		if (*cp == '\0')
    769        1.1       cgd 			break;
    770        1.1       cgd 		*argp++ = cp;
    771        1.1       cgd 		margc += 1;
    772       1.10  christos 		while (*cp != '\0' && !isspace((unsigned char)*cp))
    773        1.1       cgd 			cp++;
    774        1.1       cgd 		if (*cp == '\0')
    775        1.1       cgd 			break;
    776        1.1       cgd 		*cp++ = '\0';
    777        1.1       cgd 	}
    778        1.1       cgd 	*argp++ = 0;
    779        1.1       cgd }
    780        1.1       cgd 
    781        1.5       jtc void
    782       1.21  christos /*ARGSUSED*/
    783        1.5       jtc quit(argc, argv)
    784        1.5       jtc 	int argc;
    785        1.5       jtc 	char *argv[];
    786        1.1       cgd {
    787        1.5       jtc 
    788        1.1       cgd 	exit(0);
    789        1.1       cgd }
    790        1.1       cgd 
    791        1.1       cgd /*
    792        1.1       cgd  * Help command.
    793        1.1       cgd  */
    794        1.5       jtc void
    795        1.1       cgd help(argc, argv)
    796        1.1       cgd 	int argc;
    797        1.1       cgd 	char *argv[];
    798        1.1       cgd {
    799       1.20      ross 	const struct cmd *c;
    800        1.1       cgd 
    801        1.1       cgd 	if (argc == 1) {
    802       1.22  christos 		(void)printf("Commands may be abbreviated.  Commands are:\n\n");
    803        1.1       cgd 		for (c = cmdtab; c->name; c++)
    804       1.22  christos 			(void)printf("%-*s\t%s\n", (int)HELPINDENT, c->name, c->help);
    805        1.1       cgd 		return;
    806        1.1       cgd 	}
    807        1.1       cgd 	while (--argc > 0) {
    808        1.9     lukem 		char *arg;
    809        1.1       cgd 		arg = *++argv;
    810        1.1       cgd 		c = getcmd(arg);
    811        1.1       cgd 		if (c == (struct cmd *)-1)
    812       1.22  christos 			(void)printf("?Ambiguous help command %s\n", arg);
    813        1.1       cgd 		else if (c == (struct cmd *)0)
    814       1.22  christos 			(void)printf("?Invalid help command %s\n", arg);
    815        1.1       cgd 		else
    816       1.22  christos 			(void)printf("%s\n", c->help);
    817        1.1       cgd 	}
    818        1.1       cgd }
    819        1.1       cgd 
    820        1.5       jtc void
    821       1.21  christos /*ARGSUSED*/
    822        1.5       jtc settrace(argc, argv)
    823        1.5       jtc 	int argc;
    824        1.5       jtc 	char **argv;
    825        1.1       cgd {
    826        1.1       cgd 	trace = !trace;
    827       1.22  christos 	(void)printf("Packet tracing %s.\n", trace ? "on" : "off");
    828        1.1       cgd }
    829        1.1       cgd 
    830        1.5       jtc void
    831       1.21  christos /*ARGSUSED*/
    832        1.5       jtc setverbose(argc, argv)
    833        1.5       jtc 	int argc;
    834        1.5       jtc 	char **argv;
    835        1.1       cgd {
    836        1.1       cgd 	verbose = !verbose;
    837       1.22  christos 	(void)printf("Verbose mode %s.\n", verbose ? "on" : "off");
    838       1.15    briggs }
    839       1.15    briggs 
    840       1.15    briggs void
    841       1.21  christos /*ARGSUSED*/
    842       1.15    briggs settsize(argc, argv)
    843       1.15    briggs 	int argc;
    844       1.15    briggs 	char **argv;
    845       1.15    briggs {
    846       1.15    briggs 	tsize = !tsize;
    847       1.22  christos 	(void)printf("Tsize mode %s.\n", tsize ? "on" : "off");
    848       1.15    briggs }
    849       1.15    briggs 
    850       1.15    briggs void
    851       1.21  christos /*ARGSUSED*/
    852       1.15    briggs settimeoutopt(argc, argv)
    853       1.15    briggs 	int argc;
    854       1.15    briggs 	char **argv;
    855       1.15    briggs {
    856       1.15    briggs 	tout = !tout;
    857       1.22  christos 	(void)printf("Timeout option %s.\n", tout ? "on" : "off");
    858        1.1       cgd }
    859