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