From 861dbb4810c94214c9e00837e4a1704f8050e62e Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Wed, 8 Apr 2009 11:18:04 +0000 Subject: [PATCH] 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 --- .../userlandfs/server/fuse/FUSEFileSystem.cpp | 16 +- .../userlandfs/server/fuse/FUSEFileSystem.h | 1 + .../userlandfs/server/fuse/fuse_config.c | 168 +++++++++++++++++- .../userlandfs/server/fuse/fuse_config.h | 5 +- .../userlandfs/server/fuse/fuse_main.cpp | 145 +++++++++++++-- 5 files changed, 312 insertions(+), 23 deletions(-) diff --git a/src/add-ons/kernel/file_systems/userlandfs/server/fuse/FUSEFileSystem.cpp b/src/add-ons/kernel/file_systems/userlandfs/server/fuse/FUSEFileSystem.cpp index 87bbbd159e..2852a9c081 100644 --- a/src/add-ons/kernel/file_systems/userlandfs/server/fuse/FUSEFileSystem.cpp +++ b/src/add-ons/kernel/file_systems/userlandfs/server/fuse/FUSEFileSystem.cpp @@ -272,11 +272,19 @@ PRINT(("FUSEFileSystem::FinishInitClientFS()\n")); fFUSEConfig = *config; // 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 PRINT((" notifying mount thread\n")); - fInitStatus = error; delete_sem(fInitSemaphore); // loop until unmounting @@ -287,10 +295,10 @@ PRINT((" waiting for unmounting done\n")); fExitSemaphore = -1; - if (error == B_OK) + if (fFS != NULL) fuse_fs_destroy(fFS); - return error; + return fExitStatus; } diff --git a/src/add-ons/kernel/file_systems/userlandfs/server/fuse/FUSEFileSystem.h b/src/add-ons/kernel/file_systems/userlandfs/server/fuse/FUSEFileSystem.h index 1f6f6d729d..945f7ebba0 100644 --- a/src/add-ons/kernel/file_systems/userlandfs/server/fuse/FUSEFileSystem.h +++ b/src/add-ons/kernel/file_systems/userlandfs/server/fuse/FUSEFileSystem.h @@ -47,6 +47,7 @@ public: status_t FinishInitClientFS(fuse_config* config, const fuse_operations* ops, size_t opSize, void* userData); + status_t MainLoop(bool multithreaded); private: class ArgumentVector; diff --git a/src/add-ons/kernel/file_systems/userlandfs/server/fuse/fuse_config.c b/src/add-ons/kernel/file_systems/userlandfs/server/fuse/fuse_config.c index d14c391118..99e6d62068 100644 --- a/src/add-ons/kernel/file_systems/userlandfs/server/fuse/fuse_config.c +++ b/src/add-ons/kernel/file_systems/userlandfs/server/fuse/fuse_config.c @@ -10,7 +10,30 @@ enum { + KEY_KERN_FLAG, + KEY_KERN_OPT, + KEY_FUSERMOUNT_OPT, + KEY_SUBTYPE_OPT, + KEY_MTAB_OPT, + KEY_ALLOW_ROOT, + KEY_RO, 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 } @@ -46,6 +69,48 @@ static const struct fuse_opt fuse_lib_opts[] = { 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 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 -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; } @@ -73,3 +138,104 @@ fuse_is_lib_option(const char* opt) return /*fuse_lowlevel_is_lib_option(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; +} diff --git a/src/add-ons/kernel/file_systems/userlandfs/server/fuse/fuse_config.h b/src/add-ons/kernel/file_systems/userlandfs/server/fuse/fuse_config.h index 456a639ee9..66392f9f58 100644 --- a/src/add-ons/kernel/file_systems/userlandfs/server/fuse/fuse_config.h +++ b/src/add-ons/kernel/file_systems/userlandfs/server/fuse/fuse_config.h @@ -41,7 +41,10 @@ struct fuse_config { extern "C" { #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 } diff --git a/src/add-ons/kernel/file_systems/userlandfs/server/fuse/fuse_main.cpp b/src/add-ons/kernel/file_systems/userlandfs/server/fuse/fuse_main.cpp index 1ffbc40b41..7dc318d812 100644 --- a/src/add-ons/kernel/file_systems/userlandfs/server/fuse/fuse_main.cpp +++ b/src/add-ons/kernel/file_systems/userlandfs/server/fuse/fuse_main.cpp @@ -3,8 +3,12 @@ * Distributed under the terms of the MIT License. */ +#include #include #include +#include + +#include "Debug.h" #include "fuse_api.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, 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); - 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; + int result = 1; + + // create the kernel channel + struct fuse_chan* channel = fuse_mount("/dummy", &args); + if (channel != NULL) { + // 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); - if (!success) - return 1; - - // run the main loop - status_t error = FUSEFileSystem::GetInstance()->FinishInitClientFS(&config, - op, opSize, userData); - - - return error == B_OK ? 0 : 1; + return result; } @@ -60,3 +67,107 @@ fuse_get_context(void) ? (fuse_context*)requestThread->GetContext()->GetFSData() : 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; +}