|
|
|
@ -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 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 umount2(mnt, flags) unmount(mnt, (flags == 2) ? MNT_FORCE : 0) |
|
|
|
#define umount2(mnt, flags) unmount(mnt,(flags == MNT_DETACH) ? MNT_FORCE : 0) |
|
|
|
#endif |
|
|
|
|
|
|
|
#define FUSERMOUNT_PROG "fusermount" |
|
|
|
#define FUSE_COMMFD_ENV "_FUSE_COMMFD" |
|
|
|
#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)) |
|
|
|
return; |
|
|
|
} |
|
|
|
/* 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) |
|
|
|
static |
|
|
|
int |
|
|
|
fuse_mount_fusermount(const char *mountpoint, |
|
|
|
struct mount_opts *mo, |
|
|
|
const char *opts, |
|
|
|
int quiet) |
|
|
|
{ |
|
|
|
int fds[2], pid; |
|
|
|
int fds[2]; |
|
|
|
int pid; |
|
|
|
int res; |
|
|
|
int rv; |
|
|
|
|
|
|
|
if (!mountpoint) { |
|
|
|
fprintf(stderr, "mergerfs: missing mountpoint parameter\n"); |
|
|
|
return -1; |
|
|
|
} |
|
|
|
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; |
|
|
|
} |
|
|
|
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); |
|
|
|
} |
|
|
|
if(pid == -1) |
|
|
|
{ |
|
|
|
perror("mergerfs: fork() failed"); |
|
|
|
close(fds[0]); |
|
|
|
close(fds[1]); |
|
|
|
return -1; |
|
|
|
} |
|
|
|
|
|
|
|
argv[a++] = FUSERMOUNT_PROG; |
|
|
|
if (opts) { |
|
|
|
argv[a++] = "-o"; |
|
|
|
argv[a++] = opts; |
|
|
|
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); |
|
|
|
} |
|
|
|
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 */ |
|
|
|
} |
|
|
|
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) |
|
|
|
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); |
|
|
|
|
|
|
|
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()) |
|
|
|
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) |
|
|
|
{ |
|
|
|
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; |
|
|
|
|
|
|
|
res = fuse_mnt_add_mount("fuse", source.c_str(), newmnt, type.c_str(), |
|
|
|
mnt_opts); |
|
|
|
free(newmnt); |
|
|
|
if (res == -1) |
|
|
|
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; |
|
|
|
} |
|
|
|
#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); |
|
|
|
|