mirror of
https://github.com/libfuse/libfuse.git
synced 2026-07-07 14:47:41 +08:00
eec851bedd
We actually need these in fusermount.c and for the new mount API, which goes into its own file. Also extend the struct with the extra safe field used by fusermount.c Signed-off-by: Bernd Schubert <bernd@bsbernd.com> Reviewed-by: "Darrick J. Wong" <djwong@kernel.org>
272 lines
6.0 KiB
C
272 lines
6.0 KiB
C
/*
|
|
FUSE: Filesystem in Userspace
|
|
Copyright (C) 2005-2008 Csaba Henk <csaba.henk@creo.hu>
|
|
|
|
Architecture specific file system mounting (FreeBSD).
|
|
|
|
This program can be distributed under the terms of the GNU LGPLv2.
|
|
See the file LGPL2.txt.
|
|
*/
|
|
|
|
#include "fuse_config.h"
|
|
#include "fuse_i.h"
|
|
#include "mount_common_i.h"
|
|
#include "fuse_misc.h"
|
|
#include "fuse_opt.h"
|
|
#include "util.h"
|
|
|
|
#include <sys/param.h>
|
|
#include <sys/mount.h>
|
|
#include "fuse_mount_compat.h"
|
|
|
|
#include <sys/wait.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <stddef.h>
|
|
#include <fcntl.h>
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
|
|
#define FUSERMOUNT_PROG "mount_fusefs"
|
|
#define FUSE_DEV_TRUNK "/dev/fuse"
|
|
|
|
enum {
|
|
KEY_RO,
|
|
KEY_KERN
|
|
};
|
|
|
|
struct mount_opts {
|
|
int allow_other;
|
|
char *kernel_opts;
|
|
unsigned max_read;
|
|
};
|
|
|
|
#define FUSE_DUAL_OPT_KEY(templ, key) \
|
|
FUSE_OPT_KEY(templ, key), FUSE_OPT_KEY("no" templ, key)
|
|
|
|
static const struct fuse_opt fuse_mount_opts[] = {
|
|
{ "allow_other", offsetof(struct mount_opts, allow_other), 1 },
|
|
{ "max_read=%u", offsetof(struct mount_opts, max_read), 1 },
|
|
FUSE_OPT_KEY("-r", KEY_RO),
|
|
/* standard FreeBSD mount options */
|
|
FUSE_DUAL_OPT_KEY("dev", KEY_KERN),
|
|
FUSE_DUAL_OPT_KEY("async", KEY_KERN),
|
|
FUSE_DUAL_OPT_KEY("atime", KEY_KERN),
|
|
FUSE_DUAL_OPT_KEY("dev", KEY_KERN),
|
|
FUSE_DUAL_OPT_KEY("exec", KEY_KERN),
|
|
FUSE_DUAL_OPT_KEY("suid", KEY_KERN),
|
|
FUSE_DUAL_OPT_KEY("symfollow", KEY_KERN),
|
|
FUSE_DUAL_OPT_KEY("rdonly", KEY_KERN),
|
|
FUSE_DUAL_OPT_KEY("sync", KEY_KERN),
|
|
FUSE_DUAL_OPT_KEY("union", KEY_KERN),
|
|
FUSE_DUAL_OPT_KEY("userquota", KEY_KERN),
|
|
FUSE_DUAL_OPT_KEY("groupquota", KEY_KERN),
|
|
FUSE_DUAL_OPT_KEY("clusterr", KEY_KERN),
|
|
FUSE_DUAL_OPT_KEY("clusterw", KEY_KERN),
|
|
FUSE_DUAL_OPT_KEY("suiddir", KEY_KERN),
|
|
FUSE_DUAL_OPT_KEY("snapshot", KEY_KERN),
|
|
FUSE_DUAL_OPT_KEY("multilabel", KEY_KERN),
|
|
FUSE_DUAL_OPT_KEY("acls", KEY_KERN),
|
|
FUSE_DUAL_OPT_KEY("force", KEY_KERN),
|
|
FUSE_DUAL_OPT_KEY("update", KEY_KERN),
|
|
FUSE_DUAL_OPT_KEY("ro", KEY_KERN),
|
|
FUSE_DUAL_OPT_KEY("rw", KEY_KERN),
|
|
FUSE_DUAL_OPT_KEY("auto", KEY_KERN),
|
|
FUSE_DUAL_OPT_KEY("automounted", KEY_KERN),
|
|
/* options supported under both Linux and FBSD */
|
|
FUSE_DUAL_OPT_KEY("allow_other", KEY_KERN),
|
|
FUSE_DUAL_OPT_KEY("default_permissions",KEY_KERN),
|
|
FUSE_OPT_KEY("max_read=", KEY_KERN),
|
|
FUSE_OPT_KEY("subtype=", KEY_KERN),
|
|
/* FBSD FUSE specific mount options */
|
|
FUSE_DUAL_OPT_KEY("private", KEY_KERN),
|
|
FUSE_DUAL_OPT_KEY("neglect_shares", KEY_KERN),
|
|
FUSE_DUAL_OPT_KEY("push_symlinks_in", KEY_KERN),
|
|
#if __FreeBSD_version >= 1200519
|
|
FUSE_DUAL_OPT_KEY("intr", KEY_KERN),
|
|
#endif
|
|
/* stock FBSD mountopt parsing routine lets anything be negated... */
|
|
/*
|
|
* Linux specific mount options, but let just the mount util
|
|
* handle them
|
|
*/
|
|
FUSE_OPT_KEY("fsname=", KEY_KERN),
|
|
FUSE_OPT_END
|
|
};
|
|
|
|
void fuse_mount_version(void)
|
|
{
|
|
system(FUSERMOUNT_PROG " --version");
|
|
}
|
|
|
|
unsigned int get_max_read(const struct mount_opts *o)
|
|
{
|
|
return o->max_read;
|
|
}
|
|
|
|
static int fuse_mount_opt_proc(void *data, const char *arg, int key,
|
|
struct fuse_args *outargs)
|
|
{
|
|
(void) outargs;
|
|
struct mount_opts *mo = data;
|
|
|
|
switch (key) {
|
|
case KEY_RO:
|
|
arg = "ro";
|
|
/* fall through */
|
|
|
|
case KEY_KERN:
|
|
return fuse_opt_add_opt(&mo->kernel_opts, arg);
|
|
}
|
|
|
|
/* Pass through unknown options */
|
|
return 1;
|
|
}
|
|
|
|
void fuse_kern_unmount(const char *mountpoint, int fd)
|
|
{
|
|
if (close(fd) < 0)
|
|
fuse_log(FUSE_LOG_ERR, "closing FD %d failed: %s", fd, strerror(errno));
|
|
if (unmount(mountpoint, MNT_FORCE) < 0)
|
|
fuse_log(FUSE_LOG_ERR, "unmounting %s failed: %s",
|
|
mountpoint, strerror(errno));
|
|
}
|
|
|
|
static int fuse_mount_core(const char *mountpoint, const char *opts)
|
|
{
|
|
const char *mountprog = FUSERMOUNT_PROG;
|
|
long fd;
|
|
char *fdnam, *dev;
|
|
pid_t pid, cpid;
|
|
int status;
|
|
int err;
|
|
|
|
fdnam = getenv("FUSE_DEV_FD");
|
|
|
|
if (fdnam) {
|
|
err = libfuse_strtol(fdnam, &fd);
|
|
if (err || fd < 0) {
|
|
fuse_log(FUSE_LOG_ERR, "invalid value given in FUSE_DEV_FD\n");
|
|
return -1;
|
|
}
|
|
|
|
goto mount;
|
|
}
|
|
|
|
dev = getenv("FUSE_DEV_NAME");
|
|
|
|
if (! dev)
|
|
dev = (char *)FUSE_DEV_TRUNK;
|
|
|
|
if ((fd = open(dev, O_RDWR)) < 0) {
|
|
perror("fuse: failed to open fuse device");
|
|
return -1;
|
|
}
|
|
|
|
mount:
|
|
if (getenv("FUSE_NO_MOUNT") || ! mountpoint)
|
|
goto out;
|
|
|
|
pid = fork();
|
|
cpid = pid;
|
|
|
|
if (pid == -1) {
|
|
perror("fuse: fork() failed");
|
|
close(fd);
|
|
return -1;
|
|
}
|
|
|
|
if (pid == 0) {
|
|
pid = fork();
|
|
|
|
if (pid == -1) {
|
|
perror("fuse: fork() failed");
|
|
close(fd);
|
|
_exit(EXIT_FAILURE);
|
|
}
|
|
|
|
if (pid == 0) {
|
|
const char *argv[32];
|
|
int a = 0;
|
|
int ret = -1;
|
|
|
|
if (! fdnam)
|
|
{
|
|
ret = asprintf(&fdnam, "%ld", fd);
|
|
if(ret == -1)
|
|
{
|
|
perror("fuse: failed to assemble mount arguments");
|
|
close(fd);
|
|
_exit(EXIT_FAILURE);
|
|
}
|
|
}
|
|
|
|
argv[a++] = mountprog;
|
|
if (opts) {
|
|
argv[a++] = "-o";
|
|
argv[a++] = opts;
|
|
}
|
|
argv[a++] = fdnam;
|
|
argv[a++] = mountpoint;
|
|
argv[a++] = NULL;
|
|
execvp(mountprog, (char **) argv);
|
|
perror("fuse: failed to exec mount program");
|
|
free(fdnam);
|
|
_exit(EXIT_FAILURE);
|
|
}
|
|
|
|
waitpid(pid, &status, 0);
|
|
if (!WIFEXITED(status))
|
|
_exit(EXIT_FAILURE);
|
|
_exit(WEXITSTATUS(status));
|
|
}
|
|
|
|
if (waitpid(cpid, &status, 0) == -1 || WEXITSTATUS(status) != 0) {
|
|
perror("fuse: failed to mount file system");
|
|
if (close(fd) < 0)
|
|
perror("fuse: closing FD");
|
|
return -1;
|
|
}
|
|
|
|
out:
|
|
return fd;
|
|
}
|
|
|
|
struct mount_opts *parse_mount_opts(struct fuse_args *args)
|
|
{
|
|
struct mount_opts *mo;
|
|
|
|
mo = (struct mount_opts*) malloc(sizeof(struct mount_opts));
|
|
if (mo == NULL)
|
|
return NULL;
|
|
|
|
memset(mo, 0, sizeof(struct mount_opts));
|
|
|
|
if (args &&
|
|
fuse_opt_parse(args, mo, fuse_mount_opts, fuse_mount_opt_proc) == -1)
|
|
goto err_out;
|
|
|
|
return mo;
|
|
|
|
err_out:
|
|
destroy_mount_opts(mo);
|
|
return NULL;
|
|
}
|
|
|
|
void destroy_mount_opts(struct mount_opts *mo)
|
|
{
|
|
free(mo->kernel_opts);
|
|
free(mo);
|
|
}
|
|
|
|
int fuse_kern_mount(const char *mountpoint, struct mount_opts *mo)
|
|
{
|
|
/* mount util should not try to spawn the daemon */
|
|
setenv("MOUNT_FUSEFS_SAFE", "1", 1);
|
|
/* to notify the mount util it's called from lib */
|
|
setenv("MOUNT_FUSEFS_CALL_BY_LIB", "1", 1);
|
|
|
|
return fuse_mount_core(mountpoint, mo->kernel_opts);
|
|
}
|