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