Logo Search packages:      
Sourcecode: fuse version File versions  Download package

mount_bsd.c

/*
    FUSE: Filesystem in Userspace
    Copyright (C) 2005-2006 Csaba Henk <csaba.henk@creo.hu>

    This program can be distributed under the terms of the GNU LGPL.
    See the file COPYING.LIB.
*/

#include "fuse.h"
#include "fuse_opt.h"

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stddef.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/wait.h>
#include <string.h>

#define FUSERMOUNT_PROG         "mount_fusefs"
#define FUSE_DEV_TRUNK          "/dev/fuse"

enum {
    KEY_ALLOW_ROOT,
    KEY_RO,
    KEY_HELP,
    KEY_VERSION,
    KEY_KERN
};

struct mount_opts {
    int allow_other;
    int allow_root;
    int ishelp;
    char *kernel_opts;
};

static const struct fuse_opt fuse_mount_opts[] = {
    { "allow_other", offsetof(struct mount_opts, allow_other), 1 },
    { "allow_root", offsetof(struct mount_opts, allow_root), 1 },
    FUSE_OPT_KEY("allow_root",          KEY_ALLOW_ROOT),
    FUSE_OPT_KEY("-r",                  KEY_RO),
    FUSE_OPT_KEY("-h",                  KEY_HELP),
    FUSE_OPT_KEY("--help",              KEY_HELP),
    FUSE_OPT_KEY("-V",                  KEY_VERSION),
    FUSE_OPT_KEY("--version",           KEY_VERSION),
    /* standard FreeBSD mount options */
    FUSE_OPT_KEY("dev",                 KEY_KERN),
    FUSE_OPT_KEY("async",               KEY_KERN),
    FUSE_OPT_KEY("atime",               KEY_KERN),
    FUSE_OPT_KEY("dev",                 KEY_KERN),
    FUSE_OPT_KEY("exec",                KEY_KERN),
    FUSE_OPT_KEY("suid",                KEY_KERN),
    FUSE_OPT_KEY("symfollow",           KEY_KERN),
    FUSE_OPT_KEY("rdonly",              KEY_KERN),
    FUSE_OPT_KEY("sync",                KEY_KERN),
    FUSE_OPT_KEY("union",               KEY_KERN),
    FUSE_OPT_KEY("userquota",           KEY_KERN),
    FUSE_OPT_KEY("groupquota",          KEY_KERN),
    FUSE_OPT_KEY("clusterr",            KEY_KERN),
    FUSE_OPT_KEY("clusterw",            KEY_KERN),
    FUSE_OPT_KEY("suiddir",             KEY_KERN),
    FUSE_OPT_KEY("snapshot",            KEY_KERN),
    FUSE_OPT_KEY("multilabel",          KEY_KERN),
    FUSE_OPT_KEY("acls",                KEY_KERN),
    FUSE_OPT_KEY("force",               KEY_KERN),
    FUSE_OPT_KEY("update",              KEY_KERN),
    FUSE_OPT_KEY("ro",                  KEY_KERN),
    FUSE_OPT_KEY("rw",                  KEY_KERN),
    FUSE_OPT_KEY("auto",                KEY_KERN),
    /* stock FBSD mountopt parsing routine lets anything be negated... */
    FUSE_OPT_KEY("nodev",               KEY_KERN),
    FUSE_OPT_KEY("noasync",             KEY_KERN),
    FUSE_OPT_KEY("noatime",             KEY_KERN),
    FUSE_OPT_KEY("nodev",               KEY_KERN),
    FUSE_OPT_KEY("noexec",              KEY_KERN),
    FUSE_OPT_KEY("nosuid",              KEY_KERN),
    FUSE_OPT_KEY("nosymfollow",         KEY_KERN),
    FUSE_OPT_KEY("nordonly",            KEY_KERN),
    FUSE_OPT_KEY("nosync",              KEY_KERN),
    FUSE_OPT_KEY("nounion",             KEY_KERN),
    FUSE_OPT_KEY("nouserquota",         KEY_KERN),
    FUSE_OPT_KEY("nogroupquota",        KEY_KERN),
    FUSE_OPT_KEY("noclusterr",          KEY_KERN),
    FUSE_OPT_KEY("noclusterw",          KEY_KERN),
    FUSE_OPT_KEY("nosuiddir",           KEY_KERN),
    FUSE_OPT_KEY("nosnapshot",          KEY_KERN),
    FUSE_OPT_KEY("nomultilabel",        KEY_KERN),
    FUSE_OPT_KEY("noacls",              KEY_KERN),
    FUSE_OPT_KEY("noforce",             KEY_KERN),
    FUSE_OPT_KEY("noupdate",            KEY_KERN),
    FUSE_OPT_KEY("noro",                KEY_KERN),
    FUSE_OPT_KEY("norw",                KEY_KERN),
    FUSE_OPT_KEY("noauto",              KEY_KERN),
    /* options supported under both Linux and FBSD */
    FUSE_OPT_KEY("allow_other",         KEY_KERN),
    FUSE_OPT_KEY("default_permissions", KEY_KERN),
    /* FBSD FUSE specific mount options */
    FUSE_OPT_KEY("private",             KEY_KERN),
    FUSE_OPT_KEY("neglect_shares",      KEY_KERN),
    FUSE_OPT_KEY("push_symlinks_in",    KEY_KERN),
    /* Linux specific mount options, but let just the mount util handle them */
    FUSE_OPT_KEY("fsname=",             KEY_KERN),
    FUSE_OPT_KEY("nonempty",            KEY_KERN),
    FUSE_OPT_KEY("large_read",          KEY_KERN),
    FUSE_OPT_KEY("max_read=",           KEY_KERN),
    FUSE_OPT_END
};

