diff options
author | Damien Miller <djm@mindrot.org> | 2008-05-19 14:53:33 +1000 |
---|---|---|
committer | Damien Miller <djm@mindrot.org> | 2008-05-19 14:53:33 +1000 |
commit | d671e5a978efd5ba949d3fdcd03f728dcd68c636 (patch) | |
tree | f63127fe29690fbe2c00f7b50d7807dc24288e29 | |
parent | 354c48c641e7fbdc273ee8e1239ff71d73a1ec3e (diff) |
- 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@
-rw-r--r-- | ChangeLog | 11 | ||||
-rw-r--r-- | sftp-client.c | 120 | ||||
-rw-r--r-- | sftp-client.h | 6 | ||||
-rw-r--r-- | sftp-server.c | 75 | ||||
-rw-r--r-- | sftp.1 | 24 | ||||
-rw-r--r-- | sftp.c | 112 | ||||
-rw-r--r-- | sftp.h | 6 |
7 files changed, 339 insertions, 15 deletions
@@ -21,6 +21,15 @@ | |||
21 | Use arc4random_uniform() when the desired random number upper bound | 21 | Use arc4random_uniform() when the desired random number upper bound |
22 | is not a power of two | 22 | is not a power of two |
23 | ok deraadt@ millert@ | 23 | ok deraadt@ millert@ |
24 | - djm@cvs.openbsd.org 2008/04/18 12:32:11 | ||
25 | [sftp-client.c sftp-client.h sftp-server.c sftp.1 sftp.c sftp.h] | ||
26 | introduce sftp extension methods statvfs@openssh.com and | ||
27 | fstatvfs@openssh.com that implement statvfs(2)-like operations, | ||
28 | based on a patch from miklos AT szeredi.hu (bz#1399) | ||
29 | also add a "df" command to the sftp client that uses the | ||
30 | statvfs@openssh.com to produce a df(1)-like display of filesystem | ||
31 | space and inode utilisation | ||
32 | ok markus@ | ||
24 | 33 | ||
25 | 20080403 | 34 | 20080403 |
26 | - (djm) [openbsd-compat/bsd-poll.c] Include stdlib.h to avoid compile- | 35 | - (djm) [openbsd-compat/bsd-poll.c] Include stdlib.h to avoid compile- |
@@ -3881,4 +3890,4 @@ | |||
3881 | OpenServer 6 and add osr5bigcrypt support so when someone migrates | 3890 | OpenServer 6 and add osr5bigcrypt support so when someone migrates |
3882 | passwords between UnixWare and OpenServer they will still work. OK dtucker@ | 3891 | passwords between UnixWare and OpenServer they will still work. OK dtucker@ |
3883 | 3892 | ||
3884 | $Id: ChangeLog,v 1.4910 2008/05/19 04:50:00 djm Exp $ | 3893 | $Id: ChangeLog,v 1.4911 2008/05/19 04:53:33 djm Exp $ |
diff --git a/sftp-client.c b/sftp-client.c index 69c637785..1e54348b7 100644 --- a/sftp-client.c +++ b/sftp-client.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: sftp-client.c,v 1.81 2008/03/23 12:54:01 djm Exp $ */ | 1 | /* $OpenBSD: sftp-client.c,v 1.82 2008/04/18 12:32:11 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org> | 3 | * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org> |
4 | * | 4 | * |
@@ -24,6 +24,7 @@ | |||
24 | 24 | ||
25 | #include <sys/types.h> | 25 | #include <sys/types.h> |
26 | #include <sys/param.h> | 26 | #include <sys/param.h> |
27 | #include <sys/statvfs.h> | ||
27 | #include "openbsd-compat/sys-queue.h" | 28 | #include "openbsd-compat/sys-queue.h" |
28 | #ifdef HAVE_SYS_STAT_H | 29 | #ifdef HAVE_SYS_STAT_H |
29 | # include <sys/stat.h> | 30 | # include <sys/stat.h> |
@@ -65,7 +66,9 @@ struct sftp_conn { | |||
65 | u_int num_requests; | 66 | u_int num_requests; |
66 | u_int version; | 67 | u_int version; |
67 | u_int msg_id; | 68 | u_int msg_id; |
68 | #define SFTP_EXT_POSIX_RENAME 1 | 69 | #define SFTP_EXT_POSIX_RENAME 0x00000001 |
70 | #define SFTP_EXT_STATVFS 0x00000002 | ||
71 | #define SFTP_EXT_FSTATVFS 0x00000004 | ||
69 | u_int exts; | 72 | u_int exts; |
70 | }; | 73 | }; |
71 | 74 | ||
@@ -238,6 +241,56 @@ get_decode_stat(int fd, u_int expected_id, int quiet) | |||
238 | return(a); | 241 | return(a); |
239 | } | 242 | } |
240 | 243 | ||
244 | static int | ||
245 | get_decode_statvfs(int fd, struct statvfs *st, u_int expected_id, int quiet) | ||
246 | { | ||
247 | Buffer msg; | ||
248 | u_int type, id, flag; | ||
249 | |||
250 | buffer_init(&msg); | ||
251 | get_msg(fd, &msg); | ||
252 | |||
253 | type = buffer_get_char(&msg); | ||
254 | id = buffer_get_int(&msg); | ||
255 | |||
256 | debug3("Received statvfs reply T:%u I:%u", type, id); | ||
257 | if (id != expected_id) | ||
258 | fatal("ID mismatch (%u != %u)", id, expected_id); | ||
259 | if (type == SSH2_FXP_STATUS) { | ||
260 | int status = buffer_get_int(&msg); | ||
261 | |||
262 | if (quiet) | ||
263 | debug("Couldn't statvfs: %s", fx2txt(status)); | ||
264 | else | ||
265 | error("Couldn't statvfs: %s", fx2txt(status)); | ||
266 | buffer_free(&msg); | ||
267 | return -1; | ||
268 | } else if (type != SSH2_FXP_EXTENDED_REPLY) { | ||
269 | fatal("Expected SSH2_FXP_EXTENDED_REPLY(%u) packet, got %u", | ||
270 | SSH2_FXP_EXTENDED_REPLY, type); | ||
271 | } | ||
272 | |||
273 | bzero(st, sizeof(*st)); | ||
274 | st->f_bsize = buffer_get_int(&msg); | ||
275 | st->f_frsize = buffer_get_int(&msg); | ||
276 | st->f_blocks = buffer_get_int64(&msg); | ||
277 | st->f_bfree = buffer_get_int64(&msg); | ||
278 | st->f_bavail = buffer_get_int64(&msg); | ||
279 | st->f_files = buffer_get_int64(&msg); | ||
280 | st->f_ffree = buffer_get_int64(&msg); | ||
281 | st->f_favail = buffer_get_int64(&msg); | ||
282 | st->f_fsid = buffer_get_int(&msg); | ||
283 | flag = buffer_get_int(&msg); | ||
284 | st->f_namemax = buffer_get_int(&msg); | ||
285 | |||
286 | st->f_flag = (flag & SSH2_FXE_STATVFS_ST_RDONLY) ? ST_RDONLY : 0; | ||
287 | st->f_flag |= (flag & SSH2_FXE_STATVFS_ST_NOSUID) ? ST_NOSUID : 0; | ||
288 | |||
289 | buffer_free(&msg); | ||
290 | |||
291 | return 0; | ||
292 | } | ||
293 | |||
241 | struct sftp_conn * | 294 | struct sftp_conn * |
242 | do_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests) | 295 | do_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests) |
243 | { | 296 | { |
@@ -272,8 +325,15 @@ do_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests) | |||
272 | char *value = buffer_get_string(&msg, NULL); | 325 | char *value = buffer_get_string(&msg, NULL); |
273 | 326 | ||
274 | debug2("Init extension: \"%s\"", name); | 327 | debug2("Init extension: \"%s\"", name); |
275 | if (strcmp(name, "posix-rename@openssh.com") == 0) | 328 | if (strcmp(name, "posix-rename@openssh.com") == 0 && |
329 | strcmp(value, "1") == 0) | ||
276 | exts |= SFTP_EXT_POSIX_RENAME; | 330 | exts |= SFTP_EXT_POSIX_RENAME; |
331 | if (strcmp(name, "statvfs@openssh.com") == 0 && | ||
332 | strcmp(value, "1") == 0) | ||
333 | exts |= SFTP_EXT_STATVFS; | ||
334 | if (strcmp(name, "fstatvfs@openssh.com") == 0 && | ||
335 | strcmp(value, "1") == 0) | ||
336 | exts |= SFTP_EXT_FSTATVFS; | ||
277 | xfree(name); | 337 | xfree(name); |
278 | xfree(value); | 338 | xfree(value); |
279 | } | 339 | } |
@@ -749,6 +809,60 @@ do_readlink(struct sftp_conn *conn, char *path) | |||
749 | } | 809 | } |
750 | #endif | 810 | #endif |
751 | 811 | ||
812 | int | ||
813 | do_statvfs(struct sftp_conn *conn, const char *path, struct statvfs *st, | ||
814 | int quiet) | ||
815 | { | ||
816 | Buffer msg; | ||
817 | u_int id; | ||
818 | |||
819 | if ((conn->exts & SFTP_EXT_STATVFS) == 0) { | ||
820 | error("Server does not support statvfs@openssh.com extension"); | ||
821 | return -1; | ||
822 | } | ||
823 | |||
824 | id = conn->msg_id++; | ||
825 | |||
826 | buffer_init(&msg); | ||
827 | buffer_clear(&msg); | ||
828 | buffer_put_char(&msg, SSH2_FXP_EXTENDED); | ||
829 | buffer_put_int(&msg, id); | ||
830 | buffer_put_cstring(&msg, "statvfs@openssh.com"); | ||
831 | buffer_put_cstring(&msg, path); | ||
832 | send_msg(conn->fd_out, &msg); | ||
833 | buffer_free(&msg); | ||
834 | |||
835 | return get_decode_statvfs(conn->fd_in, st, id, quiet); | ||
836 | } | ||
837 | |||
838 | #ifdef notyet | ||
839 | int | ||
840 | do_fstatvfs(struct sftp_conn *conn, const char *handle, u_int handle_len, | ||
841 | struct statvfs *st, int quiet) | ||
842 | { | ||
843 | Buffer msg; | ||
844 | u_int id; | ||
845 | |||
846 | if ((conn->exts & SFTP_EXT_FSTATVFS) == 0) { | ||
847 | error("Server does not support fstatvfs@openssh.com extension"); | ||
848 | return -1; | ||
849 | } | ||
850 | |||
851 | id = conn->msg_id++; | ||
852 | |||
853 | buffer_init(&msg); | ||
854 | buffer_clear(&msg); | ||
855 | buffer_put_char(&msg, SSH2_FXP_EXTENDED); | ||
856 | buffer_put_int(&msg, id); | ||
857 | buffer_put_cstring(&msg, "fstatvfs@openssh.com"); | ||
858 | buffer_put_string(&msg, handle, handle_len); | ||
859 | send_msg(conn->fd_out, &msg); | ||
860 | buffer_free(&msg); | ||
861 | |||
862 | return get_decode_statvfs(conn->fd_in, st, id, quiet); | ||
863 | } | ||
864 | #endif | ||
865 | |||
752 | static void | 866 | static void |
753 | send_read_request(int fd_out, u_int id, u_int64_t offset, u_int len, | 867 | send_read_request(int fd_out, u_int id, u_int64_t offset, u_int len, |
754 | char *handle, u_int handle_len) | 868 | char *handle, u_int handle_len) |
diff --git a/sftp-client.h b/sftp-client.h index fd0630e9a..b102e1180 100644 --- a/sftp-client.h +++ b/sftp-client.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: sftp-client.h,v 1.15 2008/01/11 07:22:28 chl Exp $ */ | 1 | /* $OpenBSD: sftp-client.h,v 1.16 2008/04/18 12:32:11 djm Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org> | 4 | * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org> |
@@ -70,6 +70,10 @@ int do_fsetstat(struct sftp_conn *, char *, u_int, Attrib *); | |||
70 | /* Canonicalise 'path' - caller must free result */ | 70 | /* Canonicalise 'path' - caller must free result */ |
71 | char *do_realpath(struct sftp_conn *, char *); | 71 | char *do_realpath(struct sftp_conn *, char *); |
72 | 72 | ||
73 | /* Get statistics for filesystem hosting file at "path" */ | ||
74 | struct statvfs; | ||
75 | int do_statvfs(struct sftp_conn *, const char *, struct statvfs *, int); | ||
76 | |||
73 | /* Rename 'oldpath' to 'newpath' */ | 77 | /* Rename 'oldpath' to 'newpath' */ |
74 | int do_rename(struct sftp_conn *, char *, char *); | 78 | int do_rename(struct sftp_conn *, char *, char *); |
75 | 79 | ||
diff --git a/sftp-server.c b/sftp-server.c index d9549f5bc..300fd5cfd 100644 --- a/sftp-server.c +++ b/sftp-server.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: sftp-server.c,v 1.78 2008/02/27 20:21:15 djm Exp $ */ | 1 | /* $OpenBSD: sftp-server.c,v 1.79 2008/04/18 12:32:11 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2000-2004 Markus Friedl. All rights reserved. | 3 | * Copyright (c) 2000-2004 Markus Friedl. All rights reserved. |
4 | * | 4 | * |
@@ -23,6 +23,8 @@ | |||
23 | #ifdef HAVE_SYS_TIME_H | 23 | #ifdef HAVE_SYS_TIME_H |
24 | # include <sys/time.h> | 24 | # include <sys/time.h> |
25 | #endif | 25 | #endif |
26 | #include <sys/mount.h> | ||
27 | #include <sys/statvfs.h> | ||
26 | 28 | ||
27 | #include <dirent.h> | 29 | #include <dirent.h> |
28 | #include <errno.h> | 30 | #include <errno.h> |
@@ -475,6 +477,33 @@ send_attrib(u_int32_t id, const Attrib *a) | |||
475 | buffer_free(&msg); | 477 | buffer_free(&msg); |
476 | } | 478 | } |
477 | 479 | ||
480 | static void | ||
481 | send_statvfs(u_int32_t id, struct statvfs *st) | ||
482 | { | ||
483 | Buffer msg; | ||
484 | u_int64_t flag; | ||
485 | |||
486 | flag = (st->f_flag & ST_RDONLY) ? SSH2_FXE_STATVFS_ST_RDONLY : 0; | ||
487 | flag |= (st->f_flag & ST_NOSUID) ? SSH2_FXE_STATVFS_ST_NOSUID : 0; | ||
488 | |||
489 | buffer_init(&msg); | ||
490 | buffer_put_char(&msg, SSH2_FXP_EXTENDED_REPLY); | ||
491 | buffer_put_int(&msg, id); | ||
492 | buffer_put_int(&msg, st->f_bsize); | ||
493 | buffer_put_int(&msg, st->f_frsize); | ||
494 | buffer_put_int64(&msg, st->f_blocks); | ||
495 | buffer_put_int64(&msg, st->f_bfree); | ||
496 | buffer_put_int64(&msg, st->f_bavail); | ||
497 | buffer_put_int64(&msg, st->f_files); | ||
498 | buffer_put_int64(&msg, st->f_ffree); | ||
499 | buffer_put_int64(&msg, st->f_favail); | ||
500 | buffer_put_int(&msg, st->f_fsid); | ||
501 | buffer_put_int(&msg, flag); | ||
502 | buffer_put_int(&msg, st->f_namemax); | ||
503 | send_msg(&msg); | ||
504 | buffer_free(&msg); | ||
505 | } | ||
506 | |||
478 | /* parse incoming */ | 507 | /* parse incoming */ |
479 | 508 | ||
480 | static void | 509 | static void |
@@ -490,6 +519,10 @@ process_init(void) | |||
490 | /* POSIX rename extension */ | 519 | /* POSIX rename extension */ |
491 | buffer_put_cstring(&msg, "posix-rename@openssh.com"); | 520 | buffer_put_cstring(&msg, "posix-rename@openssh.com"); |
492 | buffer_put_cstring(&msg, "1"); /* version */ | 521 | buffer_put_cstring(&msg, "1"); /* version */ |
522 | buffer_put_cstring(&msg, "statvfs@openssh.com"); | ||
523 | buffer_put_cstring(&msg, "1"); /* version */ | ||
524 | buffer_put_cstring(&msg, "fstatvfs@openssh.com"); | ||
525 | buffer_put_cstring(&msg, "1"); /* version */ | ||
493 | send_msg(&msg); | 526 | send_msg(&msg); |
494 | buffer_free(&msg); | 527 | buffer_free(&msg); |
495 | } | 528 | } |
@@ -1100,6 +1133,42 @@ process_extended_posix_rename(u_int32_t id) | |||
1100 | } | 1133 | } |
1101 | 1134 | ||
1102 | static void | 1135 | static void |
1136 | process_extended_statvfs(u_int32_t id) | ||
1137 | { | ||
1138 | char *path; | ||
1139 | struct statvfs st; | ||
1140 | |||
1141 | path = get_string(NULL); | ||
1142 | debug3("request %u: statfs", id); | ||
1143 | logit("statfs \"%s\"", path); | ||
1144 | |||
1145 | if (statvfs(path, &st) != 0) | ||
1146 | send_status(id, errno_to_portable(errno)); | ||
1147 | else | ||
1148 | send_statvfs(id, &st); | ||
1149 | xfree(path); | ||
1150 | } | ||
1151 | |||
1152 | static void | ||
1153 | process_extended_fstatvfs(u_int32_t id) | ||
1154 | { | ||
1155 | int handle, fd; | ||
1156 | struct statvfs st; | ||
1157 | |||
1158 | handle = get_handle(); | ||
1159 | debug("request %u: fstatvfs \"%s\" (handle %u)", | ||
1160 | id, handle_to_name(handle), handle); | ||
1161 | if ((fd = handle_to_fd(handle)) < 0) { | ||
1162 | send_status(id, SSH2_FX_FAILURE); | ||
1163 | return; | ||
1164 | } | ||
1165 | if (fstatvfs(fd, &st) != 0) | ||
1166 | send_status(id, errno_to_portable(errno)); | ||
1167 | else | ||
1168 | send_statvfs(id, &st); | ||
1169 | } | ||
1170 | |||
1171 | static void | ||
1103 | process_extended(void) | 1172 | process_extended(void) |
1104 | { | 1173 | { |
1105 | u_int32_t id; | 1174 | u_int32_t id; |
@@ -1109,6 +1178,10 @@ process_extended(void) | |||
1109 | request = get_string(NULL); | 1178 | request = get_string(NULL); |
1110 | if (strcmp(request, "posix-rename@openssh.com") == 0) | 1179 | if (strcmp(request, "posix-rename@openssh.com") == 0) |
1111 | process_extended_posix_rename(id); | 1180 | process_extended_posix_rename(id); |
1181 | else if (strcmp(request, "statvfs@openssh.com") == 0) | ||
1182 | process_extended_statvfs(id); | ||
1183 | else if (strcmp(request, "fstatvfs@openssh.com") == 0) | ||
1184 | process_extended_fstatvfs(id); | ||
1112 | else | 1185 | else |
1113 | send_status(id, SSH2_FX_OP_UNSUPPORTED); /* MUST */ | 1186 | send_status(id, SSH2_FX_OP_UNSUPPORTED); /* MUST */ |
1114 | xfree(request); | 1187 | xfree(request); |
@@ -1,4 +1,4 @@ | |||
1 | .\" $OpenBSD: sftp.1,v 1.64 2007/05/31 19:20:16 jmc Exp $ | 1 | .\" $OpenBSD: sftp.1,v 1.65 2008/04/18 12:32:11 djm Exp $ |
2 | .\" | 2 | .\" |
3 | .\" Copyright (c) 2001 Damien Miller. All rights reserved. | 3 | .\" Copyright (c) 2001 Damien Miller. All rights reserved. |
4 | .\" | 4 | .\" |
@@ -22,7 +22,7 @@ | |||
22 | .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | 22 | .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
23 | .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 23 | .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
24 | .\" | 24 | .\" |
25 | .Dd $Mdocdate: May 31 2007 $ | 25 | .Dd $Mdocdate: April 18 2008 $ |
26 | .Dt SFTP 1 | 26 | .Dt SFTP 1 |
27 | .Os | 27 | .Os |
28 | .Sh NAME | 28 | .Sh NAME |
@@ -112,7 +112,7 @@ will abort if any of the following | |||
112 | commands fail: | 112 | commands fail: |
113 | .Ic get , put , rename , ln , | 113 | .Ic get , put , rename , ln , |
114 | .Ic rm , mkdir , chdir , ls , | 114 | .Ic rm , mkdir , chdir , ls , |
115 | .Ic lchdir , chmod , chown , chgrp , lpwd | 115 | .Ic lchdir , chmod , chown , chgrp , lpwd, df, |
116 | and | 116 | and |
117 | .Ic lmkdir . | 117 | .Ic lmkdir . |
118 | Termination on error can be suppressed on a command by command basis by | 118 | Termination on error can be suppressed on a command by command basis by |
@@ -272,6 +272,24 @@ may contain | |||
272 | characters and may match multiple files. | 272 | characters and may match multiple files. |
273 | .Ar own | 273 | .Ar own |
274 | must be a numeric UID. | 274 | must be a numeric UID. |
275 | .It Xo Ic df | ||
276 | .Op Fl hi | ||
277 | .Op Ar path | ||
278 | .Xc | ||
279 | Display usage information for the filesystem holding the current directory | ||
280 | (or | ||
281 | .Ar path | ||
282 | if specified). | ||
283 | If the | ||
284 | .Fl h | ||
285 | flag is specified, the capacity information will be displayed using | ||
286 | "human-readable" suffixes. | ||
287 | The | ||
288 | .Fl i | ||
289 | flag requests display of inode information in addition to capacity information. | ||
290 | This command is only supported on servers that implement the | ||
291 | .Dq statvfs@openssh.com | ||
292 | extension. | ||
275 | .It Ic exit | 293 | .It Ic exit |
276 | Quit | 294 | Quit |
277 | .Nm sftp . | 295 | .Nm sftp . |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: sftp.c,v 1.99 2008/01/20 00:38:30 djm Exp $ */ | 1 | /* $OpenBSD: sftp.c,v 1.100 2008/04/18 12:32:11 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org> | 3 | * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org> |
4 | * | 4 | * |
@@ -25,6 +25,7 @@ | |||
25 | #include <sys/param.h> | 25 | #include <sys/param.h> |
26 | #include <sys/socket.h> | 26 | #include <sys/socket.h> |
27 | #include <sys/wait.h> | 27 | #include <sys/wait.h> |
28 | #include <sys/statvfs.h> | ||
28 | 29 | ||
29 | #include <ctype.h> | 30 | #include <ctype.h> |
30 | #include <errno.h> | 31 | #include <errno.h> |
@@ -42,6 +43,7 @@ typedef void EditLine; | |||
42 | #include <stdio.h> | 43 | #include <stdio.h> |
43 | #include <string.h> | 44 | #include <string.h> |
44 | #include <unistd.h> | 45 | #include <unistd.h> |
46 | #include <util.h> | ||
45 | #include <stdarg.h> | 47 | #include <stdarg.h> |
46 | 48 | ||
47 | #include "xmalloc.h" | 49 | #include "xmalloc.h" |
@@ -104,6 +106,7 @@ extern char *__progname; | |||
104 | #define I_CHGRP 2 | 106 | #define I_CHGRP 2 |
105 | #define I_CHMOD 3 | 107 | #define I_CHMOD 3 |
106 | #define I_CHOWN 4 | 108 | #define I_CHOWN 4 |
109 | #define I_DF 24 | ||
107 | #define I_GET 5 | 110 | #define I_GET 5 |
108 | #define I_HELP 6 | 111 | #define I_HELP 6 |
109 | #define I_LCHDIR 7 | 112 | #define I_LCHDIR 7 |
@@ -136,6 +139,7 @@ static const struct CMD cmds[] = { | |||
136 | { "chgrp", I_CHGRP }, | 139 | { "chgrp", I_CHGRP }, |
137 | { "chmod", I_CHMOD }, | 140 | { "chmod", I_CHMOD }, |
138 | { "chown", I_CHOWN }, | 141 | { "chown", I_CHOWN }, |
142 | { "df", I_DF }, | ||
139 | { "dir", I_LS }, | 143 | { "dir", I_LS }, |
140 | { "exit", I_QUIT }, | 144 | { "exit", I_QUIT }, |
141 | { "get", I_GET }, | 145 | { "get", I_GET }, |
@@ -200,6 +204,8 @@ help(void) | |||
200 | printf("chgrp grp path Change group of file 'path' to 'grp'\n"); | 204 | printf("chgrp grp path Change group of file 'path' to 'grp'\n"); |
201 | printf("chmod mode path Change permissions of file 'path' to 'mode'\n"); | 205 | printf("chmod mode path Change permissions of file 'path' to 'mode'\n"); |
202 | printf("chown own path Change owner of file 'path' to 'own'\n"); | 206 | printf("chown own path Change owner of file 'path' to 'own'\n"); |
207 | printf("df [path] Display statistics for current directory or\n"); | ||
208 | printf(" filesystem containing 'path'\n"); | ||
203 | printf("help Display this help text\n"); | 209 | printf("help Display this help text\n"); |
204 | printf("get remote-path [local-path] Download file\n"); | 210 | printf("get remote-path [local-path] Download file\n"); |
205 | printf("lls [ls-options [path]] Display local directory listing\n"); | 211 | printf("lls [ls-options [path]] Display local directory listing\n"); |
@@ -422,6 +428,33 @@ parse_ls_flags(char **argv, int argc, int *lflag) | |||
422 | } | 428 | } |
423 | 429 | ||
424 | static int | 430 | static int |
431 | parse_df_flags(const char *cmd, char **argv, int argc, int *hflag, int *iflag) | ||
432 | { | ||
433 | extern int optind, optreset, opterr; | ||
434 | int ch; | ||
435 | |||
436 | optind = optreset = 1; | ||
437 | opterr = 0; | ||
438 | |||
439 | *hflag = *iflag = 0; | ||
440 | while ((ch = getopt(argc, argv, "hi")) != -1) { | ||
441 | switch (ch) { | ||
442 | case 'h': | ||
443 | *hflag = 1; | ||
444 | break; | ||
445 | case 'i': | ||
446 | *iflag = 1; | ||
447 | break; | ||
448 | default: | ||
449 | error("%s: Invalid flag -%c", cmd, ch); | ||
450 | return -1; | ||
451 | } | ||
452 | } | ||
453 | |||
454 | return optind; | ||
455 | } | ||
456 | |||
457 | static int | ||
425 | is_dir(char *path) | 458 | is_dir(char *path) |
426 | { | 459 | { |
427 | struct stat sb; | 460 | struct stat sb; |
@@ -797,6 +830,56 @@ do_globbed_ls(struct sftp_conn *conn, char *path, char *strip_path, | |||
797 | return (0); | 830 | return (0); |
798 | } | 831 | } |
799 | 832 | ||
833 | static int | ||
834 | do_df(struct sftp_conn *conn, char *path, int hflag, int iflag) | ||
835 | { | ||
836 | struct statvfs st; | ||
837 | char s_used[FMT_SCALED_STRSIZE]; | ||
838 | char s_avail[FMT_SCALED_STRSIZE]; | ||
839 | char s_root[FMT_SCALED_STRSIZE]; | ||
840 | char s_total[FMT_SCALED_STRSIZE]; | ||
841 | |||
842 | if (do_statvfs(conn, path, &st, 1) == -1) | ||
843 | return -1; | ||
844 | if (iflag) { | ||
845 | printf(" Inodes Used Avail " | ||
846 | "(root) %%Capacity\n"); | ||
847 | printf("%11llu %11llu %11llu %11llu %3llu%%\n", | ||
848 | (unsigned long long)st.f_files, | ||
849 | (unsigned long long)(st.f_files - st.f_ffree), | ||
850 | (unsigned long long)st.f_favail, | ||
851 | (unsigned long long)st.f_ffree, | ||
852 | (unsigned long long)(100 * (st.f_files - st.f_ffree) / | ||
853 | st.f_files)); | ||
854 | } else if (hflag) { | ||
855 | strlcpy(s_used, "error", sizeof(s_used)); | ||
856 | strlcpy(s_avail, "error", sizeof(s_avail)); | ||
857 | strlcpy(s_root, "error", sizeof(s_root)); | ||
858 | strlcpy(s_total, "error", sizeof(s_total)); | ||
859 | fmt_scaled((st.f_blocks - st.f_bfree) * st.f_frsize, s_used); | ||
860 | fmt_scaled(st.f_bavail * st.f_frsize, s_avail); | ||
861 | fmt_scaled(st.f_bfree * st.f_frsize, s_root); | ||
862 | fmt_scaled(st.f_blocks * st.f_frsize, s_total); | ||
863 | printf(" Size Used Avail (root) %%Capacity\n"); | ||
864 | printf("%7sB %7sB %7sB %7sB %3llu%%\n", | ||
865 | s_total, s_used, s_avail, s_root, | ||
866 | (unsigned long long)(100 * (st.f_blocks - st.f_bfree) / | ||
867 | st.f_blocks)); | ||
868 | } else { | ||
869 | printf(" Size Used Avail " | ||
870 | "(root) %%Capacity\n"); | ||
871 | printf("%12llu %12llu %12llu %12llu %3llu%%\n", | ||
872 | (unsigned long long)(st.f_frsize * st.f_blocks / 1024), | ||
873 | (unsigned long long)(st.f_frsize * | ||
874 | (st.f_blocks - st.f_bfree) / 1024), | ||
875 | (unsigned long long)(st.f_frsize * st.f_bavail / 1024), | ||
876 | (unsigned long long)(st.f_frsize * st.f_bfree / 1024), | ||
877 | (unsigned long long)(100 * (st.f_blocks - st.f_bfree) / | ||
878 | st.f_blocks)); | ||
879 | } | ||
880 | return 0; | ||
881 | } | ||
882 | |||
800 | /* | 883 | /* |
801 | * Undo escaping of glob sequences in place. Used to undo extra escaping | 884 | * Undo escaping of glob sequences in place. Used to undo extra escaping |
802 | * applied in makeargv() when the string is destined for a function that | 885 | * applied in makeargv() when the string is destined for a function that |
@@ -972,7 +1055,7 @@ makeargv(const char *arg, int *argcp) | |||
972 | } | 1055 | } |
973 | 1056 | ||
974 | static int | 1057 | static int |
975 | parse_args(const char **cpp, int *pflag, int *lflag, int *iflag, | 1058 | parse_args(const char **cpp, int *pflag, int *lflag, int *iflag, int *hflag, |
976 | unsigned long *n_arg, char **path1, char **path2) | 1059 | unsigned long *n_arg, char **path1, char **path2) |
977 | { | 1060 | { |
978 | const char *cmd, *cp = *cpp; | 1061 | const char *cmd, *cp = *cpp; |
@@ -1016,7 +1099,7 @@ parse_args(const char **cpp, int *pflag, int *lflag, int *iflag, | |||
1016 | } | 1099 | } |
1017 | 1100 | ||
1018 | /* Get arguments and parse flags */ | 1101 | /* Get arguments and parse flags */ |
1019 | *lflag = *pflag = *n_arg = 0; | 1102 | *lflag = *pflag = *hflag = *n_arg = 0; |
1020 | *path1 = *path2 = NULL; | 1103 | *path1 = *path2 = NULL; |
1021 | optidx = 1; | 1104 | optidx = 1; |
1022 | switch (cmdnum) { | 1105 | switch (cmdnum) { |
@@ -1068,6 +1151,18 @@ parse_args(const char **cpp, int *pflag, int *lflag, int *iflag, | |||
1068 | if (cmdnum != I_RM) | 1151 | if (cmdnum != I_RM) |
1069 | undo_glob_escape(*path1); | 1152 | undo_glob_escape(*path1); |
1070 | break; | 1153 | break; |
1154 | case I_DF: | ||
1155 | if ((optidx = parse_df_flags(cmd, argv, argc, hflag, | ||
1156 | iflag)) == -1) | ||
1157 | return -1; | ||
1158 | /* Default to current directory if no path specified */ | ||
1159 | if (argc - optidx < 1) | ||
1160 | *path1 = NULL; | ||
1161 | else { | ||
1162 | *path1 = xstrdup(argv[optidx]); | ||
1163 | undo_glob_escape(*path1); | ||
1164 | } | ||
1165 | break; | ||
1071 | case I_LS: | 1166 | case I_LS: |
1072 | if ((optidx = parse_ls_flags(argv, argc, lflag)) == -1) | 1167 | if ((optidx = parse_ls_flags(argv, argc, lflag)) == -1) |
1073 | return(-1); | 1168 | return(-1); |
@@ -1130,7 +1225,7 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd, | |||
1130 | int err_abort) | 1225 | int err_abort) |
1131 | { | 1226 | { |
1132 | char *path1, *path2, *tmp; | 1227 | char *path1, *path2, *tmp; |
1133 | int pflag, lflag, iflag, cmdnum, i; | 1228 | int pflag, lflag, iflag, hflag, cmdnum, i; |
1134 | unsigned long n_arg; | 1229 | unsigned long n_arg; |
1135 | Attrib a, *aa; | 1230 | Attrib a, *aa; |
1136 | char path_buf[MAXPATHLEN]; | 1231 | char path_buf[MAXPATHLEN]; |
@@ -1138,7 +1233,7 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd, | |||
1138 | glob_t g; | 1233 | glob_t g; |
1139 | 1234 | ||
1140 | path1 = path2 = NULL; | 1235 | path1 = path2 = NULL; |
1141 | cmdnum = parse_args(&cmd, &pflag, &lflag, &iflag, &n_arg, | 1236 | cmdnum = parse_args(&cmd, &pflag, &lflag, &iflag, &hflag, &n_arg, |
1142 | &path1, &path2); | 1237 | &path1, &path2); |
1143 | 1238 | ||
1144 | if (iflag != 0) | 1239 | if (iflag != 0) |
@@ -1232,6 +1327,13 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd, | |||
1232 | path1 = make_absolute(path1, *pwd); | 1327 | path1 = make_absolute(path1, *pwd); |
1233 | err = do_globbed_ls(conn, path1, tmp, lflag); | 1328 | err = do_globbed_ls(conn, path1, tmp, lflag); |
1234 | break; | 1329 | break; |
1330 | case I_DF: | ||
1331 | /* Default to current directory if no path specified */ | ||
1332 | if (path1 == NULL) | ||
1333 | path1 = xstrdup(*pwd); | ||
1334 | path1 = make_absolute(path1, *pwd); | ||
1335 | err = do_df(conn, path1, hflag, iflag); | ||
1336 | break; | ||
1235 | case I_LCHDIR: | 1337 | case I_LCHDIR: |
1236 | if (chdir(path1) == -1) { | 1338 | if (chdir(path1) == -1) { |
1237 | error("Couldn't change local directory to " | 1339 | error("Couldn't change local directory to " |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: sftp.h,v 1.7 2008/02/08 23:24:07 djm Exp $ */ | 1 | /* $OpenBSD: sftp.h,v 1.8 2008/04/18 12:32:11 djm Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Copyright (c) 2001 Markus Friedl. All rights reserved. | 4 | * Copyright (c) 2001 Markus Friedl. All rights reserved. |
@@ -79,6 +79,10 @@ | |||
79 | #define SSH2_FXF_TRUNC 0x00000010 | 79 | #define SSH2_FXF_TRUNC 0x00000010 |
80 | #define SSH2_FXF_EXCL 0x00000020 | 80 | #define SSH2_FXF_EXCL 0x00000020 |
81 | 81 | ||
82 | /* statvfs@openssh.com f_flag flags */ | ||
83 | #define SSH2_FXE_STATVFS_ST_RDONLY 0x00000001 | ||
84 | #define SSH2_FXE_STATVFS_ST_NOSUID 0x00000002 | ||
85 | |||
82 | /* status messages */ | 86 | /* status messages */ |
83 | #define SSH2_FX_OK 0 | 87 | #define SSH2_FX_OK 0 |
84 | #define SSH2_FX_EOF 1 | 88 | #define SSH2_FX_EOF 1 |