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