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