#include <sys/types.h>
#include <sys/stat.h>
#include <vfs/fuse/fuse_mount.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <unistd.h>
#include <getopt.h>
#include <mntopts.h>
#include <err.h>
#define MOPT_FUSE_LINUX_OPTS \
{ "default_permissions", 0, FUSE_MOUNT_DEFAULT_PERMISSIONS, 1 }, \
{ "allow_other", 0, FUSE_MOUNT_ALLOW_OTHER, 1 }, \
{ "max_read=", 0, FUSE_MOUNT_MAX_READ, 1 }, \
{ "subtype=", 0, FUSE_MOUNT_SUBTYPE, 1 }
#define MOPT_FUSE_LINUX_IGNORE_OPTS \
{ "fsname=", 0, 0, 1 }, \
{ "fd=", 0, 0, 1 }, \
{ "rootmode=", 0, 0, 1 }, \
{ "user_id=", 0, 0, 1 }, \
{ "group_id=", 0, 0, 1 }, \
\
{ "auto_unmount", 0, 0, 1 }, \
{ "blkdev", 0, 0, 1 }, \
{ "blksize=", 0, 0, 1 }, \
{ "context=", 0, 0, 1 }, \
{ "fscontext=", 0, 0, 1 }, \
{ "defcontext=", 0, 0, 1 }, \
{ "rootcontext=", 0, 0, 1 }, \
{ "user=", 0, 0, 1 }, \
{ "-r", 0, 0, 1 }, \
{ "ro", 0, 0, 1 }, \
{ "rw", 0, 0, 1 }, \
{ "suid", 0, 0, 1 }, \
{ "nosuid", 0, 0, 1 }, \
{ "dev", 0, 0, 1 }, \
{ "nodev", 0, 0, 1 }, \
{ "exec", 0, 0, 1 }, \
{ "noexec", 0, 0, 1 }, \
{ "async", 0, 0, 1 }, \
{ "sync", 0, 0, 1 }, \
{ "dirsync", 0, 0, 1 }, \
{ "atime", 0, 0, 1 }, \
{ "noatime", 0, 0, 1 }
static struct mntopt mopts[] = {
MOPT_FUSE_LINUX_OPTS,
MOPT_FUSE_LINUX_IGNORE_OPTS,
MOPT_STDOPTS,
MOPT_NULL
};
static void
usage(void)
{
fprintf(stderr, "usage: mount_fusefs [-o options] fd mountpoint\n");
exit(1);
}
static char*
get_optval(const char *ptr)
{
char *ret = strdup(ptr);
const char *end = strstr(ptr, ",");
if (!end)
return ret;
ret[(int)(end - ptr)] = '\0';
return ret;
}
int
main(int argc, char **argv)
{
struct fuse_mount_info args;
struct vfsconf vfc;
struct stat st;
const char *fdstr, *mntpt;
char *ep, mntpath[MAXPATHLEN], fusedev[64];
int error, c, fd, mntflags;
mntflags = 0;
memset(&args, 0, sizeof(args));
while ((c = getopt_long(argc, argv, "ho:", NULL, NULL)) != -1) {
switch(c) {
case 'o':
getmntopts(optarg, mopts, &mntflags, &args.flags);
if (args.flags & FUSE_MOUNT_MAX_READ) {
char *p = strstr(optarg, "max_read=");
if (p) {
p = get_optval(p + 9);
args.max_read = strtol(p, NULL, 0);
free(p);
}
}
if (args.flags & FUSE_MOUNT_SUBTYPE) {
char *p = strstr(optarg, "subtype=");
if (p) {
p = get_optval(p + 8);
args.subtype = strdup(p);
free(p);
}
}
break;
case 'h':
default:
usage();
}
}
argc -= optind;
argv += optind;
if (argc < 2)
usage();
fdstr = argv[0];
mntpt = argv[1];
checkpath(mntpt, mntpath);
fd = strtol(fdstr, &ep, 10);
if (fd <= 0 || *ep != '\0')
err(1, "Invalid FUSE fd %s", fdstr);
if (fstat(fd, &st) == -1)
err(1, "Failed to stat FUSE fd %d", fd);
strcpy(fusedev, "/dev/");
devname_r(st.st_rdev, S_IFCHR, fusedev + strlen(fusedev),
sizeof(fusedev) - strlen(fusedev));
if (stat(fusedev, &st) == -1)
err(1, "Failed to stat FUSE device %s", fusedev);
if (strncmp(fusedev, "/dev/fuse", 9))
err(1, "Invalid FUSE device %s", fusedev);
args.fd = fd;
args.from = strdup(fusedev);
error = getvfsbyname("fuse", &vfc);
if (error && vfsisloadable("fuse")) {
if(vfsload("fuse"))
err(1, "vfsload(%s)", "fuse");
endvfsent();
error = getvfsbyname("fuse", &vfc);
}
if (error)
errx(1, "%s filesystem not available", "fuse");
if (mount(vfc.vfc_name, mntpath, mntflags, &args) == -1)
err(1, "mount");
return 0;
}