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