Skip to content

Commit

Permalink
- djm@cvs.openbsd.org 2008/04/18 12:32:11
Browse files Browse the repository at this point in the history
     [sftp-client.c sftp-client.h sftp-server.c sftp.1 sftp.c sftp.h]
     introduce sftp extension methods statvfs@openssh.com and
     fstatvfs@openssh.com that implement statvfs(2)-like operations,
     based on a patch from miklos AT szeredi.hu (bz#1399)
     also add a "df" command to the sftp client that uses the
     statvfs@openssh.com to produce a df(1)-like display of filesystem
     space and inode utilisation
     ok markus@
  • Loading branch information
djmdjm committed May 19, 2008
1 parent 354c48c commit d671e5a
Show file tree
Hide file tree
Showing 7 changed files with 339 additions and 15 deletions.
11 changes: 10 additions & 1 deletion ChangeLog
Expand Up @@ -21,6 +21,15 @@
Use arc4random_uniform() when the desired random number upper bound
is not a power of two
ok deraadt@ millert@
- djm@cvs.openbsd.org 2008/04/18 12:32:11
[sftp-client.c sftp-client.h sftp-server.c sftp.1 sftp.c sftp.h]
introduce sftp extension methods statvfs@openssh.com and
fstatvfs@openssh.com that implement statvfs(2)-like operations,
based on a patch from miklos AT szeredi.hu (bz#1399)
also add a "df" command to the sftp client that uses the
statvfs@openssh.com to produce a df(1)-like display of filesystem
space and inode utilisation
ok markus@

20080403
- (djm) [openbsd-compat/bsd-poll.c] Include stdlib.h to avoid compile-
Expand Down Expand Up @@ -3881,4 +3890,4 @@
OpenServer 6 and add osr5bigcrypt support so when someone migrates
passwords between UnixWare and OpenServer they will still work. OK dtucker@

$Id: ChangeLog,v 1.4910 2008/05/19 04:50:00 djm Exp $
$Id: ChangeLog,v 1.4911 2008/05/19 04:53:33 djm Exp $
120 changes: 117 additions & 3 deletions sftp-client.c
@@ -1,4 +1,4 @@
/* $OpenBSD: sftp-client.c,v 1.81 2008/03/23 12:54:01 djm Exp $ */
/* $OpenBSD: sftp-client.c,v 1.82 2008/04/18 12:32:11 djm Exp $ */
/*
* Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
*
Expand All @@ -24,6 +24,7 @@

#include <sys/types.h>
#include <sys/param.h>
#include <sys/statvfs.h>
#include "openbsd-compat/sys-queue.h"
#ifdef HAVE_SYS_STAT_H
# include <sys/stat.h>
Expand Down Expand Up @@ -65,7 +66,9 @@ struct sftp_conn {
u_int num_requests;
u_int version;
u_int msg_id;
#define SFTP_EXT_POSIX_RENAME 1
#define SFTP_EXT_POSIX_RENAME 0x00000001
#define SFTP_EXT_STATVFS 0x00000002
#define SFTP_EXT_FSTATVFS 0x00000004
u_int exts;
};

Expand Down Expand Up @@ -238,6 +241,56 @@ get_decode_stat(int fd, u_int expected_id, int quiet)
return(a);
}

static int
get_decode_statvfs(int fd, struct statvfs *st, u_int expected_id, int quiet)
{
Buffer msg;
u_int type, id, flag;

buffer_init(&msg);
get_msg(fd, &msg);

type = buffer_get_char(&msg);
id = buffer_get_int(&msg);

debug3("Received statvfs reply T:%u I:%u", type, id);
if (id != expected_id)
fatal("ID mismatch (%u != %u)", id, expected_id);
if (type == SSH2_FXP_STATUS) {
int status = buffer_get_int(&msg);

if (quiet)
debug("Couldn't statvfs: %s", fx2txt(status));
else
error("Couldn't statvfs: %s", fx2txt(status));
buffer_free(&msg);
return -1;
} else if (type != SSH2_FXP_EXTENDED_REPLY) {
fatal("Expected SSH2_FXP_EXTENDED_REPLY(%u) packet, got %u",
SSH2_FXP_EXTENDED_REPLY, type);
}

bzero(st, sizeof(*st));
st->f_bsize = buffer_get_int(&msg);
st->f_frsize = buffer_get_int(&msg);
st->f_blocks = buffer_get_int64(&msg);
st->f_bfree = buffer_get_int64(&msg);
st->f_bavail = buffer_get_int64(&msg);
st->f_files = buffer_get_int64(&msg);
st->f_ffree = buffer_get_int64(&msg);
st->f_favail = buffer_get_int64(&msg);
st->f_fsid = buffer_get_int(&msg);
flag = buffer_get_int(&msg);
st->f_namemax = buffer_get_int(&msg);

st->f_flag = (flag & SSH2_FXE_STATVFS_ST_RDONLY) ? ST_RDONLY : 0;
st->f_flag |= (flag & SSH2_FXE_STATVFS_ST_NOSUID) ? ST_NOSUID : 0;

buffer_free(&msg);

return 0;
}

struct sftp_conn *
do_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests)
{
Expand Down Expand Up @@ -272,8 +325,15 @@ do_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests)
char *value = buffer_get_string(&msg, NULL);

debug2("Init extension: \"%s\"", name);
if (strcmp(name, "posix-rename@openssh.com") == 0)
if (strcmp(name, "posix-rename@openssh.com") == 0 &&
strcmp(value, "1") == 0)
exts |= SFTP_EXT_POSIX_RENAME;
if (strcmp(name, "statvfs@openssh.com") == 0 &&
strcmp(value, "1") == 0)
exts |= SFTP_EXT_STATVFS;
if (strcmp(name, "fstatvfs@openssh.com") == 0 &&
strcmp(value, "1") == 0)
exts |= SFTP_EXT_FSTATVFS;
xfree(name);
xfree(value);
}
Expand Down Expand Up @@ -749,6 +809,60 @@ do_readlink(struct sftp_conn *conn, char *path)
}
#endif

int
do_statvfs(struct sftp_conn *conn, const char *path, struct statvfs *st,
int quiet)
{
Buffer msg;
u_int id;

if ((conn->exts & SFTP_EXT_STATVFS) == 0) {
error("Server does not support statvfs@openssh.com extension");
return -1;
}

id = conn->msg_id++;

buffer_init(&msg);
buffer_clear(&msg);
buffer_put_char(&msg, SSH2_FXP_EXTENDED);
buffer_put_int(&msg, id);
buffer_put_cstring(&msg, "statvfs@openssh.com");
buffer_put_cstring(&msg, path);
send_msg(conn->fd_out, &msg);
buffer_free(&msg);

return get_decode_statvfs(conn->fd_in, st, id, quiet);
}

#ifdef notyet
int
do_fstatvfs(struct sftp_conn *conn, const char *handle, u_int handle_len,
struct statvfs *st, int quiet)
{
Buffer msg;
u_int id;

if ((conn->exts & SFTP_EXT_FSTATVFS) == 0) {
error("Server does not support fstatvfs@openssh.com extension");
return -1;
}

id = conn->msg_id++;

buffer_init(&msg);
buffer_clear(&msg);
buffer_put_char(&msg, SSH2_FXP_EXTENDED);
buffer_put_int(&msg, id);
buffer_put_cstring(&msg, "fstatvfs@openssh.com");
buffer_put_string(&msg, handle, handle_len);
send_msg(conn->fd_out, &msg);
buffer_free(&msg);

return get_decode_statvfs(conn->fd_in, st, id, quiet);
}
#endif

static void
send_read_request(int fd_out, u_int id, u_int64_t offset, u_int len,
char *handle, u_int handle_len)
Expand Down
6 changes: 5 additions & 1 deletion sftp-client.h
@@ -1,4 +1,4 @@
/* $OpenBSD: sftp-client.h,v 1.15 2008/01/11 07:22:28 chl Exp $ */
/* $OpenBSD: sftp-client.h,v 1.16 2008/04/18 12:32:11 djm Exp $ */

/*
* Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
Expand Down Expand Up @@ -70,6 +70,10 @@ int do_fsetstat(struct sftp_conn *, char *, u_int, Attrib *);
/* Canonicalise 'path' - caller must free result */
char *do_realpath(struct sftp_conn *, char *);

/* Get statistics for filesystem hosting file at "path" */
struct statvfs;
int do_statvfs(struct sftp_conn *, const char *, struct statvfs *, int);

/* Rename 'oldpath' to 'newpath' */
int do_rename(struct sftp_conn *, char *, char *);

Expand Down
75 changes: 74 additions & 1 deletion sftp-server.c
@@ -1,4 +1,4 @@
/* $OpenBSD: sftp-server.c,v 1.78 2008/02/27 20:21:15 djm Exp $ */
/* $OpenBSD: sftp-server.c,v 1.79 2008/04/18 12:32:11 djm Exp $ */
/*
* Copyright (c) 2000-2004 Markus Friedl. All rights reserved.
*
Expand All @@ -23,6 +23,8 @@
#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
#endif
#include <sys/mount.h>
#include <sys/statvfs.h>

#include <dirent.h>
#include <errno.h>
Expand Down Expand Up @@ -475,6 +477,33 @@ send_attrib(u_int32_t id, const Attrib *a)
buffer_free(&msg);
}

static void
send_statvfs(u_int32_t id, struct statvfs *st)
{
Buffer msg;
u_int64_t flag;

flag = (st->f_flag & ST_RDONLY) ? SSH2_FXE_STATVFS_ST_RDONLY : 0;
flag |= (st->f_flag & ST_NOSUID) ? SSH2_FXE_STATVFS_ST_NOSUID : 0;

buffer_init(&msg);
buffer_put_char(&msg, SSH2_FXP_EXTENDED_REPLY);
buffer_put_int(&msg, id);
buffer_put_int(&msg, st->f_bsize);
buffer_put_int(&msg, st->f_frsize);
buffer_put_int64(&msg, st->f_blocks);
buffer_put_int64(&msg, st->f_bfree);
buffer_put_int64(&msg, st->f_bavail);
buffer_put_int64(&msg, st->f_files);
buffer_put_int64(&msg, st->f_ffree);
buffer_put_int64(&msg, st->f_favail);
buffer_put_int(&msg, st->f_fsid);
buffer_put_int(&msg, flag);
buffer_put_int(&msg, st->f_namemax);
send_msg(&msg);
buffer_free(&msg);
}

/* parse incoming */

static void
Expand All @@ -490,6 +519,10 @@ process_init(void)
/* POSIX rename extension */
buffer_put_cstring(&msg, "posix-rename@openssh.com");
buffer_put_cstring(&msg, "1"); /* version */
buffer_put_cstring(&msg, "statvfs@openssh.com");
buffer_put_cstring(&msg, "1"); /* version */
buffer_put_cstring(&msg, "fstatvfs@openssh.com");
buffer_put_cstring(&msg, "1"); /* version */
send_msg(&msg);
buffer_free(&msg);
}
Expand Down Expand Up @@ -1099,6 +1132,42 @@ process_extended_posix_rename(u_int32_t id)
xfree(newpath);
}

