]> andersk Git - openssh.git/blobdiff - sftp.c
- djm@cvs.openbsd.org 2008/12/09 03:02:37
[openssh.git] / sftp.c
diff --git a/sftp.c b/sftp.c
index db0a8d9af0ef8329f5b707ea94cda92501af83e7..4d37f85699ac0b29b538a7916af77679cc0001d5 100644 (file)
--- a/sftp.c
+++ b/sftp.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sftp.c,v 1.98 2007/12/12 05:04:03 djm Exp $ */
+/* $OpenBSD: sftp.c,v 1.105 2008/12/09 03:04:39 djm Exp $ */
 /*
  * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
  *
@@ -25,6 +25,9 @@
 #include <sys/param.h>
 #include <sys/socket.h>
 #include <sys/wait.h>
+#ifdef HAVE_SYS_STATVFS_H
+#include <sys/statvfs.h>
+#endif
 
 #include <ctype.h>
 #include <errno.h>
@@ -44,6 +47,14 @@ typedef void EditLine;
 #include <unistd.h>
 #include <stdarg.h>
 
+#ifdef HAVE_UTIL_H
+# include <util.h>
+#endif
+
+#ifdef HAVE_LIBUTIL_H
+# include <libutil.h>
+#endif
+
 #include "xmalloc.h"
 #include "log.h"
 #include "pathnames.h"
@@ -64,7 +75,7 @@ int batchmode = 0;
 size_t copy_buffer_len = 32768;
 
 /* Number of concurrent outstanding requests */
-size_t num_requests = 16;
+size_t num_requests = 64;
 
 /* PID of ssh transport process */
 static pid_t sshpid = -1;
@@ -104,6 +115,7 @@ extern char *__progname;
 #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
@@ -136,6 +148,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 },
@@ -200,6 +213,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");
@@ -349,7 +364,7 @@ infer_path(const char *p, char **ifp)
 static int
 parse_getput_flags(const char *cmd, char **argv, int argc, int *pflag)
 {
-       extern int optind, optreset, opterr;
+       extern int opterr, optind, optopt, optreset;
        int ch;
 
        optind = optreset = 1;
@@ -363,7 +378,7 @@ parse_getput_flags(const char *cmd, char **argv, int argc, int *pflag)
                        *pflag = 1;
                        break;
                default:
-                       error("%s: Invalid flag -%c", cmd, ch);
+                       error("%s: Invalid flag -%c", cmd, optopt);
                        return -1;
                }
        }
@@ -374,7 +389,7 @@ parse_getput_flags(const char *cmd, char **argv, int argc, int *pflag)
 static int
 parse_ls_flags(char **argv, int argc, int *lflag)
 {
-       extern int optind, optreset, opterr;
+       extern int opterr, optind, optopt, optreset;
        int ch;
 
        optind = optreset = 1;
@@ -413,7 +428,7 @@ parse_ls_flags(char **argv, int argc, int *lflag)
                        *lflag |= LS_TIME_SORT;
                        break;
                default:
-                       error("ls: Invalid flag -%c", ch);
+                       error("ls: Invalid flag -%c", optopt);
                        return -1;
                }
        }
@@ -422,26 +437,42 @@ parse_ls_flags(char **argv, int argc, int *lflag)
 }
 
 static int
-is_dir(char *path)
+parse_df_flags(const char *cmd, char **argv, int argc, int *hflag, int *iflag)
 {
-       struct stat sb;
+       extern int opterr, optind, optopt, optreset;
+       int ch;
 
-       /* XXX: report errors? */
-       if (stat(path, &sb) == -1)
-               return(0);
+       optind = optreset = 1;
+       opterr = 0;
 
-       return(S_ISDIR(sb.st_mode));
+       *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, optopt);
+                       return -1;
+               }
+       }
+
+       return optind;
 }
 
 static int
-is_reg(char *path)
+is_dir(char *path)
 {
        struct stat sb;
 
+       /* XXX: report errors? */
        if (stat(path, &sb) == -1)
-               fatal("stat %s: %s", path, strerror(errno));
+               return(0);
 
-       return(S_ISREG(sb.st_mode));
+       return(S_ISDIR(sb.st_mode));
 }
 
 static int
@@ -532,6 +563,7 @@ process_put(struct sftp_conn *conn, char *src, char *dst, char *pwd, int pflag)
        glob_t g;
        int err = 0;
        int i;
