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