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