Make it possible to mount a fuse filesystem, such as squashfuse,
from a Linux binary. Should come handy for AppImages. Reviewed by: asomers MFC after: 2 weeks Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D26959
This commit is contained in:
parent
8b8af16875
commit
e3b1c847a4
@ -1181,13 +1181,15 @@ linux_pwritev(struct thread *td, struct linux_pwritev_args *uap)
|
|||||||
int
|
int
|
||||||
linux_mount(struct thread *td, struct linux_mount_args *args)
|
linux_mount(struct thread *td, struct linux_mount_args *args)
|
||||||
{
|
{
|
||||||
char fstypename[MFSNAMELEN];
|
struct mntarg *ma = NULL;
|
||||||
char *mntonname, *mntfromname;
|
char *fstypename, *mntonname, *mntfromname, *data;
|
||||||
int error, fsflags;
|
int error, fsflags;
|
||||||
|
|
||||||
|
fstypename = malloc(MNAMELEN, M_TEMP, M_WAITOK);
|
||||||
mntonname = malloc(MNAMELEN, M_TEMP, M_WAITOK);
|
mntonname = malloc(MNAMELEN, M_TEMP, M_WAITOK);
|
||||||
mntfromname = malloc(MNAMELEN, M_TEMP, M_WAITOK);
|
mntfromname = malloc(MNAMELEN, M_TEMP, M_WAITOK);
|
||||||
error = copyinstr(args->filesystemtype, fstypename, MFSNAMELEN - 1,
|
data = NULL;
|
||||||
|
error = copyinstr(args->filesystemtype, fstypename, MNAMELEN - 1,
|
||||||
NULL);
|
NULL);
|
||||||
if (error != 0)
|
if (error != 0)
|
||||||
goto out;
|
goto out;
|
||||||
@ -1208,6 +1210,31 @@ linux_mount(struct thread *td, struct linux_mount_args *args)
|
|||||||
strcpy(fstypename, "linprocfs");
|
strcpy(fstypename, "linprocfs");
|
||||||
} else if (strcmp(fstypename, "vfat") == 0) {
|
} else if (strcmp(fstypename, "vfat") == 0) {
|
||||||
strcpy(fstypename, "msdosfs");
|
strcpy(fstypename, "msdosfs");
|
||||||
|
} else if (strcmp(fstypename, "fuse") == 0) {
|
||||||
|
char *fuse_options, *fuse_option, *fuse_name;
|
||||||
|
|
||||||
|
if (strcmp(mntfromname, "fuse") == 0)
|
||||||
|
strcpy(mntfromname, "/dev/fuse");
|
||||||
|
|
||||||
|
strcpy(fstypename, "fusefs");
|
||||||
|
data = malloc(MNAMELEN, M_TEMP, M_WAITOK);
|
||||||
|
error = copyinstr(args->data, data, MNAMELEN - 1, NULL);
|
||||||
|
if (error != 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
fuse_options = data;
|
||||||
|
while ((fuse_option = strsep(&fuse_options, ",")) != NULL) {
|
||||||
|
fuse_name = strsep(&fuse_option, "=");
|
||||||
|
if (fuse_name == NULL || fuse_option == NULL)
|
||||||
|
goto out;
|
||||||
|
ma = mount_arg(ma, fuse_name, fuse_option, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The FUSE server uses Linux errno values instead of FreeBSD
|
||||||
|
* ones; add a flag to tell fuse(4) to do errno translation.
|
||||||
|
*/
|
||||||
|
ma = mount_arg(ma, "linux_errnos", "1", -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
fsflags = 0;
|
fsflags = 0;
|
||||||
@ -1225,14 +1252,15 @@ linux_mount(struct thread *td, struct linux_mount_args *args)
|
|||||||
if (args->rwflag & LINUX_MS_REMOUNT)
|
if (args->rwflag & LINUX_MS_REMOUNT)
|
||||||
fsflags |= MNT_UPDATE;
|
fsflags |= MNT_UPDATE;
|
||||||
|
|
||||||
error = kernel_vmount(fsflags,
|
ma = mount_arg(ma, "fstype", fstypename, -1);
|
||||||
"fstype", fstypename,
|
ma = mount_arg(ma, "fspath", mntonname, -1);
|
||||||
"fspath", mntonname,
|
ma = mount_arg(ma, "from", mntfromname, -1);
|
||||||
"from", mntfromname,
|
error = kernel_mount(ma, fsflags);
|
||||||
NULL);
|
|
||||||
out:
|
out:
|
||||||
|
free(fstypename, M_TEMP);
|
||||||
free(mntonname, M_TEMP);
|
free(mntonname, M_TEMP);
|
||||||
free(mntfromname, M_TEMP);
|
free(mntfromname, M_TEMP);
|
||||||
|
free(data, M_TEMP);
|
||||||
return (error);
|
return (error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,6 +89,9 @@ __FBSDID("$FreeBSD$");
|
|||||||
#include "fuse_internal.h"
|
#include "fuse_internal.h"
|
||||||
#include "fuse_ipc.h"
|
#include "fuse_ipc.h"
|
||||||
|
|
||||||
|
#include <compat/linux/linux_errno.h>
|
||||||
|
#include <compat/linux/linux_errno.inc>
|
||||||
|
|
||||||
SDT_PROVIDER_DECLARE(fusefs);
|
SDT_PROVIDER_DECLARE(fusefs);
|
||||||
/*
|
/*
|
||||||
* Fuse trace probe:
|
* Fuse trace probe:
|
||||||
@ -451,6 +454,15 @@ fuse_device_write(struct cdev *dev, struct uio *uio, int ioflag)
|
|||||||
if ((err = uiomove(&ohead, sizeof(struct fuse_out_header), uio)) != 0)
|
if ((err = uiomove(&ohead, sizeof(struct fuse_out_header), uio)) != 0)
|
||||||
return (err);
|
return (err);
|
||||||
|
|
||||||
|
if (data->linux_errnos != 0 && ohead.error != 0) {
|
||||||
|
err = -ohead.error;
|
||||||
|
if (err < 0 || err >= nitems(linux_to_bsd_errtbl))
|
||||||
|
return (EINVAL);
|
||||||
|
|
||||||
|
/* '-', because it will get flipped again below */
|
||||||
|
ohead.error = -linux_to_bsd_errtbl[err];
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We check header information (which is redundant) and compare it
|
* We check header information (which is redundant) and compare it
|
||||||
* with what we see. If we see some inconsistency we discard the
|
* with what we see. If we see some inconsistency we discard the
|
||||||
|
@ -217,6 +217,7 @@ struct fuse_data {
|
|||||||
struct selinfo ks_rsel;
|
struct selinfo ks_rsel;
|
||||||
|
|
||||||
int daemon_timeout;
|
int daemon_timeout;
|
||||||
|
int linux_errnos;
|
||||||
unsigned time_gran;
|
unsigned time_gran;
|
||||||
uint64_t notimpl;
|
uint64_t notimpl;
|
||||||
uint64_t mnt_flag;
|
uint64_t mnt_flag;
|
||||||
|
@ -300,6 +300,7 @@ fuse_vfsop_mount(struct mount *mp)
|
|||||||
|
|
||||||
uint64_t mntopts, __mntopts;
|
uint64_t mntopts, __mntopts;
|
||||||
uint32_t max_read;
|
uint32_t max_read;
|
||||||
|
int linux_errnos;
|
||||||
int daemon_timeout;
|
int daemon_timeout;
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
@ -312,6 +313,7 @@ fuse_vfsop_mount(struct mount *mp)
|
|||||||
|
|
||||||
subtype = NULL;
|
subtype = NULL;
|
||||||
max_read = ~0;
|
max_read = ~0;
|
||||||
|
linux_errnos = 0;
|
||||||
err = 0;
|
err = 0;
|
||||||
mntopts = 0;
|
mntopts = 0;
|
||||||
__mntopts = 0;
|
__mntopts = 0;
|
||||||
@ -337,6 +339,7 @@ fuse_vfsop_mount(struct mount *mp)
|
|||||||
FUSE_FLAGOPT(intr, FSESS_INTR);
|
FUSE_FLAGOPT(intr, FSESS_INTR);
|
||||||
|
|
||||||
(void)vfs_scanopt(opts, "max_read=", "%u", &max_read);
|
(void)vfs_scanopt(opts, "max_read=", "%u", &max_read);
|
||||||
|
(void)vfs_scanopt(opts, "linux_errnos", "%d", &linux_errnos);
|
||||||
if (vfs_scanopt(opts, "timeout=", "%u", &daemon_timeout) == 1) {
|
if (vfs_scanopt(opts, "timeout=", "%u", &daemon_timeout) == 1) {
|
||||||
if (daemon_timeout < FUSE_MIN_DAEMON_TIMEOUT)
|
if (daemon_timeout < FUSE_MIN_DAEMON_TIMEOUT)
|
||||||
daemon_timeout = FUSE_MIN_DAEMON_TIMEOUT;
|
daemon_timeout = FUSE_MIN_DAEMON_TIMEOUT;
|
||||||
@ -411,6 +414,7 @@ fuse_vfsop_mount(struct mount *mp)
|
|||||||
data->dataflags |= mntopts;
|
data->dataflags |= mntopts;
|
||||||
data->max_read = max_read;
|
data->max_read = max_read;
|
||||||
data->daemon_timeout = daemon_timeout;
|
data->daemon_timeout = daemon_timeout;
|
||||||
|
data->linux_errnos = linux_errnos;
|
||||||
data->mnt_flag = mp->mnt_flag & MNT_UPDATEMASK;
|
data->mnt_flag = mp->mnt_flag & MNT_UPDATEMASK;
|
||||||
FUSE_UNLOCK();
|
FUSE_UNLOCK();
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user