14#include "fuse_config.h" 
   18#include "mount_util.h" 
   29#include <sys/socket.h> 
   33#include "fuse_mount_compat.h" 
   38#define MS_RDONLY       MNT_RDONLY 
   39#define MS_NOSUID       MNT_NOSUID 
   40#define MS_NODEV        MNT_NODEV 
   41#define MS_NOEXEC       MNT_NOEXEC 
   42#define MS_SYNCHRONOUS  MNT_SYNCHRONOUS 
   43#define MS_NOATIME      MNT_NOATIME 
   44#define MS_NOSYMFOLLOW  MNT_NOSYMFOLLOW 
   46#define umount2(mnt, flags) unmount(mnt, (flags == 2) ? MNT_FORCE : 0) 
   49#define FUSERMOUNT_PROG         "fusermount3" 
   50#define FUSE_COMMFD_ENV         "_FUSE_COMMFD" 
   51#define FUSE_COMMFD2_ENV        "_FUSE_COMMFD2" 
   76        char *fusermount_opts;
 
   81#define FUSE_MOUNT_OPT(t, p) { t, offsetof(struct mount_opts, p), 1 } 
   83static const struct fuse_opt fuse_mount_opts[] = {
 
   84        FUSE_MOUNT_OPT(
"allow_other",           allow_other),
 
   85        FUSE_MOUNT_OPT(
"blkdev",                blkdev),
 
   86        FUSE_MOUNT_OPT(
"auto_unmount",          auto_unmount),
 
   87        FUSE_MOUNT_OPT(
"fsname=%s",             fsname),
 
   88        FUSE_MOUNT_OPT(
"max_read=%u",           max_read),
 
   89        FUSE_MOUNT_OPT(
"subtype=%s",            subtype),
 
  129static int fusermount_posix_spawn(posix_spawn_file_actions_t *action,
 
  130                                  char const * 
const argv[], pid_t *out_pid)
 
  132        const char *full_path = FUSERMOUNT_DIR 
"/" FUSERMOUNT_PROG;
 
  138        int status = posix_spawn(&pid, full_path,  action, NULL,
 
  139                                 (
char * 
const *) argv, environ);
 
  142                status = posix_spawnp(&pid, FUSERMOUNT_PROG, action, NULL,
 
  143                                      (
char * 
const *) argv, environ);
 
  148                         "On calling fusermount posix_spawn failed: %s\n",
 
  156                waitpid(pid, NULL, 0); 
 
  161void fuse_mount_version(
void)
 
  163        char const *
const argv[] = {FUSERMOUNT_PROG, 
"--version", NULL};
 
  164        int status = fusermount_posix_spawn(NULL, argv, NULL);
 
  167                fuse_log(FUSE_LOG_ERR, 
"Running '%s --version' failed",
 
  177static const struct mount_flags mount_flags[] = {
 
  178        {
"rw",      MS_RDONLY,      0},
 
  179        {
"ro",      MS_RDONLY,      1},
 
  180        {
"suid",    MS_NOSUID,      0},
 
  181        {
"nosuid",  MS_NOSUID,      1},
 
  182        {
"dev",     MS_NODEV,       0},
 
  183        {
"nodev",   MS_NODEV,       1},
 
  184        {
"exec",    MS_NOEXEC,      0},
 
  185        {
"noexec",  MS_NOEXEC,      1},
 
  186        {
"async",   MS_SYNCHRONOUS, 0},
 
  187        {
"sync",    MS_SYNCHRONOUS, 1},
 
  188        {
"noatime", MS_NOATIME,     1},
 
  189        {
"nodiratime",      MS_NODIRATIME,      1},
 
  190        {
"norelatime",      MS_RELATIME,        0},
 
  191        {
"nostrictatime",   MS_STRICTATIME,     0},
 
  192        {
"symfollow",       MS_NOSYMFOLLOW,     0},
 
  193        {
"nosymfollow",     MS_NOSYMFOLLOW,     1},
 
  195        {
"dirsync", MS_DIRSYNC,     1},
 
  200unsigned get_max_read(
struct mount_opts *o)
 
  205static void set_mount_flag(
const char *s, 
int *flags)
 
  209        for (i = 0; mount_flags[i].opt != NULL; i++) {
 
  210                const char *opt = mount_flags[i].opt;
 
  211                if (strcmp(opt, s) == 0) {
 
  212                        if (mount_flags[i].on)
 
  213                                *flags |= mount_flags[i].flag;
 
  215                                *flags &= ~mount_flags[i].flag;
 
  219        fuse_log(FUSE_LOG_ERR, 
"fuse: internal error, can't find mount flag\n");
 
  223static int fuse_mount_opt_proc(
void *data, 
const char *arg, 
int key,
 
  227        struct mount_opts *mo = data;
 
  234                set_mount_flag(arg, &mo->flags);
 
  240        case KEY_FUSERMOUNT_OPT:
 
  243        case KEY_SUBTYPE_OPT:
 
  251                return (strncmp(
"x-", arg, 2) == 0) ?
 
  264static int receive_fd(
int fd)
 
  270        size_t ccmsg[CMSG_SPACE(
sizeof(
int)) / 
sizeof(size_t)];
 
  271        struct cmsghdr *cmsg;
 
  276        memset(&msg, 0, 
sizeof(msg));
 
  283        msg.msg_control = ccmsg;
 
  284        msg.msg_controllen = 
sizeof(ccmsg);
 
  286        while(((rv = recvmsg(fd, &msg, 0)) == -1) && errno == EINTR);
 
  288                fuse_log(FUSE_LOG_ERR, 
"recvmsg failed: %s", strerror(errno));
 
  296        cmsg = CMSG_FIRSTHDR(&msg);
 
  297        if (cmsg->cmsg_type != SCM_RIGHTS) {
 
  298                fuse_log(FUSE_LOG_ERR, 
"got control message of unknown type %d\n",
 
  302        return *(
int*)CMSG_DATA(cmsg);
 
  305void fuse_kern_unmount(
const char *mountpoint, 
int fd)
 
  314                res = poll(&pfd, 1, 0);
 
  326                if (res == 1 && (pfd.revents & POLLERR))
 
  330        if (geteuid() == 0) {
 
  331                fuse_mnt_umount(
"fuse", mountpoint, mountpoint,  1);
 
  335        res = umount2(mountpoint, 2);
 
  339        char const * 
const argv[] =
 
  340                { FUSERMOUNT_PROG, 
"--unmount", 
"--quiet", 
"--lazy",
 
  341                                "--", mountpoint, NULL };
 
  342        int status = fusermount_posix_spawn(NULL, argv, NULL);
 
  344                fuse_log(FUSE_LOG_ERR, 
"Spawning %s to unmount failed: %s",
 
  345                         FUSERMOUNT_PROG, strerror(-status));
 
  350static int setup_auto_unmount(
const char *mountpoint, 
int quiet)
 
  357                fuse_log(FUSE_LOG_ERR, 
"fuse: missing mountpoint parameter\n");
 
  361        res = socketpair(PF_UNIX, SOCK_STREAM, 0, fds);
 
  363                fuse_log(FUSE_LOG_ERR, 
"Setting up auto-unmountsocketpair() failed",
 
  368        char arg_fd_entry[30];
 
  369        snprintf(arg_fd_entry, 
sizeof(arg_fd_entry), 
"%i", fds[0]);
 
  370        setenv(FUSE_COMMFD_ENV, arg_fd_entry, 1);
 
  377        snprintf(arg_fd_entry, 
sizeof(arg_fd_entry), 
"%i", fds[1]);
 
  378        setenv(FUSE_COMMFD2_ENV, arg_fd_entry, 1);
 
  380        char const *
const argv[] = {
 
  389        posix_spawn_file_actions_t action;
 
  390        posix_spawn_file_actions_init(&action);
 
  393                posix_spawn_file_actions_addopen(&action, STDOUT_FILENO, 
"/dev/null", O_WRONLY, 0);
 
  394                posix_spawn_file_actions_addopen(&action, STDERR_FILENO, 
"/dev/null", O_WRONLY, 0);
 
  396        posix_spawn_file_actions_addclose(&action, fds[1]);
 
  402        int status = fusermount_posix_spawn(&action, argv, &pid);
 
  404        posix_spawn_file_actions_destroy(&action);
 
  409                fuse_log(FUSE_LOG_ERR, 
"fuse: Setting up auto-unmount failed (spawn): %s",
 
  422static int fuse_mount_fusermount(
const char *mountpoint, 
struct mount_opts *mo,
 
  423                const char *opts, 
int quiet)
 
  430                fuse_log(FUSE_LOG_ERR, 
"fuse: missing mountpoint parameter\n");
 
  434        res = socketpair(PF_UNIX, SOCK_STREAM, 0, fds);
 
  436                fuse_log(FUSE_LOG_ERR, 
"Running %s: socketpair() failed: %s\n",
 
  437                         FUSERMOUNT_PROG, strerror(errno));
 
  441        char arg_fd_entry[30];
 
  442        snprintf(arg_fd_entry, 
sizeof(arg_fd_entry), 
"%i", fds[0]);
 
  443        setenv(FUSE_COMMFD_ENV, arg_fd_entry, 1);
 
  450        snprintf(arg_fd_entry, 
sizeof(arg_fd_entry), 
"%i", fds[1]);
 
  451        setenv(FUSE_COMMFD2_ENV, arg_fd_entry, 1);
 
  453        char const *
const argv[] = {
 
  455                "-o", opts ? opts : 
"",
 
  462        posix_spawn_file_actions_t action;
 
  463        posix_spawn_file_actions_init(&action);
 
  466                posix_spawn_file_actions_addopen(&action, STDOUT_FILENO, 
"/dev/null", O_WRONLY, 0);
 
  467                posix_spawn_file_actions_addopen(&action, STDERR_FILENO, 
"/dev/null", O_WRONLY, 0);
 
  469        posix_spawn_file_actions_addclose(&action, fds[1]);
 
  471        int status = fusermount_posix_spawn(&action, argv, &pid);
 
  473        posix_spawn_file_actions_destroy(&action);
 
  478                fuse_log(FUSE_LOG_ERR, 
"posix_spawn(p)() for %s failed: %s",
 
  479                         FUSERMOUNT_PROG, strerror(-status));
 
  486        int fd = receive_fd(fds[1]);
 
  488        if (!mo->auto_unmount) {
 
  492                waitpid(pid, NULL, 0); 
 
  496                fcntl(fd, F_SETFD, FD_CLOEXEC);
 
  505static int fuse_mount_sys(
const char *mnt, 
struct mount_opts *mo,
 
  506                          const char *mnt_opts)
 
  509        const char *devname = 
"/dev/fuse";
 
  517                fuse_log(FUSE_LOG_ERR, 
"fuse: missing mountpoint parameter\n");
 
  521        res = stat(mnt, &stbuf);
 
  523                fuse_log(FUSE_LOG_ERR, 
"fuse: failed to access mountpoint %s: %s\n",
 
  524                        mnt, strerror(errno));
 
  528        fd = open(devname, O_RDWR | O_CLOEXEC);
 
  530                if (errno == ENODEV || errno == ENOENT)
 
  531                        fuse_log(FUSE_LOG_ERR, 
"fuse: device not found, try 'modprobe fuse' first\n");
 
  533                        fuse_log(FUSE_LOG_ERR, 
"fuse: failed to open %s: %s\n",
 
  534                                devname, strerror(errno));
 
  538                fcntl(fd, F_SETFD, FD_CLOEXEC);
 
  540        snprintf(tmp, 
sizeof(tmp),  
"fd=%i,rootmode=%o,user_id=%u,group_id=%u",
 
  541                 fd, stbuf.st_mode & S_IFMT, getuid(), getgid());
 
  547        source = malloc((mo->fsname ? strlen(mo->fsname) : 0) +
 
  548                        (mo->subtype ? strlen(mo->subtype) : 0) +
 
  549                        strlen(devname) + 32);
 
  551        type = malloc((mo->subtype ? strlen(mo->subtype) : 0) + 32);
 
  552        if (!type || !source) {
 
  553                fuse_log(FUSE_LOG_ERR, 
"fuse: failed to allocate memory\n");
 
  557        strcpy(type, mo->blkdev ? 
"fuseblk" : 
"fuse");
 
  560                strcat(type, mo->subtype);
 
  563               mo->fsname ? mo->fsname : (mo->subtype ? mo->subtype : devname));
 
  565        res = mount(source, mnt, type, mo->flags, mo->kernel_opts);
 
  566        if (res == -1 && errno == ENODEV && mo->subtype) {
 
  568                strcpy(type, mo->blkdev ? 
"fuseblk" : 
"fuse");
 
  571                                sprintf(source, 
"%s#%s", mo->subtype,
 
  574                        strcpy(source, type);
 
  576                res = mount(source, mnt, type, mo->flags, mo->kernel_opts);
 
  583                if (errno == EPERM) {
 
  586                        int errno_save = errno;
 
  587                        if (mo->blkdev && errno == ENODEV &&
 
  588                            !fuse_mnt_check_fuseblk())
 
  590                                        "fuse: 'fuseblk' support missing\n");
 
  592                                fuse_log(FUSE_LOG_ERR, 
"fuse: mount failed: %s\n",
 
  593                                        strerror(errno_save));
 
  600        if (geteuid() == 0) {
 
  601                char *newmnt = fuse_mnt_resolve_path(
"fuse", mnt);
 
  606                res = fuse_mnt_add_mount(
"fuse", source, newmnt, type,
 
  627static int get_mnt_flag_opts(
char **mnt_optsp, 
int flags)
 
  634        for (i = 0; mount_flags[i].opt != NULL; i++) {
 
  635                if (mount_flags[i].on && (flags & mount_flags[i].flag) &&
 
  642struct mount_opts *parse_mount_opts(
struct fuse_args *args)
 
  644        struct mount_opts *mo;
 
  646        mo = (
struct mount_opts*) malloc(
sizeof(
struct mount_opts));
 
  650        memset(mo, 0, 
sizeof(
struct mount_opts));
 
  651        mo->flags = MS_NOSUID | MS_NODEV;
 
  654            fuse_opt_parse(args, mo, fuse_mount_opts, fuse_mount_opt_proc) == -1)
 
  660        destroy_mount_opts(mo);
 
  664void destroy_mount_opts(
struct mount_opts *mo)
 
  668        free(mo->fusermount_opts);
 
  669        free(mo->subtype_opt);
 
  670        free(mo->kernel_opts);
 
  676int fuse_kern_mount(
const char *mountpoint, 
struct mount_opts *mo)
 
  679        char *mnt_opts = NULL;
 
  682        if (get_mnt_flag_opts(&mnt_opts, mo->flags) == -1)
 
  689        res = fuse_mount_sys(mountpoint, mo, mnt_opts);
 
  690        if (res >= 0 && mo->auto_unmount) {
 
  691                if(0 > setup_auto_unmount(mountpoint, 0)) {
 
  693                        umount2(mountpoint, MNT_DETACH); 
 
  696        } 
else if (res == -2) {
 
  697                if (mo->fusermount_opts &&
 
  702                        char *tmp_opts = NULL;
 
  711                        res = fuse_mount_fusermount(mountpoint, mo, tmp_opts, 1);
 
  714                                res = fuse_mount_fusermount(mountpoint, mo,
 
  717                        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)