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