mirror of
https://github.com/openharmony/third_party_libfuse.git
synced 2026-07-21 00:45:56 -04:00
Add support for direct mounting by libfuse
This commit is contained in:
@@ -1,3 +1,8 @@
|
||||
2007-03-30 Miklos Szeredi <miklos@szeredi.hu>
|
||||
|
||||
* Add support for direct mounting by libfuse. Fall back on
|
||||
calling fusermount if it doesn't work
|
||||
|
||||
2007-03-14 Miklos Szeredi <miklos@szeredi.hu>
|
||||
|
||||
* Released 2.7.0-pre1
|
||||
|
||||
+216
-27
@@ -21,6 +21,7 @@
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/mount.h>
|
||||
|
||||
#define FUSERMOUNT_PROG "fusermount"
|
||||
#define FUSE_COMMFD_ENV "_FUSE_COMMFD"
|
||||
@@ -29,8 +30,15 @@
|
||||
#define fork() vfork()
|
||||
#endif
|
||||
|
||||
#ifndef MS_DIRSYNC
|
||||
#define MS_DIRSYNC 128
|
||||
#endif
|
||||
|
||||
enum {
|
||||
KEY_KERN,
|
||||
KEY_KERN_FLAG,
|
||||
KEY_KERN_OPT,
|
||||
KEY_FUSERMOUNT_OPT,
|
||||
KEY_MTAB_OPT,
|
||||
KEY_ALLOW_ROOT,
|
||||
KEY_RO,
|
||||
KEY_HELP,
|
||||
@@ -41,36 +49,50 @@ struct mount_opts {
|
||||
int allow_other;
|
||||
int allow_root;
|
||||
int ishelp;
|
||||
int flags;
|
||||
int nonempty;
|
||||
int blkdev;
|
||||
int large_read;
|
||||
char *fsname;
|
||||
char *mtab_opts;
|
||||
char *fusermount_opts;
|
||||
char *kernel_opts;
|
||||
};
|
||||
|
||||
#define FUSE_MOUNT_OPT(t, p) { t, offsetof(struct mount_opts, p), 1 }
|
||||
|
||||
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_other", KEY_KERN),
|
||||
FUSE_MOUNT_OPT("allow_other", allow_other),
|
||||
FUSE_MOUNT_OPT("allow_root", allow_root),
|
||||
FUSE_MOUNT_OPT("nonempty", nonempty),
|
||||
FUSE_MOUNT_OPT("blkdev", blkdev),
|
||||
FUSE_MOUNT_OPT("fsname=%s", fsname),
|
||||
FUSE_MOUNT_OPT("large_read", large_read),
|
||||
FUSE_OPT_KEY("allow_other", KEY_KERN_OPT),
|
||||
FUSE_OPT_KEY("allow_root", KEY_ALLOW_ROOT),
|
||||
FUSE_OPT_KEY("nonempty", KEY_KERN),
|
||||
FUSE_OPT_KEY("blkdev", KEY_KERN),
|
||||
FUSE_OPT_KEY("blksize=", KEY_KERN),
|
||||
FUSE_OPT_KEY("default_permissions", KEY_KERN),
|
||||
FUSE_OPT_KEY("fsname=", KEY_KERN),
|
||||
FUSE_OPT_KEY("large_read", KEY_KERN),
|
||||
FUSE_OPT_KEY("max_read=", KEY_KERN),
|
||||
FUSE_OPT_KEY("nonempty", KEY_FUSERMOUNT_OPT),
|
||||
FUSE_OPT_KEY("blkdev", KEY_FUSERMOUNT_OPT),
|
||||
FUSE_OPT_KEY("fsname=", KEY_FUSERMOUNT_OPT),
|
||||
FUSE_OPT_KEY("large_read", KEY_FUSERMOUNT_OPT),
|
||||
FUSE_OPT_KEY("blksize=", KEY_KERN_OPT),
|
||||
FUSE_OPT_KEY("default_permissions", 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("-r", KEY_RO),
|
||||
FUSE_OPT_KEY("ro", KEY_KERN),
|
||||
FUSE_OPT_KEY("rw", KEY_KERN),
|
||||
FUSE_OPT_KEY("suid", KEY_KERN),
|
||||
FUSE_OPT_KEY("nosuid", KEY_KERN),
|
||||
FUSE_OPT_KEY("dev", KEY_KERN),
|
||||
FUSE_OPT_KEY("nodev", KEY_KERN),
|
||||
FUSE_OPT_KEY("exec", KEY_KERN),
|
||||
FUSE_OPT_KEY("noexec", KEY_KERN),
|
||||
FUSE_OPT_KEY("async", KEY_KERN),
|
||||
FUSE_OPT_KEY("sync", KEY_KERN),
|
||||
FUSE_OPT_KEY("dirsync", KEY_KERN),
|
||||
FUSE_OPT_KEY("atime", KEY_KERN),
|
||||
FUSE_OPT_KEY("noatime", KEY_KERN),
|
||||
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("-h", KEY_HELP),
|
||||
FUSE_OPT_KEY("--help", KEY_HELP),
|
||||
FUSE_OPT_KEY("-V", KEY_VERSION),
|
||||
@@ -109,6 +131,47 @@ static void mount_version(void)
|
||||
waitpid(pid, NULL, 0);
|
||||
}
|
||||
|
||||
struct mount_flags {
|
||||
const char *opt;
|
||||
unsigned long flag;
|
||||
int on;
|
||||
};
|
||||
|
||||
static 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},
|
||||
{"dirsync", MS_DIRSYNC, 1},
|
||||
{NULL, 0, 0}
|
||||
};
|
||||
|
||||
static void set_mount_flag(const char *s, int *flags)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; mount_flags[i].opt != NULL; i++) {
|
||||
const char *opt = mount_flags[i].opt;
|
||||
if (strcmp(opt, s) == 0) {
|
||||
if (mount_flags[i].on)
|
||||
*flags |= mount_flags[i].flag;
|
||||
else
|
||||
*flags &= ~mount_flags[i].flag;
|
||||
return;
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "fuse: internal error, can't find mount flag\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
static int fuse_mount_opt_proc(void *data, const char *arg, int key,
|
||||
struct fuse_args *outargs)
|
||||
{
|
||||
@@ -124,10 +187,19 @@ static int fuse_mount_opt_proc(void *data, const char *arg, int key,
|
||||
case KEY_RO:
|
||||
arg = "ro";
|
||||
/* fall through */
|
||||
case KEY_KERN_FLAG:
|
||||
set_mount_flag(arg, &mo->flags);
|
||||
return 0;
|
||||
|
||||
case KEY_KERN:
|
||||
case KEY_KERN_OPT:
|
||||
return fuse_opt_add_opt(&mo->kernel_opts, arg);
|
||||
|
||||
case KEY_FUSERMOUNT_OPT:
|
||||
return fuse_opt_add_opt(&mo->fusermount_opts, arg);
|
||||
|
||||
case KEY_MTAB_OPT:
|
||||
return fuse_opt_add_opt(&mo->mtab_opts, arg);
|
||||
|
||||
case KEY_HELP:
|
||||
mount_help();
|
||||
mo->ishelp = 1;
|
||||
@@ -280,12 +352,109 @@ int fuse_mount_compat22(const char *mountpoint, const char *opts)
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int add_mount(const char *fsname, const char *mnt, const char *type,
|
||||
const char *opts)
|
||||
{
|
||||
int res;
|
||||
int status;
|
||||
|
||||
res = fork();
|
||||
if (res == -1) {
|
||||
perror("fork");
|
||||
return -1;
|
||||
}
|
||||
if (res == 0) {
|
||||
setuid(geteuid());
|
||||
execl("/bin/mount", "/bin/mount", "-i", "-f", "-t", type, "-o", opts,
|
||||
fsname, mnt, NULL);
|
||||
perror("execl /bin/mount");
|
||||
exit(1);
|
||||
}
|
||||
res = waitpid(res, &status, 0);
|
||||
if (res == -1) {
|
||||
perror("waitpid");
|
||||
return -1;
|
||||
}
|
||||
if (status != 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fuse_mount_sys(const char *mnt, struct mount_opts *mo,
|
||||
const char *mnt_opts)
|
||||
{
|
||||
const char *type = mo->blkdev ? "fuseblk" : "fuse";
|
||||
char tmp[128];
|
||||
const char *devname = "/dev/fuse";
|
||||
struct stat stbuf;
|
||||
int fd;
|
||||
int res;
|
||||
|
||||
/* For now silently fall back to fusermount if something doesn't work */
|
||||
|
||||
/* FIXME: check non-empty mountpoint*/
|
||||
|
||||
if (mo->large_read)
|
||||
return -1;
|
||||
|
||||
res = lstat(mnt, &stbuf);
|
||||
if (res == -1)
|
||||
return -1;
|
||||
|
||||
fd = open(devname, O_RDWR);
|
||||
if (fd == -1)
|
||||
return -1;
|
||||
|
||||
if (mo->fsname)
|
||||
devname = mo->fsname;
|
||||
|
||||
snprintf(tmp, sizeof(tmp), "fd=%i,rootmode=%o,user_id=%i,group_id=%i", fd,
|
||||
stbuf.st_mode & S_IFMT, getuid(), getgid());
|
||||
|
||||
if (fuse_opt_add_opt(&mo->kernel_opts, tmp) == -1) {
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
res = mount(devname, mnt, type, mo->flags, mo->kernel_opts);
|
||||
if (res == -1) {
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
if (geteuid() == 0) {
|
||||
res = add_mount(devname, mnt, type, mnt_opts);
|
||||
if (res == -1) {
|
||||
umount2(mnt, 2); /* lazy umount */
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
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)
|
||||
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)
|
||||
{
|
||||
struct mount_opts mo;
|
||||
int res = -1;
|
||||
char *mnt_opts = NULL;
|
||||
|
||||
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)
|
||||
@@ -295,12 +464,32 @@ int fuse_kern_mount(const char *mountpoint, struct fuse_args *args)
|
||||
fprintf(stderr, "fuse: 'allow_other' and 'allow_root' options are mutually exclusive\n");
|
||||
goto out;
|
||||
}
|
||||
res = 0;
|
||||
if (mo.ishelp)
|
||||
return 0;
|
||||
goto out;
|
||||
|
||||
res = fuse_mount_compat22(mountpoint, mo.kernel_opts);
|
||||
res = -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)
|
||||
goto out;
|
||||
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 == -1) {
|
||||
if (mo.fusermount_opts &&
|
||||
fuse_opt_add_opt(&mnt_opts, mo.fusermount_opts) == -1)
|
||||
goto out;
|
||||
|
||||
res = fuse_mount_compat22(mountpoint, mnt_opts);
|
||||
}
|
||||
out:
|
||||
free(mnt_opts);
|
||||
free(mo.fsname);
|
||||
free(mo.fusermount_opts);
|
||||
free(mo.kernel_opts);
|
||||
free(mo.mtab_opts);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user