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