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