11305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood/* $OpenBSD: sftp.c,v 1.132 2010/12/04 00:18:01 djm Exp $ */
21305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood/*
31305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
41305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood *
51305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * Permission to use, copy, modify, and distribute this software for any
61305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * purpose with or without fee is hereby granted, provided that the above
71305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * copyright notice and this permission notice appear in all copies.
81305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood *
91305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
101305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
111305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
121305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
131305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
141305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
151305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
161305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood */
171305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
181305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include "includes.h"
191305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
201305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include <sys/types.h>
211305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include <sys/ioctl.h>
221305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#ifdef HAVE_SYS_STAT_H
231305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood# include <sys/stat.h>
241305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#endif
251305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include <sys/param.h>
261305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include <sys/socket.h>
271305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include <sys/wait.h>
281305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#ifdef HAVE_SYS_STATVFS_H
291305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include <sys/statvfs.h>
301305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#endif
311305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
321305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include <ctype.h>
331305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include <errno.h>
341305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
351305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#ifdef HAVE_PATHS_H
361305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood# include <paths.h>
371305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#endif
381305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#ifdef HAVE_LIBGEN_H
391305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include <libgen.h>
401305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#endif
411305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#ifdef USE_LIBEDIT
421305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include <histedit.h>
431305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#else
441305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodtypedef void EditLine;
451305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#endif
461305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include <signal.h>
471305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include <stdlib.h>
481305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include <stdio.h>
491305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include <string.h>
501305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include <unistd.h>
511305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include <stdarg.h>
521305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
531305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#ifdef HAVE_UTIL_H
541305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood# include <util.h>
551305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#endif
561305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
571305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#ifdef HAVE_LIBUTIL_H
581305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood# include <libutil.h>
591305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#endif
601305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
611305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include "xmalloc.h"
621305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include "log.h"
631305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include "pathnames.h"
641305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include "misc.h"
651305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
661305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include "sftp.h"
671305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include "buffer.h"
681305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include "sftp-common.h"
691305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include "sftp-client.h"
701305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
711305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#define DEFAULT_COPY_BUFLEN	32768	/* Size of buffer for up/download */
721305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#define DEFAULT_NUM_REQUESTS	64	/* # concurrent outstanding requests */
731305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
741305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood/* File to read commands from */
751305e95ba6ff9fa202d0818caf10405df4b0f648Mike LockwoodFILE* infile;
761305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
771305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood/* Are we in batchfile mode? */
781305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodint batchmode = 0;
791305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
801305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood/* PID of ssh transport process */
811305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstatic pid_t sshpid = -1;
821305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
831305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood/* This is set to 0 if the progressmeter is not desired. */
841305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodint showprogress = 1;
851305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
861305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood/* When this option is set, we always recursively download/upload directories */
871305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodint global_rflag = 0;
881305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
891305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood/* When this option is set, the file transfers will always preserve times */
901305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodint global_pflag = 0;
911305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
921305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood/* SIGINT received during command processing */
931305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodvolatile sig_atomic_t interrupted = 0;
941305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
951305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood/* I wish qsort() took a separate ctx for the comparison function...*/
961305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodint sort_flag;
971305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
981305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood/* Context used for commandline completion */
991305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstruct complete_ctx {
1001305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	struct sftp_conn *conn;
1011305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	char **remote_pathp;
1021305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood};
1031305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
1041305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodint remote_glob(struct sftp_conn *, const char *, int,
1051305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood    int (*)(const char *, int), glob_t *); /* proto for sftp-glob.c */
1061305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
1071305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodextern char *__progname;
1081305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
1091305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood/* Separators for interactive commands */
1101305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#define WHITESPACE " \t\r\n"
1111305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
1121305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood/* ls flags */
1131305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#define LS_LONG_VIEW	0x0001	/* Full view ala ls -l */
1141305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#define LS_SHORT_VIEW	0x0002	/* Single row view ala ls -1 */
1151305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#define LS_NUMERIC_VIEW	0x0004	/* Long view with numeric uid/gid */
1161305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#define LS_NAME_SORT	0x0008	/* Sort by name (default) */
1171305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#define LS_TIME_SORT	0x0010	/* Sort by mtime */
1181305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#define LS_SIZE_SORT	0x0020	/* Sort by file size */
1191305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#define LS_REVERSE_SORT	0x0040	/* Reverse sort order */
1201305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#define LS_SHOW_ALL	0x0080	/* Don't skip filenames starting with '.' */
1211305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#define LS_SI_UNITS	0x0100	/* Display sizes as K, M, G, etc. */
1221305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
1231305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#define VIEW_FLAGS	(LS_LONG_VIEW|LS_SHORT_VIEW|LS_NUMERIC_VIEW|LS_SI_UNITS)
1241305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#define SORT_FLAGS	(LS_NAME_SORT|LS_TIME_SORT|LS_SIZE_SORT)
1251305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
1261305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood/* Commands for interactive mode */
1271305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#define I_CHDIR		1
1281305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#define I_CHGRP		2
1291305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#define I_CHMOD		3
1301305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#define I_CHOWN		4
1311305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#define I_DF		24
1321305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#define I_GET		5
1331305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#define I_HELP		6
1341305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#define I_LCHDIR	7
1351305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#define I_LINK		25
1361305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#define I_LLS		8
1371305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#define I_LMKDIR	9
1381305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#define I_LPWD		10
1391305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#define I_LS		11
1401305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#define I_LUMASK	12
1411305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#define I_MKDIR		13
1421305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#define I_PUT		14
1431305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#define I_PWD		15
1441305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#define I_QUIT		16
1451305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#define I_RENAME	17
1461305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#define I_RM		18
1471305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#define I_RMDIR		19
1481305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#define I_SHELL		20
1491305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#define I_SYMLINK	21
1501305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#define I_VERSION	22
1511305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#define I_PROGRESS	23
1521305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
1531305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstruct CMD {
1541305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	const char *c;
1551305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	const int n;
1561305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	const int t;
1571305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood};
1581305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
1591305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood/* Type of completion */
1601305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#define NOARGS	0
1611305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#define REMOTE	1
1621305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#define LOCAL	2
1631305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
1641305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstatic const struct CMD cmds[] = {
1651305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	{ "bye",	I_QUIT,		NOARGS	},
1661305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	{ "cd",		I_CHDIR,	REMOTE	},
1671305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	{ "chdir",	I_CHDIR,	REMOTE	},
1681305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	{ "chgrp",	I_CHGRP,	REMOTE	},
1691305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	{ "chmod",	I_CHMOD,	REMOTE	},
1701305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	{ "chown",	I_CHOWN,	REMOTE	},
1711305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	{ "df",		I_DF,		REMOTE	},
1721305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	{ "dir",	I_LS,		REMOTE	},
1731305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	{ "exit",	I_QUIT,		NOARGS	},
1741305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	{ "get",	I_GET,		REMOTE	},
1751305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	{ "help",	I_HELP,		NOARGS	},
1761305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	{ "lcd",	I_LCHDIR,	LOCAL	},
1771305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	{ "lchdir",	I_LCHDIR,	LOCAL	},
1781305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	{ "lls",	I_LLS,		LOCAL	},
1791305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	{ "lmkdir",	I_LMKDIR,	LOCAL	},
1801305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	{ "ln",		I_LINK,		REMOTE	},
1811305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	{ "lpwd",	I_LPWD,		LOCAL	},
1821305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	{ "ls",		I_LS,		REMOTE	},
1831305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	{ "lumask",	I_LUMASK,	NOARGS	},
1841305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	{ "mkdir",	I_MKDIR,	REMOTE	},
1851305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	{ "mget",	I_GET,		REMOTE	},
1861305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	{ "mput",	I_PUT,		LOCAL	},
1871305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	{ "progress",	I_PROGRESS,	NOARGS	},
1881305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	{ "put",	I_PUT,		LOCAL	},
1891305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	{ "pwd",	I_PWD,		REMOTE	},
1901305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	{ "quit",	I_QUIT,		NOARGS	},
1911305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	{ "rename",	I_RENAME,	REMOTE	},
1921305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	{ "rm",		I_RM,		REMOTE	},
1931305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	{ "rmdir",	I_RMDIR,	REMOTE	},
1941305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	{ "symlink",	I_SYMLINK,	REMOTE	},
1951305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	{ "version",	I_VERSION,	NOARGS	},
1961305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	{ "!",		I_SHELL,	NOARGS	},
1971305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	{ "?",		I_HELP,		NOARGS	},
1981305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	{ NULL,		-1,		-1	}
1991305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood};
2001305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
2011305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodint interactive_loop(struct sftp_conn *, char *file1, char *file2);
2021305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
2031305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood/* ARGSUSED */
2041305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstatic void
2051305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodkillchild(int signo)
2061305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{
2071305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (sshpid > 1) {
2081305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		kill(sshpid, SIGTERM);
2091305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		waitpid(sshpid, NULL, 0);
2101305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	}
2111305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
2121305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	_exit(1);
2131305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood}
2141305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
2151305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood/* ARGSUSED */
2161305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstatic void
2171305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodcmd_interrupt(int signo)
2181305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{
2191305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	const char msg[] = "\rInterrupt  \n";
2201305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	int olderrno = errno;
2211305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
2221305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	write(STDERR_FILENO, msg, sizeof(msg) - 1);
2231305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	interrupted = 1;
2241305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	errno = olderrno;
2251305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood}
2261305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
2271305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstatic void
2281305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodhelp(void)
2291305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{
2301305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	printf("Available commands:\n"
2311305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	    "bye                                Quit sftp\n"
2321305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	    "cd path                            Change remote directory to 'path'\n"
2331305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	    "chgrp grp path                     Change group of file 'path' to 'grp'\n"
2341305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	    "chmod mode path                    Change permissions of file 'path' to 'mode'\n"
2351305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	    "chown own path                     Change owner of file 'path' to 'own'\n"
2361305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	    "df [-hi] [path]                    Display statistics for current directory or\n"
2371305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	    "                                   filesystem containing 'path'\n"
2381305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	    "exit                               Quit sftp\n"
2391305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	    "get [-Ppr] remote [local]          Download file\n"
2401305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	    "help                               Display this help text\n"
2411305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	    "lcd path                           Change local directory to 'path'\n"
2421305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	    "lls [ls-options [path]]            Display local directory listing\n"
2431305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	    "lmkdir path                        Create local directory\n"
2441305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	    "ln [-s] oldpath newpath            Link remote file (-s for symlink)\n"
2451305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	    "lpwd                               Print local working directory\n"
2461305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	    "ls [-1afhlnrSt] [path]             Display remote directory listing\n"
2471305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	    "lumask umask                       Set local umask to 'umask'\n"
2481305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	    "mkdir path                         Create remote directory\n"
2491305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	    "progress                           Toggle display of progress meter\n"
2501305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	    "put [-Ppr] local [remote]          Upload file\n"
2511305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	    "pwd                                Display remote working directory\n"
2521305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	    "quit                               Quit sftp\n"
2531305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	    "rename oldpath newpath             Rename remote file\n"
2541305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	    "rm path                            Delete remote file\n"
2551305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	    "rmdir path                         Remove remote directory\n"
2561305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	    "symlink oldpath newpath            Symlink remote file\n"
2571305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	    "version                            Show SFTP version\n"
2581305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	    "!command                           Execute 'command' in local shell\n"
2591305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	    "!                                  Escape to local shell\n"
2601305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	    "?                                  Synonym for help\n");
2611305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood}
2621305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
2631305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstatic void
2641305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodlocal_do_shell(const char *args)
2651305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{
2661305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	int status;
2671305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	char *shell;
2681305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	pid_t pid;
2691305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
2701305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (!*args)
2711305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		args = NULL;
2721305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
2731305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if ((shell = getenv("SHELL")) == NULL || *shell == '\0')
2741305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		shell = _PATH_BSHELL;
2751305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
2761305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if ((pid = fork()) == -1)
2771305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		fatal("Couldn't fork: %s", strerror(errno));
2781305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
2791305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (pid == 0) {
2801305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		/* XXX: child has pipe fds to ssh subproc open - issue? */
2811305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if (args) {
2821305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			debug3("Executing %s -c \"%s\"", shell, args);
2831305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			execl(shell, shell, "-c", args, (char *)NULL);
2841305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		} else {
2851305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			debug3("Executing %s", shell);
2861305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			execl(shell, shell, (char *)NULL);
2871305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		}
2881305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		fprintf(stderr, "Couldn't execute \"%s\": %s\n", shell,
2891305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		    strerror(errno));
2901305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		_exit(1);
2911305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	}
2921305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	while (waitpid(pid, &status, 0) == -1)
2931305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if (errno != EINTR)
2941305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			fatal("Couldn't wait for child: %s", strerror(errno));
2951305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (!WIFEXITED(status))
2961305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		error("Shell exited abnormally");
2971305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	else if (WEXITSTATUS(status))
2981305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		error("Shell exited with status %d", WEXITSTATUS(status));
2991305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood}
3001305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
3011305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstatic void
3021305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodlocal_do_ls(const char *args)
3031305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{
3041305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (!args || !*args)
3051305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		local_do_shell(_PATH_LS);
3061305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	else {
3071305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		int len = strlen(_PATH_LS " ") + strlen(args) + 1;
3081305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		char *buf = xmalloc(len);
3091305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
3101305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		/* XXX: quoting - rip quoting code from ftp? */
3111305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		snprintf(buf, len, _PATH_LS " %s", args);
3121305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		local_do_shell(buf);
3131305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		xfree(buf);
3141305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	}
3151305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood}
3161305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
3171305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood/* Strip one path (usually the pwd) from the start of another */
3181305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstatic char *
3191305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodpath_strip(char *path, char *strip)
3201305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{
3211305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	size_t len;
3221305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
3231305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (strip == NULL)
3241305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		return (xstrdup(path));
3251305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
3261305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	len = strlen(strip);
3271305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (strncmp(path, strip, len) == 0) {
3281305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if (strip[len - 1] != '/' && path[len] == '/')
3291305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			len++;
3301305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		return (xstrdup(path + len));
3311305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	}
3321305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
3331305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	return (xstrdup(path));
3341305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood}
3351305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
3361305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstatic char *
3371305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodmake_absolute(char *p, char *pwd)
3381305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{
3391305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	char *abs_str;
3401305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
3411305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	/* Derelativise */
3421305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (p && p[0] != '/') {
3431305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		abs_str = path_append(pwd, p);
3441305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		xfree(p);
3451305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		return(abs_str);
3461305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	} else
3471305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		return(p);
3481305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood}
3491305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
3501305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstatic int
3511305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodparse_getput_flags(const char *cmd, char **argv, int argc, int *pflag,
3521305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood    int *rflag)
3531305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{
3541305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	extern int opterr, optind, optopt, optreset;
3551305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	int ch;
3561305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
3571305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	optind = optreset = 1;
3581305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	opterr = 0;
3591305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
3601305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	*rflag = *pflag = 0;
3611305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	while ((ch = getopt(argc, argv, "PpRr")) != -1) {
3621305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		switch (ch) {
3631305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		case 'p':
3641305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		case 'P':
3651305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			*pflag = 1;
3661305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			break;
3671305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		case 'r':
3681305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		case 'R':
3691305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			*rflag = 1;
3701305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			break;
3711305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		default:
3721305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			error("%s: Invalid flag -%c", cmd, optopt);
3731305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			return -1;
3741305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		}
3751305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	}
3761305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
3771305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	return optind;
3781305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood}
3791305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
3801305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstatic int
3811305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodparse_link_flags(const char *cmd, char **argv, int argc, int *sflag)
3821305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{
3831305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	extern int opterr, optind, optopt, optreset;
3841305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	int ch;
3851305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
3861305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	optind = optreset = 1;
3871305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	opterr = 0;
3881305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
3891305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	*sflag = 0;
3901305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	while ((ch = getopt(argc, argv, "s")) != -1) {
3911305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		switch (ch) {
3921305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		case 's':
3931305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			*sflag = 1;
3941305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			break;
3951305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		default:
3961305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			error("%s: Invalid flag -%c", cmd, optopt);
3971305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			return -1;
3981305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		}
3991305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	}
4001305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
4011305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	return optind;
4021305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood}
4031305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
4041305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstatic int
4051305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodparse_ls_flags(char **argv, int argc, int *lflag)
4061305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{
4071305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	extern int opterr, optind, optopt, optreset;
4081305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	int ch;
4091305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
4101305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	optind = optreset = 1;
4111305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	opterr = 0;
4121305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
4131305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	*lflag = LS_NAME_SORT;
4141305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	while ((ch = getopt(argc, argv, "1Safhlnrt")) != -1) {
4151305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		switch (ch) {
4161305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		case '1':
4171305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			*lflag &= ~VIEW_FLAGS;
4181305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			*lflag |= LS_SHORT_VIEW;
4191305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			break;
4201305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		case 'S':
4211305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			*lflag &= ~SORT_FLAGS;
4221305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			*lflag |= LS_SIZE_SORT;
4231305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			break;
4241305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		case 'a':
4251305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			*lflag |= LS_SHOW_ALL;
4261305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			break;
4271305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		case 'f':
4281305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			*lflag &= ~SORT_FLAGS;
4291305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			break;
4301305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		case 'h':
4311305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			*lflag |= LS_SI_UNITS;
4321305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			break;
4331305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		case 'l':
4341305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			*lflag &= ~LS_SHORT_VIEW;
4351305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			*lflag |= LS_LONG_VIEW;
4361305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			break;
4371305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		case 'n':
4381305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			*lflag &= ~LS_SHORT_VIEW;
4391305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			*lflag |= LS_NUMERIC_VIEW|LS_LONG_VIEW;
4401305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			break;
4411305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		case 'r':
4421305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			*lflag |= LS_REVERSE_SORT;
4431305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			break;
4441305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		case 't':
4451305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			*lflag &= ~SORT_FLAGS;
4461305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			*lflag |= LS_TIME_SORT;
4471305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			break;
4481305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		default:
4491305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			error("ls: Invalid flag -%c", optopt);
4501305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			return -1;
4511305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		}
4521305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	}
4531305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
4541305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	return optind;
4551305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood}
4561305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
4571305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstatic int
4581305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodparse_df_flags(const char *cmd, char **argv, int argc, int *hflag, int *iflag)
4591305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{
4601305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	extern int opterr, optind, optopt, optreset;
4611305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	int ch;
4621305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
4631305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	optind = optreset = 1;
4641305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	opterr = 0;
4651305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
4661305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	*hflag = *iflag = 0;
4671305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	while ((ch = getopt(argc, argv, "hi")) != -1) {
4681305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		switch (ch) {
4691305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		case 'h':
4701305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			*hflag = 1;
4711305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			break;
4721305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		case 'i':
4731305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			*iflag = 1;
4741305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			break;
4751305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		default:
4761305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			error("%s: Invalid flag -%c", cmd, optopt);
4771305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			return -1;
4781305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		}
4791305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	}
4801305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
4811305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	return optind;
4821305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood}
4831305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
4841305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstatic int
4851305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodis_dir(char *path)
4861305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{
4871305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	struct stat sb;
4881305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
4891305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	/* XXX: report errors? */
4901305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (stat(path, &sb) == -1)
4911305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		return(0);
4921305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
4931305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	return(S_ISDIR(sb.st_mode));
4941305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood}
4951305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
4961305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstatic int
4971305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodremote_is_dir(struct sftp_conn *conn, char *path)
4981305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{
4991305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	Attrib *a;
5001305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
5011305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	/* XXX: report errors? */
5021305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if ((a = do_stat(conn, path, 1)) == NULL)
5031305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		return(0);
5041305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (!(a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS))
5051305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		return(0);
5061305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	return(S_ISDIR(a->perm));
5071305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood}
5081305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
5091305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood/* Check whether path returned from glob(..., GLOB_MARK, ...) is a directory */
5101305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstatic int
5111305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodpathname_is_dir(char *pathname)
5121305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{
5131305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	size_t l = strlen(pathname);
5141305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
5151305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	return l > 0 && pathname[l - 1] == '/';
5161305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood}
5171305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
5181305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstatic int
5191305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodprocess_get(struct sftp_conn *conn, char *src, char *dst, char *pwd,
5201305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood    int pflag, int rflag)
5211305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{
5221305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	char *abs_src = NULL;
5231305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	char *abs_dst = NULL;
5241305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	glob_t g;
5251305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	char *filename, *tmp=NULL;
5261305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	int i, err = 0;
5271305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
5281305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	abs_src = xstrdup(src);
5291305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	abs_src = make_absolute(abs_src, pwd);
5301305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	memset(&g, 0, sizeof(g));
5311305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
5321305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	debug3("Looking up %s", abs_src);
5331305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (remote_glob(conn, abs_src, GLOB_MARK, NULL, &g)) {
5341305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		error("File \"%s\" not found.", abs_src);
5351305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		err = -1;
5361305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		goto out;
5371305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	}
5381305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
5391305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	/*
5401305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	 * If multiple matches then dst must be a directory or
5411305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	 * unspecified.
5421305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	 */
5431305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (g.gl_matchc > 1 && dst != NULL && !is_dir(dst)) {
5441305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		error("Multiple source paths, but destination "
5451305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		    "\"%s\" is not a directory", dst);
5461305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		err = -1;
5471305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		goto out;
5481305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	}
5491305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
5501305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	for (i = 0; g.gl_pathv[i] && !interrupted; i++) {
5511305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		tmp = xstrdup(g.gl_pathv[i]);
5521305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if ((filename = basename(tmp)) == NULL) {
5531305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			error("basename %s: %s", tmp, strerror(errno));
5541305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			xfree(tmp);
5551305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			err = -1;
5561305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			goto out;
5571305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		}
5581305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
5591305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if (g.gl_matchc == 1 && dst) {
5601305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			if (is_dir(dst)) {
5611305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				abs_dst = path_append(dst, filename);
5621305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			} else {
5631305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				abs_dst = xstrdup(dst);
5641305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			}
5651305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		} else if (dst) {
5661305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			abs_dst = path_append(dst, filename);
5671305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		} else {
5681305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			abs_dst = xstrdup(filename);
5691305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		}
5701305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		xfree(tmp);
5711305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
5721305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		printf("Fetching %s to %s\n", g.gl_pathv[i], abs_dst);
5731305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if (pathname_is_dir(g.gl_pathv[i]) && (rflag || global_rflag)) {
5741305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			if (download_dir(conn, g.gl_pathv[i], abs_dst, NULL,
5751305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			    pflag || global_pflag, 1) == -1)
5761305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				err = -1;
5771305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		} else {
5781305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			if (do_download(conn, g.gl_pathv[i], abs_dst, NULL,
5791305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			    pflag || global_pflag) == -1)
5801305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				err = -1;
5811305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		}
5821305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		xfree(abs_dst);
5831305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		abs_dst = NULL;
5841305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	}
5851305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
5861305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodout:
5871305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	xfree(abs_src);
5881305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	globfree(&g);
5891305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	return(err);
5901305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood}
5911305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
5921305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstatic int
5931305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodprocess_put(struct sftp_conn *conn, char *src, char *dst, char *pwd,
5941305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood    int pflag, int rflag)
5951305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{
5961305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	char *tmp_dst = NULL;
5971305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	char *abs_dst = NULL;
5981305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	char *tmp = NULL, *filename = NULL;
5991305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	glob_t g;
6001305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	int err = 0;
6011305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	int i, dst_is_dir = 1;
6021305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	struct stat sb;
6031305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
6041305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (dst) {
6051305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		tmp_dst = xstrdup(dst);
6061305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		tmp_dst = make_absolute(tmp_dst, pwd);
6071305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	}
6081305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
6091305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	memset(&g, 0, sizeof(g));
6101305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	debug3("Looking up %s", src);
6111305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (glob(src, GLOB_NOCHECK | GLOB_MARK, NULL, &g)) {
6121305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		error("File \"%s\" not found.", src);
6131305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		err = -1;
6141305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		goto out;
6151305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	}
6161305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
6171305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	/* If we aren't fetching to pwd then stash this status for later */
6181305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (tmp_dst != NULL)
6191305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		dst_is_dir = remote_is_dir(conn, tmp_dst);
6201305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
6211305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	/* If multiple matches, dst may be directory or unspecified */
6221305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (g.gl_matchc > 1 && tmp_dst && !dst_is_dir) {
6231305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		error("Multiple paths match, but destination "
6241305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		    "\"%s\" is not a directory", tmp_dst);
6251305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		err = -1;
6261305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		goto out;
6271305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	}
6281305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
6291305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	for (i = 0; g.gl_pathv[i] && !interrupted; i++) {
6301305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if (stat(g.gl_pathv[i], &sb) == -1) {
6311305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			err = -1;
6321305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			error("stat %s: %s", g.gl_pathv[i], strerror(errno));
6331305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			continue;
6341305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		}
6351305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
6361305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		tmp = xstrdup(g.gl_pathv[i]);
6371305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if ((filename = basename(tmp)) == NULL) {
6381305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			error("basename %s: %s", tmp, strerror(errno));
6391305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			xfree(tmp);
6401305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			err = -1;
6411305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			goto out;
6421305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		}
6431305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
6441305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if (g.gl_matchc == 1 && tmp_dst) {
6451305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			/* If directory specified, append filename */
6461305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			if (dst_is_dir)
6471305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				abs_dst = path_append(tmp_dst, filename);
6481305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			else
6491305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				abs_dst = xstrdup(tmp_dst);
6501305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		} else if (tmp_dst) {
6511305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			abs_dst = path_append(tmp_dst, filename);
6521305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		} else {
6531305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			abs_dst = make_absolute(xstrdup(filename), pwd);
6541305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		}
6551305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		xfree(tmp);
6561305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
6571305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		printf("Uploading %s to %s\n", g.gl_pathv[i], abs_dst);
6581305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if (pathname_is_dir(g.gl_pathv[i]) && (rflag || global_rflag)) {
6591305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			if (upload_dir(conn, g.gl_pathv[i], abs_dst,
6601305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			    pflag || global_pflag, 1) == -1)
6611305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				err = -1;
6621305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		} else {
6631305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			if (do_upload(conn, g.gl_pathv[i], abs_dst,
6641305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			    pflag || global_pflag) == -1)
6651305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				err = -1;
6661305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		}
6671305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	}
6681305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
6691305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodout:
6701305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (abs_dst)
6711305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		xfree(abs_dst);
6721305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (tmp_dst)
6731305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		xfree(tmp_dst);
6741305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	globfree(&g);
6751305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	return(err);
6761305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood}
6771305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
6781305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstatic int
6791305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodsdirent_comp(const void *aa, const void *bb)
6801305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{
6811305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	SFTP_DIRENT *a = *(SFTP_DIRENT **)aa;
6821305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	SFTP_DIRENT *b = *(SFTP_DIRENT **)bb;
6831305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	int rmul = sort_flag & LS_REVERSE_SORT ? -1 : 1;
6841305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
6851305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#define NCMP(a,b) (a == b ? 0 : (a < b ? 1 : -1))
6861305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (sort_flag & LS_NAME_SORT)
6871305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		return (rmul * strcmp(a->filename, b->filename));
6881305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	else if (sort_flag & LS_TIME_SORT)
6891305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		return (rmul * NCMP(a->a.mtime, b->a.mtime));
6901305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	else if (sort_flag & LS_SIZE_SORT)
6911305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		return (rmul * NCMP(a->a.size, b->a.size));
6921305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
6931305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	fatal("Unknown ls sort type");
6941305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood}
6951305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
6961305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood/* sftp ls.1 replacement for directories */
6971305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstatic int
6981305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwooddo_ls_dir(struct sftp_conn *conn, char *path, char *strip_path, int lflag)
6991305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{
7001305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	int n;
7011305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	u_int c = 1, colspace = 0, columns = 1;
7021305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	SFTP_DIRENT **d;
7031305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
7041305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if ((n = do_readdir(conn, path, &d)) != 0)
7051305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		return (n);
7061305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
7071305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (!(lflag & LS_SHORT_VIEW)) {
7081305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		u_int m = 0, width = 80;
7091305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		struct winsize ws;
7101305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		char *tmp;
7111305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
7121305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		/* Count entries for sort and find longest filename */
7131305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		for (n = 0; d[n] != NULL; n++) {
7141305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			if (d[n]->filename[0] != '.' || (lflag & LS_SHOW_ALL))
7151305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				m = MAX(m, strlen(d[n]->filename));
7161305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		}
7171305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
7181305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		/* Add any subpath that also needs to be counted */
7191305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		tmp = path_strip(path, strip_path);
7201305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		m += strlen(tmp);
7211305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		xfree(tmp);
7221305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
7231305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) != -1)
7241305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			width = ws.ws_col;
7251305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
7261305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		columns = width / (m + 2);
7271305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		columns = MAX(columns, 1);
7281305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		colspace = width / columns;
7291305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		colspace = MIN(colspace, width);
7301305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	}
7311305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
7321305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (lflag & SORT_FLAGS) {
7331305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		for (n = 0; d[n] != NULL; n++)
7341305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			;	/* count entries */
7351305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		sort_flag = lflag & (SORT_FLAGS|LS_REVERSE_SORT);
7361305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		qsort(d, n, sizeof(*d), sdirent_comp);
7371305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	}
7381305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
7391305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	for (n = 0; d[n] != NULL && !interrupted; n++) {
7401305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		char *tmp, *fname;
7411305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
7421305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if (d[n]->filename[0] == '.' && !(lflag & LS_SHOW_ALL))
7431305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			continue;
7441305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
7451305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		tmp = path_append(path, d[n]->filename);
7461305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		fname = path_strip(tmp, strip_path);
7471305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		xfree(tmp);
7481305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
7491305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if (lflag & LS_LONG_VIEW) {
7501305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			if (lflag & (LS_NUMERIC_VIEW|LS_SI_UNITS)) {
7511305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				char *lname;
7521305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				struct stat sb;
7531305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
7541305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				memset(&sb, 0, sizeof(sb));
7551305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				attrib_to_stat(&d[n]->a, &sb);
7561305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				lname = ls_file(fname, &sb, 1,
7571305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				    (lflag & LS_SI_UNITS));
7581305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				printf("%s\n", lname);
7591305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				xfree(lname);
7601305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			} else
7611305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				printf("%s\n", d[n]->longname);
7621305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		} else {
7631305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			printf("%-*s", colspace, fname);
7641305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			if (c >= columns) {
7651305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				printf("\n");
7661305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				c = 1;
7671305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			} else
7681305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				c++;
7691305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		}
7701305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
7711305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		xfree(fname);
7721305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	}
7731305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
7741305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (!(lflag & LS_LONG_VIEW) && (c != 1))
7751305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		printf("\n");
7761305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
7771305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	free_sftp_dirents(d);
7781305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	return (0);
7791305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood}
7801305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
7811305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood/* sftp ls.1 replacement which handles path globs */
7821305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstatic int
7831305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwooddo_globbed_ls(struct sftp_conn *conn, char *path, char *strip_path,
7841305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood    int lflag)
7851305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{
7861305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	Attrib *a = NULL;
7871305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	char *fname, *lname;
7881305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	glob_t g;
7891305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	int err;
7901305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	struct winsize ws;
7911305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	u_int i, c = 1, colspace = 0, columns = 1, m = 0, width = 80;
7921305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
7931305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	memset(&g, 0, sizeof(g));
7941305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
7951305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (remote_glob(conn, path,
7961305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	    GLOB_MARK|GLOB_NOCHECK|GLOB_BRACE|GLOB_KEEPSTAT, NULL, &g) ||
7971305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	    (g.gl_pathc && !g.gl_matchc)) {
7981305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if (g.gl_pathc)
7991305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			globfree(&g);
8001305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		error("Can't ls: \"%s\" not found", path);
8011305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		return -1;
8021305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	}
8031305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
8041305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (interrupted)
8051305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		goto out;
8061305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
8071305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	/*
8081305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	 * If the glob returns a single match and it is a directory,
8091305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	 * then just list its contents.
8101305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	 */
8111305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (g.gl_matchc == 1 && g.gl_statv[0] != NULL &&
8121305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	    S_ISDIR(g.gl_statv[0]->st_mode)) {
8131305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		err = do_ls_dir(conn, g.gl_pathv[0], strip_path, lflag);
8141305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		globfree(&g);
8151305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		return err;
8161305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	}
8171305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
8181305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) != -1)
8191305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		width = ws.ws_col;
8201305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
8211305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (!(lflag & LS_SHORT_VIEW)) {
8221305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		/* Count entries for sort and find longest filename */
8231305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		for (i = 0; g.gl_pathv[i]; i++)
8241305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			m = MAX(m, strlen(g.gl_pathv[i]));
8251305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
8261305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		columns = width / (m + 2);
8271305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		columns = MAX(columns, 1);
8281305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		colspace = width / columns;
8291305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	}
8301305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
8311305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	for (i = 0; g.gl_pathv[i] && !interrupted; i++, a = NULL) {
8321305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		fname = path_strip(g.gl_pathv[i], strip_path);
8331305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if (lflag & LS_LONG_VIEW) {
8341305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			if (g.gl_statv[i] == NULL) {
8351305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				error("no stat information for %s", fname);
8361305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				continue;
8371305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			}
8381305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			lname = ls_file(fname, g.gl_statv[i], 1,
8391305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			    (lflag & LS_SI_UNITS));
8401305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			printf("%s\n", lname);
8411305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			xfree(lname);
8421305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		} else {
8431305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			printf("%-*s", colspace, fname);
8441305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			if (c >= columns) {
8451305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				printf("\n");
8461305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				c = 1;
8471305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			} else
8481305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				c++;
8491305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		}
8501305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		xfree(fname);
8511305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	}
8521305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
8531305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (!(lflag & LS_LONG_VIEW) && (c != 1))
8541305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		printf("\n");
8551305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
8561305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood out:
8571305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (g.gl_pathc)
8581305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		globfree(&g);
8591305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
8601305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	return 0;
8611305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood}
8621305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
8631305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstatic int
8641305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwooddo_df(struct sftp_conn *conn, char *path, int hflag, int iflag)
8651305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{
8661305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	struct sftp_statvfs st;
8671305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	char s_used[FMT_SCALED_STRSIZE];
8681305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	char s_avail[FMT_SCALED_STRSIZE];
8691305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	char s_root[FMT_SCALED_STRSIZE];
8701305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	char s_total[FMT_SCALED_STRSIZE];
8711305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	unsigned long long ffree;
8721305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
8731305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (do_statvfs(conn, path, &st, 1) == -1)
8741305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		return -1;
8751305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (iflag) {
8761305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		ffree = st.f_files ? (100 * (st.f_files - st.f_ffree) / st.f_files) : 0;
8771305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		printf("     Inodes        Used       Avail      "
8781305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		    "(root)    %%Capacity\n");
8791305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		printf("%11llu %11llu %11llu %11llu         %3llu%%\n",
8801305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		    (unsigned long long)st.f_files,
8811305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		    (unsigned long long)(st.f_files - st.f_ffree),
8821305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		    (unsigned long long)st.f_favail,
8831305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		    (unsigned long long)st.f_ffree, ffree);
8841305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	} else if (hflag) {
8851305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		strlcpy(s_used, "error", sizeof(s_used));
8861305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		strlcpy(s_avail, "error", sizeof(s_avail));
8871305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		strlcpy(s_root, "error", sizeof(s_root));
8881305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		strlcpy(s_total, "error", sizeof(s_total));
8891305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		fmt_scaled((st.f_blocks - st.f_bfree) * st.f_frsize, s_used);
8901305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		fmt_scaled(st.f_bavail * st.f_frsize, s_avail);
8911305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		fmt_scaled(st.f_bfree * st.f_frsize, s_root);
8921305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		fmt_scaled(st.f_blocks * st.f_frsize, s_total);
8931305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		printf("    Size     Used    Avail   (root)    %%Capacity\n");
8941305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		printf("%7sB %7sB %7sB %7sB         %3llu%%\n",
8951305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		    s_total, s_used, s_avail, s_root,
8961305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		    (unsigned long long)(100 * (st.f_blocks - st.f_bfree) /
8971305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		    st.f_blocks));
8981305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	} else {
8991305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		printf("        Size         Used        Avail       "
9001305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		    "(root)    %%Capacity\n");
9011305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		printf("%12llu %12llu %12llu %12llu         %3llu%%\n",
9021305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		    (unsigned long long)(st.f_frsize * st.f_blocks / 1024),
9031305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		    (unsigned long long)(st.f_frsize *
9041305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		    (st.f_blocks - st.f_bfree) / 1024),
9051305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		    (unsigned long long)(st.f_frsize * st.f_bavail / 1024),
9061305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		    (unsigned long long)(st.f_frsize * st.f_bfree / 1024),
9071305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		    (unsigned long long)(100 * (st.f_blocks - st.f_bfree) /
9081305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		    st.f_blocks));
9091305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	}
9101305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	return 0;
9111305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood}
9121305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
9131305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood/*
9141305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * Undo escaping of glob sequences in place. Used to undo extra escaping
9151305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * applied in makeargv() when the string is destined for a function that
9161305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * does not glob it.
9171305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood */
9181305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstatic void
9191305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodundo_glob_escape(char *s)
9201305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{
9211305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	size_t i, j;
9221305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
9231305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	for (i = j = 0;;) {
9241305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if (s[i] == '\0') {
9251305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			s[j] = '\0';
9261305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			return;
9271305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		}
9281305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if (s[i] != '\\') {
9291305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			s[j++] = s[i++];
9301305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			continue;
9311305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		}
9321305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		/* s[i] == '\\' */
9331305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		++i;
9341305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		switch (s[i]) {
9351305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		case '?':
9361305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		case '[':
9371305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		case '*':
9381305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		case '\\':
9391305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			s[j++] = s[i++];
9401305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			break;
9411305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		case '\0':
9421305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			s[j++] = '\\';
9431305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			s[j] = '\0';
9441305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			return;
9451305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		default:
9461305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			s[j++] = '\\';
9471305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			s[j++] = s[i++];
9481305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			break;
9491305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		}
9501305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	}
9511305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood}
9521305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
9531305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood/*
9541305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * Split a string into an argument vector using sh(1)-style quoting,
9551305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * comment and escaping rules, but with some tweaks to handle glob(3)
9561305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * wildcards.
9571305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * The "sloppy" flag allows for recovery from missing terminating quote, for
9581305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * use in parsing incomplete commandlines during tab autocompletion.
9591305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood *
9601305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * Returns NULL on error or a NULL-terminated array of arguments.
9611305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood *
9621305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * If "lastquote" is not NULL, the quoting character used for the last
9631305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * argument is placed in *lastquote ("\0", "'" or "\"").
9641305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood *
9651305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * If "terminated" is not NULL, *terminated will be set to 1 when the
9661305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * last argument's quote has been properly terminated or 0 otherwise.
9671305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * This parameter is only of use if "sloppy" is set.
9681305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood */
9691305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#define MAXARGS 	128
9701305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#define MAXARGLEN	8192
9711305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstatic char **
9721305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodmakeargv(const char *arg, int *argcp, int sloppy, char *lastquote,
9731305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood    u_int *terminated)
9741305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{
9751305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	int argc, quot;
9761305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	size_t i, j;
9771305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	static char argvs[MAXARGLEN];
9781305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	static char *argv[MAXARGS + 1];
9791305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	enum { MA_START, MA_SQUOTE, MA_DQUOTE, MA_UNQUOTED } state, q;
9801305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
9811305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	*argcp = argc = 0;
9821305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (strlen(arg) > sizeof(argvs) - 1) {
9831305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood args_too_longs:
9841305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		error("string too long");
9851305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		return NULL;
9861305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	}
9871305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (terminated != NULL)
9881305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		*terminated = 1;
9891305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (lastquote != NULL)
9901305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		*lastquote = '\0';
9911305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	state = MA_START;
9921305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	i = j = 0;
9931305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	for (;;) {
9941305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if (isspace(arg[i])) {
9951305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			if (state == MA_UNQUOTED) {
9961305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				/* Terminate current argument */
9971305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				argvs[j++] = '\0';
9981305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				argc++;
9991305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				state = MA_START;
10001305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			} else if (state != MA_START)
10011305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				argvs[j++] = arg[i];
10021305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		} else if (arg[i] == '"' || arg[i] == '\'') {
10031305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			q = arg[i] == '"' ? MA_DQUOTE : MA_SQUOTE;
10041305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			if (state == MA_START) {
10051305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				argv[argc] = argvs + j;
10061305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				state = q;
10071305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				if (lastquote != NULL)
10081305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood					*lastquote = arg[i];
10091305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			} else if (state == MA_UNQUOTED)
10101305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				state = q;
10111305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			else if (state == q)
10121305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				state = MA_UNQUOTED;
10131305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			else
10141305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				argvs[j++] = arg[i];
10151305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		} else if (arg[i] == '\\') {
10161305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			if (state == MA_SQUOTE || state == MA_DQUOTE) {
10171305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				quot = state == MA_SQUOTE ? '\'' : '"';
10181305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				/* Unescape quote we are in */
10191305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				/* XXX support \n and friends? */
10201305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				if (arg[i + 1] == quot) {
10211305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood					i++;
10221305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood					argvs[j++] = arg[i];
10231305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				} else if (arg[i + 1] == '?' ||
10241305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				    arg[i + 1] == '[' || arg[i + 1] == '*') {
10251305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood					/*
10261305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood					 * Special case for sftp: append
10271305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood					 * double-escaped glob sequence -
10281305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood					 * glob will undo one level of
10291305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood					 * escaping. NB. string can grow here.
10301305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood					 */
10311305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood					if (j >= sizeof(argvs) - 5)
10321305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood						goto args_too_longs;
10331305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood					argvs[j++] = '\\';
10341305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood					argvs[j++] = arg[i++];
10351305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood					argvs[j++] = '\\';
10361305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood					argvs[j++] = arg[i];
10371305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				} else {
10381305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood					argvs[j++] = arg[i++];
10391305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood					argvs[j++] = arg[i];
10401305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				}
10411305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			} else {
10421305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				if (state == MA_START) {
10431305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood					argv[argc] = argvs + j;
10441305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood					state = MA_UNQUOTED;
10451305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood					if (lastquote != NULL)
10461305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood						*lastquote = '\0';
10471305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				}
10481305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				if (arg[i + 1] == '?' || arg[i + 1] == '[' ||
10491305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				    arg[i + 1] == '*' || arg[i + 1] == '\\') {
10501305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood					/*
10511305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood					 * Special case for sftp: append
10521305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood					 * escaped glob sequence -
10531305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood					 * glob will undo one level of
10541305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood					 * escaping.
10551305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood					 */
10561305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood					argvs[j++] = arg[i++];
10571305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood					argvs[j++] = arg[i];
10581305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				} else {
10591305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood					/* Unescape everything */
10601305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood					/* XXX support \n and friends? */
10611305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood					i++;
10621305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood					argvs[j++] = arg[i];
10631305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				}
10641305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			}
10651305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		} else if (arg[i] == '#') {
10661305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			if (state == MA_SQUOTE || state == MA_DQUOTE)
10671305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				argvs[j++] = arg[i];
10681305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			else
10691305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				goto string_done;
10701305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		} else if (arg[i] == '\0') {
10711305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			if (state == MA_SQUOTE || state == MA_DQUOTE) {
10721305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				if (sloppy) {
10731305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood					state = MA_UNQUOTED;
10741305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood					if (terminated != NULL)
10751305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood						*terminated = 0;
10761305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood					goto string_done;
10771305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				}
10781305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				error("Unterminated quoted argument");
10791305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				return NULL;
10801305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			}
10811305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood string_done:
10821305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			if (state == MA_UNQUOTED) {
10831305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				argvs[j++] = '\0';
10841305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				argc++;
10851305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			}
10861305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			break;
10871305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		} else {
10881305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			if (state == MA_START) {
10891305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				argv[argc] = argvs + j;
10901305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				state = MA_UNQUOTED;
10911305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				if (lastquote != NULL)
10921305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood					*lastquote = '\0';
10931305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			}
10941305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			if ((state == MA_SQUOTE || state == MA_DQUOTE) &&
10951305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			    (arg[i] == '?' || arg[i] == '[' || arg[i] == '*')) {
10961305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				/*
10971305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				 * Special case for sftp: escape quoted
10981305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				 * glob(3) wildcards. NB. string can grow
10991305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				 * here.
11001305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				 */
11011305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				if (j >= sizeof(argvs) - 3)
11021305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood					goto args_too_longs;
11031305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				argvs[j++] = '\\';
11041305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				argvs[j++] = arg[i];
11051305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			} else
11061305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				argvs[j++] = arg[i];
11071305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		}
11081305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		i++;
11091305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	}
11101305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	*argcp = argc;
11111305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	return argv;
11121305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood}
11131305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
11141305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstatic int
11151305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodparse_args(const char **cpp, int *pflag, int *rflag, int *lflag, int *iflag,
11161305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood    int *hflag, int *sflag, unsigned long *n_arg, char **path1, char **path2)
11171305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{
11181305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	const char *cmd, *cp = *cpp;
11191305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	char *cp2, **argv;
11201305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	int base = 0;
11211305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	long l;
11221305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	int i, cmdnum, optidx, argc;
11231305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
11241305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	/* Skip leading whitespace */
11251305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	cp = cp + strspn(cp, WHITESPACE);
11261305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
11271305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	/* Check for leading '-' (disable error processing) */
11281305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	*iflag = 0;
11291305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (*cp == '-') {
11301305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		*iflag = 1;
11311305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		cp++;
11321305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		cp = cp + strspn(cp, WHITESPACE);
11331305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	}
11341305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
11351305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	/* Ignore blank lines and lines which begin with comment '#' char */
11361305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (*cp == '\0' || *cp == '#')
11371305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		return (0);
11381305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
11391305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if ((argv = makeargv(cp, &argc, 0, NULL, NULL)) == NULL)
11401305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		return -1;
11411305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
11421305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	/* Figure out which command we have */
11431305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	for (i = 0; cmds[i].c != NULL; i++) {
11441305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if (strcasecmp(cmds[i].c, argv[0]) == 0)
11451305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			break;
11461305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	}
11471305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	cmdnum = cmds[i].n;
11481305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	cmd = cmds[i].c;
11491305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
11501305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	/* Special case */
11511305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (*cp == '!') {
11521305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		cp++;
11531305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		cmdnum = I_SHELL;
11541305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	} else if (cmdnum == -1) {
11551305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		error("Invalid command.");
11561305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		return -1;
11571305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	}
11581305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
11591305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	/* Get arguments and parse flags */
11601305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	*lflag = *pflag = *rflag = *hflag = *n_arg = 0;
11611305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	*path1 = *path2 = NULL;
11621305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	optidx = 1;
11631305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	switch (cmdnum) {
11641305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	case I_GET:
11651305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	case I_PUT:
11661305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if ((optidx = parse_getput_flags(cmd, argv, argc,
11671305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		    pflag, rflag)) == -1)
11681305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			return -1;
11691305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		/* Get first pathname (mandatory) */
11701305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if (argc - optidx < 1) {
11711305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			error("You must specify at least one path after a "
11721305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			    "%s command.", cmd);
11731305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			return -1;
11741305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		}
11751305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		*path1 = xstrdup(argv[optidx]);
11761305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		/* Get second pathname (optional) */
11771305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if (argc - optidx > 1) {
11781305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			*path2 = xstrdup(argv[optidx + 1]);
11791305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			/* Destination is not globbed */
11801305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			undo_glob_escape(*path2);
11811305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		}
11821305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		break;
11831305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	case I_LINK:
11841305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if ((optidx = parse_link_flags(cmd, argv, argc, sflag)) == -1)
11851305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			return -1;
11861305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	case I_SYMLINK:
11871305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	case I_RENAME:
11881305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if (argc - optidx < 2) {
11891305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			error("You must specify two paths after a %s "
11901305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			    "command.", cmd);
11911305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			return -1;
11921305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		}
11931305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		*path1 = xstrdup(argv[optidx]);
11941305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		*path2 = xstrdup(argv[optidx + 1]);
11951305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		/* Paths are not globbed */
11961305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		undo_glob_escape(*path1);
11971305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		undo_glob_escape(*path2);
11981305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		break;
11991305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	case I_RM:
12001305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	case I_MKDIR:
12011305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	case I_RMDIR:
12021305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	case I_CHDIR:
12031305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	case I_LCHDIR:
12041305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	case I_LMKDIR:
12051305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		/* Get pathname (mandatory) */
12061305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if (argc - optidx < 1) {
12071305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			error("You must specify a path after a %s command.",
12081305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			    cmd);
12091305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			return -1;
12101305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		}
12111305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		*path1 = xstrdup(argv[optidx]);
12121305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		/* Only "rm" globs */
12131305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if (cmdnum != I_RM)
12141305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			undo_glob_escape(*path1);
12151305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		break;
12161305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	case I_DF:
12171305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if ((optidx = parse_df_flags(cmd, argv, argc, hflag,
12181305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		    iflag)) == -1)
12191305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			return -1;
12201305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		/* Default to current directory if no path specified */
12211305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if (argc - optidx < 1)
12221305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			*path1 = NULL;
12231305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		else {
12241305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			*path1 = xstrdup(argv[optidx]);
12251305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			undo_glob_escape(*path1);
12261305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		}
12271305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		break;
12281305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	case I_LS:
12291305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if ((optidx = parse_ls_flags(argv, argc, lflag)) == -1)
12301305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			return(-1);
12311305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		/* Path is optional */
12321305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if (argc - optidx > 0)
12331305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			*path1 = xstrdup(argv[optidx]);
12341305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		break;
12351305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	case I_LLS:
12361305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		/* Skip ls command and following whitespace */
12371305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		cp = cp + strlen(cmd) + strspn(cp, WHITESPACE);
12381305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	case I_SHELL:
12391305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		/* Uses the rest of the line */
12401305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		break;
12411305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	case I_LUMASK:
12421305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	case I_CHMOD:
12431305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		base = 8;
12441305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	case I_CHOWN:
12451305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	case I_CHGRP:
12461305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		/* Get numeric arg (mandatory) */
12471305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if (argc - optidx < 1)
12481305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			goto need_num_arg;
12491305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		errno = 0;
12501305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		l = strtol(argv[optidx], &cp2, base);
12511305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if (cp2 == argv[optidx] || *cp2 != '\0' ||
12521305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		    ((l == LONG_MIN || l == LONG_MAX) && errno == ERANGE) ||
12531305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		    l < 0) {
12541305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood need_num_arg:
12551305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			error("You must supply a numeric argument "
12561305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			    "to the %s command.", cmd);
12571305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			return -1;
12581305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		}
12591305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		*n_arg = l;
12601305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if (cmdnum == I_LUMASK)
12611305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			break;
12621305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		/* Get pathname (mandatory) */
12631305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if (argc - optidx < 2) {
12641305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			error("You must specify a path after a %s command.",
12651305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			    cmd);
12661305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			return -1;
12671305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		}
12681305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		*path1 = xstrdup(argv[optidx + 1]);
12691305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		break;
12701305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	case I_QUIT:
12711305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	case I_PWD:
12721305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	case I_LPWD:
12731305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	case I_HELP:
12741305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	case I_VERSION:
12751305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	case I_PROGRESS:
12761305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		break;
12771305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	default:
12781305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		fatal("Command not implemented");
12791305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	}
12801305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
12811305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	*cpp = cp;
12821305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	return(cmdnum);
12831305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood}
12841305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
12851305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstatic int
12861305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodparse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
12871305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood    int err_abort)
12881305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{
12891305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	char *path1, *path2, *tmp;
12901305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	int pflag = 0, rflag = 0, lflag = 0, iflag = 0, hflag = 0, sflag = 0;
12911305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	int cmdnum, i;
12921305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	unsigned long n_arg = 0;
12931305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	Attrib a, *aa;
12941305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	char path_buf[MAXPATHLEN];
12951305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	int err = 0;
12961305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	glob_t g;
12971305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
12981305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	path1 = path2 = NULL;
12991305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	cmdnum = parse_args(&cmd, &pflag, &rflag, &lflag, &iflag, &hflag,
13001305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	    &sflag, &n_arg, &path1, &path2);
13011305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
13021305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (iflag != 0)
13031305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		err_abort = 0;
13041305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
13051305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	memset(&g, 0, sizeof(g));
13061305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
13071305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	/* Perform command */
13081305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	switch (cmdnum) {
13091305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	case 0:
13101305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		/* Blank line */
13111305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		break;
13121305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	case -1:
13131305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		/* Unrecognized command */
13141305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		err = -1;
13151305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		break;
13161305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	case I_GET:
13171305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		err = process_get(conn, path1, path2, *pwd, pflag, rflag);
13181305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		break;
13191305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	case I_PUT:
13201305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		err = process_put(conn, path1, path2, *pwd, pflag, rflag);
13211305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		break;
13221305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	case I_RENAME:
13231305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		path1 = make_absolute(path1, *pwd);
13241305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		path2 = make_absolute(path2, *pwd);
13251305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		err = do_rename(conn, path1, path2);
13261305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		break;
13271305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	case I_SYMLINK:
13281305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		sflag = 1;
13291305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	case I_LINK:
13301305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		path1 = make_absolute(path1, *pwd);
13311305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		path2 = make_absolute(path2, *pwd);
13321305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		err = (sflag ? do_symlink : do_hardlink)(conn, path1, path2);
13331305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		break;
13341305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	case I_RM:
13351305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		path1 = make_absolute(path1, *pwd);
13361305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g);
13371305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		for (i = 0; g.gl_pathv[i] && !interrupted; i++) {
13381305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			printf("Removing %s\n", g.gl_pathv[i]);
13391305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			err = do_rm(conn, g.gl_pathv[i]);
13401305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			if (err != 0 && err_abort)
13411305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				break;
13421305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		}
13431305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		break;
13441305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	case I_MKDIR:
13451305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		path1 = make_absolute(path1, *pwd);
13461305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		attrib_clear(&a);
13471305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS;
13481305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		a.perm = 0777;
13491305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		err = do_mkdir(conn, path1, &a, 1);
13501305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		break;
13511305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	case I_RMDIR:
13521305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		path1 = make_absolute(path1, *pwd);
13531305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		err = do_rmdir(conn, path1);
13541305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		break;
13551305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	case I_CHDIR:
13561305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		path1 = make_absolute(path1, *pwd);
13571305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if ((tmp = do_realpath(conn, path1)) == NULL) {
13581305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			err = 1;
13591305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			break;
13601305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		}
13611305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if ((aa = do_stat(conn, tmp, 0)) == NULL) {
13621305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			xfree(tmp);
13631305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			err = 1;
13641305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			break;
13651305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		}
13661305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if (!(aa->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)) {
13671305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			error("Can't change directory: Can't check target");
13681305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			xfree(tmp);
13691305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			err = 1;
13701305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			break;
13711305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		}
13721305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if (!S_ISDIR(aa->perm)) {
13731305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			error("Can't change directory: \"%s\" is not "
13741305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			    "a directory", tmp);
13751305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			xfree(tmp);
13761305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			err = 1;
13771305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			break;
13781305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		}
13791305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		xfree(*pwd);
13801305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		*pwd = tmp;
13811305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		break;
13821305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	case I_LS:
13831305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if (!path1) {
13841305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			do_ls_dir(conn, *pwd, *pwd, lflag);
13851305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			break;
13861305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		}
13871305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
13881305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		/* Strip pwd off beginning of non-absolute paths */
13891305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		tmp = NULL;
13901305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if (*path1 != '/')
13911305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			tmp = *pwd;
13921305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
13931305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		path1 = make_absolute(path1, *pwd);
13941305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		err = do_globbed_ls(conn, path1, tmp, lflag);
13951305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		break;
13961305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	case I_DF:
13971305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		/* Default to current directory if no path specified */
13981305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if (path1 == NULL)
13991305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			path1 = xstrdup(*pwd);
14001305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		path1 = make_absolute(path1, *pwd);
14011305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		err = do_df(conn, path1, hflag, iflag);
14021305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		break;
14031305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	case I_LCHDIR:
14041305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if (chdir(path1) == -1) {
14051305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			error("Couldn't change local directory to "
14061305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			    "\"%s\": %s", path1, strerror(errno));
14071305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			err = 1;
14081305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		}
14091305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		break;
14101305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	case I_LMKDIR:
14111305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if (mkdir(path1, 0777) == -1) {
14121305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			error("Couldn't create local directory "
14131305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			    "\"%s\": %s", path1, strerror(errno));
14141305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			err = 1;
14151305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		}
14161305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		break;
14171305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	case I_LLS:
14181305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		local_do_ls(cmd);
14191305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		break;
14201305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	case I_SHELL:
14211305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		local_do_shell(cmd);
14221305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		break;
14231305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	case I_LUMASK:
14241305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		umask(n_arg);
14251305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		printf("Local umask: %03lo\n", n_arg);
14261305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		break;
14271305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	case I_CHMOD:
14281305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		path1 = make_absolute(path1, *pwd);
14291305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		attrib_clear(&a);
14301305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS;
14311305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		a.perm = n_arg;
14321305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g);
14331305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		for (i = 0; g.gl_pathv[i] && !interrupted; i++) {
14341305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			printf("Changing mode on %s\n", g.gl_pathv[i]);
14351305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			err = do_setstat(conn, g.gl_pathv[i], &a);
14361305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			if (err != 0 && err_abort)
14371305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				break;
14381305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		}
14391305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		break;
14401305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	case I_CHOWN:
14411305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	case I_CHGRP:
14421305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		path1 = make_absolute(path1, *pwd);
14431305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g);
14441305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		for (i = 0; g.gl_pathv[i] && !interrupted; i++) {
14451305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			if (!(aa = do_stat(conn, g.gl_pathv[i], 0))) {
14461305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				if (err_abort) {
14471305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood					err = -1;
14481305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood					break;
14491305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				} else
14501305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood					continue;
14511305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			}
14521305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			if (!(aa->flags & SSH2_FILEXFER_ATTR_UIDGID)) {
14531305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				error("Can't get current ownership of "
14541305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				    "remote file \"%s\"", g.gl_pathv[i]);
14551305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				if (err_abort) {
14561305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood					err = -1;
14571305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood					break;
14581305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				} else
14591305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood					continue;
14601305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			}
14611305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			aa->flags &= SSH2_FILEXFER_ATTR_UIDGID;
14621305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			if (cmdnum == I_CHOWN) {
14631305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				printf("Changing owner on %s\n", g.gl_pathv[i]);
14641305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				aa->uid = n_arg;
14651305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			} else {
14661305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				printf("Changing group on %s\n", g.gl_pathv[i]);
14671305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				aa->gid = n_arg;
14681305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			}
14691305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			err = do_setstat(conn, g.gl_pathv[i], aa);
14701305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			if (err != 0 && err_abort)
14711305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				break;
14721305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		}
14731305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		break;
14741305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	case I_PWD:
14751305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		printf("Remote working directory: %s\n", *pwd);
14761305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		break;
14771305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	case I_LPWD:
14781305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if (!getcwd(path_buf, sizeof(path_buf))) {
14791305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			error("Couldn't get local cwd: %s", strerror(errno));
14801305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			err = -1;
14811305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			break;
14821305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		}
14831305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		printf("Local working directory: %s\n", path_buf);
14841305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		break;
14851305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	case I_QUIT:
14861305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		/* Processed below */
14871305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		break;
14881305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	case I_HELP:
14891305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		help();
14901305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		break;
14911305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	case I_VERSION:
14921305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		printf("SFTP protocol version %u\n", sftp_proto_version(conn));
14931305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		break;
14941305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	case I_PROGRESS:
14951305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		showprogress = !showprogress;
14961305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if (showprogress)
14971305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			printf("Progress meter enabled\n");
14981305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		else
14991305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			printf("Progress meter disabled\n");
15001305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		break;
15011305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	default:
15021305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		fatal("%d is not implemented", cmdnum);
15031305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	}
15041305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
15051305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (g.gl_pathc)
15061305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		globfree(&g);
15071305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (path1)
15081305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		xfree(path1);
15091305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (path2)
15101305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		xfree(path2);
15111305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
15121305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	/* If an unignored error occurs in batch mode we should abort. */
15131305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (err_abort && err != 0)
15141305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		return (-1);
15151305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	else if (cmdnum == I_QUIT)
15161305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		return (1);
15171305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
15181305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	return (0);
15191305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood}
15201305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
15211305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#ifdef USE_LIBEDIT
15221305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstatic char *
15231305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodprompt(EditLine *el)
15241305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{
15251305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	return ("sftp> ");
15261305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood}
15271305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
15281305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood/* Display entries in 'list' after skipping the first 'len' chars */
15291305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstatic void
15301305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodcomplete_display(char **list, u_int len)
15311305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{
15321305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	u_int y, m = 0, width = 80, columns = 1, colspace = 0, llen;
15331305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	struct winsize ws;
15341305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	char *tmp;
15351305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
15361305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	/* Count entries for sort and find longest */
15371305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	for (y = 0; list[y]; y++)
15381305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		m = MAX(m, strlen(list[y]));
15391305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
15401305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) != -1)
15411305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		width = ws.ws_col;
15421305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
15431305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	m = m > len ? m - len : 0;
15441305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	columns = width / (m + 2);
15451305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	columns = MAX(columns, 1);
15461305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	colspace = width / columns;
15471305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	colspace = MIN(colspace, width);
15481305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
15491305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	printf("\n");
15501305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	m = 1;
15511305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	for (y = 0; list[y]; y++) {
15521305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		llen = strlen(list[y]);
15531305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		tmp = llen > len ? list[y] + len : "";
15541305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		printf("%-*s", colspace, tmp);
15551305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if (m >= columns) {
15561305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			printf("\n");
15571305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			m = 1;
15581305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		} else
15591305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			m++;
15601305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	}
15611305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	printf("\n");
15621305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood}
15631305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
15641305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood/*
15651305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * Given a "list" of words that begin with a common prefix of "word",
15661305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * attempt to find an autocompletion to extends "word" by the next
15671305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * characters common to all entries in "list".
15681305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood */
15691305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstatic char *
15701305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodcomplete_ambiguous(const char *word, char **list, size_t count)
15711305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{
15721305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (word == NULL)
15731305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		return NULL;
15741305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
15751305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (count > 0) {
15761305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		u_int y, matchlen = strlen(list[0]);
15771305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
15781305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		/* Find length of common stem */
15791305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		for (y = 1; list[y]; y++) {
15801305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			u_int x;
15811305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
15821305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			for (x = 0; x < matchlen; x++)
15831305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				if (list[0][x] != list[y][x])
15841305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood					break;
15851305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
15861305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			matchlen = x;
15871305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		}
15881305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
15891305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if (matchlen > strlen(word)) {
15901305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			char *tmp = xstrdup(list[0]);
15911305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
15921305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			tmp[matchlen] = '\0';
15931305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			return tmp;
15941305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		}
15951305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	}
15961305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
15971305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	return xstrdup(word);
15981305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood}
15991305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
16001305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood/* Autocomplete a sftp command */
16011305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstatic int
16021305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodcomplete_cmd_parse(EditLine *el, char *cmd, int lastarg, char quote,
16031305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood    int terminated)
16041305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{
16051305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	u_int y, count = 0, cmdlen, tmplen;
16061305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	char *tmp, **list, argterm[3];
16071305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	const LineInfo *lf;
16081305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
16091305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	list = xcalloc((sizeof(cmds) / sizeof(*cmds)) + 1, sizeof(char *));
16101305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
16111305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	/* No command specified: display all available commands */
16121305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (cmd == NULL) {
16131305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		for (y = 0; cmds[y].c; y++)
16141305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			list[count++] = xstrdup(cmds[y].c);
16151305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
16161305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		list[count] = NULL;
16171305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		complete_display(list, 0);
16181305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
16191305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		for (y = 0; list[y] != NULL; y++)
16201305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			xfree(list[y]);
16211305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		xfree(list);
16221305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		return count;
16231305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	}
16241305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
16251305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	/* Prepare subset of commands that start with "cmd" */
16261305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	cmdlen = strlen(cmd);
16271305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	for (y = 0; cmds[y].c; y++)  {
16281305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if (!strncasecmp(cmd, cmds[y].c, cmdlen))
16291305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			list[count++] = xstrdup(cmds[y].c);
16301305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	}
16311305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	list[count] = NULL;
16321305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
16331305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (count == 0)
16341305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		return 0;
16351305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
16361305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	/* Complete ambigious command */
16371305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	tmp = complete_ambiguous(cmd, list, count);
16381305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (count > 1)
16391305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		complete_display(list, 0);
16401305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
16411305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	for (y = 0; list[y]; y++)
16421305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		xfree(list[y]);
16431305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	xfree(list);
16441305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
16451305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (tmp != NULL) {
16461305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		tmplen = strlen(tmp);
16471305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		cmdlen = strlen(cmd);
16481305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		/* If cmd may be extended then do so */
16491305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if (tmplen > cmdlen)
16501305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			if (el_insertstr(el, tmp + cmdlen) == -1)
16511305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				fatal("el_insertstr failed.");
16521305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		lf = el_line(el);
16531305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		/* Terminate argument cleanly */
16541305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if (count == 1) {
16551305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			y = 0;
16561305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			if (!terminated)
16571305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				argterm[y++] = quote;
16581305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			if (lastarg || *(lf->cursor) != ' ')
16591305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				argterm[y++] = ' ';
16601305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			argterm[y] = '\0';
16611305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			if (y > 0 && el_insertstr(el, argterm) == -1)
16621305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				fatal("el_insertstr failed.");
16631305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		}
16641305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		xfree(tmp);
16651305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	}
16661305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
16671305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	return count;
16681305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood}
16691305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
16701305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood/*
16711305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * Determine whether a particular sftp command's arguments (if any)
16721305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * represent local or remote files.
16731305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood */
16741305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstatic int
16751305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodcomplete_is_remote(char *cmd) {
16761305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	int i;
16771305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
16781305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (cmd == NULL)
16791305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		return -1;
16801305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
16811305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	for (i = 0; cmds[i].c; i++) {
16821305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if (!strncasecmp(cmd, cmds[i].c, strlen(cmds[i].c)))
16831305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			return cmds[i].t;
16841305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	}
16851305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
16861305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	return -1;
16871305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood}
16881305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
16891305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood/* Autocomplete a filename "file" */
16901305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstatic int
16911305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodcomplete_match(EditLine *el, struct sftp_conn *conn, char *remote_path,
16921305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood    char *file, int remote, int lastarg, char quote, int terminated)
16931305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{
16941305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	glob_t g;
16951305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	char *tmp, *tmp2, ins[3];
16961305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	u_int i, hadglob, pwdlen, len, tmplen, filelen;
16971305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	const LineInfo *lf;
16981305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
16991305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	/* Glob from "file" location */
17001305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (file == NULL)
17011305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		tmp = xstrdup("*");
17021305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	else
17031305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		xasprintf(&tmp, "%s*", file);
17041305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
17051305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	memset(&g, 0, sizeof(g));
17061305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (remote != LOCAL) {
17071305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		tmp = make_absolute(tmp, remote_path);
17081305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		remote_glob(conn, tmp, GLOB_DOOFFS|GLOB_MARK, NULL, &g);
17091305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	} else
17101305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		glob(tmp, GLOB_DOOFFS|GLOB_MARK, NULL, &g);
17111305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
17121305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	/* Determine length of pwd so we can trim completion display */
17131305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	for (hadglob = tmplen = pwdlen = 0; tmp[tmplen] != 0; tmplen++) {
17141305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		/* Terminate counting on first unescaped glob metacharacter */
17151305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if (tmp[tmplen] == '*' || tmp[tmplen] == '?') {
17161305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			if (tmp[tmplen] != '*' || tmp[tmplen + 1] != '\0')
17171305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				hadglob = 1;
17181305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			break;
17191305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		}
17201305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if (tmp[tmplen] == '\\' && tmp[tmplen + 1] != '\0')
17211305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			tmplen++;
17221305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if (tmp[tmplen] == '/')
17231305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			pwdlen = tmplen + 1;	/* track last seen '/' */
17241305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	}
17251305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	xfree(tmp);
17261305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
17271305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (g.gl_matchc == 0)
17281305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		goto out;
17291305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
17301305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (g.gl_matchc > 1)
17311305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		complete_display(g.gl_pathv, pwdlen);
17321305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
17331305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	tmp = NULL;
17341305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	/* Don't try to extend globs */
17351305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (file == NULL || hadglob)
17361305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		goto out;
17371305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
17381305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	tmp2 = complete_ambiguous(file, g.gl_pathv, g.gl_matchc);
17391305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	tmp = path_strip(tmp2, remote_path);
17401305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	xfree(tmp2);
17411305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
17421305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (tmp == NULL)
17431305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		goto out;
17441305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
17451305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	tmplen = strlen(tmp);
17461305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	filelen = strlen(file);
17471305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
17481305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (tmplen > filelen)  {
17491305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		tmp2 = tmp + filelen;
17501305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		len = strlen(tmp2);
17511305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		/* quote argument on way out */
17521305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		for (i = 0; i < len; i++) {
17531305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			ins[0] = '\\';
17541305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			ins[1] = tmp2[i];
17551305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			ins[2] = '\0';
17561305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			switch (tmp2[i]) {
17571305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			case '\'':
17581305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			case '"':
17591305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			case '\\':
17601305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			case '\t':
17611305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			case '[':
17621305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			case ' ':
17631305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				if (quote == '\0' || tmp2[i] == quote) {
17641305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood					if (el_insertstr(el, ins) == -1)
17651305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood						fatal("el_insertstr "
17661305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood						    "failed.");
17671305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood					break;
17681305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				}
17691305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				/* FALLTHROUGH */
17701305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			default:
17711305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				if (el_insertstr(el, ins + 1) == -1)
17721305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood					fatal("el_insertstr failed.");
17731305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				break;
17741305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			}
17751305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		}
17761305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	}
17771305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
17781305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	lf = el_line(el);
17791305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (g.gl_matchc == 1) {
17801305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		i = 0;
17811305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if (!terminated)
17821305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			ins[i++] = quote;
17831305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if (*(lf->cursor - 1) != '/' &&
17841305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		    (lastarg || *(lf->cursor) != ' '))
17851305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			ins[i++] = ' ';
17861305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		ins[i] = '\0';
17871305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if (i > 0 && el_insertstr(el, ins) == -1)
17881305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			fatal("el_insertstr failed.");
17891305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	}
17901305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	xfree(tmp);
17911305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
17921305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood out:
17931305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	globfree(&g);
17941305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	return g.gl_matchc;
17951305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood}
17961305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
17971305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood/* tab-completion hook function, called via libedit */
17981305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstatic unsigned char
17991305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodcomplete(EditLine *el, int ch)
18001305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{
18011305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	char **argv, *line, quote;
18021305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	u_int argc, carg, cursor, len, terminated, ret = CC_ERROR;
18031305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	const LineInfo *lf;
18041305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	struct complete_ctx *complete_ctx;
18051305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
18061305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	lf = el_line(el);
18071305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (el_get(el, EL_CLIENTDATA, (void**)&complete_ctx) != 0)
18081305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		fatal("%s: el_get failed", __func__);
18091305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
18101305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	/* Figure out which argument the cursor points to */
18111305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	cursor = lf->cursor - lf->buffer;
18121305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	line = (char *)xmalloc(cursor + 1);
18131305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	memcpy(line, lf->buffer, cursor);
18141305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	line[cursor] = '\0';
18151305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	argv = makeargv(line, &carg, 1, &quote, &terminated);
18161305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	xfree(line);
18171305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
18181305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	/* Get all the arguments on the line */
18191305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	len = lf->lastchar - lf->buffer;
18201305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	line = (char *)xmalloc(len + 1);
18211305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	memcpy(line, lf->buffer, len);
18221305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	line[len] = '\0';
18231305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	argv = makeargv(line, &argc, 1, NULL, NULL);
18241305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
18251305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	/* Ensure cursor is at EOL or a argument boundary */
18261305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (line[cursor] != ' ' && line[cursor] != '\0' &&
18271305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	    line[cursor] != '\n') {
18281305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		xfree(line);
18291305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		return ret;
18301305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	}
18311305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
18321305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (carg == 0) {
18331305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		/* Show all available commands */
18341305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		complete_cmd_parse(el, NULL, argc == carg, '\0', 1);
18351305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		ret = CC_REDISPLAY;
18361305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	} else if (carg == 1 && cursor > 0 && line[cursor - 1] != ' ')  {
18371305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		/* Handle the command parsing */
18381305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if (complete_cmd_parse(el, argv[0], argc == carg,
18391305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		    quote, terminated) != 0)
18401305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			ret = CC_REDISPLAY;
18411305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	} else if (carg >= 1) {
18421305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		/* Handle file parsing */
18431305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		int remote = complete_is_remote(argv[0]);
18441305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		char *filematch = NULL;
18451305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
18461305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if (carg > 1 && line[cursor-1] != ' ')
18471305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			filematch = argv[carg - 1];
18481305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
18491305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if (remote != 0 &&
18501305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		    complete_match(el, complete_ctx->conn,
18511305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		    *complete_ctx->remote_pathp, filematch,
18521305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		    remote, carg == argc, quote, terminated) != 0)
18531305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			ret = CC_REDISPLAY;
18541305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	}
18551305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
18561305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	xfree(line);
18571305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	return ret;
18581305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood}
18591305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#endif /* USE_LIBEDIT */
18601305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
18611305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodint
18621305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodinteractive_loop(struct sftp_conn *conn, char *file1, char *file2)
18631305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{
18641305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	char *remote_path;
18651305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	char *dir = NULL;
18661305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	char cmd[2048];
18671305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	int err, interactive;
18681305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	EditLine *el = NULL;
18691305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#ifdef USE_LIBEDIT
18701305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	History *hl = NULL;
18711305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	HistEvent hev;
18721305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	extern char *__progname;
18731305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	struct complete_ctx complete_ctx;
18741305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
18751305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (!batchmode && isatty(STDIN_FILENO)) {
18761305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if ((el = el_init(__progname, stdin, stdout, stderr)) == NULL)
18771305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			fatal("Couldn't initialise editline");
18781305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if ((hl = history_init()) == NULL)
18791305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			fatal("Couldn't initialise editline history");
18801305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		history(hl, &hev, H_SETSIZE, 100);
18811305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		el_set(el, EL_HIST, history, hl);
18821305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
18831305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		el_set(el, EL_PROMPT, prompt);
18841305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		el_set(el, EL_EDITOR, "emacs");
18851305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		el_set(el, EL_TERMINAL, NULL);
18861305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		el_set(el, EL_SIGNAL, 1);
18871305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		el_source(el, NULL);
18881305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
18891305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		/* Tab Completion */
18901305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		el_set(el, EL_ADDFN, "ftp-complete",
18911305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		    "Context sensitive argument completion", complete);
18921305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		complete_ctx.conn = conn;
18931305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		complete_ctx.remote_pathp = &remote_path;
18941305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		el_set(el, EL_CLIENTDATA, (void*)&complete_ctx);
18951305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		el_set(el, EL_BIND, "^I", "ftp-complete", NULL);
18961305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	}
18971305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#endif /* USE_LIBEDIT */
18981305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
18991305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	remote_path = do_realpath(conn, ".");
19001305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (remote_path == NULL)
19011305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		fatal("Need cwd");
19021305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
19031305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (file1 != NULL) {
19041305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		dir = xstrdup(file1);
19051305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		dir = make_absolute(dir, remote_path);
19061305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
19071305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if (remote_is_dir(conn, dir) && file2 == NULL) {
19081305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			printf("Changing to: %s\n", dir);
19091305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			snprintf(cmd, sizeof cmd, "cd \"%s\"", dir);
19101305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			if (parse_dispatch_command(conn, cmd,
19111305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			    &remote_path, 1) != 0) {
19121305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				xfree(dir);
19131305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				xfree(remote_path);
19141305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				xfree(conn);
19151305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				return (-1);
19161305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			}
19171305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		} else {
19181305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			if (file2 == NULL)
19191305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				snprintf(cmd, sizeof cmd, "get %s", dir);
19201305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			else
19211305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				snprintf(cmd, sizeof cmd, "get %s %s", dir,
19221305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				    file2);
19231305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
19241305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			err = parse_dispatch_command(conn, cmd,
19251305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			    &remote_path, 1);
19261305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			xfree(dir);
19271305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			xfree(remote_path);
19281305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			xfree(conn);
19291305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			return (err);
19301305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		}
19311305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		xfree(dir);
19321305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	}
19331305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
19341305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#if defined(HAVE_SETVBUF) && !defined(BROKEN_SETVBUF)
19351305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	setvbuf(stdout, NULL, _IOLBF, 0);
19361305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	setvbuf(infile, NULL, _IOLBF, 0);
19371305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#else
19381305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	setlinebuf(stdout);
19391305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	setlinebuf(infile);
19401305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#endif
19411305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
19421305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	interactive = !batchmode && isatty(STDIN_FILENO);
19431305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	err = 0;
19441305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	for (;;) {
19451305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		char *cp;
19461305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
19471305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		signal(SIGINT, SIG_IGN);
19481305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
19491305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if (el == NULL) {
19501305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			if (interactive)
19511305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				printf("sftp> ");
19521305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			if (fgets(cmd, sizeof(cmd), infile) == NULL) {
19531305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				if (interactive)
19541305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood					printf("\n");
19551305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				break;
19561305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			}
19571305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			if (!interactive) { /* Echo command */
19581305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				printf("sftp> %s", cmd);
19591305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				if (strlen(cmd) > 0 &&
19601305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				    cmd[strlen(cmd) - 1] != '\n')
19611305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood					printf("\n");
19621305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			}
19631305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		} else {
19641305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#ifdef USE_LIBEDIT
19651305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			const char *line;
19661305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			int count = 0;
19671305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
19681305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			if ((line = el_gets(el, &count)) == NULL ||
19691305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			    count <= 0) {
19701305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				printf("\n");
19711305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 				break;
19721305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			}
19731305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			history(hl, &hev, H_ENTER, line);
19741305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			if (strlcpy(cmd, line, sizeof(cmd)) >= sizeof(cmd)) {
19751305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				fprintf(stderr, "Error: input line too long\n");
19761305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				continue;
19771305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			}
19781305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#endif /* USE_LIBEDIT */
19791305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		}
19801305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
19811305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		cp = strrchr(cmd, '\n');
19821305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if (cp)
19831305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			*cp = '\0';
19841305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
19851305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		/* Handle user interrupts gracefully during commands */
19861305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		interrupted = 0;
19871305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		signal(SIGINT, cmd_interrupt);
19881305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
19891305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		err = parse_dispatch_command(conn, cmd, &remote_path,
19901305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		    batchmode);
19911305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if (err != 0)
19921305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			break;
19931305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	}
19941305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	xfree(remote_path);
19951305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	xfree(conn);
19961305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
19971305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#ifdef USE_LIBEDIT
19981305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (el != NULL)
19991305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		el_end(el);
20001305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#endif /* USE_LIBEDIT */
20011305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
20021305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	/* err == 1 signifies normal "quit" exit */
20031305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	return (err >= 0 ? 0 : -1);
20041305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood}
20051305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
20061305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstatic void
20071305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodconnect_to_server(char *path, char **args, int *in, int *out)
20081305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{
20091305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	int c_in, c_out;
20101305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
20111305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#ifdef USE_PIPES
20121305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	int pin[2], pout[2];
20131305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
20141305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if ((pipe(pin) == -1) || (pipe(pout) == -1))
20151305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		fatal("pipe: %s", strerror(errno));
20161305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	*in = pin[0];
20171305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	*out = pout[1];
20181305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	c_in = pout[0];
20191305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	c_out = pin[1];
20201305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#else /* USE_PIPES */
20211305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	int inout[2];
20221305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
20231305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) == -1)
20241305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		fatal("socketpair: %s", strerror(errno));
20251305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	*in = *out = inout[0];
20261305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	c_in = c_out = inout[1];
20271305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#endif /* USE_PIPES */
20281305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
20291305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if ((sshpid = fork()) == -1)
20301305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		fatal("fork: %s", strerror(errno));
20311305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	else if (sshpid == 0) {
20321305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if ((dup2(c_in, STDIN_FILENO) == -1) ||
20331305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		    (dup2(c_out, STDOUT_FILENO) == -1)) {
20341305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			fprintf(stderr, "dup2: %s\n", strerror(errno));
20351305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			_exit(1);
20361305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		}
20371305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		close(*in);
20381305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		close(*out);
20391305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		close(c_in);
20401305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		close(c_out);
20411305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
20421305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		/*
20431305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		 * The underlying ssh is in the same process group, so we must
20441305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		 * ignore SIGINT if we want to gracefully abort commands,
20451305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		 * otherwise the signal will make it to the ssh process and
20461305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		 * kill it too.  Contrawise, since sftp sends SIGTERMs to the
20471305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		 * underlying ssh, it must *not* ignore that signal.
20481305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		 */
20491305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		signal(SIGINT, SIG_IGN);
20501305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		signal(SIGTERM, SIG_DFL);
20511305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		execvp(path, args);
20521305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		fprintf(stderr, "exec: %s: %s\n", path, strerror(errno));
20531305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		_exit(1);
20541305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	}
20551305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
20561305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	signal(SIGTERM, killchild);
20571305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	signal(SIGINT, killchild);
20581305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	signal(SIGHUP, killchild);
20591305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	close(c_in);
20601305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	close(c_out);
20611305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood}
20621305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
20631305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstatic void
20641305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodusage(void)
20651305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{
20661305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	extern char *__progname;
20671305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
20681305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	fprintf(stderr,
20691305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	    "usage: %s [-1246Cpqrv] [-B buffer_size] [-b batchfile] [-c cipher]\n"
20701305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	    "          [-D sftp_server_path] [-F ssh_config] "
20711305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	    "[-i identity_file] [-l limit]\n"
20721305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	    "          [-o ssh_option] [-P port] [-R num_requests] "
20731305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	    "[-S program]\n"
20741305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	    "          [-s subsystem | sftp_server] host\n"
20751305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	    "       %s [user@]host[:file ...]\n"
20761305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	    "       %s [user@]host[:dir[/]]\n"
20771305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	    "       %s -b batchfile [user@]host\n",
20781305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	    __progname, __progname, __progname, __progname);
20791305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	exit(1);
20801305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood}
20811305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
20821305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodint
20831305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodmain(int argc, char **argv)
20841305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{
20851305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	int in, out, ch, err;
20861305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	char *host = NULL, *userhost, *cp, *file2 = NULL;
20871305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	int debug_level = 0, sshver = 2;
20881305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	char *file1 = NULL, *sftp_server = NULL;
20891305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	char *ssh_program = _PATH_SSH_PROGRAM, *sftp_direct = NULL;
20901305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	const char *errstr;
20911305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	LogLevel ll = SYSLOG_LEVEL_INFO;
20921305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	arglist args;
20931305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	extern int optind;
20941305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	extern char *optarg;
20951305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	struct sftp_conn *conn;
20961305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	size_t copy_buffer_len = DEFAULT_COPY_BUFLEN;
20971305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	size_t num_requests = DEFAULT_NUM_REQUESTS;
20981305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	long long limit_kbps = 0;
20991305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
21001305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	/* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
21011305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	sanitise_stdfd();
21021305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
21031305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	__progname = ssh_get_progname(argv[0]);
21041305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	memset(&args, '\0', sizeof(args));
21051305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	args.list = NULL;
21061305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	addargs(&args, "%s", ssh_program);
21071305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	addargs(&args, "-oForwardX11 no");
21081305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	addargs(&args, "-oForwardAgent no");
21091305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	addargs(&args, "-oPermitLocalCommand no");
21101305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	addargs(&args, "-oClearAllForwardings yes");
21111305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
21121305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	ll = SYSLOG_LEVEL_INFO;
21131305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	infile = stdin;
21141305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
21151305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	while ((ch = getopt(argc, argv,
21161305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	    "1246hpqrvCc:D:i:l:o:s:S:b:B:F:P:R:")) != -1) {
21171305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		switch (ch) {
21181305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		/* Passed through to ssh(1) */
21191305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		case '4':
21201305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		case '6':
21211305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		case 'C':
21221305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			addargs(&args, "-%c", ch);
21231305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			break;
21241305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		/* Passed through to ssh(1) with argument */
21251305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		case 'F':
21261305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		case 'c':
21271305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		case 'i':
21281305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		case 'o':
21291305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			addargs(&args, "-%c", ch);
21301305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			addargs(&args, "%s", optarg);
21311305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			break;
21321305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		case 'q':
21331305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			showprogress = 0;
21341305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			addargs(&args, "-%c", ch);
21351305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			break;
21361305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		case 'P':
21371305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			addargs(&args, "-oPort %s", optarg);
21381305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			break;
21391305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		case 'v':
21401305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			if (debug_level < 3) {
21411305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				addargs(&args, "-v");
21421305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				ll = SYSLOG_LEVEL_DEBUG1 + debug_level;
21431305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			}
21441305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			debug_level++;
21451305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			break;
21461305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		case '1':
21471305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			sshver = 1;
21481305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			if (sftp_server == NULL)
21491305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				sftp_server = _PATH_SFTP_SERVER;
21501305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			break;
21511305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		case '2':
21521305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			sshver = 2;
21531305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			break;
21541305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		case 'B':
21551305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			copy_buffer_len = strtol(optarg, &cp, 10);
21561305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			if (copy_buffer_len == 0 || *cp != '\0')
21571305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				fatal("Invalid buffer size \"%s\"", optarg);
21581305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			break;
21591305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		case 'b':
21601305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			if (batchmode)
21611305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				fatal("Batch file already specified.");
21621305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
21631305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			/* Allow "-" as stdin */
21641305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			if (strcmp(optarg, "-") != 0 &&
21651305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			    (infile = fopen(optarg, "r")) == NULL)
21661305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				fatal("%s (%s).", strerror(errno), optarg);
21671305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			showprogress = 0;
21681305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			batchmode = 1;
21691305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			addargs(&args, "-obatchmode yes");
21701305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			break;
21711305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		case 'p':
21721305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			global_pflag = 1;
21731305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			break;
21741305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		case 'D':
21751305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			sftp_direct = optarg;
21761305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			break;
21771305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		case 'l':
21781305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			limit_kbps = strtonum(optarg, 1, 100 * 1024 * 1024,
21791305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			    &errstr);
21801305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			if (errstr != NULL)
21811305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				usage();
21821305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			limit_kbps *= 1024; /* kbps */
21831305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			break;
21841305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		case 'r':
21851305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			global_rflag = 1;
21861305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			break;
21871305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		case 'R':
21881305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			num_requests = strtol(optarg, &cp, 10);
21891305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			if (num_requests == 0 || *cp != '\0')
21901305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				fatal("Invalid number of requests \"%s\"",
21911305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				    optarg);
21921305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			break;
21931305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		case 's':
21941305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			sftp_server = optarg;
21951305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			break;
21961305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		case 'S':
21971305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			ssh_program = optarg;
21981305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			replacearg(&args, 0, "%s", ssh_program);
21991305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			break;
22001305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		case 'h':
22011305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		default:
22021305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			usage();
22031305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		}
22041305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	}
22051305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
22061305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (!isatty(STDERR_FILENO))
22071305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		showprogress = 0;
22081305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
22091305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	log_init(argv[0], ll, SYSLOG_FACILITY_USER, 1);
22101305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
22111305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (sftp_direct == NULL) {
22121305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if (optind == argc || argc > (optind + 2))
22131305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			usage();
22141305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
22151305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		userhost = xstrdup(argv[optind]);
22161305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		file2 = argv[optind+1];
22171305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
22181305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if ((host = strrchr(userhost, '@')) == NULL)
22191305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			host = userhost;
22201305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		else {
22211305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			*host++ = '\0';
22221305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			if (!userhost[0]) {
22231305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				fprintf(stderr, "Missing username\n");
22241305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood				usage();
22251305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			}
22261305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			addargs(&args, "-l");
22271305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			addargs(&args, "%s", userhost);
22281305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		}
22291305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
22301305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if ((cp = colon(host)) != NULL) {
22311305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			*cp++ = '\0';
22321305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			file1 = cp;
22331305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		}
22341305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
22351305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		host = cleanhostname(host);
22361305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if (!*host) {
22371305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			fprintf(stderr, "Missing hostname\n");
22381305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			usage();
22391305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		}
22401305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
22411305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		addargs(&args, "-oProtocol %d", sshver);
22421305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
22431305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		/* no subsystem if the server-spec contains a '/' */
22441305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if (sftp_server == NULL || strchr(sftp_server, '/') == NULL)
22451305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			addargs(&args, "-s");
22461305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
22471305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		addargs(&args, "--");
22481305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		addargs(&args, "%s", host);
22491305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		addargs(&args, "%s", (sftp_server != NULL ?
22501305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		    sftp_server : "sftp"));
22511305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
22521305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		connect_to_server(ssh_program, args.list, &in, &out);
22531305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	} else {
22541305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		args.list = NULL;
22551305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		addargs(&args, "sftp-server");
22561305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
22571305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		connect_to_server(sftp_direct, args.list, &in, &out);
22581305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	}
22591305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	freeargs(&args);
22601305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
22611305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	conn = do_init(in, out, copy_buffer_len, num_requests, limit_kbps);
22621305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (conn == NULL)
22631305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		fatal("Couldn't initialise connection to server");
22641305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
22651305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (!batchmode) {
22661305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if (sftp_direct == NULL)
22671305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			fprintf(stderr, "Connected to %s.\n", host);
22681305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		else
22691305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			fprintf(stderr, "Attached to %s.\n", sftp_direct);
22701305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	}
22711305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
22721305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	err = interactive_loop(conn, file1, file2);
22731305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
22741305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#if !defined(USE_PIPES)
22751305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	shutdown(in, SHUT_RDWR);
22761305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	shutdown(out, SHUT_RDWR);
22771305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#endif
22781305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
22791305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	close(in);
22801305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	close(out);
22811305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	if (batchmode)
22821305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		fclose(infile);
22831305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
22841305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	while (waitpid(sshpid, NULL, 0) == -1)
22851305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood		if (errno != EINTR)
22861305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			fatal("Couldn't wait for ssh process: %s",
22871305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood			    strerror(errno));
22881305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood
22891305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood	exit(err == 0 ? 0 : 1);
22901305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood}
2291