+       struct stat sb;
 
        if (dst) {
                tmp_dst = xstrdup(dst);
@@ -540,7 +572,7 @@ process_put(struct sftp_conn *conn, char *src, char *dst, char *pwd, int pflag)
 
        memset(&g, 0, sizeof(g));
        debug3("Looking up %s", src);
-       if (glob(src, 0, NULL, &g)) {
+       if (glob(src, GLOB_NOCHECK, NULL, &g)) {
                error("File \"%s\" not found.", src);
                err = -1;
                goto out;
@@ -555,7 +587,13 @@ process_put(struct sftp_conn *conn, char *src, char *dst, char *pwd, int pflag)
        }
 
        for (i = 0; g.gl_pathv[i] && !interrupted; i++) {
-               if (!is_reg(g.gl_pathv[i])) {
+               if (stat(g.gl_pathv[i], &sb) == -1) {
+                       err = -1;
+                       error("stat %s: %s", g.gl_pathv[i], strerror(errno));
+                       continue;
+               }
+
+               if (!S_ISREG(sb.st_mode)) {
                        error("skipping non-regular file %s",
                            g.gl_pathv[i]);
                        continue;
@@ -801,6 +839,56 @@ do_globbed_ls(struct sftp_conn *conn, char *path, char *strip_path,
        return (0);
 }
 
+static int
+do_df(struct sftp_conn *conn, char *path, int hflag, int iflag)
+{
+       struct sftp_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_frsize, s_used);
+               fmt_scaled(st.f_bavail * st.f_frsize, s_avail);
+               fmt_scaled(st.f_bfree * st.f_frsize, s_root);
+               fmt_scaled(st.f_blocks * st.f_frsize, 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_frsize * st.f_blocks / 1024),
+                   (unsigned long long)(st.f_frsize *
+                   (st.f_blocks - st.f_bfree) / 1024),
+                   (unsigned long long)(st.f_frsize * st.f_bavail / 1024),
+                   (unsigned long long)(st.f_frsize * 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
@@ -976,7 +1064,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;
@@ -1020,7 +1108,7 @@ parse_args(const char **cpp, int *pflag, int *lflag, int *iflag,
        }
 
        /* Get arguments and parse flags */
-       *lflag = *pflag = *n_arg = 0;
+       *lflag = *pflag = *hflag = *n_arg = 0;
        *path1 = *path2 = NULL;
        optidx = 1;
        switch (cmdnum) {
@@ -1072,6 +1160,18 @@ parse_args(const char **cpp, int *pflag, int *lflag, int *iflag,
                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);
@@ -1134,7 +1234,7 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
     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];
@@ -1142,7 +1242,7 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
        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)
@@ -1236,6 +1336,13 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
                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) {
                        error("Couldn't change local directory to "
@@ -1279,17 +1386,19 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
                remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g);
                for (i = 0; g.gl_pathv[i] && !interrupted; i++) {
                        if (!(aa = do_stat(conn, g.gl_pathv[i], 0))) {
-                               if (err != 0 && err_abort)
+                               if (err_abort) {
+                                       err = -1;
                                        break;
-                               else
+                               else
                                        continue;
                        }
                        if (!(aa->flags & SSH2_FILEXFER_ATTR_UIDGID)) {
                                error("Can't get current ownership of "
                                    "remote file \"%s\"", g.gl_pathv[i]);
-                               if (err != 0 && err_abort)
+                               if (err_abort) {
+                                       err = -1;
                                        break;
-                               else
+                               else
                                        continue;
                        }
                        aa->flags &= SSH2_FILEXFER_ATTR_UIDGID;
@@ -1561,8 +1670,8 @@ usage(void)
            "usage: %s [-1Cv] [-B buffer_size] [-b batchfile] [-F ssh_config]\n"
            "            [-o ssh_option] [-P sftp_server_path] [-R num_requests]\n"
            "            [-S program] [-s subsystem | sftp_server] host\n"
-           "       %s [[user@]host[:file [file]]]\n"
-           "       %s [[user@]host[:dir[/]]]\n"
+           "       %s [user@]host[:file ...]\n"
+           "       %s [user@]host[:dir[/]]\n"
            "       %s -b batchfile [user@]host\n", __progname, __progname, __progname, __progname);
        exit(1);
 }
This page took 0.095229 seconds and 4 git commands to generate.