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