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