17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate /*
237c478bd9Sstevel@tonic-gate  * Copyright 2002 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
28*cb76cc66SToomas Soome /*	  All Rights Reserved	*/
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate /*
317c478bd9Sstevel@tonic-gate  * University Copyright- Copyright (c) 1982, 1986, 1988
327c478bd9Sstevel@tonic-gate  * The Regents of the University of California
337c478bd9Sstevel@tonic-gate  * All Rights Reserved
347c478bd9Sstevel@tonic-gate  *
357c478bd9Sstevel@tonic-gate  * University Acknowledgment- Portions of this document are derived from
367c478bd9Sstevel@tonic-gate  * software developed by the University of California, Berkeley, and its
377c478bd9Sstevel@tonic-gate  * contributors.
387c478bd9Sstevel@tonic-gate  */
397c478bd9Sstevel@tonic-gate 
407c478bd9Sstevel@tonic-gate /*
417c478bd9Sstevel@tonic-gate  * TFTP User Program -- Command Interface.
427c478bd9Sstevel@tonic-gate  */
437c478bd9Sstevel@tonic-gate #include <sys/types.h>
447c478bd9Sstevel@tonic-gate #include <sys/socket.h>
45*cb76cc66SToomas Soome #include <sys/sysmacros.h>
467c478bd9Sstevel@tonic-gate 
477c478bd9Sstevel@tonic-gate #include <arpa/inet.h>
487c478bd9Sstevel@tonic-gate 
497c478bd9Sstevel@tonic-gate #include <signal.h>
507c478bd9Sstevel@tonic-gate #include <stdio.h>
517c478bd9Sstevel@tonic-gate #include <stdlib.h>
52*cb76cc66SToomas Soome #include <stdbool.h>
537c478bd9Sstevel@tonic-gate #include <errno.h>
547c478bd9Sstevel@tonic-gate #include <ctype.h>
557c478bd9Sstevel@tonic-gate #include <netdb.h>
567c478bd9Sstevel@tonic-gate #include <fcntl.h>
577c478bd9Sstevel@tonic-gate #include <string.h>
587c478bd9Sstevel@tonic-gate #include <limits.h>
59*cb76cc66SToomas Soome #include <libtecla.h>
607c478bd9Sstevel@tonic-gate 
617c478bd9Sstevel@tonic-gate #include "tftpcommon.h"
627c478bd9Sstevel@tonic-gate #include "tftpprivate.h"
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate #define	TIMEOUT		5		/* secs between rexmt's */
657c478bd9Sstevel@tonic-gate 
667c478bd9Sstevel@tonic-gate struct sockaddr_in6	sin6;
677c478bd9Sstevel@tonic-gate int			f;
687c478bd9Sstevel@tonic-gate int			maxtimeout = 5 * TIMEOUT;
697c478bd9Sstevel@tonic-gate int			verbose;
707c478bd9Sstevel@tonic-gate int			trace;
717c478bd9Sstevel@tonic-gate int			srexmtval;
727c478bd9Sstevel@tonic-gate int			blksize;
737c478bd9Sstevel@tonic-gate int			rexmtval = TIMEOUT;
747c478bd9Sstevel@tonic-gate int			tsize_opt;
757c478bd9Sstevel@tonic-gate jmp_buf			toplevel;
767c478bd9Sstevel@tonic-gate 
777c478bd9Sstevel@tonic-gate static int			default_port, port;
787c478bd9Sstevel@tonic-gate static int			connected;
797c478bd9Sstevel@tonic-gate static char			mode[32];
807c478bd9Sstevel@tonic-gate static char			line[200];
81*cb76cc66SToomas Soome static char			*prompt = "tftp> ";
827c478bd9Sstevel@tonic-gate static char			hostname[MAXHOSTNAMELEN];
83*cb76cc66SToomas Soome static GetLine			*gl;
847c478bd9Sstevel@tonic-gate 
857c478bd9Sstevel@tonic-gate static void		intr(int);
867c478bd9Sstevel@tonic-gate static void		quit(int, char **);
877c478bd9Sstevel@tonic-gate static void		help(int, char **);
887c478bd9Sstevel@tonic-gate static void		setverbose(int, char **);
897c478bd9Sstevel@tonic-gate static void		settrace(int, char **);
907c478bd9Sstevel@tonic-gate static void		status(int, char **);
917c478bd9Sstevel@tonic-gate static void		get(int, char **);
927c478bd9Sstevel@tonic-gate static void		put(int, char **);
937c478bd9Sstevel@tonic-gate static void		setpeer(int, char **);
947c478bd9Sstevel@tonic-gate static void		modecmd(int, char **);
957c478bd9Sstevel@tonic-gate static void		setrexmt(int, char **);
967c478bd9Sstevel@tonic-gate static void		settimeout(int, char **);
977c478bd9Sstevel@tonic-gate static void		setbinary(int, char **);
987c478bd9Sstevel@tonic-gate static void		setascii(int, char **);
997c478bd9Sstevel@tonic-gate static void		setblksize(int, char **);
1007c478bd9Sstevel@tonic-gate static void		setsrexmt(int, char **);
1017c478bd9Sstevel@tonic-gate static void		settsize(int, char **);
1027c478bd9Sstevel@tonic-gate static void		setmode(char *);
1037c478bd9Sstevel@tonic-gate static void		putusage(char *);
1047c478bd9Sstevel@tonic-gate static void		getusage(char *);
1057c478bd9Sstevel@tonic-gate static char		*finddelimiter(char *);
1067c478bd9Sstevel@tonic-gate static char		*removebrackets(char *);
1077c478bd9Sstevel@tonic-gate static int		prompt_for_arg(char *, int, char *);
1087c478bd9Sstevel@tonic-gate static struct cmd	*getcmd(char *);
1097c478bd9Sstevel@tonic-gate static char		*tail(char *);
1107c478bd9Sstevel@tonic-gate static void		command(int);
111*cb76cc66SToomas Soome static void		makeargv(char *, int *, char ***);
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate #define	HELPINDENT (sizeof ("connect"))
1147c478bd9Sstevel@tonic-gate 
1157c478bd9Sstevel@tonic-gate struct cmd {
1167c478bd9Sstevel@tonic-gate 	char	*name;
1177c478bd9Sstevel@tonic-gate 	char	*help;
1187c478bd9Sstevel@tonic-gate 	void	(*handler)(int, char **);
1197c478bd9Sstevel@tonic-gate };
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate static char	vhelp[] =	"toggle verbose mode";
1227c478bd9Sstevel@tonic-gate static char	thelp[] =	"toggle packet tracing";
1237c478bd9Sstevel@tonic-gate static char	chelp[] =	"connect to remote tftp";
1247c478bd9Sstevel@tonic-gate static char	qhelp[] =	"exit tftp";
1257c478bd9Sstevel@tonic-gate static char	hhelp[] =	"print help information";
1267c478bd9Sstevel@tonic-gate static char	shelp[] =	"send file";
1277c478bd9Sstevel@tonic-gate static char	rhelp[] =	"receive file";
1287c478bd9Sstevel@tonic-gate static char	mhelp[] =	"set file transfer mode";
1297c478bd9Sstevel@tonic-gate static char	sthelp[] =	"show current status";
1307c478bd9Sstevel@tonic-gate static char	xhelp[] =	"set per-packet retransmission timeout";
1317c478bd9Sstevel@tonic-gate static char	ihelp[] =	"set total retransmission timeout";
1327c478bd9Sstevel@tonic-gate static char	ashelp[] =	"set mode to netascii";
1337c478bd9Sstevel@tonic-gate static char	bnhelp[] =	"set mode to octet";
1347c478bd9Sstevel@tonic-gate static char	bshelp[] =	"set transfer blocksize to negotiate with the "
1357c478bd9Sstevel@tonic-gate 				"server";
1367c478bd9Sstevel@tonic-gate static char	srhelp[] =	"set preferred per-packet retransmission "
1377c478bd9Sstevel@tonic-gate 				"timeout for server";
1387c478bd9Sstevel@tonic-gate static char	tshelp[] =	"toggle sending the transfer size option to "
1397c478bd9Sstevel@tonic-gate 				"the server";
1407c478bd9Sstevel@tonic-gate 
1417c478bd9Sstevel@tonic-gate static struct cmd	cmdtab[] = {
1427c478bd9Sstevel@tonic-gate 	{ "connect",	chelp,		setpeer },
1437c478bd9Sstevel@tonic-gate 	{ "mode",	mhelp,		modecmd },
1447c478bd9Sstevel@tonic-gate 	{ "put",	shelp,		put },
1457c478bd9Sstevel@tonic-gate 	{ "get",	rhelp,		get },
1467c478bd9Sstevel@tonic-gate 	{ "quit",	qhelp,		quit },
1477c478bd9Sstevel@tonic-gate 	{ "verbose",	vhelp,		setverbose },
1487c478bd9Sstevel@tonic-gate 	{ "trace",	thelp,		settrace },
1497c478bd9Sstevel@tonic-gate 	{ "status",	sthelp,		status },
1507c478bd9Sstevel@tonic-gate 	{ "binary",	bnhelp,		setbinary },
1517c478bd9Sstevel@tonic-gate 	{ "ascii",	ashelp,		setascii },
1527c478bd9Sstevel@tonic-gate 	{ "rexmt",	xhelp,		setrexmt },
1537c478bd9Sstevel@tonic-gate 	{ "timeout",	ihelp,		settimeout },
1547c478bd9Sstevel@tonic-gate 	{ "blksize",	bshelp,		setblksize },
1557c478bd9Sstevel@tonic-gate 	{ "srexmt",	srhelp,		setsrexmt },
1567c478bd9Sstevel@tonic-gate 	{ "tsize",	tshelp,		settsize },
157*cb76cc66SToomas Soome 	{ "help",	hhelp,		help },
1587c478bd9Sstevel@tonic-gate 	{ "?",		hhelp,		help },
1597c478bd9Sstevel@tonic-gate 	{ NULL }
1607c478bd9Sstevel@tonic-gate };
1617c478bd9Sstevel@tonic-gate 
162*cb76cc66SToomas Soome #define	AMBIGCMD	(&cmdtab[ARRAY_SIZE(cmdtab)])
163*cb76cc66SToomas Soome 
164*cb76cc66SToomas Soome static struct modes {
165*cb76cc66SToomas Soome 	char *m_name;
166*cb76cc66SToomas Soome 	char *m_mode;
167*cb76cc66SToomas Soome } modes[] = {
168*cb76cc66SToomas Soome 	{ "ascii",	"netascii" },
169*cb76cc66SToomas Soome 	{ "netascii",	"netascii" },
170*cb76cc66SToomas Soome 	{ "binary",	"octet" },
171*cb76cc66SToomas Soome 	{ "image",	"octet" },
172*cb76cc66SToomas Soome 	{ "octet",	"octet" },
173*cb76cc66SToomas Soome /*      { "mail",       "mail" },       */
174*cb76cc66SToomas Soome 	{ NULL,		NULL }
175*cb76cc66SToomas Soome };
176*cb76cc66SToomas Soome 
177*cb76cc66SToomas Soome static int
cmdmatch(WordCompletion * cpl,void * data,const char * line,int word_end)178*cb76cc66SToomas Soome cmdmatch(WordCompletion *cpl, void *data, const char *line, int word_end)
179*cb76cc66SToomas Soome {
180*cb76cc66SToomas Soome 	struct cmd *cmds = data;
181*cb76cc66SToomas Soome 	const char *word;
182*cb76cc66SToomas Soome 	int i, rc = 0;
183*cb76cc66SToomas Soome 
184*cb76cc66SToomas Soome 	for (word = line + word_end; word > line && *(word - 1) != ' '; word--)
185*cb76cc66SToomas Soome 		;
186*cb76cc66SToomas Soome 
187*cb76cc66SToomas Soome 	/* This word is command */
188*cb76cc66SToomas Soome 	if (word == line) {
189*cb76cc66SToomas Soome 		for (i = 0; cmds[i].name != NULL; i++) {
190*cb76cc66SToomas Soome 			const char *cmd = strstr(cmds[i].name, word);
191*cb76cc66SToomas Soome 
192*cb76cc66SToomas Soome 			if (cmd == cmds[i].name) {
193*cb76cc66SToomas Soome 				rc = cpl_add_completion(cpl, line, 0,
194*cb76cc66SToomas Soome 				    word_end, cmds[i].name + strlen(word),
195*cb76cc66SToomas Soome 				    NULL, NULL);
196*cb76cc66SToomas Soome 			}
197*cb76cc66SToomas Soome 		}
198*cb76cc66SToomas Soome 	} else {
199*cb76cc66SToomas Soome 		/* We only complete arguments for mode command */
200*cb76cc66SToomas Soome 		if (strncmp(line, "mode", 4) == 0) {
201*cb76cc66SToomas Soome 			for (i = 0; modes[i].m_name != NULL; i++) {
202*cb76cc66SToomas Soome 				const char *mode;
203*cb76cc66SToomas Soome 
204*cb76cc66SToomas Soome 				mode = strstr(modes[i].m_name, word);
205*cb76cc66SToomas Soome 				if (mode == modes[i].m_name) {
206*cb76cc66SToomas Soome 					rc = cpl_add_completion(cpl, line, 0,
207*cb76cc66SToomas Soome 					    word_end,
208*cb76cc66SToomas Soome 					    modes[i].m_name + strlen(word),
209*cb76cc66SToomas Soome 					    NULL, NULL);
210*cb76cc66SToomas Soome 				}
211*cb76cc66SToomas Soome 			}
212*cb76cc66SToomas Soome 		}
213*cb76cc66SToomas Soome 	}
214*cb76cc66SToomas Soome 
215*cb76cc66SToomas Soome 	return (rc);
216*cb76cc66SToomas Soome }
217*cb76cc66SToomas Soome 
218*cb76cc66SToomas Soome #define	LINELEN		1024
219*cb76cc66SToomas Soome #define	HISTORY		2048
2207c478bd9Sstevel@tonic-gate 
2217c478bd9Sstevel@tonic-gate int
main(int argc,char ** argv)2227c478bd9Sstevel@tonic-gate main(int argc, char **argv)
2237c478bd9Sstevel@tonic-gate {
2247c478bd9Sstevel@tonic-gate 	struct servent *sp;
2257c478bd9Sstevel@tonic-gate 	struct sockaddr_in6 sin6;
2267c478bd9Sstevel@tonic-gate 	int top;
2277c478bd9Sstevel@tonic-gate 
2287c478bd9Sstevel@tonic-gate 	sp = getservbyname("tftp", "udp");
2297c478bd9Sstevel@tonic-gate 	default_port = (sp != NULL) ? sp->s_port : htons(IPPORT_TFTP);
2307c478bd9Sstevel@tonic-gate 	port = default_port;
2317c478bd9Sstevel@tonic-gate 
2327c478bd9Sstevel@tonic-gate 	f = socket(AF_INET6, SOCK_DGRAM, 0);
2337c478bd9Sstevel@tonic-gate 	if (f < 0) {
2347c478bd9Sstevel@tonic-gate 		perror("tftp: socket");
2357c478bd9Sstevel@tonic-gate 		exit(3);
2367c478bd9Sstevel@tonic-gate 	}
2377c478bd9Sstevel@tonic-gate 
2387c478bd9Sstevel@tonic-gate 	(void) memset(&sin6, 0, sizeof (sin6));
2397c478bd9Sstevel@tonic-gate 	sin6.sin6_family = AF_INET6;
2407c478bd9Sstevel@tonic-gate 	if (bind(f, (struct sockaddr *)&sin6, sizeof (sin6)) < 0) {
2417c478bd9Sstevel@tonic-gate 		perror("tftp: bind");
2427c478bd9Sstevel@tonic-gate 		exit(1);
2437c478bd9Sstevel@tonic-gate 	}
2447c478bd9Sstevel@tonic-gate 
2457c478bd9Sstevel@tonic-gate 	(void) strlcpy(mode, "netascii", sizeof (mode));
246*cb76cc66SToomas Soome 
247*cb76cc66SToomas Soome 	gl = new_GetLine(LINELEN, HISTORY);
248*cb76cc66SToomas Soome 	if (gl == NULL) {
249*cb76cc66SToomas Soome 		perror("tftp: cli setup");
250*cb76cc66SToomas Soome 		exit(1);
251*cb76cc66SToomas Soome 	}
252*cb76cc66SToomas Soome 
253*cb76cc66SToomas Soome 	/* SIGALRM is used by tftp */
254*cb76cc66SToomas Soome 	if (gl_ignore_signal(gl, SIGALRM) == 0) {
255*cb76cc66SToomas Soome 		if (gl_customize_completion(gl, cmdtab, cmdmatch) != 0)
256*cb76cc66SToomas Soome 			perror("gl_customize_completion");
257*cb76cc66SToomas Soome 	} else {
258*cb76cc66SToomas Soome 		perror("gl_ignore_signal");
259*cb76cc66SToomas Soome 	}
260*cb76cc66SToomas Soome 
2617c478bd9Sstevel@tonic-gate 	(void) signal(SIGINT, intr);
2627c478bd9Sstevel@tonic-gate 	if (argc > 1) {
2637c478bd9Sstevel@tonic-gate 		if (setjmp(toplevel) != 0)
2647c478bd9Sstevel@tonic-gate 			exit(0);
2657c478bd9Sstevel@tonic-gate 		setpeer(argc, argv);
2667c478bd9Sstevel@tonic-gate 	}
2677c478bd9Sstevel@tonic-gate 
2687c478bd9Sstevel@tonic-gate 	top = (setjmp(toplevel) == 0);
2697c478bd9Sstevel@tonic-gate 	for (;;)
2707c478bd9Sstevel@tonic-gate 		command(top);
2717c478bd9Sstevel@tonic-gate 
2727c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
2737c478bd9Sstevel@tonic-gate 	return (0);
2747c478bd9Sstevel@tonic-gate }
2757c478bd9Sstevel@tonic-gate 
2767c478bd9Sstevel@tonic-gate /* Prompt for command argument, add to buffer with space separator */
2777c478bd9Sstevel@tonic-gate static int
prompt_for_arg(char * buffer,int buffer_size,char * prompt)2787c478bd9Sstevel@tonic-gate prompt_for_arg(char *buffer, int buffer_size, char *prompt)
2797c478bd9Sstevel@tonic-gate {
280*cb76cc66SToomas Soome 	char *buf;
281*cb76cc66SToomas Soome 	char *p;
2827c478bd9Sstevel@tonic-gate 
2837c478bd9Sstevel@tonic-gate 	if (strlcat(buffer, " ", buffer_size) >= buffer_size) {
2847c478bd9Sstevel@tonic-gate 		(void) fputs("?Line too long\n", stderr);
2857c478bd9Sstevel@tonic-gate 		return (-1);
2867c478bd9Sstevel@tonic-gate 	}
287*cb76cc66SToomas Soome 
288*cb76cc66SToomas Soome 	if (asprintf(&p, "(%s) ", prompt) < 0)
289*cb76cc66SToomas Soome 		perror("prompt_for_arg");
290*cb76cc66SToomas Soome 	buf = gl_get_line(gl, p, NULL, -1);
291*cb76cc66SToomas Soome 	free(p);
292*cb76cc66SToomas Soome 	if (buf == NULL)
2937c478bd9Sstevel@tonic-gate 		return (-1);
294*cb76cc66SToomas Soome 
295*cb76cc66SToomas Soome 	if (strlcat(buffer, buf, buffer_size) >= buffer_size) {
2967c478bd9Sstevel@tonic-gate 		(void) fputs("?Line too long\n", stderr);
2977c478bd9Sstevel@tonic-gate 		return (-1);
2987c478bd9Sstevel@tonic-gate 	}
2997c478bd9Sstevel@tonic-gate 	return (0);
3007c478bd9Sstevel@tonic-gate }
3017c478bd9Sstevel@tonic-gate 
3027c478bd9Sstevel@tonic-gate static void
unknown_host(int error,char * hostname)3037c478bd9Sstevel@tonic-gate unknown_host(int error, char *hostname)
3047c478bd9Sstevel@tonic-gate {
3057c478bd9Sstevel@tonic-gate 	if (error == TRY_AGAIN)
3067c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "%s: Unknown host (try again later).\n",
3077c478bd9Sstevel@tonic-gate 		    hostname);
3087c478bd9Sstevel@tonic-gate 	else
3097c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "%s: Unknown host.\n", hostname);
3107c478bd9Sstevel@tonic-gate }
3117c478bd9Sstevel@tonic-gate 
3127c478bd9Sstevel@tonic-gate static void
setpeer(int argc,char ** argv)3137c478bd9Sstevel@tonic-gate setpeer(int argc, char **argv)
3147c478bd9Sstevel@tonic-gate {
3157c478bd9Sstevel@tonic-gate 	struct hostent *host;
3167c478bd9Sstevel@tonic-gate 	int error_num;
3177c478bd9Sstevel@tonic-gate 	struct in6_addr ipv6addr;
3187c478bd9Sstevel@tonic-gate 	struct in_addr ipv4addr;
3197c478bd9Sstevel@tonic-gate 	char *hostnameinput;
320*cb76cc66SToomas Soome 	const char *errstr;
3217c478bd9Sstevel@tonic-gate 
3227c478bd9Sstevel@tonic-gate 	if (argc < 2) {
323*cb76cc66SToomas Soome 		if (strlcat(line, argv[0], sizeof (line)) >= sizeof (line)) {
324*cb76cc66SToomas Soome 			(void) fprintf(stderr, "%s is too big\n", argv[0]);
325*cb76cc66SToomas Soome 			return;
326*cb76cc66SToomas Soome 		}
3277c478bd9Sstevel@tonic-gate 		if (prompt_for_arg(line, sizeof (line), "to") == -1)
3287c478bd9Sstevel@tonic-gate 			return;
329*cb76cc66SToomas Soome 		makeargv(line, &argc, &argv);
3307c478bd9Sstevel@tonic-gate 	}
3317c478bd9Sstevel@tonic-gate 	if (argc > 3 || argc < 2) {
3327c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "usage: %s host-name [port]\n",
3337c478bd9Sstevel@tonic-gate 		    argv[0]);
3347c478bd9Sstevel@tonic-gate 		return;
3357c478bd9Sstevel@tonic-gate 	}
3367c478bd9Sstevel@tonic-gate 	hostnameinput = removebrackets(argv[1]);
3377c478bd9Sstevel@tonic-gate 
3387c478bd9Sstevel@tonic-gate 	(void) memset(&sin6, 0, sizeof (sin6));
3397c478bd9Sstevel@tonic-gate 	sin6.sin6_family = AF_INET6;
340*cb76cc66SToomas Soome 	host = getipnodebyname(hostnameinput, AF_INET6,
341*cb76cc66SToomas Soome 	    AI_ALL | AI_ADDRCONFIG | AI_V4MAPPED, &error_num);
342*cb76cc66SToomas Soome 	if (host != NULL) {
3437c478bd9Sstevel@tonic-gate 		(void) memcpy(&sin6.sin6_addr, host->h_addr_list[0],
3447c478bd9Sstevel@tonic-gate 		    host->h_length);
3457c478bd9Sstevel@tonic-gate 		/*
3467c478bd9Sstevel@tonic-gate 		 * If host->h_name is a IPv4-mapped IPv6 literal, we'll convert
3477c478bd9Sstevel@tonic-gate 		 * it to IPv4 literal address.
3487c478bd9Sstevel@tonic-gate 		 */
3497c478bd9Sstevel@tonic-gate 		if ((inet_pton(AF_INET6, host->h_name, &ipv6addr) > 0) &&
3507c478bd9Sstevel@tonic-gate 		    IN6_IS_ADDR_V4MAPPED(&ipv6addr)) {
3517c478bd9Sstevel@tonic-gate 			IN6_V4MAPPED_TO_INADDR(&ipv6addr, &ipv4addr);
3527c478bd9Sstevel@tonic-gate 			(void) inet_ntop(AF_INET, &ipv4addr, hostname,
3537c478bd9Sstevel@tonic-gate 			    sizeof (hostname));
3547c478bd9Sstevel@tonic-gate 		} else {
3557c478bd9Sstevel@tonic-gate 			(void) strlcpy(hostname, host->h_name,
3567c478bd9Sstevel@tonic-gate 			    sizeof (hostname));
3577c478bd9Sstevel@tonic-gate 		}
3587c478bd9Sstevel@tonic-gate 		freehostent(host);
3597c478bd9Sstevel@tonic-gate 	} else {
3607c478bd9Sstevel@tonic-gate 		/* Keeping with previous semantics */
3617c478bd9Sstevel@tonic-gate 		connected = 0;
3627c478bd9Sstevel@tonic-gate 		unknown_host(error_num, hostnameinput);
3637c478bd9Sstevel@tonic-gate 		return;
3647c478bd9Sstevel@tonic-gate 	}
3657c478bd9Sstevel@tonic-gate 
3667c478bd9Sstevel@tonic-gate 	port = default_port;
3677c478bd9Sstevel@tonic-gate 	if (argc == 3) {
368*cb76cc66SToomas Soome 		port = strtonum(argv[2], 1, 65535, &errstr);
369*cb76cc66SToomas Soome 		if (errstr != NULL) {
370*cb76cc66SToomas Soome 			(void) fprintf(stderr, "%s: bad port number: %s\n",
371*cb76cc66SToomas Soome 			    argv[2], errstr);
3727c478bd9Sstevel@tonic-gate 			connected = 0;
3737c478bd9Sstevel@tonic-gate 			return;
3747c478bd9Sstevel@tonic-gate 		}
3757c478bd9Sstevel@tonic-gate 		port = htons(port);
3767c478bd9Sstevel@tonic-gate 	}
3777c478bd9Sstevel@tonic-gate 	connected = 1;
3787c478bd9Sstevel@tonic-gate }
3797c478bd9Sstevel@tonic-gate 
3807c478bd9Sstevel@tonic-gate static void
modecmd(int argc,char ** argv)3817c478bd9Sstevel@tonic-gate modecmd(int argc, char **argv)
3827c478bd9Sstevel@tonic-gate {
3837c478bd9Sstevel@tonic-gate 	struct modes *p;
3847c478bd9Sstevel@tonic-gate 
3857c478bd9Sstevel@tonic-gate 	if (argc < 2) {
3867c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "Using %s mode to transfer files.\n",
3877c478bd9Sstevel@tonic-gate 		    mode);
3887c478bd9Sstevel@tonic-gate 		return;
3897c478bd9Sstevel@tonic-gate 	}
3907c478bd9Sstevel@tonic-gate 	if (argc == 2) {
3917c478bd9Sstevel@tonic-gate 		for (p = modes; p->m_name != NULL; p++)
3927c478bd9Sstevel@tonic-gate 			if (strcmp(argv[1], p->m_name) == 0) {
3937c478bd9Sstevel@tonic-gate 				setmode(p->m_mode);
3947c478bd9Sstevel@tonic-gate 				return;
3957c478bd9Sstevel@tonic-gate 			}
3967c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "%s: unknown mode\n", argv[1]);
3977c478bd9Sstevel@tonic-gate 		/* drop through and print usage message */
3987c478bd9Sstevel@tonic-gate 	}
3997c478bd9Sstevel@tonic-gate 
4007c478bd9Sstevel@tonic-gate 	p = modes;
4017c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "usage: %s [ %s", argv[0], p->m_name);
4027c478bd9Sstevel@tonic-gate 	for (p++; p->m_name != NULL; p++)
4037c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, " | %s", p->m_name);
4047c478bd9Sstevel@tonic-gate 	(void) puts(" ]");
4057c478bd9Sstevel@tonic-gate }
4067c478bd9Sstevel@tonic-gate 
4077c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4087c478bd9Sstevel@tonic-gate static void
setbinary(int argc,char ** argv)4097c478bd9Sstevel@tonic-gate setbinary(int argc, char **argv)
4107c478bd9Sstevel@tonic-gate {
4117c478bd9Sstevel@tonic-gate 	setmode("octet");
4127c478bd9Sstevel@tonic-gate }
4137c478bd9Sstevel@tonic-gate 
4147c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4157c478bd9Sstevel@tonic-gate static void
setascii(int argc,char ** argv)4167c478bd9Sstevel@tonic-gate setascii(int argc, char **argv)
4177c478bd9Sstevel@tonic-gate {
4187c478bd9Sstevel@tonic-gate 	setmode("netascii");
4197c478bd9Sstevel@tonic-gate }
4207c478bd9Sstevel@tonic-gate 
4217c478bd9Sstevel@tonic-gate static void
setmode(char * newmode)4227c478bd9Sstevel@tonic-gate setmode(char *newmode)
4237c478bd9Sstevel@tonic-gate {
4247c478bd9Sstevel@tonic-gate 	(void) strlcpy(mode, newmode, sizeof (mode));
4257c478bd9Sstevel@tonic-gate 	if (verbose)
4267c478bd9Sstevel@tonic-gate 		(void) printf("mode set to %s\n", mode);
4277c478bd9Sstevel@tonic-gate }
4287c478bd9Sstevel@tonic-gate 
4297c478bd9Sstevel@tonic-gate /*
4307c478bd9Sstevel@tonic-gate  * Send file(s).
4317c478bd9Sstevel@tonic-gate  */
4327c478bd9Sstevel@tonic-gate static void
put(int argc,char ** argv)4337c478bd9Sstevel@tonic-gate put(int argc, char **argv)
4347c478bd9Sstevel@tonic-gate {
4357c478bd9Sstevel@tonic-gate 	int fd;
4367c478bd9Sstevel@tonic-gate 	int n;
4377c478bd9Sstevel@tonic-gate 	char *cp, *targ;
4387c478bd9Sstevel@tonic-gate 	struct in6_addr	ipv6addr;
4397c478bd9Sstevel@tonic-gate 	struct in_addr ipv4addr;
4407c478bd9Sstevel@tonic-gate 	char buf[PATH_MAX + 1], *argtail;
4417c478bd9Sstevel@tonic-gate 
4427c478bd9Sstevel@tonic-gate 	if (argc < 2) {
443*cb76cc66SToomas Soome 		if (strlcat(line, argv[0], sizeof (line)) >= sizeof (line)) {
444*cb76cc66SToomas Soome 			(void) fprintf(stderr, "%s is too big\n", argv[0]);
445*cb76cc66SToomas Soome 			return;
446*cb76cc66SToomas Soome 		}
4477c478bd9Sstevel@tonic-gate 		if (prompt_for_arg(line, sizeof (line), "file") == -1)
4487c478bd9Sstevel@tonic-gate 			return;
449*cb76cc66SToomas Soome 		makeargv(line, &argc, &argv);
4507c478bd9Sstevel@tonic-gate 	}
4517c478bd9Sstevel@tonic-gate 	if (argc < 2) {
4527c478bd9Sstevel@tonic-gate 		putusage(argv[0]);
4537c478bd9Sstevel@tonic-gate 		return;
4547c478bd9Sstevel@tonic-gate 	}
4557c478bd9Sstevel@tonic-gate 	targ = argv[argc - 1];
4567c478bd9Sstevel@tonic-gate 	if (finddelimiter(argv[argc - 1])) {
4577c478bd9Sstevel@tonic-gate 		char *cp;
4587c478bd9Sstevel@tonic-gate 		struct hostent *hp;
4597c478bd9Sstevel@tonic-gate 		int error_num;
4607c478bd9Sstevel@tonic-gate 
4617c478bd9Sstevel@tonic-gate 		for (n = 1; n < argc - 1; n++)
4627c478bd9Sstevel@tonic-gate 			if (finddelimiter(argv[n])) {
4637c478bd9Sstevel@tonic-gate 				putusage(argv[0]);
4647c478bd9Sstevel@tonic-gate 				return;
4657c478bd9Sstevel@tonic-gate 			}
4667c478bd9Sstevel@tonic-gate 		cp = argv[argc - 1];
4677c478bd9Sstevel@tonic-gate 		targ = finddelimiter(cp);
4687c478bd9Sstevel@tonic-gate 		*targ++ = 0;
4697c478bd9Sstevel@tonic-gate 		cp = removebrackets(cp);
4707c478bd9Sstevel@tonic-gate 
4717c478bd9Sstevel@tonic-gate 		if ((hp = getipnodebyname(cp,
4727c478bd9Sstevel@tonic-gate 		    AF_INET6, AI_ALL | AI_ADDRCONFIG | AI_V4MAPPED,
4737c478bd9Sstevel@tonic-gate 		    &error_num)) == NULL) {
4747c478bd9Sstevel@tonic-gate 			unknown_host(error_num, cp);
4757c478bd9Sstevel@tonic-gate 			return;
4767c478bd9Sstevel@tonic-gate 		}
4777c478bd9Sstevel@tonic-gate 		(void) memcpy(&sin6.sin6_addr, hp->h_addr_list[0],
4787c478bd9Sstevel@tonic-gate 		    hp->h_length);
4797c478bd9Sstevel@tonic-gate 
4807c478bd9Sstevel@tonic-gate 		sin6.sin6_family = AF_INET6;
4817c478bd9Sstevel@tonic-gate 		connected = 1;
4827c478bd9Sstevel@tonic-gate 		/*
4837c478bd9Sstevel@tonic-gate 		 * If hp->h_name is a IPv4-mapped IPv6 literal, we'll convert
4847c478bd9Sstevel@tonic-gate 		 * it to IPv4 literal address.
4857c478bd9Sstevel@tonic-gate 		 */
4867c478bd9Sstevel@tonic-gate 		if ((inet_pton(AF_INET6, hp->h_name, &ipv6addr) > 0) &&
4877c478bd9Sstevel@tonic-gate 		    IN6_IS_ADDR_V4MAPPED(&ipv6addr)) {
4887c478bd9Sstevel@tonic-gate 			IN6_V4MAPPED_TO_INADDR(&ipv6addr, &ipv4addr);
4897c478bd9Sstevel@tonic-gate 			(void) inet_ntop(AF_INET, &ipv4addr, hostname,
4907c478bd9Sstevel@tonic-gate 			    sizeof (hostname));
4917c478bd9Sstevel@tonic-gate 		} else {
4927c478bd9Sstevel@tonic-gate 			(void) strlcpy(hostname, hp->h_name,
4937c478bd9Sstevel@tonic-gate 			    sizeof (hostname));
4947c478bd9Sstevel@tonic-gate 		}
4957c478bd9Sstevel@tonic-gate 	}
4967c478bd9Sstevel@tonic-gate 	if (!connected) {
4977c478bd9Sstevel@tonic-gate 		(void) fputs("No target machine specified.\n", stderr);
4987c478bd9Sstevel@tonic-gate 		return;
4997c478bd9Sstevel@tonic-gate 	}
5007c478bd9Sstevel@tonic-gate 	if (argc < 4) {
5017c478bd9Sstevel@tonic-gate 		cp = argc == 2 ? tail(targ) : argv[1];
5027c478bd9Sstevel@tonic-gate 		fd = open(cp, O_RDONLY);
5037c478bd9Sstevel@tonic-gate 		if (fd < 0) {
5047c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "tftp: %s: %s\n", cp,
5057c478bd9Sstevel@tonic-gate 			    strerror(errno));
5067c478bd9Sstevel@tonic-gate 			return;
5077c478bd9Sstevel@tonic-gate 		}
5087c478bd9Sstevel@tonic-gate 		if (verbose)
5097c478bd9Sstevel@tonic-gate 			(void) printf("putting %s to %s:%s [%s]\n",
510*cb76cc66SToomas Soome 			    cp, hostname, targ, mode);
5117c478bd9Sstevel@tonic-gate 		sin6.sin6_port = port;
5127c478bd9Sstevel@tonic-gate 		tftp_sendfile(fd, targ, mode);
5137c478bd9Sstevel@tonic-gate 		return;
5147c478bd9Sstevel@tonic-gate 	}
5157c478bd9Sstevel@tonic-gate 	/* this assumes the target is a directory */
5167c478bd9Sstevel@tonic-gate 	/* on a remote unix system.  hmmmm.  */
5177c478bd9Sstevel@tonic-gate 	if (strlen(targ) + 1 >= sizeof (buf)) {
5187c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "tftp: filename too long: %s\n", targ);
5197c478bd9Sstevel@tonic-gate 		return;
5207c478bd9Sstevel@tonic-gate 	}
5217c478bd9Sstevel@tonic-gate 	for (n = 1; n < argc - 1; n++) {
5227c478bd9Sstevel@tonic-gate 		argtail = tail(argv[n]);
5237c478bd9Sstevel@tonic-gate 		if (snprintf(buf, sizeof (buf), "%s/%s", targ, argtail) >=
5247c478bd9Sstevel@tonic-gate 		    sizeof (buf)) {
5257c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
5267c478bd9Sstevel@tonic-gate 			    "tftp: filename too long: %s/%s\n", targ, argtail);
5277c478bd9Sstevel@tonic-gate 			continue;
5287c478bd9Sstevel@tonic-gate 		}
5297c478bd9Sstevel@tonic-gate 		fd = open(argv[n], O_RDONLY);
5307c478bd9Sstevel@tonic-gate 		if (fd < 0) {
5317c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "tftp: %s: %s\n", argv[n],
5327c478bd9Sstevel@tonic-gate 			    strerror(errno));
5337c478bd9Sstevel@tonic-gate 			continue;
5347c478bd9Sstevel@tonic-gate 		}
5357c478bd9Sstevel@tonic-gate 		if (verbose)
5367c478bd9Sstevel@tonic-gate 			(void) printf("putting %s to %s:%s [%s]\n",
537*cb76cc66SToomas Soome 			    argv[n], hostname, buf, mode);
5387c478bd9Sstevel@tonic-gate 		sin6.sin6_port = port;
5397c478bd9Sstevel@tonic-gate 		tftp_sendfile(fd, buf, mode);
5407c478bd9Sstevel@tonic-gate 	}
5417c478bd9Sstevel@tonic-gate }
5427c478bd9Sstevel@tonic-gate 
5437c478bd9Sstevel@tonic-gate static void
putusage(char * s)5447c478bd9Sstevel@tonic-gate putusage(char *s)
5457c478bd9Sstevel@tonic-gate {
5467c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "usage: %s file ... host:target, or\n"
5477c478bd9Sstevel@tonic-gate 	    "       %s file ... target (when already connected)\n", s, s);
5487c478bd9Sstevel@tonic-gate }
5497c478bd9Sstevel@tonic-gate 
5507c478bd9Sstevel@tonic-gate /*
5517c478bd9Sstevel@tonic-gate  * Receive file(s).
5527c478bd9Sstevel@tonic-gate  */
5537c478bd9Sstevel@tonic-gate static void
get(int argc,char ** argv)5547c478bd9Sstevel@tonic-gate get(int argc, char **argv)
5557c478bd9Sstevel@tonic-gate {
5567c478bd9Sstevel@tonic-gate 	int fd;
5577c478bd9Sstevel@tonic-gate 	int n;
5587c478bd9Sstevel@tonic-gate 	char *cp;
5597c478bd9Sstevel@tonic-gate 	char *src;
5607c478bd9Sstevel@tonic-gate 	struct in6_addr ipv6addr;
5617c478bd9Sstevel@tonic-gate 	struct in_addr ipv4addr;
5627c478bd9Sstevel@tonic-gate 	int error_num;
5637c478bd9Sstevel@tonic-gate 
5647c478bd9Sstevel@tonic-gate 	if (argc < 2) {
565*cb76cc66SToomas Soome 		if (strlcat(line, argv[0], sizeof (line)) >= sizeof (line)) {
566*cb76cc66SToomas Soome 			(void) fprintf(stderr, "%s is too big\n", argv[0]);
567*cb76cc66SToomas Soome 			return;
568*cb76cc66SToomas Soome 		}
5697c478bd9Sstevel@tonic-gate 		if (prompt_for_arg(line, sizeof (line), "files") == -1)
5707c478bd9Sstevel@tonic-gate 			return;
571*cb76cc66SToomas Soome 		makeargv(line, &argc, &argv);
5727c478bd9Sstevel@tonic-gate 	}
5737c478bd9Sstevel@tonic-gate 	if (argc < 2) {
5747c478bd9Sstevel@tonic-gate 		getusage(argv[0]);
5757c478bd9Sstevel@tonic-gate 		return;
5767c478bd9Sstevel@tonic-gate 	}
5777c478bd9Sstevel@tonic-gate 	if (!connected) {
5787c478bd9Sstevel@tonic-gate 		for (n = 1; n < argc; n++)
5797c478bd9Sstevel@tonic-gate 			if (finddelimiter(argv[n]) == 0) {
5807c478bd9Sstevel@tonic-gate 				getusage(argv[0]);
5817c478bd9Sstevel@tonic-gate 				return;
5827c478bd9Sstevel@tonic-gate 			}
5837c478bd9Sstevel@tonic-gate 	}
5847c478bd9Sstevel@tonic-gate 	for (n = 1; n < argc; n++) {
5857c478bd9Sstevel@tonic-gate 		src = finddelimiter(argv[n]);
5867c478bd9Sstevel@tonic-gate 		if (src == NULL)
5877c478bd9Sstevel@tonic-gate 			src = argv[n];
5887c478bd9Sstevel@tonic-gate 		else {
5897c478bd9Sstevel@tonic-gate 			struct hostent *hp;
5907c478bd9Sstevel@tonic-gate 			char *hostnameinput;
5917c478bd9Sstevel@tonic-gate 
5927c478bd9Sstevel@tonic-gate 			*src++ = 0;
5937c478bd9Sstevel@tonic-gate 			hostnameinput = removebrackets(argv[n]);
5947c478bd9Sstevel@tonic-gate 
5957c478bd9Sstevel@tonic-gate 			if ((hp = getipnodebyname(hostnameinput, AF_INET6,
5967c478bd9Sstevel@tonic-gate 			    AI_ALL | AI_ADDRCONFIG | AI_V4MAPPED,
5977c478bd9Sstevel@tonic-gate 			    &error_num)) == NULL) {
5987c478bd9Sstevel@tonic-gate 				unknown_host(error_num, hostnameinput);
5997c478bd9Sstevel@tonic-gate 				continue;
6007c478bd9Sstevel@tonic-gate 			}
6017c478bd9Sstevel@tonic-gate 			(void) memcpy((caddr_t)&sin6.sin6_addr,
6027c478bd9Sstevel@tonic-gate 			    hp->h_addr_list[0], hp->h_length);
6037c478bd9Sstevel@tonic-gate 
6047c478bd9Sstevel@tonic-gate 			sin6.sin6_family = AF_INET6;
6057c478bd9Sstevel@tonic-gate 			connected = 1;
6067c478bd9Sstevel@tonic-gate 			/*
6077c478bd9Sstevel@tonic-gate 			 * If hp->h_name is a IPv4-mapped IPv6 literal, we'll
6087c478bd9Sstevel@tonic-gate 			 * convert it to IPv4 literal address.
6097c478bd9Sstevel@tonic-gate 			 */
6107c478bd9Sstevel@tonic-gate 			if ((inet_pton(AF_INET6, hp->h_name, &ipv6addr) > 0) &&
6117c478bd9Sstevel@tonic-gate 			    IN6_IS_ADDR_V4MAPPED(&ipv6addr)) {
6127c478bd9Sstevel@tonic-gate 				IN6_V4MAPPED_TO_INADDR(&ipv6addr, &ipv4addr);
6137c478bd9Sstevel@tonic-gate 				(void) inet_ntop(AF_INET, &ipv4addr, hostname,
6147c478bd9Sstevel@tonic-gate 				    sizeof (hostname));
6157c478bd9Sstevel@tonic-gate 			} else {
6167c478bd9Sstevel@tonic-gate 				(void) strlcpy(hostname, hp->h_name,
6177c478bd9Sstevel@tonic-gate 				    sizeof (hostname));
6187c478bd9Sstevel@tonic-gate 			}
6197c478bd9Sstevel@tonic-gate 		}
6207c478bd9Sstevel@tonic-gate 		if (argc < 4) {
6217c478bd9Sstevel@tonic-gate 			cp = argc == 3 ? argv[2] : tail(src);
6227c478bd9Sstevel@tonic-gate 			fd = creat(cp, 0644);
6237c478bd9Sstevel@tonic-gate 			if (fd < 0) {
6247c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, "tftp: %s: %s\n", cp,
6257c478bd9Sstevel@tonic-gate 				    strerror(errno));
6267c478bd9Sstevel@tonic-gate 				return;
6277c478bd9Sstevel@tonic-gate 			}
6287c478bd9Sstevel@tonic-gate 			if (verbose)
6297c478bd9Sstevel@tonic-gate 				(void) printf("getting from %s:%s to %s [%s]\n",
630*cb76cc66SToomas Soome 				    hostname, src, cp, mode);
6317c478bd9Sstevel@tonic-gate 			sin6.sin6_port = port;
6327c478bd9Sstevel@tonic-gate 			tftp_recvfile(fd, src, mode);
6337c478bd9Sstevel@tonic-gate 			break;
6347c478bd9Sstevel@tonic-gate 		}
6357c478bd9Sstevel@tonic-gate 		cp = tail(src);	/* new .. jdg */
6367c478bd9Sstevel@tonic-gate 		fd = creat(cp, 0644);
6377c478bd9Sstevel@tonic-gate 		if (fd < 0) {
6387c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "tftp: %s: %s\n", cp,
6397c478bd9Sstevel@tonic-gate 			    strerror(errno));
6407c478bd9Sstevel@tonic-gate 			continue;
6417c478bd9Sstevel@tonic-gate 		}
6427c478bd9Sstevel@tonic-gate 		if (verbose)
6437c478bd9Sstevel@tonic-gate 			(void) printf("getting from %s:%s to %s [%s]\n",
6447c478bd9Sstevel@tonic-gate 			    hostname, src, cp, mode);
6457c478bd9Sstevel@tonic-gate 		sin6.sin6_port = port;
6467c478bd9Sstevel@tonic-gate 		tftp_recvfile(fd, src, mode);
6477c478bd9Sstevel@tonic-gate 	}
6487c478bd9Sstevel@tonic-gate }
6497c478bd9Sstevel@tonic-gate 
6507c478bd9Sstevel@tonic-gate static void
getusage(char * s)6517c478bd9Sstevel@tonic-gate getusage(char *s)
6527c478bd9Sstevel@tonic-gate {
6537c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "usage: %s host:file host:file ... file, or\n"
6547c478bd9Sstevel@tonic-gate 	    "       %s file file ... file if connected\n", s, s);
6557c478bd9Sstevel@tonic-gate }
6567c478bd9Sstevel@tonic-gate 
6577c478bd9Sstevel@tonic-gate static void
setrexmt(int argc,char ** argv)6587c478bd9Sstevel@tonic-gate setrexmt(int argc, char **argv)
6597c478bd9Sstevel@tonic-gate {
6607c478bd9Sstevel@tonic-gate 	int t;
661*cb76cc66SToomas Soome 	const char *errstr;
6627c478bd9Sstevel@tonic-gate 
6637c478bd9Sstevel@tonic-gate 	if (argc < 2) {
664*cb76cc66SToomas Soome 		if (strlcat(line, argv[0], sizeof (line)) >= sizeof (line)) {
665*cb76cc66SToomas Soome 			(void) fprintf(stderr, "%s is too big\n", argv[0]);
666*cb76cc66SToomas Soome 			return;
667*cb76cc66SToomas Soome 		}
6687c478bd9Sstevel@tonic-gate 		if (prompt_for_arg(line, sizeof (line), "value") == -1)
6697c478bd9Sstevel@tonic-gate 			return;
670*cb76cc66SToomas Soome 		makeargv(line, &argc, &argv);
6717c478bd9Sstevel@tonic-gate 	}
6727c478bd9Sstevel@tonic-gate 	if (argc != 2) {
6737c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "usage: %s value\n", argv[0]);
6747c478bd9Sstevel@tonic-gate 		return;
6757c478bd9Sstevel@tonic-gate 	}
676*cb76cc66SToomas Soome 
677*cb76cc66SToomas Soome 	t = strtonum(argv[1], 0, INT_MAX, &errstr);
678*cb76cc66SToomas Soome 	if (errstr != NULL)
679*cb76cc66SToomas Soome 		(void) fprintf(stderr, "%s: bad value: %s\n", argv[1], errstr);
6807c478bd9Sstevel@tonic-gate 	else
6817c478bd9Sstevel@tonic-gate 		rexmtval = t;
6827c478bd9Sstevel@tonic-gate }
6837c478bd9Sstevel@tonic-gate 
6847c478bd9Sstevel@tonic-gate static void
settimeout(int argc,char ** argv)6857c478bd9Sstevel@tonic-gate settimeout(int argc, char **argv)
6867c478bd9Sstevel@tonic-gate {
6877c478bd9Sstevel@tonic-gate 	int t;
688*cb76cc66SToomas Soome 	const char *errstr;
6897c478bd9Sstevel@tonic-gate 
6907c478bd9Sstevel@tonic-gate 	if (argc < 2) {
691*cb76cc66SToomas Soome 		if (strlcat(line, argv[0], sizeof (line)) >= sizeof (line)) {
692*cb76cc66SToomas Soome 			(void) fprintf(stderr, "%s is too big\n", argv[0]);
693*cb76cc66SToomas Soome 			return;
694*cb76cc66SToomas Soome 		}
6957c478bd9Sstevel@tonic-gate 		if (prompt_for_arg(line, sizeof (line), "value") == -1)
6967c478bd9Sstevel@tonic-gate 			return;
697*cb76cc66SToomas Soome 		makeargv(line, &argc, &argv);
6987c478bd9Sstevel@tonic-gate 	}
6997c478bd9Sstevel@tonic-gate 	if (argc != 2) {
7007c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "usage: %s value\n", argv[0]);
7017c478bd9Sstevel@tonic-gate 		return;
7027c478bd9Sstevel@tonic-gate 	}
703*cb76cc66SToomas Soome 	t = strtonum(argv[1], 0, INT_MAX, &errstr);
704*cb76cc66SToomas Soome 	if (errstr != NULL)
705*cb76cc66SToomas Soome 		(void) fprintf(stderr, "%s: bad value: %s\n", argv[1], errstr);
7067c478bd9Sstevel@tonic-gate 	else
7077c478bd9Sstevel@tonic-gate 		maxtimeout = t;
7087c478bd9Sstevel@tonic-gate }
7097c478bd9Sstevel@tonic-gate 
7107c478bd9Sstevel@tonic-gate /*ARGSUSED*/
7117c478bd9Sstevel@tonic-gate static void
status(int argc,char ** argv)7127c478bd9Sstevel@tonic-gate status(int argc, char **argv)
7137c478bd9Sstevel@tonic-gate {
7147c478bd9Sstevel@tonic-gate 	if (connected)
7157c478bd9Sstevel@tonic-gate 		(void) printf("Connected to %s.\n", hostname);
7167c478bd9Sstevel@tonic-gate 	else
7177c478bd9Sstevel@tonic-gate 		(void) puts("Not connected.");
7187c478bd9Sstevel@tonic-gate 	(void) printf("Mode: %s Verbose: %s Tracing: %s\n", mode,
719*cb76cc66SToomas Soome 	    verbose ? "on" : "off", trace ? "on" : "off");
7207c478bd9Sstevel@tonic-gate 	(void) printf("Rexmt-interval: %d seconds, Max-timeout: %d seconds\n",
721*cb76cc66SToomas Soome 	    rexmtval, maxtimeout);
7227c478bd9Sstevel@tonic-gate 	(void) printf("Transfer blocksize option: ");
7237c478bd9Sstevel@tonic-gate 	if (blksize == 0)
7247c478bd9Sstevel@tonic-gate 		(void) puts("off");
7257c478bd9Sstevel@tonic-gate 	else
7267c478bd9Sstevel@tonic-gate 		(void) printf("%d bytes\n", blksize);
7277c478bd9Sstevel@tonic-gate 	(void) printf("Server rexmt-interval option: ");
7287c478bd9Sstevel@tonic-gate 	if (srexmtval == 0)
7297c478bd9Sstevel@tonic-gate 		(void) puts("off");
7307c478bd9Sstevel@tonic-gate 	else
7317c478bd9Sstevel@tonic-gate 		(void) printf("%d seconds\n", srexmtval);
7327c478bd9Sstevel@tonic-gate 	(void) printf("Transfer size option: %s\n", tsize_opt ? "on" : "off");
7337c478bd9Sstevel@tonic-gate }
7347c478bd9Sstevel@tonic-gate 
7357c478bd9Sstevel@tonic-gate /*ARGSUSED*/
7367c478bd9Sstevel@tonic-gate static void
intr(int signum)7377c478bd9Sstevel@tonic-gate intr(int signum)
7387c478bd9Sstevel@tonic-gate {
7397c478bd9Sstevel@tonic-gate 	(void) cancel_alarm();
7407c478bd9Sstevel@tonic-gate 	longjmp(toplevel, -1);
7417c478bd9Sstevel@tonic-gate }
7427c478bd9Sstevel@tonic-gate 
7437c478bd9Sstevel@tonic-gate static char *
tail(char * filename)7447c478bd9Sstevel@tonic-gate tail(char *filename)
7457c478bd9Sstevel@tonic-gate {
7467c478bd9Sstevel@tonic-gate 	char *s;
7477c478bd9Sstevel@tonic-gate 
7487c478bd9Sstevel@tonic-gate 	while (*filename != '\0') {
7497c478bd9Sstevel@tonic-gate 		s = strrchr(filename, '/');
7507c478bd9Sstevel@tonic-gate 		if (s == NULL)
7517c478bd9Sstevel@tonic-gate 			break;
7527c478bd9Sstevel@tonic-gate 		if (s[1] != '\0')
7537c478bd9Sstevel@tonic-gate 			return (&s[1]);
7547c478bd9Sstevel@tonic-gate 		*s = '\0';
7557c478bd9Sstevel@tonic-gate 	}
7567c478bd9Sstevel@tonic-gate 	return (filename);
7577c478bd9Sstevel@tonic-gate }
7587c478bd9Sstevel@tonic-gate 
7597c478bd9Sstevel@tonic-gate /*
7607c478bd9Sstevel@tonic-gate  * Command parser.
7617c478bd9Sstevel@tonic-gate  */
7627c478bd9Sstevel@tonic-gate static void
command(int top)7637c478bd9Sstevel@tonic-gate command(int top)
7647c478bd9Sstevel@tonic-gate {
7657c478bd9Sstevel@tonic-gate 	struct cmd *c;
766*cb76cc66SToomas Soome 	char *buf, **argv;
767*cb76cc66SToomas Soome 	int argc;
7687c478bd9Sstevel@tonic-gate 
7697c478bd9Sstevel@tonic-gate 	if (!top)
7707c478bd9Sstevel@tonic-gate 		(void) putchar('\n');
7717c478bd9Sstevel@tonic-gate 	for (;;) {
772*cb76cc66SToomas Soome 		buf = gl_get_line(gl, prompt, NULL, -1);
773*cb76cc66SToomas Soome 		if (buf == NULL) {
774*cb76cc66SToomas Soome 			quit(0, NULL);
7757c478bd9Sstevel@tonic-gate 		}
7767c478bd9Sstevel@tonic-gate 
777*cb76cc66SToomas Soome 		makeargv(buf, &argc, &argv);
778*cb76cc66SToomas Soome 		c = getcmd(argv[0]);
779*cb76cc66SToomas Soome 		if (c == AMBIGCMD)
780*cb76cc66SToomas Soome 			(void) fputs("?Ambiguous command\n", stderr);
781*cb76cc66SToomas Soome 		else if (c == NULL)
782*cb76cc66SToomas Soome 			(void) fputs("?Invalid command\n", stderr);
783*cb76cc66SToomas Soome 		else
784*cb76cc66SToomas Soome 			(*c->handler)(argc, argv);
7857c478bd9Sstevel@tonic-gate 	}
7867c478bd9Sstevel@tonic-gate }
7877c478bd9Sstevel@tonic-gate 
7887c478bd9Sstevel@tonic-gate static struct cmd *
getcmd(char * name)7897c478bd9Sstevel@tonic-gate getcmd(char *name)
7907c478bd9Sstevel@tonic-gate {
7917c478bd9Sstevel@tonic-gate 	char *p, *q;
7927c478bd9Sstevel@tonic-gate 	struct cmd *c, *found;
7937c478bd9Sstevel@tonic-gate 
7947c478bd9Sstevel@tonic-gate 	if (name == NULL)
7957c478bd9Sstevel@tonic-gate 		return (NULL);
7967c478bd9Sstevel@tonic-gate 
7977c478bd9Sstevel@tonic-gate 	found = NULL;
7987c478bd9Sstevel@tonic-gate 	for (c = cmdtab; (p = c->name) != NULL; c++) {
7997c478bd9Sstevel@tonic-gate 		for (q = name; *q == *p++; q++)
8007c478bd9Sstevel@tonic-gate 			if (*q == '\0')		/* exact match? */
801*cb76cc66SToomas Soome 				return (c);
8027c478bd9Sstevel@tonic-gate 		if (*q == '\0')		/* the name was a prefix */
8037c478bd9Sstevel@tonic-gate 			found = (found == NULL) ? c : AMBIGCMD;
8047c478bd9Sstevel@tonic-gate 	}
8057c478bd9Sstevel@tonic-gate 	return (found);
8067c478bd9Sstevel@tonic-gate }
8077c478bd9Sstevel@tonic-gate 
8087c478bd9Sstevel@tonic-gate /*
8097c478bd9Sstevel@tonic-gate  * Given a string, this function returns the pointer to the delimiting ':'.
8107c478bd9Sstevel@tonic-gate  * The string can contain an IPv6 literal address, which should be inside a
8117c478bd9Sstevel@tonic-gate  * pair of brackets, e.g. [1::2]. Any colons inside a pair of brackets are not
8127c478bd9Sstevel@tonic-gate  * accepted as delimiters. Returns NULL if delimiting ':' is not found.
8137c478bd9Sstevel@tonic-gate  */
8147c478bd9Sstevel@tonic-gate static char *
finddelimiter(char * str)8157c478bd9Sstevel@tonic-gate finddelimiter(char *str)
8167c478bd9Sstevel@tonic-gate {
817*cb76cc66SToomas Soome 	bool is_bracket_open = false;
8187c478bd9Sstevel@tonic-gate 	char *cp;
8197c478bd9Sstevel@tonic-gate 
8207c478bd9Sstevel@tonic-gate 	for (cp = str; *cp != '\0'; cp++) {
8217c478bd9Sstevel@tonic-gate 		if (*cp == '[')
822*cb76cc66SToomas Soome 			is_bracket_open = true;
8237c478bd9Sstevel@tonic-gate 		else if (*cp == ']')
824*cb76cc66SToomas Soome 			is_bracket_open = false;
8257c478bd9Sstevel@tonic-gate 		else if (*cp == ':' && !is_bracket_open)
8267c478bd9Sstevel@tonic-gate 			return (cp);
8277c478bd9Sstevel@tonic-gate 	}
8287c478bd9Sstevel@tonic-gate 	return (NULL);
8297c478bd9Sstevel@tonic-gate }
8307c478bd9Sstevel@tonic-gate 
8317c478bd9Sstevel@tonic-gate /*
8327c478bd9Sstevel@tonic-gate  * Given a string which is possibly surrounded by brackets, e.g. [1::2], this
8337c478bd9Sstevel@tonic-gate  * function returns a string after removing those brackets. If the brackets
8347c478bd9Sstevel@tonic-gate  * don't match, it does nothing.
8357c478bd9Sstevel@tonic-gate  */
8367c478bd9Sstevel@tonic-gate static char *
removebrackets(char * str)8377c478bd9Sstevel@tonic-gate removebrackets(char *str)
8387c478bd9Sstevel@tonic-gate {
8397c478bd9Sstevel@tonic-gate 	char *newstr = str;
8407c478bd9Sstevel@tonic-gate 
8417c478bd9Sstevel@tonic-gate 	if ((str[0] == '[') && (str[strlen(str) - 1] == ']')) {
8427c478bd9Sstevel@tonic-gate 		newstr = str + 1;
8437c478bd9Sstevel@tonic-gate 		str[strlen(str) - 1] = '\0';
8447c478bd9Sstevel@tonic-gate 	}
8457c478bd9Sstevel@tonic-gate 	return (newstr);
8467c478bd9Sstevel@tonic-gate }
8477c478bd9Sstevel@tonic-gate 
8487c478bd9Sstevel@tonic-gate #define	MARGV_INC	20
8497c478bd9Sstevel@tonic-gate 
8507c478bd9Sstevel@tonic-gate /*
8517c478bd9Sstevel@tonic-gate  * Slice a string up into argc/argv.
8527c478bd9Sstevel@tonic-gate  */
8537c478bd9Sstevel@tonic-gate static void
makeargv(char * buf,int * argcp,char *** argvp)854*cb76cc66SToomas Soome makeargv(char *buf, int *argcp, char ***argvp)
8557c478bd9Sstevel@tonic-gate {
8567c478bd9Sstevel@tonic-gate 	char *cp;
8577c478bd9Sstevel@tonic-gate 	char **argp;
8587c478bd9Sstevel@tonic-gate 	int argc;
8597c478bd9Sstevel@tonic-gate 	static char **argv;
8607c478bd9Sstevel@tonic-gate 	static int argv_size;
8617c478bd9Sstevel@tonic-gate 
8627c478bd9Sstevel@tonic-gate 	if (argv == NULL) {
8637c478bd9Sstevel@tonic-gate 		argv_size = MARGV_INC;
8647c478bd9Sstevel@tonic-gate 		if ((argv = malloc(argv_size * sizeof (char *))) == NULL) {
8657c478bd9Sstevel@tonic-gate 			perror("tftp: malloc");
8667c478bd9Sstevel@tonic-gate 			exit(1);
8677c478bd9Sstevel@tonic-gate 		}
8687c478bd9Sstevel@tonic-gate 	}
8697c478bd9Sstevel@tonic-gate 	argc = 0;
8707c478bd9Sstevel@tonic-gate 	argp = argv;
871*cb76cc66SToomas Soome 	for (cp = buf; *cp != '\0'; ) {
8727c478bd9Sstevel@tonic-gate 		while (isspace(*cp))
8737c478bd9Sstevel@tonic-gate 			cp++;
8747c478bd9Sstevel@tonic-gate 		if (*cp == '\0')
8757c478bd9Sstevel@tonic-gate 			break;
8767c478bd9Sstevel@tonic-gate 		*argp++ = cp;
8777c478bd9Sstevel@tonic-gate 		argc++;
8787c478bd9Sstevel@tonic-gate 		if (argc == argv_size) {
8797c478bd9Sstevel@tonic-gate 			argv_size += MARGV_INC;
8807c478bd9Sstevel@tonic-gate 			if ((argv = realloc(argv,
8817c478bd9Sstevel@tonic-gate 			    argv_size * sizeof (char *))) == NULL) {
8827c478bd9Sstevel@tonic-gate 				perror("tftp: realloc");
8837c478bd9Sstevel@tonic-gate 				exit(1);
8847c478bd9Sstevel@tonic-gate 			}
8857c478bd9Sstevel@tonic-gate 			argp = argv + argc;
8867c478bd9Sstevel@tonic-gate 		}
8877c478bd9Sstevel@tonic-gate 		while (*cp != '\0' && !isspace(*cp))
8887c478bd9Sstevel@tonic-gate 			cp++;
8897c478bd9Sstevel@tonic-gate 		if (*cp == '\0')
8907c478bd9Sstevel@tonic-gate 			break;
8917c478bd9Sstevel@tonic-gate 		*cp++ = '\0';
8927c478bd9Sstevel@tonic-gate 	}
8937c478bd9Sstevel@tonic-gate 	*argp = NULL;
8947c478bd9Sstevel@tonic-gate 
8957c478bd9Sstevel@tonic-gate 	*argcp = argc;
8967c478bd9Sstevel@tonic-gate 	*argvp = argv;
8977c478bd9Sstevel@tonic-gate }
8987c478bd9Sstevel@tonic-gate 
8997c478bd9Sstevel@tonic-gate /*ARGSUSED*/
9007c478bd9Sstevel@tonic-gate static void
quit(int argc,char ** argv)9017c478bd9Sstevel@tonic-gate quit(int argc, char **argv)
9027c478bd9Sstevel@tonic-gate {
9037c478bd9Sstevel@tonic-gate 	exit(0);
9047c478bd9Sstevel@tonic-gate }
9057c478bd9Sstevel@tonic-gate 
9067c478bd9Sstevel@tonic-gate /*
9077c478bd9Sstevel@tonic-gate  * Help command.
9087c478bd9Sstevel@tonic-gate  */
9097c478bd9Sstevel@tonic-gate static void
help(int argc,char ** argv)9107c478bd9Sstevel@tonic-gate help(int argc, char **argv)
9117c478bd9Sstevel@tonic-gate {
9127c478bd9Sstevel@tonic-gate 	struct cmd *c;
9137c478bd9Sstevel@tonic-gate 
9147c478bd9Sstevel@tonic-gate 	if (argc == 1) {
9157c478bd9Sstevel@tonic-gate 		(void) puts("Commands may be abbreviated.  Commands are:\n");
9167c478bd9Sstevel@tonic-gate 		for (c = cmdtab; c->name != NULL; c++)
9177c478bd9Sstevel@tonic-gate 			(void) printf("%-*s\t%s\n", HELPINDENT, c->name,
9187c478bd9Sstevel@tonic-gate 			    c->help);
9197c478bd9Sstevel@tonic-gate 		return;
9207c478bd9Sstevel@tonic-gate 	}
9217c478bd9Sstevel@tonic-gate 	while (--argc > 0) {
9227c478bd9Sstevel@tonic-gate 		char *arg;
9237c478bd9Sstevel@tonic-gate 		arg = *++argv;
9247c478bd9Sstevel@tonic-gate 		c = getcmd(arg);
9257c478bd9Sstevel@tonic-gate 		if (c == AMBIGCMD)
9267c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "?Ambiguous help command %s\n",
9277c478bd9Sstevel@tonic-gate 			    arg);
9287c478bd9Sstevel@tonic-gate 		else if (c == NULL)
9297c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "?Invalid help command %s\n",
9307c478bd9Sstevel@tonic-gate 			    arg);
9317c478bd9Sstevel@tonic-gate 		else
9327c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "%s\n", c->help);
9337c478bd9Sstevel@tonic-gate 	}
9347c478bd9Sstevel@tonic-gate }
9357c478bd9Sstevel@tonic-gate 
9367c478bd9Sstevel@tonic-gate /*ARGSUSED*/
9377c478bd9Sstevel@tonic-gate static void
settrace(int argc,char ** argv)9387c478bd9Sstevel@tonic-gate settrace(int argc, char **argv)
9397c478bd9Sstevel@tonic-gate {
9407c478bd9Sstevel@tonic-gate 	trace = !trace;
9417c478bd9Sstevel@tonic-gate 	(void) printf("Packet tracing %s.\n", trace ? "on" : "off");
9427c478bd9Sstevel@tonic-gate }
9437c478bd9Sstevel@tonic-gate 
9447c478bd9Sstevel@tonic-gate /*ARGSUSED*/
9457c478bd9Sstevel@tonic-gate static void
setverbose(int argc,char ** argv)9467c478bd9Sstevel@tonic-gate setverbose(int argc, char **argv)
9477c478bd9Sstevel@tonic-gate {
9487c478bd9Sstevel@tonic-gate 	verbose = !verbose;
9497c478bd9Sstevel@tonic-gate 	(void) printf("Verbose mode %s.\n", verbose ? "on" : "off");
9507c478bd9Sstevel@tonic-gate }
9517c478bd9Sstevel@tonic-gate 
9527c478bd9Sstevel@tonic-gate static void
setblksize(int argc,char ** argv)9537c478bd9Sstevel@tonic-gate setblksize(int argc, char **argv)
9547c478bd9Sstevel@tonic-gate {
9557c478bd9Sstevel@tonic-gate 	int b;
956*cb76cc66SToomas Soome 	const char *errstr;
9577c478bd9Sstevel@tonic-gate 
9587c478bd9Sstevel@tonic-gate 	if (argc < 2) {
959*cb76cc66SToomas Soome 		if (strlcat(line, argv[0], sizeof (line)) >= sizeof (line)) {
960*cb76cc66SToomas Soome 			(void) fprintf(stderr, "%s is too big\n", argv[0]);
961*cb76cc66SToomas Soome 			return;
962*cb76cc66SToomas Soome 		}
9637c478bd9Sstevel@tonic-gate 		if (prompt_for_arg(line, sizeof (line), "value") == -1)
9647c478bd9Sstevel@tonic-gate 			return;
965*cb76cc66SToomas Soome 		makeargv(line, &argc, &argv);
9667c478bd9Sstevel@tonic-gate 	}
9677c478bd9Sstevel@tonic-gate 	if (argc != 2) {
9687c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "usage: %s value\n", argv[0]);
9697c478bd9Sstevel@tonic-gate 		return;
9707c478bd9Sstevel@tonic-gate 	}
9717c478bd9Sstevel@tonic-gate 
9727c478bd9Sstevel@tonic-gate 	/* RFC 2348 specifies valid blksize range, allow 0 to turn option off */
973*cb76cc66SToomas Soome 	errno = 0;
974*cb76cc66SToomas Soome 	b = strtonum(argv[1], 0, MAX_BLKSIZE, &errstr);
975*cb76cc66SToomas Soome 	if (errstr != NULL || (b > 0 && b < MIN_BLKSIZE))
976*cb76cc66SToomas Soome 		(void) fprintf(stderr, "%s: bad value: %s\n", argv[1], errstr);
9777c478bd9Sstevel@tonic-gate 	else
9787c478bd9Sstevel@tonic-gate 		blksize = b;
9797c478bd9Sstevel@tonic-gate }
9807c478bd9Sstevel@tonic-gate 
9817c478bd9Sstevel@tonic-gate static void
setsrexmt(int argc,char ** argv)9827c478bd9Sstevel@tonic-gate setsrexmt(int argc, char **argv)
9837c478bd9Sstevel@tonic-gate {
9847c478bd9Sstevel@tonic-gate 	int t;
985*cb76cc66SToomas Soome 	const char *errstr;
9867c478bd9Sstevel@tonic-gate 
9877c478bd9Sstevel@tonic-gate 	if (argc < 2) {
988*cb76cc66SToomas Soome 		if (strlcat(line, argv[0], sizeof (line)) >= sizeof (line)) {
989*cb76cc66SToomas Soome 			(void) fprintf(stderr, "%s is too big\n", argv[0]);
990*cb76cc66SToomas Soome 			return;
991*cb76cc66SToomas Soome 		}
9927c478bd9Sstevel@tonic-gate 		if (prompt_for_arg(line, sizeof (line), "value") == -1)
9937c478bd9Sstevel@tonic-gate 			return;
994*cb76cc66SToomas Soome 		makeargv(line, &argc, &argv);
9957c478bd9Sstevel@tonic-gate 	}
9967c478bd9Sstevel@tonic-gate 	if (argc != 2) {
9977c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "usage: %s value\n", argv[0]);
9987c478bd9Sstevel@tonic-gate 		return;
9997c478bd9Sstevel@tonic-gate 	}
10007c478bd9Sstevel@tonic-gate 
10017c478bd9Sstevel@tonic-gate 	/* RFC 2349 specifies valid timeout range, allow 0 to turn option off */
1002*cb76cc66SToomas Soome 	t = strtonum(argv[1], 0, MAX_TIMEOUT, &errstr);
1003*cb76cc66SToomas Soome 	if (errstr != NULL || (t > 0 && t < MIN_TIMEOUT))
1004*cb76cc66SToomas Soome 		(void) fprintf(stderr, "%s: bad value: %s\n", argv[1], errstr);
10057c478bd9Sstevel@tonic-gate 	else
10067c478bd9Sstevel@tonic-gate 		srexmtval = t;
10077c478bd9Sstevel@tonic-gate }
10087c478bd9Sstevel@tonic-gate 
10097c478bd9Sstevel@tonic-gate static void
settsize(int argc,char ** argv)10107c478bd9Sstevel@tonic-gate settsize(int argc, char **argv)
10117c478bd9Sstevel@tonic-gate {
10127c478bd9Sstevel@tonic-gate 	if (argc != 1) {
10137c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "usage: %s\n", argv[0]);
10147c478bd9Sstevel@tonic-gate 		return;
10157c478bd9Sstevel@tonic-gate 	}
10167c478bd9Sstevel@tonic-gate 	tsize_opt = !tsize_opt;
10177c478bd9Sstevel@tonic-gate 	(void) printf("Transfer size option %s.\n", tsize_opt ? "on" : "off");
10187c478bd9Sstevel@tonic-gate }
1019