Implemented more of the detailed FUSE initialization functions for file systems

that use them directly instead of fuse_main().


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@30024 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold 2009-04-08 11:18:04 +00:00
parent ab15dd259a
commit 861dbb4810
5 changed files with 312 additions and 23 deletions

View File

@ -272,11 +272,19 @@ PRINT(("FUSEFileSystem::FinishInitClientFS()\n"));
fFUSEConfig = *config; fFUSEConfig = *config;
// do the initialization // do the initialization
status_t error = _InitClientFS(ops, opSize, userData); fInitStatus = _InitClientFS(ops, opSize, userData);
return fInitStatus;
}
status_t
FUSEFileSystem::MainLoop(bool multithreaded)
{
// TODO: Respect the multithreaded flag!
PRINT(("FUSEFileSystem::FinishMounting()\n"));
// notify the mount thread // notify the mount thread
PRINT((" notifying mount thread\n")); PRINT((" notifying mount thread\n"));
fInitStatus = error;
delete_sem(fInitSemaphore); delete_sem(fInitSemaphore);
// loop until unmounting // loop until unmounting
@ -287,10 +295,10 @@ PRINT((" waiting for unmounting done\n"));
fExitSemaphore = -1; fExitSemaphore = -1;
if (error == B_OK) if (fFS != NULL)
fuse_fs_destroy(fFS); fuse_fs_destroy(fFS);
return error; return fExitStatus;
} }

View File

@ -47,6 +47,7 @@ public:
status_t FinishInitClientFS(fuse_config* config, status_t FinishInitClientFS(fuse_config* config,
const fuse_operations* ops, size_t opSize, const fuse_operations* ops, size_t opSize,
void* userData); void* userData);
status_t MainLoop(bool multithreaded);
private: private:
class ArgumentVector; class ArgumentVector;

View File

