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