text mount options
authorMiklos Szeredi <miklos@szeredi.hu>
Tue, 13 Apr 2004 10:49:14 +0000 (10:49 +0000)
committerMiklos Szeredi <miklos@szeredi.hu>
Tue, 13 Apr 2004 10:49:14 +0000 (10:49 +0000)
include/linux/fuse.h
kernel/fuse_i.h
kernel/inode.c
util/fusermount.c

index bee2930dc367b92b28b709800848d983f0e37752..63cf16707d5db28dbde7b0cf55e950730c102cd9 100644 (file)
 /** The file containing the version in the form MAJOR.MINOR */
 #define FUSE_VERSION_FILE "/proc/fs/fuse/version"
 
-/** Data passed to mount */
-struct fuse_mount_data {
-       /** The control file descriptor */
-       int fd;
-       
-       /** The file type of the root inode */
-       unsigned int rootmode;
-
-       /** The user ID of the user initiating this mount */
-       unsigned int uid;
-       
-       /** FUSE specific mount flags */
-       unsigned int flags;
-};
-
-/* FUSE mount flags: */
-
-/** If the FUSE_DEFAULT_PERMISSIONS flag is given, the filesystem
-module will check permissions based on the file mode.  Otherwise no
-permission checking is done in the kernel */
-#define FUSE_DEFAULT_PERMISSIONS (1 << 0)
-
-/** If the FUSE_ALLOW_OTHER flag is given, then not only the user
-    doing the mount will be allowed to access the filesystem */
-#define FUSE_ALLOW_OTHER         (1 << 1)
-
-/** If the FUSE_KERNEL_CACHE flag is given, then files will be cached
-    until the INVALIDATE operation is invoked */
-#define FUSE_KERNEL_CACHE        (1 << 2)
-
-/** Allow FUSE to combine reads into 64k chunks.  This is useful if
-    the filesystem is better at handling large chunks.  NOTE: in
-    current implementation the raw throughput is worse for large reads
-    than for small. */
-#define FUSE_LARGE_READ          (1 << 3)
-
 struct fuse_attr {
        unsigned int        mode;
        unsigned int        nlink;
index 6f064fe48d2a0a62f9afce4ed1ba5b4e8b7173bf..12991396c510e80252d70871178344e483874cab 100644 (file)
 
 #define FUSE_BLOCK_PAGE_SHIFT (FUSE_BLOCK_SHIFT - PAGE_CACHE_SHIFT)
 
+/** If the FUSE_DEFAULT_PERMISSIONS flag is given, the filesystem
+module will check permissions based on the file mode.  Otherwise no
+permission checking is done in the kernel */
+#define FUSE_DEFAULT_PERMISSIONS (1 << 0)
+
+/** If the FUSE_ALLOW_OTHER flag is given, then not only the user
+    doing the mount will be allowed to access the filesystem */
+#define FUSE_ALLOW_OTHER         (1 << 1)
+
+/** If the FUSE_KERNEL_CACHE flag is given, then files will be cached
+    until the INVALIDATE operation is invoked */
+#define FUSE_KERNEL_CACHE        (1 << 2)
+
+/** Allow FUSE to combine reads into 64k chunks.  This is useful if
+    the filesystem is better at handling large chunks.  NOTE: in
+    current implementation the raw throughput is worse for large reads
+    than for small. */
+#define FUSE_LARGE_READ          (1 << 3)
+
 /**
  * A Fuse connection.
  *
index 17c0f6062ffac35e8b1aa6354d3b9877a02b9107..a719ad900d068ae078244a2bd54dbcfc5d4f7ea9 100644 (file)
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/file.h>
+#include <linux/mount.h>
 #include <linux/proc_fs.h>
+#include <linux/parser.h>
+#include <linux/seq_file.h>
 #ifdef KERNEL_2_6
 #include <linux/statfs.h>
 #endif
 #ifndef FS_SAFE
 #define FS_SAFE 0
 #endif
-#ifndef FS_BINARY_MOUNTDATA
-#define FS_BINARY_MOUNTDATA 0
-#endif
+
+struct fuse_mount_data {
+       int fd;
+       unsigned int rootmode;
+       unsigned int uid;
+       unsigned int flags;
+};
 
 static void fuse_read_inode(struct inode *inode)
 {
@@ -111,24 +118,113 @@ static int fuse_statfs(struct super_block *sb, struct kstatfs *buf)
        return out.h.error;
 }
 
-static struct fuse_conn *get_conn(struct fuse_mount_data *d)
+enum { opt_fd, opt_rootmode, opt_uid, opt_default_permissions, 
+       opt_allow_other, opt_kernel_cache, opt_large_read, opt_err };
+
+static match_table_t tokens = {
+       {opt_fd, "fd=%u"},
+       {opt_rootmode, "rootmode=%o"},
+       {opt_uid, "uid=%u"},
+       {opt_default_permissions, "default_permissions"},
+       {opt_allow_other, "allow_other"},
+       {opt_kernel_cache, "kernel_cache"},
+       {opt_large_read, "large_read"},
+       {opt_err, NULL}
+};
+
+static int parse_fuse_opt(char *opt, struct fuse_mount_data *d)
+{
+       char *p;
+       memset(d, 0, sizeof(struct fuse_mount_data));
+       d->fd = -1;
+
+       if (opt == NULL)
+               return 0;
+
+       if (opt[PAGE_SIZE - 1] != '\0')
+               return 0;
+
+       while ((p = strsep(&opt, ",")) != NULL) {
+               int token;
+               int value;
+               substring_t args[MAX_OPT_ARGS];
+               if (!*p)
+                       continue;
+               
+               token = match_token(p, tokens, args);
+               switch (token) {
+               case opt_fd:
+                       if (match_int(&args[0], &value))
+                               return 0;
+                       d->fd = value;
+                       break;
+
+               case opt_rootmode:
+                       if (match_octal(&args[0], &value))
+                               return 0;
+                       d->rootmode = value;
+                       break;
+                       
+               case opt_uid:
+                       if (match_int(&args[0], &value))
+                               return 0;
+                       d->uid = value;
+                       break;
+                       
+               case opt_default_permissions:
+                       d->flags |= FUSE_DEFAULT_PERMISSIONS;
+                       break;
+
+               case opt_allow_other:
+                       d->flags |= FUSE_ALLOW_OTHER;
+                       break;
+
+               case opt_kernel_cache:
+                       d->flags |= FUSE_KERNEL_CACHE;
+                       break;
+                       
+               case opt_large_read:
+                       d->flags |= FUSE_LARGE_READ;
+                       break;
+               default:
+                       return 0;
+               }
+       }
+       if (d->fd == -1)
+               return 0;
+
+       return 1;
+}
+
+static int fuse_show_options(struct seq_file *m, struct vfsmount *mnt)
+{
+       struct fuse_conn *fc = SB_FC(mnt->mnt_sb);
+
+       seq_printf(m, ",uid=%u", fc->uid);
+       if (fc->flags & FUSE_DEFAULT_PERMISSIONS)
+               seq_puts(m, ",default_permissions");
+       if (fc->flags & FUSE_ALLOW_OTHER)
+               seq_puts(m, ",allow_other");
+       if (fc->flags & FUSE_KERNEL_CACHE)
+               seq_puts(m, ",kernel_cache");
+       if (fc->flags & FUSE_LARGE_READ)
+               seq_puts(m, ",large_read");
+       return 0;
+}
+
+static struct fuse_conn *get_conn(int fd)
 {
        struct fuse_conn *fc = NULL;
        struct file *file;
        struct inode *ino;
 
-       if (d == NULL) {
-               printk("fuse_read_super: Bad mount data\n");
-               return NULL;
-       }
-
-       file = fget(d->fd);
+       file = fget(fd);
        ino = NULL;
        if (file)
                ino = file->f_dentry->d_inode;
        
        if (!ino || !proc_fuse_dev || proc_fuse_dev->low_ino != ino->i_ino) {
-               printk("fuse_read_super: Bad file: %i\n", d->fd);
+               printk("FUSE: bad communication file descriptor: %i\n", fd);
                goto out;
        }
 
@@ -186,18 +282,20 @@ static struct super_operations fuse_super_operations = {
        .clear_inode    = fuse_clear_inode,
        .put_super      = fuse_put_super,
        .statfs         = fuse_statfs,
+       .show_options   = fuse_show_options,
 };
 
 static int fuse_read_super(struct super_block *sb, void *data, int silent)
 {      
        struct fuse_conn *fc;
        struct inode *root;
-       struct fuse_mount_data *d = data;
+       struct fuse_mount_data d;
 
-       if (!capable(CAP_SYS_ADMIN)) {
-               if (d->flags & FUSE_ALLOW_OTHER)
-                       return -EPERM;
-       }
+       if (!parse_fuse_opt((char *) data, &d))
+               return -EINVAL;
+
+       if ((d.flags & FUSE_ALLOW_OTHER) && !capable(CAP_SYS_ADMIN))
+               return -EPERM;
 
        sb->s_blocksize = PAGE_CACHE_SIZE;
        sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
@@ -208,9 +306,10 @@ static int fuse_read_super(struct super_block *sb, void *data, int silent)
        sb->s_export_op = &fuse_export_operations;
 #endif
 
-       fc = get_conn(d);
+       fc = get_conn(d.fd);
        if (fc == NULL)
                return -EINVAL;
+
        spin_lock(&fuse_lock);
        if (fc->sb != NULL) {
                printk("fuse_read_super: connection already mounted\n");
@@ -218,15 +317,15 @@ static int fuse_read_super(struct super_block *sb, void *data, int silent)
                return -EINVAL;
        }
        fc->sb = sb;
-       fc->flags = d->flags;
-       fc->uid = d->uid;
+       fc->flags = d.flags;
+       fc->uid = d.uid;
        spin_unlock(&fuse_lock);
        
        /* fc is needed in fuse_init_file_inode which could be called
           from get_root_inode */
        SB_FC(sb) = fc;
 
-       root = get_root_inode(sb, d->rootmode);
+       root = get_root_inode(sb, d.rootmode);
        if (root == NULL) {
                printk("fuse_read_super: failed to get root inode\n");
                return -EINVAL;
@@ -252,7 +351,7 @@ static struct file_system_type fuse_fs_type = {
        .name           = "fuse",
        .get_sb         = fuse_get_sb,
        .kill_sb        = kill_anon_super,
-       .fs_flags       = FS_SAFE | FS_BINARY_MOUNTDATA,
+       .fs_flags       = FS_SAFE,
 };
 #else
 static struct super_block *fuse_read_super_compat(struct super_block *sb,
index 42e9d47d563a224086775ba19a60dfcddc4a3296..bd52e4a5c8813db241b1a17586a52872f653ce4f 100644 (file)
 
 const char *progname;
 
+struct fuse_opts {
+    int kernel_cache;
+    int default_permissions;
+    int allow_other;
+    int large_read;
+};
+
 static const char *get_user_name()
 {
     struct passwd *pw = getpwuid(getuid());
@@ -289,11 +296,12 @@ static void restore_privs()
 }
 
 static int do_mount(const char *dev, const char *mnt, const char *type,
-                    mode_t rootmode, int fd, int fuseflags)
+                    mode_t rootmode, int fd, struct fuse_opts *opts)
 {
     int res;
-    struct fuse_mount_data data;
     int flags = MS_NOSUID | MS_NODEV;
+    char optbuf[1024];
+    char *s = optbuf;
 
     if(getuid() != 0) {
         res = drop_privs();
@@ -301,12 +309,17 @@ static int do_mount(const char *dev, const char *mnt, const char *type,
             return -1;
     }
     
-    data.fd = fd;
-    data.rootmode = rootmode;
-    data.uid = getuid();
-    data.flags = fuseflags;
-
-    res = mount(dev, mnt, type, flags, &data);
+    s += sprintf(s, "fd=%i,rootmode=%o,uid=%i", fd, rootmode, getuid());
+    if (opts->kernel_cache)
+        s += sprintf(s, ",kernel_cache");
+    if (opts->default_permissions)
+        s += sprintf(s, ",default_permissions");
+    if (opts->allow_other)
+        s += sprintf(s, ",allow_other");
+    if (opts->large_read)
+        s += sprintf(s, ",large_read");
+
+    res = mount(dev, mnt, type, flags, optbuf);
     if(res == -1)
         fprintf(stderr, "%s: mount failed: %s\n", progname, strerror(errno));
 
@@ -354,7 +367,8 @@ static int check_perm(const char *mnt, struct stat *stbuf)
     return 0;
 }
 
-static int mount_fuse(const char *mnt, int flags, const char *fsname)
+static int mount_fuse(const char *mnt, struct fuse_opts *opts,
+                      const char *fsname)
 {
     int res;
     int fd;
@@ -390,7 +404,7 @@ static int mount_fuse(const char *mnt, int flags, const char *fsname)
     if(fsname == NULL)
         fsname = dev;
 
-    res = do_mount(fsname, mnt, type, stbuf.st_mode & S_IFMT, fd, flags);
+    res = do_mount(fsname, mnt, type, stbuf.st_mode & S_IFMT, fd, opts);
     if(res == -1)
         return -1;
 
@@ -499,10 +513,12 @@ int main(int argc, char *argv[])
     int lazy = 0;
     char *commfd;
     const char *fsname = NULL;
-    int flags = 0;
     int quiet = 0;
+    struct fuse_opts opts;
     int cfd;
 
+
+    memset(&opts, 0, sizeof(struct fuse_opts));
     progname = argv[0];
     
     for(a = 1; a < argc; a++) {
@@ -511,7 +527,7 @@ int main(int argc, char *argv[])
 
         switch(argv[a][1]) {
         case 'c':
-            flags |= FUSE_KERNEL_CACHE;
+            opts.kernel_cache = 1;
             break;
 
         case 'h':
@@ -527,7 +543,7 @@ int main(int argc, char *argv[])
             break;
             
         case 'p':
-            flags |= FUSE_DEFAULT_PERMISSIONS;
+            opts.default_permissions = 1;
             break;
             
         case 'x':
@@ -536,7 +552,7 @@ int main(int argc, char *argv[])
                         progname, argv[a]);
                 exit(1);
             }
-            flags |= FUSE_ALLOW_OTHER;
+            opts.allow_other = 1;
             break;
             
         case 'n':
@@ -549,7 +565,7 @@ int main(int argc, char *argv[])
             break;
 
         case 'l':
-            flags |= FUSE_LARGE_READ;
+            opts.large_read = 1;
             break;
             
         case 'q':
@@ -604,7 +620,7 @@ int main(int argc, char *argv[])
         exit(1);
     }
 
-    fd = mount_fuse(mnt, flags, fsname);
+    fd = mount_fuse(mnt, &opts, fsname);
     if(fd == -1)
         exit(1);