@ -10,7 +10,30 @@
enum { enum {
KEY_KERN_FLAG,
KEY_KERN_OPT,
KEY_FUSERMOUNT_OPT,
KEY_SUBTYPE_OPT,
KEY_MTAB_OPT,
KEY_ALLOW_ROOT,
KEY_RO,
KEY_HELP, KEY_HELP,
KEY_VERSION,
};
struct mount_opts {
int allow_other;
int allow_root;
int ishelp;
int flags;
int nonempty;
int blkdev;
char *fsname;
char *subtype;
char *subtype_opt;
char *mtab_opts;
char *fusermount_opts;
char *kernel_opts;
}; };
#define FUSE_LIB_OPT(t, p, v) { t, offsetof(struct fuse_config, p), v } #define FUSE_LIB_OPT(t, p, v) { t, offsetof(struct fuse_config, p), v }
@ -46,6 +69,48 @@ static const struct fuse_opt fuse_lib_opts[] = {
FUSE_OPT_END FUSE_OPT_END
}; };
#define FUSE_MOUNT_OPT(t, p) { t, offsetof(struct mount_opts, p), 1 }
static const struct fuse_opt fuse_mount_opts[] = {
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("subtype=%s", subtype),
FUSE_OPT_KEY("allow_other", KEY_KERN_OPT),
FUSE_OPT_KEY("allow_root", KEY_ALLOW_ROOT),
FUSE_OPT_KEY("nonempty", 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("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_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),
FUSE_OPT_KEY("--version", KEY_VERSION),
FUSE_OPT_END
};
static int static int
fuse_lib_opt_proc(void *data, const char *arg, int key, fuse_lib_opt_proc(void *data, const char *arg, int key,
@ -61,7 +126,7 @@ fuse_lib_opt_proc(void *data, const char *arg, int key,
int int
fuse_parse_config_args(struct fuse_args* args, struct fuse_config* config) fuse_parse_lib_config_args(struct fuse_args* args, struct fuse_config* config)
{ {
return fuse_opt_parse(args, config, fuse_lib_opts, fuse_lib_opt_proc) == 0; return fuse_opt_parse(args, config, fuse_lib_opts, fuse_lib_opt_proc) == 0;
} }
@ -73,3 +138,104 @@ fuse_is_lib_option(const char* opt)
return /*fuse_lowlevel_is_lib_option(opt) ||*/ return /*fuse_lowlevel_is_lib_option(opt) ||*/
fuse_opt_match(fuse_lib_opts, opt); fuse_opt_match(fuse_lib_opts, opt);
} }
#if 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}
};
#endif // 0
static void set_mount_flag(const char *s, int *flags)
{
#if 0
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();
#endif
}
static int fuse_mount_opt_proc(void *data, const char *arg, int key,
struct fuse_args *outargs)
{
struct mount_opts *mo = data;
switch (key) {
case KEY_ALLOW_ROOT:
if (fuse_opt_add_opt(&mo->kernel_opts, "allow_other") == -1 ||
fuse_opt_add_arg(outargs, "-oallow_root") == -1)
return -1;
return 0;
case KEY_RO:
arg = "ro";
/* fall through */
case KEY_KERN_FLAG:
set_mount_flag(arg, &mo->flags);
return 0;
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_SUBTYPE_OPT:
return fuse_opt_add_opt(&mo->subtype_opt, arg);
case KEY_MTAB_OPT:
return fuse_opt_add_opt(&mo->mtab_opts, arg);
case KEY_HELP:
// mount_help();
mo->ishelp = 1;
break;
case KEY_VERSION:
// mount_version();
mo->ishelp = 1;
break;
}
return 1;
}
int
fuse_parse_mount_config_args(struct fuse_args* args)
{
struct mount_opts mo;
memset(&mo, 0, sizeof(mo));
return args == 0
|| fuse_opt_parse(args, &mo, fuse_mount_opts, fuse_mount_opt_proc) == 0;
}

View File

@ -41,7 +41,10 @@ struct fuse_config {
extern "C" { extern "C" {
#endif #endif
int fuse_parse_config_args(struct fuse_args* args, struct fuse_config* config); int fuse_parse_lib_config_args(struct fuse_args* args,
struct fuse_config* config);
int fuse_parse_mount_config_args(struct fuse_args* args);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -3,8 +3,12 @@
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
*/ */
#include <errno.h>
#include <signal.h> #include <signal.h>
#include <stdio.h> #include <stdio.h>
#include <string.h>
#include "Debug.h"
#include "fuse_api.h" #include "fuse_api.h"
#include "fuse_config.h" #include "fuse_config.h"
@ -19,29 +23,32 @@ fuse_main_real(int argc, char* argv[], const struct fuse_operations* op,
{ {
printf("fuse_main_real(%d, %p, %p, %ld, %p)\n", argc, argv, op, opSize, printf("fuse_main_real(%d, %p, %p, %ld, %p)\n", argc, argv, op, opSize,
userData); userData);
// Note: We use the fuse_*() functions here to initialize and run the
// file system, although some of them are merely dummies.
// parse args
struct fuse_args args = FUSE_ARGS_INIT(argc, argv); struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
fuse_config config; int result = 1;
memset(&config, 0, sizeof(config));
config.entry_timeout = 1.0; // create the kernel channel
config.attr_timeout = 1.0; struct fuse_chan* channel = fuse_mount("/dummy", &args);
config.negative_timeout = 0.0; if (channel != NULL) {
config.intr_signal = SIGUSR1; // create the FUSE handle
struct fuse* fuseHandle = fuse_new(channel, &args, op, opSize,
userData);
if (fuseHandle != NULL) {
// run the main loop
result = fuse_loop_mt(fuseHandle);
fuse_destroy(fuseHandle);
}
fuse_unmount("/dummy", channel);
}
bool success = fuse_parse_config_args(&args, &config);
fuse_opt_free_args(&args); fuse_opt_free_args(&args);
if (!success) return result;
return 1;
// run the main loop
status_t error = FUSEFileSystem::GetInstance()->FinishInitClientFS(&config,
op, opSize, userData);
return error == B_OK ? 0 : 1;
} }
@ -60,3 +67,107 @@ fuse_get_context(void)
? (fuse_context*)requestThread->GetContext()->GetFSData() ? (fuse_context*)requestThread->GetContext()->GetFSData()
: NULL; : NULL;
} }
struct fuse_chan*
fuse_mount(const char* mountpoint, struct fuse_args* args)
{
// make sure the stdin/out/err descriptors are open
while (true) {
int fd = open("/dev/null", O_RDONLY);
if (fd < 0) {
ERROR(("fuse_mount(): Failed to open /dev/null: %s\n",
strerror(errno)));
return NULL;
}
if (fd > 2) {
close(fd);
break;
}
}
if (!fuse_parse_mount_config_args(args))
return NULL;
return (fuse_chan*)FUSEFileSystem::GetInstance();
}
void
fuse_unmount(const char* mountpoint, struct fuse_chan* ch)
{
// nothing to do
}
struct fuse*
fuse_new(struct fuse_chan* ch, struct fuse_args* args,
const struct fuse_operations *op, size_t opSize, void *userData)
{
// parse args
fuse_config config;
memset(&config, 0, sizeof(config));
config.entry_timeout = 1.0;
config.attr_timeout = 1.0;
config.negative_timeout = 0.0;
config.intr_signal = SIGUSR1;
bool success = fuse_parse_lib_config_args(args, &config);
if (!success) {
PRINT(("fuse_new(): failed to parse arguments!\n"));
return NULL;
}
// run the main loop
status_t error = FUSEFileSystem::GetInstance()->FinishInitClientFS(&config,
op, opSize, userData);
return error == B_OK ? (struct fuse*)FUSEFileSystem::GetInstance() : NULL;
}
void
fuse_destroy(struct fuse* f)
{
// TODO: Implement!
}
int
fuse_loop(struct fuse* f)
{
status_t error = FUSEFileSystem::GetInstance()->MainLoop(false);
return error == B_OK ? 0 : -1;
}
int
fuse_loop_mt(struct fuse* f)
{
status_t error = FUSEFileSystem::GetInstance()->MainLoop(true);
return error == B_OK ? 0 : -1;
}
void
fuse_exit(struct fuse* f)
{
// TODO: Implement!
}
int
fuse_interrupted(void)
{
// TODO: ?
return false;
}
int
fuse_invalidate(struct fuse* f, const char* path)
{
return EINVAL;
}