version 1.22.2.2, 2001/02/19 17:19:23 |
version 1.22.2.3, 2001/03/21 19:46:29 |
|
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
*/ |
*/ |
|
|
/* XXX: finish implementation of all commands */ |
|
/* XXX: do fnmatch() instead of using raw pathname */ |
|
/* XXX: globbed ls */ |
/* XXX: globbed ls */ |
/* XXX: recursive operations */ |
/* XXX: recursive operations */ |
|
|
#include "includes.h" |
#include "includes.h" |
RCSID("$OpenBSD$"); |
RCSID("$OpenBSD$"); |
|
|
|
#include <glob.h> |
|
|
#include "buffer.h" |
#include "buffer.h" |
#include "xmalloc.h" |
#include "xmalloc.h" |
#include "log.h" |
#include "log.h" |
|
|
|
|
#include "sftp.h" |
#include "sftp.h" |
#include "sftp-common.h" |
#include "sftp-common.h" |
|
#include "sftp-glob.h" |
#include "sftp-client.h" |
#include "sftp-client.h" |
#include "sftp-int.h" |
#include "sftp-int.h" |
|
|
|
/* File to read commands from */ |
|
extern FILE *infile; |
|
|
|
/* Version of server we are speaking to */ |
|
int version; |
|
|
/* Seperators for interactive commands */ |
/* Seperators for interactive commands */ |
#define WHITESPACE " \t\r\n" |
#define WHITESPACE " \t\r\n" |
|
|
|
|
#define I_RM 18 |
#define I_RM 18 |
#define I_RMDIR 19 |
#define I_RMDIR 19 |
#define I_SHELL 20 |
#define I_SHELL 20 |
|
#define I_SYMLINK 21 |
|
#define I_VERSION 22 |
|
|
struct CMD { |
struct CMD { |
const char *c; |
const char *c; |
|
|
{ "lchdir", I_LCHDIR }, |
{ "lchdir", I_LCHDIR }, |
{ "lls", I_LLS }, |
{ "lls", I_LLS }, |
{ "lmkdir", I_LMKDIR }, |
{ "lmkdir", I_LMKDIR }, |
|
{ "ln", I_SYMLINK }, |
{ "lpwd", I_LPWD }, |
{ "lpwd", I_LPWD }, |
{ "ls", I_LS }, |
{ "ls", I_LS }, |
{ "lumask", I_LUMASK }, |
{ "lumask", I_LUMASK }, |
|
|
{ "rename", I_RENAME }, |
{ "rename", I_RENAME }, |
{ "rm", I_RM }, |
{ "rm", I_RM }, |
{ "rmdir", I_RMDIR }, |
{ "rmdir", I_RMDIR }, |
|
{ "symlink", I_SYMLINK }, |
|
{ "version", I_VERSION }, |
{ "!", I_SHELL }, |
{ "!", I_SHELL }, |
{ "?", I_HELP }, |
{ "?", I_HELP }, |
{ NULL, -1} |
{ NULL, -1} |
|
|
printf("help Display this help text\n"); |
printf("help Display this help text\n"); |
printf("get remote-path [local-path] Download file\n"); |
printf("get remote-path [local-path] Download file\n"); |
printf("lls [ls-options [path]] Display local directory listing\n"); |
printf("lls [ls-options [path]] Display local directory listing\n"); |
|
printf("ln oldpath newpath Symlink remote file\n"); |
printf("lmkdir path Create local directory\n"); |
printf("lmkdir path Create local directory\n"); |
printf("lpwd Print local working directory\n"); |
printf("lpwd Print local working directory\n"); |
printf("ls [path] Display remote directory listing\n"); |
printf("ls [path] Display remote directory listing\n"); |
|
|
printf("rename oldpath newpath Rename remote file\n"); |
printf("rename oldpath newpath Rename remote file\n"); |
printf("rmdir path Remove remote directory\n"); |
printf("rmdir path Remove remote directory\n"); |
printf("rm path Delete remote file\n"); |
printf("rm path Delete remote file\n"); |
|
printf("symlink oldpath newpath Symlink remote file\n"); |
|
printf("version Show SFTP version\n"); |
printf("!command Execute 'command' in local shell\n"); |
printf("!command Execute 'command' in local shell\n"); |
printf("! Escape to local shell\n"); |
printf("! Escape to local shell\n"); |
printf("? Synonym for help\n"); |
printf("? Synonym for help\n"); |
|
|
} |
} |
|
|
char * |
char * |
|
path_append(char *p1, char *p2) |
|
{ |
|
char *ret; |
|
int len = strlen(p1) + strlen(p2) + 2; |
|
|
|
ret = xmalloc(len); |
|
strlcpy(ret, p1, len); |
|
strlcat(ret, "/", len); |
|
strlcat(ret, p2, len); |
|
|
|
return(ret); |
|
} |
|
|
|
char * |
make_absolute(char *p, char *pwd) |
make_absolute(char *p, char *pwd) |
{ |
{ |
char buf[2048]; |
char *abs; |
|
|
/* Derelativise */ |
/* Derelativise */ |
if (p && p[0] != '/') { |
if (p && p[0] != '/') { |
snprintf(buf, sizeof(buf), "%s/%s", pwd, p); |
abs = path_append(pwd, p); |
xfree(p); |
xfree(p); |
p = xstrdup(buf); |
return(abs); |
|
} else |
|
return(p); |
|
} |
|
|
|
int |
|
infer_path(const char *p, char **ifp) |
|
{ |
|
char *cp; |
|
|
|
cp = strrchr(p, '/'); |
|
if (cp == NULL) { |
|
*ifp = xstrdup(p); |
|
return(0); |
} |
} |
|
|
return(p); |
if (!cp[1]) { |
|
error("Invalid path"); |
|
return(-1); |
|
} |
|
|
|
*ifp = xstrdup(cp + 1); |
|
return(0); |
} |
} |
|
|
int |
int |
|
|
/* Check for quoted filenames */ |
/* Check for quoted filenames */ |
if (*cp == '\"' || *cp == '\'') { |
if (*cp == '\"' || *cp == '\'') { |
quot = *cp++; |
quot = *cp++; |
|
|
end = strchr(cp, quot); |
end = strchr(cp, quot); |
if (end == NULL) { |
if (end == NULL) { |
error("Unterminated quote"); |
error("Unterminated quote"); |
|
|
} |
} |
|
|
int |
int |
infer_path(const char *p, char **ifp) |
is_dir(char *path) |
{ |
{ |
char *cp; |
struct stat sb; |
|
|
debug("XXX: P = \"%s\"", p); |
/* XXX: report errors? */ |
|
if (stat(path, &sb) == -1) |
|
return(0); |
|
|
cp = strrchr(p, '/'); |
return(sb.st_mode & S_IFDIR); |
if (cp == NULL) { |
} |
*ifp = xstrdup(p); |
|
|
int |
|
remote_is_dir(int in, int out, char *path) |
|
{ |
|
Attrib *a; |
|
|
|
/* XXX: report errors? */ |
|
if ((a = do_stat(in, out, path, 1)) == NULL) |
return(0); |
return(0); |
|
if (!(a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)) |
|
return(0); |
|
return(a->perm & S_IFDIR); |
|
} |
|
|
|
int |
|
process_get(int in, int out, char *src, char *dst, char *pwd, int pflag) |
|
{ |
|
char *abs_src = NULL; |
|
char *abs_dst = NULL; |
|
char *tmp; |
|
glob_t g; |
|
int err = 0; |
|
int i; |
|
|
|
abs_src = xstrdup(src); |
|
abs_src = make_absolute(abs_src, pwd); |
|
|
|
memset(&g, 0, sizeof(g)); |
|
debug3("Looking up %s", abs_src); |
|
if (remote_glob(in, out, abs_src, 0, NULL, &g)) { |
|
error("File \"%s\" not found.", abs_src); |
|
err = -1; |
|
goto out; |
} |
} |
|
|
if (!cp[1]) { |
/* Only one match, dst may be file, directory or unspecified */ |
error("Invalid path"); |
if (g.gl_pathv[0] && g.gl_matchc == 1) { |
return(-1); |
if (dst) { |
|
/* If directory specified, append filename */ |
|
if (is_dir(dst)) { |
|
if (infer_path(g.gl_pathv[0], &tmp)) { |
|
err = 1; |
|
goto out; |
|
} |
|
abs_dst = path_append(dst, tmp); |
|
xfree(tmp); |
|
} else |
|
abs_dst = xstrdup(dst); |
|
} else if (infer_path(g.gl_pathv[0], &abs_dst)) { |
|
err = -1; |
|
goto out; |
|
} |
|
printf("Fetching %s to %s\n", g.gl_pathv[0], abs_dst); |
|
err = do_download(in, out, g.gl_pathv[0], abs_dst, pflag); |
|
goto out; |
} |
} |
|
|
*ifp = xstrdup(cp + 1); |
/* Multiple matches, dst may be directory or unspecified */ |
return(0); |
if (dst && !is_dir(dst)) { |
|
error("Multiple files match, but \"%s\" is not a directory", |
|
dst); |
|
err = -1; |
|
goto out; |
|
} |
|
|
|
for(i = 0; g.gl_pathv[i]; i++) { |
|
if (infer_path(g.gl_pathv[i], &tmp)) { |
|
err = -1; |
|
goto out; |
|
} |
|
if (dst) { |
|
abs_dst = path_append(dst, tmp); |
|
xfree(tmp); |
|
} else |
|
abs_dst = tmp; |
|
|
|
printf("Fetching %s to %s\n", g.gl_pathv[i], abs_dst); |
|
if (do_download(in, out, g.gl_pathv[i], abs_dst, pflag) == -1) |
|
err = -1; |
|
xfree(abs_dst); |
|
abs_dst = NULL; |
|
} |
|
|
|
out: |
|
xfree(abs_src); |
|
if (abs_dst) |
|
xfree(abs_dst); |
|
globfree(&g); |
|
return(err); |
} |
} |
|
|
int |
int |
|
process_put(int in, int out, char *src, char *dst, char *pwd, int pflag) |
|
{ |
|
char *tmp_dst = NULL; |
|
char *abs_dst = NULL; |
|
char *tmp; |
|
glob_t g; |
|
int err = 0; |
|
int i; |
|
|
|
if (dst) { |
|
tmp_dst = xstrdup(dst); |
|
tmp_dst = make_absolute(tmp_dst, pwd); |
|
} |
|
|
|
memset(&g, 0, sizeof(g)); |
|
debug3("Looking up %s", src); |
|
if (glob(src, 0, NULL, &g)) { |
|
error("File \"%s\" not found.", src); |
|
err = -1; |
|
goto out; |
|
} |
|
|
|
/* Only one match, dst may be file, directory or unspecified */ |
|
if (g.gl_pathv[0] && g.gl_matchc == 1) { |
|
if (tmp_dst) { |
|
/* If directory specified, append filename */ |
|
if (remote_is_dir(in, out, tmp_dst)) { |
|
if (infer_path(g.gl_pathv[0], &tmp)) { |
|
err = 1; |
|
goto out; |
|
} |
|
abs_dst = path_append(tmp_dst, tmp); |
|
xfree(tmp); |
|
} else |
|
abs_dst = xstrdup(tmp_dst); |
|
} else if (infer_path(g.gl_pathv[0], &abs_dst)) { |
|
err = -1; |
|
goto out; |
|
} |
|
printf("Uploading %s to %s\n", g.gl_pathv[0], abs_dst); |
|
err = do_upload(in, out, g.gl_pathv[0], abs_dst, pflag); |
|
goto out; |
|
} |
|
|
|
/* Multiple matches, dst may be directory or unspecified */ |
|
if (tmp_dst && !remote_is_dir(in, out, tmp_dst)) { |
|
error("Multiple files match, but \"%s\" is not a directory", |
|
tmp_dst); |
|
err = -1; |
|
goto out; |
|
} |
|
|
|
for(i = 0; g.gl_pathv[i]; i++) { |
|
if (infer_path(g.gl_pathv[i], &tmp)) { |
|
err = -1; |
|
goto out; |
|
} |
|
if (tmp_dst) { |
|
abs_dst = path_append(tmp_dst, tmp); |
|
xfree(tmp); |
|
} else |
|
abs_dst = make_absolute(tmp, pwd); |
|
|
|
printf("Uploading %s to %s\n", g.gl_pathv[i], abs_dst); |
|
if (do_upload(in, out, g.gl_pathv[i], abs_dst, pflag) == -1) |
|
err = -1; |
|
} |
|
|
|
out: |
|
if (abs_dst) |
|
xfree(abs_dst); |
|
if (tmp_dst) |
|
xfree(tmp_dst); |
|
return(err); |
|
} |
|
|
|
int |
parse_args(const char **cpp, int *pflag, unsigned long *n_arg, |
parse_args(const char **cpp, int *pflag, unsigned long *n_arg, |
char **path1, char **path2) |
char **path1, char **path2) |
{ |
{ |
|
|
/* Try to get second pathname (optional) */ |
/* Try to get second pathname (optional) */ |
if (get_pathname(&cp, path2)) |
if (get_pathname(&cp, path2)) |
return(-1); |
return(-1); |
/* Otherwise try to guess it from first path */ |
|
if (*path2 == NULL && infer_path(*path1, path2)) |
|
return(-1); |
|
break; |
break; |
case I_RENAME: |
case I_RENAME: |
/* Get first pathname (mandatory) */ |
case I_SYMLINK: |
if (get_pathname(&cp, path1)) |
if (get_pathname(&cp, path1)) |
return(-1); |
return(-1); |
if (get_pathname(&cp, path2)) |
if (get_pathname(&cp, path2)) |
|
|
case I_PWD: |
case I_PWD: |
case I_LPWD: |
case I_LPWD: |
case I_HELP: |
case I_HELP: |
|
case I_VERSION: |
break; |
break; |
default: |
default: |
fatal("Command not implemented"); |
fatal("Command not implemented"); |
|
|
parse_dispatch_command(int in, int out, const char *cmd, char **pwd) |
parse_dispatch_command(int in, int out, const char *cmd, char **pwd) |
{ |
{ |
char *path1, *path2, *tmp; |
char *path1, *path2, *tmp; |
int pflag, cmdnum; |
int pflag, cmdnum, i; |
unsigned long n_arg; |
unsigned long n_arg; |
Attrib a, *aa; |
Attrib a, *aa; |
char path_buf[PATH_MAX]; |
char path_buf[MAXPATHLEN]; |
|
int err = 0; |
|
glob_t g; |
|
|
path1 = path2 = NULL; |
path1 = path2 = NULL; |
cmdnum = parse_args(&cmd, &pflag, &n_arg, &path1, &path2); |
cmdnum = parse_args(&cmd, &pflag, &n_arg, &path1, &path2); |
|
|
|
memset(&g, 0, sizeof(g)); |
|
|
/* Perform command */ |
/* Perform command */ |
switch (cmdnum) { |
switch (cmdnum) { |
case -1: |
case -1: |
break; |
break; |
case I_GET: |
case I_GET: |
path1 = make_absolute(path1, *pwd); |
err = process_get(in, out, path1, path2, *pwd, pflag); |
do_download(in, out, path1, path2, pflag); |
|
break; |
break; |
case I_PUT: |
case I_PUT: |
path2 = make_absolute(path2, *pwd); |
err = process_put(in, out, path1, path2, *pwd, pflag); |
do_upload(in, out, path1, path2, pflag); |
break; |
break; |
case I_RENAME: |
case I_RENAME: |
|
path1 = make_absolute(path1, *pwd); |
path1 = make_absolute(path1, *pwd); |
path2 = make_absolute(path2, *pwd); |
path2 = make_absolute(path2, *pwd); |
do_rename(in, out, path1, path2); |
err = do_rename(in, out, path1, path2); |
break; |
break; |
|
case I_SYMLINK: |
|
if (version < 3) { |
|
error("The server (version %d) does not support " |
|
"this operation", version); |
|
err = -1; |
|
} else { |
|
path2 = make_absolute(path2, *pwd); |
|
err = do_symlink(in, out, path1, path2); |
|
} |
|
break; |
case I_RM: |
case I_RM: |
path1 = make_absolute(path1, *pwd); |
path1 = make_absolute(path1, *pwd); |
do_rm(in, out, path1); |
remote_glob(in, out, path1, GLOB_NOCHECK, NULL, &g); |
|
for(i = 0; g.gl_pathv[i]; i++) { |
|
printf("Removing %s\n", g.gl_pathv[i]); |
|
if (do_rm(in, out, g.gl_pathv[i]) == -1) |
|
err = -1; |
|
} |
break; |
break; |
case I_MKDIR: |
case I_MKDIR: |
path1 = make_absolute(path1, *pwd); |
path1 = make_absolute(path1, *pwd); |
attrib_clear(&a); |
attrib_clear(&a); |
a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS; |
a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS; |
a.perm = 0777; |
a.perm = 0777; |
do_mkdir(in, out, path1, &a); |
err = do_mkdir(in, out, path1, &a); |
break; |
break; |
case I_RMDIR: |
case I_RMDIR: |
path1 = make_absolute(path1, *pwd); |
path1 = make_absolute(path1, *pwd); |
do_rmdir(in, out, path1); |
err = do_rmdir(in, out, path1); |
break; |
break; |
case I_CHDIR: |
case I_CHDIR: |
path1 = make_absolute(path1, *pwd); |
path1 = make_absolute(path1, *pwd); |
if ((tmp = do_realpath(in, out, path1)) == NULL) |
if ((tmp = do_realpath(in, out, path1)) == NULL) { |
|
err = 1; |
break; |
break; |
if ((aa = do_stat(in, out, tmp)) == NULL) { |
} |
|
if ((aa = do_stat(in, out, tmp, 0)) == NULL) { |
xfree(tmp); |
xfree(tmp); |
|
err = 1; |
break; |
break; |
} |
} |
if (!(aa->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)) { |
if (!(aa->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)) { |
error("Can't change directory: Can't check target"); |
error("Can't change directory: Can't check target"); |
xfree(tmp); |
xfree(tmp); |
|
err = 1; |
break; |
break; |
} |
} |
if (!S_ISDIR(aa->perm)) { |
if (!S_ISDIR(aa->perm)) { |
error("Can't change directory: \"%s\" is not " |
error("Can't change directory: \"%s\" is not " |
"a directory", tmp); |
"a directory", tmp); |
xfree(tmp); |
xfree(tmp); |
|
err = 1; |
break; |
break; |
} |
} |
xfree(*pwd); |
xfree(*pwd); |
|
|
break; |
break; |
xfree(path1); |
xfree(path1); |
path1 = tmp; |
path1 = tmp; |
if ((aa = do_stat(in, out, path1)) == NULL) |
if ((aa = do_stat(in, out, path1, 0)) == NULL) |
break; |
break; |
if ((aa->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) && |
if ((aa->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) && |
!S_ISDIR(aa->perm)) { |
!S_ISDIR(aa->perm)) { |
error("Can't ls: \"%s\" is not a directory", path1); |
error("Can't ls: \"%s\" is not a directory", path1); |
break; |
break; |
|
|
do_ls(in, out, path1); |
do_ls(in, out, path1); |
break; |
break; |
case I_LCHDIR: |
case I_LCHDIR: |
if (chdir(path1) == -1) |
if (chdir(path1) == -1) { |
error("Couldn't change local directory to " |
error("Couldn't change local directory to " |
"\"%s\": %s", path1, strerror(errno)); |
"\"%s\": %s", path1, strerror(errno)); |
|
err = 1; |
|
} |
break; |
break; |
case I_LMKDIR: |
case I_LMKDIR: |
if (mkdir(path1, 0777) == -1) |
if (mkdir(path1, 0777) == -1) { |
error("Couldn't create local directory " |
error("Couldn't create local directory " |
"\"%s\": %s", path1, strerror(errno)); |
"\"%s\": %s", path1, strerror(errno)); |
|
err = 1; |
|
} |
break; |
break; |
case I_LLS: |
case I_LLS: |
local_do_ls(cmd); |
local_do_ls(cmd); |
|
|
attrib_clear(&a); |
attrib_clear(&a); |
a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS; |
a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS; |
a.perm = n_arg; |
a.perm = n_arg; |
do_setstat(in, out, path1, &a); |
remote_glob(in, out, path1, GLOB_NOCHECK, NULL, &g); |
|
for(i = 0; g.gl_pathv[i]; i++) { |
|
printf("Changing mode on %s\n", g.gl_pathv[i]); |
|
do_setstat(in, out, g.gl_pathv[i], &a); |
|
} |
break; |
break; |
case I_CHOWN: |
case I_CHOWN: |
path1 = make_absolute(path1, *pwd); |
path1 = make_absolute(path1, *pwd); |
if (!(aa = do_stat(in, out, path1))) |
remote_glob(in, out, path1, GLOB_NOCHECK, NULL, &g); |
break; |
for(i = 0; g.gl_pathv[i]; i++) { |
if (!(aa->flags & SSH2_FILEXFER_ATTR_UIDGID)) { |
if (!(aa = do_stat(in, out, g.gl_pathv[i], 0))) |
error("Can't get current ownership of " |
continue; |
"remote file \"%s\"", path1); |
if (!(aa->flags & SSH2_FILEXFER_ATTR_UIDGID)) { |
break; |
error("Can't get current ownership of " |
|
"remote file \"%s\"", g.gl_pathv[i]); |
|
continue; |
|
} |
|
printf("Changing owner on %s\n", g.gl_pathv[i]); |
|
aa->flags &= SSH2_FILEXFER_ATTR_UIDGID; |
|
aa->uid = n_arg; |
|
do_setstat(in, out, g.gl_pathv[i], aa); |
} |
} |
aa->flags &= SSH2_FILEXFER_ATTR_UIDGID; |
|
aa->uid = n_arg; |
|
do_setstat(in, out, path1, aa); |
|
break; |
break; |
case I_CHGRP: |
case I_CHGRP: |
path1 = make_absolute(path1, *pwd); |
path1 = make_absolute(path1, *pwd); |
if (!(aa = do_stat(in, out, path1))) |
remote_glob(in, out, path1, GLOB_NOCHECK, NULL, &g); |
break; |
for(i = 0; g.gl_pathv[i]; i++) { |
if (!(aa->flags & SSH2_FILEXFER_ATTR_UIDGID)) { |
if (!(aa = do_stat(in, out, g.gl_pathv[i], 0))) |
error("Can't get current ownership of " |
continue; |
"remote file \"%s\"", path1); |
if (!(aa->flags & SSH2_FILEXFER_ATTR_UIDGID)) { |
break; |
error("Can't get current ownership of " |
|
"remote file \"%s\"", g.gl_pathv[i]); |
|
continue; |
|
} |
|
printf("Changing group on %s\n", g.gl_pathv[i]); |
|
aa->flags &= SSH2_FILEXFER_ATTR_UIDGID; |
|
aa->gid = n_arg; |
|
do_setstat(in, out, g.gl_pathv[i], aa); |
} |
} |
aa->flags &= SSH2_FILEXFER_ATTR_UIDGID; |
|
aa->gid = n_arg; |
|
do_setstat(in, out, path1, aa); |
|
break; |
break; |
case I_PWD: |
case I_PWD: |
printf("Remote working directory: %s\n", *pwd); |
printf("Remote working directory: %s\n", *pwd); |
break; |
break; |
case I_LPWD: |
case I_LPWD: |
if (!getcwd(path_buf, sizeof(path_buf))) |
if (!getcwd(path_buf, sizeof(path_buf))) |
error("Couldn't get local cwd: %s\n", |
error("Couldn't get local cwd: %s", |
strerror(errno)); |
strerror(errno)); |
else |
else |
printf("Local working directory: %s\n", |
printf("Local working directory: %s\n", |
|
|
case I_HELP: |
case I_HELP: |
help(); |
help(); |
break; |
break; |
|
case I_VERSION: |
|
printf("SFTP protocol version %d\n", version); |
|
break; |
default: |
default: |
fatal("%d is not implemented", cmdnum); |
fatal("%d is not implemented", cmdnum); |
} |
} |
|
|
|
if (g.gl_pathc) |
|
globfree(&g); |
if (path1) |
if (path1) |
xfree(path1); |
xfree(path1); |
if (path2) |
if (path2) |
xfree(path2); |
xfree(path2); |
|
|
|
/* If an error occurs in batch mode we should abort. */ |
|
if (infile != stdin && err > 0) |
|
return -1; |
|
|
return(0); |
return(0); |
} |
} |
|
|
|
|
char *pwd; |
char *pwd; |
char cmd[2048]; |
char cmd[2048]; |
|
|
|
version = do_init(fd_in, fd_out); |
|
if (version == -1) |
|
fatal("Couldn't initialise connection to server"); |
|
|
pwd = do_realpath(fd_in, fd_out, "."); |
pwd = do_realpath(fd_in, fd_out, "."); |
if (pwd == NULL) |
if (pwd == NULL) |
fatal("Need cwd"); |
fatal("Need cwd"); |
|
|
setvbuf(stdout, NULL, _IOLBF, 0); |
setvbuf(stdout, NULL, _IOLBF, 0); |
setvbuf(stdin, NULL, _IOLBF, 0); |
setvbuf(infile, NULL, _IOLBF, 0); |
|
|
for(;;) { |
for(;;) { |
char *cp; |
char *cp; |
|
|
printf("sftp> "); |
printf("sftp> "); |
|
|
/* XXX: use libedit */ |
/* XXX: use libedit */ |
if (fgets(cmd, sizeof(cmd), stdin) == NULL) { |
if (fgets(cmd, sizeof(cmd), infile) == NULL) { |
printf("\n"); |
printf("\n"); |
break; |
break; |
} |
} else if (infile != stdin) /* Bluff typing */ |
|
printf("%s", cmd); |
|
|
cp = strrchr(cmd, '\n'); |
cp = strrchr(cmd, '\n'); |
if (cp) |
if (cp) |
*cp = '\0'; |
*cp = '\0'; |
|
|
if (parse_dispatch_command(fd_in, fd_out, cmd, &pwd)) |
if (parse_dispatch_command(fd_in, fd_out, cmd, &pwd)) |
break; |
break; |
} |
} |