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