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