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