11#include "fuse_config.h" 
   15#include "mount_util.h" 
   25#include <sys/socket.h> 
   29#include "fuse_mount_compat.h" 
   34#define MS_RDONLY       MNT_RDONLY 
   35#define MS_NOSUID       MNT_NOSUID 
   36#define MS_NODEV        MNT_NODEV 
   37#define MS_NOEXEC       MNT_NOEXEC 
   38#define MS_SYNCHRONOUS  MNT_SYNCHRONOUS 
   39#define MS_NOATIME      MNT_NOATIME 
   41#define umount2(mnt, flags) unmount(mnt, (flags == 2) ? MNT_FORCE : 0) 
   44#define FUSERMOUNT_PROG         "fusermount3" 
   45#define FUSE_COMMFD_ENV         "_FUSE_COMMFD" 
   74        char *fusermount_opts;
 
   79#define FUSE_MOUNT_OPT(t, p) { t, offsetof(struct mount_opts, p), 1 } 
   81static const struct fuse_opt fuse_mount_opts[] = {
 
   82        FUSE_MOUNT_OPT(
"allow_other",           allow_other),
 
   83        FUSE_MOUNT_OPT(
"blkdev",                blkdev),
 
   84        FUSE_MOUNT_OPT(
"auto_unmount",          auto_unmount),
 
   85        FUSE_MOUNT_OPT(
"fsname=%s",             fsname),
 
   86        FUSE_MOUNT_OPT(
"max_read=%u",           max_read),
 
   87        FUSE_MOUNT_OPT(
"subtype=%s",            subtype),
 
  120static void exec_fusermount(
const char *argv[])
 
  122        execv(FUSERMOUNT_DIR 
"/" FUSERMOUNT_PROG, (
char **) argv);
 
  123        execvp(FUSERMOUNT_PROG, (
char **) argv);
 
  126void fuse_mount_version(
void)
 
  130                const char *argv[] = { FUSERMOUNT_PROG, 
"--version", NULL };
 
  131                exec_fusermount(argv);
 
  133        } 
