Bugzilla – Attachment 1475 Details for
Bug 1399
add statfs extension to sftp-server
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
statvfs support for client and server
sftp-statvfs.diff (text/plain), 16.26 KB, created by
Damien Miller
on 2008-03-24 00:09:42 AEDT
(
hide
)
Description:
statvfs support for client and server
Filename:
MIME Type:
Creator:
Damien Miller
Created:
2008-03-24 00:09:42 AEDT
Size:
16.26 KB
patch
obsolete
>Index: sftp/Makefile >=================================================================== >RCS file: /cvs/src/usr.bin/ssh/sftp/Makefile,v >retrieving revision 1.10 >diff -u -p -r1.10 Makefile >--- sftp/Makefile 18 Apr 2006 10:44:28 -0000 1.10 >+++ sftp/Makefile 23 Mar 2008 13:05:17 -0000 >@@ -14,4 +14,4 @@ SRCS= sftp.c sftp-client.c sftp-common.c > > .include <bsd.prog.mk> > >-LDADD+= -ledit -ltermcap >+LDADD+= -ledit -ltermcap -lutil >Index: sftp.h >=================================================================== >RCS file: /cvs/src/usr.bin/ssh/sftp.h,v >retrieving revision 1.7 >diff -u -p -r1.7 sftp.h >--- sftp.h 8 Feb 2008 23:24:07 -0000 1.7 >+++ sftp.h 23 Mar 2008 13:05:17 -0000 >@@ -79,6 +79,10 @@ > #define SSH2_FXF_TRUNC 0x00000010 > #define SSH2_FXF_EXCL 0x00000020 > >+/* statvfs@openssh.com f_flag flags */ >+#define SSH2_FXE_STATVFS_ST_RDONLY 0x00000001 >+#define SSH2_FXE_STATVFS_ST_NOSUID 0x00000002 >+ > /* status messages */ > #define SSH2_FX_OK 0 > #define SSH2_FX_EOF 1 >Index: sftp.c >=================================================================== >RCS file: /cvs/src/usr.bin/ssh/sftp.c,v >retrieving revision 1.99 >diff -u -p -r1.99 sftp.c >--- sftp.c 20 Jan 2008 00:38:30 -0000 1.99 >+++ sftp.c 23 Mar 2008 13:05:17 -0000 >@@ -21,6 +21,7 @@ > #include <sys/stat.h> > #include <sys/socket.h> > #include <sys/param.h> >+#include <sys/statvfs.h> > > #include <ctype.h> > #include <errno.h> >@@ -32,6 +33,7 @@ > #include <stdio.h> > #include <string.h> > #include <unistd.h> >+#include <util.h> > #include <stdarg.h> > > #include "xmalloc.h" >@@ -92,6 +94,7 @@ int remote_glob(struct sftp_conn *, cons > #define I_CHGRP 2 > #define I_CHMOD 3 > #define I_CHOWN 4 >+#define I_DF 24 > #define I_GET 5 > #define I_HELP 6 > #define I_LCHDIR 7 >@@ -124,6 +127,7 @@ static const struct CMD cmds[] = { > { "chgrp", I_CHGRP }, > { "chmod", I_CHMOD }, > { "chown", I_CHOWN }, >+ { "df", I_DF }, > { "dir", I_LS }, > { "exit", I_QUIT }, > { "get", I_GET }, >@@ -188,6 +192,8 @@ help(void) > printf("chgrp grp path Change group of file 'path' to 'grp'\n"); > printf("chmod mode path Change permissions of file 'path' to 'mode'\n"); > printf("chown own path Change owner of file 'path' to 'own'\n"); >+ printf("df [path] Display statistics for current directory or\n"); >+ printf(" filesystem containing 'path'\n"); > printf("help Display this help text\n"); > printf("get remote-path [local-path] Download file\n"); > printf("lls [ls-options [path]] Display local directory listing\n"); >@@ -410,6 +416,33 @@ parse_ls_flags(char **argv, int argc, in > } > > static int >+parse_df_flags(const char *cmd, char **argv, int argc, int *hflag, int *iflag) >+{ >+ extern int optind, optreset, opterr; >+ int ch; >+ >+ optind = optreset = 1; >+ opterr = 0; >+ >+ *hflag = *iflag = 0; >+ while ((ch = getopt(argc, argv, "hi")) != -1) { >+ switch (ch) { >+ case 'h': >+ *hflag = 1; >+ break; >+ case 'i': >+ *iflag = 1; >+ break; >+ default: >+ error("%s: Invalid flag -%c", cmd, ch); >+ return -1; >+ } >+ } >+ >+ return optind; >+} >+ >+static int > is_dir(char *path) > { > struct stat sb; >@@ -785,6 +818,56 @@ do_globbed_ls(struct sftp_conn *conn, ch > return (0); > } > >+static int >+do_df(struct sftp_conn *conn, char *path, int hflag, int iflag) >+{ >+ struct statvfs st; >+ char s_used[FMT_SCALED_STRSIZE]; >+ char s_avail[FMT_SCALED_STRSIZE]; >+ char s_root[FMT_SCALED_STRSIZE]; >+ char s_total[FMT_SCALED_STRSIZE]; >+ >+ if (do_statvfs(conn, path, &st, 1) == -1) >+ return -1; >+ if (iflag) { >+ printf(" Inodes Used Avail " >+ "(root) %%Capacity\n"); >+ printf("%11llu %11llu %11llu %11llu %3llu%%\n", >+ (unsigned long long)st.f_files, >+ (unsigned long long)(st.f_files - st.f_ffree), >+ (unsigned long long)st.f_favail, >+ (unsigned long long)st.f_ffree, >+ (unsigned long long)(100 * (st.f_files - st.f_ffree) / >+ st.f_files)); >+ } else if (hflag) { >+ strlcpy(s_used, "error", sizeof(s_used)); >+ strlcpy(s_avail, "error", sizeof(s_avail)); >+ strlcpy(s_root, "error", sizeof(s_root)); >+ strlcpy(s_total, "error", sizeof(s_total)); >+ fmt_scaled((st.f_blocks - st.f_bfree) * st.f_bsize, s_used); >+ fmt_scaled(st.f_bavail * st.f_bsize, s_avail); >+ fmt_scaled(st.f_bfree * st.f_bsize, s_root); >+ fmt_scaled(st.f_blocks * st.f_bsize, s_total); >+ printf(" Size Used Avail (root) %%Capacity\n"); >+ printf("%7sB %7sB %7sB %7sB %3llu%%\n", >+ s_total, s_used, s_avail, s_root, >+ (unsigned long long)(100 * (st.f_blocks - st.f_bfree) / >+ st.f_blocks)); >+ } else { >+ printf(" Size Used Avail " >+ "(root) %%Capacity\n"); >+ printf("%12llu %12llu %12llu %12llu %3llu%%\n", >+ (unsigned long long)(st.f_bsize * st.f_blocks / 1024), >+ (unsigned long long)(st.f_bsize * >+ (st.f_blocks - st.f_bfree) / 1024), >+ (unsigned long long)(st.f_bsize * st.f_bavail / 1024), >+ (unsigned long long)(st.f_bsize * st.f_bfree / 1024), >+ (unsigned long long)(100 * (st.f_blocks - st.f_bfree) / >+ st.f_blocks)); >+ } >+ return 0; >+} >+ > /* > * Undo escaping of glob sequences in place. Used to undo extra escaping > * applied in makeargv() when the string is destined for a function that >@@ -960,7 +1043,7 @@ makeargv(const char *arg, int *argcp) > } > > static int >-parse_args(const char **cpp, int *pflag, int *lflag, int *iflag, >+parse_args(const char **cpp, int *pflag, int *lflag, int *iflag, int *hflag, > unsigned long *n_arg, char **path1, char **path2) > { > const char *cmd, *cp = *cpp; >@@ -1004,7 +1087,7 @@ parse_args(const char **cpp, int *pflag, > } > > /* Get arguments and parse flags */ >- *lflag = *pflag = *n_arg = 0; >+ *lflag = *pflag = *hflag = *n_arg = 0; > *path1 = *path2 = NULL; > optidx = 1; > switch (cmdnum) { >@@ -1056,6 +1139,18 @@ parse_args(const char **cpp, int *pflag, > if (cmdnum != I_RM) > undo_glob_escape(*path1); > break; >+ case I_DF: >+ if ((optidx = parse_df_flags(cmd, argv, argc, hflag, >+ iflag)) == -1) >+ return -1; >+ /* Default to current directory if no path specified */ >+ if (argc - optidx < 1) >+ *path1 = NULL; >+ else { >+ *path1 = xstrdup(argv[optidx]); >+ undo_glob_escape(*path1); >+ } >+ break; > case I_LS: > if ((optidx = parse_ls_flags(argv, argc, lflag)) == -1) > return(-1); >@@ -1118,7 +1213,7 @@ parse_dispatch_command(struct sftp_conn > int err_abort) > { > char *path1, *path2, *tmp; >- int pflag, lflag, iflag, cmdnum, i; >+ int pflag, lflag, iflag, hflag, cmdnum, i; > unsigned long n_arg; > Attrib a, *aa; > char path_buf[MAXPATHLEN]; >@@ -1126,7 +1221,7 @@ parse_dispatch_command(struct sftp_conn > glob_t g; > > path1 = path2 = NULL; >- cmdnum = parse_args(&cmd, &pflag, &lflag, &iflag, &n_arg, >+ cmdnum = parse_args(&cmd, &pflag, &lflag, &iflag, &hflag, &n_arg, > &path1, &path2); > > if (iflag != 0) >@@ -1219,6 +1314,13 @@ parse_dispatch_command(struct sftp_conn > > path1 = make_absolute(path1, *pwd); > err = do_globbed_ls(conn, path1, tmp, lflag); >+ break; >+ case I_DF: >+ /* Default to current directory if no path specified */ >+ if (path1 == NULL) >+ path1 = xstrdup(*pwd); >+ path1 = make_absolute(path1, *pwd); >+ err = do_df(conn, path1, hflag, iflag); > break; > case I_LCHDIR: > if (chdir(path1) == -1) { >Index: sftp.1 >=================================================================== >RCS file: /cvs/src/usr.bin/ssh/sftp.1,v >retrieving revision 1.64 >diff -u -p -r1.64 sftp.1 >--- sftp.1 31 May 2007 19:20:16 -0000 1.64 >+++ sftp.1 23 Mar 2008 13:05:18 -0000 >@@ -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 >@@ -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 . >Index: sftp-server.c >=================================================================== >RCS file: /cvs/src/usr.bin/ssh/sftp-server.c,v >retrieving revision 1.78 >diff -u -p -r1.78 sftp-server.c >--- sftp-server.c 27 Feb 2008 20:21:15 -0000 1.78 >+++ sftp-server.c 23 Mar 2008 13:05:18 -0000 >@@ -19,6 +19,8 @@ > #include <sys/stat.h> > #include <sys/time.h> > #include <sys/param.h> >+#include <sys/mount.h> >+#include <sys/statvfs.h> > > #include <dirent.h> > #include <errno.h> >@@ -470,6 +472,33 @@ send_attrib(u_int32_t id, const Attrib * > 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 >@@ -485,6 +514,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); > } >@@ -1079,6 +1112,43 @@ process_extended_posix_rename(u_int32_t > } > > 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; >+ >+ id = get_int(); >+ 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) > { > u_int32_t id; >@@ -1088,8 +1158,12 @@ 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 */ >+ send_status(id, SSH2_FX_OP_UNSUPPORTED); /* MUST */ > xfree(request); > } > >Index: sftp-client.h >=================================================================== >RCS file: /cvs/src/usr.bin/ssh/sftp-client.h,v >retrieving revision 1.15 >diff -u -p -r1.15 sftp-client.h >--- sftp-client.h 11 Jan 2008 07:22:28 -0000 1.15 >+++ sftp-client.h 23 Mar 2008 13:05:18 -0000 >@@ -70,6 +70,10 @@ int do_fsetstat(struct sftp_conn *, char > /* 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 *); > >Index: sftp-client.c >=================================================================== >RCS file: /cvs/src/usr.bin/ssh/sftp-client.c,v >retrieving revision 1.81 >diff -u -p -r1.81 sftp-client.c >--- sftp-client.c 23 Mar 2008 12:54:01 -0000 1.81 >+++ sftp-client.c 23 Mar 2008 13:05:18 -0000 >@@ -25,6 +25,7 @@ > #include <sys/stat.h> > #include <sys/time.h> > #include <sys/param.h> >+#include <sys/statvfs.h> > #include <sys/uio.h> > > #include <errno.h> >@@ -59,7 +60,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; > }; > >@@ -232,6 +235,56 @@ get_decode_stat(int fd, u_int expected_i > 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) > { >@@ -266,8 +319,15 @@ do_init(int fd_in, int fd_out, u_int tra > 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); > } >@@ -740,6 +800,60 @@ do_readlink(struct sftp_conn *conn, char > buffer_free(&msg); > > return(filename); >+} >+#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 >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 1399
:
1393
| 1475