aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorGravatar Miklos Szeredi <miklos@szeredi.hu>2007-06-20 21:37:58 +0000
committerGravatar Miklos Szeredi <miklos@szeredi.hu>2007-06-20 21:37:58 +0000
commit62c24a8e4b10d77e08ee4a40c6f6b6a8d1eafeab (patch)
treea94336f70cf1199760a84089c8e83dfe1fe01167 /lib
parent2b3a22fea0509681d9e86d5131a0008165bbf6ba (diff)
Add fs subtype support to libfuse and fusermount
Diffstat (limited to 'lib')
-rw-r--r--lib/fuse_versionscript1
-rw-r--r--lib/helper.c29
-rw-r--r--lib/mount.c101
-rw-r--r--lib/mount_util.c17
-rw-r--r--lib/mount_util.h1
5 files changed, 127 insertions, 22 deletions
diff --git a/lib/fuse_versionscript b/lib/fuse_versionscript
index cbce074..6125f20 100644
--- a/lib/fuse_versionscript
+++ b/lib/fuse_versionscript
@@ -150,6 +150,7 @@ FUSE_2.7 {
fuse_fs_utimens;
fuse_fs_write;
fuse_register_module;
+ fuse_version;
local:
*;
diff --git a/lib/helper.c b/lib/helper.c
index 1de088f..d7cc9b7 100644
--- a/lib/helper.c
+++ b/lib/helper.c
@@ -29,7 +29,7 @@ enum {
struct helper_opts {
int singlethread;
int foreground;
- int fsname;
+ int nodefault_subtype;
char *mountpoint;
};
@@ -40,7 +40,8 @@ static const struct fuse_opt fuse_helper_opts[] = {
FUSE_HELPER_OPT("debug", foreground),
FUSE_HELPER_OPT("-f", foreground),
FUSE_HELPER_OPT("-s", singlethread),
- FUSE_HELPER_OPT("fsname=", fsname),
+ FUSE_HELPER_OPT("fsname=", nodefault_subtype),
+ FUSE_HELPER_OPT("subtype=", nodefault_subtype),
FUSE_OPT_KEY("-h", KEY_HELP),
FUSE_OPT_KEY("--help", KEY_HELP),
@@ -50,6 +51,7 @@ static const struct fuse_opt fuse_helper_opts[] = {
FUSE_OPT_KEY("-d", FUSE_OPT_KEY_KEEP),
FUSE_OPT_KEY("debug", FUSE_OPT_KEY_KEEP),
FUSE_OPT_KEY("fsname=", FUSE_OPT_KEY_KEEP),
+ FUSE_OPT_KEY("subtype=", FUSE_OPT_KEY_KEEP),
FUSE_OPT_END
};
@@ -117,24 +119,24 @@ static int fuse_helper_opt_proc(void *data, const char *arg, int key,
}
}
-static int add_default_fsname(const char *progname, struct fuse_args *args)
+static int add_default_subtype(const char *progname, struct fuse_args *args)
{
int res;
- char *fsname_opt;
+ char *subtype_opt;
const char *basename = strrchr(progname, '/');
if (basename == NULL)
basename = progname;
else if (basename[1] != '\0')
basename++;
- fsname_opt = (char *) malloc(strlen(basename) + 64);
- if (fsname_opt == NULL) {
+ subtype_opt = (char *) malloc(strlen(basename) + 64);
+ if (subtype_opt == NULL) {
fprintf(stderr, "fuse: memory allocation failed\n");
return -1;
}
- sprintf(fsname_opt, "-ofsname=%s", basename);
- res = fuse_opt_add_arg(args, fsname_opt);
- free(fsname_opt);
+ sprintf(subtype_opt, "-osubtype=%s", basename);
+ res = fuse_opt_add_arg(args, subtype_opt);
+ free(subtype_opt);
return res;
}
@@ -149,8 +151,8 @@ int fuse_parse_cmdline(struct fuse_args *args, char **mountpoint,
if (res == -1)
return -1;
- if (!hopts.fsname) {
- res = add_default_fsname(args->argv[0], args);
+ if (!hopts.nodefault_subtype) {
+ res = add_default_subtype(args->argv[0], args);
if (res == -1)
goto err;
}
@@ -331,6 +333,11 @@ int fuse_main(void)
return -1;
}
+int fuse_version(void)
+{
+ return FUSE_VERSION;
+}
+
#include "fuse_compat.h"
#ifndef __FreeBSD__
diff --git a/lib/mount.c b/lib/mount.c
index 24bcf8c..aa0c0cb 100644
--- a/lib/mount.c
+++ b/lib/mount.c
@@ -39,6 +39,7 @@ enum {
KEY_KERN_FLAG,
KEY_KERN_OPT,
KEY_FUSERMOUNT_OPT,
+ KEY_SUBTYPE_OPT,
KEY_MTAB_OPT,
KEY_ALLOW_ROOT,
KEY_RO,
@@ -54,6 +55,8 @@ struct mount_opts {
int nonempty;
int blkdev;
char *fsname;
+ char *subtype;
+ char *subtype_opt;
char *mtab_opts;
char *fusermount_opts;
char *kernel_opts;
@@ -67,11 +70,13 @@ static const struct fuse_opt fuse_mount_opts[] = {
FUSE_MOUNT_OPT("nonempty", nonempty),
FUSE_MOUNT_OPT("blkdev", blkdev),
FUSE_MOUNT_OPT("fsname=%s", fsname),
+ FUSE_MOUNT_OPT("subtype=%s", subtype),
FUSE_OPT_KEY("allow_other", KEY_KERN_OPT),
FUSE_OPT_KEY("allow_root", KEY_ALLOW_ROOT),
FUSE_OPT_KEY("nonempty", KEY_FUSERMOUNT_OPT),
FUSE_OPT_KEY("blkdev", KEY_FUSERMOUNT_OPT),
FUSE_OPT_KEY("fsname=", KEY_FUSERMOUNT_OPT),
+ FUSE_OPT_KEY("subtype=", KEY_SUBTYPE_OPT),
FUSE_OPT_KEY("large_read", KEY_KERN_OPT),
FUSE_OPT_KEY("blksize=", KEY_KERN_OPT),
FUSE_OPT_KEY("default_permissions", KEY_KERN_OPT),
@@ -107,6 +112,7 @@ static void mount_help(void)
" -o nonempty allow mounts over non-empty file/dir\n"
" -o default_permissions enable permission checking by kernel\n"
" -o fsname=NAME set filesystem name\n"
+ " -o subtype=NAME set filesystem type\n"
" -o large_read issue large read requests (2.4 only)\n"
" -o max_read=N set maximum size of read requests\n"
"\n"
@@ -196,6 +202,9 @@ static int fuse_mount_opt_proc(void *data, const char *arg, int key,
case KEY_FUSERMOUNT_OPT:
return fuse_opt_add_opt(&mo->fusermount_opts, arg);
+ case KEY_SUBTYPE_OPT:
+ return fuse_opt_add_opt(&mo->subtype_opt, arg);
+
case KEY_MTAB_OPT:
return fuse_opt_add_opt(&mo->mtab_opts, arg);
@@ -304,7 +313,8 @@ void fuse_unmount_compat22(const char *mountpoint)
fuse_kern_unmount(mountpoint, -1);
}
-int fuse_mount_compat22(const char *mountpoint, const char *opts)
+static int fuse_mount_fusermount(const char *mountpoint, const char *opts,
+ int quiet)
{
int fds[2], pid;
int res;
@@ -334,6 +344,12 @@ int fuse_mount_compat22(const char *mountpoint, const char *opts)
const char *argv[32];
int a = 0;
+ if (quiet) {
+ int fd = open("/dev/null", O_RDONLY);
+ dup2(fd, 1);
+ dup2(fd, 2);
+ }
+
argv[a++] = FUSERMOUNT_PROG;
if (opts) {
argv[a++] = "-o";
@@ -360,13 +376,18 @@ int fuse_mount_compat22(const char *mountpoint, const char *opts)
return rv;
}
+int fuse_mount_compat22(const char *mountpoint, const char *opts)
+{
+ return fuse_mount_fusermount(mountpoint, opts, 0);
+}
static int fuse_mount_sys(const char *mnt, struct mount_opts *mo,
const char *mnt_opts)
{
- const char *type = mo->blkdev ? "fuseblk" : "fuse";
char tmp[128];
const char *devname = "/dev/fuse";
+ char *source = NULL;
+ char *type = NULL;
struct stat stbuf;
int fd;
int res;
@@ -395,9 +416,6 @@ static int fuse_mount_sys(const char *mnt, struct mount_opts *mo,
return -1;
}
- if (mo->fsname)
- devname = mo->fsname;
-
snprintf(tmp, sizeof(tmp), "fd=%i,rootmode=%o,user_id=%i,group_id=%i", fd,
stbuf.st_mode & S_IFMT, getuid(), getgid());
@@ -405,16 +423,52 @@ static int fuse_mount_sys(const char *mnt, struct mount_opts *mo,
if (res == -1)
goto out_close;
- res = mount(devname, mnt, type, mo->flags, mo->kernel_opts);
+ source = malloc((mo->fsname ? strlen(mo->fsname) : 0) +
+ (mo->subtype ? strlen(mo->subtype) : 0) +
+ strlen(devname) + 32);
+
+ type = malloc((mo->subtype ? strlen(mo->subtype) : 0) + 32);
+ if (!type || !source) {
+ fprintf(stderr, "fuse: failed to allocate memory\n");
+ goto out_close;
+ }
+
+ strcpy(type, mo->blkdev ? "fuseblk" : "fuse");
+ if (mo->subtype) {
+ strcat(type, ".");
+ strcat(type, mo->subtype);
+ }
+ strcpy(source,
+ mo->fsname ? mo->fsname : (mo->subtype ? mo->subtype : devname));
+
+ res = mount(source, mnt, type, mo->flags, mo->kernel_opts);
+ if (res == -1 && errno == ENODEV && mo->subtype) {
+ /* Probably missing subtype support */
+ strcpy(type, mo->blkdev ? "fuseblk" : "fuse");
+ if (mo->fsname) {
+ if (!mo->blkdev)
+ sprintf(source, "%s#%s", mo->subtype, mo->fsname);
+ } else {
+ strcpy(source, type);
+ }
+ res = mount(source, mnt, type, mo->flags, mo->kernel_opts);
+ }
if (res == -1) {
/*
* Maybe kernel doesn't support unprivileged mounts, in this
* case try falling back to fusermount
*/
- if (errno == EPERM)
+ if (errno == EPERM) {
res = -2;
- else
- perror("fuse: mount failed");
+ } else {
+ int errno_save = errno;
+ if (mo->blkdev && errno == ENODEV && !fuse_mnt_check_fuseblk())
+ fprintf(stderr, "fuse: 'fuseblk' support missing\n");
+ else
+ fprintf(stderr, "fuse: mount failed: %s\n",
+ strerror(errno_save));
+ }
+
goto out_close;
}
@@ -424,7 +478,7 @@ static int fuse_mount_sys(const char *mnt, struct mount_opts *mo,
if (!newmnt)
goto out_umount;
- res = fuse_mnt_add_mount("fuse", devname, newmnt, type, mnt_opts);
+ res = fuse_mnt_add_mount("fuse", source, newmnt, type, mnt_opts);
free(newmnt);
if (res == -1)
goto out_umount;
@@ -435,6 +489,8 @@ static int fuse_mount_sys(const char *mnt, struct mount_opts *mo,
out_umount:
umount2(mnt, 2); /* lazy umount */
out_close:
+ free(type);
+ free(source);
close(fd);
return res;
}
@@ -460,6 +516,11 @@ int fuse_kern_mount(const char *mountpoint, struct fuse_args *args)
int res = -1;
char *mnt_opts = NULL;
+ if (!mountpoint) {
+ fprintf(stderr, "fuse: missing mountpoint\n");
+ return -1;
+ }
+
memset(&mo, 0, sizeof(mo));
mo.flags = MS_NOSUID | MS_NODEV;
@@ -489,12 +550,30 @@ int fuse_kern_mount(const char *mountpoint, struct fuse_args *args)
fuse_opt_add_opt(&mnt_opts, mo.fusermount_opts) == -1)
goto out;
- res = fuse_mount_compat22(mountpoint, mnt_opts);
+ if (mo.subtype) {
+ char *tmp_opts = NULL;
+
+ res = -1;
+ if (fuse_opt_add_opt(&tmp_opts, mnt_opts) == -1 ||
+ fuse_opt_add_opt(&tmp_opts, mo.subtype_opt) == -1) {
+ free(tmp_opts);
+ goto out;
+ }
+
+ res = fuse_mount_fusermount(mountpoint, tmp_opts, 1);
+ free(tmp_opts);
+ if (res == -1)
+ res = fuse_mount_fusermount(mountpoint, mnt_opts, 0);
+ } else {
+ res = fuse_mount_fusermount(mountpoint, mnt_opts, 0);
+ }
}
out:
free(mnt_opts);
free(mo.fsname);
+ free(mo.subtype);
free(mo.fusermount_opts);
+ free(mo.subtype_opt);
free(mo.kernel_opts);
free(mo.mtab_opts);
return res;
diff --git a/lib/mount_util.c b/lib/mount_util.c
index 02b2731..dccecdf 100644
--- a/lib/mount_util.c
+++ b/lib/mount_util.c
@@ -193,3 +193,20 @@ int fuse_mnt_check_empty(const char *progname, const char *mnt,
}
return 0;
}
+
+int fuse_mnt_check_fuseblk(void)
+{
+ char buf[256];
+ FILE *f = fopen("/proc/filesystems", "r");
+ if (!f)
+ return 1;
+
+ while (fgets(buf, sizeof(buf), f))
+ if (strstr(buf, "fuseblk\n")) {
+ fclose(f);
+ return 1;
+ }
+
+ fclose(f);
+ return 0;
+}
diff --git a/lib/mount_util.h b/lib/mount_util.h
index 106a6f8..f9f6cbe 100644
--- a/lib/mount_util.h
+++ b/lib/mount_util.h
@@ -14,3 +14,4 @@ int fuse_mnt_umount(const char *progname, const char *mnt, int lazy);
char *fuse_mnt_resolve_path(const char *progname, const char *orig);
int fuse_mnt_check_empty(const char *progname, const char *mnt,
mode_t rootmode, off_t rootsize);
+int fuse_mnt_check_fuseblk(void);