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