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