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