sftp.c revision 323136
1/* $OpenBSD: sftp.c,v 1.178 2017/02/15 01:46:47 djm 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], s_avail[FMT_SCALED_STRSIZE];
973	char s_root[FMT_SCALED_STRSIZE], s_total[FMT_SCALED_STRSIZE];
974	char s_icapacity[16], s_dcapacity[16];
975
976	if (do_statvfs(conn, path, &st, 1) == -1)
977		return -1;
978	if (st.f_files == 0)
979		strlcpy(s_icapacity, "ERR", sizeof(s_icapacity));
980	else {
981		snprintf(s_icapacity, sizeof(s_icapacity), "%3llu%%",
982		    (unsigned long long)(100 * (st.f_files - st.f_ffree) /
983		    st.f_files));
984	}
985	if (st.f_blocks == 0)
986		strlcpy(s_dcapacity, "ERR", sizeof(s_dcapacity));
987	else {
988		snprintf(s_dcapacity, sizeof(s_dcapacity), "%3llu%%",
989		    (unsigned long long)(100 * (st.f_blocks - st.f_bfree) /
990		    st.f_blocks));
991	}
992	if (iflag) {
993		printf("     Inodes        Used       Avail      "
994		    "(root)    %%Capacity\n");
995		printf("%11llu %11llu %11llu %11llu         %s\n",
996		    (unsigned long long)st.f_files,
997		    (unsigned long long)(st.f_files - st.f_ffree),
998		    (unsigned long long)st.f_favail,
999		    (unsigned long long)st.f_ffree, s_icapacity);
1000	} else if (hflag) {
1001		strlcpy(s_used, "error", sizeof(s_used));
1002		strlcpy(s_avail, "error", sizeof(s_avail));
1003		strlcpy(s_root, "error", sizeof(s_root));
1004		strlcpy(s_total, "error", sizeof(s_total));
1005		fmt_scaled((st.f_blocks - st.f_bfree) * st.f_frsize, s_used);
1006		fmt_scaled(st.f_bavail * st.f_frsize, s_avail);
1007		fmt_scaled(st.f_bfree * st.f_frsize, s_root);
1008		fmt_scaled(st.f_blocks * st.f_frsize, s_total);
1009		printf("    Size     Used    Avail   (root)    %%Capacity\n");
1010		printf("%7sB %7sB %7sB %7sB         %s\n",
1011		    s_total, s_used, s_avail, s_root, s_dcapacity);
1012	} else {
1013		printf("        Size         Used        Avail       "
1014		    "(root)    %%Capacity\n");
1015		printf("%12llu %12llu %12llu %12llu         %s\n",
1016		    (unsigned long long)(st.f_frsize * st.f_blocks / 1024),
1017		    (unsigned long long)(st.f_frsize *
1018		    (st.f_blocks - st.f_bfree) / 1024),
1019		    (unsigned long long)(st.f_frsize * st.f_bavail / 1024),
1020		    (unsigned long long)(st.f_frsize * st.f_bfree / 1024),
1021		    s_dcapacity);
1022	}
1023	return 0;
1024}
1025
1026/*
1027 * Undo escaping of glob sequences in place. Used to undo extra escaping
1028 * applied in makeargv() when the string is destined for a function that
1029 * does not glob it.
1030 */
1031static void
1032undo_glob_escape(char *s)
1033{
1034	size_t i, j;
1035
1036	for (i = j = 0;;) {
1037		if (s[i] == '\0') {
1038			s[j] = '\0';
1039			return;
1040		}
1041		if (s[i] != '\\') {
1042			s[j++] = s[i++];
1043			continue;
1044		}
1045		/* s[i] == '\\' */
1046		++i;
1047		switch (s[i]) {
1048		case '?':
1049		case '[':
1050		case '*':
1051		case '\\':
1052			s[j++] = s[i++];
1053			break;
1054		case '\0':
1055			s[j++] = '\\';
1056			s[j] = '\0';
1057			return;
1058		default:
1059			s[j++] = '\\';
1060			s[j++] = s[i++];
1061			break;
1062		}
1063	}
1064}
1065
1066/*
1067 * Split a string into an argument vector using sh(1)-style quoting,
1068 * comment and escaping rules, but with some tweaks to handle glob(3)
1069 * wildcards.
1070 * The "sloppy" flag allows for recovery from missing terminating quote, for
1071 * use in parsing incomplete commandlines during tab autocompletion.
1072 *
1073 * Returns NULL on error or a NULL-terminated array of arguments.
1074 *
1075 * If "lastquote" is not NULL, the quoting character used for the last
1076 * argument is placed in *lastquote ("\0", "'" or "\"").
1077 *
1078 * If "terminated" is not NULL, *terminated will be set to 1 when the
1079 * last argument's quote has been properly terminated or 0 otherwise.
1080 * This parameter is only of use if "sloppy" is set.
1081 */
1082#define MAXARGS 	128
1083#define MAXARGLEN	8192
1084static char **
1085makeargv(const char *arg, int *argcp, int sloppy, char *lastquote,
1086    u_int *terminated)
1087{
1088	int argc, quot;
1089	size_t i, j;
1090	static char argvs[MAXARGLEN];
1091	static char *argv[MAXARGS + 1];
1092	enum { MA_START, MA_SQUOTE, MA_DQUOTE, MA_UNQUOTED } state, q;
1093
1094	*argcp = argc = 0;
1095	if (strlen(arg) > sizeof(argvs) - 1) {
1096 args_too_longs:
1097		error("string too long");
1098		return NULL;
1099	}
1100	if (terminated != NULL)
1101		*terminated = 1;
1102	if (lastquote != NULL)
1103		*lastquote = '\0';
1104	state = MA_START;
1105	i = j = 0;
1106	for (;;) {
1107		if ((size_t)argc >= sizeof(argv) / sizeof(*argv)){
1108			error("Too many arguments.");
1109			return NULL;
1110		}
1111		if (isspace((unsigned char)arg[i])) {
1112			if (state == MA_UNQUOTED) {
1113				/* Terminate current argument */
1114				argvs[j++] = '\0';
1115				argc++;
1116				state = MA_START;
1117			} else if (state != MA_START)
1118				argvs[j++] = arg[i];
1119		} else if (arg[i] == '"' || arg[i] == '\'') {
1120			q = arg[i] == '"' ? MA_DQUOTE : MA_SQUOTE;
1121			if (state == MA_START) {
1122				argv[argc] = argvs + j;
1123				state = q;
1124				if (lastquote != NULL)
1125					*lastquote = arg[i];
1126			} else if (state == MA_UNQUOTED)
1127				state = q;
1128			else if (state == q)
1129				state = MA_UNQUOTED;
1130			else
1131				argvs[j++] = arg[i];
1132		} else if (arg[i] == '\\') {
1133			if (state == MA_SQUOTE || state == MA_DQUOTE) {
1134				quot = state == MA_SQUOTE ? '\'' : '"';
1135				/* Unescape quote we are in */
1136				/* XXX support \n and friends? */
1137				if (arg[i + 1] == quot) {
1138					i++;
1139					argvs[j++] = arg[i];
1140				} else if (arg[i + 1] == '?' ||
1141				    arg[i + 1] == '[' || arg[i + 1] == '*') {
1142					/*
1143					 * Special case for sftp: append
1144					 * double-escaped glob sequence -
1145					 * glob will undo one level of
1146					 * escaping. NB. string can grow here.
1147					 */
1148					if (j >= sizeof(argvs) - 5)
1149						goto args_too_longs;
1150					argvs[j++] = '\\';
1151					argvs[j++] = arg[i++];
1152					argvs[j++] = '\\';
1153					argvs[j++] = arg[i];
1154				} else {
1155					argvs[j++] = arg[i++];
1156					argvs[j++] = arg[i];
1157				}
1158			} else {
1159				if (state == MA_START) {
1160					argv[argc] = argvs + j;
1161					state = MA_UNQUOTED;
1162					if (lastquote != NULL)
1163						*lastquote = '\0';
1164				}
1165				if (arg[i + 1] == '?' || arg[i + 1] == '[' ||
1166				    arg[i + 1] == '*' || arg[i + 1] == '\\') {
1167					/*
1168					 * Special case for sftp: append
1169					 * escaped glob sequence -
1170					 * glob will undo one level of
1171					 * escaping.
1172					 */
1173					argvs[j++] = arg[i++];
1174					argvs[j++] = arg[i];
1175				} else {
1176					/* Unescape everything */
1177					/* XXX support \n and friends? */
1178					i++;
1179					argvs[j++] = arg[i];
1180				}
1181			}
1182		} else if (arg[i] == '#') {
1183			if (state == MA_SQUOTE || state == MA_DQUOTE)
1184				argvs[j++] = arg[i];
1185			else
1186				goto string_done;
1187		} else if (arg[i] == '\0') {
1188			if (state == MA_SQUOTE || state == MA_DQUOTE) {
1189				if (sloppy) {
1190					state = MA_UNQUOTED;
1191					if (terminated != NULL)
1192						*terminated = 0;
1193					goto string_done;
1194				}
1195				error("Unterminated quoted argument");
1196				return NULL;
1197			}
1198 string_done:
1199			if (state == MA_UNQUOTED) {
1200				argvs[j++] = '\0';
1201				argc++;
1202			}
1203			break;
1204		} else {
1205			if (state == MA_START) {
1206				argv[argc] = argvs + j;
1207				state = MA_UNQUOTED;
1208				if (lastquote != NULL)
1209					*lastquote = '\0';
1210			}
1211			if ((state == MA_SQUOTE || state == MA_DQUOTE) &&
1212			    (arg[i] == '?' || arg[i] == '[' || arg[i] == '*')) {
1213				/*
1214				 * Special case for sftp: escape quoted
1215				 * glob(3) wildcards. NB. string can grow
1216				 * here.
1217				 */
1218				if (j >= sizeof(argvs) - 3)
1219					goto args_too_longs;
1220				argvs[j++] = '\\';
1221				argvs[j++] = arg[i];
1222			} else
1223				argvs[j++] = arg[i];
1224		}
1225		i++;
1226	}
1227	*argcp = argc;
1228	return argv;
1229}
1230
1231static int
1232parse_args(const char **cpp, int *ignore_errors, int *aflag,
1233	  int *fflag, int *hflag, int *iflag, int *lflag, int *pflag,
1234	  int *rflag, int *sflag,
1235    unsigned long *n_arg, char **path1, char **path2)
1236{
1237	const char *cmd, *cp = *cpp;
1238	char *cp2, **argv;
1239	int base = 0;
1240	long l;
1241	int i, cmdnum, optidx, argc;
1242
1243	/* Skip leading whitespace */
1244	cp = cp + strspn(cp, WHITESPACE);
1245
1246	/* Check for leading '-' (disable error processing) */
1247	*ignore_errors = 0;
1248	if (*cp == '-') {
1249		*ignore_errors = 1;
1250		cp++;
1251		cp = cp + strspn(cp, WHITESPACE);
1252	}
1253
1254	/* Ignore blank lines and lines which begin with comment '#' char */
1255	if (*cp == '\0' || *cp == '#')
1256		return (0);
1257
1258	if ((argv = makeargv(cp, &argc, 0, NULL, NULL)) == NULL)
1259		return -1;
1260
1261	/* Figure out which command we have */
1262	for (i = 0; cmds[i].c != NULL; i++) {
1263		if (argv[0] != NULL && strcasecmp(cmds[i].c, argv[0]) == 0)
1264			break;
1265	}
1266	cmdnum = cmds[i].n;
1267	cmd = cmds[i].c;
1268
1269	/* Special case */
1270	if (*cp == '!') {
1271		cp++;
1272		cmdnum = I_SHELL;
1273	} else if (cmdnum == -1) {
1274		error("Invalid command.");
1275		return -1;
1276	}
1277
1278	/* Get arguments and parse flags */
1279	*aflag = *fflag = *hflag = *iflag = *lflag = *pflag = 0;
1280	*rflag = *sflag = 0;
1281	*path1 = *path2 = NULL;
1282	optidx = 1;
1283	switch (cmdnum) {
1284	case I_GET:
1285	case I_REGET:
1286	case I_REPUT:
1287	case I_PUT:
1288		if ((optidx = parse_getput_flags(cmd, argv, argc,
1289		    aflag, fflag, pflag, rflag)) == -1)
1290			return -1;
1291		/* Get first pathname (mandatory) */
1292		if (argc - optidx < 1) {
1293			error("You must specify at least one path after a "
1294			    "%s command.", cmd);
1295			return -1;
1296		}
1297		*path1 = xstrdup(argv[optidx]);
1298		/* Get second pathname (optional) */
1299		if (argc - optidx > 1) {
1300			*path2 = xstrdup(argv[optidx + 1]);
1301			/* Destination is not globbed */
1302			undo_glob_escape(*path2);
1303		}
1304		break;
1305	case I_LINK:
1306		if ((optidx = parse_link_flags(cmd, argv, argc, sflag)) == -1)
1307			return -1;
1308		goto parse_two_paths;
1309	case I_RENAME:
1310		if ((optidx = parse_rename_flags(cmd, argv, argc, lflag)) == -1)
1311			return -1;
1312		goto parse_two_paths;
1313	case I_SYMLINK:
1314		if ((optidx = parse_no_flags(cmd, argv, argc)) == -1)
1315			return -1;
1316 parse_two_paths:
1317		if (argc - optidx < 2) {
1318			error("You must specify two paths after a %s "
1319			    "command.", cmd);
1320			return -1;
1321		}
1322		*path1 = xstrdup(argv[optidx]);
1323		*path2 = xstrdup(argv[optidx + 1]);
1324		/* Paths are not globbed */
1325		undo_glob_escape(*path1);
1326		undo_glob_escape(*path2);
1327		break;
1328	case I_RM:
1329	case I_MKDIR:
1330	case I_RMDIR:
1331	case I_CHDIR:
1332	case I_LCHDIR:
1333	case I_LMKDIR:
1334		if ((optidx = parse_no_flags(cmd, argv, argc)) == -1)
1335			return -1;
1336		/* Get pathname (mandatory) */
1337		if (argc - optidx < 1) {
1338			error("You must specify a path after a %s command.",
1339			    cmd);
1340			return -1;
1341		}
1342		*path1 = xstrdup(argv[optidx]);
1343		/* Only "rm" globs */
1344		if (cmdnum != I_RM)
1345			undo_glob_escape(*path1);
1346		break;
1347	case I_DF:
1348		if ((optidx = parse_df_flags(cmd, argv, argc, hflag,
1349		    iflag)) == -1)
1350			return -1;
1351		/* Default to current directory if no path specified */
1352		if (argc - optidx < 1)
1353			*path1 = NULL;
1354		else {
1355			*path1 = xstrdup(argv[optidx]);
1356			undo_glob_escape(*path1);
1357		}
1358		break;
1359	case I_LS:
1360		if ((optidx = parse_ls_flags(argv, argc, lflag)) == -1)
1361			return(-1);
1362		/* Path is optional */
1363		if (argc - optidx > 0)
1364			*path1 = xstrdup(argv[optidx]);
1365		break;
1366	case I_LLS:
1367		/* Skip ls command and following whitespace */
1368		cp = cp + strlen(cmd) + strspn(cp, WHITESPACE);
1369	case I_SHELL:
1370		/* Uses the rest of the line */
1371		break;
1372	case I_LUMASK:
1373	case I_CHMOD:
1374		base = 8;
1375	case I_CHOWN:
1376	case I_CHGRP:
1377		if ((optidx = parse_no_flags(cmd, argv, argc)) == -1)
1378			return -1;
1379		/* Get numeric arg (mandatory) */
1380		if (argc - optidx < 1)
1381			goto need_num_arg;
1382		errno = 0;
1383		l = strtol(argv[optidx], &cp2, base);
1384		if (cp2 == argv[optidx] || *cp2 != '\0' ||
1385		    ((l == LONG_MIN || l == LONG_MAX) && errno == ERANGE) ||
1386		    l < 0) {
1387 need_num_arg:
1388			error("You must supply a numeric argument "
1389			    "to the %s command.", cmd);
1390			return -1;
1391		}
1392		*n_arg = l;
1393		if (cmdnum == I_LUMASK)
1394			break;
1395		/* Get pathname (mandatory) */
1396		if (argc - optidx < 2) {
1397			error("You must specify a path after a %s command.",
1398			    cmd);
1399			return -1;
1400		}
1401		*path1 = xstrdup(argv[optidx + 1]);
1402		break;
1403	case I_QUIT:
1404	case I_PWD:
1405	case I_LPWD:
1406	case I_HELP:
1407	case I_VERSION:
1408	case I_PROGRESS:
1409		if ((optidx = parse_no_flags(cmd, argv, argc)) == -1)
1410			return -1;
1411		break;
1412	default:
1413		fatal("Command not implemented");
1414	}
1415
1416	*cpp = cp;
1417	return(cmdnum);
1418}
1419
1420static int
1421parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
1422    int err_abort)
1423{
1424	char *path1, *path2, *tmp;
1425	int ignore_errors = 0, aflag = 0, fflag = 0, hflag = 0,
1426	iflag = 0;
1427	int lflag = 0, pflag = 0, rflag = 0, sflag = 0;
1428	int cmdnum, i;
1429	unsigned long n_arg = 0;
1430	Attrib a, *aa;
1431	char path_buf[PATH_MAX];
1432	int err = 0;
1433	glob_t g;
1434
1435	path1 = path2 = NULL;
1436	cmdnum = parse_args(&cmd, &ignore_errors, &aflag, &fflag, &hflag,
1437	    &iflag, &lflag, &pflag, &rflag, &sflag, &n_arg, &path1, &path2);
1438	if (ignore_errors != 0)
1439		err_abort = 0;
1440
1441	memset(&g, 0, sizeof(g));
1442
1443	/* Perform command */
1444	switch (cmdnum) {
1445	case 0:
1446		/* Blank line */
1447		break;
1448	case -1:
1449		/* Unrecognized command */
1450		err = -1;
1451		break;
1452	case I_REGET:
1453		aflag = 1;
1454		/* FALLTHROUGH */
1455	case I_GET:
1456		err = process_get(conn, path1, path2, *pwd, pflag,
1457		    rflag, aflag, fflag);
1458		break;
1459	case I_REPUT:
1460		aflag = 1;
1461		/* FALLTHROUGH */
1462	case I_PUT:
1463		err = process_put(conn, path1, path2, *pwd, pflag,
1464		    rflag, aflag, fflag);
1465		break;
1466	case I_RENAME:
1467		path1 = make_absolute(path1, *pwd);
1468		path2 = make_absolute(path2, *pwd);
1469		err = do_rename(conn, path1, path2, lflag);
1470		break;
1471	case I_SYMLINK:
1472		sflag = 1;
1473	case I_LINK:
1474		if (!sflag)
1475			path1 = make_absolute(path1, *pwd);
1476		path2 = make_absolute(path2, *pwd);
1477		err = (sflag ? do_symlink : do_hardlink)(conn, path1, path2);
1478		break;
1479	case I_RM:
1480		path1 = make_absolute(path1, *pwd);
1481		remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g);
1482		for (i = 0; g.gl_pathv[i] && !interrupted; i++) {
1483			if (!quiet)
1484				mprintf("Removing %s\n", g.gl_pathv[i]);
1485			err = do_rm(conn, g.gl_pathv[i]);
1486			if (err != 0 && err_abort)
1487				break;
1488		}
1489		break;
1490	case I_MKDIR:
1491		path1 = make_absolute(path1, *pwd);
1492		attrib_clear(&a);
1493		a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS;
1494		a.perm = 0777;
1495		err = do_mkdir(conn, path1, &a, 1);
1496		break;
1497	case I_RMDIR:
1498		path1 = make_absolute(path1, *pwd);
1499		err = do_rmdir(conn, path1);
1500		break;
1501	case I_CHDIR:
1502		path1 = make_absolute(path1, *pwd);
1503		if ((tmp = do_realpath(conn, path1)) == NULL) {
1504			err = 1;
1505			break;
1506		}
1507		if ((aa = do_stat(conn, tmp, 0)) == NULL) {
1508			free(tmp);
1509			err = 1;
1510			break;
1511		}
1512		if (!(aa->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)) {
1513			error("Can't change directory: Can't check target");
1514			free(tmp);
1515			err = 1;
1516			break;
1517		}
1518		if (!S_ISDIR(aa->perm)) {
1519			error("Can't change directory: \"%s\" is not "
1520			    "a directory", tmp);
1521			free(tmp);
1522			err = 1;
1523			break;
1524		}
1525		free(*pwd);
1526		*pwd = tmp;
1527		break;
1528	case I_LS:
1529		if (!path1) {
1530			do_ls_dir(conn, *pwd, *pwd, lflag);
1531			break;
1532		}
1533
1534		/* Strip pwd off beginning of non-absolute paths */
1535		tmp = NULL;
1536		if (*path1 != '/')
1537			tmp = *pwd;
1538
1539		path1 = make_absolute(path1, *pwd);
1540		err = do_globbed_ls(conn, path1, tmp, lflag);
1541		break;
1542	case I_DF:
1543		/* Default to current directory if no path specified */
1544		if (path1 == NULL)
1545			path1 = xstrdup(*pwd);
1546		path1 = make_absolute(path1, *pwd);
1547		err = do_df(conn, path1, hflag, iflag);
1548		break;
1549	case I_LCHDIR:
1550		tmp = tilde_expand_filename(path1, getuid());
1551		free(path1);
1552		path1 = tmp;
1553		if (chdir(path1) == -1) {
1554			error("Couldn't change local directory to "
1555			    "\"%s\": %s", path1, strerror(errno));
1556			err = 1;
1557		}
1558		break;
1559	case I_LMKDIR:
1560		if (mkdir(path1, 0777) == -1) {
1561			error("Couldn't create local directory "
1562			    "\"%s\": %s", path1, strerror(errno));
1563			err = 1;
1564		}
1565		break;
1566	case I_LLS:
1567		local_do_ls(cmd);
1568		break;
1569	case I_SHELL:
1570		local_do_shell(cmd);
1571		break;
1572	case I_LUMASK:
1573		umask(n_arg);
1574		printf("Local umask: %03lo\n", n_arg);
1575		break;
1576	case I_CHMOD:
1577		path1 = make_absolute(path1, *pwd);
1578		attrib_clear(&a);
1579		a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS;
1580		a.perm = n_arg;
1581		remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g);
1582		for (i = 0; g.gl_pathv[i] && !interrupted; i++) {
1583			if (!quiet)
1584				mprintf("Changing mode on %s\n",
1585				    g.gl_pathv[i]);
1586			err = do_setstat(conn, g.gl_pathv[i], &a);
1587			if (err != 0 && err_abort)
1588				break;
1589		}
1590		break;
1591	case I_CHOWN:
1592	case I_CHGRP:
1593		path1 = make_absolute(path1, *pwd);
1594		remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g);
1595		for (i = 0; g.gl_pathv[i] && !interrupted; i++) {
1596			if (!(aa = do_stat(conn, g.gl_pathv[i], 0))) {
1597				if (err_abort) {
1598					err = -1;
1599					break;
1600				} else
1601					continue;
1602			}
1603			if (!(aa->flags & SSH2_FILEXFER_ATTR_UIDGID)) {
1604				error("Can't get current ownership of "
1605				    "remote file \"%s\"", g.gl_pathv[i]);
1606				if (err_abort) {
1607					err = -1;
1608					break;
1609				} else
1610					continue;
1611			}
1612			aa->flags &= SSH2_FILEXFER_ATTR_UIDGID;
1613			if (cmdnum == I_CHOWN) {
1614				if (!quiet)
1615					mprintf("Changing owner on %s\n",
1616					    g.gl_pathv[i]);
1617				aa->uid = n_arg;
1618			} else {
1619				if (!quiet)
1620					mprintf("Changing group on %s\n",
1621					    g.gl_pathv[i]);
1622				aa->gid = n_arg;
1623			}
1624			err = do_setstat(conn, g.gl_pathv[i], aa);
1625			if (err != 0 && err_abort)
1626				break;
1627		}
1628		break;
1629	case I_PWD:
1630		mprintf("Remote working directory: %s\n", *pwd);
1631		break;
1632	case I_LPWD:
1633		if (!getcwd(path_buf, sizeof(path_buf))) {
1634			error("Couldn't get local cwd: %s", strerror(errno));
1635			err = -1;
1636			break;
1637		}
1638		mprintf("Local working directory: %s\n", path_buf);
1639		break;
1640	case I_QUIT:
1641		/* Processed below */
1642		break;
1643	case I_HELP:
1644		help();
1645		break;
1646	case I_VERSION:
1647		printf("SFTP protocol version %u\n", sftp_proto_version(conn));
1648		break;
1649	case I_PROGRESS:
1650		showprogress = !showprogress;
1651		if (showprogress)
1652			printf("Progress meter enabled\n");
1653		else
1654			printf("Progress meter disabled\n");
1655		break;
1656	default:
1657		fatal("%d is not implemented", cmdnum);
1658	}
1659
1660	if (g.gl_pathc)
1661		globfree(&g);
1662	free(path1);
1663	free(path2);
1664
1665	/* If an unignored error occurs in batch mode we should abort. */
1666	if (err_abort && err != 0)
1667		return (-1);
1668	else if (cmdnum == I_QUIT)
1669		return (1);
1670
1671	return (0);
1672}
1673
1674#ifdef USE_LIBEDIT
1675static char *
1676prompt(EditLine *el)
1677{
1678	return ("sftp> ");
1679}
1680
1681/* Display entries in 'list' after skipping the first 'len' chars */
1682static void
1683complete_display(char **list, u_int len)
1684{
1685	u_int y, m = 0, width = 80, columns = 1, colspace = 0, llen;
1686	struct winsize ws;
1687	char *tmp;
1688
1689	/* Count entries for sort and find longest */
1690	for (y = 0; list[y]; y++)
1691		m = MAXIMUM(m, strlen(list[y]));
1692
1693	if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) != -1)
1694		width = ws.ws_col;
1695
1696	m = m > len ? m - len : 0;
1697	columns = width / (m + 2);
1698	columns = MAXIMUM(columns, 1);
1699	colspace = width / columns;
1700	colspace = MINIMUM(colspace, width);
1701
1702	printf("\n");
1703	m = 1;
1704	for (y = 0; list[y]; y++) {
1705		llen = strlen(list[y]);
1706		tmp = llen > len ? list[y] + len : "";
1707		mprintf("%-*s", colspace, tmp);
1708		if (m >= columns) {
1709			printf("\n");
1710			m = 1;
1711		} else
1712			m++;
1713	}
1714	printf("\n");
1715}
1716
1717/*
1718 * Given a "list" of words that begin with a common prefix of "word",
1719 * attempt to find an autocompletion to extends "word" by the next
1720 * characters common to all entries in "list".
1721 */
1722static char *
1723complete_ambiguous(const char *word, char **list, size_t count)
1724{
1725	if (word == NULL)
1726		return NULL;
1727
1728	if (count > 0) {
1729		u_int y, matchlen = strlen(list[0]);
1730
1731		/* Find length of common stem */
1732		for (y = 1; list[y]; y++) {
1733			u_int x;
1734
1735			for (x = 0; x < matchlen; x++)
1736				if (list[0][x] != list[y][x])
1737					break;
1738
1739			matchlen = x;
1740		}
1741
1742		if (matchlen > strlen(word)) {
1743			char *tmp = xstrdup(list[0]);
1744
1745			tmp[matchlen] = '\0';
1746			return tmp;
1747		}
1748	}
1749
1750	return xstrdup(word);
1751}
1752
1753/* Autocomplete a sftp command */
1754static int
1755complete_cmd_parse(EditLine *el, char *cmd, int lastarg, char quote,
1756    int terminated)
1757{
1758	u_int y, count = 0, cmdlen, tmplen;
1759	char *tmp, **list, argterm[3];
1760	const LineInfo *lf;
1761
1762	list = xcalloc((sizeof(cmds) / sizeof(*cmds)) + 1, sizeof(char *));
1763
1764	/* No command specified: display all available commands */
1765	if (cmd == NULL) {
1766		for (y = 0; cmds[y].c; y++)
1767			list[count++] = xstrdup(cmds[y].c);
1768
1769		list[count] = NULL;
1770		complete_display(list, 0);
1771
1772		for (y = 0; list[y] != NULL; y++)
1773			free(list[y]);
1774		free(list);
1775		return count;
1776	}
1777
1778	/* Prepare subset of commands that start with "cmd" */
1779	cmdlen = strlen(cmd);
1780	for (y = 0; cmds[y].c; y++)  {
1781		if (!strncasecmp(cmd, cmds[y].c, cmdlen))
1782			list[count++] = xstrdup(cmds[y].c);
1783	}
1784	list[count] = NULL;
1785
1786	if (count == 0) {
1787		free(list);
1788		return 0;
1789	}
1790
1791	/* Complete ambigious command */
1792	tmp = complete_ambiguous(cmd, list, count);
1793	if (count > 1)
1794		complete_display(list, 0);
1795
1796	for (y = 0; list[y]; y++)
1797		free(list[y]);
1798	free(list);
1799
1800	if (tmp != NULL) {
1801		tmplen = strlen(tmp);
1802		cmdlen = strlen(cmd);
1803		/* If cmd may be extended then do so */
1804		if (tmplen > cmdlen)
1805			if (el_insertstr(el, tmp + cmdlen) == -1)
1806				fatal("el_insertstr failed.");
1807		lf = el_line(el);
1808		/* Terminate argument cleanly */
1809		if (count == 1) {
1810			y = 0;
1811			if (!terminated)
1812				argterm[y++] = quote;
1813			if (lastarg || *(lf->cursor) != ' ')
1814				argterm[y++] = ' ';
1815			argterm[y] = '\0';
1816			if (y > 0 && el_insertstr(el, argterm) == -1)
1817				fatal("el_insertstr failed.");
1818		}
1819		free(tmp);
1820	}
1821
1822	return count;
1823}
1824
1825/*
1826 * Determine whether a particular sftp command's arguments (if any)
1827 * represent local or remote files.
1828 */
1829static int
1830complete_is_remote(char *cmd) {
1831	int i;
1832
1833	if (cmd == NULL)
1834		return -1;
1835
1836	for (i = 0; cmds[i].c; i++) {
1837		if (!strncasecmp(cmd, cmds[i].c, strlen(cmds[i].c)))
1838			return cmds[i].t;
1839	}
1840
1841	return -1;
1842}
1843
1844/* Autocomplete a filename "file" */
1845static int
1846complete_match(EditLine *el, struct sftp_conn *conn, char *remote_path,
1847    char *file, int remote, int lastarg, char quote, int terminated)
1848{
1849	glob_t g;
1850	char *tmp, *tmp2, ins[8];
1851	u_int i, hadglob, pwdlen, len, tmplen, filelen, cesc, isesc, isabs;
1852	int clen;
1853	const LineInfo *lf;
1854
1855	/* Glob from "file" location */
1856	if (file == NULL)
1857		tmp = xstrdup("*");
1858	else
1859		xasprintf(&tmp, "%s*", file);
1860
1861	/* Check if the path is absolute. */
1862	isabs = tmp[0] == '/';
1863
1864	memset(&g, 0, sizeof(g));
1865	if (remote != LOCAL) {
1866		tmp = make_absolute(tmp, remote_path);
1867		remote_glob(conn, tmp, GLOB_DOOFFS|GLOB_MARK, NULL, &g);
1868	} else
1869		glob(tmp, GLOB_DOOFFS|GLOB_MARK, NULL, &g);
1870
1871	/* Determine length of pwd so we can trim completion display */
1872	for (hadglob = tmplen = pwdlen = 0; tmp[tmplen] != 0; tmplen++) {
1873		/* Terminate counting on first unescaped glob metacharacter */
1874		if (tmp[tmplen] == '*' || tmp[tmplen] == '?') {
1875			if (tmp[tmplen] != '*' || tmp[tmplen + 1] != '\0')
1876				hadglob = 1;
1877			break;
1878		}
1879		if (tmp[tmplen] == '\\' && tmp[tmplen + 1] != '\0')
1880			tmplen++;
1881		if (tmp[tmplen] == '/')
1882			pwdlen = tmplen + 1;	/* track last seen '/' */
1883	}
1884	free(tmp);
1885	tmp = NULL;
1886
1887	if (g.gl_matchc == 0)
1888		goto out;
1889
1890	if (g.gl_matchc > 1)
1891		complete_display(g.gl_pathv, pwdlen);
1892
1893	/* Don't try to extend globs */
1894	if (file == NULL || hadglob)
1895		goto out;
1896
1897	tmp2 = complete_ambiguous(file, g.gl_pathv, g.gl_matchc);
1898	tmp = path_strip(tmp2, isabs ? NULL : remote_path);
1899	free(tmp2);
1900
1901	if (tmp == NULL)
1902		goto out;
1903
1904	tmplen = strlen(tmp);
1905	filelen = strlen(file);
1906
1907	/* Count the number of escaped characters in the input string. */
1908	cesc = isesc = 0;
1909	for (i = 0; i < filelen; i++) {
1910		if (!isesc && file[i] == '\\' && i + 1 < filelen){
1911			isesc = 1;
1912			cesc++;
1913		} else
1914			isesc = 0;
1915	}
1916
1917	if (tmplen > (filelen - cesc)) {
1918		tmp2 = tmp + filelen - cesc;
1919		len = strlen(tmp2);
1920		/* quote argument on way out */
1921		for (i = 0; i < len; i += clen) {
1922			if ((clen = mblen(tmp2 + i, len - i)) < 0 ||
1923			    (size_t)clen > sizeof(ins) - 2)
1924				fatal("invalid multibyte character");
1925			ins[0] = '\\';
1926			memcpy(ins + 1, tmp2 + i, clen);
1927			ins[clen + 1] = '\0';
1928			switch (tmp2[i]) {
1929			case '\'':
1930			case '"':
1931			case '\\':
1932			case '\t':
1933			case '[':
1934			case ' ':
1935			case '#':
1936			case '*':
1937				if (quote == '\0' || tmp2[i] == quote) {
1938					if (el_insertstr(el, ins) == -1)
1939						fatal("el_insertstr "
1940						    "failed.");
1941					break;
1942				}
1943				/* FALLTHROUGH */
1944			default:
1945				if (el_insertstr(el, ins + 1) == -1)
1946					fatal("el_insertstr failed.");
1947				break;
1948			}
1949		}
1950	}
1951
1952	lf = el_line(el);
1953	if (g.gl_matchc == 1) {
1954		i = 0;
1955		if (!terminated && quote != '\0')
1956			ins[i++] = quote;
1957		if (*(lf->cursor - 1) != '/' &&
1958		    (lastarg || *(lf->cursor) != ' '))
1959			ins[i++] = ' ';
1960		ins[i] = '\0';
1961		if (i > 0 && el_insertstr(el, ins) == -1)
1962			fatal("el_insertstr failed.");
1963	}
1964	free(tmp);
1965
1966 out:
1967	globfree(&g);
1968	return g.gl_matchc;
1969}
1970
1971/* tab-completion hook function, called via libedit */
1972static unsigned char
1973complete(EditLine *el, int ch)
1974{
1975	char **argv, *line, quote;
1976	int argc, carg;
1977	u_int cursor, len, terminated, ret = CC_ERROR;
1978	const LineInfo *lf;
1979	struct complete_ctx *complete_ctx;
1980
1981	lf = el_line(el);
1982	if (el_get(el, EL_CLIENTDATA, (void**)&complete_ctx) != 0)
1983		fatal("%s: el_get failed", __func__);
1984
1985	/* Figure out which argument the cursor points to */
1986	cursor = lf->cursor - lf->buffer;
1987	line = xmalloc(cursor + 1);
1988	memcpy(line, lf->buffer, cursor);
1989	line[cursor] = '\0';
1990	argv = makeargv(line, &carg, 1, &quote, &terminated);
1991	free(line);
1992
1993	/* Get all the arguments on the line */
1994	len = lf->lastchar - lf->buffer;
1995	line = xmalloc(len + 1);
1996	memcpy(line, lf->buffer, len);
1997	line[len] = '\0';
1998	argv = makeargv(line, &argc, 1, NULL, NULL);
1999
2000	/* Ensure cursor is at EOL or a argument boundary */
2001	if (line[cursor] != ' ' && line[cursor] != '\0' &&
2002	    line[cursor] != '\n') {
2003		free(line);
2004		return ret;
2005	}
2006
2007	if (carg == 0) {
2008		/* Show all available commands */
2009		complete_cmd_parse(el, NULL, argc == carg, '\0', 1);
2010		ret = CC_REDISPLAY;
2011	} else if (carg == 1 && cursor > 0 && line[cursor - 1] != ' ')  {
2012		/* Handle the command parsing */
2013		if (complete_cmd_parse(el, argv[0], argc == carg,
2014		    quote, terminated) != 0)
2015			ret = CC_REDISPLAY;
2016	} else if (carg >= 1) {
2017		/* Handle file parsing */
2018		int remote = complete_is_remote(argv[0]);
2019		char *filematch = NULL;
2020
2021		if (carg > 1 && line[cursor-1] != ' ')
2022			filematch = argv[carg - 1];
2023
2024		if (remote != 0 &&
2025		    complete_match(el, complete_ctx->conn,
2026		    *complete_ctx->remote_pathp, filematch,
2027		    remote, carg == argc, quote, terminated) != 0)
2028			ret = CC_REDISPLAY;
2029	}
2030
2031	free(line);
2032	return ret;
2033}
2034#endif /* USE_LIBEDIT */
2035
2036int
2037interactive_loop(struct sftp_conn *conn, char *file1, char *file2)
2038{
2039	char *remote_path;
2040	char *dir = NULL;
2041	char cmd[2048];
2042	int err, interactive;
2043	EditLine *el = NULL;
2044#ifdef USE_LIBEDIT
2045	History *hl = NULL;
2046	HistEvent hev;
2047	extern char *__progname;
2048	struct complete_ctx complete_ctx;
2049
2050	if (!batchmode && isatty(STDIN_FILENO)) {
2051		if ((el = el_init(__progname, stdin, stdout, stderr)) == NULL)
2052			fatal("Couldn't initialise editline");
2053		if ((hl = history_init()) == NULL)
2054			fatal("Couldn't initialise editline history");
2055		history(hl, &hev, H_SETSIZE, 100);
2056		el_set(el, EL_HIST, history, hl);
2057
2058		el_set(el, EL_PROMPT, prompt);
2059		el_set(el, EL_EDITOR, "emacs");
2060		el_set(el, EL_TERMINAL, NULL);
2061		el_set(el, EL_SIGNAL, 1);
2062		el_source(el, NULL);
2063
2064		/* Tab Completion */
2065		el_set(el, EL_ADDFN, "ftp-complete",
2066		    "Context sensitive argument completion", complete);
2067		complete_ctx.conn = conn;
2068		complete_ctx.remote_pathp = &remote_path;
2069		el_set(el, EL_CLIENTDATA, (void*)&complete_ctx);
2070		el_set(el, EL_BIND, "^I", "ftp-complete", NULL);
2071		/* enable ctrl-left-arrow and ctrl-right-arrow */
2072		el_set(el, EL_BIND, "\\e[1;5C", "em-next-word", NULL);
2073		el_set(el, EL_BIND, "\\e[5C", "em-next-word", NULL);
2074		el_set(el, EL_BIND, "\\e[1;5D", "ed-prev-word", NULL);
2075		el_set(el, EL_BIND, "\\e\\e[D", "ed-prev-word", NULL);
2076		/* make ^w match ksh behaviour */
2077		el_set(el, EL_BIND, "^w", "ed-delete-prev-word", NULL);
2078	}
2079#endif /* USE_LIBEDIT */
2080
2081	remote_path = do_realpath(conn, ".");
2082	if (remote_path == NULL)
2083		fatal("Need cwd");
2084
2085	if (file1 != NULL) {
2086		dir = xstrdup(file1);
2087		dir = make_absolute(dir, remote_path);
2088
2089		if (remote_is_dir(conn, dir) && file2 == NULL) {
2090			if (!quiet)
2091				mprintf("Changing to: %s\n", dir);
2092			snprintf(cmd, sizeof cmd, "cd \"%s\"", dir);
2093			if (parse_dispatch_command(conn, cmd,
2094			    &remote_path, 1) != 0) {
2095				free(dir);
2096				free(remote_path);
2097				free(conn);
2098				return (-1);
2099			}
2100		} else {
2101			/* XXX this is wrong wrt quoting */
2102			snprintf(cmd, sizeof cmd, "get%s %s%s%s",
2103			    global_aflag ? " -a" : "", dir,
2104			    file2 == NULL ? "" : " ",
2105			    file2 == NULL ? "" : file2);
2106			err = parse_dispatch_command(conn, cmd,
2107			    &remote_path, 1);
2108			free(dir);
2109			free(remote_path);
2110			free(conn);
2111			return (err);
2112		}
2113		free(dir);
2114	}
2115
2116	setvbuf(stdout, NULL, _IOLBF, 0);
2117	setvbuf(infile, NULL, _IOLBF, 0);
2118
2119	interactive = !batchmode && isatty(STDIN_FILENO);
2120	err = 0;
2121	for (;;) {
2122		char *cp;
2123
2124		signal(SIGINT, SIG_IGN);
2125
2126		if (el == NULL) {
2127			if (interactive)
2128				printf("sftp> ");
2129			if (fgets(cmd, sizeof(cmd), infile) == NULL) {
2130				if (interactive)
2131					printf("\n");
2132				break;
2133			}
2134			if (!interactive) { /* Echo command */
2135				mprintf("sftp> %s", cmd);
2136				if (strlen(cmd) > 0 &&
2137				    cmd[strlen(cmd) - 1] != '\n')
2138					printf("\n");
2139			}
2140		} else {
2141#ifdef USE_LIBEDIT
2142			const char *line;
2143			int count = 0;
2144
2145			if ((line = el_gets(el, &count)) == NULL ||
2146			    count <= 0) {
2147				printf("\n");
2148 				break;
2149			}
2150			history(hl, &hev, H_ENTER, line);
2151			if (strlcpy(cmd, line, sizeof(cmd)) >= sizeof(cmd)) {
2152				fprintf(stderr, "Error: input line too long\n");
2153				continue;
2154			}
2155#endif /* USE_LIBEDIT */
2156		}
2157
2158		cp = strrchr(cmd, '\n');
2159		if (cp)
2160			*cp = '\0';
2161
2162		/* Handle user interrupts gracefully during commands */
2163		interrupted = 0;
2164		signal(SIGINT, cmd_interrupt);
2165
2166		err = parse_dispatch_command(conn, cmd, &remote_path,
2167		    batchmode);
2168		if (err != 0)
2169			break;
2170	}
2171	free(remote_path);
2172	free(conn);
2173
2174#ifdef USE_LIBEDIT
2175	if (el != NULL)
2176		el_end(el);
2177#endif /* USE_LIBEDIT */
2178
2179	/* err == 1 signifies normal "quit" exit */
2180	return (err >= 0 ? 0 : -1);
2181}
2182
2183static void
2184connect_to_server(char *path, char **args, int *in, int *out)
2185{
2186	int c_in, c_out;
2187
2188#ifdef USE_PIPES
2189	int pin[2], pout[2];
2190
2191	if ((pipe(pin) == -1) || (pipe(pout) == -1))
2192		fatal("pipe: %s", strerror(errno));
2193	*in = pin[0];
2194	*out = pout[1];
2195	c_in = pout[0];
2196	c_out = pin[1];
2197#else /* USE_PIPES */
2198	int inout[2];
2199
2200	if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) == -1)
2201		fatal("socketpair: %s", strerror(errno));
2202	*in = *out = inout[0];
2203	c_in = c_out = inout[1];
2204#endif /* USE_PIPES */
2205
2206	if ((sshpid = fork()) == -1)
2207		fatal("fork: %s", strerror(errno));
2208	else if (sshpid == 0) {
2209		if ((dup2(c_in, STDIN_FILENO) == -1) ||
2210		    (dup2(c_out, STDOUT_FILENO) == -1)) {
2211			fprintf(stderr, "dup2: %s\n", strerror(errno));
2212			_exit(1);
2213		}
2214		close(*in);
2215		close(*out);
2216		close(c_in);
2217		close(c_out);
2218
2219		/*
2220		 * The underlying ssh is in the same process group, so we must
2221		 * ignore SIGINT if we want to gracefully abort commands,
2222		 * otherwise the signal will make it to the ssh process and
2223		 * kill it too.  Contrawise, since sftp sends SIGTERMs to the
2224		 * underlying ssh, it must *not* ignore that signal.
2225		 */
2226		signal(SIGINT, SIG_IGN);
2227		signal(SIGTERM, SIG_DFL);
2228		execvp(path, args);
2229		fprintf(stderr, "exec: %s: %s\n", path, strerror(errno));
2230		_exit(1);
2231	}
2232
2233	signal(SIGTERM, killchild);
2234	signal(SIGINT, killchild);
2235	signal(SIGHUP, killchild);
2236	signal(SIGTSTP, suspchild);
2237	signal(SIGTTIN, suspchild);
2238	signal(SIGTTOU, suspchild);
2239	close(c_in);
2240	close(c_out);
2241}
2242
2243static void
2244usage(void)
2245{
2246	extern char *__progname;
2247
2248	fprintf(stderr,
2249	    "usage: %s [-1246aCfpqrv] [-B buffer_size] [-b batchfile] [-c cipher]\n"
2250	    "          [-D sftp_server_path] [-F ssh_config] "
2251	    "[-i identity_file] [-l limit]\n"
2252	    "          [-o ssh_option] [-P port] [-R num_requests] "
2253	    "[-S program]\n"
2254	    "          [-s subsystem | sftp_server] host\n"
2255	    "       %s [user@]host[:file ...]\n"
2256	    "       %s [user@]host[:dir[/]]\n"
2257	    "       %s -b batchfile [user@]host\n",
2258	    __progname, __progname, __progname, __progname);
2259	exit(1);
2260}
2261
2262int
2263main(int argc, char **argv)
2264{
2265	int in, out, ch, err;
2266	char *host = NULL, *userhost, *cp, *file2 = NULL;
2267	int debug_level = 0, sshver = 2;
2268	char *file1 = NULL, *sftp_server = NULL;
2269	char *ssh_program = _PATH_SSH_PROGRAM, *sftp_direct = NULL;
2270	const char *errstr;
2271	LogLevel ll = SYSLOG_LEVEL_INFO;
2272	arglist args;
2273	extern int optind;
2274	extern char *optarg;
2275	struct sftp_conn *conn;
2276	size_t copy_buffer_len = DEFAULT_COPY_BUFLEN;
2277	size_t num_requests = DEFAULT_NUM_REQUESTS;
2278	long long limit_kbps = 0;
2279
2280	ssh_malloc_init();	/* must be called before any mallocs */
2281	/* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
2282	sanitise_stdfd();
2283	msetlocale();
2284
2285	__progname = ssh_get_progname(argv[0]);
2286	memset(&args, '\0', sizeof(args));
2287	args.list = NULL;
2288	addargs(&args, "%s", ssh_program);
2289	addargs(&args, "-oForwardX11 no");
2290	addargs(&args, "-oForwardAgent no");
2291	addargs(&args, "-oPermitLocalCommand no");
2292	addargs(&args, "-oClearAllForwardings yes");
2293
2294	ll = SYSLOG_LEVEL_INFO;
2295	infile = stdin;
2296
2297	while ((ch = getopt(argc, argv,
2298	    "1246afhpqrvCc:D:i:l:o:s:S:b:B:F:P:R:")) != -1) {
2299		switch (ch) {
2300		/* Passed through to ssh(1) */
2301		case '4':
2302		case '6':
2303		case 'C':
2304			addargs(&args, "-%c", ch);
2305			break;
2306		/* Passed through to ssh(1) with argument */
2307		case 'F':
2308		case 'c':
2309		case 'i':
2310		case 'o':
2311			addargs(&args, "-%c", ch);
2312			addargs(&args, "%s", optarg);
2313			break;
2314		case 'q':
2315			ll = SYSLOG_LEVEL_ERROR;
2316			quiet = 1;
2317			showprogress = 0;
2318			addargs(&args, "-%c", ch);
2319			break;
2320		case 'P':
2321			addargs(&args, "-oPort %s", optarg);
2322			break;
2323		case 'v':
2324			if (debug_level < 3) {
2325				addargs(&args, "-v");
2326				ll = SYSLOG_LEVEL_DEBUG1 + debug_level;
2327			}
2328			debug_level++;
2329			break;
2330		case '1':
2331			sshver = 1;
2332			if (sftp_server == NULL)
2333				sftp_server = _PATH_SFTP_SERVER;
2334			break;
2335		case '2':
2336			sshver = 2;
2337			break;
2338		case 'a':
2339			global_aflag = 1;
2340			break;
2341		case 'B':
2342			copy_buffer_len = strtol(optarg, &cp, 10);
2343			if (copy_buffer_len == 0 || *cp != '\0')
2344				fatal("Invalid buffer size \"%s\"", optarg);
2345			break;
2346		case 'b':
2347			if (batchmode)
2348				fatal("Batch file already specified.");
2349
2350			/* Allow "-" as stdin */
2351			if (strcmp(optarg, "-") != 0 &&
2352			    (infile = fopen(optarg, "r")) == NULL)
2353				fatal("%s (%s).", strerror(errno), optarg);
2354			showprogress = 0;
2355			quiet = batchmode = 1;
2356			addargs(&args, "-obatchmode yes");
2357			break;
2358		case 'f':
2359			global_fflag = 1;
2360			break;
2361		case 'p':
2362			global_pflag = 1;
2363			break;
2364		case 'D':
2365			sftp_direct = optarg;
2366			break;
2367		case 'l':
2368			limit_kbps = strtonum(optarg, 1, 100 * 1024 * 1024,
2369			    &errstr);
2370			if (errstr != NULL)
2371				usage();
2372			limit_kbps *= 1024; /* kbps */
2373			break;
2374		case 'r':
2375			global_rflag = 1;
2376			break;
2377		case 'R':
2378			num_requests = strtol(optarg, &cp, 10);
2379			if (num_requests == 0 || *cp != '\0')
2380				fatal("Invalid number of requests \"%s\"",
2381				    optarg);
2382			break;
2383		case 's':
2384			sftp_server = optarg;
2385			break;
2386		case 'S':
2387			ssh_program = optarg;
2388			replacearg(&args, 0, "%s", ssh_program);
2389			break;
2390		case 'h':
2391		default:
2392			usage();
2393		}
2394	}
2395
2396	if (!isatty(STDERR_FILENO))
2397		showprogress = 0;
2398
2399	log_init(argv[0], ll, SYSLOG_FACILITY_USER, 1);
2400
2401	if (sftp_direct == NULL) {
2402		if (optind == argc || argc > (optind + 2))
2403			usage();
2404
2405		userhost = xstrdup(argv[optind]);
2406		file2 = argv[optind+1];
2407
2408		if ((host = strrchr(userhost, '@')) == NULL)
2409			host = userhost;
2410		else {
2411			*host++ = '\0';
2412			if (!userhost[0]) {
2413				fprintf(stderr, "Missing username\n");
2414				usage();
2415			}
2416			addargs(&args, "-l");
2417			addargs(&args, "%s", userhost);
2418		}
2419
2420		if ((cp = colon(host)) != NULL) {
2421			*cp++ = '\0';
2422			file1 = cp;
2423		}
2424
2425		host = cleanhostname(host);
2426		if (!*host) {
2427			fprintf(stderr, "Missing hostname\n");
2428			usage();
2429		}
2430
2431		addargs(&args, "-oProtocol %d", sshver);
2432
2433		/* no subsystem if the server-spec contains a '/' */
2434		if (sftp_server == NULL || strchr(sftp_server, '/') == NULL)
2435			addargs(&args, "-s");
2436
2437		addargs(&args, "--");
2438		addargs(&args, "%s", host);
2439		addargs(&args, "%s", (sftp_server != NULL ?
2440		    sftp_server : "sftp"));
2441
2442		connect_to_server(ssh_program, args.list, &in, &out);
2443	} else {
2444		args.list = NULL;
2445		addargs(&args, "sftp-server");
2446
2447		connect_to_server(sftp_direct, args.list, &in, &out);
2448	}
2449	freeargs(&args);
2450
2451	conn = do_init(in, out, copy_buffer_len, num_requests, limit_kbps);
2452	if (conn == NULL)
2453		fatal("Couldn't initialise connection to server");
2454
2455	if (!quiet) {
2456		if (sftp_direct == NULL)
2457			fprintf(stderr, "Connected to %s.\n", host);
2458		else
2459			fprintf(stderr, "Attached to %s.\n", sftp_direct);
2460	}
2461
2462	err = interactive_loop(conn, file1, file2);
2463
2464#if !defined(USE_PIPES)
2465	shutdown(in, SHUT_RDWR);
2466	shutdown(out, SHUT_RDWR);
2467#endif
2468
2469	close(in);
2470	close(out);
2471	if (batchmode)
2472		fclose(infile);
2473
2474	while (waitpid(sshpid, NULL, 0) == -1)
2475		if (errno != EINTR)
2476			fatal("Couldn't wait for ssh process: %s",
2477			    strerror(errno));
2478
2479	exit(err == 0 ? 0 : 1);
2480}
2481