mirror of
https://github.com/trapexit/mergerfs.git
synced 2026-10-26 19:01:56 -04:00
Fallback to fusermount3 where available
Some checks failed
mkdocs / deploy (push) Has been cancelled
Some checks failed
mkdocs / deploy (push) Has been cancelled
Also general cleanup of mount_generic.
This commit is contained in:
parent
f4b602340b
commit
06433a0548
1 changed files with 360 additions and 315 deletions
|
|
@ -11,51 +11,57 @@
|
|||
#include "fuse_opt.h"
|
||||
#include "mount_util.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <poll.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <poll.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/mount.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef __NetBSD__
|
||||
#include <perfuse.h>
|
||||
|
||||
#define MS_RDONLY MNT_RDONLY
|
||||
#define MS_NOSUID MNT_NOSUID
|
||||
#define MS_NODEV MNT_NODEV
|
||||
#define MS_NOEXEC MNT_NOEXEC
|
||||
#define MS_SYNCHRONOUS MNT_SYNCHRONOUS
|
||||
#define MS_NOATIME MNT_NOATIME
|
||||
|
||||
#define umount2(mnt, flags) unmount(mnt, (flags == 2) ? MNT_FORCE : 0)
|
||||
#define MS_RDONLY MNT_RDONLY
|
||||
#define MS_NOSUID MNT_NOSUID
|
||||
#define MS_NODEV MNT_NODEV
|
||||
#define MS_NOEXEC MNT_NOEXEC
|
||||
#define MS_SYNCHRONOUS MNT_SYNCHRONOUS
|
||||
#define MS_NOATIME MNT_NOATIME
|
||||
#ifndef MNT_DETACH
|
||||
#define MNT_DETACH 2
|
||||
#endif
|
||||
|
||||
#define FUSERMOUNT_PROG "fusermount"
|
||||
#define FUSE_COMMFD_ENV "_FUSE_COMMFD"
|
||||
#define umount2(mnt, flags) unmount(mnt,(flags == MNT_DETACH) ? MNT_FORCE : 0)
|
||||
#endif
|
||||
|
||||
#define FUSERMOUNT_PROG "fusermount"
|
||||
#define FUSERMOUNT3_PROG "fusermount3"
|
||||
#define FUSE_COMMFD_ENV "_FUSE_COMMFD"
|
||||
|
||||
#ifndef MS_DIRSYNC
|
||||
#define MS_DIRSYNC 128
|
||||
#endif
|
||||
|
||||
enum {
|
||||
KEY_KERN_FLAG,
|
||||
KEY_KERN_OPT,
|
||||
KEY_FUSERMOUNT_OPT,
|
||||
KEY_SUBTYPE_OPT,
|
||||
KEY_MTAB_OPT,
|
||||
KEY_RO
|
||||
};
|
||||
enum
|
||||
{
|
||||
KEY_KERN_FLAG,
|
||||
KEY_KERN_OPT,
|
||||
KEY_FUSERMOUNT_OPT,
|
||||
KEY_SUBTYPE_OPT,
|
||||
KEY_MTAB_OPT,
|
||||
KEY_RO
|
||||
};
|
||||
|
||||
struct mount_opts {
|
||||
struct mount_opts
|
||||
{
|
||||
int allow_other;
|
||||
int flags;
|
||||
int auto_unmount;
|
||||
|
|
@ -68,101 +74,100 @@ struct mount_opts {
|
|||
char *kernel_opts;
|
||||
};
|
||||
|
||||
#define FUSE_MOUNT_OPT(t, p) { t, offsetof(struct mount_opts, p), 1 }
|
||||
#define FUSE_MOUNT_OPT(t,p) { t, offsetof(struct mount_opts,p), 1 }
|
||||
|
||||
static
|
||||
const
|
||||
struct fuse_opt fuse_mount_opts[] =
|
||||
static const struct fuse_opt fuse_mount_opts[] =
|
||||
{
|
||||
FUSE_MOUNT_OPT("allow_other", allow_other),
|
||||
FUSE_MOUNT_OPT("blkdev", blkdev),
|
||||
FUSE_MOUNT_OPT("auto_unmount", auto_unmount),
|
||||
FUSE_MOUNT_OPT("fsname=%s", fsname),
|
||||
FUSE_MOUNT_OPT("subtype=%s", subtype),
|
||||
FUSE_OPT_KEY("allow_other", KEY_KERN_OPT),
|
||||
FUSE_OPT_KEY("auto_unmount", 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),
|
||||
FUSE_OPT_KEY("context=", KEY_KERN_OPT),
|
||||
FUSE_OPT_KEY("fscontext=", KEY_KERN_OPT),
|
||||
FUSE_OPT_KEY("defcontext=", KEY_KERN_OPT),
|
||||
FUSE_OPT_KEY("rootcontext=", KEY_KERN_OPT),
|
||||
FUSE_OPT_KEY("max_read=", KEY_KERN_OPT),
|
||||
FUSE_OPT_KEY("max_read=", FUSE_OPT_KEY_KEEP),
|
||||
FUSE_OPT_KEY("user=", KEY_MTAB_OPT),
|
||||
FUSE_OPT_KEY("-n", KEY_MTAB_OPT),
|
||||
FUSE_OPT_KEY("-r", KEY_RO),
|
||||
FUSE_OPT_KEY("ro", KEY_KERN_FLAG),
|
||||
FUSE_OPT_KEY("rw", KEY_KERN_FLAG),
|
||||
FUSE_OPT_KEY("suid", KEY_KERN_FLAG),
|
||||
FUSE_OPT_KEY("nosuid", KEY_KERN_FLAG),
|
||||
FUSE_OPT_KEY("dev", KEY_KERN_FLAG),
|
||||
FUSE_OPT_KEY("nodev", KEY_KERN_FLAG),
|
||||
FUSE_OPT_KEY("exec", KEY_KERN_FLAG),
|
||||
FUSE_OPT_KEY("noexec", KEY_KERN_FLAG),
|
||||
FUSE_OPT_KEY("async", KEY_KERN_FLAG),
|
||||
FUSE_OPT_KEY("sync", KEY_KERN_FLAG),
|
||||
FUSE_OPT_KEY("dirsync", KEY_KERN_FLAG),
|
||||
FUSE_OPT_KEY("atime", KEY_KERN_FLAG),
|
||||
FUSE_OPT_KEY("noatime", KEY_KERN_FLAG),
|
||||
FUSE_OPT_KEY("relatime", KEY_KERN_FLAG),
|
||||
FUSE_OPT_KEY("norelatime", KEY_KERN_FLAG),
|
||||
FUSE_OPT_KEY("lazytime", KEY_KERN_FLAG),
|
||||
FUSE_OPT_KEY("nolazytime", KEY_KERN_FLAG),
|
||||
FUSE_OPT_KEY("diratime", KEY_KERN_FLAG),
|
||||
FUSE_OPT_KEY("nodiratime", KEY_KERN_FLAG),
|
||||
FUSE_OPT_KEY("strictatime", KEY_KERN_FLAG),
|
||||
FUSE_OPT_KEY("nostrictatime", KEY_KERN_FLAG),
|
||||
FUSE_MOUNT_OPT("allow_other",allow_other),
|
||||
FUSE_MOUNT_OPT("blkdev",blkdev),
|
||||
FUSE_MOUNT_OPT("auto_unmount",auto_unmount),
|
||||
FUSE_MOUNT_OPT("fsname=%s",fsname),
|
||||
FUSE_MOUNT_OPT("subtype=%s",subtype),
|
||||
FUSE_OPT_KEY("allow_other",KEY_KERN_OPT),
|
||||
FUSE_OPT_KEY("auto_unmount",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),
|
||||
FUSE_OPT_KEY("context=",KEY_KERN_OPT),
|
||||
FUSE_OPT_KEY("fscontext=",KEY_KERN_OPT),
|
||||
FUSE_OPT_KEY("defcontext=",KEY_KERN_OPT),
|
||||
FUSE_OPT_KEY("rootcontext=",KEY_KERN_OPT),
|
||||
FUSE_OPT_KEY("max_read=",KEY_KERN_OPT),
|
||||
FUSE_OPT_KEY("max_read=",FUSE_OPT_KEY_KEEP),
|
||||
FUSE_OPT_KEY("user=",KEY_MTAB_OPT),
|
||||
FUSE_OPT_KEY("-n",KEY_MTAB_OPT),
|
||||
FUSE_OPT_KEY("-r",KEY_RO),
|
||||
FUSE_OPT_KEY("ro",KEY_KERN_FLAG),
|
||||
FUSE_OPT_KEY("rw",KEY_KERN_FLAG),
|
||||
FUSE_OPT_KEY("suid",KEY_KERN_FLAG),
|
||||
FUSE_OPT_KEY("nosuid",KEY_KERN_FLAG),
|
||||
FUSE_OPT_KEY("dev",KEY_KERN_FLAG),
|
||||
FUSE_OPT_KEY("nodev",KEY_KERN_FLAG),
|
||||
FUSE_OPT_KEY("exec",KEY_KERN_FLAG),
|
||||
FUSE_OPT_KEY("noexec",KEY_KERN_FLAG),
|
||||
FUSE_OPT_KEY("async",KEY_KERN_FLAG),
|
||||
FUSE_OPT_KEY("sync",KEY_KERN_FLAG),
|
||||
FUSE_OPT_KEY("dirsync",KEY_KERN_FLAG),
|
||||
FUSE_OPT_KEY("atime",KEY_KERN_FLAG),
|
||||
FUSE_OPT_KEY("noatime",KEY_KERN_FLAG),
|
||||
FUSE_OPT_KEY("relatime",KEY_KERN_FLAG),
|
||||
FUSE_OPT_KEY("norelatime",KEY_KERN_FLAG),
|
||||
FUSE_OPT_KEY("lazytime",KEY_KERN_FLAG),
|
||||
FUSE_OPT_KEY("nolazytime",KEY_KERN_FLAG),
|
||||
FUSE_OPT_KEY("diratime",KEY_KERN_FLAG),
|
||||
FUSE_OPT_KEY("nodiratime",KEY_KERN_FLAG),
|
||||
FUSE_OPT_KEY("strictatime",KEY_KERN_FLAG),
|
||||
FUSE_OPT_KEY("nostrictatime",KEY_KERN_FLAG),
|
||||
FUSE_OPT_END
|
||||
};
|
||||
|
||||
static void exec_fusermount(const char *argv[])
|
||||
static void
|
||||
exec_fusermount(const char *argv[])
|
||||
{
|
||||
execv(FUSERMOUNT_DIR "/mergerfs-" FUSERMOUNT_PROG, (char **) argv);
|
||||
execvp("mergerfs-" FUSERMOUNT_PROG, (char **) argv);
|
||||
execv(FUSERMOUNT_DIR "/" FUSERMOUNT_PROG, (char **) argv);
|
||||
execvp(FUSERMOUNT_PROG, (char **) argv);
|
||||
execv(FUSERMOUNT_DIR "/mergerfs-" FUSERMOUNT_PROG,(char**)argv);
|
||||
execvp("mergerfs-" FUSERMOUNT_PROG,(char**)argv);
|
||||
execv(FUSERMOUNT_DIR "/" FUSERMOUNT_PROG,(char**)argv);
|
||||
execvp(FUSERMOUNT_PROG,(char**)argv);
|
||||
execv(FUSERMOUNT_DIR "/" FUSERMOUNT3_PROG,(char**)argv);
|
||||
execvp(FUSERMOUNT3_PROG,(char**)argv);
|
||||
}
|
||||
|
||||
struct mount_flags {
|
||||
struct mount_flags
|
||||
{
|
||||
const char *opt;
|
||||
unsigned long flag;
|
||||
int on;
|
||||
};
|
||||
|
||||
static
|
||||
const
|
||||
struct mount_flags
|
||||
mount_flags[] =
|
||||
static const struct mount_flags mount_flags[] =
|
||||
{
|
||||
{"rw", MS_RDONLY, 0},
|
||||
{"ro", MS_RDONLY, 1},
|
||||
{"suid", MS_NOSUID, 0},
|
||||
{"nosuid", MS_NOSUID, 1},
|
||||
{"dev", MS_NODEV, 0},
|
||||
{"nodev", MS_NODEV, 1},
|
||||
{"exec", MS_NOEXEC, 0},
|
||||
{"noexec", MS_NOEXEC, 1},
|
||||
{"async", MS_SYNCHRONOUS, 0},
|
||||
{"sync", MS_SYNCHRONOUS, 1},
|
||||
{"atime", MS_NOATIME, 0},
|
||||
{"noatime", MS_NOATIME, 1},
|
||||
{"relatime", MS_RELATIME, 1},
|
||||
{"norelatime", MS_RELATIME, 0},
|
||||
{"lazytime", MS_LAZYTIME, 1},
|
||||
{"nolazytime", MS_LAZYTIME, 0},
|
||||
{"diratime", MS_NODIRATIME, 0},
|
||||
{"nodiratime", MS_NODIRATIME, 1},
|
||||
{"strictatime", MS_STRICTATIME, 1},
|
||||
{"nostrictatime",MS_STRICTATIME, 0},
|
||||
{ "rw", MS_RDONLY, 0 },
|
||||
{ "ro", MS_RDONLY, 1 },
|
||||
{ "suid", MS_NOSUID, 0 },
|
||||
{ "nosuid", MS_NOSUID, 1 },
|
||||
{ "dev", MS_NODEV, 0 },
|
||||
{ "nodev", MS_NODEV, 1 },
|
||||
{ "exec", MS_NOEXEC, 0 },
|
||||
{ "noexec", MS_NOEXEC, 1 },
|
||||
{ "async", MS_SYNCHRONOUS, 0 },
|
||||
{ "sync", MS_SYNCHRONOUS, 1 },
|
||||
{ "atime", MS_NOATIME, 0 },
|
||||
{ "noatime", MS_NOATIME, 1 },
|
||||
{ "relatime", MS_RELATIME, 1 },
|
||||
{ "norelatime", MS_RELATIME, 0 },
|
||||
{ "lazytime", MS_LAZYTIME, 1 },
|
||||
{ "nolazytime", MS_LAZYTIME, 0 },
|
||||
{ "diratime", MS_NODIRATIME, 0 },
|
||||
{ "nodiratime", MS_NODIRATIME, 1 },
|
||||
{ "strictatime", MS_STRICTATIME, 1 },
|
||||
{ "nostrictatime", MS_STRICTATIME, 0 },
|
||||
#ifndef __NetBSD__
|
||||
{"dirsync", MS_DIRSYNC, 1},
|
||||
{ "dirsync", MS_DIRSYNC, 1 },
|
||||
#endif
|
||||
{NULL, 0, 0}
|
||||
{ NULL, 0, 0 }
|
||||
};
|
||||
|
||||
static
|
||||
|
|
@ -172,7 +177,7 @@ set_mount_flag(const char *s,
|
|||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; mount_flags[i].opt != NULL; i++)
|
||||
for(i = 0; mount_flags[i].opt != NULL; i++)
|
||||
{
|
||||
const char *opt = mount_flags[i].opt;
|
||||
if(strcmp(opt, s) == 0)
|
||||
|
|
@ -189,12 +194,13 @@ set_mount_flag(const char *s,
|
|||
abort();
|
||||
}
|
||||
|
||||
static int fuse_mount_opt_proc(void *data, const char *arg, int key,
|
||||
struct fuse_args *outargs)
|
||||
static int
|
||||
fuse_mount_opt_proc(void *data, const char *arg, int key,
|
||||
struct fuse_args *outargs)
|
||||
{
|
||||
struct mount_opts *mo = static_cast<struct mount_opts*>(data);
|
||||
struct mount_opts *mo = static_cast<struct mount_opts *>(data);
|
||||
|
||||
switch (key)
|
||||
switch(key)
|
||||
{
|
||||
case KEY_RO:
|
||||
arg = "ro";
|
||||
|
|
@ -216,8 +222,8 @@ static int fuse_mount_opt_proc(void *data, const char *arg, int key,
|
|||
return fuse_opt_add_opt(&mo->mtab_opts, arg);
|
||||
|
||||
case FUSE_OPT_KEY_OPT:
|
||||
if(strncmp("x-",arg,2) == 0)
|
||||
return fuse_opt_add_opt(&mo->mtab_opts,arg);
|
||||
if(strncmp("x-", arg, 2) == 0)
|
||||
return fuse_opt_add_opt(&mo->mtab_opts, arg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
@ -229,7 +235,9 @@ static int fuse_mount_opt_proc(void *data, const char *arg, int key,
|
|||
* >= 0 => fd
|
||||
* -1 => error
|
||||
*/
|
||||
static int receive_fd(int fd)
|
||||
static
|
||||
int
|
||||
receive_fd(int fd)
|
||||
{
|
||||
struct msghdr msg;
|
||||
struct iovec iov;
|
||||
|
|
@ -251,168 +259,187 @@ static int receive_fd(int fd)
|
|||
msg.msg_control = ccmsg;
|
||||
msg.msg_controllen = sizeof(ccmsg);
|
||||
|
||||
while(((rv = recvmsg(fd, &msg, 0)) == -1) && errno == EINTR);
|
||||
if (rv == -1) {
|
||||
perror("recvmsg");
|
||||
return -1;
|
||||
}
|
||||
if(!rv) {
|
||||
/* EOF */
|
||||
return -1;
|
||||
}
|
||||
while(((rv = recvmsg(fd, &msg, 0)) == -1) && errno == EINTR)
|
||||
;
|
||||
if(rv == -1)
|
||||
{
|
||||
perror("recvmsg");
|
||||
return -1;
|
||||
}
|
||||
if(!rv)
|
||||
{
|
||||
/* EOF */
|
||||
return -1;
|
||||
}
|
||||
|
||||
cmsg = CMSG_FIRSTHDR(&msg);
|
||||
if(!cmsg)
|
||||
{
|
||||
fprintf(stderr,"no control message received or not enough buf space\n");
|
||||
fprintf(stderr,
|
||||
"no control message received or not enough buf space\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(cmsg->cmsg_type != SCM_RIGHTS)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"got control message of unknown type %d\n",
|
||||
fprintf(stderr, "got control message of unknown type %d\n",
|
||||
cmsg->cmsg_type);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return *reinterpret_cast<int*>(CMSG_DATA(cmsg));
|
||||
return *reinterpret_cast<int *>(CMSG_DATA(cmsg));
|
||||
}
|
||||
|
||||
void fuse_kern_unmount(const char *mountpoint, int fd)
|
||||
void
|
||||
fuse_kern_unmount(const char *mountpoint,
|
||||
int fd)
|
||||
{
|
||||
int res;
|
||||
int pid;
|
||||
|
||||
if (!mountpoint)
|
||||
if(!mountpoint)
|
||||
return;
|
||||
|
||||
if (fd != -1) {
|
||||
struct pollfd pfd;
|
||||
if(fd != -1)
|
||||
{
|
||||
struct pollfd pfd;
|
||||
|
||||
pfd.fd = fd;
|
||||
pfd.events = 0;
|
||||
res = poll(&pfd, 1, 0);
|
||||
pfd.fd = fd;
|
||||
pfd.events = 0;
|
||||
res = poll(&pfd, 1, 0);
|
||||
|
||||
/* Need to close file descriptor, otherwise synchronous umount
|
||||
would recurse into filesystem, and deadlock.
|
||||
/* Need to close file descriptor, otherwise synchronous umount
|
||||
would recurse into filesystem, and deadlock.
|
||||
|
||||
Caller expects fuse_kern_unmount to close the fd, so close it
|
||||
anyway. */
|
||||
close(fd);
|
||||
Caller expects fuse_kern_unmount to close the fd, so close it
|
||||
anyway. */
|
||||
close(fd);
|
||||
|
||||
/* If file poll returns POLLERR on the device file descriptor,
|
||||
then the filesystem is already unmounted */
|
||||
if (res == 1 && (pfd.revents & POLLERR))
|
||||
/* If file poll returns POLLERR on the device file descriptor,
|
||||
then the filesystem is already unmounted */
|
||||
if(res == 1 &&(pfd.revents & POLLERR))
|
||||
return;
|
||||
}
|
||||
|
||||
if(geteuid() == 0)
|
||||
{
|
||||
fuse_mnt_umount("fuse", mountpoint, mountpoint, 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (geteuid() == 0) {
|
||||
fuse_mnt_umount("fuse", mountpoint, mountpoint, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
res = umount2(mountpoint, 2);
|
||||
if (res == 0)
|
||||
res = umount2(mountpoint,MNT_DETACH);
|
||||
if(res == 0)
|
||||
return;
|
||||
|
||||
pid = fork();
|
||||
if(pid == -1)
|
||||
return;
|
||||
|
||||
if(pid == 0) {
|
||||
const char *argv[] = { FUSERMOUNT_PROG, "-u", "-q", "-z",
|
||||
"--", mountpoint, NULL };
|
||||
if(pid == 0)
|
||||
{
|
||||
const char *argv[] =
|
||||
{ FUSERMOUNT_PROG, "-u", "-q", "-z", "--", mountpoint, NULL };
|
||||
|
||||
exec_fusermount(argv);
|
||||
_exit(1);
|
||||
}
|
||||
exec_fusermount(argv);
|
||||
perror("mergerfs: failed to exec fusermount");
|
||||
_exit(1);
|
||||
}
|
||||
waitpid(pid, NULL, 0);
|
||||
}
|
||||
|
||||
static int fuse_mount_fusermount(const char *mountpoint, struct mount_opts *mo,
|
||||
const char *opts, int quiet)
|
||||
{
|
||||
int fds[2], pid;
|
||||
int res;
|
||||
int rv;
|
||||
|
||||
if (!mountpoint) {
|
||||
fprintf(stderr, "mergerfs: missing mountpoint parameter\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
res = socketpair(PF_UNIX, SOCK_STREAM, 0, fds);
|
||||
if(res == -1) {
|
||||
perror("mergerfs: socketpair() failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
pid = fork();
|
||||
if(pid == -1) {
|
||||
perror("mergerfs: fork() failed");
|
||||
close(fds[0]);
|
||||
close(fds[1]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(pid == 0) {
|
||||
char env[10];
|
||||
const char *argv[32];
|
||||
int a = 0;
|
||||
|
||||
if (quiet) {
|
||||
int fd = open("/dev/null", O_RDONLY);
|
||||
if (fd != -1) {
|
||||
dup2(fd, 1);
|
||||
dup2(fd, 2);
|
||||
}
|
||||
}
|
||||
|
||||
argv[a++] = FUSERMOUNT_PROG;
|
||||
if (opts) {
|
||||
argv[a++] = "-o";
|
||||
argv[a++] = opts;
|
||||
}
|
||||
argv[a++] = "--";
|
||||
argv[a++] = mountpoint;
|
||||
argv[a++] = NULL;
|
||||
|
||||
close(fds[1]);
|
||||
fcntl(fds[0], F_SETFD, 0);
|
||||
snprintf(env, sizeof(env), "%i", fds[0]);
|
||||
setenv(FUSE_COMMFD_ENV, env, 1);
|
||||
exec_fusermount(argv);
|
||||
perror("mergerfs: failed to exec fusermount");
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
close(fds[0]);
|
||||
rv = receive_fd(fds[1]);
|
||||
|
||||
if (!mo->auto_unmount) {
|
||||
/* with auto_unmount option fusermount will not exit until
|
||||
this socket is closed */
|
||||
close(fds[1]);
|
||||
waitpid(pid, NULL, 0); /* bury zombie */
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
fuse_mount_sys(const char *mnt,
|
||||
struct mount_opts *mo,
|
||||
const char *mnt_opts)
|
||||
fuse_mount_fusermount(const char *mountpoint,
|
||||
struct mount_opts *mo,
|
||||
const char *opts,
|
||||
int quiet)
|
||||
{
|
||||
int fds[2];
|
||||
int pid;
|
||||
int res;
|
||||
int rv;
|
||||
|
||||
if(!mountpoint)
|
||||
{
|
||||
fprintf(stderr, "mergerfs: missing mountpoint parameter\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
res = socketpair(PF_UNIX, SOCK_STREAM, 0, fds);
|
||||
if(res == -1)
|
||||
{
|
||||
perror("mergerfs: socketpair() failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
pid = fork();
|
||||
if(pid == -1)
|
||||
{
|
||||
perror("mergerfs: fork() failed");
|
||||
close(fds[0]);
|
||||
close(fds[1]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(pid == 0)
|
||||
{
|
||||
char env[10];
|
||||
const char *argv[32];
|
||||
int a = 0;
|
||||
|
||||
if(quiet)
|
||||
{
|
||||
int fd = open("/dev/null", O_RDONLY);
|
||||
if(fd != -1)
|
||||
{
|
||||
dup2(fd, 1);
|
||||
dup2(fd, 2);
|
||||
}
|
||||
}
|
||||
|
||||
argv[a++] = FUSERMOUNT_PROG;
|
||||
if(opts)
|
||||
{
|
||||
argv[a++] = "-o";
|
||||
argv[a++] = opts;
|
||||
}
|
||||
argv[a++] = "--";
|
||||
argv[a++] = mountpoint;
|
||||
argv[a++] = NULL;
|
||||
|
||||
close(fds[1]);
|
||||
fcntl(fds[0], F_SETFD, 0);
|
||||
snprintf(env, sizeof(env), "%i", fds[0]);
|
||||
setenv(FUSE_COMMFD_ENV, env, 1);
|
||||
exec_fusermount(argv);
|
||||
perror("mergerfs: failed to exec fusermount");
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
close(fds[0]);
|
||||
rv = receive_fd(fds[1]);
|
||||
|
||||
if(!mo->auto_unmount)
|
||||
{
|
||||
/* with auto_unmount option fusermount will not exit until
|
||||
this socket is closed */
|
||||
close(fds[1]);
|
||||
waitpid(pid, NULL, 0); /* bury zombie */
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int
|
||||
fuse_mount_sys(const char *mnt, struct mount_opts *mo, const char *mnt_opts)
|
||||
{
|
||||
int fd;
|
||||
int res;
|
||||
char tmp[128];
|
||||
const char *devname = "/dev/fuse";
|
||||
std::string source;
|
||||
std::string type;
|
||||
struct stat stbuf;
|
||||
int fd;
|
||||
int res;
|
||||
|
||||
if(!mnt)
|
||||
{
|
||||
|
|
@ -432,7 +459,7 @@ fuse_mount_sys(const char *mnt,
|
|||
mnt);
|
||||
res = umount(mnt);
|
||||
if(res == 0)
|
||||
fprintf(stderr,"mergerfs: umount succeeded");
|
||||
fprintf(stderr, "mergerfs: umount succeeded");
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr,
|
||||
|
|
@ -443,13 +470,13 @@ fuse_mount_sys(const char *mnt,
|
|||
break;
|
||||
}
|
||||
|
||||
memset(&stbuf,0,sizeof(stbuf));
|
||||
memset(&stbuf, 0, sizeof(stbuf));
|
||||
res = stat(mnt,&stbuf);
|
||||
if(res == -1)
|
||||
stbuf.st_mode = S_IFDIR;
|
||||
}
|
||||
|
||||
if (mo->auto_unmount)
|
||||
if(mo->auto_unmount)
|
||||
{
|
||||
/* Tell the caller to fallback to fusermount because
|
||||
auto-unmount does not work otherwise. */
|
||||
|
|
@ -460,10 +487,11 @@ fuse_mount_sys(const char *mnt,
|
|||
if(fd == -1)
|
||||
{
|
||||
if(errno == ENODEV || errno == ENOENT)
|
||||
fprintf(stderr, "mergerfs: device not found, try 'modprobe fuse' first\n");
|
||||
fprintf(stderr,
|
||||
"mergerfs: device not found, try 'modprobe fuse' first\n");
|
||||
else
|
||||
fprintf(stderr, "mergerfs: failed to open %s: %s\n",
|
||||
devname, strerror(errno));
|
||||
fprintf(stderr, "mergerfs: failed to open %s: %s\n", devname,
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
@ -471,100 +499,112 @@ fuse_mount_sys(const char *mnt,
|
|||
sizeof(tmp),
|
||||
"fd=%i,rootmode=%o,user_id=%u,group_id=%u",
|
||||
fd,
|
||||
stbuf.st_mode & S_IFMT,
|
||||
(stbuf.st_mode & S_IFMT),
|
||||
getuid(),
|
||||
getgid());
|
||||
|
||||
res = fuse_opt_add_opt(&mo->kernel_opts, tmp);
|
||||
if (res == -1)
|
||||
if(res == -1)
|
||||
goto out_close;
|
||||
|
||||
type = mo->blkdev ? "fuseblk" : "fuse";
|
||||
if (mo->subtype)
|
||||
if(mo->subtype)
|
||||
type += "." + std::string(mo->subtype);
|
||||
|
||||
source = mo->fsname ? mo->fsname : (mo->subtype ? mo->subtype : devname);
|
||||
source = mo->fsname ? mo->fsname :(mo->subtype ? mo->subtype : devname);
|
||||
|
||||
res = mount(source.c_str(), mnt, type.c_str(), mo->flags, mo->kernel_opts);
|
||||
if (res == -1 && errno == ENODEV && mo->subtype) {
|
||||
/* Probably missing subtype support */
|
||||
type = mo->blkdev ? "fuseblk" : "fuse";
|
||||
if (mo->fsname) {
|
||||
if (!mo->blkdev)
|
||||
source = std::string(mo->subtype) + "#" + mo->fsname;
|
||||
} else {
|
||||
source = type;
|
||||
}
|
||||
res = mount(source.c_str(), mnt, type.c_str(), 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) {
|
||||
res = -2;
|
||||
} else {
|
||||
int errno_save = errno;
|
||||
if (mo->blkdev && errno == ENODEV &&
|
||||
!fuse_mnt_check_fuseblk())
|
||||
res = mount(source.c_str(), mnt, type.c_str(), mo->flags,
|
||||
mo->kernel_opts);
|
||||
if(res == -1 && errno == ENODEV && mo->subtype)
|
||||
{
|
||||
/* Probably missing subtype support */
|
||||
type = mo->blkdev ? "fuseblk" : "fuse";
|
||||
if(mo->fsname)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"mergerfs: 'fuseblk' support missing\n");
|
||||
if(!mo->blkdev)
|
||||
source = std::string(mo->subtype) + "#" + mo->fsname;
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr,
|
||||
"mergerfs: mount failed: %s\n",
|
||||
strerror(errno_save));
|
||||
source = type;
|
||||
}
|
||||
res = mount(source.c_str(), mnt, type.c_str(), 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)
|
||||
{
|
||||
res = -2;
|
||||
}
|
||||
else
|
||||
{
|
||||
int errno_save = errno;
|
||||
if(mo->blkdev && errno == ENODEV && !fuse_mnt_check_fuseblk())
|
||||
{
|
||||
fprintf(stderr,"mergerfs: 'fuseblk' support missing\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr,
|
||||
"mergerfs: mount failed: %s\n",
|
||||
strerror(errno_save));
|
||||
}
|
||||
}
|
||||
|
||||
goto out_close;
|
||||
}
|
||||
goto out_close;
|
||||
}
|
||||
|
||||
#ifndef __NetBSD__
|
||||
#ifndef IGNORE_MTAB
|
||||
if (geteuid() == 0) {
|
||||
char *newmnt = fuse_mnt_resolve_path("fuse", mnt);
|
||||
res = -1;
|
||||
if (!newmnt)
|
||||
goto out_umount;
|
||||
if(geteuid() == 0)
|
||||
{
|
||||
char *newmnt = fuse_mnt_resolve_path("fuse", mnt);
|
||||
res = -1;
|
||||
if(!newmnt)
|
||||
goto out_umount;
|
||||
|
||||
res = fuse_mnt_add_mount("fuse", source.c_str(), newmnt, type.c_str(),
|
||||
mnt_opts);
|
||||
free(newmnt);
|
||||
if (res == -1)
|
||||
goto out_umount;
|
||||
}
|
||||
res = fuse_mnt_add_mount("fuse", source.c_str(), newmnt, type.c_str(),
|
||||
mnt_opts);
|
||||
free(newmnt);
|
||||
if(res == -1)
|
||||
goto out_umount;
|
||||
}
|
||||
#endif /* IGNORE_MTAB */
|
||||
#endif /* __NetBSD__ */
|
||||
|
||||
return fd;
|
||||
|
||||
out_umount:
|
||||
umount2(mnt, 2); /* lazy umount */
|
||||
umount2(mnt,MNT_DETACH); /* lazy umount */
|
||||
out_close:
|
||||
close(fd);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int get_mnt_flag_opts(char **mnt_optsp, int flags)
|
||||
static int
|
||||
get_mnt_flag_opts(char **mnt_optsp, int flags)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!(flags & MS_RDONLY) && fuse_opt_add_opt(mnt_optsp, "rw") == -1)
|
||||
if(!(flags & MS_RDONLY) && fuse_opt_add_opt(mnt_optsp, "rw") == -1)
|
||||
return -1;
|
||||
|
||||
for (i = 0; mount_flags[i].opt != NULL; i++) {
|
||||
if (mount_flags[i].on && (flags & mount_flags[i].flag) &&
|
||||
fuse_opt_add_opt(mnt_optsp, mount_flags[i].opt) == -1)
|
||||
return -1;
|
||||
}
|
||||
for(i = 0; mount_flags[i].opt != NULL; i++)
|
||||
{
|
||||
if(mount_flags[i].on &&(flags & mount_flags[i].flag)
|
||||
&& fuse_opt_add_opt(mnt_optsp, mount_flags[i].opt) == -1)
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fuse_kern_mount(const char *mountpoint, struct fuse_args *args)
|
||||
int
|
||||
fuse_kern_mount(const char *mountpoint, struct fuse_args *args)
|
||||
{
|
||||
struct mount_opts mo;
|
||||
int res = -1;
|
||||
|
|
@ -573,43 +613,48 @@ int fuse_kern_mount(const char *mountpoint, struct fuse_args *args)
|
|||
memset(&mo, 0, sizeof(mo));
|
||||
mo.flags = MS_NOSUID | MS_NODEV;
|
||||
|
||||
if(args &&
|
||||
fuse_opt_parse(args, &mo, fuse_mount_opts, fuse_mount_opt_proc) == -1)
|
||||
if(args
|
||||
&& fuse_opt_parse(args, &mo, fuse_mount_opts, fuse_mount_opt_proc)
|
||||
== -1)
|
||||
return -1;
|
||||
|
||||
res = -1;
|
||||
if (get_mnt_flag_opts(&mnt_opts, mo.flags) == -1)
|
||||
if(get_mnt_flag_opts(&mnt_opts, mo.flags) == -1)
|
||||
goto out;
|
||||
if (mo.kernel_opts && fuse_opt_add_opt(&mnt_opts, mo.kernel_opts) == -1)
|
||||
if(mo.kernel_opts && fuse_opt_add_opt(&mnt_opts, mo.kernel_opts) == -1)
|
||||
goto out;
|
||||
if (mo.mtab_opts && fuse_opt_add_opt(&mnt_opts, mo.mtab_opts) == -1)
|
||||
if(mo.mtab_opts && fuse_opt_add_opt(&mnt_opts, mo.mtab_opts) == -1)
|
||||
goto out;
|
||||
|
||||
res = fuse_mount_sys(mountpoint, &mo, mnt_opts);
|
||||
if (res == -2) {
|
||||
if (mo.fusermount_opts &&
|
||||
fuse_opt_add_opt(&mnt_opts, mo.fusermount_opts) == -1)
|
||||
goto out;
|
||||
|
||||
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);
|
||||
if(res == -2)
|
||||
{
|
||||
if(mo.fusermount_opts
|
||||
&& fuse_opt_add_opt(&mnt_opts, mo.fusermount_opts) == -1)
|
||||
goto out;
|
||||
}
|
||||
|
||||
res = fuse_mount_fusermount(mountpoint, &mo, tmp_opts, 1);
|
||||
free(tmp_opts);
|
||||
if (res == -1)
|
||||
res = fuse_mount_fusermount(mountpoint, &mo,
|
||||
mnt_opts, 0);
|
||||
} else {
|
||||
res = fuse_mount_fusermount(mountpoint, &mo, mnt_opts, 0);
|
||||
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, &mo, tmp_opts, 1);
|
||||
free(tmp_opts);
|
||||
if(res == -1)
|
||||
res = fuse_mount_fusermount(mountpoint, &mo, mnt_opts, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
res = fuse_mount_fusermount(mountpoint, &mo, mnt_opts, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
out:
|
||||
free(mnt_opts);
|
||||
free(mo.fsname);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue