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