sftp.c revision 204917
1/* $OpenBSD: sftp.c,v 1.123 2010/01/27 19:21:39 djm Exp $ */
2/*
3 * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18#include "includes.h"
19
20#include <sys/types.h>
21#include <sys/ioctl.h>
22#ifdef HAVE_SYS_STAT_H
23# include <sys/stat.h>
24#endif
25#include <sys/param.h>
26#include <sys/socket.h>
27#include <sys/wait.h>
28#ifdef HAVE_SYS_STATVFS_H
29#include <sys/statvfs.h>
30#endif
31
32#include <ctype.h>
33#include <errno.h>
34
35#ifdef HAVE_PATHS_H
36# include <paths.h>
37#endif
38#ifdef HAVE_LIBGEN_H
39#include <libgen.h>
40#endif
41#ifdef USE_LIBEDIT
42#include <histedit.h>
43#else
44typedef void EditLine;
45#endif
46#include <signal.h>
47#include <stdlib.h>
48#include <stdio.h>
49#include <string.h>
50#include <unistd.h>
51#include <stdarg.h>
52
53#ifdef HAVE_UTIL_H
54# include <util.h>
55#endif
56
57#ifdef HAVE_LIBUTIL_H
58# include <libutil.h>
59#endif
60
61#include "xmalloc.h"
62#include "log.h"
63#include "pathnames.h"
64#include "misc.h"
65
66#include "sftp.h"
67#include "buffer.h"
68#include "sftp-common.h"
69#include "sftp-client.h"
70
71#define DEFAULT_COPY_BUFLEN	32768	/* Size of buffer for up/download */
72#define DEFAULT_NUM_REQUESTS	64	/* # concurrent outstanding requests */
73
74/* File to read commands from */
75FILE* infile;
76
77/* Are we in batchfile mode? */
78int batchmode = 0;
79
80/* PID of ssh transport process */
81static pid_t sshpid = -1;
82
83/* This is set to 0 if the progressmeter is not desired. */
84int showprogress = 1;
85
86/* When this option is set, we always recursively download/upload directories */
87int global_rflag = 0;
88
89/* When this option is set, the file transfers will always preserve times */
90int global_pflag = 0;
91
92/* SIGINT received during command processing */
93volatile sig_atomic_t interrupted = 0;
94
95/* I wish qsort() took a separate ctx for the comparison function...*/
96int sort_flag;
97
98/* Context used for commandline completion */
99struct complete_ctx {
100	struct sftp_conn *conn;
101	char **remote_pathp;
102};
103
104int remote_glob(struct sftp_conn *, const char *, int,
105    int (*)(const char *, int), glob_t *); /* proto for sftp-glob.c */
106
107extern char *__progname;
108
109/* Separators for interactive commands */
110#define WHITESPACE " \t\r\n"
111
112/* ls flags */
113#define LS_LONG_VIEW	0x0001	/* Full view ala ls -l */
114#define LS_SHORT_VIEW	0x0002	/* Single row view ala ls -1 */
115#define LS_NUMERIC_VIEW	0x0004	/* Long view with numeric uid/gid */
116#define LS_NAME_SORT	0x0008	/* Sort by name (default) */
117#define LS_TIME_SORT	0x0010	/* Sort by mtime */
118#define LS_SIZE_SORT	0x0020	/* Sort by file size */
119#define LS_REVERSE_SORT	0x0040	/* Reverse sort order */
120#define LS_SHOW_ALL	0x0080	/* Don't skip filenames starting with '.' */
121#define LS_SI_UNITS	0x0100	/* Display sizes as K, M, G, etc. */
122
123#define VIEW_FLAGS	(LS_LONG_VIEW|LS_SHORT_VIEW|LS_NUMERIC_VIEW|LS_SI_UNITS)
124#define SORT_FLAGS	(LS_NAME_SORT|LS_TIME_SORT|LS_SIZE_SORT)
125
126/* Commands for interactive mode */
127#define I_CHDIR		1
128#define I_CHGRP		2
129#define I_CHMOD		3
130#define I_CHOWN		4
131#define I_DF		24
132#define I_GET		5
133#define I_HELP		6
134#define I_LCHDIR	7
135#define I_LLS		8
136#define I_LMKDIR	9
137#define I_LPWD		10
138#define I_LS		11
139#define I_LUMASK	12
140#define I_MKDIR		13
141#define I_PUT		14
142#define I_PWD		15
143#define I_QUIT		16
144#define I_RENAME	17
145#define I_RM		18
146#define I_RMDIR		19
147#define I_SHELL		20
148#define I_SYMLINK	21
149#define I_VERSION	22
150#define I_PROGRESS	23
151
152struct CMD {
153	const char *c;
154	const int n;
155	const int t;
156};
157
158/* Type of completion */
159#define NOARGS	0
160#define REMOTE	1
161#define LOCAL	2
162
163static const struct CMD cmds[] = {
164	{ "bye",	I_QUIT,		NOARGS	},
165	{ "cd",		I_CHDIR,	REMOTE	},
166	{ "chdir",	I_CHDIR,	REMOTE	},
167	{ "chgrp",	I_CHGRP,	REMOTE	},
168	{ "chmod",	I_CHMOD,	REMOTE	},
169	{ "chown",	I_CHOWN,	REMOTE	},
170	{ "df",		I_DF,		REMOTE	},
171	{ "dir",	I_LS,		REMOTE	},
172	{ "exit",	I_QUIT,		NOARGS	},
173	{ "get",	I_GET,		REMOTE	},
174	{ "help",	I_HELP,		NOARGS	},
175	{ "lcd",	I_LCHDIR,	LOCAL	},
176	{ "lchdir",	I_LCHDIR,	LOCAL	},
177	{ "lls",	I_LLS,		LOCAL	},
178	{ "lmkdir",	I_LMKDIR,	LOCAL	},
179	{ "ln",		I_SYMLINK,	REMOTE	},
180	{ "lpwd",	I_LPWD,		LOCAL	},
181	{ "ls",		I_LS,		REMOTE	},
182	{ "lumask",	I_LUMASK,	NOARGS	},
183	{ "mkdir",	I_MKDIR,	REMOTE	},
184	{ "progress",	I_PROGRESS,	NOARGS	},
185	{ "put",	I_PUT,		LOCAL	},
186	{ "pwd",	I_PWD,		REMOTE	},
187	{ "quit",	I_QUIT,		NOARGS	},
188	{ "rename",	I_RENAME,	REMOTE	},
189	{ "rm",		I_RM,		REMOTE	},
190	{ "rmdir",	I_RMDIR,	REMOTE	},
191	{ "symlink",	I_SYMLINK,	REMOTE	},
192	{ "version",	I_VERSION,	NOARGS	},
193	{ "!",		I_SHELL,	NOARGS	},
194	{ "?",		I_HELP,		NOARGS	},
195	{ NULL,		-1,		-1	}
196};
197
198int interactive_loop(struct sftp_conn *, char *file1, char *file2);
199
200/* ARGSUSED */
201static void
202killchild(int signo)
203{
204	if (sshpid > 1) {
205		kill(sshpid, SIGTERM);
206		waitpid(sshpid, NULL, 0);
207	}
208
209	_exit(1);
210}
211
212/* ARGSUSED */
213static void
214cmd_interrupt(int signo)
215{
216	const char msg[] = "\rInterrupt  \n";
217	int olderrno = errno;
218
219	write(STDERR_FILENO, msg, sizeof(msg) - 1);
220	interrupted = 1;
221	errno = olderrno;
222}
223
224static void
225help(void)
226{
227	printf("Available commands:\n"
228	    "bye                                Quit sftp\n"
229	    "cd path                            Change remote directory to 'path'\n"
230	    "chgrp grp path                     Change group of file 'path' to 'grp'\n"
231	    "chmod mode path                    Change permissions of file 'path' to 'mode'\n"
232	    "chown own path                     Change owner of file 'path' to 'own'\n"
233	    "df [-hi] [path]                    Display statistics for current directory or\n"
234	    "                                   filesystem containing 'path'\n"
235	    "exit                               Quit sftp\n"
236	    "get [-Ppr] remote [local]          Download file\n"
237	    "help                               Display this help text\n"
238	    "lcd path                           Change local directory to 'path'\n"
239	    "lls [ls-options [path]]            Display local directory listing\n"
240	    "lmkdir path                        Create local directory\n"
241	    "ln oldpath newpath                 Symlink remote file\n"
242	    "lpwd                               Print local working directory\n"
243	    "ls [-1afhlnrSt] [path]             Display remote directory listing\n"
244	    "lumask umask                       Set local umask to 'umask'\n"
245	    "mkdir path                         Create remote directory\n"
246	    "progress                           Toggle display of progress meter\n"
247	    "put [-Ppr] local [remote]          Upload file\n"
248	    "pwd                                Display remote working directory\n"
249	    "quit                               Quit sftp\n"
250	    "rename oldpath newpath             Rename remote file\n"
251	    "rm path                            Delete remote file\n"
252	    "rmdir path                         Remove remote directory\n"
253	    "symlink oldpath newpath            Symlink remote file\n"
254	    "version                            Show SFTP version\n"
255	    "!command                           Execute 'command' in local shell\n"
256	    "!                                  Escape to local shell\n"
257	    "?                                  Synonym for help\n");
258}
259
260static void
261local_do_shell(const char *args)
262{
263	int status;
264	char *shell;
265	pid_t pid;
266
267	if (!*args)
268		args = NULL;
269
270	if ((shell = getenv("SHELL")) == NULL)
271		shell = _PATH_BSHELL;
272
273	if ((pid = fork()) == -1)
274		fatal("Couldn't fork: %s", strerror(errno));
275
276	if (pid == 0) {
277		/* XXX: child has pipe fds to ssh subproc open - issue? */
278		if (args) {
279			debug3("Executing %s -c \"%s\"", shell, args);
280			execl(shell, shell, "-c", args, (char *)NULL);
281		} else {
282			debug3("Executing %s", shell);
283			execl(shell, shell, (char *)NULL);
284		}
285		fprintf(stderr, "Couldn't execute \"%s\": %s\n", shell,
286		    strerror(errno));
287		_exit(1);
288	}
289	while (waitpid(pid, &status, 0) == -1)
290		if (errno != EINTR)
291			fatal("Couldn't wait for child: %s", strerror(errno));
292	if (!WIFEXITED(status))
293		error("Shell exited abnormally");
294	else if (WEXITSTATUS(status))
295		error("Shell exited with status %d", WEXITSTATUS(status));
296}
297
298static void
299local_do_ls(const char *args)
300{
301	if (!args || !*args)
302		local_do_shell(_PATH_LS);
303	else {
304		int len = strlen(_PATH_LS " ") + strlen(args) + 1;
305		char *buf = xmalloc(len);
306
307		/* XXX: quoting - rip quoting code from ftp? */
308		snprintf(buf, len, _PATH_LS " %s", args);
309		local_do_shell(buf);
310		xfree(buf);
311	}
312}
313
314/* Strip one path (usually the pwd) from the start of another */
315static char *
316path_strip(char *path, char *strip)
317{
318	size_t len;
319
320	if (strip == NULL)
321		return (xstrdup(path));
322
323	len = strlen(strip);
324	if (strncmp(path, strip, len) == 0) {
325		if (strip[len - 1] != '/' && path[len] == '/')
326			len++;
327		return (xstrdup(path + len));
328	}
329
330	return (xstrdup(path));
331}
332
333static char *
334make_absolute(char *p, char *pwd)
335{
336	char *abs_str;
337
338	/* Derelativise */
339	if (p && p[0] != '/') {
340		abs_str = path_append(pwd, p);
341		xfree(p);
342		return(abs_str);
343	} else
344		return(p);
345}
346
347static int
348parse_getput_flags(const char *cmd, char **argv, int argc, int *pflag,
349    int *rflag)
350{
351	extern int opterr, optind, optopt, optreset;
352	int ch;
353
354	optind = optreset = 1;
355	opterr = 0;
356
357	*rflag = *pflag = 0;
358	while ((ch = getopt(argc, argv, "PpRr")) != -1) {
359		switch (ch) {
360		case 'p':
361		case 'P':
362			*pflag = 1;
363			break;
364		case 'r':
365		case 'R':
366			*rflag = 1;
367			break;
368		default:
369			error("%s: Invalid flag -%c", cmd, optopt);
370			return -1;
371		}
372	}
373
374	return optind;
375}
376
377static int
378parse_ls_flags(char **argv, int argc, int *lflag)
379{
380	extern int opterr, optind, optopt, optreset;
381	int ch;
382
383	optind = optreset = 1;
384	opterr = 0;
385
386	*lflag = LS_NAME_SORT;
387	while ((ch = getopt(argc, argv, "1Safhlnrt")) != -1) {
388		switch (ch) {
389		case '1':
390			*lflag &= ~VIEW_FLAGS;
391			*lflag |= LS_SHORT_VIEW;
392			break;
393		case 'S':
394			*lflag &= ~SORT_FLAGS;
395			*lflag |= LS_SIZE_SORT;
396			break;
397		case 'a':
398			*lflag |= LS_SHOW_ALL;
399			break;
400		case 'f':
401			*lflag &= ~SORT_FLAGS;
402			break;
403		case 'h':
404			*lflag |= LS_SI_UNITS;
405			break;
406		case 'l':
407			*lflag &= ~LS_SHORT_VIEW;
408			*lflag |= LS_LONG_VIEW;
409			break;
410		case 'n':
411			*lflag &= ~LS_SHORT_VIEW;
412			*lflag |= LS_NUMERIC_VIEW|LS_LONG_VIEW;
413			break;
414		case 'r':
415			*lflag |= LS_REVERSE_SORT;
416			break;
417		case 't':
418			*lflag &= ~SORT_FLAGS;
419			*lflag |= LS_TIME_SORT;
420			break;
421		default:
422			error("ls: Invalid flag -%c", optopt);
423			return -1;
424		}
425	}
426
427	return optind;
428}
429
430static int
431parse_df_flags(const char *cmd, char **argv, int argc, int *hflag, int *iflag)
432{
433	extern int opterr, optind, optopt, optreset;
434	int ch;
435
436	optind = optreset = 1;
437	opterr = 0;
438
439	*hflag = *iflag = 0;
440	while ((ch = getopt(argc, argv, "hi")) != -1) {
441		switch (ch) {
442		case 'h':
443			*hflag = 1;
444			break;
445		case 'i':
446			*iflag = 1;
447			break;
448		default:
449			error("%s: Invalid flag -%c", cmd, optopt);
450			return -1;
451		}
452	}
453
454	return optind;
455}
456
457static int
458is_dir(char *path)
459{
460	struct stat sb;
461
462	/* XXX: report errors? */
463	if (stat(path, &sb) == -1)
464		return(0);
465
466	return(S_ISDIR(sb.st_mode));
467}
468
469static int
470remote_is_dir(struct sftp_conn *conn, char *path)
471{
472	Attrib *a;
473
474	/* XXX: report errors? */
475	if ((a = do_stat(conn, path, 1)) == NULL)
476		return(0);
477	if (!(a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS))
478		return(0);
479	return(S_ISDIR(a->perm));
480}
481
482/* Check whether path returned from glob(..., GLOB_MARK, ...) is a directory */
483static int
484pathname_is_dir(char *pathname)
485{
486	size_t l = strlen(pathname);
487
488	return l > 0 && pathname[l - 1] == '/';
489}
490
491static int
492process_get(struct sftp_conn *conn, char *src, char *dst, char *pwd,
493    int pflag, int rflag)
494{
495	char *abs_src = NULL;
496	char *abs_dst = NULL;
497	glob_t g;
498	char *filename, *tmp=NULL;
499	int i, err = 0;
500
501	abs_src = xstrdup(src);
502	abs_src = make_absolute(abs_src, pwd);
503	memset(&g, 0, sizeof(g));
504
505	debug3("Looking up %s", abs_src);
506	if (remote_glob(conn, abs_src, GLOB_MARK, NULL, &g)) {
507		error("File \"%s\" not found.", abs_src);
508		err = -1;
509		goto out;
510	}
511
512	/*
513	 * If multiple matches then dst must be a directory or
514	 * unspecified.
515	 */
516	if (g.gl_matchc > 1 && dst != NULL && !is_dir(dst)) {
517		error("Multiple source paths, but destination "
518		    "\"%s\" is not a directory", dst);
519		err = -1;
520		goto out;
521	}
522
523	for (i = 0; g.gl_pathv[i] && !interrupted; i++) {
524		tmp = xstrdup(g.gl_pathv[i]);
525		if ((filename = basename(tmp)) == NULL) {
526			error("basename %s: %s", tmp, strerror(errno));
527			xfree(tmp);
528			err = -1;
529			goto out;
530		}
531
532		if (g.gl_matchc == 1 && dst) {
533			if (is_dir(dst)) {
534				abs_dst = path_append(dst, filename);
535			} else {
536				abs_dst = xstrdup(dst);
537			}
538		} else if (dst) {
539			abs_dst = path_append(dst, filename);
540		} else {
541			abs_dst = xstrdup(filename);
542		}
543		xfree(tmp);
544
545		printf("Fetching %s to %s\n", g.gl_pathv[i], abs_dst);
546		if (pathname_is_dir(g.gl_pathv[i]) && (rflag || global_rflag)) {
547			if (download_dir(conn, g.gl_pathv[i], abs_dst, NULL,
548			    pflag || global_pflag, 1) == -1)
549				err = -1;
550		} else {
551			if (do_download(conn, g.gl_pathv[i], abs_dst, NULL,
552			    pflag || global_pflag) == -1)
553				err = -1;
554		}
555		xfree(abs_dst);
556		abs_dst = NULL;
557	}
558
559out:
560	xfree(abs_src);
561	globfree(&g);
562	return(err);
563}
564
565static int
566process_put(struct sftp_conn *conn, char *src, char *dst, char *pwd,
567    int pflag, int rflag)
568{
569	char *tmp_dst = NULL;
570	char *abs_dst = NULL;
571	char *tmp = NULL, *filename = NULL;
572	glob_t g;
573	int err = 0;
574	int i, dst_is_dir = 1;
575	struct stat sb;
576
577	if (dst) {
578		tmp_dst = xstrdup(dst);
579		tmp_dst = make_absolute(tmp_dst, pwd);
580	}
581
582	memset(&g, 0, sizeof(g));
583	debug3("Looking up %s", src);
584	if (glob(src, GLOB_NOCHECK | GLOB_MARK, NULL, &g)) {
585		error("File \"%s\" not found.", src);
586		err = -1;
587		goto out;
588	}
589
590	/* If we aren't fetching to pwd then stash this status for later */
591	if (tmp_dst != NULL)
592		dst_is_dir = remote_is_dir(conn, tmp_dst);
593
594	/* If multiple matches, dst may be directory or unspecified */
595	if (g.gl_matchc > 1 && tmp_dst && !dst_is_dir) {
596		error("Multiple paths match, but destination "
597		    "\"%s\" is not a directory", tmp_dst);
598		err = -1;
599		goto out;
600	}
601
602	for (i = 0; g.gl_pathv[i] && !interrupted; i++) {
603		if (stat(g.gl_pathv[i], &sb) == -1) {
604			err = -1;
605			error("stat %s: %s", g.gl_pathv[i], strerror(errno));
606			continue;
607		}
608
609		tmp = xstrdup(g.gl_pathv[i]);
610		if ((filename = basename(tmp)) == NULL) {
611			error("basename %s: %s", tmp, strerror(errno));
612			xfree(tmp);
613			err = -1;
614			goto out;
615		}
616
617		if (g.gl_matchc == 1 && tmp_dst) {
618			/* If directory specified, append filename */
619			if (dst_is_dir)
620				abs_dst = path_append(tmp_dst, filename);
621			else
622				abs_dst = xstrdup(tmp_dst);
623		} else if (tmp_dst) {
624			abs_dst = path_append(tmp_dst, filename);
625		} else {
626			abs_dst = make_absolute(xstrdup(filename), pwd);
627		}
628		xfree(tmp);
629
630		printf("Uploading %s to %s\n", g.gl_pathv[i], abs_dst);
631		if (pathname_is_dir(g.gl_pathv[i]) && (rflag || global_rflag)) {
632			if (upload_dir(conn, g.gl_pathv[i], abs_dst,
633			    pflag || global_pflag, 1) == -1)
634				err = -1;
635		} else {
636			if (do_upload(conn, g.gl_pathv[i], abs_dst,
637			    pflag || global_pflag) == -1)
638				err = -1;
639		}
640	}
641
642out:
643	if (abs_dst)
644		xfree(abs_dst);
645	if (tmp_dst)
646		xfree(tmp_dst);
647	globfree(&g);
648	return(err);
649}
650
651static int
652sdirent_comp(const void *aa, const void *bb)
653{
654	SFTP_DIRENT *a = *(SFTP_DIRENT **)aa;
655	SFTP_DIRENT *b = *(SFTP_DIRENT **)bb;
656	int rmul = sort_flag & LS_REVERSE_SORT ? -1 : 1;
657
658#define NCMP(a,b) (a == b ? 0 : (a < b ? 1 : -1))
659	if (sort_flag & LS_NAME_SORT)
660		return (rmul * strcmp(a->filename, b->filename));
661	else if (sort_flag & LS_TIME_SORT)
662		return (rmul * NCMP(a->a.mtime, b->a.mtime));
663	else if (sort_flag & LS_SIZE_SORT)
664		return (rmul * NCMP(a->a.size, b->a.size));
665
666	fatal("Unknown ls sort type");
667}
668
669/* sftp ls.1 replacement for directories */
670static int
671do_ls_dir(struct sftp_conn *conn, char *path, char *strip_path, int lflag)
672{
673	int n;
674	u_int c = 1, colspace = 0, columns = 1;
675	SFTP_DIRENT **d;
676
677	if ((n = do_readdir(conn, path, &d)) != 0)
678		return (n);
679
680	if (!(lflag & LS_SHORT_VIEW)) {
681		u_int m = 0, width = 80;
682		struct winsize ws;
683		char *tmp;
684
685		/* Count entries for sort and find longest filename */
686		for (n = 0; d[n] != NULL; n++) {
687			if (d[n]->filename[0] != '.' || (lflag & LS_SHOW_ALL))
688				m = MAX(m, strlen(d[n]->filename));
689		}
690
691		/* Add any subpath that also needs to be counted */
692		tmp = path_strip(path, strip_path);
693		m += strlen(tmp);
694		xfree(tmp);
695
696		if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) != -1)
697			width = ws.ws_col;
698
699		columns = width / (m + 2);
700		columns = MAX(columns, 1);
701		colspace = width / columns;
702		colspace = MIN(colspace, width);
703	}
704
705	if (lflag & SORT_FLAGS) {
706		for (n = 0; d[n] != NULL; n++)
707			;	/* count entries */
708		sort_flag = lflag & (SORT_FLAGS|LS_REVERSE_SORT);
709		qsort(d, n, sizeof(*d), sdirent_comp);
710	}
711
712	for (n = 0; d[n] != NULL && !interrupted; n++) {
713		char *tmp, *fname;
714
715		if (d[n]->filename[0] == '.' && !(lflag & LS_SHOW_ALL))
716			continue;
717
718		tmp = path_append(path, d[n]->filename);
719		fname = path_strip(tmp, strip_path);
720		xfree(tmp);
721
722		if (lflag & LS_LONG_VIEW) {
723			if (lflag & (LS_NUMERIC_VIEW|LS_SI_UNITS)) {
724				char *lname;
725				struct stat sb;
726
727				memset(&sb, 0, sizeof(sb));
728				attrib_to_stat(&d[n]->a, &sb);
729				lname = ls_file(fname, &sb, 1,
730				    (lflag & LS_SI_UNITS));
731				printf("%s\n", lname);
732				xfree(lname);
733			} else
734				printf("%s\n", d[n]->longname);
735		} else {
736			printf("%-*s", colspace, fname);
737			if (c >= columns) {
738				printf("\n");
739				c = 1;
740			} else
741				c++;
742		}
743
744		xfree(fname);
745	}
746
747	if (!(lflag & LS_LONG_VIEW) && (c != 1))
748		printf("\n");
749
750	free_sftp_dirents(d);
751	return (0);
752}
753
754/* sftp ls.1 replacement which handles path globs */
755static int
756do_globbed_ls(struct sftp_conn *conn, char *path, char *strip_path,
757    int lflag)
758{
759	glob_t g;
760	u_int i, c = 1, colspace = 0, columns = 1;
761	Attrib *a = NULL;
762
763	memset(&g, 0, sizeof(g));
764
765	if (remote_glob(conn, path, GLOB_MARK|GLOB_NOCHECK|GLOB_BRACE,
766	    NULL, &g) || (g.gl_pathc && !g.gl_matchc)) {
767		if (g.gl_pathc)
768			globfree(&g);
769		error("Can't ls: \"%s\" not found", path);
770		return (-1);
771	}
772
773	if (interrupted)
774		goto out;
775
776	/*
777	 * If the glob returns a single match and it is a directory,
778	 * then just list its contents.
779	 */
780	if (g.gl_matchc == 1) {
781		if ((a = do_lstat(conn, g.gl_pathv[0], 1)) == NULL) {
782			globfree(&g);
783			return (-1);
784		}
785		if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) &&
786		    S_ISDIR(a->perm)) {
787			int err;
788
789			err = do_ls_dir(conn, g.gl_pathv[0], strip_path, lflag);
790			globfree(&g);
791			return (err);
792		}
793	}
794
795	if (!(lflag & LS_SHORT_VIEW)) {
796		u_int m = 0, width = 80;
797		struct winsize ws;
798
799		/* Count entries for sort and find longest filename */
800		for (i = 0; g.gl_pathv[i]; i++)
801			m = MAX(m, strlen(g.gl_pathv[i]));
802
803		if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) != -1)
804			width = ws.ws_col;
805
806		columns = width / (m + 2);
807		columns = MAX(columns, 1);
808		colspace = width / columns;
809	}
810
811	for (i = 0; g.gl_pathv[i] && !interrupted; i++, a = NULL) {
812		char *fname;
813
814		fname = path_strip(g.gl_pathv[i], strip_path);
815
816		if (lflag & LS_LONG_VIEW) {
817			char *lname;
818			struct stat sb;
819
820			/*
821			 * XXX: this is slow - 1 roundtrip per path
822			 * A solution to this is to fork glob() and
823			 * build a sftp specific version which keeps the
824			 * attribs (which currently get thrown away)
825			 * that the server returns as well as the filenames.
826			 */
827			memset(&sb, 0, sizeof(sb));
828			if (a == NULL)
829				a = do_lstat(conn, g.gl_pathv[i], 1);
830			if (a != NULL)
831				attrib_to_stat(a, &sb);
832			lname = ls_file(fname, &sb, 1, (lflag & LS_SI_UNITS));
833			printf("%s\n", lname);
834			xfree(lname);
835		} else {
836			printf("%-*s", colspace, fname);
837			if (c >= columns) {
838				printf("\n");
839				c = 1;
840			} else
841				c++;
842		}
843		xfree(fname);
844	}
845
846	if (!(lflag & LS_LONG_VIEW) && (c != 1))
847		printf("\n");
848
849 out:
850	if (g.gl_pathc)
851		globfree(&g);
852
853	return (0);
854}
855
856static int
857do_df(struct sftp_conn *conn, char *path, int hflag, int iflag)
858{
859	struct sftp_statvfs st;
860	char s_used[FMT_SCALED_STRSIZE];
861	char s_avail[FMT_SCALED_STRSIZE];
862	char s_root[FMT_SCALED_STRSIZE];
863	char s_total[FMT_SCALED_STRSIZE];
864	unsigned long long ffree;
865
866	if (do_statvfs(conn, path, &st, 1) == -1)
867		return -1;
868	if (iflag) {
869		ffree = st.f_files ? (100 * (st.f_files - st.f_ffree) / st.f_files) : 0;
870		printf("     Inodes        Used       Avail      "
871		    "(root)    %%Capacity\n");
872		printf("%11llu %11llu %11llu %11llu         %3llu%%\n",
873		    (unsigned long long)st.f_files,
874		    (unsigned long long)(st.f_files - st.f_ffree),
875		    (unsigned long long)st.f_favail,
876		    (unsigned long long)st.f_ffree, ffree);
877	} else if (hflag) {
878		strlcpy(s_used, "error", sizeof(s_used));
879		strlcpy(s_avail, "error", sizeof(s_avail));
880		strlcpy(s_root, "error", sizeof(s_root));
881		strlcpy(s_total, "error", sizeof(s_total));
882		fmt_scaled((st.f_blocks - st.f_bfree) * st.f_frsize, s_used);
883		fmt_scaled(st.f_bavail * st.f_frsize, s_avail);
884		fmt_scaled(st.f_bfree * st.f_frsize, s_root);
885		fmt_scaled(st.f_blocks * st.f_frsize, s_total);
886		printf("    Size     Used    Avail   (root)    %%Capacity\n");
887		printf("%7sB %7sB %7sB %7sB         %3llu%%\n",
888		    s_total, s_used, s_avail, s_root,
889		    (unsigned long long)(100 * (st.f_blocks - st.f_bfree) /
890		    st.f_blocks));
891	} else {
892		printf("        Size         Used        Avail       "
893		    "(root)    %%Capacity\n");
894		printf("%12llu %12llu %12llu %12llu         %3llu%%\n",
895		    (unsigned long long)(st.f_frsize * st.f_blocks / 1024),
896		    (unsigned long long)(st.f_frsize *
897		    (st.f_blocks - st.f_bfree) / 1024),
898		    (unsigned long long)(st.f_frsize * st.f_bavail / 1024),
899		    (unsigned long long)(st.f_frsize * st.f_bfree / 1024),
900		    (unsigned long long)(100 * (st.f_blocks - st.f_bfree) /
901		    st.f_blocks));
902	}
903	return 0;
904}
905
906/*
907 * Undo escaping of glob sequences in place. Used to undo extra escaping
908 * applied in makeargv() when the string is destined for a function that
909 * does not glob it.
910 */
911static void
912undo_glob_escape(char *s)
913{
914	size_t i, j;
915
916	for (i = j = 0;;) {
917		if (s[i] == '\0') {
918			s[j] = '\0';
919			return;
920		}
921		if (s[i] != '\\') {
922			s[j++] = s[i++];
923			continue;
924		}
925		/* s[i] == '\\' */
926		++i;
927		switch (s[i]) {
928		case '?':
929		case '[':
930		case '*':
931		case '\\':
932			s[j++] = s[i++];
933			break;
934		case '\0':
935			s[j++] = '\\';
936			s[j] = '\0';
937			return;
938		default:
939			s[j++] = '\\';
940			s[j++] = s[i++];
941			break;
942		}
943	}
944}
945
946/*
947 * Split a string into an argument vector using sh(1)-style quoting,
948 * comment and escaping rules, but with some tweaks to handle glob(3)
949 * wildcards.
950 * The "sloppy" flag allows for recovery from missing terminating quote, for
951 * use in parsing incomplete commandlines during tab autocompletion.
952 *
953 * Returns NULL on error or a NULL-terminated array of arguments.
954 *
955 * If "lastquote" is not NULL, the quoting character used for the last
956 * argument is placed in *lastquote ("\0", "'" or "\"").
957 *
958 * If "terminated" is not NULL, *terminated will be set to 1 when the
959 * last argument's quote has been properly terminated or 0 otherwise.
960 * This parameter is only of use if "sloppy" is set.
961 */
962#define MAXARGS 	128
963#define MAXARGLEN	8192
964static char **
965makeargv(const char *arg, int *argcp, int sloppy, char *lastquote,
966    u_int *terminated)
967{
968	int argc, quot;
969	size_t i, j;
970	static char argvs[MAXARGLEN];
971	static char *argv[MAXARGS + 1];
972	enum { MA_START, MA_SQUOTE, MA_DQUOTE, MA_UNQUOTED } state, q;
973
974	*argcp = argc = 0;
975	if (strlen(arg) > sizeof(argvs) - 1) {
976 args_too_longs:
977		error("string too long");
978		return NULL;
979	}
980	if (terminated != NULL)
981		*terminated = 1;
982	if (lastquote != NULL)
983		*lastquote = '\0';
984	state = MA_START;
985	i = j = 0;
986	for (;;) {
987		if (isspace(arg[i])) {
988			if (state == MA_UNQUOTED) {
989				/* Terminate current argument */
990				argvs[j++] = '\0';
991				argc++;
992				state = MA_START;
993			} else if (state != MA_START)
994				argvs[j++] = arg[i];
995		} else if (arg[i] == '"' || arg[i] == '\'') {
996			q = arg[i] == '"' ? MA_DQUOTE : MA_SQUOTE;
997			if (state == MA_START) {
998				argv[argc] = argvs + j;
999				state = q;
1000				if (lastquote != NULL)
1001					*lastquote = arg[i];
1002			} else if (state == MA_UNQUOTED)
1003				state = q;
1004			else if (state == q)
1005				state = MA_UNQUOTED;
1006			else
1007				argvs[j++] = arg[i];
1008		} else if (arg[i] == '\\') {
1009			if (state == MA_SQUOTE || state == MA_DQUOTE) {
1010				quot = state == MA_SQUOTE ? '\'' : '"';
1011				/* Unescape quote we are in */
1012				/* XXX support \n and friends? */
1013				if (arg[i + 1] == quot) {
1014					i++;
1015					argvs[j++] = arg[i];
1016				} else if (arg[i + 1] == '?' ||
1017				    arg[i + 1] == '[' || arg[i + 1] == '*') {
1018					/*
1019					 * Special case for sftp: append
1020					 * double-escaped glob sequence -
1021					 * glob will undo one level of
1022					 * escaping. NB. string can grow here.
1023					 */
1024					if (j >= sizeof(argvs) - 5)
1025						goto args_too_longs;
1026					argvs[j++] = '\\';
1027					argvs[j++] = arg[i++];
1028					argvs[j++] = '\\';
1029					argvs[j++] = arg[i];
1030				} else {
1031					argvs[j++] = arg[i++];
1032					argvs[j++] = arg[i];
1033				}
1034			} else {
1035				if (state == MA_START) {
1036					argv[argc] = argvs + j;
1037					state = MA_UNQUOTED;
1038					if (lastquote != NULL)
1039						*lastquote = '\0';
1040				}
1041				if (arg[i + 1] == '?' || arg[i + 1] == '[' ||
1042				    arg[i + 1] == '*' || arg[i + 1] == '\\') {
1043					/*
1044					 * Special case for sftp: append
1045					 * escaped glob sequence -
1046					 * glob will undo one level of
1047					 * escaping.
1048					 */
1049					argvs[j++] = arg[i++];
1050					argvs[j++] = arg[i];
1051				} else {
1052					/* Unescape everything */
1053					/* XXX support \n and friends? */
1054					i++;
1055					argvs[j++] = arg[i];
1056				}
1057			}
1058		} else if (arg[i] == '#') {
1059			if (state == MA_SQUOTE || state == MA_DQUOTE)
1060				argvs[j++] = arg[i];
1061			else
1062				goto string_done;
1063		} else if (arg[i] == '\0') {
1064			if (state == MA_SQUOTE || state == MA_DQUOTE) {
1065				if (sloppy) {
1066					state = MA_UNQUOTED;
1067					if (terminated != NULL)
1068						*terminated = 0;
1069					goto string_done;
1070				}
1071				error("Unterminated quoted argument");
1072				return NULL;
1073			}
1074 string_done:
1075			if (state == MA_UNQUOTED) {
1076				argvs[j++] = '\0';
1077				argc++;
1078			}
1079			break;
1080		} else {
1081			if (state == MA_START) {
1082				argv[argc] = argvs + j;
1083				state = MA_UNQUOTED;
1084				if (lastquote != NULL)
1085					*lastquote = '\0';
1086			}
1087			if ((state == MA_SQUOTE || state == MA_DQUOTE) &&
1088			    (arg[i] == '?' || arg[i] == '[' || arg[i] == '*')) {
1089				/*
1090				 * Special case for sftp: escape quoted
1091				 * glob(3) wildcards. NB. string can grow
1092				 * here.
1093				 */
1094				if (j >= sizeof(argvs) - 3)
1095					goto args_too_longs;
1096				argvs[j++] = '\\';
1097				argvs[j++] = arg[i];
1098			} else
1099				argvs[j++] = arg[i];
1100		}
1101		i++;
1102	}
1103	*argcp = argc;
1104	return argv;
1105}
1106
1107static int
1108parse_args(const char **cpp, int *pflag, int *rflag, int *lflag, int *iflag,
1109    int *hflag, unsigned long *n_arg, char **path1, char **path2)
1110{
1111	const char *cmd, *cp = *cpp;
1112	char *cp2, **argv;
1113	int base = 0;
1114	long l;
1115	int i, cmdnum, optidx, argc;
1116
1117	/* Skip leading whitespace */
1118	cp = cp + strspn(cp, WHITESPACE);
1119
1120	/* Check for leading '-' (disable error processing) */
1121	*iflag = 0;
1122	if (*cp == '-') {
1123		*iflag = 1;
1124		cp++;
1125		cp = cp + strspn(cp, WHITESPACE);
1126	}
1127
1128	/* Ignore blank lines and lines which begin with comment '#' char */
1129	if (*cp == '\0' || *cp == '#')
1130		return (0);
1131
1132	if ((argv = makeargv(cp, &argc, 0, NULL, NULL)) == NULL)
1133		return -1;
1134
1135	/* Figure out which command we have */
1136	for (i = 0; cmds[i].c != NULL; i++) {
1137		if (strcasecmp(cmds[i].c, argv[0]) == 0)
1138			break;
1139	}
1140	cmdnum = cmds[i].n;
1141	cmd = cmds[i].c;
1142
1143	/* Special case */
1144	if (*cp == '!') {
1145		cp++;
1146		cmdnum = I_SHELL;
1147	} else if (cmdnum == -1) {
1148		error("Invalid command.");
1149		return -1;
1150	}
1151
1152	/* Get arguments and parse flags */
1153	*lflag = *pflag = *rflag = *hflag = *n_arg = 0;
1154	*path1 = *path2 = NULL;
1155	optidx = 1;
1156	switch (cmdnum) {
1157	case I_GET:
1158	case I_PUT:
1159		if ((optidx = parse_getput_flags(cmd, argv, argc, pflag, rflag)) == -1)
1160			return -1;
1161		/* Get first pathname (mandatory) */
1162		if (argc - optidx < 1) {
1163			error("You must specify at least one path after a "
1164			    "%s command.", cmd);
1165			return -1;
1166		}
1167		*path1 = xstrdup(argv[optidx]);
1168		/* Get second pathname (optional) */
1169		if (argc - optidx > 1) {
1170			*path2 = xstrdup(argv[optidx + 1]);
1171			/* Destination is not globbed */
1172			undo_glob_escape(*path2);
1173		}
1174		break;
1175	case I_RENAME:
1176	case I_SYMLINK:
1177		if (argc - optidx < 2) {
1178			error("You must specify two paths after a %s "
1179			    "command.", cmd);
1180			return -1;
1181		}
1182		*path1 = xstrdup(argv[optidx]);
1183		*path2 = xstrdup(argv[optidx + 1]);
1184		/* Paths are not globbed */
1185		undo_glob_escape(*path1);
1186		undo_glob_escape(*path2);
1187		break;
1188	case I_RM:
1189	case I_MKDIR:
1190	case I_RMDIR:
1191	case I_CHDIR:
1192	case I_LCHDIR:
1193	case I_LMKDIR:
1194		/* Get pathname (mandatory) */
1195		if (argc - optidx < 1) {
1196			error("You must specify a path after a %s command.",
1197			    cmd);
1198			return -1;
1199		}
1200		*path1 = xstrdup(argv[optidx]);
1201		/* Only "rm" globs */
1202		if (cmdnum != I_RM)
1203			undo_glob_escape(*path1);
1204		break;
1205	case I_DF:
1206		if ((optidx = parse_df_flags(cmd, argv, argc, hflag,
1207		    iflag)) == -1)
1208			return -1;
1209		/* Default to current directory if no path specified */
1210		if (argc - optidx < 1)
1211			*path1 = NULL;
1212		else {
1213			*path1 = xstrdup(argv[optidx]);
1214			undo_glob_escape(*path1);
1215		}
1216		break;
1217	case I_LS:
1218		if ((optidx = parse_ls_flags(argv, argc, lflag)) == -1)
1219			return(-1);
1220		/* Path is optional */
1221		if (argc - optidx > 0)
1222			*path1 = xstrdup(argv[optidx]);
1223		break;
1224	case I_LLS:
1225		/* Skip ls command and following whitespace */
1226		cp = cp + strlen(cmd) + strspn(cp, WHITESPACE);
1227	case I_SHELL:
1228		/* Uses the rest of the line */
1229		break;
1230	case I_LUMASK:
1231	case I_CHMOD:
1232		base = 8;
1233	case I_CHOWN:
1234	case I_CHGRP:
1235		/* Get numeric arg (mandatory) */
1236		if (argc - optidx < 1)
1237			goto need_num_arg;
1238		errno = 0;
1239		l = strtol(argv[optidx], &cp2, base);
1240		if (cp2 == argv[optidx] || *cp2 != '\0' ||
1241		    ((l == LONG_MIN || l == LONG_MAX) && errno == ERANGE) ||
1242		    l < 0) {
1243 need_num_arg:
1244			error("You must supply a numeric argument "
1245			    "to the %s command.", cmd);
1246			return -1;
1247		}
1248		*n_arg = l;
1249		if (cmdnum == I_LUMASK)
1250			break;
1251		/* Get pathname (mandatory) */
1252		if (argc - optidx < 2) {
1253			error("You must specify a path after a %s command.",
1254			    cmd);
1255			return -1;
1256		}
1257		*path1 = xstrdup(argv[optidx + 1]);
1258		break;
1259	case I_QUIT:
1260	case I_PWD:
1261	case I_LPWD:
1262	case I_HELP:
1263	case I_VERSION:
1264	case I_PROGRESS:
1265		break;
1266	default:
1267		fatal("Command not implemented");
1268	}
1269
1270	*cpp = cp;
1271	return(cmdnum);
1272}
1273
1274static int
1275parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
1276    int err_abort)
1277{
1278	char *path1, *path2, *tmp;
1279	int pflag = 0, rflag = 0, lflag = 0, iflag = 0, hflag = 0, cmdnum, i;
1280	unsigned long n_arg = 0;
1281	Attrib a, *aa;
1282	char path_buf[MAXPATHLEN];
1283	int err = 0;
1284	glob_t g;
1285
1286	path1 = path2 = NULL;
1287	cmdnum = parse_args(&cmd, &pflag, &rflag, &lflag, &iflag, &hflag, &n_arg,
1288	    &path1, &path2);
1289
1290	if (iflag != 0)
1291		err_abort = 0;
1292
1293	memset(&g, 0, sizeof(g));
1294
1295	/* Perform command */
1296	switch (cmdnum) {
1297	case 0:
1298		/* Blank line */
1299		break;
1300	case -1:
1301		/* Unrecognized command */
1302		err = -1;
1303		break;
1304	case I_GET:
1305		err = process_get(conn, path1, path2, *pwd, pflag, rflag);
1306		break;
1307	case I_PUT:
1308		err = process_put(conn, path1, path2, *pwd, pflag, rflag);
1309		break;
1310	case I_RENAME:
1311		path1 = make_absolute(path1, *pwd);
1312		path2 = make_absolute(path2, *pwd);
1313		err = do_rename(conn, path1, path2);
1314		break;
1315	case I_SYMLINK:
1316		path2 = make_absolute(path2, *pwd);
1317		err = do_symlink(conn, path1, path2);
1318		break;
1319	case I_RM:
1320		path1 = make_absolute(path1, *pwd);
1321		remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g);
1322		for (i = 0; g.gl_pathv[i] && !interrupted; i++) {
1323			printf("Removing %s\n", g.gl_pathv[i]);
1324			err = do_rm(conn, g.gl_pathv[i]);
1325			if (err != 0 && err_abort)
1326				break;
1327		}
1328		break;
1329	case I_MKDIR:
1330		path1 = make_absolute(path1, *pwd);
1331		attrib_clear(&a);
1332		a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS;
1333		a.perm = 0777;
1334		err = do_mkdir(conn, path1, &a, 1);
1335		break;
1336	case I_RMDIR:
1337		path1 = make_absolute(path1, *pwd);
1338		err = do_rmdir(conn, path1);
1339		break;
1340	case I_CHDIR:
1341		path1 = make_absolute(path1, *pwd);
1342		if ((tmp = do_realpath(conn, path1)) == NULL) {
1343			err = 1;
1344			break;
1345		}
1346		if ((aa = do_stat(conn, tmp, 0)) == NULL) {
1347			xfree(tmp);
1348			err = 1;
1349			break;
1350		}
1351		if (!(aa->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)) {
1352			error("Can't change directory: Can't check target");
1353			xfree(tmp);
1354			err = 1;
1355			break;
1356		}
1357		if (!S_ISDIR(aa->perm)) {
1358			error("Can't change directory: \"%s\" is not "
1359			    "a directory", tmp);
1360			xfree(tmp);
1361			err = 1;
1362			break;
1363		}
1364		xfree(*pwd);
1365		*pwd = tmp;
1366		break;
1367	case I_LS:
1368		if (!path1) {
1369			do_globbed_ls(conn, *pwd, *pwd, lflag);
1370			break;
1371		}
1372
1373		/* Strip pwd off beginning of non-absolute paths */
1374		tmp = NULL;
1375		if (*path1 != '/')
1376			tmp = *pwd;
1377
1378		path1 = make_absolute(path1, *pwd);
1379		err = do_globbed_ls(conn, path1, tmp, lflag);
1380		break;
1381	case I_DF:
1382		/* Default to current directory if no path specified */
1383		if (path1 == NULL)
1384			path1 = xstrdup(*pwd);
1385		path1 = make_absolute(path1, *pwd);
1386		err = do_df(conn, path1, hflag, iflag);
1387		break;
1388	case I_LCHDIR:
1389		if (chdir(path1) == -1) {
1390			error("Couldn't change local directory to "
1391			    "\"%s\": %s", path1, strerror(errno));
1392			err = 1;
1393		}
1394		break;
1395	case I_LMKDIR:
1396		if (mkdir(path1, 0777) == -1) {
1397			error("Couldn't create local directory "
1398			    "\"%s\": %s", path1, strerror(errno));
1399			err = 1;
1400		}
1401		break;
1402	case I_LLS:
1403		local_do_ls(cmd);
1404		break;
1405	case I_SHELL:
1406		local_do_shell(cmd);
1407		break;
1408	case I_LUMASK:
1409		umask(n_arg);
1410		printf("Local umask: %03lo\n", n_arg);
1411		break;
1412	case I_CHMOD:
1413		path1 = make_absolute(path1, *pwd);
1414		attrib_clear(&a);
1415		a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS;
1416		a.perm = n_arg;
1417		remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g);
1418		for (i = 0; g.gl_pathv[i] && !interrupted; i++) {
1419			printf("Changing mode on %s\n", g.gl_pathv[i]);
1420			err = do_setstat(conn, g.gl_pathv[i], &a);
1421			if (err != 0 && err_abort)
1422				break;
1423		}
1424		break;
1425	case I_CHOWN:
1426	case I_CHGRP:
1427		path1 = make_absolute(path1, *pwd);
1428		remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g);
1429		for (i = 0; g.gl_pathv[i] && !interrupted; i++) {
1430			if (!(aa = do_stat(conn, g.gl_pathv[i], 0))) {
1431				if (err_abort) {
1432					err = -1;
1433					break;
1434				} else
1435					continue;
1436			}
1437			if (!(aa->flags & SSH2_FILEXFER_ATTR_UIDGID)) {
1438				error("Can't get current ownership of "
1439				    "remote file \"%s\"", g.gl_pathv[i]);
1440				if (err_abort) {
1441					err = -1;
1442					break;
1443				} else
1444					continue;
1445			}
1446			aa->flags &= SSH2_FILEXFER_ATTR_UIDGID;
1447			if (cmdnum == I_CHOWN) {
1448				printf("Changing owner on %s\n", g.gl_pathv[i]);
1449				aa->uid = n_arg;
1450			} else {
1451				printf("Changing group on %s\n", g.gl_pathv[i]);
1452				aa->gid = n_arg;
1453			}
1454			err = do_setstat(conn, g.gl_pathv[i], aa);
1455			if (err != 0 && err_abort)
1456				break;
1457		}
1458		break;
1459	case I_PWD:
1460		printf("Remote working directory: %s\n", *pwd);
1461		break;
1462	case I_LPWD:
1463		if (!getcwd(path_buf, sizeof(path_buf))) {
1464			error("Couldn't get local cwd: %s", strerror(errno));
1465			err = -1;
1466			break;
1467		}
1468		printf("Local working directory: %s\n", path_buf);
1469		break;
1470	case I_QUIT:
1471		/* Processed below */
1472		break;
1473	case I_HELP:
1474		help();
1475		break;
1476	case I_VERSION:
1477		printf("SFTP protocol version %u\n", sftp_proto_version(conn));
1478		break;
1479	case I_PROGRESS:
1480		showprogress = !showprogress;
1481		if (showprogress)
1482			printf("Progress meter enabled\n");
1483		else
1484			printf("Progress meter disabled\n");
1485		break;
1486	default:
1487		fatal("%d is not implemented", cmdnum);
1488	}
1489
1490	if (g.gl_pathc)
1491		globfree(&g);
1492	if (path1)
1493		xfree(path1);
1494	if (path2)
1495		xfree(path2);
1496
1497	/* If an unignored error occurs in batch mode we should abort. */
1498	if (err_abort && err != 0)
1499		return (-1);
1500	else if (cmdnum == I_QUIT)
1501		return (1);
1502
1503	return (0);
1504}
1505
1506#ifdef USE_LIBEDIT
1507static char *
1508prompt(EditLine *el)
1509{
1510	return ("sftp> ");
1511}
1512
1513/* Display entries in 'list' after skipping the first 'len' chars */
1514static void
1515complete_display(char **list, u_int len)
1516{
1517	u_int y, m = 0, width = 80, columns = 1, colspace = 0, llen;
1518	struct winsize ws;
1519	char *tmp;
1520
1521	/* Count entries for sort and find longest */
1522	for (y = 0; list[y]; y++)
1523		m = MAX(m, strlen(list[y]));
1524
1525	if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) != -1)
1526		width = ws.ws_col;
1527
1528	m = m > len ? m - len : 0;
1529	columns = width / (m + 2);
1530	columns = MAX(columns, 1);
1531	colspace = width / columns;
1532	colspace = MIN(colspace, width);
1533
1534	printf("\n");
1535	m = 1;
1536	for (y = 0; list[y]; y++) {
1537		llen = strlen(list[y]);
1538		tmp = llen > len ? list[y] + len : "";
1539		printf("%-*s", colspace, tmp);
1540		if (m >= columns) {
1541			printf("\n");
1542			m = 1;
1543		} else
1544			m++;
1545	}
1546	printf("\n");
1547}
1548
1549/*
1550 * Given a "list" of words that begin with a common prefix of "word",
1551 * attempt to find an autocompletion to extends "word" by the next
1552 * characters common to all entries in "list".
1553 */
1554static char *
1555complete_ambiguous(const char *word, char **list, size_t count)
1556{
1557	if (word == NULL)
1558		return NULL;
1559
1560	if (count > 0) {
1561		u_int y, matchlen = strlen(list[0]);
1562
1563		/* Find length of common stem */
1564		for (y = 1; list[y]; y++) {
1565			u_int x;
1566
1567			for (x = 0; x < matchlen; x++)
1568				if (list[0][x] != list[y][x])
1569					break;
1570
1571			matchlen = x;
1572		}
1573
1574		if (matchlen > strlen(word)) {
1575			char *tmp = xstrdup(list[0]);
1576
1577			tmp[matchlen] = '\0';
1578			return tmp;
1579		}
1580	}
1581
1582	return xstrdup(word);
1583}
1584
1585/* Autocomplete a sftp command */
1586static int
1587complete_cmd_parse(EditLine *el, char *cmd, int lastarg, char quote,
1588    int terminated)
1589{
1590	u_int y, count = 0, cmdlen, tmplen;
1591	char *tmp, **list, argterm[3];
1592	const LineInfo *lf;
1593
1594	list = xcalloc((sizeof(cmds) / sizeof(*cmds)) + 1, sizeof(char *));
1595
1596	/* No command specified: display all available commands */
1597	if (cmd == NULL) {
1598		for (y = 0; cmds[y].c; y++)
1599			list[count++] = xstrdup(cmds[y].c);
1600
1601		list[count] = NULL;
1602		complete_display(list, 0);
1603
1604		for (y = 0; list[y] != NULL; y++)
1605			xfree(list[y]);
1606		xfree(list);
1607		return count;
1608	}
1609
1610	/* Prepare subset of commands that start with "cmd" */
1611	cmdlen = strlen(cmd);
1612	for (y = 0; cmds[y].c; y++)  {
1613		if (!strncasecmp(cmd, cmds[y].c, cmdlen))
1614			list[count++] = xstrdup(cmds[y].c);
1615	}
1616	list[count] = NULL;
1617
1618	if (count == 0)
1619		return 0;
1620
1621	/* Complete ambigious command */
1622	tmp = complete_ambiguous(cmd, list, count);
1623	if (count > 1)
1624		complete_display(list, 0);
1625
1626	for (y = 0; list[y]; y++)
1627		xfree(list[y]);
1628	xfree(list);
1629
1630	if (tmp != NULL) {
1631		tmplen = strlen(tmp);
1632		cmdlen = strlen(cmd);
1633		/* If cmd may be extended then do so */
1634		if (tmplen > cmdlen)
1635			if (el_insertstr(el, tmp + cmdlen) == -1)
1636				fatal("el_insertstr failed.");
1637		lf = el_line(el);
1638		/* Terminate argument cleanly */
1639		if (count == 1) {
1640			y = 0;
1641			if (!terminated)
1642				argterm[y++] = quote;
1643			if (lastarg || *(lf->cursor) != ' ')
1644				argterm[y++] = ' ';
1645			argterm[y] = '\0';
1646			if (y > 0 && el_insertstr(el, argterm) == -1)
1647				fatal("el_insertstr failed.");
1648		}
1649		xfree(tmp);
1650	}
1651
1652	return count;
1653}
1654
1655/*
1656 * Determine whether a particular sftp command's arguments (if any)
1657 * represent local or remote files.
1658 */
1659static int
1660complete_is_remote(char *cmd) {
1661	int i;
1662
1663	if (cmd == NULL)
1664		return -1;
1665
1666	for (i = 0; cmds[i].c; i++) {
1667		if (!strncasecmp(cmd, cmds[i].c, strlen(cmds[i].c)))
1668			return cmds[i].t;
1669	}
1670
1671	return -1;
1672}
1673
1674/* Autocomplete a filename "file" */
1675static int
1676complete_match(EditLine *el, struct sftp_conn *conn, char *remote_path,
1677    char *file, int remote, int lastarg, char quote, int terminated)
1678{
1679	glob_t g;
1680	char *tmp, *tmp2, ins[3];
1681	u_int i, hadglob, pwdlen, len, tmplen, filelen;
1682	const LineInfo *lf;
1683
1684	/* Glob from "file" location */
1685	if (file == NULL)
1686		tmp = xstrdup("*");
1687	else
1688		xasprintf(&tmp, "%s*", file);
1689
1690	memset(&g, 0, sizeof(g));
1691	if (remote != LOCAL) {
1692		tmp = make_absolute(tmp, remote_path);
1693		remote_glob(conn, tmp, GLOB_DOOFFS|GLOB_MARK, NULL, &g);
1694	} else
1695		glob(tmp, GLOB_DOOFFS|GLOB_MARK, NULL, &g);
1696
1697	/* Determine length of pwd so we can trim completion display */
1698	for (hadglob = tmplen = pwdlen = 0; tmp[tmplen] != 0; tmplen++) {
1699		/* Terminate counting on first unescaped glob metacharacter */
1700		if (tmp[tmplen] == '*' || tmp[tmplen] == '?') {
1701			if (tmp[tmplen] != '*' || tmp[tmplen + 1] != '\0')
1702				hadglob = 1;
1703			break;
1704		}
1705		if (tmp[tmplen] == '\\' && tmp[tmplen + 1] != '\0')
1706			tmplen++;
1707		if (tmp[tmplen] == '/')
1708			pwdlen = tmplen + 1;	/* track last seen '/' */
1709	}
1710	xfree(tmp);
1711
1712	if (g.gl_matchc == 0)
1713		goto out;
1714
1715	if (g.gl_matchc > 1)
1716		complete_display(g.gl_pathv, pwdlen);
1717
1718	tmp = NULL;
1719	/* Don't try to extend globs */
1720	if (file == NULL || hadglob)
1721		goto out;
1722
1723	tmp2 = complete_ambiguous(file, g.gl_pathv, g.gl_matchc);
1724	tmp = path_strip(tmp2, remote_path);
1725	xfree(tmp2);
1726
1727	if (tmp == NULL)
1728		goto out;
1729
1730	tmplen = strlen(tmp);
1731	filelen = strlen(file);
1732
1733	if (tmplen > filelen)  {
1734		tmp2 = tmp + filelen;
1735		len = strlen(tmp2);
1736		/* quote argument on way out */
1737		for (i = 0; i < len; i++) {
1738			ins[0] = '\\';
1739			ins[1] = tmp2[i];
1740			ins[2] = '\0';
1741			switch (tmp2[i]) {
1742			case '\'':
1743			case '"':
1744			case '\\':
1745			case '\t':
1746			case ' ':
1747				if (quote == '\0' || tmp2[i] == quote) {
1748					if (el_insertstr(el, ins) == -1)
1749						fatal("el_insertstr "
1750						    "failed.");
1751					break;
1752				}
1753				/* FALLTHROUGH */
1754			default:
1755				if (el_insertstr(el, ins + 1) == -1)
1756					fatal("el_insertstr failed.");
1757				break;
1758			}
1759		}
1760	}
1761
1762	lf = el_line(el);
1763	if (g.gl_matchc == 1) {
1764		i = 0;
1765		if (!terminated)
1766			ins[i++] = quote;
1767		if (*(lf->cursor - 1) != '/' &&
1768		    (lastarg || *(lf->cursor) != ' '))
1769			ins[i++] = ' ';
1770		ins[i] = '\0';
1771		if (i > 0 && el_insertstr(el, ins) == -1)
1772			fatal("el_insertstr failed.");
1773	}
1774	xfree(tmp);
1775
1776 out:
1777	globfree(&g);
1778	return g.gl_matchc;
1779}
1780
1781/* tab-completion hook function, called via libedit */
1782static unsigned char
1783complete(EditLine *el, int ch)
1784{
1785	char **argv, *line, quote;
1786	u_int argc, carg, cursor, len, terminated, ret = CC_ERROR;
1787	const LineInfo *lf;
1788	struct complete_ctx *complete_ctx;
1789
1790	lf = el_line(el);
1791	if (el_get(el, EL_CLIENTDATA, (void**)&complete_ctx) != 0)
1792		fatal("%s: el_get failed", __func__);
1793
1794	/* Figure out which argument the cursor points to */
1795	cursor = lf->cursor - lf->buffer;
1796	line = (char *)xmalloc(cursor + 1);
1797	memcpy(line, lf->buffer, cursor);
1798	line[cursor] = '\0';
1799	argv = makeargv(line, &carg, 1, &quote, &terminated);
1800	xfree(line);
1801
1802	/* Get all the arguments on the line */
1803	len = lf->lastchar - lf->buffer;
1804	line = (char *)xmalloc(len + 1);
1805	memcpy(line, lf->buffer, len);
1806	line[len] = '\0';
1807	argv = makeargv(line, &argc, 1, NULL, NULL);
1808
1809	/* Ensure cursor is at EOL or a argument boundary */
1810	if (line[cursor] != ' ' && line[cursor] != '\0' &&
1811	    line[cursor] != '\n') {
1812		xfree(line);
1813		return ret;
1814	}
1815
1816	if (carg == 0) {
1817		/* Show all available commands */
1818		complete_cmd_parse(el, NULL, argc == carg, '\0', 1);
1819		ret = CC_REDISPLAY;
1820	} else if (carg == 1 && cursor > 0 && line[cursor - 1] != ' ')  {
1821		/* Handle the command parsing */
1822		if (complete_cmd_parse(el, argv[0], argc == carg,
1823		    quote, terminated) != 0)
1824			ret = CC_REDISPLAY;
1825	} else if (carg >= 1) {
1826		/* Handle file parsing */
1827		int remote = complete_is_remote(argv[0]);
1828		char *filematch = NULL;
1829
1830		if (carg > 1 && line[cursor-1] != ' ')
1831			filematch = argv[carg - 1];
1832
1833		if (remote != 0 &&
1834		    complete_match(el, complete_ctx->conn,
1835		    *complete_ctx->remote_pathp, filematch,
1836		    remote, carg == argc, quote, terminated) != 0)
1837			ret = CC_REDISPLAY;
1838	}
1839
1840	xfree(line);
1841	return ret;
1842}
1843#endif /* USE_LIBEDIT */
1844
1845int
1846interactive_loop(struct sftp_conn *conn, char *file1, char *file2)
1847{
1848	char *remote_path;
1849	char *dir = NULL;
1850	char cmd[2048];
1851	int err, interactive;
1852	EditLine *el = NULL;
1853#ifdef USE_LIBEDIT
1854	History *hl = NULL;
1855	HistEvent hev;
1856	extern char *__progname;
1857	struct complete_ctx complete_ctx;
1858
1859	if (!batchmode && isatty(STDIN_FILENO)) {
1860		if ((el = el_init(__progname, stdin, stdout, stderr)) == NULL)
1861			fatal("Couldn't initialise editline");
1862		if ((hl = history_init()) == NULL)
1863			fatal("Couldn't initialise editline history");
1864		history(hl, &hev, H_SETSIZE, 100);
1865		el_set(el, EL_HIST, history, hl);
1866
1867		el_set(el, EL_PROMPT, prompt);
1868		el_set(el, EL_EDITOR, "emacs");
1869		el_set(el, EL_TERMINAL, NULL);
1870		el_set(el, EL_SIGNAL, 1);
1871		el_source(el, NULL);
1872
1873		/* Tab Completion */
1874		el_set(el, EL_ADDFN, "ftp-complete",
1875		    "Context senstive argument completion", complete);
1876		complete_ctx.conn = conn;
1877		complete_ctx.remote_pathp = &remote_path;
1878		el_set(el, EL_CLIENTDATA, (void*)&complete_ctx);
1879		el_set(el, EL_BIND, "^I", "ftp-complete", NULL);
1880	}
1881#endif /* USE_LIBEDIT */
1882
1883	remote_path = do_realpath(conn, ".");
1884	if (remote_path == NULL)
1885		fatal("Need cwd");
1886
1887	if (file1 != NULL) {
1888		dir = xstrdup(file1);
1889		dir = make_absolute(dir, remote_path);
1890
1891		if (remote_is_dir(conn, dir) && file2 == NULL) {
1892			printf("Changing to: %s\n", dir);
1893			snprintf(cmd, sizeof cmd, "cd \"%s\"", dir);
1894			if (parse_dispatch_command(conn, cmd,
1895			    &remote_path, 1) != 0) {
1896				xfree(dir);
1897				xfree(remote_path);
1898				xfree(conn);
1899				return (-1);
1900			}
1901		} else {
1902			if (file2 == NULL)
1903				snprintf(cmd, sizeof cmd, "get %s", dir);
1904			else
1905				snprintf(cmd, sizeof cmd, "get %s %s", dir,
1906				    file2);
1907
1908			err = parse_dispatch_command(conn, cmd,
1909			    &remote_path, 1);
1910			xfree(dir);
1911			xfree(remote_path);
1912			xfree(conn);
1913			return (err);
1914		}
1915		xfree(dir);
1916	}
1917
1918#if defined(HAVE_SETVBUF) && !defined(BROKEN_SETVBUF)
1919	setvbuf(stdout, NULL, _IOLBF, 0);
1920	setvbuf(infile, NULL, _IOLBF, 0);
1921#else
1922	setlinebuf(stdout);
1923	setlinebuf(infile);
1924#endif
1925
1926	interactive = !batchmode && isatty(STDIN_FILENO);
1927	err = 0;
1928	for (;;) {
1929		char *cp;
1930
1931		signal(SIGINT, SIG_IGN);
1932
1933		if (el == NULL) {
1934			if (interactive)
1935				printf("sftp> ");
1936			if (fgets(cmd, sizeof(cmd), infile) == NULL) {
1937				if (interactive)
1938					printf("\n");
1939				break;
1940			}
1941			if (!interactive) { /* Echo command */
1942				printf("sftp> %s", cmd);
1943				if (strlen(cmd) > 0 &&
1944				    cmd[strlen(cmd) - 1] != '\n')
1945					printf("\n");
1946			}
1947		} else {
1948#ifdef USE_LIBEDIT
1949			const char *line;
1950			int count = 0;
1951
1952			if ((line = el_gets(el, &count)) == NULL ||
1953			    count <= 0) {
1954				printf("\n");
1955 				break;
1956			}
1957			history(hl, &hev, H_ENTER, line);
1958			if (strlcpy(cmd, line, sizeof(cmd)) >= sizeof(cmd)) {
1959				fprintf(stderr, "Error: input line too long\n");
1960				continue;
1961			}
1962#endif /* USE_LIBEDIT */
1963		}
1964
1965		cp = strrchr(cmd, '\n');
1966		if (cp)
1967			*cp = '\0';
1968
1969		/* Handle user interrupts gracefully during commands */
1970		interrupted = 0;
1971		signal(SIGINT, cmd_interrupt);
1972
1973		err = parse_dispatch_command(conn, cmd, &remote_path,
1974		    batchmode);
1975		if (err != 0)
1976			break;
1977	}
1978	xfree(remote_path);
1979	xfree(conn);
1980
1981#ifdef USE_LIBEDIT
1982	if (el != NULL)
1983		el_end(el);
1984#endif /* USE_LIBEDIT */
1985
1986	/* err == 1 signifies normal "quit" exit */
1987	return (err >= 0 ? 0 : -1);
1988}
1989
1990static void
1991connect_to_server(char *path, char **args, int *in, int *out)
1992{
1993	int c_in, c_out;
1994
1995#ifdef USE_PIPES
1996	int pin[2], pout[2];
1997
1998	if ((pipe(pin) == -1) || (pipe(pout) == -1))
1999		fatal("pipe: %s", strerror(errno));
2000	*in = pin[0];
2001	*out = pout[1];
2002	c_in = pout[0];
2003	c_out = pin[1];
2004#else /* USE_PIPES */
2005	int inout[2];
2006
2007	if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) == -1)
2008		fatal("socketpair: %s", strerror(errno));
2009	*in = *out = inout[0];
2010	c_in = c_out = inout[1];
2011#endif /* USE_PIPES */
2012
2013	if ((sshpid = fork()) == -1)
2014		fatal("fork: %s", strerror(errno));
2015	else if (sshpid == 0) {
2016		if ((dup2(c_in, STDIN_FILENO) == -1) ||
2017		    (dup2(c_out, STDOUT_FILENO) == -1)) {
2018			fprintf(stderr, "dup2: %s\n", strerror(errno));
2019			_exit(1);
2020		}
2021		close(*in);
2022		close(*out);
2023		close(c_in);
2024		close(c_out);
2025
2026		/*
2027		 * The underlying ssh is in the same process group, so we must
2028		 * ignore SIGINT if we want to gracefully abort commands,
2029		 * otherwise the signal will make it to the ssh process and
2030		 * kill it too.  Contrawise, since sftp sends SIGTERMs to the
2031		 * underlying ssh, it must *not* ignore that signal.
2032		 */
2033		signal(SIGINT, SIG_IGN);
2034		signal(SIGTERM, SIG_DFL);
2035		execvp(path, args);
2036		fprintf(stderr, "exec: %s: %s\n", path, strerror(errno));
2037		_exit(1);
2038	}
2039
2040	signal(SIGTERM, killchild);
2041	signal(SIGINT, killchild);
2042	signal(SIGHUP, killchild);
2043	close(c_in);
2044	close(c_out);
2045}
2046
2047static void
2048usage(void)
2049{
2050	extern char *__progname;
2051
2052	fprintf(stderr,
2053	    "usage: %s [-1246Cpqrv] [-B buffer_size] [-b batchfile] [-c cipher]\n"
2054	    "          [-D sftp_server_path] [-F ssh_config] "
2055	    "[-i identity_file]\n"
2056	    "          [-o ssh_option] [-P port] [-R num_requests] "
2057	    "[-S program]\n"
2058	    "          [-s subsystem | sftp_server] host\n"
2059	    "       %s [user@]host[:file ...]\n"
2060	    "       %s [user@]host[:dir[/]]\n"
2061	    "       %s -b batchfile [user@]host\n",
2062	    __progname, __progname, __progname, __progname);
2063	exit(1);
2064}
2065
2066int
2067main(int argc, char **argv)
2068{
2069	int in, out, ch, err;
2070	char *host = NULL, *userhost, *cp, *file2 = NULL;
2071	int debug_level = 0, sshver = 2;
2072	char *file1 = NULL, *sftp_server = NULL;
2073	char *ssh_program = _PATH_SSH_PROGRAM, *sftp_direct = NULL;
2074	LogLevel ll = SYSLOG_LEVEL_INFO;
2075	arglist args;
2076	extern int optind;
2077	extern char *optarg;
2078	struct sftp_conn *conn;
2079	size_t copy_buffer_len = DEFAULT_COPY_BUFLEN;
2080	size_t num_requests = DEFAULT_NUM_REQUESTS;
2081
2082	/* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
2083	sanitise_stdfd();
2084
2085	__progname = ssh_get_progname(argv[0]);
2086	memset(&args, '\0', sizeof(args));
2087	args.list = NULL;
2088	addargs(&args, "%s", ssh_program);
2089	addargs(&args, "-oForwardX11 no");
2090	addargs(&args, "-oForwardAgent no");
2091	addargs(&args, "-oPermitLocalCommand no");
2092	addargs(&args, "-oClearAllForwardings yes");
2093
2094	ll = SYSLOG_LEVEL_INFO;
2095	infile = stdin;
2096
2097	while ((ch = getopt(argc, argv,
2098	    "1246hpqrvCc:D:i:o:s:S:b:B:F:P:R:")) != -1) {
2099		switch (ch) {
2100		/* Passed through to ssh(1) */
2101		case '4':
2102		case '6':
2103		case 'C':
2104			addargs(&args, "-%c", ch);
2105			break;
2106		/* Passed through to ssh(1) with argument */
2107		case 'F':
2108		case 'c':
2109		case 'i':
2110		case 'o':
2111			addargs(&args, "-%c", ch);
2112			addargs(&args, "%s", optarg);
2113			break;
2114		case 'q':
2115			showprogress = 0;
2116			addargs(&args, "-%c", ch);
2117			break;
2118		case 'P':
2119			addargs(&args, "-oPort %s", optarg);
2120			break;
2121		case 'v':
2122			if (debug_level < 3) {
2123				addargs(&args, "-v");
2124				ll = SYSLOG_LEVEL_DEBUG1 + debug_level;
2125			}
2126			debug_level++;
2127			break;
2128		case '1':
2129			sshver = 1;
2130			if (sftp_server == NULL)
2131				sftp_server = _PATH_SFTP_SERVER;
2132			break;
2133		case '2':
2134			sshver = 2;
2135			break;
2136		case 'B':
2137			copy_buffer_len = strtol(optarg, &cp, 10);
2138			if (copy_buffer_len == 0 || *cp != '\0')
2139				fatal("Invalid buffer size \"%s\"", optarg);
2140			break;
2141		case 'b':
2142			if (batchmode)
2143				fatal("Batch file already specified.");
2144
2145			/* Allow "-" as stdin */
2146			if (strcmp(optarg, "-") != 0 &&
2147			    (infile = fopen(optarg, "r")) == NULL)
2148				fatal("%s (%s).", strerror(errno), optarg);
2149			showprogress = 0;
2150			batchmode = 1;
2151			addargs(&args, "-obatchmode yes");
2152			break;
2153		case 'p':
2154			global_pflag = 1;
2155			break;
2156		case 'D':
2157			sftp_direct = optarg;
2158			break;
2159		case 'r':
2160			global_rflag = 1;
2161			break;
2162		case 'R':
2163			num_requests = strtol(optarg, &cp, 10);
2164			if (num_requests == 0 || *cp != '\0')
2165				fatal("Invalid number of requests \"%s\"",
2166				    optarg);
2167			break;
2168		case 's':
2169			sftp_server = optarg;
2170			break;
2171		case 'S':
2172			ssh_program = optarg;
2173			replacearg(&args, 0, "%s", ssh_program);
2174			break;
2175		case 'h':
2176		default:
2177			usage();
2178		}
2179	}
2180
2181	if (!isatty(STDERR_FILENO))
2182		showprogress = 0;
2183
2184	log_init(argv[0], ll, SYSLOG_FACILITY_USER, 1);
2185
2186	if (sftp_direct == NULL) {
2187		if (optind == argc || argc > (optind + 2))
2188			usage();
2189
2190		userhost = xstrdup(argv[optind]);
2191		file2 = argv[optind+1];
2192
2193		if ((host = strrchr(userhost, '@')) == NULL)
2194			host = userhost;
2195		else {
2196			*host++ = '\0';
2197			if (!userhost[0]) {
2198				fprintf(stderr, "Missing username\n");
2199				usage();
2200			}
2201			addargs(&args, "-l");
2202			addargs(&args, "%s", userhost);
2203		}
2204
2205		if ((cp = colon(host)) != NULL) {
2206			*cp++ = '\0';
2207			file1 = cp;
2208		}
2209
2210		host = cleanhostname(host);
2211		if (!*host) {
2212			fprintf(stderr, "Missing hostname\n");
2213			usage();
2214		}
2215
2216		addargs(&args, "-oProtocol %d", sshver);
2217
2218		/* no subsystem if the server-spec contains a '/' */
2219		if (sftp_server == NULL || strchr(sftp_server, '/') == NULL)
2220			addargs(&args, "-s");
2221
2222		addargs(&args, "--");
2223		addargs(&args, "%s", host);
2224		addargs(&args, "%s", (sftp_server != NULL ?
2225		    sftp_server : "sftp"));
2226
2227		connect_to_server(ssh_program, args.list, &in, &out);
2228	} else {
2229		args.list = NULL;
2230		addargs(&args, "sftp-server");
2231
2232		connect_to_server(sftp_direct, args.list, &in, &out);
2233	}
2234	freeargs(&args);
2235
2236	conn = do_init(in, out, copy_buffer_len, num_requests);
2237	if (conn == NULL)
2238		fatal("Couldn't initialise connection to server");
2239
2240	if (!batchmode) {
2241		if (sftp_direct == NULL)
2242			fprintf(stderr, "Connected to %s.\n", host);
2243		else
2244			fprintf(stderr, "Attached to %s.\n", sftp_direct);
2245	}
2246
2247	err = interactive_loop(conn, file1, file2);
2248
2249#if !defined(USE_PIPES)
2250	shutdown(in, SHUT_RDWR);
2251	shutdown(out, SHUT_RDWR);
2252#endif
2253
2254	close(in);
2255	close(out);
2256	if (batchmode)
2257		fclose(infile);
2258
2259	while (waitpid(sshpid, NULL, 0) == -1)
2260		if (errno != EINTR)
2261			fatal("Couldn't wait for ssh process: %s",
2262			    strerror(errno));
2263
2264	exit(err == 0 ? 0 : 1);
2265}
2266