/*
* Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* $OpenBSD: sftp.c,v 1.96 2007/01/03 04:09:15 stevesk Exp $ */
#include "includes.h"
#include <sys/types.h>
#include <sys/ioctl.h>
#ifdef HAVE_SYS_STAT_H
# include <sys/stat.h>
#endif
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <errno.h>
#ifdef HAVE_PATHS_H
# include <paths.h>
#endif
#ifdef USE_LIBEDIT
#include <histedit.h>
#else
#ifdef USE_LIBTECLA
#include <libtecla.h>
#define MAX_LINE_LEN 2048
#define MAX_CMD_HIST 10000
#endif /* USE_LIBTECLA */
#endif /* USE_LIBEDIT */
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdarg.h>
#include "xmalloc.h"
#include "log.h"
#include "pathnames.h"
#include "misc.h"
#include "sftp.h"
#include "buffer.h"
#include "sftp-common.h"
#include "sftp-client.h"
#ifdef HAVE___PROGNAME
extern char *__progname;
#else
char *__progname;
#endif
/* File to read commands from */
FILE* infile;
/* Are we in batchfile mode? */
int batchmode = 0;
/* Size of buffer used when copying files */
size_t copy_buffer_len = 32768;
/* Number of concurrent outstanding requests */
size_t num_requests = 16;
/* PID of ssh transport process */
static pid_t sshpid = -1;
/* This is set to 0 if the progressmeter is not desired. */
int showprogress = 1;
/* SIGINT received during command processing */
volatile sig_atomic_t interrupted = 0;
/* I wish qsort() took a separate ctx for the comparison function...*/
int sort_flag;
int remote_glob(struct sftp_conn *, const char *, int,
int (*)(const char *, int), glob_t *); /* proto for sftp-glob.c */
/* Separators for interactive commands */
#define WHITESPACE " \t\r\n"
/* ls flags */
#define LS_LONG_VIEW 0x01 /* Full view ala ls -l */
#define LS_SHORT_VIEW 0x02 /* Single row view ala ls -1 */
#define LS_NUMERIC_VIEW 0x04 /* Long view with numeric uid/gid */
#define LS_NAME_SORT 0x08 /* Sort by name (default) */
#define LS_TIME_SORT 0x10 /* Sort by mtime */
#define LS_SIZE_SORT 0x20 /* Sort by file size */
#define LS_REVERSE_SORT 0x40 /* Reverse sort order */
#define LS_SHOW_ALL 0x80 /* Don't skip filenames starting with '.' */
#define VIEW_FLAGS (LS_LONG_VIEW|LS_SHORT_VIEW|LS_NUMERIC_VIEW)
#define SORT_FLAGS (LS_NAME_SORT|LS_TIME_SORT|LS_SIZE_SORT)
/* Commands for interactive mode */
#define I_CHDIR 1
#define I_CHGRP 2
#define I_CHMOD 3
#define I_CHOWN 4
#define I_GET 5
#define I_HELP 6
#define I_LCHDIR 7
#define I_LLS 8
#define I_LMKDIR 9
#define I_LPWD 10
#define I_LS 11
#define I_LUMASK 12
#define I_MKDIR 13
#define I_PUT 14
#define I_PWD 15
#define I_QUIT 16
#define I_RENAME 17
#define I_RM 18
#define I_RMDIR 19
#define I_SHELL 20
#define I_SYMLINK 21
#define I_VERSION 22
#define I_PROGRESS 23
struct CMD {
const char *c;
const int n;
};
static const struct CMD cmds[] = {
{ "bye", I_QUIT },
{ "cd", I_CHDIR },
{ "chdir", I_CHDIR },
{ "chgrp", I_CHGRP },
{ "chmod", I_CHMOD },
{ "chown", I_CHOWN },
{ "dir", I_LS },
{ "exit", I_QUIT },
{ "get", I_GET },
{ "mget", I_GET },
{ "help", I_HELP },
{ "lcd", I_LCHDIR },
{ "lchdir", I_LCHDIR },
{ "lls", I_LLS },
{ "lmkdir", I_LMKDIR },
{ "ln", I_SYMLINK },
{ "lpwd", I_LPWD },
{ "ls", I_LS },
{ "lumask", I_LUMASK },
{ "mkdir", I_MKDIR },
{ "progress", I_PROGRESS },
{ "put", I_PUT },
{ "mput", I_PUT },
{ "pwd", I_PWD },
{ "quit", I_QUIT },
{ "rename", I_RENAME },
{ "rm", I_RM },
{ "rmdir", I_RMDIR },
{ "symlink", I_SYMLINK },
{ "version", I_VERSION },
{ "!", I_SHELL },
{ "?", I_HELP },
{ NULL, -1}
};
int interactive_loop(int fd_in, int fd_out, char *file1, char *file2);
/* ARGSUSED */
static void
killchild(int signo)
{
if (sshpid > 1) {
kill(sshpid, SIGTERM);
waitpid(sshpid, NULL, 0);
}
_exit(1);
}
/* ARGSUSED */
static void
cmd_interrupt(int signo)
{
const char msg[] = "\rInterrupt \n";
int olderrno = errno;
write(STDERR_FILENO, msg, sizeof(msg) - 1);
interrupted = 1;
errno = olderrno;
}
static void
help(void)
{
printf(gettext("Available commands:\n"
"cd path Change remote directory to 'path'\n"
"lcd path Change local directory to 'path'\n"
"chgrp grp path Change group of file 'path' to 'grp'\n"
"chmod mode path Change permissions of file 'path' to 'mode'\n"
"chown own path Change owner of file 'path' to 'own'\n"
"help Display this help text\n"
"get remote-path [local-path] Download file\n"
"lls [ls-options [path]] Display local directory listing\n"
"ln oldpath newpath Symlink remote file\n"
"lmkdir path Create local directory\n"
"lpwd Print local working directory\n"
"ls [path] Display remote directory listing\n"
"lumask umask Set local umask to 'umask'\n"
"mkdir path Create remote directory\n"
"progress Toggle display of progress meter\n"
"put local-path [remote-path] Upload file\n"
"pwd Display remote working directory\n"
"exit Quit sftp\n"
"quit Quit sftp\n"
"rename oldpath newpath Rename remote file\n"
"rmdir path Remove remote directory\n"
"rm path Delete remote file\n"
"symlink oldpath newpath Symlink remote file\n"
"version Show SFTP version\n"
"!command Execute 'command' in local shell\n"
"! Escape to local shell\n"
"? Synonym for help\n"));
}
static void
local_do_shell(const char *args)
{
int status;
char *shell;
pid_t pid;
if (!*args)
args = NULL;
if ((shell = getenv("SHELL")) == NULL)
shell = _PATH_BSHELL;
if ((pid = fork()) == -1)
fatal("Couldn't fork: %s", strerror(errno));
if (pid == 0) {
/* XXX: child has pipe fds to ssh subproc open - issue? */
if (args) {
debug3("Executing %s -c \"%s\"", shell, args);
execl(shell, shell, "-c", args, (char *)NULL);
} else {
debug3("Executing %s", shell);
execl(shell, shell, (char *)NULL);
}
fprintf(stderr, gettext("Couldn't execute \"%s\": %s\n"), shell,
strerror(errno));
_exit(1);
}
while (waitpid(pid, &status, 0) == -1)
if (errno != EINTR)
fatal("Couldn't wait for child: %s", strerror(errno));
if (!WIFEXITED(status))
error("Shell exited abnormally");
else if (WEXITSTATUS(status))
error("Shell exited with status %d", WEXITSTATUS(status));
}
static void
local_do_ls(const char *args)
{
if (!args || !*args)
local_do_shell(_PATH_LS);
else {
int len = strlen(_PATH_LS " ") + strlen(args) + 1;
char *buf = xmalloc(len);
/* XXX: quoting - rip quoting code from ftp? */
snprintf(buf, len, _PATH_LS " %s", args);
local_do_shell(buf);
xfree(buf);
}
}
/* Strip one path (usually the pwd) from the start of another */
static char *
path_strip(char *path, char *strip)
{
size_t len;
if (strip == NULL)
return (xstrdup(path));
len = strlen(strip);
if (strncmp(path,
- 1
- 2
- 3
前往页