static void mount_help(void)
{
    fprintf(stderr,
            "    -o allow_root          allow access to root\n"
            );
    system(FUSERMOUNT_PROG " --help");
    fputc('\n', stderr);
}

static void mount_version(void)
{
    system(FUSERMOUNT_PROG " --version");
}

static int fuse_mount_opt_proc(void *data, const char *arg, int key,
                               struct fuse_args *outargs)
{
    struct mount_opts *mo = data;

    switch (key) {
    case KEY_ALLOW_ROOT:
        if (fuse_opt_add_opt(&mo->kernel_opts, "allow_other") == -1 ||
            fuse_opt_add_arg(outargs, "-oallow_root") == -1)
            return -1;
        return 0;

    case KEY_RO:
        arg = "ro";
        /* fall through */

    case KEY_KERN:
        return fuse_opt_add_opt(&mo->kernel_opts, arg);

    case KEY_HELP:
        mount_help();
        mo->ishelp = 1;
        break;

    case KEY_VERSION:
        mount_version();
        mo->ishelp = 1;
        break;
    }
    return 1;
}

void fuse_unmount(const char *mountpoint)
{
    char dev[128];
    char *ssc, *umount_cmd;
    FILE *sf;
    int rv;
    char *seekscript =
    "exec 2>/dev/null; " /* error message is annoying in help output */
    "/usr/bin/fstat " FUSE_DEV_TRUNK "* | "
    "/usr/bin/awk 'BEGIN{ getline; if (! ($3 == \"PID\" && $10 == \"NAME\")) exit 1; }; "
    "              { if ($3 == %d) print $10; }' | "
    "/usr/bin/sort | "
    "/usr/bin/uniq | "
    "/usr/bin/awk '{ i += 1; if (i > 1){ exit 1; }; printf; }; END{ if (i == 0) exit 1; }'";

    (void) mountpoint;

    asprintf(&ssc, seekscript, getpid());

    errno = 0;
    sf = popen(ssc, "r");
    if (! sf)
        return;

    fgets(dev, sizeof(dev), sf);
    rv = pclose(sf);
    if (rv)
        return;

    asprintf(&umount_cmd, "/sbin/umount %s", dev);
    system(umount_cmd);
}

static int fuse_mount_core(const char *mountpoint, const char *opts)
{
    const char *mountprog = FUSERMOUNT_PROG;
    int fd;
    char *fdnam, *dev;
    int pid;

    fdnam = getenv("FUSE_DEV_FD");

    if (fdnam) {
        char *ep;

        fd = strtol(fdnam, &ep, 10);

        if (*ep != '\0') {
            fprintf(stderr, "invalid value given in FUSE_DEV_FD\n");
            return -1;
        }

        if (fd < 0)
            return -1;

        goto mount;
    }

    dev = getenv("FUSE_DEV_NAME");

    if (! dev)
      dev = FUSE_DEV_TRUNK;

    if ((fd = open(dev, O_RDWR)) < 0) {
        perror("fuse: failed to open fuse device");
        return -1;
    }

mount:
    if (getenv("FUSE_NO_MOUNT") || ! mountpoint)
        goto out;

    pid = fork();

    if (pid == -1) {
        perror("fuse: fork() failed");
        close(fd);
        return -1;
    }

    if (pid == 0) {
        pid = fork();

        if (pid == -1) {
            perror("fuse: fork() failed");
            close(fd);
            exit(1);
        }

        if (pid == 0) {
            const char *argv[32];
            int a = 0;

            if (! fdnam)
                asprintf(&fdnam, "%d", fd);

            argv[a++] = mountprog;
            if (opts) {
                argv[a++] = "-o";
                argv[a++] = opts;
            }
            argv[a++] = fdnam;
            argv[a++] = mountpoint;
            argv[a++] = NULL;
            execvp(mountprog, (char **) argv);
            perror("fuse: failed to exec mount program");
            exit(1);
        }

        exit(0);
    }

    waitpid(pid, NULL, 0);

out:
    return fd;
}

int fuse_mount(const char *mountpoint, struct fuse_args *args)
{
    struct mount_opts mo;
    int res = -1;

    memset(&mo, 0, sizeof(mo));
    /* mount util should not try to spawn the daemon */
    setenv("MOUNT_FUSEFS_SAFE", "1", 1);
    /* to notify the mount util it's called from lib */
    setenv("MOUNT_FUSEFS_CALL_BY_LIB", "1", 1);

    if (args &&
        fuse_opt_parse(args, &mo, fuse_mount_opts, fuse_mount_opt_proc) == -1)
        return -1;

    if (mo.allow_other && mo.allow_root) {
        fprintf(stderr, "fuse: 'allow_other' and 'allow_root' options are mutually exclusive\n");
        goto out;
    }
    if (mo.ishelp)
        return 0;

    res = fuse_mount_core(mountpoint, mo.kernel_opts);
 out:
    free(mo.kernel_opts);
    return res;
}

Generated by  Doxygen 1.6.0   Back to index