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