else if (pid != -1)
 
  134                waitpid(pid, NULL, 0);
 
  143static const struct mount_flags mount_flags[] = {
 
  144        {
"rw",      MS_RDONLY,      0},
 
  145        {
"ro",      MS_RDONLY,      1},
 
  146        {
"suid",    MS_NOSUID,      0},
 
  147        {
"nosuid",  MS_NOSUID,      1},
 
  148        {
"dev",     MS_NODEV,       0},
 
  149        {
"nodev",   MS_NODEV,       1},
 
  150        {
"exec",    MS_NOEXEC,      0},
 
  151        {
"noexec",  MS_NOEXEC,      1},
 
  152        {
"async",   MS_SYNCHRONOUS, 0},
 
  153        {
"sync",    MS_SYNCHRONOUS, 1},
 
  154        {
"noatime", MS_NOATIME,     1},
 
  155        {
"nodiratime",      MS_NODIRATIME,      1},
 
  156        {
"norelatime",      MS_RELATIME,        0},
 
  157        {
"nostrictatime",   MS_STRICTATIME,     0},
 
  159        {
"dirsync", MS_DIRSYNC,     1},
 
  164unsigned get_max_read(
struct mount_opts *o)
 
  169static void set_mount_flag(
const char *s, 
int *flags)
 
  173        for (i = 0; mount_flags[i].opt != NULL; i++) {
 
  174                const char *opt = mount_flags[i].opt;
 
  175                if (strcmp(opt, s) == 0) {
 
  176                        if (mount_flags[i].on)
 
  177                                *flags |= mount_flags[i].flag;
 
  179                                *flags &= ~mount_flags[i].flag;
 
  183        fuse_log(FUSE_LOG_ERR, 
"fuse: internal error, can't find mount flag\n");
 
  187static int fuse_mount_opt_proc(
void *data, 
const char *arg, 
int key,
 
  191        struct mount_opts *mo = data;
 
  198                set_mount_flag(arg, &mo->flags);
 
  204        case KEY_FUSERMOUNT_OPT:
 
  207        case KEY_SUBTYPE_OPT:
 
  222static int receive_fd(
int fd)
 
  228        size_t ccmsg[CMSG_SPACE(
sizeof(
int)) / 
sizeof(size_t)];
 
  229        struct cmsghdr *cmsg;
 
  234        memset(&msg, 0, 
sizeof(msg));
 
  241        msg.msg_control = ccmsg;
 
  242        msg.msg_controllen = 
sizeof(ccmsg);
 
  244        while(((rv = recvmsg(fd, &msg, 0)) == -1) && errno == EINTR);
 
  254        cmsg = CMSG_FIRSTHDR(&msg);
 
  255        if (cmsg->cmsg_type != SCM_RIGHTS) {
 
  256                fuse_log(FUSE_LOG_ERR, 
"got control message of unknown type %d\n",
 
  260        return *(
int*)CMSG_DATA(cmsg);
 
  263void fuse_kern_unmount(
const char *mountpoint, 
int fd)
 
  273                res = poll(&pfd, 1, 0);
 
  285                if (res == 1 && (pfd.revents & POLLERR))
 
  289        if (geteuid() == 0) {
 
  290                fuse_mnt_umount(
"fuse", mountpoint, mountpoint,  1);
 
  294        res = umount2(mountpoint, 2);
 
  303                const char *argv[] = { FUSERMOUNT_PROG, 
"-u", 
"-q", 
"-z",
 
  304                                       "--", mountpoint, NULL };
 
  306                exec_fusermount(argv);
 
  309        waitpid(pid, NULL, 0);
 
  312static int setup_auto_unmount(
const char *mountpoint, 
int quiet)
 
  318                fuse_log(FUSE_LOG_ERR, 
"fuse: missing mountpoint parameter\n");
 
  322        res = socketpair(PF_UNIX, SOCK_STREAM, 0, fds);
 
  324                perror(
"fuse: socketpair() failed");
 
  330                perror(
"fuse: fork() failed");
 
  338                const char *argv[32];
 
  342                        int fd = open(
"/dev/null", O_RDONLY);
 
  349                argv[a++] = FUSERMOUNT_PROG;
 
  350                argv[a++] = 
"--auto-unmount";
 
  352                argv[a++] = mountpoint;
 
  356                fcntl(fds[0], F_SETFD, 0);
 
  357                snprintf(env, 
sizeof(env), 
"%i", fds[0]);
 
  358                setenv(FUSE_COMMFD_ENV, env, 1);
 
  359                exec_fusermount(argv);
 
  360                perror(
"fuse: failed to exec fusermount3");
 
  371static int fuse_mount_fusermount(
const char *mountpoint, 
struct mount_opts *mo,
 
  372                const char *opts, 
int quiet)
 
  379                fuse_log(FUSE_LOG_ERR, 
"fuse: missing mountpoint parameter\n");
 
  383        res = socketpair(PF_UNIX, SOCK_STREAM, 0, fds);
 
  385                perror(
"fuse: socketpair() failed");
 
  391                perror(
"fuse: fork() failed");
 
  399                const char *argv[32];
 
  403                        int fd = open(
"/dev/null", O_RDONLY);
 
  410                argv[a++] = FUSERMOUNT_PROG;
 
  416                argv[a++] = mountpoint;
 
  420                fcntl(fds[0], F_SETFD, 0);
 
  421                snprintf(env, 
sizeof(env), 
"%i", fds[0]);
 
  422                setenv(FUSE_COMMFD_ENV, env, 1);
 
  423                exec_fusermount(argv);
 
  424                perror(
"fuse: failed to exec fusermount3");
 
  429        rv = receive_fd(fds[1]);
 
  431        if (!mo->auto_unmount) {
 
  435                waitpid(pid, NULL, 0); 
 
  439                fcntl(rv, F_SETFD, FD_CLOEXEC);
 
  448static int fuse_mount_sys(
const char *mnt, 
struct mount_opts *mo,
 
  449                          const char *mnt_opts)
 
  452        const char *devname = 
"/dev/fuse";
 
  460                fuse_log(FUSE_LOG_ERR, 
"fuse: missing mountpoint parameter\n");
 
  464        res = stat(mnt, &stbuf);
 
  466                fuse_log(FUSE_LOG_ERR, 
"fuse: failed to access mountpoint %s: %s\n",
 
  467                        mnt, strerror(errno));
 
  471        fd = open(devname, O_RDWR | O_CLOEXEC);
 
  473                if (errno == ENODEV || errno == ENOENT)
 
  474                        fuse_log(FUSE_LOG_ERR, 
"fuse: device not found, try 'modprobe fuse' first\n");
 
  476                        fuse_log(FUSE_LOG_ERR, 
"fuse: failed to open %s: %s\n",
 
  477                                devname, strerror(errno));
 
  481                fcntl(fd, F_SETFD, FD_CLOEXEC);
 
  483        snprintf(tmp, 
sizeof(tmp),  
"fd=%i,rootmode=%o,user_id=%u,group_id=%u",
 
  484                 fd, stbuf.st_mode & S_IFMT, getuid(), getgid());
 
  490        source = malloc((mo->fsname ? strlen(mo->fsname) : 0) +
 
  491                        (mo->subtype ? strlen(mo->subtype) : 0) +
 
  492                        strlen(devname) + 32);
 
  494        type = malloc((mo->subtype ? strlen(mo->subtype) : 0) + 32);
 
  495        if (!type || !source) {
 
  496                fuse_log(FUSE_LOG_ERR, 
"fuse: failed to allocate memory\n");
 
  500        strcpy(type, mo->blkdev ? 
"fuseblk" : 
"fuse");
 
  503                strcat(type, mo->subtype);
 
  506               mo->fsname ? mo->fsname : (mo->subtype ? mo->subtype : devname));
 
  508        res = mount(source, mnt, type, mo->flags, mo->kernel_opts);
 
  509        if (res == -1 && errno == ENODEV && mo->subtype) {
 
  511                strcpy(type, mo->blkdev ? 
"fuseblk" : 
"fuse");
 
  514                                sprintf(source, 
"%s#%s", mo->subtype,
 
  517                        strcpy(source, type);
 
  519                res = mount(source, mnt, type, mo->flags, mo->kernel_opts);
 
  526                if (errno == EPERM) {
 
  529                        int errno_save = errno;
 
  530                        if (mo->blkdev && errno == ENODEV &&
 
  531                            !fuse_mnt_check_fuseblk())
 
  533                                        "fuse: 'fuseblk' support missing\n");
 
  535                                fuse_log(FUSE_LOG_ERR, 
"fuse: mount failed: %s\n",
 
  536                                        strerror(errno_save));
 
  543        if (geteuid() == 0) {
 
  544                char *newmnt = fuse_mnt_resolve_path(
"fuse", mnt);
 
  549                res = fuse_mnt_add_mount(
"fuse", source, newmnt, type,
 
  570static int get_mnt_flag_opts(
char **mnt_optsp, 
int flags)
 
  577        for (i = 0; mount_flags[i].opt != NULL; i++) {
 
  578                if (mount_flags[i].on && (flags & mount_flags[i].flag) &&
 
  585struct mount_opts *parse_mount_opts(
struct fuse_args *args)
 
  587        struct mount_opts *mo;
 
  589        mo = (
struct mount_opts*) malloc(
sizeof(
struct mount_opts));
 
  593        memset(mo, 0, 
sizeof(
struct mount_opts));
 
  594        mo->flags = MS_NOSUID | MS_NODEV;
 
  597            fuse_opt_parse(args, mo, fuse_mount_opts, fuse_mount_opt_proc) == -1)
 
  603        destroy_mount_opts(mo);
 
  607void destroy_mount_opts(
struct mount_opts *mo)
 
  611        free(mo->fusermount_opts);
 
  612        free(mo->subtype_opt);
 
  613        free(mo->kernel_opts);
 
  619int fuse_kern_mount(
const char *mountpoint, 
struct mount_opts *mo)
 
  622        char *mnt_opts = NULL;
 
  625        if (get_mnt_flag_opts(&mnt_opts, mo->flags) == -1)
 
  632        res = fuse_mount_sys(mountpoint, mo, mnt_opts);
 
  633        if (res >= 0 && mo->auto_unmount) {
 
  634                if(0 > setup_auto_unmount(mountpoint, 0)) {
 
  636                        umount2(mountpoint, MNT_DETACH); 
 
  639        } 
else if (res == -2) {
 
  640                if (mo->fusermount_opts &&
 
  645                        char *tmp_opts = NULL;
 
  654                        res = fuse_mount_fusermount(mountpoint, mo, tmp_opts, 1);
 
  657                                res = fuse_mount_fusermount(mountpoint, mo,
 
  660                        res = fuse_mount_fusermount(mountpoint, mo, mnt_opts, 0);
 
void fuse_log(enum fuse_log_level level, const char *fmt,...)
#define FUSE_OPT_KEY(templ, key)
int fuse_opt_add_opt_escaped(char **opts, const char *opt)
int fuse_opt_parse(struct fuse_args *args, void *data, const struct fuse_opt opts[], fuse_opt_proc_t proc)
int fuse_opt_add_opt(char **opts, const char *opt)