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