From f73cd9b6cf770ece4f90651bffcaf37b0f77aed2 Mon Sep 17 00:00:00 2001 From: "Scott E. Graves" Date: Tue, 5 Aug 2025 14:28:39 -0500 Subject: [PATCH] macos fixes --- .cspell/words.txt | 1 + .../include/drives/fuse/fuse_base.hpp | 4 +- .../include/utils/unix/unix_utils.hpp | 9 ++++ .../src/drives/fuse/fuse_base.cpp | 53 +++++++++++++++++-- .../src/utils/unix/unix_utils.cpp | 43 +++++++++++++++ repertory/repertory/include/cli/mount.hpp | 12 +++-- repertory/repertory/include/cli/unmount.hpp | 2 +- 7 files changed, 115 insertions(+), 9 deletions(-) diff --git a/.cspell/words.txt b/.cspell/words.txt index 9c8a2b55..cf410302 100644 --- a/.cspell/words.txt +++ b/.cspell/words.txt @@ -177,6 +177,7 @@ nuspell_version oleaut32 openal_version openssldir +osascript osxfuse pistream pkgconfig diff --git a/repertory/librepertory/include/drives/fuse/fuse_base.hpp b/repertory/librepertory/include/drives/fuse/fuse_base.hpp index 3c12482e..dbe84ced 100644 --- a/repertory/librepertory/include/drives/fuse/fuse_base.hpp +++ b/repertory/librepertory/include/drives/fuse/fuse_base.hpp @@ -614,7 +614,9 @@ public: return mount_location_; } - [[nodiscard]] auto mount(std::vector args) -> int; + [[nodiscard]] auto mount(std::vector orig_args, + std::vector args, provider_type prov, + std::string_view unique_id) -> int; }; } // namespace repertory diff --git a/repertory/librepertory/include/utils/unix/unix_utils.hpp b/repertory/librepertory/include/utils/unix/unix_utils.hpp index a2cdf929..8fe82799 100644 --- a/repertory/librepertory/include/utils/unix/unix_utils.hpp +++ b/repertory/librepertory/include/utils/unix/unix_utils.hpp @@ -48,6 +48,15 @@ inline const std::array attribute_namespaces = { void windows_create_to_unix(const UINT32 &create_options, const UINT32 &granted_access, std::uint32_t &flags, remote::file_mode &mode); +#if defined(__APPLE__) +[[nodiscard]] auto +generate_launchd_plist(const std::string &label, std::string plist_path, + const std::vector &args, + const std::string &working_dir = "/tmp", + const std::string &stdout_log = "/tmp/stdout.log", + const std::string &stderr_log = "/tmp/stderr.log") + -> bool; +#endif // defined(__APPLE__) } // namespace repertory::utils #endif // !_WIN32 diff --git a/repertory/librepertory/src/drives/fuse/fuse_base.cpp b/repertory/librepertory/src/drives/fuse/fuse_base.cpp index 63be455c..d50a7aa2 100644 --- a/repertory/librepertory/src/drives/fuse/fuse_base.cpp +++ b/repertory/librepertory/src/drives/fuse/fuse_base.cpp @@ -19,6 +19,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#include #if !defined(_WIN32) #include "drives/fuse/fuse_base.hpp" @@ -396,14 +397,16 @@ auto fuse_base::mkdir_(const char *path, mode_t mode) -> int { }); } -auto fuse_base::mount(std::vector args) -> int { +auto fuse_base::mount(std::vector orig_args, + std::vector args, provider_type prov, + std::string_view unique_id) -> int { auto res = parse_args(args); if (res != 0) { return res; } if (not foreground_ && not utils::collection::includes(args, "-f")) { - args.emplace_back("-f"); + args.insert(std::next(args.begin()), "-f"); } std::vector fuse_argv(args.size()); @@ -422,7 +425,7 @@ auto fuse_base::mount(std::vector args) -> int { fuse_parse_cmdline(&f_args, &opts); mount_location = opts.mountpoint; #else // FUSE_USE_VERSION < 30 - fuse_parse_cmdline(&f_args, &mount_location, nullptr, nullptr); + auto res = fuse_parse_cmdline(&f_args, &mount_location, nullptr, nullptr); #endif // FUSE_USE_VERSION >= 30 if (mount_location != nullptr) { @@ -432,6 +435,49 @@ auto fuse_base::mount(std::vector args) -> int { } } +#if defined(__APPLE__) + if (not foreground_) { + if (not utils::file::change_to_process_directory()) { + std::cerr << "Failed to change to process directory" << std::endl; + return -1; + } + + orig_args[0U] = utils::path::combine(".", {"repertory"}); + orig_args.insert(std::next(orig_args.begin()), "-f"); + + auto label = std::format("com.fifthgrid.blockstorage.repertory.{}.{}", + provider_type_to_string(prov), unique_id); + if (not utils::generate_launchd_plist( + label, utils::path::combine("~", {"/Library/LaunchAgents"}), + orig_args, utils::path::absolute("."), + fmt::format("/tmp/repertory_{}_{}.out", + provider_type_to_string(prov), unique_id), + fmt::format("/tmp/repertory_{}_{}.err", + provider_type_to_string(prov), unique_id))) { + std::cerr << fmt::format("Failed to generate plist|{}", label) + << std::endl; + return -1; + } + + system(fmt::format("launchctl bootstrap gui/{} '{}' 1>/dev/null 2>&1", + getuid(), + utils::path::combine("~", + { + "/Library/LaunchAgents", + fmt::format("{}.plist", label), + })) + .c_str()); + res = system( + fmt::format("launchctl kickstart gui/{}/{}", getuid(), label).c_str()); + if (res != 0) { + std::cerr << fmt::format("Failed to kickstart {}/{}", getuid(), label) + << std::endl; + } + + return res; + } +#endif // defined(__APPLE__) + notify_fuse_args_parsed(args); const auto main_func = [&]() -> int { @@ -447,7 +493,6 @@ auto fuse_base::mount(std::vector args) -> int { return main_func(); } - repertory::project_cleanup(); return utils::create_daemon(main_func); } diff --git a/repertory/librepertory/src/utils/unix/unix_utils.cpp b/repertory/librepertory/src/utils/unix/unix_utils.cpp index 049aacef..cc7d2102 100644 --- a/repertory/librepertory/src/utils/unix/unix_utils.cpp +++ b/repertory/librepertory/src/utils/unix/unix_utils.cpp @@ -273,6 +273,49 @@ auto create_daemon(std::function main_func) -> int { return main_func(); } + +#if defined(__APPLE__) +auto generate_launchd_plist(const std::string &label, std::string plist_path, + const std::vector &args, + const std::string &working_dir, + const std::string &stdout_log, + const std::string &stderr_log) -> bool { + pugi::xml_document doc; + auto decl = doc.append_child(pugi::node_declaration); + decl.append_attribute("version") = "1.0"; + decl.append_attribute("encoding") = "UTF-8"; + + auto plist = doc.append_child("plist"); + plist.append_attribute("version") = "1.0"; + + auto dict = plist.append_child("dict"); + + dict.append_child("key").text().set("Label"); + dict.append_child("string").text().set(label.c_str()); + + dict.append_child("key").text().set("ProgramArguments"); + auto array = dict.append_child("array"); + for (const auto &arg : args) { + array.append_child("string").text().set(arg.c_str()); + } + + dict.append_child("key").text().set("WorkingDirectory"); + dict.append_child("string").text().set(working_dir.c_str()); + + dict.append_child("key").text().set("KeepAlive"); + dict.append_child("false"); + + dict.append_child("key").text().set("StandardOutPath"); + dict.append_child("string").text().set(stdout_log.c_str()); + + dict.append_child("key").text().set("StandardErrorPath"); + dict.append_child("string").text().set(stderr_log.c_str()); + + return doc.save_file( + utils::path::combine(plist_path, {label + ".plist"}).c_str(), " ", + pugi::format_indent | pugi::format_write_bom); +} +#endif // defined(__APPLE__) } // namespace repertory::utils #endif // !defined(_WIN32) diff --git a/repertory/repertory/include/cli/mount.hpp b/repertory/repertory/include/cli/mount.hpp index 9a865f12..f0276a6e 100644 --- a/repertory/repertory/include/cli/mount.hpp +++ b/repertory/repertory/include/cli/mount.hpp @@ -30,6 +30,12 @@ namespace repertory::cli::actions { mount(std::vector args, std::string data_directory, int &mount_result, provider_type prov, const std::string &remote_host, std::uint16_t remote_port, const std::string &unique_id) -> exit_code { + std::vector orig_args; + args.reserve(args.size()); + for (const auto *arg : args) { + orig_args.emplace_back(arg); + } + lock_data global_lock(provider_type::unknown, "global"); { auto lock_result = global_lock.grab_lock(100U); @@ -129,7 +135,7 @@ mount(std::vector args, std::string data_directory, constexpr const std::uint8_t retry_count{30U}; std::cout << "Connecting to remote [" << remote_host << ':' << remote_port - << "] ..." << std::flush; + << "]..." << std::flush; auto online{false}; for (std::uint8_t retry{0U}; not online && retry < retry_count; ++retry) { online = remote_client(config).check() == 0; @@ -158,7 +164,7 @@ mount(std::vector args, std::string data_directory, } global_lock.release(); - mount_result = drive.mount(drive_args); + mount_result = drive.mount(orig_args, drive_args, prov, unique_id); return exit_code::mount_result; } catch (const std::exception &e) { std::cerr << "FATAL: " << e.what() << std::endl; @@ -180,7 +186,7 @@ mount(std::vector args, std::string data_directory, } global_lock.release(); - mount_result = drive.mount(drive_args); + mount_result = drive.mount(orig_args, drive_args, prov, unique_id); return exit_code::mount_result; } catch (const std::exception &e) { std::cerr << "FATAL: " << e.what() << std::endl; diff --git a/repertory/repertory/include/cli/unmount.hpp b/repertory/repertory/include/cli/unmount.hpp index 10dc3c96..384d1d28 100644 --- a/repertory/repertory/include/cli/unmount.hpp +++ b/repertory/repertory/include/cli/unmount.hpp @@ -42,7 +42,7 @@ unmount(std::vector /* args */, const std::string &data_directory, .unmount(); if (response.response_type == rpc_response_type::success) { auto orig_response{response}; - std::cout << "waiting for unmount ..." << std::flush; + std::cout << "Waiting for unmount..." << std::flush; for (std::uint8_t retry{0U}; retry < retry_count && response.response_type == rpc_response_type::success;