From 62c24a8e4b10d77e08ee4a40c6f6b6a8d1eafeab Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Wed, 20 Jun 2007 21:37:58 +0000 Subject: Add fs subtype support to libfuse and fusermount --- ChangeLog | 4 ++ include/fuse_common.h | 14 +++++- lib/fuse_versionscript | 1 + lib/helper.c | 29 +++++++----- lib/mount.c | 101 ++++++++++++++++++++++++++++++++++----- lib/mount_util.c | 17 +++++++ lib/mount_util.h | 1 + util/fusermount.c | 126 ++++++++++++++++++++++++++++++------------------- 8 files changed, 222 insertions(+), 71 deletions(-) diff --git a/ChangeLog b/ChangeLog index 59653aa..9b397db 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2007-06-20 Miklos Szeredi + + * Add fs subtype support to libfuse and fusermount + 2007-06-19 Miklos Szeredi * kernel: sync with mainline (2.6.22) diff --git a/include/fuse_common.h b/include/fuse_common.h index 26e9967..384bd00 100644 --- a/include/fuse_common.h +++ b/include/fuse_common.h @@ -160,9 +160,21 @@ void fuse_unmount(const char *mountpoint, struct fuse_chan *ch); int fuse_parse_cmdline(struct fuse_args *args, char **mountpoint, int *multithreaded, int *foreground); - +/** + * Go into the background + * + * @param foreground if true, stay in the foreground + * @return 0 on success, -1 on failure + */ int fuse_daemonize(int foreground); +/** + * Get the version of the library + * + * @return the version + */ +int fuse_version(void); + /* ----------------------------------------------------------- * * Signal handling * * ----------------------------------------------------------- */ 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); diff --git a/util/fusermount.c b/util/fusermount.c index 8f69599..716caff 100644 --- a/util/fusermount.c +++ b/util/fusermount.c @@ -74,10 +74,10 @@ static void restore_privs(void) } #ifndef IGNORE_MTAB -static int add_mount(const char *fsname, const char *mnt, const char *type, +static int add_mount(const char *source, const char *mnt, const char *type, const char *opts) { - return fuse_mnt_add_mount(progname, fsname, mnt, type, opts); + return fuse_mnt_add_mount(progname, source, mnt, type, opts); } static int unmount_fuse(const char *mnt, int quiet, int lazy) @@ -108,7 +108,9 @@ static int unmount_fuse(const char *mnt, int quiet, int lazy) while ((entp = getmntent(fp)) != NULL) { if (!found && strcmp(entp->mnt_dir, mnt) == 0 && (strcmp(entp->mnt_type, "fuse") == 0 || - strcmp(entp->mnt_type, "fuseblk") == 0)) { + strcmp(entp->mnt_type, "fuseblk") == 0 || + strncmp(entp->mnt_type, "fuse.", 5) == 0 || + strncmp(entp->mnt_type, "fuseblk.", 8) == 0)) { char *p = strstr(entp->mnt_opts, "user="); if (p && (p == entp->mnt_opts || *(p-1) == ',') && strcmp(p + 5, user) == 0) { @@ -150,7 +152,8 @@ static int count_fuse_fs(void) return -1; } while ((entp = getmntent(fp)) != NULL) { - if (strcmp(entp->mnt_type, "fuse") == 0) + if (strcmp(entp->mnt_type, "fuse") == 0 || + strncmp(entp->mnt_type, "fuse.", 5) == 0) count ++; } endmntent(fp); @@ -164,10 +167,10 @@ static int count_fuse_fs() return 0; } -static int add_mount(const char *fsname, const char *mnt, const char *type, +static int add_mount(const char *source, const char *mnt, const char *type, const char *opts) { - (void) fsname; + (void) source; (void) mnt; (void) type; (void) opts; @@ -345,25 +348,26 @@ static int opt_eq(const char *s, unsigned len, const char *opt) return 0; } -static int has_fuseblk(void) +static int get_string_opt(const char *s, unsigned len, const char *opt, + char **val) { - char buf[256]; - FILE *f = fopen("/proc/filesystems", "r"); - if (!f) - return 1; + unsigned opt_len = strlen(opt); - while (fgets(buf, sizeof(buf), f)) - if (strstr(buf, "fuseblk\n")) { - fclose(f); - return 1; - } + if (*val) + free(*val); + *val = (char *) malloc(len - opt_len + 1); + if (!*val) { + fprintf(stderr, "%s: failed to allocate memory\n", progname); + return 0; + } - fclose(f); - return 0; + memcpy(*val, s + opt_len, len - opt_len); + (*val)[len - opt_len] = '\0'; + return 1; } -static int do_mount(const char *mnt, const char **type, mode_t rootmode, - int fd, const char *opts, const char *dev, char **fsnamep, +static int do_mount(const char *mnt, char **typep, mode_t rootmode, + int fd, const char *opts, const char *dev, char **sourcep, char **mnt_optsp, off_t rootsize) { int res; @@ -373,6 +377,9 @@ static int do_mount(const char *mnt, const char **type, mode_t rootmode, const char *s; char *d; char *fsname = NULL; + char *subtype = NULL; + char *source = NULL; + char *type = NULL; int check_empty = 1; int blkdev = 0; @@ -385,18 +392,14 @@ static int do_mount(const char *mnt, const char **type, mode_t rootmode, for (s = opts, d = optbuf; *s;) { unsigned len; const char *fsname_str = "fsname="; + const char *subtype_str = "subtype="; for (len = 0; s[len] && s[len] != ','; len++); if (begins_with(s, fsname_str)) { - unsigned fsname_str_len = strlen(fsname_str); - if (fsname) - free(fsname); - fsname = (char *) malloc(len - fsname_str_len + 1); - if (!fsname) { - fprintf(stderr, "%s: failed to allocate memory\n", progname); + if (!get_string_opt(s, len, fsname_str, &fsname)) + goto err; + } else if (begins_with(s, subtype_str)) { + if (!get_string_opt(s, len, subtype_str, &subtype)) goto err; - } - memcpy(fsname, s + fsname_str_len, len - fsname_str_len); - fsname[len - fsname_str_len] = '\0'; } else if (opt_eq(s, len, "blkdev")) { if (getuid() != 0) { fprintf(stderr, "%s: option blkdev is privileged\n", progname); @@ -453,35 +456,58 @@ static int do_mount(const char *mnt, const char **type, mode_t rootmode, sprintf(d, "fd=%i,rootmode=%o,user_id=%i,group_id=%i", fd, rootmode, getuid(), getgid()); - if (fsname == NULL) { - fsname = strdup(dev); - if (!fsname) { - fprintf(stderr, "%s: failed to allocate memory\n", progname); - goto err; - } - } if (check_empty && fuse_mnt_check_empty(progname, mnt, rootmode, rootsize) == -1) goto err; - if (blkdev) - *type = "fuseblk"; - res = mount(fsname, mnt, *type, flags, optbuf); + source = malloc((fsname ? strlen(fsname) : 0) + + (subtype ? strlen(subtype) : 0) + strlen(dev) + 32); + + type = malloc((subtype ? strlen(subtype) : 0) + 32); + if (!type || !source) { + fprintf(stderr, "%s: failed to allocate memory\n", progname); + goto err; + } + + if (subtype) + sprintf(type, "%s.%s", blkdev ? "fuseblk" : "fuse", subtype); + else + strcpy(type, blkdev ? "fuseblk" : "fuse"); + + if (fsname) + strcpy(source, fsname); + else + strcpy(source, subtype ? subtype : dev); + + res = mount(source, mnt, type, flags, optbuf); + if (res == -1 && errno == ENODEV && subtype) { + /* Probably missing subtype support */ + strcpy(type, blkdev ? "fuseblk" : "fuse"); + if (fsname) { + if (!blkdev) + sprintf(source, "%s#%s", subtype, fsname); + } else { + strcpy(source, type); + } + + res = mount(source, mnt, type, flags, optbuf); + } if (res == -1 && errno == EINVAL) { /* It could be an old version not supporting group_id */ sprintf(d, "fd=%i,rootmode=%o,user_id=%i", fd, rootmode, getuid()); - res = mount(fsname, mnt, *type, flags, optbuf); + res = mount(source, mnt, type, flags, optbuf); } if (res == -1) { int errno_save = errno; - if (blkdev && errno == ENODEV && !has_fuseblk()) - fprintf(stderr, "%s: 'fuseblk' support missing; try the kernel module from fuse-2.6.0 or later\n", progname); + if (blkdev && errno == ENODEV && !fuse_mnt_check_fuseblk()) + fprintf(stderr, "%s: 'fuseblk' support missing\n", progname); else fprintf(stderr, "%s: mount failed: %s\n", progname, strerror(errno_save)); goto err; } else { - *fsnamep = fsname; + *sourcep = source; + *typep = type; *mnt_optsp = mnt_opts; } free(optbuf); @@ -490,6 +516,9 @@ static int do_mount(const char *mnt, const char **type, mode_t rootmode, err: free(fsname); + free(subtype); + free(source); + free(type); free(mnt_opts); free(optbuf); return -1; @@ -666,9 +695,9 @@ static int mount_fuse(const char *mnt, const char *opts) int res; int fd; char *dev; - const char *type = "fuse"; struct stat stbuf; - char *fsname = NULL; + char *type = NULL; + char *source = NULL; char *mnt_opts = NULL; const char *real_mnt = mnt; int currdir_fd = -1; @@ -696,7 +725,7 @@ static int mount_fuse(const char *mnt, const char *opts) restore_privs(); if (res != -1) res = do_mount(real_mnt, &type, stbuf.st_mode & S_IFMT, fd, opts, - dev, &fsname, &mnt_opts, stbuf.st_size); + dev, &source, &mnt_opts, stbuf.st_size); } else restore_privs(); @@ -713,7 +742,7 @@ static int mount_fuse(const char *mnt, const char *opts) } if (geteuid() == 0) { - res = add_mount(fsname, mnt, type, mnt_opts); + res = add_mount(source, mnt, type, mnt_opts); if (res == -1) { umount2(mnt, 2); /* lazy umount */ close(fd); @@ -721,7 +750,8 @@ static int mount_fuse(const char *mnt, const char *opts) } } - free(fsname); + free(source); + free(type); free(mnt_opts); free(dev); -- cgit v1.2.3