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