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