static void
process_extended_statvfs(u_int32_t id)
{
char *path;
struct statvfs st;

path = get_string(NULL);
debug3("request %u: statfs", id);
logit("statfs \"%s\"", path);

if (statvfs(path, &st) != 0)
send_status(id, errno_to_portable(errno));
else
send_statvfs(id, &st);
xfree(path);
}

static void
process_extended_fstatvfs(u_int32_t id)
{
int handle, fd;
struct statvfs st;

handle = get_handle();
debug("request %u: fstatvfs \"%s\" (handle %u)",
id, handle_to_name(handle), handle);
if ((fd = handle_to_fd(handle)) < 0) {
send_status(id, SSH2_FX_FAILURE);
return;
}
if (fstatvfs(fd, &st) != 0)
send_status(id, errno_to_portable(errno));
else
send_statvfs(id, &st);
}

static void
process_extended(void)
{
Expand All @@ -1109,6 +1178,10 @@ process_extended(void)
request = get_string(NULL);
if (strcmp(request, "posix-rename@openssh.com") == 0)
process_extended_posix_rename(id);
else if (strcmp(request, "statvfs@openssh.com") == 0)
process_extended_statvfs(id);
else if (strcmp(request, "fstatvfs@openssh.com") == 0)
process_extended_fstatvfs(id);
else
send_status(id, SSH2_FX_OP_UNSUPPORTED); /* MUST */
xfree(request);
Expand Down
24 changes: 21 additions & 3 deletions sftp.1
@@ -1,4 +1,4 @@
.\" $OpenBSD: sftp.1,v 1.64 2007/05/31 19:20:16 jmc Exp $
.\" $OpenBSD: sftp.1,v 1.65 2008/04/18 12:32:11 djm Exp $
.\"
.\" Copyright (c) 2001 Damien Miller. All rights reserved.
.\"
Expand All @@ -22,7 +22,7 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
.Dd $Mdocdate: May 31 2007 $
.Dd $Mdocdate: April 18 2008 $
.Dt SFTP 1
.Os
.Sh NAME
Expand Down Expand Up @@ -112,7 +112,7 @@ will abort if any of the following
commands fail:
.Ic get , put , rename , ln ,
.Ic rm , mkdir , chdir , ls ,
.Ic lchdir , chmod , chown , chgrp , lpwd
.Ic lchdir , chmod , chown , chgrp , lpwd, df,
and
.Ic lmkdir .
Termination on error can be suppressed on a command by command basis by
Expand Down Expand Up @@ -272,6 +272,24 @@ may contain
characters and may match multiple files.
.Ar own
must be a numeric UID.
.It Xo Ic df
.Op Fl hi
.Op Ar path
.Xc
Display usage information for the filesystem holding the current directory
(or
.Ar path
if specified).
If the
.Fl h
flag is specified, the capacity information will be displayed using
"human-readable" suffixes.
The
.Fl i
flag requests display of inode information in addition to capacity information.
This command is only supported on servers that implement the
.Dq statvfs@openssh.com
extension.
.It Ic exit
Quit
.Nm sftp .
Expand Down

0 comments on commit d671e5a

Please sign in to comment.