diff --git a/CMakeLists.txt b/CMakeLists.txt index 966db70..c86e64f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,6 +20,8 @@ add_library(webfuse_static STATIC src/webfuse/fuse.cpp src/webfuse/request_type.cpp src/webfuse/response_type.cpp + src/webfuse/util/commandline_args.cpp + src/webfuse/util/commandline_reader.cpp src/webfuse/filesystem.cpp src/webfuse/filesystem/status.cpp src/webfuse/filesystem/accessmode.cpp diff --git a/src/webfuse/fuse.cpp b/src/webfuse/fuse.cpp index 02b9f47..f2432b0 100644 --- a/src/webfuse/fuse.cpp +++ b/src/webfuse/fuse.cpp @@ -288,4 +288,17 @@ int fuse::run(int argc, char * argv[]) return fuse_main(argc, argv, &operations, context); } +void fuse::print_usage() +{ + struct fuse_operations operations; + memset(reinterpret_cast(&operations), 0, sizeof(operations)); + + int const argc = 2; + char progname[] = "webfuse"; + char show_help[] = "--help"; + char * argv[] = { progname, show_help, nullptr}; + fuse_main(argc, argv, &operations, nullptr); +} + + } \ No newline at end of file diff --git a/src/webfuse/fuse.hpp b/src/webfuse/fuse.hpp index aa5bbbb..b0c1fc5 100644 --- a/src/webfuse/fuse.hpp +++ b/src/webfuse/fuse.hpp @@ -16,6 +16,7 @@ public: fuse (fuse && other); fuse& operator=(fuse && other); int run(int argc, char * argv[]); + static void print_usage(); private: class detail; detail * d; diff --git a/src/webfuse/util/commandline_args.cpp b/src/webfuse/util/commandline_args.cpp new file mode 100644 index 0000000..b97266d --- /dev/null +++ b/src/webfuse/util/commandline_args.cpp @@ -0,0 +1,56 @@ +#include "webfuse/util/commandline_args.hpp" +#include +#include + +namespace webfuse +{ + +commandline_args::commandline_args(char const * prog_name, int capacity) +: capacity_(capacity) +, argc(0) +{ + if (capacity < 1) + { + throw std::runtime_error("too few commandline args"); + } + + argv = new char*[capacity_ + 1]; + argv[0] = nullptr; + push(prog_name); +} + +commandline_args::~commandline_args() +{ + for(int i = 0; i < argc; i++) + { + free(argv[i]); + } + delete[] argv; +} + +void commandline_args::push(char const * arg) +{ + if (argc < capacity_) + { + argv[argc] = strdup(arg); + argv[argc + 1] = nullptr; + argc++; + } + else + { + throw std::runtime_error("capacity exceeded"); + } +} + +int commandline_args::get_argc() const +{ + return argc; +} + +char ** commandline_args::get_argv() +{ + return argv; +} + + +} \ No newline at end of file diff --git a/src/webfuse/util/commandline_args.hpp b/src/webfuse/util/commandline_args.hpp new file mode 100644 index 0000000..9c9b631 --- /dev/null +++ b/src/webfuse/util/commandline_args.hpp @@ -0,0 +1,29 @@ +#ifndef WEBFUSE_COMMANDLINE_ARGS_HPP +#define WEBFUSE_COMMANDLINE_ARGS_HPP + +namespace webfuse +{ + +class commandline_args +{ + commandline_args (commandline_args const &) = delete; + commandline_args& operator=(commandline_args const &) = delete; + commandline_args (commandline_args &&) = delete; + commandline_args& operator=(commandline_args &&) = delete; +public: + commandline_args(char const * prog_name, int capacity); + ~commandline_args(); + + void push(char const * arg); + int get_argc() const; + char ** get_argv(); + +private: + int capacity_; + int argc; + char ** argv; +}; + +} + +#endif diff --git a/src/webfuse/util/commandline_reader.cpp b/src/webfuse/util/commandline_reader.cpp new file mode 100644 index 0000000..e4b07a9 --- /dev/null +++ b/src/webfuse/util/commandline_reader.cpp @@ -0,0 +1,30 @@ +#include "webfuse/util/commandline_reader.hpp" +namespace webfuse +{ + +commandline_reader::commandline_reader(int argc, char * argv[]) +: current_(0) +, argc_(argc) +, argv_(argv) +{ + +} + +bool commandline_reader::next() +{ + if (current_ < argc_) + { + current_++; + } + + bool const has_next = (current_ < argc_); + return has_next; +} + +char const * commandline_reader::current() const +{ + return argv_[current_]; +} + + +} \ No newline at end of file diff --git a/src/webfuse/util/commandline_reader.hpp b/src/webfuse/util/commandline_reader.hpp new file mode 100644 index 0000000..252f869 --- /dev/null +++ b/src/webfuse/util/commandline_reader.hpp @@ -0,0 +1,22 @@ +#ifndef WEBFUSE_COMMANDLINE_READER_HPP +#define WEBFUSE_COMMANDLINE_READER_HPP + +namespace webfuse +{ + +class commandline_reader +{ +public: + commandline_reader(int argc, char * argv[]); + ~commandline_reader() = default; + bool next(); + char const * current() const; +private: + int current_; + int argc_; + char ** argv_; +}; + +} + +#endif diff --git a/src/webfuse/webfuse.cpp b/src/webfuse/webfuse.cpp index 3977692..a172d1e 100644 --- a/src/webfuse/webfuse.cpp +++ b/src/webfuse/webfuse.cpp @@ -3,17 +3,43 @@ #include "webfuse/filesystem.hpp" #include "webfuse/ws/server.hpp" +#include + namespace webfuse { int app::run(int argc, char * argv[]) // NOLINT(readability-convert-member-functions-to-static) { - ws_config config; - ws_server server(config); - filesystem filesystem(server); - fuse fuse_fs(filesystem); + ws_config config(argc, argv); - return fuse_fs.run(argc, argv); + switch (config.cmd) + { + case command::run: + { + ws_server server(config); + filesystem filesystem(server); + fuse fuse_fs(filesystem); + + config.exit_code = fuse_fs.run(config.args.get_argc(), config.args.get_argv()); + } + break; + case command::show_help: + // fall-through + default: + { + fuse::print_usage(); + std::cout << R"( +WEBFUSE options: + --wf-port PORT port number of websocket server (default: 8081) + --wf-vhost VHOST name of the virtual host (default: localhost) + --wf-cert PATH path of the server's public certificate (optional) + --wf-key PATH path of the server's private key (optional) +)"; + } + break; + } + + return config.exit_code; } } \ No newline at end of file diff --git a/src/webfuse/ws/config.cpp b/src/webfuse/ws/config.cpp index f7a68e1..61bf44a 100644 --- a/src/webfuse/ws/config.cpp +++ b/src/webfuse/ws/config.cpp @@ -1,19 +1,99 @@ #include "webfuse/ws/config.hpp" +#include "webfuse/util/commandline_reader.hpp" + +#include namespace { constexpr int const default_port = 8081; +constexpr char const default_vhost_name[] = "localhost"; + +void verify(webfuse::ws_config & config) +{ + if (config.cmd == webfuse::command::run) + { + if ((config.use_tls) && ((config.key_path.empty()) || (config.cert_path.empty()))) + { + std::cerr << "error: use of TLS requires both, key ander certificate path" << std::endl; + config.cmd = webfuse::command::show_help; + config.exit_code = EXIT_FAILURE; + } + } +} + +bool get_arg(webfuse::ws_config & config, webfuse::commandline_reader& reader, std::string & value, std::string const error_message) +{ + const bool has_next = reader.next(); + if (has_next) + { + value = reader.current(); + } + else + { + std::cerr << "error: " << error_message << std::endl; + config.cmd = webfuse::command::show_help; + config.exit_code = EXIT_FAILURE; + } + + return has_next; +} } namespace webfuse { -ws_config::ws_config() -: port(default_port) +ws_config::ws_config(int argc, char * argv[]) +: exit_code(EXIT_SUCCESS) +, args(argv[0], argc) +, cmd(command::run) +, port(default_port) +, vhost_name(default_vhost_name) +, use_tls(false) { + commandline_reader reader(argc, argv); + while ((exit_code == EXIT_SUCCESS) && (reader.next())) + { + std::string const arg = reader.current(); + if ((arg == "-h") || (arg == "--help")) + { + cmd = command::show_help; + } + else if (arg == "--wf-port") + { + std::string value; + if (get_arg(*this, reader, value, "missing PORT")) + { + port = static_cast(std::stoi(value)); + } + } + else if (arg == "--wf-vhost") + { + get_arg(*this, reader, vhost_name, "missing VHOST"); + } + else if (arg == "--wf-key") + { + if (get_arg(*this, reader, key_path, "missing KEY_PATH")) + { + use_tls = true; + } + } + else if (arg == "--wf-cert") + { + if (get_arg(*this, reader, cert_path, "missing CERT_PATH")) + { + use_tls = true; + } + } + else + { + args.push(arg.c_str()); + } + } + + verify(*this); } diff --git a/src/webfuse/ws/config.hpp b/src/webfuse/ws/config.hpp index 97c20e7..6f09ffb 100644 --- a/src/webfuse/ws/config.hpp +++ b/src/webfuse/ws/config.hpp @@ -1,17 +1,35 @@ #ifndef WEBFUSE_WS_CONFIG_HPP #define WEBFUSE_WS_CONFIG_HPP +#include + #include +#include namespace webfuse { +enum class command +{ + run, + show_help +}; + class ws_config { public: - ws_config(); + ws_config(int argc, char * argv[]); + + int exit_code; + commandline_args args; + command cmd; uint16_t port; + std::string vhost_name; + + bool use_tls; + std::string cert_path; + std::string key_path; }; }