diff options
Diffstat (limited to 'lib/mount.c')
-rw-r--r-- | lib/mount.c | 101 |
1 files changed, 90 insertions, 11 deletions
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; |