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