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