xref: /netbsd-src/crypto/external/bsd/openssh/dist/sftp.c (revision 7788a0781fe6ff2cce37368b4578a7ade0850cb1)
1 /*	$NetBSD: sftp.c,v 1.11 2013/03/29 16:19:45 christos Exp $	*/
2 /* $OpenBSD: sftp.c,v 1.142 2013/02/08 00:41:12 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.11 2013/03/29 16:19:45 christos Exp $");
21 #include <sys/types.h>
22 #include <sys/ioctl.h>
23 #include <sys/wait.h>
24 #include <sys/stat.h>
25 #include <sys/socket.h>
26 #include <sys/param.h>
27 #include <sys/statvfs.h>
28 
29 #include <ctype.h>
30 #include <errno.h>
31 #include <glob.h>
32 #include <histedit.h>
33 #include <paths.h>
34 #include <libgen.h>
35 #include <signal.h>
36 #include <stdlib.h>
37 #include <stdio.h>
38 #include <string.h>
39 #include <unistd.h>
40 #include <util.h>
41 #include <stdarg.h>
42 
43 #include "xmalloc.h"
44 #include "log.h"
45 #include "pathnames.h"
46 #include "misc.h"
47 
48 #include "sftp.h"
49 #include "buffer.h"
50 #include "sftp-common.h"
51 #include "sftp-client.h"
52 #include "fmt_scaled.h"
53 
54 #define DEFAULT_COPY_BUFLEN	32768	/* Size of buffer for up/download */
55 #define DEFAULT_NUM_REQUESTS	256	/* # concurrent outstanding requests */
56 
57 /* File to read commands from */
58 FILE* infile;
59 
60 /* Are we in batchfile mode? */
61 int batchmode = 0;
62 
63 /* PID of ssh transport process */
64 static pid_t sshpid = -1;
65 
66 /* This is set to 0 if the progressmeter is not desired. */
67 int showprogress = 1;
68 
69 /* When this option is set, we always recursively download/upload directories */
70 int global_rflag = 0;
71 
72 /* When this option is set, the file transfers will always preserve times */
73 int global_pflag = 0;
74 
75 /* SIGINT received during command processing */
76 volatile sig_atomic_t interrupted = 0;
77 
78 /* I wish qsort() took a separate ctx for the comparison function...*/
79 int sort_flag;
80 
81 /* Context used for commandline completion */
82 struct complete_ctx {
83 	struct sftp_conn *conn;
84 	char **remote_pathp;
85 };
86 
87 int remote_glob(struct sftp_conn *, const char *, int,
88     int (*)(const char *, int), glob_t *); /* proto for sftp-glob.c */
89 
90 /* Separators for interactive commands */
91 #define WHITESPACE " \t\r\n"
92 
93 /* ls flags */
94 #define LS_LONG_VIEW	0x0001	/* Full view ala ls -l */
95 #define LS_SHORT_VIEW	0x0002	/* Single row view ala ls -1 */
96 #define LS_NUMERIC_VIEW	0x0004	/* Long view with numeric uid/gid */
97 #define LS_NAME_SORT	0x0008	/* Sort by name (default) */
98 #define LS_TIME_SORT	0x0010	/* Sort by mtime */
99 #define LS_SIZE_SORT	0x0020	/* Sort by file size */
100 #define LS_REVERSE_SORT	0x0040	/* Reverse sort order */
101 #define LS_SHOW_ALL	0x0080	/* Don't skip filenames starting with '.' */
102 #define LS_SI_UNITS	0x0100	/* Display sizes as K, M, G, etc. */
103 
104 #define VIEW_FLAGS	(LS_LONG_VIEW|LS_SHORT_VIEW|LS_NUMERIC_VIEW|LS_SI_UNITS)
105 #define SORT_FLAGS	(LS_NAME_SORT|LS_TIME_SORT|LS_SIZE_SORT)
106 
107 /* Commands for interactive mode */
108 #define I_CHDIR		1
109 #define I_CHGRP		2
110 #define I_CHMOD		3
111 #define I_CHOWN		4
112 #define I_DF		24
113 #define I_GET		5
114 #define I_HELP		6
115 #define I_LCHDIR	7
116 #define I_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 	char *fname, *lname;
770 	glob_t g;
771 	int err;
772 	struct winsize ws;
773 	u_int i, c = 1, colspace = 0, columns = 1, m = 0, width = 80;
774 	struct stat *stp;
775 #ifndef GLOB_KEEPSTAT
776 	struct stat st;
777 #define GLOB_KEEPSTAT	0
778 #endif
779 
780 	memset(&g, 0, sizeof(g));
781 
782 	if (remote_glob(conn, path,
783 	    GLOB_MARK|GLOB_NOCHECK|GLOB_BRACE|GLOB_KEEPSTAT|GLOB_NOSORT,
784 	    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++) {
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 ((size_t)argc >= sizeof(argv) / sizeof(*argv)){
993 			error("Too many arguments.");
994 			return NULL;
995 		}
996 		if (isspace((unsigned char)arg[i])) {
997 			if (state == MA_UNQUOTED) {
998 				/* Terminate current argument */
999 				argvs[j++] = '\0';
1000 				argc++;
1001 				state = MA_START;
1002 			} else if (state != MA_START)
1003 				argvs[j++] = arg[i];
1004 		} else if (arg[i] == '"' || arg[i] == '\'') {
1005 			q = arg[i] == '"' ? MA_DQUOTE : MA_SQUOTE;
1006 			if (state == MA_START) {
1007 				argv[argc] = argvs + j;
1008 				state = q;
1009 				if (lastquote != NULL)
1010 					*lastquote = arg[i];
1011 			} else if (state == MA_UNQUOTED)
1012 				state = q;
1013 			else if (state == q)
1014 				state = MA_UNQUOTED;
1015 			else
1016 				argvs[j++] = arg[i];
1017 		} else if (arg[i] == '\\') {
1018 			if (state == MA_SQUOTE || state == MA_DQUOTE) {
1019 				quot = state == MA_SQUOTE ? '\'' : '"';
1020 				/* Unescape quote we are in */
1021 				/* XXX support \n and friends? */
1022 				if (arg[i + 1] == quot) {
1023 					i++;
1024 					argvs[j++] = arg[i];
1025 				} else if (arg[i + 1] == '?' ||
1026 				    arg[i + 1] == '[' || arg[i + 1] == '*') {
1027 					/*
1028 					 * Special case for sftp: append
1029 					 * double-escaped glob sequence -
1030 					 * glob will undo one level of
1031 					 * escaping. NB. string can grow here.
1032 					 */
1033 					if (j >= sizeof(argvs) - 5)
1034 						goto args_too_longs;
1035 					argvs[j++] = '\\';
1036 					argvs[j++] = arg[i++];
1037 					argvs[j++] = '\\';
1038 					argvs[j++] = arg[i];
1039 				} else {
1040 					argvs[j++] = arg[i++];
1041 					argvs[j++] = arg[i];
1042 				}
1043 			} else {
1044 				if (state == MA_START) {
1045 					argv[argc] = argvs + j;
1046 					state = MA_UNQUOTED;
1047 					if (lastquote != NULL)
1048 						*lastquote = '\0';
1049 				}
1050 				if (arg[i + 1] == '?' || arg[i + 1] == '[' ||
1051 				    arg[i + 1] == '*' || arg[i + 1] == '\\') {
1052 					/*
1053 					 * Special case for sftp: append
1054 					 * escaped glob sequence -
1055 					 * glob will undo one level of
1056 					 * escaping.
1057 					 */
1058 					argvs[j++] = arg[i++];
1059 					argvs[j++] = arg[i];
1060 				} else {
1061 					/* Unescape everything */
1062 					/* XXX support \n and friends? */
1063 					i++;
1064 					argvs[j++] = arg[i];
1065 				}
1066 			}
1067 		} else if (arg[i] == '#') {
1068 			if (state == MA_SQUOTE || state == MA_DQUOTE)
1069 				argvs[j++] = arg[i];
1070 			else
1071 				goto string_done;
1072 		} else if (arg[i] == '\0') {
1073 			if (state == MA_SQUOTE || state == MA_DQUOTE) {
1074 				if (sloppy) {
1075 					state = MA_UNQUOTED;
1076 					if (terminated != NULL)
1077 						*terminated = 0;
1078 					goto string_done;
1079 				}
1080 				error("Unterminated quoted argument");
1081 				return NULL;
1082 			}
1083  string_done:
1084 			if (state == MA_UNQUOTED) {
1085 				argvs[j++] = '\0';
1086 				argc++;
1087 			}
1088 			break;
1089 		} else {
1090 			if (state == MA_START) {
1091 				argv[argc] = argvs + j;
1092 				state = MA_UNQUOTED;
1093 				if (lastquote != NULL)
1094 					*lastquote = '\0';
1095 			}
1096 			if ((state == MA_SQUOTE || state == MA_DQUOTE) &&
1097 			    (arg[i] == '?' || arg[i] == '[' || arg[i] == '*')) {
1098 				/*
1099 				 * Special case for sftp: escape quoted
1100 				 * glob(3) wildcards. NB. string can grow
1101 				 * here.
1102 				 */
1103 				if (j >= sizeof(argvs) - 3)
1104 					goto args_too_longs;
1105 				argvs[j++] = '\\';
1106 				argvs[j++] = arg[i];
1107 			} else
1108 				argvs[j++] = arg[i];
1109 		}
1110 		i++;
1111 	}
1112 	*argcp = argc;
1113 	return argv;
1114 }
1115 
1116 static int
1117 parse_args(const char **cpp, int *pflag, int *rflag, int *lflag, int *iflag,
1118     int *hflag, int *sflag, unsigned long *n_arg, char **path1, char **path2)
1119 {
1120 	const char *cmd, *cp = *cpp;
1121 	char *cp2, **argv;
1122 	int base = 0;
1123 	long l;
1124 	int i, cmdnum, optidx, argc;
1125 
1126 	/* Skip leading whitespace */
1127 	cp = cp + strspn(cp, WHITESPACE);
1128 
1129 	/* Check for leading '-' (disable error processing) */
1130 	*iflag = 0;
1131 	if (*cp == '-') {
1132 		*iflag = 1;
1133 		cp++;
1134 		cp = cp + strspn(cp, WHITESPACE);
1135 	}
1136 
1137 	/* Ignore blank lines and lines which begin with comment '#' char */
1138 	if (*cp == '\0' || *cp == '#')
1139 		return (0);
1140 
1141 	if ((argv = makeargv(cp, &argc, 0, NULL, NULL)) == NULL)
1142 		return -1;
1143 
1144 	/* Figure out which command we have */
1145 	for (i = 0; cmds[i].c != NULL; i++) {
1146 		if (argv[0] != NULL && strcasecmp(cmds[i].c, argv[0]) == 0)
1147 			break;
1148 	}
1149 	cmdnum = cmds[i].n;
1150 	cmd = cmds[i].c;
1151 
1152 	/* Special case */
1153 	if (*cp == '!') {
1154 		cp++;
1155 		cmdnum = I_SHELL;
1156 	} else if (cmdnum == -1) {
1157 		error("Invalid command.");
1158 		return -1;
1159 	}
1160 
1161 	/* Get arguments and parse flags */
1162 	*lflag = *pflag = *rflag = *hflag = *n_arg = 0;
1163 	*path1 = *path2 = NULL;
1164 	optidx = 1;
1165 	switch (cmdnum) {
1166 	case I_GET:
1167 	case I_PUT:
1168 		if ((optidx = parse_getput_flags(cmd, argv, argc,
1169 		    pflag, rflag)) == -1)
1170 			return -1;
1171 		/* Get first pathname (mandatory) */
1172 		if (argc - optidx < 1) {
1173 			error("You must specify at least one path after a "
1174 			    "%s command.", cmd);
1175 			return -1;
1176 		}
1177 		*path1 = xstrdup(argv[optidx]);
1178 		/* Get second pathname (optional) */
1179 		if (argc - optidx > 1) {
1180 			*path2 = xstrdup(argv[optidx + 1]);
1181 			/* Destination is not globbed */
1182 			undo_glob_escape(*path2);
1183 		}
1184 		break;
1185 	case I_LINK:
1186 		if ((optidx = parse_link_flags(cmd, argv, argc, sflag)) == -1)
1187 			return -1;
1188 	case I_SYMLINK:
1189 	case I_RENAME:
1190 		if (argc - optidx < 2) {
1191 			error("You must specify two paths after a %s "
1192 			    "command.", cmd);
1193 			return -1;
1194 		}
1195 		*path1 = xstrdup(argv[optidx]);
1196 		*path2 = xstrdup(argv[optidx + 1]);
1197 		/* Paths are not globbed */
1198 		undo_glob_escape(*path1);
1199 		undo_glob_escape(*path2);
1200 		break;
1201 	case I_RM:
1202 	case I_MKDIR:
1203 	case I_RMDIR:
1204 	case I_CHDIR:
1205 	case I_LCHDIR:
1206 	case I_LMKDIR:
1207 		/* Get pathname (mandatory) */
1208 		if (argc - optidx < 1) {
1209 			error("You must specify a path after a %s command.",
1210 			    cmd);
1211 			return -1;
1212 		}
1213 		*path1 = xstrdup(argv[optidx]);
1214 		/* Only "rm" globs */
1215 		if (cmdnum != I_RM)
1216 			undo_glob_escape(*path1);
1217 		break;
1218 	case I_DF:
1219 		if ((optidx = parse_df_flags(cmd, argv, argc, hflag,
1220 		    iflag)) == -1)
1221 			return -1;
1222 		/* Default to current directory if no path specified */
1223 		if (argc - optidx < 1)
1224 			*path1 = NULL;
1225 		else {
1226 			*path1 = xstrdup(argv[optidx]);
1227 			undo_glob_escape(*path1);
1228 		}
1229 		break;
1230 	case I_LS:
1231 		if ((optidx = parse_ls_flags(argv, argc, lflag)) == -1)
1232 			return(-1);
1233 		/* Path is optional */
1234 		if (argc - optidx > 0)
1235 			*path1 = xstrdup(argv[optidx]);
1236 		break;
1237 	case I_LLS:
1238 		/* Skip ls command and following whitespace */
1239 		cp = cp + strlen(cmd) + strspn(cp, WHITESPACE);
1240 	case I_SHELL:
1241 		/* Uses the rest of the line */
1242 		break;
1243 	case I_LUMASK:
1244 	case I_CHMOD:
1245 		base = 8;
1246 	case I_CHOWN:
1247 	case I_CHGRP:
1248 		/* Get numeric arg (mandatory) */
1249 		if (argc - optidx < 1)
1250 			goto need_num_arg;
1251 		errno = 0;
1252 		l = strtol(argv[optidx], &cp2, base);
1253 		if (cp2 == argv[optidx] || *cp2 != '\0' ||
1254 		    ((l == LONG_MIN || l == LONG_MAX) && errno == ERANGE) ||
1255 		    l < 0) {
1256  need_num_arg:
1257 			error("You must supply a numeric argument "
1258 			    "to the %s command.", cmd);
1259 			return -1;
1260 		}
1261 		*n_arg = l;
1262 		if (cmdnum == I_LUMASK)
1263 			break;
1264 		/* Get pathname (mandatory) */
1265 		if (argc - optidx < 2) {
1266 			error("You must specify a path after a %s command.",
1267 			    cmd);
1268 			return -1;
1269 		}
1270 		*path1 = xstrdup(argv[optidx + 1]);
1271 		break;
1272 	case I_QUIT:
1273 	case I_PWD:
1274 	case I_LPWD:
1275 	case I_HELP:
1276 	case I_VERSION:
1277 	case I_PROGRESS:
1278 		break;
1279 	default:
1280 		fatal("Command not implemented");
1281 	}
1282 
1283 	*cpp = cp;
1284 	return(cmdnum);
1285 }
1286 
1287 static int
1288 parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
1289     int err_abort)
1290 {
1291 	char *path1, *path2, *tmp;
1292 	int pflag = 0, rflag = 0, lflag = 0, iflag = 0, hflag = 0, sflag = 0;
1293 	int cmdnum, i;
1294 	unsigned long n_arg = 0;
1295 	Attrib a, *aa;
1296 	char path_buf[MAXPATHLEN];
1297 	int err = 0;
1298 	glob_t g;
1299 
1300 	pflag = 0;	/* XXX gcc */
1301 	lflag = 0;	/* XXX gcc */
1302 	iflag = 0;	/* XXX gcc */
1303 	hflag = 0;	/* XXX gcc */
1304 	n_arg = 0;	/* XXX gcc */
1305 
1306 	path1 = path2 = NULL;
1307 	cmdnum = parse_args(&cmd, &pflag, &rflag, &lflag, &iflag, &hflag,
1308 	    &sflag, &n_arg, &path1, &path2);
1309 
1310 	if (iflag != 0)
1311 		err_abort = 0;
1312 
1313 	memset(&g, 0, sizeof(g));
1314 
1315 	/* Perform command */
1316 	switch (cmdnum) {
1317 	case 0:
1318 		/* Blank line */
1319 		break;
1320 	case -1:
1321 		/* Unrecognized command */
1322 		err = -1;
1323 		break;
1324 	case I_GET:
1325 		err = process_get(conn, path1, path2, *pwd, pflag, rflag);
1326 		break;
1327 	case I_PUT:
1328 		err = process_put(conn, path1, path2, *pwd, pflag, rflag);
1329 		break;
1330 	case I_RENAME:
1331 		path1 = make_absolute(path1, *pwd);
1332 		path2 = make_absolute(path2, *pwd);
1333 		err = do_rename(conn, path1, path2);
1334 		break;
1335 	case I_SYMLINK:
1336 		sflag = 1;
1337 	case I_LINK:
1338 		path1 = make_absolute(path1, *pwd);
1339 		path2 = make_absolute(path2, *pwd);
1340 		err = (sflag ? do_symlink : do_hardlink)(conn, path1, path2);
1341 		break;
1342 	case I_RM:
1343 		path1 = make_absolute(path1, *pwd);
1344 		remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g);
1345 		for (i = 0; g.gl_pathv[i] && !interrupted; i++) {
1346 			printf("Removing %s\n", g.gl_pathv[i]);
1347 			err = do_rm(conn, g.gl_pathv[i]);
1348 			if (err != 0 && err_abort)
1349 				break;
1350 		}
1351 		break;
1352 	case I_MKDIR:
1353 		path1 = make_absolute(path1, *pwd);
1354 		attrib_clear(&a);
1355 		a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS;
1356 		a.perm = 0777;
1357 		err = do_mkdir(conn, path1, &a, 1);
1358 		break;
1359 	case I_RMDIR:
1360 		path1 = make_absolute(path1, *pwd);
1361 		err = do_rmdir(conn, path1);
1362 		break;
1363 	case I_CHDIR:
1364 		path1 = make_absolute(path1, *pwd);
1365 		if ((tmp = do_realpath(conn, path1)) == NULL) {
1366 			err = 1;
1367 			break;
1368 		}
1369 		if ((aa = do_stat(conn, tmp, 0)) == NULL) {
1370 			xfree(tmp);
1371 			err = 1;
1372 			break;
1373 		}
1374 		if (!(aa->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)) {
1375 			error("Can't change directory: Can't check target");
1376 			xfree(tmp);
1377 			err = 1;
1378 			break;
1379 		}
1380 		if (!S_ISDIR(aa->perm)) {
1381 			error("Can't change directory: \"%s\" is not "
1382 			    "a directory", tmp);
1383 			xfree(tmp);
1384 			err = 1;
1385 			break;
1386 		}
1387 		xfree(*pwd);
1388 		*pwd = tmp;
1389 		break;
1390 	case I_LS:
1391 		if (!path1) {
1392 			do_ls_dir(conn, *pwd, *pwd, lflag);
1393 			break;
1394 		}
1395 
1396 		/* Strip pwd off beginning of non-absolute paths */
1397 		tmp = NULL;
1398 		if (*path1 != '/')
1399 			tmp = *pwd;
1400 
1401 		path1 = make_absolute(path1, *pwd);
1402 		err = do_globbed_ls(conn, path1, tmp, lflag);
1403 		break;
1404 	case I_DF:
1405 		/* Default to current directory if no path specified */
1406 		if (path1 == NULL)
1407 			path1 = xstrdup(*pwd);
1408 		path1 = make_absolute(path1, *pwd);
1409 		err = do_df(conn, path1, hflag, iflag);
1410 		break;
1411 	case I_LCHDIR:
1412 		if (chdir(path1) == -1) {
1413 			error("Couldn't change local directory to "
1414 			    "\"%s\": %s", path1, strerror(errno));
1415 			err = 1;
1416 		}
1417 		break;
1418 	case I_LMKDIR:
1419 		if (mkdir(path1, 0777) == -1) {
1420 			error("Couldn't create local directory "
1421 			    "\"%s\": %s", path1, strerror(errno));
1422 			err = 1;
1423 		}
1424 		break;
1425 	case I_LLS:
1426 		local_do_ls(cmd);
1427 		break;
1428 	case I_SHELL:
1429 		local_do_shell(cmd);
1430 		break;
1431 	case I_LUMASK:
1432 		umask(n_arg);
1433 		printf("Local umask: %03lo\n", n_arg);
1434 		break;
1435 	case I_CHMOD:
1436 		path1 = make_absolute(path1, *pwd);
1437 		attrib_clear(&a);
1438 		a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS;
1439 		a.perm = n_arg;
1440 		remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g);
1441 		for (i = 0; g.gl_pathv[i] && !interrupted; i++) {
1442 			printf("Changing mode on %s\n", g.gl_pathv[i]);
1443 			err = do_setstat(conn, g.gl_pathv[i], &a);
1444 			if (err != 0 && err_abort)
1445 				break;
1446 		}
1447 		break;
1448 	case I_CHOWN:
1449 	case I_CHGRP:
1450 		path1 = make_absolute(path1, *pwd);
1451 		remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g);
1452 		for (i = 0; g.gl_pathv[i] && !interrupted; i++) {
1453 			if (!(aa = do_stat(conn, g.gl_pathv[i], 0))) {
1454 				if (err_abort) {
1455 					err = -1;
1456 					break;
1457 				} else
1458 					continue;
1459 			}
1460 			if (!(aa->flags & SSH2_FILEXFER_ATTR_UIDGID)) {
1461 				error("Can't get current ownership of "
1462 				    "remote file \"%s\"", g.gl_pathv[i]);
1463 				if (err_abort) {
1464 					err = -1;
1465 					break;
1466 				} else
1467 					continue;
1468 			}
1469 			aa->flags &= SSH2_FILEXFER_ATTR_UIDGID;
1470 			if (cmdnum == I_CHOWN) {
1471 				printf("Changing owner on %s\n", g.gl_pathv[i]);
1472 				aa->uid = n_arg;
1473 			} else {
1474 				printf("Changing group on %s\n", g.gl_pathv[i]);
1475 				aa->gid = n_arg;
1476 			}
1477 			err = do_setstat(conn, g.gl_pathv[i], aa);
1478 			if (err != 0 && err_abort)
1479 				break;
1480 		}
1481 		break;
1482 	case I_PWD:
1483 		printf("Remote working directory: %s\n", *pwd);
1484 		break;
1485 	case I_LPWD:
1486 		if (!getcwd(path_buf, sizeof(path_buf))) {
1487 			error("Couldn't get local cwd: %s", strerror(errno));
1488 			err = -1;
1489 			break;
1490 		}
1491 		printf("Local working directory: %s\n", path_buf);
1492 		break;
1493 	case I_QUIT:
1494 		/* Processed below */
1495 		break;
1496 	case I_HELP:
1497 		help();
1498 		break;
1499 	case I_VERSION:
1500 		printf("SFTP protocol version %u\n", sftp_proto_version(conn));
1501 		break;
1502 	case I_PROGRESS:
1503 		showprogress = !showprogress;
1504 		if (showprogress)
1505 			printf("Progress meter enabled\n");
1506 		else
1507 			printf("Progress meter disabled\n");
1508 		break;
1509 	default:
1510 		fatal("%d is not implemented", cmdnum);
1511 	}
1512 
1513 	if (g.gl_pathc)
1514 		globfree(&g);
1515 	if (path1)
1516 		xfree(path1);
1517 	if (path2)
1518 		xfree(path2);
1519 
1520 	/* If an unignored error occurs in batch mode we should abort. */
1521 	if (err_abort && err != 0)
1522 		return (-1);
1523 	else if (cmdnum == I_QUIT)
1524 		return (1);
1525 
1526 	return (0);
1527 }
1528 
1529 static const char *
1530 prompt(EditLine *el)
1531 {
1532 	return ("sftp> ");
1533 }
1534 
1535 /* Display entries in 'list' after skipping the first 'len' chars */
1536 static void
1537 complete_display(char **list, u_int len)
1538 {
1539 	u_int y, m = 0, width = 80, columns = 1, colspace = 0, llen;
1540 	struct winsize ws;
1541 	const char *tmp;
1542 
1543 	/* Count entries for sort and find longest */
1544 	for (y = 0; list[y]; y++)
1545 		m = MAX(m, strlen(list[y]));
1546 
1547 	if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) != -1)
1548 		width = ws.ws_col;
1549 
1550 	m = m > len ? m - len : 0;
1551 	columns = width / (m + 2);
1552 	columns = MAX(columns, 1);
1553 	colspace = width / columns;
1554 	colspace = MIN(colspace, width);
1555 
1556 	printf("\n");
1557 	m = 1;
1558 	for (y = 0; list[y]; y++) {
1559 		llen = strlen(list[y]);
1560 		tmp = llen > len ? list[y] + len : "";
1561 		printf("%-*s", colspace, tmp);
1562 		if (m >= columns) {
1563 			printf("\n");
1564 			m = 1;
1565 		} else
1566 			m++;
1567 	}
1568 	printf("\n");
1569 }
1570 
1571 /*
1572  * Given a "list" of words that begin with a common prefix of "word",
1573  * attempt to find an autocompletion to extends "word" by the next
1574  * characters common to all entries in "list".
1575  */
1576 static char *
1577 complete_ambiguous(const char *word, char **list, size_t count)
1578 {
1579 	if (word == NULL)
1580 		return NULL;
1581 
1582 	if (count > 0) {
1583 		u_int y, matchlen = strlen(list[0]);
1584 
1585 		/* Find length of common stem */
1586 		for (y = 1; list[y]; y++) {
1587 			u_int x;
1588 
1589 			for (x = 0; x < matchlen; x++)
1590 				if (list[0][x] != list[y][x])
1591 					break;
1592 
1593 			matchlen = x;
1594 		}
1595 
1596 		if (matchlen > strlen(word)) {
1597 			char *tmp = xstrdup(list[0]);
1598 
1599 			tmp[matchlen] = '\0';
1600 			return tmp;
1601 		}
1602 	}
1603 
1604 	return xstrdup(word);
1605 }
1606 
1607 /* Autocomplete a sftp command */
1608 static int
1609 complete_cmd_parse(EditLine *el, char *cmd, int lastarg, char quote,
1610     int terminated)
1611 {
1612 	u_int y, count = 0, cmdlen, tmplen;
1613 	char *tmp, **list, argterm[3];
1614 	const LineInfo *lf;
1615 
1616 	list = xcalloc((sizeof(cmds) / sizeof(*cmds)) + 1, sizeof(char *));
1617 
1618 	/* No command specified: display all available commands */
1619 	if (cmd == NULL) {
1620 		for (y = 0; cmds[y].c; y++)
1621 			list[count++] = xstrdup(cmds[y].c);
1622 
1623 		list[count] = NULL;
1624 		complete_display(list, 0);
1625 
1626 		for (y = 0; list[y] != NULL; y++)
1627 			xfree(list[y]);
1628 		xfree(list);
1629 		return count;
1630 	}
1631 
1632 	/* Prepare subset of commands that start with "cmd" */
1633 	cmdlen = strlen(cmd);
1634 	for (y = 0; cmds[y].c; y++)  {
1635 		if (!strncasecmp(cmd, cmds[y].c, cmdlen))
1636 			list[count++] = xstrdup(cmds[y].c);
1637 	}
1638 	list[count] = NULL;
1639 
1640 	if (count == 0) {
1641 		xfree(list);
1642 		return 0;
1643 	}
1644 
1645 	/* Complete ambigious command */
1646 	tmp = complete_ambiguous(cmd, list, count);
1647 	if (count > 1)
1648 		complete_display(list, 0);
1649 
1650 	for (y = 0; list[y]; y++)
1651 		xfree(list[y]);
1652 	xfree(list);
1653 
1654 	if (tmp != NULL) {
1655 		tmplen = strlen(tmp);
1656 		cmdlen = strlen(cmd);
1657 		/* If cmd may be extended then do so */
1658 		if (tmplen > cmdlen)
1659 			if (el_insertstr(el, tmp + cmdlen) == -1)
1660 				fatal("el_insertstr failed.");
1661 		lf = el_line(el);
1662 		/* Terminate argument cleanly */
1663 		if (count == 1) {
1664 			y = 0;
1665 			if (!terminated)
1666 				argterm[y++] = quote;
1667 			if (lastarg || *(lf->cursor) != ' ')
1668 				argterm[y++] = ' ';
1669 			argterm[y] = '\0';
1670 			if (y > 0 && el_insertstr(el, argterm) == -1)
1671 				fatal("el_insertstr failed.");
1672 		}
1673 		xfree(tmp);
1674 	}
1675 
1676 	return count;
1677 }
1678 
1679 /*
1680  * Determine whether a particular sftp command's arguments (if any)
1681  * represent local or remote files.
1682  */
1683 static int
1684 complete_is_remote(char *cmd) {
1685 	int i;
1686 
1687 	if (cmd == NULL)
1688 		return -1;
1689 
1690 	for (i = 0; cmds[i].c; i++) {
1691 		if (!strncasecmp(cmd, cmds[i].c, strlen(cmds[i].c)))
1692 			return cmds[i].t;
1693 	}
1694 
1695 	return -1;
1696 }
1697 
1698 /* Autocomplete a filename "file" */
1699 static int
1700 complete_match(EditLine *el, struct sftp_conn *conn, char *remote_path,
1701     char *file, int remote, int lastarg, char quote, int terminated)
1702 {
1703 	glob_t g;
1704 	char *tmp, *tmp2, ins[3];
1705 	u_int i, hadglob, pwdlen, len, tmplen, filelen, cesc, isesc, isabs;
1706 	const LineInfo *lf;
1707 
1708 	/* Glob from "file" location */
1709 	if (file == NULL)
1710 		tmp = xstrdup("*");
1711 	else
1712 		xasprintf(&tmp, "%s*", file);
1713 
1714 	/* Check if the path is absolute. */
1715 	isabs = tmp[0] == '/';
1716 
1717 	memset(&g, 0, sizeof(g));
1718 	if (remote != LOCAL) {
1719 		tmp = make_absolute(tmp, remote_path);
1720 		remote_glob(conn, tmp, GLOB_DOOFFS|GLOB_MARK, NULL, &g);
1721 	} else
1722 		glob(tmp, GLOB_LIMIT|GLOB_DOOFFS|GLOB_MARK, NULL, &g);
1723 
1724 	/* Determine length of pwd so we can trim completion display */
1725 	for (hadglob = tmplen = pwdlen = 0; tmp[tmplen] != 0; tmplen++) {
1726 		/* Terminate counting on first unescaped glob metacharacter */
1727 		if (tmp[tmplen] == '*' || tmp[tmplen] == '?') {
1728 			if (tmp[tmplen] != '*' || tmp[tmplen + 1] != '\0')
1729 				hadglob = 1;
1730 			break;
1731 		}
1732 		if (tmp[tmplen] == '\\' && tmp[tmplen + 1] != '\0')
1733 			tmplen++;
1734 		if (tmp[tmplen] == '/')
1735 			pwdlen = tmplen + 1;	/* track last seen '/' */
1736 	}
1737 	xfree(tmp);
1738 
1739 	if (g.gl_matchc == 0)
1740 		goto out;
1741 
1742 	if (g.gl_matchc > 1)
1743 		complete_display(g.gl_pathv, pwdlen);
1744 
1745 	tmp = NULL;
1746 	/* Don't try to extend globs */
1747 	if (file == NULL || hadglob)
1748 		goto out;
1749 
1750 	tmp2 = complete_ambiguous(file, g.gl_pathv, g.gl_matchc);
1751 	tmp = path_strip(tmp2, isabs ? NULL : remote_path);
1752 	xfree(tmp2);
1753 
1754 	if (tmp == NULL)
1755 		goto out;
1756 
1757 	tmplen = strlen(tmp);
1758 	filelen = strlen(file);
1759 
1760 	/* Count the number of escaped characters in the input string. */
1761 	cesc = isesc = 0;
1762 	for (i = 0; i < filelen; i++) {
1763 		if (!isesc && file[i] == '\\' && i + 1 < filelen){
1764 			isesc = 1;
1765 			cesc++;
1766 		} else
1767 			isesc = 0;
1768 	}
1769 
1770 	if (tmplen > (filelen - cesc)) {
1771 		tmp2 = tmp + filelen - cesc;
1772 		len = strlen(tmp2);
1773 		/* quote argument on way out */
1774 		for (i = 0; i < len; i++) {
1775 			ins[0] = '\\';
1776 			ins[1] = tmp2[i];
1777 			ins[2] = '\0';
1778 			switch (tmp2[i]) {
1779 			case '\'':
1780 			case '"':
1781 			case '\\':
1782 			case '\t':
1783 			case '[':
1784 			case ' ':
1785 			case '#':
1786 			case '*':
1787 				if (quote == '\0' || tmp2[i] == quote) {
1788 					if (el_insertstr(el, ins) == -1)
1789 						fatal("el_insertstr "
1790 						    "failed.");
1791 					break;
1792 				}
1793 				/* FALLTHROUGH */
1794 			default:
1795 				if (el_insertstr(el, ins + 1) == -1)
1796 					fatal("el_insertstr failed.");
1797 				break;
1798 			}
1799 		}
1800 	}
1801 
1802 	lf = el_line(el);
1803 	if (g.gl_matchc == 1) {
1804 		i = 0;
1805 		if (!terminated)
1806 			ins[i++] = quote;
1807 		if (*(lf->cursor - 1) != '/' &&
1808 		    (lastarg || *(lf->cursor) != ' '))
1809 			ins[i++] = ' ';
1810 		ins[i] = '\0';
1811 		if (i > 0 && el_insertstr(el, ins) == -1)
1812 			fatal("el_insertstr failed.");
1813 	}
1814 	xfree(tmp);
1815 
1816  out:
1817 	globfree(&g);
1818 	return g.gl_matchc;
1819 }
1820 
1821 /* tab-completion hook function, called via libedit */
1822 static unsigned char
1823 complete(EditLine *el, int ch)
1824 {
1825 	char **argv, *line, quote;
1826 	u_int argc, carg, cursor, len, terminated, ret = CC_ERROR;
1827 	const LineInfo *lf;
1828 	struct complete_ctx *complete_ctx;
1829 
1830 	lf = el_line(el);
1831 	if (el_get(el, EL_CLIENTDATA, &complete_ctx) != 0)
1832 		fatal("%s: el_get failed", __func__);
1833 
1834 	/* Figure out which argument the cursor points to */
1835 	cursor = lf->cursor - lf->buffer;
1836 	line = (char *)xmalloc(cursor + 1);
1837 	memcpy(line, lf->buffer, cursor);
1838 	line[cursor] = '\0';
1839 	argv = makeargv(line, &carg, 1, &quote, &terminated);
1840 	xfree(line);
1841 
1842 	/* Get all the arguments on the line */
1843 	len = lf->lastchar - lf->buffer;
1844 	line = (char *)xmalloc(len + 1);
1845 	memcpy(line, lf->buffer, len);
1846 	line[len] = '\0';
1847 	argv = makeargv(line, &argc, 1, NULL, NULL);
1848 
1849 	/* Ensure cursor is at EOL or a argument boundary */
1850 	if (line[cursor] != ' ' && line[cursor] != '\0' &&
1851 	    line[cursor] != '\n') {
1852 		xfree(line);
1853 		return ret;
1854 	}
1855 
1856 	if (carg == 0) {
1857 		/* Show all available commands */
1858 		complete_cmd_parse(el, NULL, argc == carg, '\0', 1);
1859 		ret = CC_REDISPLAY;
1860 	} else if (carg == 1 && cursor > 0 && line[cursor - 1] != ' ')  {
1861 		/* Handle the command parsing */
1862 		if (complete_cmd_parse(el, argv[0], argc == carg,
1863 		    quote, terminated) != 0)
1864 			ret = CC_REDISPLAY;
1865 	} else if (carg >= 1) {
1866 		/* Handle file parsing */
1867 		int remote = complete_is_remote(argv[0]);
1868 		char *filematch = NULL;
1869 
1870 		if (carg > 1 && line[cursor-1] != ' ')
1871 			filematch = argv[carg - 1];
1872 
1873 		if (remote != 0 &&
1874 		    complete_match(el, complete_ctx->conn,
1875 		    *complete_ctx->remote_pathp, filematch,
1876 		    remote, carg == argc, quote, terminated) != 0)
1877 			ret = CC_REDISPLAY;
1878 	}
1879 
1880 	xfree(line);
1881 	return ret;
1882 }
1883 
1884 int
1885 interactive_loop(struct sftp_conn *conn, const char *file1, const char *file2)
1886 {
1887 	char *remote_path;
1888 	char *dir = NULL;
1889 	char cmd[2048];
1890 	int err, interactive;
1891 	EditLine *el = NULL;
1892 	History *hl = NULL;
1893 	HistEvent hev;
1894 	extern char *__progname;
1895 	struct complete_ctx complete_ctx;
1896 
1897 	if (!batchmode && isatty(STDIN_FILENO)) {
1898 		if ((el = el_init(__progname, stdin, stdout, stderr)) == NULL)
1899 			fatal("Couldn't initialise editline");
1900 		if ((hl = history_init()) == NULL)
1901 			fatal("Couldn't initialise editline history");
1902 		history(hl, &hev, H_SETSIZE, 100);
1903 		el_set(el, EL_HIST, history, hl);
1904 
1905 		el_set(el, EL_PROMPT, prompt);
1906 		el_set(el, EL_EDITOR, "emacs");
1907 		el_set(el, EL_TERMINAL, NULL);
1908 		el_set(el, EL_SIGNAL, 1);
1909 		el_source(el, NULL);
1910 
1911 		/* Tab Completion */
1912 		el_set(el, EL_ADDFN, "ftp-complete",
1913 		    "Context sensitive argument completion", complete);
1914 		complete_ctx.conn = conn;
1915 		complete_ctx.remote_pathp = &remote_path;
1916 		el_set(el, EL_CLIENTDATA, (void*)&complete_ctx);
1917 		el_set(el, EL_BIND, "^I", "ftp-complete", NULL);
1918 	}
1919 
1920 	remote_path = do_realpath(conn, ".");
1921 	if (remote_path == NULL)
1922 		fatal("Need cwd");
1923 
1924 	if (file1 != NULL) {
1925 		dir = xstrdup(file1);
1926 		dir = make_absolute(dir, remote_path);
1927 
1928 		if (remote_is_dir(conn, dir) && file2 == NULL) {
1929 			printf("Changing to: %s\n", dir);
1930 			snprintf(cmd, sizeof cmd, "cd \"%s\"", dir);
1931 			if (parse_dispatch_command(conn, cmd,
1932 			    &remote_path, 1) != 0) {
1933 				xfree(dir);
1934 				xfree(remote_path);
1935 				xfree(conn);
1936 				return (-1);
1937 			}
1938 		} else {
1939 			/* XXX this is wrong wrt quoting */
1940 			if (file2 == NULL)
1941 				snprintf(cmd, sizeof cmd, "get %s", dir);
1942 			else
1943 				snprintf(cmd, sizeof cmd, "get %s %s", dir,
1944 				    file2);
1945 
1946 			err = parse_dispatch_command(conn, cmd,
1947 			    &remote_path, 1);
1948 			xfree(dir);
1949 			xfree(remote_path);
1950 			xfree(conn);
1951 			return (err);
1952 		}
1953 		xfree(dir);
1954 	}
1955 
1956 	setlinebuf(stdout);
1957 	setlinebuf(infile);
1958 
1959 	interactive = !batchmode && isatty(STDIN_FILENO);
1960 	err = 0;
1961 	for (;;) {
1962 		char *cp;
1963 		const char *line;
1964 		int count = 0;
1965 
1966 		signal(SIGINT, SIG_IGN);
1967 
1968 		if (el == NULL) {
1969 			if (interactive)
1970 				printf("sftp> ");
1971 			if (fgets(cmd, sizeof(cmd), infile) == NULL) {
1972 				if (interactive)
1973 					printf("\n");
1974 				break;
1975 			}
1976 			if (!interactive) { /* Echo command */
1977 				printf("sftp> %s", cmd);
1978 				if (strlen(cmd) > 0 &&
1979 				    cmd[strlen(cmd) - 1] != '\n')
1980 					printf("\n");
1981 			}
1982 		} else {
1983 			if ((line = el_gets(el, &count)) == NULL ||
1984 			    count <= 0) {
1985 				printf("\n");
1986 				break;
1987 			}
1988 			history(hl, &hev, H_ENTER, line);
1989 			if (strlcpy(cmd, line, sizeof(cmd)) >= sizeof(cmd)) {
1990 				fprintf(stderr, "Error: input line too long\n");
1991 				continue;
1992 			}
1993 		}
1994 
1995 		cp = strrchr(cmd, '\n');
1996 		if (cp)
1997 			*cp = '\0';
1998 
1999 		/* Handle user interrupts gracefully during commands */
2000 		interrupted = 0;
2001 		signal(SIGINT, cmd_interrupt);
2002 
2003 		err = parse_dispatch_command(conn, cmd, &remote_path,
2004 		    batchmode);
2005 		if (err != 0)
2006 			break;
2007 	}
2008 	xfree(remote_path);
2009 	xfree(conn);
2010 
2011 	if (el != NULL)
2012 		el_end(el);
2013 
2014 	/* err == 1 signifies normal "quit" exit */
2015 	return (err >= 0 ? 0 : -1);
2016 }
2017 
2018 static void
2019 connect_to_server(const char *path, char **args, int *in, int *out)
2020 {
2021 	int c_in, c_out;
2022 
2023 	int inout[2];
2024 
2025 	if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) == -1)
2026 		fatal("socketpair: %s", strerror(errno));
2027 	*in = *out = inout[0];
2028 	c_in = c_out = inout[1];
2029 
2030 	if ((sshpid = fork()) == -1)
2031 		fatal("fork: %s", strerror(errno));
2032 	else if (sshpid == 0) {
2033 		if ((dup2(c_in, STDIN_FILENO) == -1) ||
2034 		    (dup2(c_out, STDOUT_FILENO) == -1)) {
2035 			fprintf(stderr, "dup2: %s\n", strerror(errno));
2036 			_exit(1);
2037 		}
2038 		close(*in);
2039 		close(*out);
2040 		close(c_in);
2041 		close(c_out);
2042 
2043 		/*
2044 		 * The underlying ssh is in the same process group, so we must
2045 		 * ignore SIGINT if we want to gracefully abort commands,
2046 		 * otherwise the signal will make it to the ssh process and
2047 		 * kill it too.  Contrawise, since sftp sends SIGTERMs to the
2048 		 * underlying ssh, it must *not* ignore that signal.
2049 		 */
2050 		signal(SIGINT, SIG_IGN);
2051 		signal(SIGTERM, SIG_DFL);
2052 		execvp(path, args);
2053 		fprintf(stderr, "exec: %s: %s\n", path, strerror(errno));
2054 		_exit(1);
2055 	}
2056 
2057 	signal(SIGTERM, killchild);
2058 	signal(SIGINT, killchild);
2059 	signal(SIGHUP, killchild);
2060 	close(c_in);
2061 	close(c_out);
2062 }
2063 
2064 __dead static void
2065 usage(void)
2066 {
2067 	extern char *__progname;
2068 
2069 	fprintf(stderr,
2070 	    "usage: %s [-1246Cpqrv] [-B buffer_size] [-b batchfile] [-c cipher]\n"
2071 	    "          [-D sftp_server_path] [-F ssh_config] "
2072 	    "[-i identity_file] [-l limit]\n"
2073 	    "          [-o ssh_option] [-P port] [-R num_requests] "
2074 	    "[-S program]\n"
2075 	    "          [-s subsystem | sftp_server] host\n"
2076 	    "       %s [user@]host[:file ...]\n"
2077 	    "       %s [user@]host[:dir[/]]\n"
2078 	    "       %s -b batchfile [user@]host\n",
2079 	    __progname, __progname, __progname, __progname);
2080 	exit(1);
2081 }
2082 
2083 int
2084 main(int argc, char **argv)
2085 {
2086 	int in, out, ch, err;
2087 	char *host = NULL, *userhost, *cp, *file2 = NULL;
2088 	int debug_level = 0, sshver = 2;
2089 	const char *file1 = NULL, *sftp_server = NULL;
2090 	const char *ssh_program = _PATH_SSH_PROGRAM, *sftp_direct = NULL;
2091 	const char *errstr;
2092 	LogLevel ll = SYSLOG_LEVEL_INFO;
2093 	arglist args;
2094 	extern int optind;
2095 	extern char *optarg;
2096 	struct sftp_conn *conn;
2097 	size_t copy_buffer_len = DEFAULT_COPY_BUFLEN;
2098 	size_t num_requests = DEFAULT_NUM_REQUESTS;
2099 	long long limit_kbps = 0;
2100 
2101 	/* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
2102 	sanitise_stdfd();
2103 
2104 	memset(&args, '\0', sizeof(args));
2105 	args.list = NULL;
2106 	addargs(&args, "%s", ssh_program);
2107 	addargs(&args, "-oForwardX11 no");
2108 	addargs(&args, "-oForwardAgent no");
2109 	addargs(&args, "-oPermitLocalCommand no");
2110 	addargs(&args, "-oClearAllForwardings yes");
2111 
2112 	ll = SYSLOG_LEVEL_INFO;
2113 	infile = stdin;
2114 
2115 	while ((ch = getopt(argc, argv,
2116 	    "1246hpqrvCc:D:i:l:o:s:S:b:B:F:P:R:")) != -1) {
2117 		switch (ch) {
2118 		/* Passed through to ssh(1) */
2119 		case '4':
2120 		case '6':
2121 		case 'C':
2122 			addargs(&args, "-%c", ch);
2123 			break;
2124 		/* Passed through to ssh(1) with argument */
2125 		case 'F':
2126 		case 'c':
2127 		case 'i':
2128 		case 'o':
2129 			addargs(&args, "-%c", ch);
2130 			addargs(&args, "%s", optarg);
2131 			break;
2132 		case 'q':
2133 			showprogress = 0;
2134 			addargs(&args, "-%c", ch);
2135 			break;
2136 		case 'P':
2137 			addargs(&args, "-oPort %s", optarg);
2138 			break;
2139 		case 'v':
2140 			if (debug_level < 3) {
2141 				addargs(&args, "-v");
2142 				ll = SYSLOG_LEVEL_DEBUG1 + debug_level;
2143 			}
2144 			debug_level++;
2145 			break;
2146 		case '1':
2147 			sshver = 1;
2148 			if (sftp_server == NULL)
2149 				sftp_server = _PATH_SFTP_SERVER;
2150 			break;
2151 		case '2':
2152 			sshver = 2;
2153 			break;
2154 		case 'B':
2155 			copy_buffer_len = strtol(optarg, &cp, 10);
2156 			if (copy_buffer_len == 0 || *cp != '\0')
2157 				fatal("Invalid buffer size \"%s\"", optarg);
2158 			break;
2159 		case 'b':
2160 			if (batchmode)
2161 				fatal("Batch file already specified.");
2162 
2163 			/* Allow "-" as stdin */
2164 			if (strcmp(optarg, "-") != 0 &&
2165 			    (infile = fopen(optarg, "r")) == NULL)
2166 				fatal("%s (%s).", strerror(errno), optarg);
2167 			showprogress = 0;
2168 			batchmode = 1;
2169 			addargs(&args, "-obatchmode yes");
2170 			break;
2171 		case 'p':
2172 			global_pflag = 1;
2173 			break;
2174 		case 'D':
2175 			sftp_direct = optarg;
2176 			break;
2177 		case 'l':
2178 			limit_kbps = strtonum(optarg, 1, 100 * 1024 * 1024,
2179 			    &errstr);
2180 			if (errstr != NULL)
2181 				usage();
2182 			limit_kbps *= 1024; /* kbps */
2183 			break;
2184 		case 'r':
2185 			global_rflag = 1;
2186 			break;
2187 		case 'R':
2188 			num_requests = strtol(optarg, &cp, 10);
2189 			if (num_requests == 0 || *cp != '\0')
2190 				fatal("Invalid number of requests \"%s\"",
2191 				    optarg);
2192 			break;
2193 		case 's':
2194 			sftp_server = optarg;
2195 			break;
2196 		case 'S':
2197 			ssh_program = optarg;
2198 			replacearg(&args, 0, "%s", ssh_program);
2199 			break;
2200 		case 'h':
2201 		default:
2202 			usage();
2203 		}
2204 	}
2205 
2206 	if (!isatty(STDERR_FILENO))
2207 		showprogress = 0;
2208 
2209 	log_init(argv[0], ll, SYSLOG_FACILITY_USER, 1);
2210 
2211 	if (sftp_direct == NULL) {
2212 		if (optind == argc || argc > (optind + 2))
2213 			usage();
2214 
2215 		userhost = xstrdup(argv[optind]);
2216 		file2 = argv[optind+1];
2217 
2218 		if ((host = strrchr(userhost, '@')) == NULL)
2219 			host = userhost;
2220 		else {
2221 			*host++ = '\0';
2222 			if (!userhost[0]) {
2223 				fprintf(stderr, "Missing username\n");
2224 				usage();
2225 			}
2226 			addargs(&args, "-l");
2227 			addargs(&args, "%s", userhost);
2228 		}
2229 
2230 		if ((cp = colon(host)) != NULL) {
2231 			*cp++ = '\0';
2232 			file1 = cp;
2233 		}
2234 
2235 		host = cleanhostname(host);
2236 		if (!*host) {
2237 			fprintf(stderr, "Missing hostname\n");
2238 			usage();
2239 		}
2240 
2241 		addargs(&args, "-oProtocol %d", sshver);
2242 
2243 		/* no subsystem if the server-spec contains a '/' */
2244 		if (sftp_server == NULL || strchr(sftp_server, '/') == NULL)
2245 			addargs(&args, "-s");
2246 
2247 		addargs(&args, "--");
2248 		addargs(&args, "%s", host);
2249 		addargs(&args, "%s", (sftp_server != NULL ?
2250 		    sftp_server : "sftp"));
2251 
2252 		connect_to_server(ssh_program, args.list, &in, &out);
2253 	} else {
2254 		args.list = NULL;
2255 		addargs(&args, "sftp-server");
2256 
2257 		connect_to_server(sftp_direct, args.list, &in, &out);
2258 	}
2259 	freeargs(&args);
2260 
2261 	conn = do_init(in, out, copy_buffer_len, num_requests, limit_kbps);
2262 	if (conn == NULL)
2263 		fatal("Couldn't initialise connection to server");
2264 
2265 	if (!batchmode) {
2266 		if (sftp_direct == NULL)
2267 			fprintf(stderr, "Connected to %s.\n", host);
2268 		else
2269 			fprintf(stderr, "Attached to %s.\n", sftp_direct);
2270 	}
2271 
2272 	err = interactive_loop(conn, file1, file2);
2273 
2274 	close(in);
2275 	close(out);
2276 	if (batchmode)
2277 		fclose(infile);
2278 
2279 	while (waitpid(sshpid, NULL, 0) == -1)
2280 		if (errno != EINTR)
2281 			fatal("Couldn't wait for ssh process: %s",
2282 			    strerror(errno));
2283 
2284 	exit(err == 0 ? 0 : 1);
2285 }
2286