From 53883d5bf4f0b34f9dfe2d793d94902e0fd64a21 Mon Sep 17 00:00:00 2001 From: ComixHe Date: Wed, 6 Aug 2025 11:45:13 +0800 Subject: [PATCH 01/26] improve: add system error details to file operation error handling Replace std::runtime_error with std::system_error for better debugging. Signed-off-by: ComixHe --- src/linyaps_box/container.cpp | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/linyaps_box/container.cpp b/src/linyaps_box/container.cpp index c7162ed..a0025fc 100644 --- a/src/linyaps_box/container.cpp +++ b/src/linyaps_box/container.cpp @@ -282,10 +282,17 @@ void initialize_container(const linyaps_box::config &config, std::ofstream ofs("/proc/self/oom_score_adj"); if (!ofs) { - throw std::runtime_error("failed to open /proc/self/oom_score_adj"); + throw std::system_error(errno, + std::generic_category(), + "failed to open /proc/self/oom_score_adj"); } ofs << score; + if (!ofs) { + throw std::system_error(errno, + std::generic_category(), + "failed to write to /proc/self/oom_score_adj"); + } } } @@ -1584,12 +1591,16 @@ void processing_extensions(const linyaps_box::container &container) std::ofstream ofs("/proc/sys/kernel/ns_last_pid"); if (!ofs) { - throw std::runtime_error("failed to open /proc/sys/kernel/ns_last_pid"); + throw std::system_error(errno, + std::generic_category(), + "failed to open /proc/sys/kernel/ns_last_pid"); } ofs << it->second; if (!ofs) { - throw std::runtime_error("failed to write to /proc/sys/kernel/ns_last_pid"); + throw std::system_error(errno, + std::generic_category(), + "failed to write to /proc/sys/kernel/ns_last_pid"); } LINYAPS_BOX_DEBUG() << "Successfully set ns_last_pid to " << it->second; From 61d1b26eaecc3745b2d5f1d70b6dfd9b29e3c28a Mon Sep 17 00:00:00 2001 From: ComixHe Date: Wed, 6 Aug 2025 11:49:26 +0800 Subject: [PATCH 02/26] feat: add ns_last_pid extension test and enhance test framework - Add comprehensive test for ns_last_pid extension - Improve test script JSON merging capabilities - Update existing tests and CMake configuration Signed-off-by: ComixHe --- CMakeLists.txt | 6 +++--- tests/ll-box-st/12-bind-host-dev.json | 2 +- tests/ll-box-st/13-pid-extension.json | 29 +++++++++++++++++++++++++++ tests/ll-box-st/ll-box-st | 27 +++++++++++++++---------- 4 files changed, 49 insertions(+), 15 deletions(-) create mode 100644 tests/ll-box-st/13-pid-extension.json diff --git a/CMakeLists.txt b/CMakeLists.txt index 8f5d939..3fee416 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -195,8 +195,7 @@ if(NOT linyaps-box_MAKE_RELEASE) COMMAND git rev-parse --short=7 HEAD WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} OUTPUT_VARIABLE GIT_COMMIT_HASH - OUTPUT_STRIP_TRAILING_WHITESPACE - ) + OUTPUT_STRIP_TRAILING_WHITESPACE) set(LINYAPS_BOX_VERSION "${LINYAPS_BOX_VERSION}-dev-${GIT_COMMIT_HASH}") endif() @@ -438,7 +437,8 @@ function(setup_linyaps_box_smoke_tests) ./tests/ll-box-st/09-check-rlimit.json ./tests/ll-box-st/10-check-oom.json ./tests/ll-box-st/11-output-to-null.json - ./tests/ll-box-st/12-bind-host-dev.json) + ./tests/ll-box-st/12-bind-host-dev.json + ./tests/ll-box-st/13-pid-extension.json) foreach(test ${linyaps-box_SMOKE_TESTS}) add_test( diff --git a/tests/ll-box-st/12-bind-host-dev.json b/tests/ll-box-st/12-bind-host-dev.json index d9662c7..f0463b8 100644 --- a/tests/ll-box-st/12-bind-host-dev.json +++ b/tests/ll-box-st/12-bind-host-dev.json @@ -5,7 +5,7 @@ "uid": 0, "gid": 0 }, - "args": ["/bin/env", "bash", "-c", "pwd"], + "args": ["true"], "env": [ "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "TERM=xterm", diff --git a/tests/ll-box-st/13-pid-extension.json b/tests/ll-box-st/13-pid-extension.json new file mode 100644 index 0000000..f0ea486 --- /dev/null +++ b/tests/ll-box-st/13-pid-extension.json @@ -0,0 +1,29 @@ +{ + "name": "Set ns_last_pid", + "process": { + "user": { + "uid": 0, + "gid": 0 + }, + "args": ["/bin/env", "bash", "-c", "cat /proc/sys/kernel/ns_last_pid"], + "env": [ + "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", + "TERM=xterm", + "HOME=/root" + ], + "cwd": "/" + }, + "annotations": { + "cn.org.linyaps.runtime.ns_last_pid": "100" + }, + "linux": { + "readonlyPaths": [ + "/proc/asound", + "/proc/bus", + "/proc/fs", + "/proc/irq", + "/proc/sysrq-trigger" + ] + }, + "expected": "100" +} diff --git a/tests/ll-box-st/ll-box-st b/tests/ll-box-st/ll-box-st index cc1b944..6f2a8cd 100755 --- a/tests/ll-box-st/ll-box-st +++ b/tests/ll-box-st/ll-box-st @@ -175,17 +175,22 @@ function run_test() { mkdir -p -- "${TEST_DIR}" local TEST_CONFIG="${TEST_DIR}/test_config.json" - # patch process from test file - "${JQ}" >"${TEST_CONFIG}" \ - ".process |= $("${JQ}" -r '.process' "${TEST_FILE}" || true)" \ - "${BUNDLE_DIR}/config.json" - - # patch mount from test file if test file has mount field - if "${JQ}" -e '.mounts' "${TEST_FILE}" &>/dev/null; then - "${JQ}" >"${TEST_CONFIG}" \ - ".mounts |= $("${JQ}" -r '.mounts' "${TEST_FILE}" || true)" \ - "${BUNDLE_DIR}/config.json" - fi + + # Create a copy of the original config and apply all patches at once + "${JQ}" -s ' + .[0] as $base | + .[1] as $patch | + $base * { + process: ($patch.process // $base.process), + mounts: ($patch.mounts // $base.mounts), + annotations: ($patch.annotations // $base.annotations), + linux: (if $patch.linux then + $base.linux * $patch.linux + else + $base.linux + end) + } + ' "${BUNDLE_DIR}/config.json" "${TEST_FILE}" > "${TEST_CONFIG}" local CONTAINER_NAME CONTAINER_NAME="$(basename -- "${TEST_FILE_NAME}" .json)" From 2a8c21b68117069c6802bd48f0d9f01171fd9c1c Mon Sep 17 00:00:00 2001 From: taotieren Date: Tue, 19 Aug 2025 10:08:59 +0800 Subject: [PATCH 03/26] docs: Update linyaps-box documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. Update linyaps-box package status docs: 更新 linyaps-box文档 1. 更新 linyaps-box 软件包状态 --- README.md | 2 ++ README.zh_CN.md | 2 ++ 2 files changed, 4 insertions(+) diff --git a/README.md b/README.md index 3c2c888..f6fb96b 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,8 @@ \[ **en** | [zh_CN](./README.zh_CN.md) \] +[![Packaging status](https://repology.org/badge/vertical-allrepos/linyaps-box.svg)](https://repology.org/project/linyaps-box/versions) + This project is a simple [OCI runtime] mainly used by [linyaps], which is a toolkit for Linux desktop application distributing. diff --git a/README.zh_CN.md b/README.zh_CN.md index 6378383..8bcbc23 100644 --- a/README.zh_CN.md +++ b/README.zh_CN.md @@ -2,6 +2,8 @@ \[ [en](./README.md) | **zh_CN** \] +[![Packaging status](https://repology.org/badge/vertical-allrepos/linyaps-box.svg)](https://repology.org/project/linyaps-box/versions) + 这个项目是一个简单的[OCI运行时],主要由[玲珑]使用, 玲珑是一个用于Linux桌面应用程序分发的工具包。 From 2b51656a6e14911ccabd3407981d3238b3ed154f Mon Sep 17 00:00:00 2001 From: ComixHe Date: Fri, 22 Aug 2025 16:55:17 +0800 Subject: [PATCH 04/26] chore: suppress compiler warning If the log level is higher than debug level the dump_mount_flags function will not be called. Signed-off-by: ComixHe --- src/linyaps_box/container.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/linyaps_box/container.cpp b/src/linyaps_box/container.cpp index a0025fc..1193399 100644 --- a/src/linyaps_box/container.cpp +++ b/src/linyaps_box/container.cpp @@ -152,7 +152,7 @@ constexpr std::array mount_flags{ MountFlag{ MS_RDONLY, "MS_RDONL { MS_ACTIVE, "MS_ACTIVE" }, { MS_NOUSER, "MS_NOUSER" } }; -std::string dump_mount_flags(uint flags) noexcept +[[maybe_unused]] std::string dump_mount_flags(uint flags) noexcept { std::stringstream ss; ss << "[ "; From e62d7d53e4b59a58314a4d22de2ce0866c39acc4 Mon Sep 17 00:00:00 2001 From: ComixHe Date: Mon, 25 Aug 2025 10:35:25 +0800 Subject: [PATCH 05/26] fix: early return if an exception is thrown while command parsing According the documentation of CLI11, this library will throw a exception while encounter -h,--help or a parse error. Signed-off-by: ComixHe --- src/linyaps_box/command/options.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/linyaps_box/command/options.cpp b/src/linyaps_box/command/options.cpp index cb37d1b..bf0f2e4 100644 --- a/src/linyaps_box/command/options.cpp +++ b/src/linyaps_box/command/options.cpp @@ -111,6 +111,7 @@ linyaps_box::command::options linyaps_box::command::parse(int argc, char *argv[] app.parse(argc, argv); } catch (const CLI::ParseError &e) { options.global.return_code = app.exit(e); + return options; } if (cmd_list->parsed()) { From 08c47fff3cc9efed6613e5f8840e60843d68a139 Mon Sep 17 00:00:00 2001 From: ComixHe Date: Tue, 26 Aug 2025 14:42:24 +0800 Subject: [PATCH 06/26] refactor: resolving the most of compiler warnings Signed-off-by: ComixHe --- CMakeLists.txt | 2 +- src/linyaps_box/app.cpp | 29 +++++---- src/linyaps_box/app.h | 2 +- src/linyaps_box/cgroup.h | 31 +++++---- .../{cgroup_manager.c => cgroup_manager.cpp} | 8 ++- src/linyaps_box/cgroup_manager.h | 16 +++-- src/linyaps_box/command/exec.cpp | 2 +- src/linyaps_box/command/kill.cpp | 2 +- src/linyaps_box/command/list.cpp | 2 +- src/linyaps_box/command/options.h | 21 +++---- src/linyaps_box/command/run.cpp | 6 +- src/linyaps_box/command/run.h | 2 +- src/linyaps_box/config.cpp | 22 ++++--- src/linyaps_box/config.h | 2 +- src/linyaps_box/container.cpp | 63 +++++++++++-------- src/linyaps_box/container.h | 15 +++-- src/linyaps_box/container_ref.cpp | 8 ++- src/linyaps_box/container_ref.h | 15 +++-- src/linyaps_box/container_status.cpp | 10 +-- src/linyaps_box/container_status.h | 6 +- .../impl/disabled_cgroup_manager.cpp | 7 ++- .../impl/disabled_cgroup_manager.h | 4 +- src/linyaps_box/impl/status_directory.cpp | 26 ++++---- src/linyaps_box/impl/status_directory.h | 6 +- src/linyaps_box/impl/table_printer.cpp | 10 +-- src/linyaps_box/interface.cpp | 7 +++ src/linyaps_box/interface.h | 6 +- src/linyaps_box/printer.cpp | 6 ++ src/linyaps_box/printer.h | 10 +++ src/linyaps_box/runtime.cpp | 19 +++--- src/linyaps_box/runtime.h | 6 +- src/linyaps_box/status_directory.cpp | 4 ++ src/linyaps_box/status_directory.h | 14 ++++- src/linyaps_box/utils/cgroups.cpp | 2 +- src/linyaps_box/utils/cgroups.h | 4 +- src/linyaps_box/utils/close_range.cpp | 10 +-- src/linyaps_box/utils/defer.h | 19 +++--- src/linyaps_box/utils/file_describer.cpp | 51 ++++++++------- src/linyaps_box/utils/file_describer.h | 27 +++++--- src/linyaps_box/utils/fstat.cpp | 45 +++++++++++++ src/linyaps_box/utils/fstat.h | 41 ++---------- src/linyaps_box/utils/inspect.cpp | 14 ++--- src/linyaps_box/utils/inspect.h | 10 +-- src/linyaps_box/utils/log.cpp | 36 +++++++---- src/linyaps_box/utils/log.h | 16 ++--- src/linyaps_box/utils/mkdir.cpp | 5 +- src/linyaps_box/utils/mkdir.h | 3 +- src/linyaps_box/utils/open_file.cpp | 44 +++++++------ src/linyaps_box/utils/open_file.h | 11 ++-- src/linyaps_box/utils/platform.cpp | 8 +-- src/linyaps_box/utils/platform.h | 4 +- src/linyaps_box/utils/semver.cpp | 18 +++++- src/linyaps_box/utils/semver.h | 16 ++--- src/linyaps_box/utils/socketpair.cpp | 20 ++++++ src/linyaps_box/utils/socketpair.h | 16 +---- src/linyaps_box/utils/touch.cpp | 4 +- src/linyaps_box/utils/touch.h | 2 +- 57 files changed, 473 insertions(+), 342 deletions(-) rename src/linyaps_box/{cgroup_manager.c => cgroup_manager.cpp} (62%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3fee416..b350de5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -118,7 +118,7 @@ set(linyaps-box_LIBRARY_SOURCE src/linyaps_box/app.cpp src/linyaps_box/app.h src/linyaps_box/cgroup.h - src/linyaps_box/cgroup_manager.c + src/linyaps_box/cgroup_manager.cpp src/linyaps_box/cgroup_manager.h src/linyaps_box/command/exec.cpp src/linyaps_box/command/exec.h diff --git a/src/linyaps_box/app.cpp b/src/linyaps_box/app.cpp index 9fa08f5..77a445e 100644 --- a/src/linyaps_box/app.cpp +++ b/src/linyaps_box/app.cpp @@ -9,8 +9,7 @@ #include "linyaps_box/command/list.h" #include "linyaps_box/command/run.h" #include "linyaps_box/utils/log.h" - -#include +#include "utils/log.h" namespace { @@ -32,19 +31,19 @@ namespace linyaps_box { // Command line arguments are parsed according to // https://github.com/opencontainers/runtime-tools/blob/v0.9.0/docs/command-line-interface.md // Extended commands and options should be compatible with crun. -int main(int argc, char **argv) noexcept +auto main(int argc, char **argv) noexcept -> int try { LINYAPS_BOX_DEBUG() << "linyaps box called with" << [=]() -> std::string { std::stringstream result; for (int i = 0; i < argc; ++i) { result << " \""; - for (const char *c = argv[i]; *c != '\0'; ++c) { - if (*c == '\\') { + for (const auto ch : std::string_view(argv[i])) { // NOLINT + if (ch == '\\') { result << "\\\\"; - } else if (*c == '"') { + } else if (ch == '"') { result << "\\\""; } else { - result << *c; + result << ch; } } result << "\""; @@ -52,18 +51,18 @@ try { return result.str(); }(); - command::options options = command::parse(argc, argv); - if (options.global.return_code != 0) { - return options.global.return_code; + auto opts = command::parse(argc, argv); + if (opts.global.return_code != 0) { + return opts.global.return_code; } return std::visit(subCommand{ [](const command::list_options &options) { command::list(options); return 0; }, - [](const command::exec_options &options) { + [](const command::exec_options &options) -> int { command::exec(options); - return 0; + __builtin_unreachable(); }, [](const command::kill_options &options) { command::kill(options); @@ -72,10 +71,10 @@ try { [](const command::run_options &options) { return command::run(options); }, - [code = options.global.return_code](const std::monostate &) { - return code; + [](const std::monostate &) { + return 0; } }, - options.subcommand_opt); + opts.subcommand_opt); } catch (const std::exception &e) { LINYAPS_BOX_ERR() << "Error: " << e.what(); return -1; diff --git a/src/linyaps_box/app.h b/src/linyaps_box/app.h index 455428d..a813c7a 100644 --- a/src/linyaps_box/app.h +++ b/src/linyaps_box/app.h @@ -6,6 +6,6 @@ namespace linyaps_box { -int main(int argc, char **argv) noexcept; +auto main(int argc, char **argv) noexcept -> int; } // namespace linyaps_box diff --git a/src/linyaps_box/cgroup.h b/src/linyaps_box/cgroup.h index d0783db..fdc7cad 100644 --- a/src/linyaps_box/cgroup.h +++ b/src/linyaps_box/cgroup.h @@ -10,47 +10,52 @@ namespace linyaps_box { -enum class cgroup_manager_t : std::uint16_t { disabled, systemd, cgroupfs }; +enum class cgroup_manager_t : std::uint8_t { disabled, systemd, cgroupfs }; struct cgroup_options { std::unordered_map annotations; std::filesystem::path cgroup_path; - std::string id; std::filesystem::path state_root; + std::string id; pid_t pid; // resources and so on... }; struct cgroup_status { - std::filesystem::path path; - std::string scope; +public: + [[nodiscard]] auto path() const noexcept -> std::filesystem::path { return path_; } - [[nodiscard]] cgroup_manager_t manager_type() const noexcept { return manager; } + [[nodiscard]] auto scope() const noexcept -> std::string_view { return scope_; } + + [[nodiscard]] auto manager() const noexcept -> cgroup_manager_t { return manager_; } private: friend class cgroup_manager; - cgroup_manager_t manager; + std::filesystem::path path_; + std::string scope_; + cgroup_manager_t manager_; }; -inline std::ostream &operator<<(std::ostream &os, cgroup_manager_t manager) +inline auto operator<<(std::ostream &stream, cgroup_manager_t manager) -> std::ostream & { switch (manager) { case cgroup_manager_t::disabled: { - os << "disabled"; + stream << "disabled"; } break; case cgroup_manager_t::systemd: { - os << "systemd"; + stream << "systemd"; } break; case cgroup_manager_t::cgroupfs: { - os << "cgroupfs"; + stream << "cgroupfs"; + } break; + default: { + stream << "unknown"; } break; - default: - os << "unknown"; } - return os; + return stream; } } // namespace linyaps_box diff --git a/src/linyaps_box/cgroup_manager.c b/src/linyaps_box/cgroup_manager.cpp similarity index 62% rename from src/linyaps_box/cgroup_manager.c rename to src/linyaps_box/cgroup_manager.cpp index 66432c5..2dec2f6 100644 --- a/src/linyaps_box/cgroup_manager.c +++ b/src/linyaps_box/cgroup_manager.cpp @@ -2,6 +2,10 @@ // // SPDX-License-Identifier: LGPL-3.0-or-later -#pragma once - #include + +namespace linyaps_box { + +cgroup_manager::~cgroup_manager() = default; + +} // namespace linyaps_box diff --git a/src/linyaps_box/cgroup_manager.h b/src/linyaps_box/cgroup_manager.h index f7dde88..8bf1b52 100644 --- a/src/linyaps_box/cgroup_manager.h +++ b/src/linyaps_box/cgroup_manager.h @@ -13,9 +13,17 @@ namespace linyaps_box { class cgroup_manager : public virtual interface { public: - [[nodiscard]] virtual cgroup_manager_t type() const = 0; + cgroup_manager() = default; + ~cgroup_manager() override; - virtual cgroup_status create_cgroup(const cgroup_options &options) = 0; + cgroup_manager(const cgroup_manager &) = delete; + auto operator=(const cgroup_manager &) -> cgroup_manager & = delete; + cgroup_manager(cgroup_manager &&) = delete; + auto operator=(cgroup_manager &&) -> cgroup_manager & = delete; + + [[nodiscard]] virtual auto type() const -> cgroup_manager_t = 0; + + virtual auto create_cgroup(const cgroup_options &options) -> cgroup_status = 0; virtual void precreate_cgroup(const cgroup_options &options, utils::file_descriptor &dirfd) = 0; @@ -24,9 +32,9 @@ class cgroup_manager : public virtual interface // TODO: support update resource // virtual void update_resource(const cgroup_status &status, ) = 0; protected: - static void set_manager_type(cgroup_status &status, cgroup_manager_t type) noexcept + static void set_manager(cgroup_status &status, cgroup_manager_t type) noexcept { - status.manager = type; + status.manager_ = type; } }; diff --git a/src/linyaps_box/command/exec.cpp b/src/linyaps_box/command/exec.cpp index 71683c0..0ffd442 100644 --- a/src/linyaps_box/command/exec.cpp +++ b/src/linyaps_box/command/exec.cpp @@ -11,7 +11,7 @@ void linyaps_box::command::exec(const struct exec_options &options) { std::unique_ptr dir = - std::make_unique(options.global.get().root); + std::make_unique(options.global_.get().root); runtime_t runtime(std::move(dir)); auto container_refs = runtime.containers(); diff --git a/src/linyaps_box/command/kill.cpp b/src/linyaps_box/command/kill.cpp index 09527db..d716bc7 100644 --- a/src/linyaps_box/command/kill.cpp +++ b/src/linyaps_box/command/kill.cpp @@ -28,7 +28,7 @@ void linyaps_box::command::kill(const struct kill_options &options) break; } - auto status_dir = std::make_unique(options.global.get().root); + auto status_dir = std::make_unique(options.global_.get().root); if (!status_dir) { throw std::runtime_error("failed to create status directory"); } diff --git a/src/linyaps_box/command/list.cpp b/src/linyaps_box/command/list.cpp index 65f5b0b..a5aeb79 100644 --- a/src/linyaps_box/command/list.cpp +++ b/src/linyaps_box/command/list.cpp @@ -13,7 +13,7 @@ void linyaps_box::command::list(const struct list_options &options) { - auto status_dir = std::make_unique(options.global.get().root); + auto status_dir = std::make_unique(options.global_.get().root); if (!status_dir) { throw std::runtime_error("failed to create status directory"); } diff --git a/src/linyaps_box/command/options.h b/src/linyaps_box/command/options.h index b5b6c5d..6594c85 100644 --- a/src/linyaps_box/command/options.h +++ b/src/linyaps_box/command/options.h @@ -22,30 +22,27 @@ struct global_options struct list_options { - // FIXME: if the underlying type of enum class is std::uint8_t, - // the mapping message of CLI11 transformer is incorrect - // use std::uint16_t for now - enum class output_format_t : std::uint16_t { table, json }; + enum class output_format_t : std::uint8_t { table, json }; explicit list_options(global_options &global) - : global(global) + : global_(global) { } output_format_t output_format{ output_format_t::table }; - std::reference_wrapper global; + std::reference_wrapper global_; }; struct exec_options { explicit exec_options(global_options &global) : no_new_privs(false) - , global(global) + , global_(global) { } bool no_new_privs; - std::reference_wrapper global; + std::reference_wrapper global_; std::vector command; std::string user; std::optional> caps; @@ -57,11 +54,11 @@ struct exec_options struct run_options { explicit run_options(global_options &global) - : global(global) + : global_(global) { } - std::reference_wrapper global; + std::reference_wrapper global_; std::string ID; std::string bundle; std::string config; @@ -70,11 +67,11 @@ struct run_options struct kill_options { explicit kill_options(global_options &global) - : global(global) + : global_(global) { } - std::reference_wrapper global; + std::reference_wrapper global_; std::string container; std::string signal; }; diff --git a/src/linyaps_box/command/run.cpp b/src/linyaps_box/command/run.cpp index 3c10804..932686e 100644 --- a/src/linyaps_box/command/run.cpp +++ b/src/linyaps_box/command/run.cpp @@ -8,16 +8,16 @@ #include "linyaps_box/runtime.h" #include "linyaps_box/status_directory.h" -int linyaps_box::command::run(const struct run_options &options) +auto linyaps_box::command::run(const struct run_options &options) -> int { std::unique_ptr dir = - std::make_unique(options.global.get().root); + std::make_unique(options.global_.get().root); runtime_t runtime(std::move(dir)); runtime_t::create_container_options_t create_container_options; create_container_options.bundle = options.bundle; create_container_options.config = options.config; create_container_options.ID = options.ID; - create_container_options.manager = options.global.get().manager; + create_container_options.manager = options.global_.get().manager; auto container = runtime.create_container(create_container_options); diff --git a/src/linyaps_box/command/run.h b/src/linyaps_box/command/run.h index e42c0a0..d5f23ea 100644 --- a/src/linyaps_box/command/run.h +++ b/src/linyaps_box/command/run.h @@ -8,6 +8,6 @@ namespace linyaps_box::command { -[[nodiscard]] int run(const run_options &options); +[[nodiscard]] auto run(const run_options &options) -> int; } // namespace linyaps_box::command diff --git a/src/linyaps_box/config.cpp b/src/linyaps_box/config.cpp index dbb0190..273e88b 100644 --- a/src/linyaps_box/config.cpp +++ b/src/linyaps_box/config.cpp @@ -11,17 +11,19 @@ namespace { -std::tuple -parse_mount_options(const std::vector &options) +// This function is used to parse the mount options from the config file and it only will be called +// once. +auto parse_mount_options(const std::vector &options) + -> std::tuple { - const static std::unordered_map propagation_flags_map{ + const std::unordered_map propagation_flags_map{ { "rprivate", MS_PRIVATE | MS_REC }, { "private", MS_PRIVATE }, { "rslave", MS_SLAVE | MS_REC }, { "slave", MS_SLAVE }, { "rshared", MS_SHARED | MS_REC }, { "shared", MS_SHARED }, { "runbindable", MS_UNBINDABLE | MS_REC }, { "unbindable", MS_UNBINDABLE }, }; - const static std::unordered_map flags_map{ + const std::unordered_map flags_map{ { "bind", MS_BIND }, { "defaults", 0 }, { "dirsync", MS_DIRSYNC }, @@ -43,7 +45,7 @@ parse_mount_options(const std::vector &options) { "sync", MS_SYNCHRONOUS }, }; - const static std::unordered_map unset_flags_map{ + const std::unordered_map unset_flags_map{ { "async", MS_SYNCHRONOUS }, { "atime", MS_NOATIME }, { "dev", MS_NODEV }, @@ -60,7 +62,7 @@ parse_mount_options(const std::vector &options) { "symfollow", LINGYAPS_MS_NOSYMFOLLOW }, }; - const static std::unordered_map extra_flags_map{ + const std::unordered_map extra_flags_map{ { "copy-symlink", linyaps_box::config::mount_t::COPY_SYMLINK } }; @@ -162,8 +164,8 @@ linyaps_box::config::process_t::rlimits_t parse_rlimits(const nlohmann::json &ob return ret; } -linyaps_box::config::linux_t parse_linux(const nlohmann::json &obj, - const nlohmann::json::json_pointer &ptr) +auto parse_linux(const nlohmann::json &obj, const nlohmann::json::json_pointer &ptr) + -> linyaps_box::config::linux_t { auto linux = linyaps_box::config::linux_t{}; if (auto uid_ptr = ptr / "uidMappings"; obj.contains(uid_ptr)) { @@ -280,9 +282,9 @@ linyaps_box::config::linux_t parse_linux(const nlohmann::json &obj, return linux; } -linyaps_box::config parse_1_2_0(const nlohmann::json &j) +auto parse_1_2_0(const nlohmann::json &j) -> linyaps_box::config { - static const auto ptr = ""_json_pointer; + const auto ptr = ""_json_pointer; auto semver = linyaps_box::utils::semver(j[ptr / "ociVersion"].get()); if (!linyaps_box::utils::semver(linyaps_box::config::oci_version).is_compatible_with(semver)) { diff --git a/src/linyaps_box/config.h b/src/linyaps_box/config.h index 3d57b96..00c62f5 100644 --- a/src/linyaps_box/config.h +++ b/src/linyaps_box/config.h @@ -31,7 +31,7 @@ struct config { static constexpr auto oci_version = "1.2.0"; - static config parse(std::istream &is); + static auto parse(std::istream &is) -> config; struct process_t { diff --git a/src/linyaps_box/container.cpp b/src/linyaps_box/container.cpp index 1193399..92cdc2f 100644 --- a/src/linyaps_box/container.cpp +++ b/src/linyaps_box/container.cpp @@ -112,7 +112,7 @@ std::ostream &operator<<(std::ostream &os, const sync_message message) } break; default: { assert(false); - os << "UNKNOWN " << (uint8_t)message; + os << "UNKNOWN " << static_cast(message); } break; } return os; @@ -152,7 +152,7 @@ constexpr std::array mount_flags{ MountFlag{ MS_RDONLY, "MS_RDONL { MS_ACTIVE, "MS_ACTIVE" }, { MS_NOUSER, "MS_NOUSER" } }; -[[maybe_unused]] std::string dump_mount_flags(uint flags) noexcept +[[maybe_unused]] auto dump_mount_flags(unsigned long flags) noexcept -> std::string { std::stringstream ss; ss << "[ "; @@ -374,7 +374,9 @@ void do_remount(const remount_t &mount) } auto state = linyaps_box::utils::statfs(mount.destination_fd); - auto remount_flags = state.f_flags & (MS_NOSUID | MS_NODEV | MS_NOEXEC); + const auto dest_flag = static_cast(state.f_flags); + + auto remount_flags = dest_flag & (MS_NOSUID | MS_NODEV | MS_NOEXEC); if ((remount_flags | mount.flags) != mount.flags) { try { syscall_mount(nullptr, @@ -391,8 +393,8 @@ void do_remount(const remount_t &mount) } } - if ((state.f_flags & MS_RDONLY) != 0) { - remount_flags = state.f_flags & (MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_RDONLY); + if ((dest_flag & MS_RDONLY) != 0) { + remount_flags = dest_flag & (MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_RDONLY); syscall_mount(nullptr, destination.c_str(), nullptr, mount.flags | remount_flags, data_ptr); } } @@ -530,7 +532,7 @@ void do_propagation_mount(const linyaps_box::utils::file_descriptor &destination nullptr, bind_flags, nullptr); - } catch (const std::system_error &e) { + } catch ([[maybe_unused]] const std::system_error &e) { // mounting sysfs with rootless/userns container will fail with EPERM // TODO: try to bind mount /sys throw; @@ -539,9 +541,9 @@ void do_propagation_mount(const linyaps_box::utils::file_descriptor &destination return linyaps_box::utils::open_at(root, mount.destination.value(), open_flag); } -void do_cgroup_mount([[maybe_unused]] const linyaps_box::utils::file_descriptor &root, - [[maybe_unused]] const linyaps_box::config::mount_t &mount, - [[maybe_unused]] std::string_view unified_cgroup_path) +[[noreturn]] void do_cgroup_mount([[maybe_unused]] const linyaps_box::utils::file_descriptor &root, + [[maybe_unused]] const linyaps_box::config::mount_t &mount, + [[maybe_unused]] std::string_view unified_cgroup_path) { // TODO: implement throw std::runtime_error("mount cgroup: Not implemented"); @@ -658,7 +660,7 @@ class mounter try { do_propagation_mount(rootfsfd, MS_PRIVATE); return; - } catch (const std::system_error &e) { + } catch ([[maybe_unused]] const std::system_error &e) { auto parent_fd = ::openat(rootfsfd.get(), "..", O_PATH | O_CLOEXEC); if (parent_fd < 0) { throw std::system_error(errno, @@ -675,10 +677,10 @@ class mounter } public: - explicit mounter(linyaps_box::utils::file_descriptor root, + explicit mounter(linyaps_box::utils::file_descriptor rootfd, const linyaps_box::container &container) : container(container) - , root(std::move(root)) + , root(std::move(rootfd)) { } @@ -1219,16 +1221,19 @@ void configure_mounts(const linyaps_box::container &container, const std::filesy LINYAPS_BOX_DEBUG() << "Execute container process:" << [&process]() -> std::string { std::stringstream ss; + assert(!process.args.empty()); + ss << " " << process.args[0]; - for (size_t i = 1; i < process.args.size(); ++i) { - ss << " " << process.args[i]; - } + std::for_each(process.args.cbegin() + 1, process.args.cend(), [&ss](const auto &arg) { + ss << " " << arg; + }); + return ss.str(); }(); execvpe(c_args[0], - const_cast(c_args.data()), - const_cast(c_env.data())); + const_cast(c_args.data()), // NOLINT + const_cast(c_env.data())); // NOLINT throw std::system_error(errno, std::generic_category(), "execvpe"); } @@ -1496,7 +1501,7 @@ void set_capabilities(const linyaps_box::container &container, int last_cap) throw std::system_error(errno, std::generic_category(), "cap_ambient_clear_all"); } - std::for_each(capabilities.ambient.cend(), capabilities.ambient.cend(), [](cap_value_t cap) { + std::for_each(capabilities.ambient.cbegin(), capabilities.ambient.cend(), [](cap_value_t cap) { auto ret = prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, cap, 0L, 0L); if (ret < 0) { throw std::system_error(errno, std::generic_category(), "cap_ambient_raise"); @@ -1583,10 +1588,9 @@ void processing_extensions(const linyaps_box::container &container) + std::to_string(std::numeric_limits::max()) + ")"); } } catch (const std::out_of_range &e) { - throw std::runtime_error("ns_last_pid value out of range: " + it->second); + throw std::runtime_error("parse ns_last_pid " + it->second + " failed: " + e.what()); } catch (const std::invalid_argument &e) { - throw std::runtime_error("Invalid ns_last_pid value: " + it->second - + " (must be a valid number)"); + throw std::runtime_error("parse ns_last_pid " + it->second + " failed: " + e.what()); } std::ofstream ofs("/proc/sys/kernel/ns_last_pid"); @@ -1639,8 +1643,10 @@ try { auto &args = *static_cast(data); assert(args.socket.get() >= 0); - close_other_fds( - { STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO, (unsigned int)(args.socket.get()) }); + close_other_fds({ STDIN_FILENO, + STDOUT_FILENO, + STDERR_FILENO, + static_cast(args.socket.get()) }); const auto &container = *args.container; const auto &process = *args.process; @@ -1720,8 +1726,11 @@ namespace runtime_ns { flag |= CLONE_NEWCGROUP; LINYAPS_BOX_DEBUG() << "Add CLONE_NEWCGROUP, flag=0x" << std::hex << flag; } break; + case linyaps_box::config::linux_t::namespace_t::INVALID: { + throw std::invalid_argument("invalid namespace type: " + std::to_string(ns.type)); + } break; default: { - throw std::invalid_argument("invalid namespace"); + throw std::invalid_argument("unknown namespace type: " + std::to_string(ns.type)); } } @@ -1767,12 +1776,12 @@ class child_stack assert(false); } - [[nodiscard]] void *top() const noexcept + [[nodiscard]] auto top() const noexcept -> void * { if constexpr (LINYAPS_BOX_STACK_GROWTH_DOWN) { - return (char *)this->stack_low + LINYAPS_BOX_CLONE_CHILD_STACK_SIZE; + return static_cast(this->stack_low) + LINYAPS_BOX_CLONE_CHILD_STACK_SIZE; } else { - return (char *)this->stack_low - LINYAPS_BOX_CLONE_CHILD_STACK_SIZE; + return static_cast(this->stack_low) - LINYAPS_BOX_CLONE_CHILD_STACK_SIZE; } } diff --git a/src/linyaps_box/container.h b/src/linyaps_box/container.h index 420d7b5..0bfed33 100644 --- a/src/linyaps_box/container.h +++ b/src/linyaps_box/container.h @@ -22,14 +22,19 @@ class container final : public container_ref std::filesystem::path config, cgroup_manager_t manager); - [[nodiscard]] const linyaps_box::config &get_config() const; - [[nodiscard]] const std::filesystem::path &get_bundle() const; - [[nodiscard]] int run(const config::process_t &process) const; + container(const container &) = delete; + auto operator=(const container &) -> container & = delete; + container(container &&) = delete; + auto operator=(container &&) -> container & = delete; + + [[nodiscard]] auto get_config() const -> const linyaps_box::config &; + [[nodiscard]] auto get_bundle() const -> const std::filesystem::path &; + [[nodiscard]] auto run(const config::process_t &process) const -> int; // TODO:: support fully container capabilities, e.g. create, start, stop, delete... - friend container_data &get_private_data(const container &c) noexcept; + friend auto get_private_data(const container &c) noexcept -> container_data &; ~container() noexcept override; - [[nodiscard]] auto host_gid() const noexcept { return host_gid_; }; + [[nodiscard]] auto host_gid() const noexcept { return host_gid_; } [[nodiscard]] auto host_uid() const noexcept { return host_uid_; } diff --git a/src/linyaps_box/container_ref.cpp b/src/linyaps_box/container_ref.cpp index 48a84f9..45a0696 100644 --- a/src/linyaps_box/container_ref.cpp +++ b/src/linyaps_box/container_ref.cpp @@ -12,14 +12,16 @@ #include linyaps_box::container_ref::container_ref(const status_directory &status_dir, std::string id) - : id(std::move(id)) + : id_(std::move(id)) , status_dir_(status_dir) { } +linyaps_box::container_ref::~container_ref() noexcept = default; + linyaps_box::container_status_t linyaps_box::container_ref::status() const { - return this->status_dir_.read(this->id); + return this->status_dir_.read(this->id_); } void linyaps_box::container_ref::kill(int signal) const @@ -111,5 +113,5 @@ const linyaps_box::status_directory &linyaps_box::container_ref::status_dir() co const std::string &linyaps_box::container_ref::get_id() const { - return this->id; + return this->id_; } diff --git a/src/linyaps_box/container_ref.h b/src/linyaps_box/container_ref.h index beb9fd3..dfa69b2 100644 --- a/src/linyaps_box/container_ref.h +++ b/src/linyaps_box/container_ref.h @@ -14,18 +14,23 @@ class container_ref { public: container_ref(const status_directory &status_dir, std::string id); - virtual ~container_ref() noexcept = default; + virtual ~container_ref() noexcept; - [[nodiscard]] container_status_t status() const; + container_ref(const container_ref &) = delete; + auto operator=(const container_ref &) -> container_ref & = delete; + container_ref(container_ref &&) = delete; + auto operator=(container_ref &&) -> container_ref & = delete; + + [[nodiscard]] auto status() const -> container_status_t; void kill(int signal) const; [[noreturn]] void exec(const config::process_t &process); protected: - [[nodiscard]] const status_directory &status_dir() const; - [[nodiscard]] const std::string &get_id() const; + [[nodiscard]] auto status_dir() const -> const status_directory &; + [[nodiscard]] auto get_id() const -> const std::string &; private: - std::string id; + std::string id_; const status_directory &status_dir_; }; diff --git a/src/linyaps_box/container_status.cpp b/src/linyaps_box/container_status.cpp index f3fc47f..102556a 100644 --- a/src/linyaps_box/container_status.cpp +++ b/src/linyaps_box/container_status.cpp @@ -5,7 +5,7 @@ #include "linyaps_box/container_status.h" namespace linyaps_box { -std::string to_string(linyaps_box::container_status_t::runtime_status status) +auto to_string(linyaps_box::container_status_t::runtime_status status) -> std::string { switch (status) { case linyaps_box::container_status_t::runtime_status::CREATING: @@ -16,12 +16,12 @@ std::string to_string(linyaps_box::container_status_t::runtime_status status) return "running"; case linyaps_box::container_status_t::runtime_status::STOPPED: return "stopped"; + default: + throw std::logic_error("unknown status"); } - - throw std::logic_error("unknown status"); } -linyaps_box::container_status_t::runtime_status from_string(std::string_view status) +auto from_string(std::string_view status) -> linyaps_box::container_status_t::runtime_status { if (status == "creating") { return linyaps_box::container_status_t::runtime_status::CREATING; @@ -39,7 +39,7 @@ linyaps_box::container_status_t::runtime_status from_string(std::string_view sta throw std::logic_error("unknown status"); } -nlohmann::json status_to_json(const linyaps_box::container_status_t &status) +auto status_to_json(const linyaps_box::container_status_t &status) -> nlohmann::json { return nlohmann::json::object({ { "id", status.ID }, { "pid", status.PID }, diff --git a/src/linyaps_box/container_status.h b/src/linyaps_box/container_status.h index 71cce0c..4211d16 100644 --- a/src/linyaps_box/container_status.h +++ b/src/linyaps_box/container_status.h @@ -26,8 +26,8 @@ struct container_status_t std::unordered_map annotations; }; -std::string to_string(linyaps_box::container_status_t::runtime_status status); -linyaps_box::container_status_t::runtime_status from_string(std::string_view status); -nlohmann::json status_to_json(const linyaps_box::container_status_t &status); +auto to_string(linyaps_box::container_status_t::runtime_status status) -> std::string; +auto from_string(std::string_view status) -> linyaps_box::container_status_t::runtime_status; +auto status_to_json(const linyaps_box::container_status_t &status) -> nlohmann::json; } // namespace linyaps_box diff --git a/src/linyaps_box/impl/disabled_cgroup_manager.cpp b/src/linyaps_box/impl/disabled_cgroup_manager.cpp index 5150c1b..4d12d33 100644 --- a/src/linyaps_box/impl/disabled_cgroup_manager.cpp +++ b/src/linyaps_box/impl/disabled_cgroup_manager.cpp @@ -5,15 +5,16 @@ #include "linyaps_box/impl/disabled_cgroup_manager.h" namespace linyaps_box { -[[nodiscard]] cgroup_manager_t disabled_cgroup_manager::type() const +[[nodiscard]] auto disabled_cgroup_manager::type() const -> cgroup_manager_t { return cgroup_manager_t::disabled; } -cgroup_status disabled_cgroup_manager::create_cgroup([[maybe_unused]] const cgroup_options &options) +auto disabled_cgroup_manager::create_cgroup([[maybe_unused]] const cgroup_options &options) + -> cgroup_status { cgroup_status status{}; - set_manager_type(status, type()); + set_manager(status, type()); return status; } diff --git a/src/linyaps_box/impl/disabled_cgroup_manager.h b/src/linyaps_box/impl/disabled_cgroup_manager.h index db3d0a2..2c66070 100644 --- a/src/linyaps_box/impl/disabled_cgroup_manager.h +++ b/src/linyaps_box/impl/disabled_cgroup_manager.h @@ -11,9 +11,9 @@ namespace linyaps_box { class disabled_cgroup_manager : public virtual cgroup_manager { public: - [[nodiscard]] cgroup_manager_t type() const override; + [[nodiscard]] auto type() const -> cgroup_manager_t override; - cgroup_status create_cgroup([[maybe_unused]] const cgroup_options &options) override; + auto create_cgroup([[maybe_unused]] const cgroup_options &options) -> cgroup_status override; void precreate_cgroup([[maybe_unused]] const cgroup_options &options, [[maybe_unused]] utils::file_descriptor &dirfd) override; diff --git a/src/linyaps_box/impl/status_directory.cpp b/src/linyaps_box/impl/status_directory.cpp index 7d5a5a3..961c79c 100644 --- a/src/linyaps_box/impl/status_directory.cpp +++ b/src/linyaps_box/impl/status_directory.cpp @@ -9,15 +9,15 @@ #include "linyaps_box/utils/log.h" #include "nlohmann/json.hpp" -#include -#include +#include // IWYU pragma: keep #include +#include #include namespace { -linyaps_box::container_status_t read_status(const std::filesystem::path &path) +auto read_status(const std::filesystem::path &path) -> linyaps_box::container_status_t { nlohmann::json j; { @@ -34,7 +34,7 @@ linyaps_box::container_status_t read_status(const std::filesystem::path &path) ret.PID = j["pid"]; ret.ID = j["id"]; ret.status = linyaps_box::from_string(j["status"].get()); - if (kill(ret.PID, 0) != 0) { + if (::kill(ret.PID, 0) != 0) { ret.status = linyaps_box::container_status_t::runtime_status::STOPPED; } ret.bundle = std::string(j["bundle"]); @@ -61,22 +61,22 @@ void linyaps_box::impl::status_directory::write(const container_status_t &status utils::atomic_write(this->path / (status.ID + ".json"), j.dump()); } -linyaps_box::container_status_t -linyaps_box::impl::status_directory::read(const std::string &id) const +auto linyaps_box::impl::status_directory::read(const std::string &id) const + -> linyaps_box::container_status_t { return read_status(this->path / (id + ".json")); } void linyaps_box::impl::status_directory::remove(const std::string &id) const { - auto path = this->path / (id + ".json"); - LINYAPS_BOX_DEBUG() << "Remove " << path; - if (!std::filesystem::remove(path)) { - LINYAPS_BOX_WARNING() << "Failed to remove " << path; + auto file_path = this->path / (id + ".json"); + LINYAPS_BOX_DEBUG() << "Remove " << file_path; + if (!std::filesystem::remove(file_path)) { + LINYAPS_BOX_WARNING() << "Failed to remove " << file_path; } } -std::vector linyaps_box::impl::status_directory::list() const +auto linyaps_box::impl::status_directory::list() const -> std::vector { std::vector ret; for (const auto &entry : std::filesystem::directory_iterator(this->path)) { @@ -95,8 +95,8 @@ std::vector linyaps_box::impl::status_directory::list() const return ret; } -linyaps_box::impl::status_directory::status_directory(const std::filesystem::path &path) - : path(path) +linyaps_box::impl::status_directory::status_directory(std::filesystem::path dir) + : path(std::move(dir)) { if (std::filesystem::is_directory(path) || std::filesystem::create_directories(path)) { return; diff --git a/src/linyaps_box/impl/status_directory.h b/src/linyaps_box/impl/status_directory.h index 22dd241..bd10185 100644 --- a/src/linyaps_box/impl/status_directory.h +++ b/src/linyaps_box/impl/status_directory.h @@ -14,11 +14,11 @@ class status_directory : public virtual linyaps_box::status_directory { public: void write(const container_status_t &status) const override; - [[nodiscard]] container_status_t read(const std::string &id) const override; + [[nodiscard]] auto read(const std::string &id) const -> container_status_t override; void remove(const std::string &id) const override; - [[nodiscard]] std::vector list() const override; + [[nodiscard]] auto list() const -> std::vector override; - explicit status_directory(const std::filesystem::path &path); + explicit status_directory(std::filesystem::path dir); private: std::filesystem::path path; diff --git a/src/linyaps_box/impl/table_printer.cpp b/src/linyaps_box/impl/table_printer.cpp index 5576148..a06d818 100644 --- a/src/linyaps_box/impl/table_printer.cpp +++ b/src/linyaps_box/impl/table_printer.cpp @@ -7,7 +7,7 @@ #include namespace { -std::string get_status_string(const linyaps_box::container_status_t::runtime_status &status) +auto get_status_string(const linyaps_box::container_status_t::runtime_status &status) -> std::string { switch (status) { case linyaps_box::container_status_t::runtime_status::CREATING: @@ -18,17 +18,17 @@ std::string get_status_string(const linyaps_box::container_status_t::runtime_sta return "running"; case linyaps_box::container_status_t::runtime_status::STOPPED: return "stopped"; + default: + throw std::logic_error("unknown status"); } - - throw std::logic_error("unknown status"); } } // namespace void linyaps_box::impl::table_printer::print_statuses(const std::vector &status) { - size_t max_length = 4; + int max_length = 4; for (const auto &s : status) { - max_length = std::max(max_length, s.ID.length()); + max_length = std::max(max_length, static_cast(s.ID.length())); } std::cout << std::left << std::setw(max_length + 1) << "NAME" << std::setw(10) << "PID" diff --git a/src/linyaps_box/interface.cpp b/src/linyaps_box/interface.cpp index 2647a7b..44e6431 100644 --- a/src/linyaps_box/interface.cpp +++ b/src/linyaps_box/interface.cpp @@ -3,3 +3,10 @@ // SPDX-License-Identifier: LGPL-3.0-or-later #include "linyaps_box/interface.h" + +namespace linyaps_box { + +// ensure vtable only here +interface::~interface() = default; + +} // namespace linyaps_box diff --git a/src/linyaps_box/interface.h b/src/linyaps_box/interface.h index bb3f550..cd42b45 100644 --- a/src/linyaps_box/interface.h +++ b/src/linyaps_box/interface.h @@ -11,10 +11,10 @@ class interface { public: interface() = default; - virtual ~interface() = default; + virtual ~interface(); interface(const interface &) = delete; - interface &operator=(const interface &) = delete; + auto operator=(const interface &) -> interface & = delete; interface(interface &&) = delete; - interface &operator=(interface &&) = delete; + auto operator=(interface &&) -> interface & = delete; }; } // namespace linyaps_box diff --git a/src/linyaps_box/printer.cpp b/src/linyaps_box/printer.cpp index 4a3340e..456ebab 100644 --- a/src/linyaps_box/printer.cpp +++ b/src/linyaps_box/printer.cpp @@ -3,3 +3,9 @@ // SPDX-License-Identifier: LGPL-3.0-or-later #include "linyaps_box/printer.h" + +namespace linyaps_box { + +printer::~printer() = default; + +} // namespace linyaps_box diff --git a/src/linyaps_box/printer.h b/src/linyaps_box/printer.h index 5a295da..6a82919 100644 --- a/src/linyaps_box/printer.h +++ b/src/linyaps_box/printer.h @@ -12,7 +12,17 @@ namespace linyaps_box { class printer : public virtual interface { +protected: + printer() = default; + public: + ~printer() override; + + printer(const printer &) = delete; + auto operator=(const printer &) -> printer & = delete; + printer(printer &&) = delete; + auto operator=(printer &&) -> printer & = delete; + virtual void print_status(const container_status_t &status) = 0; virtual void print_statuses(const std::vector &status) = 0; }; diff --git a/src/linyaps_box/runtime.cpp b/src/linyaps_box/runtime.cpp index 93ae356..cc292e9 100644 --- a/src/linyaps_box/runtime.cpp +++ b/src/linyaps_box/runtime.cpp @@ -5,27 +5,30 @@ #include "linyaps_box/runtime.h" linyaps_box::runtime_t::runtime_t(std::unique_ptr &&status_dir) - : status_dir{ std::move(status_dir) } + : status_dir_{ std::move(status_dir) } { - if (!this->status_dir) { + if (!this->status_dir_) { throw std::invalid_argument("status_dir is nullptr"); } } -std::unordered_map linyaps_box::runtime_t::containers() +auto linyaps_box::runtime_t::containers() + -> std::unordered_map { - auto container_ids = this->status_dir->list(); + auto container_ids = this->status_dir_->list(); std::unordered_map containers; for (const auto &container_id : container_ids) { - containers.emplace(container_id, container_ref(*this->status_dir, container_id)); + containers.emplace(std::piecewise_construct, + std::forward_as_tuple(container_id), + std::forward_as_tuple(*this->status_dir_, container_id)); } return containers; } -linyaps_box::container linyaps_box::runtime_t::create_container( - const linyaps_box::runtime_t::create_container_options_t &options) +auto linyaps_box::runtime_t::create_container( + const linyaps_box::runtime_t::create_container_options_t &options) -> linyaps_box::container { - return { *this->status_dir, options.ID, options.bundle, options.config, options.manager }; + return { *this->status_dir_, options.ID, options.bundle, options.config, options.manager }; } diff --git a/src/linyaps_box/runtime.h b/src/linyaps_box/runtime.h index f55e27e..177e1c7 100644 --- a/src/linyaps_box/runtime.h +++ b/src/linyaps_box/runtime.h @@ -17,7 +17,7 @@ class runtime_t { public: explicit runtime_t(std::unique_ptr &&status_dir); - std::unordered_map containers(); + auto containers() -> std::unordered_map; struct create_container_options_t { @@ -27,10 +27,10 @@ class runtime_t cgroup_manager_t manager; }; - container create_container(const create_container_options_t &options); + auto create_container(const create_container_options_t &options) -> container; private: - std::unique_ptr status_dir; + std::unique_ptr status_dir_; }; } // namespace linyaps_box diff --git a/src/linyaps_box/status_directory.cpp b/src/linyaps_box/status_directory.cpp index 98eb590..d281230 100644 --- a/src/linyaps_box/status_directory.cpp +++ b/src/linyaps_box/status_directory.cpp @@ -3,3 +3,7 @@ // SPDX-License-Identifier: LGPL-3.0-or-later #include "linyaps_box/status_directory.h" + +namespace linyaps_box { +status_directory::~status_directory() = default; +} // namespace linyaps_box diff --git a/src/linyaps_box/status_directory.h b/src/linyaps_box/status_directory.h index 74db51f..10d53f0 100644 --- a/src/linyaps_box/status_directory.h +++ b/src/linyaps_box/status_directory.h @@ -12,10 +12,20 @@ namespace linyaps_box { class status_directory : public virtual interface { +protected: + status_directory() = default; + public: + ~status_directory() override; + + status_directory(const status_directory &) = delete; + auto operator=(const status_directory &) -> status_directory & = delete; + status_directory(status_directory &&) = delete; + auto operator=(status_directory &&) -> status_directory & = delete; + virtual void write(const container_status_t &status) const = 0; - [[nodiscard]] virtual container_status_t read(const std::string &id) const = 0; + [[nodiscard]] virtual auto read(const std::string &id) const -> container_status_t = 0; virtual void remove(const std::string &id) const = 0; - [[nodiscard]] virtual std::vector list() const = 0; + [[nodiscard]] virtual auto list() const -> std::vector = 0; }; } // namespace linyaps_box diff --git a/src/linyaps_box/utils/cgroups.cpp b/src/linyaps_box/utils/cgroups.cpp index f13fee3..311ac62 100644 --- a/src/linyaps_box/utils/cgroups.cpp +++ b/src/linyaps_box/utils/cgroups.cpp @@ -11,7 +11,7 @@ constexpr auto cgroup_root = "/sys/fs/cgroups"; -linyaps_box::utils::cgroup_t linyaps_box::utils::get_cgroup_type() +auto linyaps_box::utils::get_cgroup_type() -> linyaps_box::utils::cgroup_t { static auto cgroup_type = []() -> cgroup_t { struct statfs stat{}; diff --git a/src/linyaps_box/utils/cgroups.h b/src/linyaps_box/utils/cgroups.h index 98cbf16..fa8be44 100644 --- a/src/linyaps_box/utils/cgroups.h +++ b/src/linyaps_box/utils/cgroups.h @@ -8,8 +8,8 @@ namespace linyaps_box::utils { -enum class cgroup_t : std::uint16_t { unified, legacy, hybrid }; +enum class cgroup_t : std::uint8_t { unified, legacy, hybrid }; -cgroup_t get_cgroup_type(); +auto get_cgroup_type() -> cgroup_t; } // namespace linyaps_box::utils diff --git a/src/linyaps_box/utils/close_range.cpp b/src/linyaps_box/utils/close_range.cpp index dd2ba86..71cb6cb 100644 --- a/src/linyaps_box/utils/close_range.cpp +++ b/src/linyaps_box/utils/close_range.cpp @@ -24,7 +24,7 @@ void syscall_close_range(uint fd, uint max_fd, int flags) void close_range_fallback(uint first, uint last, int flags) { - if ((flags & CLOSE_RANGE_UNSHARE) != 0) { + if ((static_cast(flags) & CLOSE_RANGE_UNSHARE) != 0) { // not support CLOSE_RANGE_UNSHARE // it request to create a new file descriptor table // we can't do that in user space @@ -59,7 +59,7 @@ void close_range_fallback(uint first, uint last, int flags) continue; } - auto fd = std::stoi(name.c_str()); + auto fd = std::stoi(name); if (fd == self_fd) { continue; } @@ -68,7 +68,7 @@ void close_range_fallback(uint first, uint last, int flags) continue; } - if ((flags & CLOSE_RANGE_CLOEXEC) != 0) { + if ((static_cast(flags) & CLOSE_RANGE_CLOEXEC) != 0) { if (::fcntl(fd, F_SETFD, FD_CLOEXEC) < 0) { throw std::system_error(errno, std::generic_category(), @@ -89,10 +89,10 @@ void linyaps_box::utils::close_range(uint first, uint last, int flags) << [flags]() -> std::string { std::stringstream ss; ss << '['; - if ((flags & CLOSE_RANGE_CLOEXEC) != 0) { + if ((static_cast(flags) & CLOSE_RANGE_CLOEXEC) != 0) { ss << "CLOSE_RANGE_CLOEXEC "; } - if ((flags & CLOSE_RANGE_UNSHARE) != 0) { + if ((static_cast(flags) & CLOSE_RANGE_UNSHARE) != 0) { ss << "CLOSE_RANGE_UNSHARE "; } ss << ']'; diff --git a/src/linyaps_box/utils/defer.h b/src/linyaps_box/utils/defer.h index 7bee2e1..0bdc5d9 100644 --- a/src/linyaps_box/utils/defer.h +++ b/src/linyaps_box/utils/defer.h @@ -26,16 +26,15 @@ template defer & = delete; defer(defer &&other) noexcept - : fn(std::move(other.fn)) + : fn_(std::move(other.fn_)) , cancelled(other.cancelled) { other.cancelled = true; @@ -51,7 +50,7 @@ struct defer execute(); } - fn = std::move(other.fn); + fn_ = std::move(other.fn_); cancelled = other.cancelled; other.cancelled = true; @@ -67,22 +66,22 @@ struct defer void cancel() noexcept { cancelled = true; } - [[nodiscard]] bool is_cancelled() const noexcept { return cancelled; } + [[nodiscard]] auto is_cancelled() const noexcept -> bool { return cancelled; } private: void execute() noexcept { if constexpr (Policy == defer_policy::always) { - fn(); + fn_(); } else if constexpr (Policy == defer_policy::on_error) { if (std::uncaught_exceptions() > 0) { - fn(); + fn_(); } } } - Fn fn; - bool cancelled; + Fn fn_; + bool cancelled{ false }; }; // Helper functions to create defer objects diff --git a/src/linyaps_box/utils/file_describer.cpp b/src/linyaps_box/utils/file_describer.cpp index 51309a8..179639f 100644 --- a/src/linyaps_box/utils/file_describer.cpp +++ b/src/linyaps_box/utils/file_describer.cpp @@ -15,19 +15,22 @@ linyaps_box::utils::file_descriptor_closed_exception::file_descriptor_closed_exc { } +linyaps_box::utils::file_descriptor_closed_exception::~file_descriptor_closed_exception() noexcept = + default; + linyaps_box::utils::file_descriptor::file_descriptor(int fd) - : fd(fd) + : fd_(fd) { } linyaps_box::utils::file_descriptor::~file_descriptor() { - if (fd == -1) { + if (fd_ == -1) { return; } - if (close(fd) != 0) { - LINYAPS_BOX_ERR() << "close " << fd << " failed:" << ::strerror(errno); + if (close(fd_) != 0) { + LINYAPS_BOX_ERR() << "close " << fd_ << " failed:" << ::strerror(errno); } } @@ -36,33 +39,33 @@ linyaps_box::utils::file_descriptor::file_descriptor(file_descriptor &&other) no *this = std::move(other); } -int linyaps_box::utils::file_descriptor::release() && noexcept +auto linyaps_box::utils::file_descriptor::release() && noexcept -> int { int ret = -1; - std::swap(ret, fd); + std::swap(ret, fd_); return ret; } -int linyaps_box::utils::file_descriptor::get() const noexcept +auto linyaps_box::utils::file_descriptor::get() const noexcept -> int { - return fd; + return fd_; } -linyaps_box::utils::file_descriptor linyaps_box::utils::file_descriptor::duplicate() const +auto linyaps_box::utils::file_descriptor::duplicate() const -> linyaps_box::utils::file_descriptor { - if (fd == -1) { + if (fd_ == -1) { throw file_descriptor_closed_exception(); } - auto ret = dup(fd); + auto ret = dup(fd_); if (ret < 0) { throw std::system_error(errno, std::generic_category(), "fcntl"); } // dup will lost the close-on-exec flag // and we don't want to use FD_DUPFD_CLOEXEC due to it require a specific fd number - auto flag = fcntl(fd, F_GETFD); + auto flag = fcntl(fd_, F_GETFD); if (flag < 0) { throw std::system_error(errno, std::generic_category(), "fcntl"); } @@ -74,11 +77,11 @@ linyaps_box::utils::file_descriptor linyaps_box::utils::file_descriptor::duplica return file_descriptor{ ret }; } -linyaps_box::utils::file_descriptor & -linyaps_box::utils::file_descriptor::operator<<(const std::byte &byte) +auto linyaps_box::utils::file_descriptor::operator<<(const std::byte &byte) + -> linyaps_box::utils::file_descriptor & { while (true) { - auto ret = write(fd, &byte, 1); + auto ret = write(fd_, &byte, 1); if (ret == 1) { return *this; } @@ -89,18 +92,18 @@ linyaps_box::utils::file_descriptor::operator<<(const std::byte &byte) } } -linyaps_box::utils::file_descriptor & -linyaps_box::utils::file_descriptor::operator=(file_descriptor &&other) noexcept +auto linyaps_box::utils::file_descriptor::operator=(file_descriptor &&other) noexcept + -> linyaps_box::utils::file_descriptor & { - std::swap(this->fd, other.fd); + std::swap(this->fd_, other.fd_); return *this; } -linyaps_box::utils::file_descriptor & -linyaps_box::utils::file_descriptor::operator>>(std::byte &byte) +auto linyaps_box::utils::file_descriptor::operator>>(std::byte &byte) + -> linyaps_box::utils::file_descriptor & { while (true) { - auto ret = read(fd, &byte, 1); + auto ret = read(fd_, &byte, 1); if (ret == 1) { return *this; } @@ -114,13 +117,13 @@ linyaps_box::utils::file_descriptor::operator>>(std::byte &byte) } } -std::filesystem::path linyaps_box::utils::file_descriptor::proc_path() const +auto linyaps_box::utils::file_descriptor::proc_path() const -> std::filesystem::path { return std::filesystem::current_path().root_path() / "proc" / "self" / "fd" - / std::to_string(fd); + / std::to_string(fd_); } -std::filesystem::path linyaps_box::utils::file_descriptor::current_path() const noexcept +auto linyaps_box::utils::file_descriptor::current_path() const noexcept -> std::filesystem::path { std::error_code ec; auto p_path = proc_path(); diff --git a/src/linyaps_box/utils/file_describer.h b/src/linyaps_box/utils/file_describer.h index 0b85205..a2d955a 100644 --- a/src/linyaps_box/utils/file_describer.h +++ b/src/linyaps_box/utils/file_describer.h @@ -14,6 +14,13 @@ class file_descriptor_closed_exception : public std::runtime_error { public: file_descriptor_closed_exception(); + file_descriptor_closed_exception(const file_descriptor_closed_exception &) = default; + file_descriptor_closed_exception(file_descriptor_closed_exception &&) noexcept = default; + auto operator=(const file_descriptor_closed_exception &) + -> file_descriptor_closed_exception & = default; + auto operator=(file_descriptor_closed_exception &&) noexcept + -> file_descriptor_closed_exception & = default; + ~file_descriptor_closed_exception() noexcept override; }; class file_descriptor @@ -24,28 +31,28 @@ class file_descriptor ~file_descriptor(); file_descriptor(const file_descriptor &) = delete; - file_descriptor &operator=(const file_descriptor &) = delete; + auto operator=(const file_descriptor &) -> file_descriptor & = delete; file_descriptor(file_descriptor &&other) noexcept; - file_descriptor &operator=(file_descriptor &&other) noexcept; + auto operator=(file_descriptor &&other) noexcept -> file_descriptor &; - [[nodiscard]] int get() const noexcept; + [[nodiscard]] auto get() const noexcept -> int; - int release() && noexcept; + auto release() && noexcept -> int; - [[nodiscard]] file_descriptor duplicate() const; + [[nodiscard]] auto duplicate() const -> file_descriptor; - file_descriptor &operator<<(const std::byte &byte); + auto operator<<(const std::byte &byte) -> file_descriptor &; - file_descriptor &operator>>(std::byte &byte); + auto operator>>(std::byte &byte) -> file_descriptor &; - [[nodiscard]] std::filesystem::path proc_path() const; + [[nodiscard]] auto proc_path() const -> std::filesystem::path; - [[nodiscard]] std::filesystem::path current_path() const noexcept; + [[nodiscard]] auto current_path() const noexcept -> std::filesystem::path; private: - int fd{ -1 }; + int fd_{ -1 }; }; } // namespace linyaps_box::utils diff --git a/src/linyaps_box/utils/fstat.cpp b/src/linyaps_box/utils/fstat.cpp index c7e7391..85dbd74 100644 --- a/src/linyaps_box/utils/fstat.cpp +++ b/src/linyaps_box/utils/fstat.cpp @@ -3,3 +3,48 @@ // SPDX-License-Identifier: LGPL-3.0-or-later #include "linyaps_box/utils/fstat.h" + +namespace linyaps_box::utils { + +auto fstatat(const file_descriptor &fd, std::filesystem::path path, int flag) -> struct stat +{ + if (!path.empty() && path.is_absolute()) { + path = path.lexically_relative("/"); + } + + struct stat statbuf{}; + auto ret = ::fstatat(fd.get(), path.c_str(), &statbuf, flag); + if (ret == -1) { + throw std::system_error(errno, std::generic_category(), "fstatat"); + } + + return statbuf; + +} + +auto fstatat(const file_descriptor &fd, const std::filesystem::path &path) -> struct stat + +{ + return linyaps_box::utils::fstatat(fd, path, AT_EMPTY_PATH); + +} + +auto lstatat(const file_descriptor &fd, const std::filesystem::path &path) -> struct stat + +{ + return linyaps_box::utils::fstatat(fd, path, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW); + +} + +auto statfs(const file_descriptor &fd) -> struct statfs + +{ + struct statfs statbuf{}; + auto ret = ::statfs(fd.proc_path().c_str(), &statbuf); + if (ret == -1) { + throw std::system_error(errno, std::generic_category(), "statfs"); + } + + return statbuf; +} +} // namespace linyaps_box::utils diff --git a/src/linyaps_box/utils/fstat.h b/src/linyaps_box/utils/fstat.h index afc9b3d..541cbf2 100644 --- a/src/linyaps_box/utils/fstat.h +++ b/src/linyaps_box/utils/fstat.h @@ -12,41 +12,8 @@ #include namespace linyaps_box::utils { - -inline struct stat fstatat(const file_descriptor &fd, std::filesystem::path path, int flag) -{ - if (!path.empty() && path.is_absolute()) { - path = path.lexically_relative("/"); - } - - struct stat statbuf{}; - auto ret = ::fstatat(fd.get(), path.c_str(), &statbuf, flag); - if (ret == -1) { - throw std::system_error(errno, std::generic_category(), "fstatat"); - } - - return statbuf; -} - -inline struct stat fstatat(const file_descriptor &fd, const std::filesystem::path &path) -{ - return linyaps_box::utils::fstatat(fd, path, AT_EMPTY_PATH); -} - -inline struct stat lstatat(const file_descriptor &fd, const std::filesystem::path &path) -{ - return linyaps_box::utils::fstatat(fd, path, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW); -} - -inline struct statfs statfs(const file_descriptor &fd) -{ - struct statfs statbuf{}; - auto ret = ::statfs(fd.proc_path().c_str(), &statbuf); - if (ret == -1) { - throw std::system_error(errno, std::generic_category(), "statfs"); - } - - return statbuf; -} - +auto fstatat(const file_descriptor &fd, std::filesystem::path path, int flag) -> struct stat; +auto fstatat(const file_descriptor &fd, const std::filesystem::path &path) -> struct stat; +auto lstatat(const file_descriptor &fd, const std::filesystem::path &path) -> struct stat; +auto statfs(const file_descriptor &fd) -> struct statfs; } // namespace linyaps_box::utils diff --git a/src/linyaps_box/utils/inspect.cpp b/src/linyaps_box/utils/inspect.cpp index 3266de1..58f0ae7 100644 --- a/src/linyaps_box/utils/inspect.cpp +++ b/src/linyaps_box/utils/inspect.cpp @@ -17,7 +17,7 @@ namespace { -std::string inspect_fdinfo(const std::filesystem::path &fdinfoPath) +auto inspect_fdinfo(const std::filesystem::path &fdinfoPath) -> std::string { std::ifstream fdinfo(fdinfoPath); assert(fdinfo.is_open()); @@ -42,7 +42,7 @@ std::string inspect_fdinfo(const std::filesystem::path &fdinfoPath) return ss.str(); } -std::string inspect_fdinfo(int fd) +auto inspect_fdinfo(int fd) -> std::string { std::stringstream ss; ss << linyaps_box::utils::inspect_path(fd) << " "; @@ -54,7 +54,7 @@ std::string inspect_fdinfo(int fd) namespace linyaps_box::utils { -std::string inspect_fcntl_or_open_flags(size_t flags) +auto inspect_fcntl_or_open_flags(size_t flags) -> std::string { std::stringstream ss; @@ -126,12 +126,12 @@ std::string inspect_fcntl_or_open_flags(size_t flags) return ss.str(); } -std::string inspect_fd(int fd) +auto inspect_fd(int fd) -> std::string { return inspect_fdinfo(fd); } -std::string inspect_fds() +auto inspect_fds() -> std::string { std::stringstream ss; @@ -160,7 +160,7 @@ std::string inspect_fds() return ss.str(); } -std::string inspect_permissions(int fd) +auto inspect_permissions(int fd) -> std::string { std::stringstream ss; struct stat buf{}; @@ -228,7 +228,7 @@ std::string inspect_permissions(int fd) return ss.str(); } -std::filesystem::path inspect_path(int fd) +auto inspect_path(int fd) -> std::filesystem::path { std::error_code ec; auto ret = std::filesystem::read_symlink("/proc/self/fd/" + std::to_string(fd), ec); diff --git a/src/linyaps_box/utils/inspect.h b/src/linyaps_box/utils/inspect.h index d15633c..ff85155 100644 --- a/src/linyaps_box/utils/inspect.h +++ b/src/linyaps_box/utils/inspect.h @@ -9,10 +9,10 @@ namespace linyaps_box::utils { -std::string inspect_fcntl_or_open_flags(size_t flags); -std::string inspect_fd(int fd); -std::string inspect_fds(); -std::string inspect_permissions(int fd); -std::filesystem::path inspect_path(int fd); +auto inspect_fcntl_or_open_flags(size_t flags) -> std::string; +auto inspect_fd(int fd) -> std::string; +auto inspect_fds() -> std::string; +auto inspect_permissions(int fd) -> std::string; +auto inspect_path(int fd) -> std::filesystem::path; } // namespace linyaps_box::utils diff --git a/src/linyaps_box/utils/log.cpp b/src/linyaps_box/utils/log.cpp index 6365323..4bdcf98 100644 --- a/src/linyaps_box/utils/log.cpp +++ b/src/linyaps_box/utils/log.cpp @@ -68,31 +68,32 @@ template class Logger; template class Logger; template class Logger; -bool force_log_to_stderr() +auto force_log_to_stderr() -> bool { static const auto *result = getenv("LINYAPS_BOX_LOG_FORCE_STDERR"); return result != nullptr; } -bool stderr_is_a_tty() +auto stderr_is_a_tty() -> bool { static const bool result = isatty(fileno(stderr)) != 0; return result; } namespace { -unsigned int get_current_log_level_from_env() +auto get_current_log_level_from_env() -> unsigned int { auto *env = getenv("LINYAPS_BOX_LOG_LEVEL"); if (env == nullptr) { return LINYAPS_BOX_LOG_DEFAULT_LEVEL; } - auto level = std::stoi(env); - if (level < 0) { + auto ret = std::stoi(env); + if (ret < 0) { return LOG_ALERT; } + auto level = static_cast(ret); if (level > LOG_DEBUG) { return LOG_DEBUG; } @@ -101,13 +102,13 @@ unsigned int get_current_log_level_from_env() } } // namespace -unsigned int get_current_log_level() +auto get_current_log_level() -> unsigned int { static const unsigned int level = get_current_log_level_from_env(); return level; } -std::string get_pid_namespace(int pid) +auto get_pid_namespace(int pid) -> std::string { const auto &pidns_path = "/proc/" + ((pid != 0) ? std::to_string(pid) : "self") + "/ns/pid"; @@ -117,16 +118,25 @@ std::string get_pid_namespace(int pid) return "not available"; } - std::string result{ buf.begin(), buf.begin() + length }; - if (result.rfind("pid:[", 0) != 0) { - std::abort(); + const std::string_view result(buf.data(), static_cast(length)); + constexpr std::string_view prefix = "pid:["; + constexpr char suffix = ']'; + constexpr auto prefix_len = prefix.size(); + constexpr auto total_wrapper_len = prefix_len + 1; // "pid:[" + "]" + + if (result.size() < total_wrapper_len) { + return "invalid format"; + } + + if (result.rfind(prefix, 0) != 0) { + return "invalid format"; } - if (result.back() != ']') { - std::abort(); + if (result.back() != suffix) { + return "invalid format"; } - return result.substr(sizeof("pid:[") - 1, result.size() - 6); + return std::string{ result.substr(prefix_len, result.size() - total_wrapper_len) }; } } // namespace linyaps_box::utils diff --git a/src/linyaps_box/utils/log.h b/src/linyaps_box/utils/log.h index e97e903..3d01a31 100644 --- a/src/linyaps_box/utils/log.h +++ b/src/linyaps_box/utils/log.h @@ -13,11 +13,11 @@ // TODO: maybe fmt with spdlog namespace linyaps_box::utils { -bool force_log_to_stderr(); -bool stderr_is_a_tty(); -unsigned int get_current_log_level(); -std::string get_pid_namespace(int pid = 0); -std::string get_current_command(); +auto force_log_to_stderr() -> bool; +auto stderr_is_a_tty() -> bool; +auto get_current_log_level() -> unsigned int; +auto get_pid_namespace(int pid = 0) -> std::string; +auto get_current_command() -> std::string; template class Logger @@ -25,7 +25,7 @@ class Logger public: Logger() = default; Logger(const Logger &) = delete; - Logger &operator=(const Logger &) = delete; + auto operator=(const Logger &) -> Logger & = delete; Logger(Logger &&) noexcept(std::is_nothrow_move_constructible_v) = // NOLINT default; Logger & @@ -34,13 +34,13 @@ class Logger ~Logger() noexcept; template - Logger &operator<<(const T &value) + auto operator<<(const T &value) -> Logger & { ss << value; return *this; } - Logger &operator<<(std::ostream &(*manipulator)(std::ostream &)) + auto operator<<(std::ostream &(*manipulator)(std::ostream &)) -> Logger & { manipulator(ss); return *this; diff --git a/src/linyaps_box/utils/mkdir.cpp b/src/linyaps_box/utils/mkdir.cpp index f5cafd8..7ee1d3a 100644 --- a/src/linyaps_box/utils/mkdir.cpp +++ b/src/linyaps_box/utils/mkdir.cpp @@ -12,9 +12,8 @@ #include #include -linyaps_box::utils::file_descriptor linyaps_box::utils::mkdir(const file_descriptor &root, - std::filesystem::path path, - mode_t mode) +auto linyaps_box::utils::mkdir(const file_descriptor &root, std::filesystem::path path, mode_t mode) + -> linyaps_box::utils::file_descriptor { LINYAPS_BOX_DEBUG() << "mkdir " << path << " at " << inspect_fd(root.get()); diff --git a/src/linyaps_box/utils/mkdir.h b/src/linyaps_box/utils/mkdir.h index f3fb863..407475f 100644 --- a/src/linyaps_box/utils/mkdir.h +++ b/src/linyaps_box/utils/mkdir.h @@ -8,6 +8,7 @@ namespace linyaps_box::utils { -file_descriptor mkdir(const file_descriptor &root, std::filesystem::path path, mode_t mode = 0755); +auto mkdir(const file_descriptor &root, std::filesystem::path path, mode_t mode = 0755) + -> file_descriptor; } // namespace linyaps_box::utils diff --git a/src/linyaps_box/utils/open_file.cpp b/src/linyaps_box/utils/open_file.cpp index a07ad8c..0b8244a 100644 --- a/src/linyaps_box/utils/open_file.cpp +++ b/src/linyaps_box/utils/open_file.cpp @@ -24,15 +24,15 @@ #endif namespace { -linyaps_box::utils::file_descriptor -open_at_fallback(const linyaps_box::utils::file_descriptor &root, - const std::filesystem::path &path, - int flag, - int mode) +auto open_at_fallback(const linyaps_box::utils::file_descriptor &root, + const std::filesystem::path &path, + int flag, + uint mode) -> linyaps_box::utils::file_descriptor { LINYAPS_BOX_DEBUG() << "fallback openat " << path.c_str() << " at FD=" << root.get() << " with " - << linyaps_box::utils::inspect_fcntl_or_open_flags(flag) << "\n\t" - << linyaps_box::utils::inspect_fd(root.get()); + << linyaps_box::utils::inspect_fcntl_or_open_flags( + static_cast(flag)) + << "\n\t" << linyaps_box::utils::inspect_fd(root.get()); // TODO: we need implement a compatible fallback // currently we just use openat and do some simple check const auto &file_path = path.relative_path(); @@ -47,8 +47,8 @@ open_at_fallback(const linyaps_box::utils::file_descriptor &root, return linyaps_box::utils::file_descriptor{ fd }; } -linyaps_box::utils::file_descriptor -syscall_openat2(int dirfd, const char *path, uint64_t flag, uint64_t mode, uint64_t resolve) +auto syscall_openat2(int dirfd, const char *path, uint64_t flag, uint64_t mode, uint64_t resolve) + -> linyaps_box::utils::file_descriptor { struct openat2_how { @@ -66,11 +66,11 @@ syscall_openat2(int dirfd, const char *path, uint64_t flag, uint64_t mode, uint6 } } // namespace -linyaps_box::utils::file_descriptor linyaps_box::utils::open(const std::filesystem::path &path, - int flag, - mode_t mode) +auto linyaps_box::utils::open(const std::filesystem::path &path, int flag, mode_t mode) + -> linyaps_box::utils::file_descriptor { - LINYAPS_BOX_DEBUG() << "open " << path.c_str() << " with " << inspect_fcntl_or_open_flags(flag); + LINYAPS_BOX_DEBUG() << "open " << path.c_str() << " with " + << inspect_fcntl_or_open_flags(static_cast(flag)); const auto fd = ::open(path.c_str(), flag, mode); if (fd == -1) { throw std::system_error(errno, @@ -81,19 +81,23 @@ linyaps_box::utils::file_descriptor linyaps_box::utils::open(const std::filesyst return linyaps_box::utils::file_descriptor{ fd }; } -linyaps_box::utils::file_descriptor -linyaps_box::utils::open_at(const linyaps_box::utils::file_descriptor &root, - const std::filesystem::path &path, - int flag, - mode_t mode) +auto linyaps_box::utils::open_at(const linyaps_box::utils::file_descriptor &root, + const std::filesystem::path &path, + int flag, + mode_t mode) -> linyaps_box::utils::file_descriptor { LINYAPS_BOX_DEBUG() << "open " << path.c_str() << " at FD=" << root.get() << " with " - << inspect_fcntl_or_open_flags(flag) << "\n\t" << inspect_fd(root.get()); + << inspect_fcntl_or_open_flags(static_cast(flag)) << "\n\t" + << inspect_fd(root.get()); static bool support_openat2{ true }; while (support_openat2) { try { - return syscall_openat2(root.get(), path.c_str(), flag, mode, RESOLVE_IN_ROOT); + return syscall_openat2(root.get(), + path.c_str(), + static_cast(flag), + mode, + RESOLVE_IN_ROOT); } catch (const std::system_error &e) { const auto code = e.code().value(); if (code == EINTR || code == EAGAIN) { diff --git a/src/linyaps_box/utils/open_file.h b/src/linyaps_box/utils/open_file.h index 54b4d0b..2eb444d 100644 --- a/src/linyaps_box/utils/open_file.h +++ b/src/linyaps_box/utils/open_file.h @@ -12,11 +12,12 @@ namespace linyaps_box::utils { -file_descriptor open(const std::filesystem::path &path, int flag = O_RDONLY, mode_t mode = 0); +auto open(const std::filesystem::path &path, int flag = O_RDONLY, mode_t mode = 0) + -> file_descriptor; -file_descriptor open_at(const file_descriptor &root, - const std::filesystem::path &path, - int flag = O_RDONLY, - mode_t mode = 0); +auto open_at(const file_descriptor &root, + const std::filesystem::path &path, + int flag = O_RDONLY, + mode_t mode = 0) -> file_descriptor; } // namespace linyaps_box::utils diff --git a/src/linyaps_box/utils/platform.cpp b/src/linyaps_box/utils/platform.cpp index 6ea345b..3500bb5 100644 --- a/src/linyaps_box/utils/platform.cpp +++ b/src/linyaps_box/utils/platform.cpp @@ -11,11 +11,11 @@ #include namespace linyaps_box::utils { -int str_to_signal(std::string_view str) +auto str_to_signal(std::string_view str) -> int { // Only support standard signals for now, // TODO: support real-time signal in the future - static const std::unordered_map sigMap{ + const std::unordered_map sigMap{ { "SIGABRT", SIGABRT }, { "SIGALRM", SIGALRM }, { "SIGBUS", SIGBUS }, { "SIGCHLD", SIGCHLD }, { "SIGCONT", SIGCONT }, { "SIGFPE", SIGFPE }, { "SIGHUP", SIGHUP }, { "SIGILL", SIGILL }, { "SIGINT", SIGINT }, @@ -37,9 +37,9 @@ int str_to_signal(std::string_view str) return it->second; } -int str_to_rlimit(std::string_view str) +auto str_to_rlimit(std::string_view str) -> int { - const static std::unordered_map resources{ + const std::unordered_map resources{ { "RLIMIT_AS", RLIMIT_AS }, { "RLIMIT_CORE", RLIMIT_CORE }, { "RLIMIT_CPU", RLIMIT_CPU }, diff --git a/src/linyaps_box/utils/platform.h b/src/linyaps_box/utils/platform.h index c72b96f..7cc2f8a 100644 --- a/src/linyaps_box/utils/platform.h +++ b/src/linyaps_box/utils/platform.h @@ -6,6 +6,6 @@ #include namespace linyaps_box::utils { -int str_to_signal(std::string_view str); -int str_to_rlimit(std::string_view str); +auto str_to_signal(std::string_view str) -> int; +auto str_to_rlimit(std::string_view str) -> int; } // namespace linyaps_box::utils diff --git a/src/linyaps_box/utils/semver.cpp b/src/linyaps_box/utils/semver.cpp index 37a81c1..2e340b7 100644 --- a/src/linyaps_box/utils/semver.cpp +++ b/src/linyaps_box/utils/semver.cpp @@ -16,7 +16,11 @@ linyaps_box::utils::semver::semver(const std::string &str) throw std::invalid_argument("invalid semver: " + str); } - auto major = std::stoi(str.substr(begin, end)); + auto ret = std::stoi(str.substr(begin, end)); + if (ret < 0) { + throw std::invalid_argument("invalid semver: " + str); + } + const auto major{ static_cast(ret) }; begin = end + 1; end = str.find('.', begin); @@ -24,12 +28,20 @@ linyaps_box::utils::semver::semver(const std::string &str) throw std::invalid_argument("invalid semver: " + str); } - auto minor = std::stoi(str.substr(begin, end)); + ret = std::stoi(str.substr(begin, end)); + if (ret < 0) { + throw std::invalid_argument("invalid semver: " + str); + } + const auto minor{ static_cast(ret) }; begin = end + 1; end = str.find_first_of("-+", begin); - auto patch = std::stoi(str.substr(begin, end)); + ret = std::stoi(str.substr(begin, end)); + if (ret < 0) { + throw std::invalid_argument("invalid semver: " + str); + } + const auto patch{ static_cast(ret) }; if (end == std::string::npos) { this->major_ = major; diff --git a/src/linyaps_box/utils/semver.h b/src/linyaps_box/utils/semver.h index 118e8b7..e63c021 100644 --- a/src/linyaps_box/utils/semver.h +++ b/src/linyaps_box/utils/semver.h @@ -19,14 +19,14 @@ class semver explicit semver(const std::string &str); - [[nodiscard]] unsigned int major() const; - [[nodiscard]] unsigned int minor() const; - [[nodiscard]] unsigned int patch() const; - [[nodiscard]] const std::string &prerelease() const; - [[nodiscard]] const std::string &build() const; - - [[nodiscard]] std::string to_string() const; - [[nodiscard]] bool is_compatible_with(const semver &other) const; + [[nodiscard]] auto major() const -> unsigned int; + [[nodiscard]] auto minor() const -> unsigned int; + [[nodiscard]] auto patch() const -> unsigned int; + [[nodiscard]] auto prerelease() const -> const std::string &; + [[nodiscard]] auto build() const -> const std::string &; + + [[nodiscard]] auto to_string() const -> std::string; + [[nodiscard]] auto is_compatible_with(const semver &other) const -> bool; private: unsigned int major_; diff --git a/src/linyaps_box/utils/socketpair.cpp b/src/linyaps_box/utils/socketpair.cpp index 99ef544..85dd311 100644 --- a/src/linyaps_box/utils/socketpair.cpp +++ b/src/linyaps_box/utils/socketpair.cpp @@ -3,3 +3,23 @@ // SPDX-License-Identifier: LGPL-3.0-or-later #include "linyaps_box/utils/socketpair.h" + +#include +#include + +namespace linyaps_box::utils { + +auto socketpair(int domain, int type, int protocol) -> std::pair +{ + std::array fds{}; + if (::socketpair(domain, type, protocol, fds.data()) == -1) { + throw std::system_error(errno, + std::system_category(), + "socketpair(" + std::to_string(domain) + ", " + std::to_string(type) + + ", " + std::to_string(protocol) + ")"); + } + + return std::make_pair(file_descriptor(fds[0]), file_descriptor(fds[1])); +} + +} // namespace linyaps_box::utils diff --git a/src/linyaps_box/utils/socketpair.h b/src/linyaps_box/utils/socketpair.h index be12179..0dba48c 100644 --- a/src/linyaps_box/utils/socketpair.h +++ b/src/linyaps_box/utils/socketpair.h @@ -4,25 +4,11 @@ #include "linyaps_box/utils/file_describer.h" -#include -#include - #include #include namespace linyaps_box::utils { -inline std::pair socketpair(int domain, int type, int protocol) -{ - std::array fds{}; - if (::socketpair(domain, type, protocol, fds.data()) == -1) { - throw std::system_error(errno, - std::system_category(), - "socketpair(" + std::to_string(domain) + ", " + std::to_string(type) - + ", " + std::to_string(protocol) + ")"); - } - - return std::make_pair(file_descriptor(fds[0]), file_descriptor(fds[1])); -} +auto socketpair(int domain, int type, int protocol) -> std::pair; } // namespace linyaps_box::utils diff --git a/src/linyaps_box/utils/touch.cpp b/src/linyaps_box/utils/touch.cpp index bb215f0..0264283 100644 --- a/src/linyaps_box/utils/touch.cpp +++ b/src/linyaps_box/utils/touch.cpp @@ -9,8 +9,8 @@ #include -linyaps_box::utils::file_descriptor linyaps_box::utils::touch(const file_descriptor &root, - const std::filesystem::path &path) +auto linyaps_box::utils::touch(const file_descriptor &root, const std::filesystem::path &path) + -> linyaps_box::utils::file_descriptor { LINYAPS_BOX_DEBUG() << "touch " << path << " at " << inspect_fd(root.get()); const auto fd = ::openat(root.get(), path.c_str(), O_CREAT | O_WRONLY, 0666); diff --git a/src/linyaps_box/utils/touch.h b/src/linyaps_box/utils/touch.h index 5bd8da1..d6dbc89 100644 --- a/src/linyaps_box/utils/touch.h +++ b/src/linyaps_box/utils/touch.h @@ -8,6 +8,6 @@ namespace linyaps_box::utils { -file_descriptor touch(const file_descriptor &root, const std::filesystem::path &path); +auto touch(const file_descriptor &root, const std::filesystem::path &path) -> file_descriptor; } // namespace linyaps_box::utils From b1c7fa13d8cf7baed7b869c44471afd266e0c0c4 Mon Sep 17 00:00:00 2001 From: ComixHe Date: Fri, 29 Aug 2025 17:43:55 +0800 Subject: [PATCH 07/26] fix: handle broken symlinks during mount destination creation When a destination file doesn't exist, the previous implementation couldn't distinguish between creation failure due to existing files vs other reasons. If both opening and creating fail, the destination is definitely a broken symlink. - Add recursive symlink resolution with depth limit (32) in create_destination_file() - Use O_NOFOLLOW to detect symlink during file creation - When creation fails with ELOOP, read symlink target and recursively create it - Replace filesystem functions with internal utils for consistent error handling - Add proper broken symlink detection and resolution logic This ensures mount destinations work correctly even when they point to broken symlinks, by creating the missing target files in the symlink chain. Signed-off-by: ComixHe --- src/linyaps_box/container.cpp | 57 +++++++++++++++--------- src/linyaps_box/utils/file_describer.cpp | 20 ++++++++- src/linyaps_box/utils/file_describer.h | 15 +++++++ src/linyaps_box/utils/symlink.cpp | 27 +++++++++++ src/linyaps_box/utils/symlink.h | 4 ++ src/linyaps_box/utils/touch.cpp | 8 ++-- src/linyaps_box/utils/touch.h | 5 ++- 7 files changed, 109 insertions(+), 27 deletions(-) diff --git a/src/linyaps_box/container.cpp b/src/linyaps_box/container.cpp index 92cdc2f..bf8e613 100644 --- a/src/linyaps_box/container.cpp +++ b/src/linyaps_box/container.cpp @@ -48,6 +48,7 @@ #endif constexpr auto propagations_flag = (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE); +constexpr auto max_symlink_depth{ 32 }; namespace linyaps_box { @@ -399,21 +400,40 @@ void do_remount(const remount_t &mount) } } -[[nodiscard]] linyaps_box::utils::file_descriptor create_destination_file( +[[nodiscard]] linyaps_box::utils::file_descriptor create_destination_directory( const linyaps_box::utils::file_descriptor &root, const std::filesystem::path &destination) { - LINYAPS_BOX_DEBUG() << "Creating file " << destination.string() << " under " + LINYAPS_BOX_DEBUG() << "Creating directory " << destination.string() << " under " << linyaps_box::utils::inspect_path(root.get()); - const auto &parent = linyaps_box::utils::mkdir(root, destination.parent_path()); - return linyaps_box::utils::touch(parent, destination.filename()); + return linyaps_box::utils::mkdir(root, destination); } -[[nodiscard]] linyaps_box::utils::file_descriptor create_destination_directory( - const linyaps_box::utils::file_descriptor &root, const std::filesystem::path &destination) +[[nodiscard]] linyaps_box::utils::file_descriptor +create_destination_file(const linyaps_box::utils::file_descriptor &root, + const std::filesystem::path &destination, + int max_depth) { - LINYAPS_BOX_DEBUG() << "Creating directory " << destination.string() << " under " + if (max_depth < 0) { + throw std::system_error(ELOOP, std::system_category(), "failed to create file"); + } + + LINYAPS_BOX_DEBUG() << "Creating file " << destination.string() << " under " << linyaps_box::utils::inspect_path(root.get()); - return linyaps_box::utils::mkdir(root, destination); + const auto &parent = create_destination_directory(root, destination.parent_path()); + + try { + auto ret = linyaps_box::utils::touch(parent, + destination.filename(), + O_CLOEXEC | O_CREAT | O_WRONLY | O_NOFOLLOW); + return ret; + } catch (std::system_error &e) { + if (e.code() != std::errc::too_many_symbolic_link_levels) { + throw; + } + + auto target = linyaps_box::utils::readlinkat(parent, destination.filename()); + return create_destination_file(root, target, max_depth - 1); + } } [[nodiscard]] linyaps_box::utils::file_descriptor @@ -421,7 +441,7 @@ create_destination_symlink(const linyaps_box::utils::file_descriptor &root, const std::filesystem::path &source, std::filesystem::path destination) { - auto ret = std::filesystem::read_symlink(source); + auto ret = linyaps_box::utils::readlink(source); auto parent = linyaps_box::utils::mkdir(root, destination.parent_path()); LINYAPS_BOX_DEBUG() << "Creating symlink " << destination.string() << " under " @@ -447,13 +467,8 @@ create_destination_symlink(const linyaps_box::utils::file_descriptor &root, + " already exists and is not a symlink"); } - std::array buf{}; - auto to = ::readlinkat(root.get(), destination.c_str(), buf.data(), buf.size()); - if (to == -1) { - throw std::system_error(errno, std::system_category(), "readlinkat"); - } - - if (std::string_view{ buf.data(), static_cast(to) } == ret) { + auto target = linyaps_box::utils::readlinkat(root, destination); + if (target == ret) { return linyaps_box::utils::open_at(root, destination, O_PATH | O_NOFOLLOW | O_CLOEXEC); } @@ -469,11 +484,9 @@ ensure_mount_destination(bool isDir, const linyaps_box::config::mount_t &mount) try { assert(mount.destination.has_value()); - auto open_flag = O_PATH; - if ((mount.flags & LINGYAPS_MS_NOSYMFOLLOW) != 0) { - open_flag |= O_NOFOLLOW; - } - + auto open_flag = O_PATH | O_CLOEXEC; + LINYAPS_BOX_DEBUG() << "Opening " << (isDir ? "directory " : "file ") + << mount.destination.value() << " under " << root.current_path(); return linyaps_box::utils::open_at(root, mount.destination.value(), open_flag); } catch (const std::system_error &e) { if (e.code().value() != ENOENT) { @@ -492,7 +505,7 @@ try { return create_destination_directory(root, path); } - return create_destination_file(root, path); + return create_destination_file(root, path, max_symlink_depth); } void do_propagation_mount(const linyaps_box::utils::file_descriptor &destination, diff --git a/src/linyaps_box/utils/file_describer.cpp b/src/linyaps_box/utils/file_describer.cpp index 179639f..81a282e 100644 --- a/src/linyaps_box/utils/file_describer.cpp +++ b/src/linyaps_box/utils/file_describer.cpp @@ -18,6 +18,15 @@ linyaps_box::utils::file_descriptor_closed_exception::file_descriptor_closed_exc linyaps_box::utils::file_descriptor_closed_exception::~file_descriptor_closed_exception() noexcept = default; +linyaps_box::utils::file_descriptor_invalid_exception::file_descriptor_invalid_exception( + const std::string &message) + : std::runtime_error(message) +{ +} + +linyaps_box::utils::file_descriptor_invalid_exception:: + ~file_descriptor_invalid_exception() noexcept = default; + linyaps_box::utils::file_descriptor::file_descriptor(int fd) : fd_(fd) { @@ -25,7 +34,7 @@ linyaps_box::utils::file_descriptor::file_descriptor(int fd) linyaps_box::utils::file_descriptor::~file_descriptor() { - if (fd_ == -1) { + if (fd_ < 0) { return; } @@ -58,6 +67,10 @@ auto linyaps_box::utils::file_descriptor::duplicate() const -> linyaps_box::util throw file_descriptor_closed_exception(); } + if (fd_ == AT_FDCWD) { + throw file_descriptor_invalid_exception("cannot duplicate AT_FDCWD"); + } + auto ret = dup(fd_); if (ret < 0) { throw std::system_error(errno, std::generic_category(), "fcntl"); @@ -134,3 +147,8 @@ auto linyaps_box::utils::file_descriptor::current_path() const noexcept -> std:: return path; } + +auto linyaps_box::utils::file_descriptor::cwd() -> file_descriptor +{ + return file_descriptor{ AT_FDCWD }; +} diff --git a/src/linyaps_box/utils/file_describer.h b/src/linyaps_box/utils/file_describer.h index a2d955a..556f9e9 100644 --- a/src/linyaps_box/utils/file_describer.h +++ b/src/linyaps_box/utils/file_describer.h @@ -23,6 +23,19 @@ class file_descriptor_closed_exception : public std::runtime_error ~file_descriptor_closed_exception() noexcept override; }; +class file_descriptor_invalid_exception : public std::runtime_error +{ +public: + explicit file_descriptor_invalid_exception(const std::string &message); + file_descriptor_invalid_exception(const file_descriptor_invalid_exception &) = default; + file_descriptor_invalid_exception(file_descriptor_invalid_exception &&) noexcept = default; + auto operator=(const file_descriptor_invalid_exception &) + -> file_descriptor_invalid_exception & = default; + auto operator=(file_descriptor_invalid_exception &&) noexcept + -> file_descriptor_invalid_exception & = default; + ~file_descriptor_invalid_exception() noexcept override; +}; + class file_descriptor { public: @@ -51,6 +64,8 @@ class file_descriptor [[nodiscard]] auto current_path() const noexcept -> std::filesystem::path; + static auto cwd() -> file_descriptor; + private: int fd_{ -1 }; }; diff --git a/src/linyaps_box/utils/symlink.cpp b/src/linyaps_box/utils/symlink.cpp index ab6f64f..e22eee0 100644 --- a/src/linyaps_box/utils/symlink.cpp +++ b/src/linyaps_box/utils/symlink.cpp @@ -6,6 +6,10 @@ #include "linyaps_box/utils/log.h" +#include + +#include + void linyaps_box::utils::symlink(const std::filesystem::path &target, const std::filesystem::path &link_path) { @@ -30,3 +34,26 @@ void linyaps_box::utils::symlink_at(const std::filesystem::path &target, throw std::system_error(errno, std::system_category(), "symlinkat"); } } + +std::filesystem::path linyaps_box::utils::readlink(const std::filesystem::path &path) +{ + std::error_code ec; + auto ret = std::filesystem::read_symlink(path, ec); + if (ec) { + throw std::system_error{ ec.value(), std::system_category(), ec.message() }; + } + + return ret; +} + +std::filesystem::path linyaps_box::utils::readlinkat(const file_descriptor &dirfd, + const std::filesystem::path &path) +{ + std::array buf{}; + auto ret = ::readlinkat(dirfd.get(), path.c_str(), buf.data(), PATH_MAX + 1); + if (ret == -1) { + throw std::system_error(errno, std::system_category(), "readlinkat"); + } + + return std::filesystem::path{ buf.data() }; +} diff --git a/src/linyaps_box/utils/symlink.h b/src/linyaps_box/utils/symlink.h index dcbab84..434300a 100644 --- a/src/linyaps_box/utils/symlink.h +++ b/src/linyaps_box/utils/symlink.h @@ -16,4 +16,8 @@ void symlink_at(const std::filesystem::path &target, const file_descriptor &dirfd, const std::filesystem::path &link_path); +std::filesystem::path readlink(const std::filesystem::path &path); + +std::filesystem::path readlinkat(const file_descriptor &dirfd, const std::filesystem::path &path); + } // namespace linyaps_box::utils diff --git a/src/linyaps_box/utils/touch.cpp b/src/linyaps_box/utils/touch.cpp index 0264283..becc89e 100644 --- a/src/linyaps_box/utils/touch.cpp +++ b/src/linyaps_box/utils/touch.cpp @@ -9,11 +9,13 @@ #include -auto linyaps_box::utils::touch(const file_descriptor &root, const std::filesystem::path &path) - -> linyaps_box::utils::file_descriptor +auto linyaps_box::utils::touch(const file_descriptor &root, + const std::filesystem::path &path, + int flag, + mode_t mode) -> linyaps_box::utils::file_descriptor { LINYAPS_BOX_DEBUG() << "touch " << path << " at " << inspect_fd(root.get()); - const auto fd = ::openat(root.get(), path.c_str(), O_CREAT | O_WRONLY, 0666); + const auto fd = ::openat(root.get(), path.c_str(), flag, mode); if (fd == -1) { throw std::system_error(errno, std::system_category(), diff --git a/src/linyaps_box/utils/touch.h b/src/linyaps_box/utils/touch.h index d6dbc89..0105680 100644 --- a/src/linyaps_box/utils/touch.h +++ b/src/linyaps_box/utils/touch.h @@ -8,6 +8,9 @@ namespace linyaps_box::utils { -auto touch(const file_descriptor &root, const std::filesystem::path &path) -> file_descriptor; +auto touch(const file_descriptor &root, + const std::filesystem::path &path, + int flag, + mode_t mode = 0700) -> file_descriptor; } // namespace linyaps_box::utils From 24a6a99f981f34ca59f17413dcec545b31b12a86 Mon Sep 17 00:00:00 2001 From: ComixHe Date: Mon, 1 Sep 2025 14:08:23 +0800 Subject: [PATCH 08/26] feat: implement preserve_fds support and fix file descriptor handling - Add --preserve-fds command line option for runtime - Refactor container creation with unified options structure - Improve file_descriptor class API Signed-off-by: ComixHe --- src/linyaps_box/command/options.cpp | 4 +++ src/linyaps_box/command/options.h | 1 + src/linyaps_box/command/run.cpp | 11 +++---- src/linyaps_box/container.cpp | 41 ++++++++++++++---------- src/linyaps_box/container.h | 24 +++++++++----- src/linyaps_box/runtime.cpp | 6 ++-- src/linyaps_box/runtime.h | 8 ----- src/linyaps_box/utils/file_describer.cpp | 8 +++-- src/linyaps_box/utils/file_describer.h | 3 +- 9 files changed, 60 insertions(+), 46 deletions(-) diff --git a/src/linyaps_box/command/options.cpp b/src/linyaps_box/command/options.cpp index bf0f2e4..c3a7bf5 100644 --- a/src/linyaps_box/command/options.cpp +++ b/src/linyaps_box/command/options.cpp @@ -61,6 +61,10 @@ linyaps_box::command::options linyaps_box::command::parse(int argc, char *argv[] cmd_run->add_option("-b,--bundle", run_opt.bundle, "Path to the OCI bundle")->default_val("."); cmd_run->add_option("-f,--config", run_opt.config, "Override the configuration file to use") ->default_val("config.json"); + cmd_run->add_option("--preserve-fds", + run_opt.preserve_fds, + "Pass N additional file descriptors to the container") + ->default_val(0); exec_options exec_opt{ options.global }; auto *cmd_exec = app.add_subcommand("exec", "Exec a command in a running container") diff --git a/src/linyaps_box/command/options.h b/src/linyaps_box/command/options.h index 6594c85..c1c6d8a 100644 --- a/src/linyaps_box/command/options.h +++ b/src/linyaps_box/command/options.h @@ -62,6 +62,7 @@ struct run_options std::string ID; std::string bundle; std::string config; + uint preserve_fds; }; struct kill_options diff --git a/src/linyaps_box/command/run.cpp b/src/linyaps_box/command/run.cpp index 932686e..e15fad3 100644 --- a/src/linyaps_box/command/run.cpp +++ b/src/linyaps_box/command/run.cpp @@ -13,13 +13,12 @@ auto linyaps_box::command::run(const struct run_options &options) -> int std::unique_ptr dir = std::make_unique(options.global_.get().root); runtime_t runtime(std::move(dir)); - runtime_t::create_container_options_t create_container_options; - create_container_options.bundle = options.bundle; - create_container_options.config = options.config; - create_container_options.ID = options.ID; - create_container_options.manager = options.global_.get().manager; + const create_container_options_t create_container_options{ options.global_.get().manager, + options.preserve_fds, + options.ID, + options.bundle, + options.config }; auto container = runtime.create_container(create_container_options); - return container.run(container.get_config().process); } diff --git a/src/linyaps_box/container.cpp b/src/linyaps_box/container.cpp index bf8e613..5ae32a6 100644 --- a/src/linyaps_box/container.cpp +++ b/src/linyaps_box/container.cpp @@ -1655,11 +1655,17 @@ try { auto &args = *static_cast(data); - assert(args.socket.get() >= 0); - close_other_fds({ STDIN_FILENO, - STDOUT_FILENO, - STDERR_FILENO, - static_cast(args.socket.get()) }); + assert(args.self_socket.get() >= 0); + std::set except_fds{ + STDIN_FILENO, + STDOUT_FILENO, + STDERR_FILENO, + }; + for (uint fd = 0; fd < args.container->preserve_fds(); ++fd) { + except_fds.insert(fd + 3); + } + except_fds.insert(static_cast(args.socket.get())); + close_other_fds(std::move(except_fds)); const auto &container = *args.container; const auto &process = *args.process; @@ -1837,14 +1843,16 @@ std::tuple start_container_process( namespaces = config.linux->namespaces; } - int clone_flag = runtime_ns::generate_clone_flag(namespaces); - clone_fn_args args = { &container, &process, std::move(sockets.second) }; + const int clone_flag = runtime_ns::generate_clone_flag(namespaces); + clone_fn_args args = { &container, + &process, + linyaps_box::utils::file_descriptor{ sockets.second.get() } }; LINYAPS_BOX_DEBUG() << "OCI runtime in runtime namespace: PID=" << getpid() << " PIDNS=" << linyaps_box::utils::get_pid_namespace(); - child_stack stack; - int child_pid = clone(container_ns::clone_fn, stack.top(), clone_flag, (void *)&args); + const child_stack stack; + const int child_pid = clone(container_ns::clone_fn, stack.top(), clone_flag, (void *)&args); if (child_pid < 0) { throw std::runtime_error("clone failed"); } @@ -2307,14 +2315,13 @@ void poststop_hooks(const linyaps_box::container &container) noexcept } // namespace linyaps_box::container::container(const status_directory &status_dir, - const std::string &id, - const std::filesystem::path &bundle, - std::filesystem::path config, - cgroup_manager_t manager) - : container_ref(status_dir, id) - , bundle(bundle) + const create_container_options_t &options) + : container_ref(status_dir, options.ID) + , preserve_fds_(options.preserve_fds) , data(new linyaps_box::container_data) + , bundle(options.bundle) { + auto config = options.config; if (config.is_relative()) { config = bundle / config; } @@ -2340,7 +2347,7 @@ linyaps_box::container::container(const status_directory &status_dir, { container_status_t status; status.oci_version = linyaps_box::config::oci_version; - status.ID = id; + status.ID = options.ID; status.PID = getpid(); status.status = container_status_t::runtime_status::CREATING; status.bundle = bundle; @@ -2353,7 +2360,7 @@ linyaps_box::container::container(const status_directory &status_dir, this->status_dir().write(status); } - switch (manager) { + switch (options.manager) { case cgroup_manager_t::disabled: { this->manager = std::make_unique(); } break; diff --git a/src/linyaps_box/container.h b/src/linyaps_box/container.h index 0bfed33..db1f368 100644 --- a/src/linyaps_box/container.h +++ b/src/linyaps_box/container.h @@ -13,14 +13,19 @@ namespace linyaps_box { struct container_data; +struct create_container_options_t +{ + cgroup_manager_t manager; + uint preserve_fds; + std::string ID; + std::filesystem::path bundle; + std::filesystem::path config; +}; + class container final : public container_ref { public: - container(const status_directory &status_dir, - const std::string &id, - const std::filesystem::path &bundle, - std::filesystem::path config, - cgroup_manager_t manager); + container(const status_directory &status_dir, const create_container_options_t &options); container(const container &) = delete; auto operator=(const container &) -> container & = delete; @@ -38,14 +43,17 @@ class container final : public container_ref [[nodiscard]] auto host_uid() const noexcept { return host_uid_; } + [[nodiscard]] auto preserve_fds() const noexcept { return preserve_fds_; } + private: void cgroup_preenter(const cgroup_options &options, utils::file_descriptor &dirfd); - std::filesystem::path bundle; - linyaps_box::config config; - std::unique_ptr manager; + uint preserve_fds_; gid_t host_gid_; uid_t host_uid_; container_data *data{ nullptr }; + std::filesystem::path bundle; + std::unique_ptr manager; + linyaps_box::config config; }; } // namespace linyaps_box diff --git a/src/linyaps_box/runtime.cpp b/src/linyaps_box/runtime.cpp index cc292e9..3f88027 100644 --- a/src/linyaps_box/runtime.cpp +++ b/src/linyaps_box/runtime.cpp @@ -27,8 +27,8 @@ auto linyaps_box::runtime_t::containers() return containers; } -auto linyaps_box::runtime_t::create_container( - const linyaps_box::runtime_t::create_container_options_t &options) -> linyaps_box::container +auto linyaps_box::runtime_t::create_container(const create_container_options_t &options) + -> linyaps_box::container { - return { *this->status_dir_, options.ID, options.bundle, options.config, options.manager }; + return { *this->status_dir_, options }; } diff --git a/src/linyaps_box/runtime.h b/src/linyaps_box/runtime.h index 177e1c7..a219b65 100644 --- a/src/linyaps_box/runtime.h +++ b/src/linyaps_box/runtime.h @@ -19,14 +19,6 @@ class runtime_t explicit runtime_t(std::unique_ptr &&status_dir); auto containers() -> std::unordered_map; - struct create_container_options_t - { - std::filesystem::path bundle; - std::filesystem::path config; - std::string ID; - cgroup_manager_t manager; - }; - auto create_container(const create_container_options_t &options) -> container; private: diff --git a/src/linyaps_box/utils/file_describer.cpp b/src/linyaps_box/utils/file_describer.cpp index 81a282e..c7e9983 100644 --- a/src/linyaps_box/utils/file_describer.cpp +++ b/src/linyaps_box/utils/file_describer.cpp @@ -48,12 +48,16 @@ linyaps_box::utils::file_descriptor::file_descriptor(file_descriptor &&other) no *this = std::move(other); } -auto linyaps_box::utils::file_descriptor::release() && noexcept -> int +auto linyaps_box::utils::file_descriptor::release() -> void { int ret = -1; std::swap(ret, fd_); - return ret; + if (::close(ret) < 0) { + auto msg{ "failed to close file descriptor " + std::to_string(ret) + ": " + + ::strerror(errno) }; + throw file_descriptor_invalid_exception(msg); + } } auto linyaps_box::utils::file_descriptor::get() const noexcept -> int diff --git a/src/linyaps_box/utils/file_describer.h b/src/linyaps_box/utils/file_describer.h index 556f9e9..af8d336 100644 --- a/src/linyaps_box/utils/file_describer.h +++ b/src/linyaps_box/utils/file_describer.h @@ -47,12 +47,11 @@ class file_descriptor auto operator=(const file_descriptor &) -> file_descriptor & = delete; file_descriptor(file_descriptor &&other) noexcept; - auto operator=(file_descriptor &&other) noexcept -> file_descriptor &; [[nodiscard]] auto get() const noexcept -> int; - auto release() && noexcept -> int; + auto release() -> void; [[nodiscard]] auto duplicate() const -> file_descriptor; From 4ad30a7efb832fef20f5a4241901093d57fbecb0 Mon Sep 17 00:00:00 2001 From: ComixHe Date: Fri, 5 Sep 2025 14:11:14 +0800 Subject: [PATCH 09/26] fix: correct variable name Fixes #115 Signed-off-by: ComixHe --- src/linyaps_box/container.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/linyaps_box/container.cpp b/src/linyaps_box/container.cpp index 5ae32a6..f0ac6ee 100644 --- a/src/linyaps_box/container.cpp +++ b/src/linyaps_box/container.cpp @@ -1655,7 +1655,7 @@ try { auto &args = *static_cast(data); - assert(args.self_socket.get() >= 0); + assert(args.socket.get() >= 0); std::set except_fds{ STDIN_FILENO, STDOUT_FILENO, From 3b94fbcf43a1ea3da9340af1b75f63e32e421be7 Mon Sep 17 00:00:00 2001 From: ComixHe Date: Thu, 11 Sep 2025 17:44:59 +0800 Subject: [PATCH 10/26] fix(deps): upgrade CLI11 to 2.5.0 to resolve bug in argument parsing See https://github.com/CLIUtils/CLI11/commit/7ff65c16f272ea8f0d98bb6458740f626c8924cb Signed-off-by: ComixHe --- CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b350de5..3f32b99 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -237,7 +237,7 @@ if(linyaps-box_ENABLE_CPM) OPTIONS "JSON_BuildTests OFF") CPMFindPackage( NAME CLI11 - VERSION 2.4.1 + VERSION 2.5.0 GITHUB_REPOSITORY CLIUtils/CLI11 GIT_TAG v2.5.0 EXCLUDE_FROM_ALL ON @@ -256,12 +256,12 @@ endif() list(APPEND linyaps-box_LIBRARY_LINK_LIBRARIES PUBLIC nlohmann_json::nlohmann_json) -find_package(CLI11 2.4.1 QUIET) +find_package(CLI11 2.5.0 QUIET) if(NOT CLI11_FOUND) add_subdirectory(external/CLI11) list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake.external/CLI11") - find_package(CLI11 2.4.1 REQUIRED) + find_package(CLI11 2.5.0 REQUIRED) message(STATUS "use vendor CLI11 ${CLI11_VERSION}") endif() From 9204ffba0c0984e1acfaa73048039821c50f824f Mon Sep 17 00:00:00 2001 From: ComixHe Date: Mon, 15 Sep 2025 14:16:56 +0800 Subject: [PATCH 11/26] fix: use O_PATH flag when masking paths to avoid permission issues Signed-off-by: ComixHe --- src/linyaps_box/container.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/linyaps_box/container.cpp b/src/linyaps_box/container.cpp index f0ac6ee..26652e5 100644 --- a/src/linyaps_box/container.cpp +++ b/src/linyaps_box/container.cpp @@ -318,6 +318,7 @@ void syscall_mount(const char *_special_file, if (_dir == nullptr) { return "nullptr"; } + if (auto str = std::string_view{ _dir }; str.rfind(fd_prefix, 0) == 0) { return linyaps_box::utils::inspect_fd(std::stoi(str.data() + fd_prefix.size())); } @@ -790,6 +791,8 @@ class mounter return; } + LINYAPS_BOX_DEBUG() << "make readonly paths"; + for (const auto &path : *linux->readonly_paths) { linyaps_box::utils::file_descriptor dst; try { @@ -836,10 +839,14 @@ class mounter return; } + LINYAPS_BOX_DEBUG() << "make masked paths"; + for (const auto &path : *linux->masked_paths) { linyaps_box::utils::file_descriptor dst; try { - dst = linyaps_box::utils::open_at(root, path); + // we only need to open a fd to refer to the path + // so O_PATH is sufficient. + dst = linyaps_box::utils::open_at(root, path, O_PATH | O_CLOEXEC); } catch (const std::system_error &e) { if (auto err = e.code().value(); err == ENOENT || err == EACCES) { continue; From 0e5def0fe24405e73400e069e6a20c8903a61168 Mon Sep 17 00:00:00 2001 From: ComixHe Date: Mon, 15 Sep 2025 14:29:09 +0800 Subject: [PATCH 12/26] refactor: change the default open flag make O_PATH as the default flag. Signed-off-by: ComixHe --- src/linyaps_box/utils/open_file.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/linyaps_box/utils/open_file.h b/src/linyaps_box/utils/open_file.h index 2eb444d..7063753 100644 --- a/src/linyaps_box/utils/open_file.h +++ b/src/linyaps_box/utils/open_file.h @@ -12,12 +12,12 @@ namespace linyaps_box::utils { -auto open(const std::filesystem::path &path, int flag = O_RDONLY, mode_t mode = 0) +auto open(const std::filesystem::path &path, int flag = O_PATH | O_CLOEXEC, mode_t mode = 0) -> file_descriptor; auto open_at(const file_descriptor &root, const std::filesystem::path &path, - int flag = O_RDONLY, + int flag = O_PATH | O_CLOEXEC, mode_t mode = 0) -> file_descriptor; } // namespace linyaps_box::utils From 881bcc93c0cb88ed5aca38b79d5651e3b57c51c7 Mon Sep 17 00:00:00 2001 From: ComixHe Date: Thu, 9 Oct 2025 15:18:13 +0800 Subject: [PATCH 13/26] fix: move the one of sockpairs to child container process Signed-off-by: ComixHe --- src/linyaps_box/container.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/linyaps_box/container.cpp b/src/linyaps_box/container.cpp index 26652e5..c427d24 100644 --- a/src/linyaps_box/container.cpp +++ b/src/linyaps_box/container.cpp @@ -1680,6 +1680,7 @@ try { auto rootfs = container.get_config().root.path; if (rootfs.is_relative()) { + LINYAPS_BOX_DEBUG() << "rootfs is relative based on bundle path:" << container.get_bundle(); rootfs = std::filesystem::canonical(container.get_bundle() / rootfs); } @@ -1853,7 +1854,7 @@ std::tuple start_container_process( const int clone_flag = runtime_ns::generate_clone_flag(namespaces); clone_fn_args args = { &container, &process, - linyaps_box::utils::file_descriptor{ sockets.second.get() } }; + std::move(sockets.second)}; LINYAPS_BOX_DEBUG() << "OCI runtime in runtime namespace: PID=" << getpid() << " PIDNS=" << linyaps_box::utils::get_pid_namespace(); From 53f0e1e8350649bdd7d1cf940386f1c0568325d7 Mon Sep 17 00:00:00 2001 From: "deepsource-autofix[bot]" <62050782+deepsource-autofix[bot]@users.noreply.github.com> Date: Thu, 9 Oct 2025 07:20:22 +0000 Subject: [PATCH 14/26] style: format code with ClangFormat and Prettier This commit fixes the style issues introduced in 881bcc9 according to the output from ClangFormat and Prettier. Details: None --- src/linyaps_box/container.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/linyaps_box/container.cpp b/src/linyaps_box/container.cpp index c427d24..f9e3376 100644 --- a/src/linyaps_box/container.cpp +++ b/src/linyaps_box/container.cpp @@ -1852,9 +1852,7 @@ std::tuple start_container_process( } const int clone_flag = runtime_ns::generate_clone_flag(namespaces); - clone_fn_args args = { &container, - &process, - std::move(sockets.second)}; + clone_fn_args args = { &container, &process, std::move(sockets.second) }; LINYAPS_BOX_DEBUG() << "OCI runtime in runtime namespace: PID=" << getpid() << " PIDNS=" << linyaps_box::utils::get_pid_namespace(); From 08b790480de8c6dba9f50c160a7f1f997281a52a Mon Sep 17 00:00:00 2001 From: ComixHe Date: Sat, 11 Oct 2025 10:40:09 +0800 Subject: [PATCH 15/26] feat: allow cn.org.linyaps.runtime.ns_last_pid extension failed if /proc/sys/kernel/ns_last_pid doesn't exist, skip this extension. Signed-off-by: ComixHe --- src/linyaps_box/container.cpp | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/linyaps_box/container.cpp b/src/linyaps_box/container.cpp index f9e3376..9cca48d 100644 --- a/src/linyaps_box/container.cpp +++ b/src/linyaps_box/container.cpp @@ -1594,8 +1594,13 @@ void processing_extensions(const linyaps_box::container &container) LINYAPS_BOX_DEBUG() << "Processing container extensions"; // ext_ns_last_pid - if (auto it = config.annotations->find("cn.org.linyaps.runtime.ns_last_pid"); - it != config.annotations->end()) { + // This file may not exist if the kernel config CONFIG_CHECKPOINT_RESTORE is not enabled + // and this feature originally was used for userspace checkpoint/restore + // we use this feature for avoiding two process has the same pid. + // e.g some application will register a tray through dbus and use the pid as the part of + // dbus object path, if two process has the same pid, the dbus object path will conflict + auto it = config.annotations->find("cn.org.linyaps.runtime.ns_last_pid"); + while (it != config.annotations->end()) { LINYAPS_BOX_DEBUG() << "Processing ns_last_pid extension: " << it->second; // Validate input is a valid pid_t number @@ -1613,7 +1618,13 @@ void processing_extensions(const linyaps_box::container &container) throw std::runtime_error("parse ns_last_pid " + it->second + " failed: " + e.what()); } - std::ofstream ofs("/proc/sys/kernel/ns_last_pid"); + // ignore ns_last_pid if the file does not exist + auto ns_last_pid = std::filesystem::path{ "/proc/sys/kernel/ns_last_pid" }; + if (!std::filesystem::exists(ns_last_pid)) { + break; + } + + std::ofstream ofs(ns_last_pid); if (!ofs) { throw std::system_error(errno, std::generic_category(), @@ -1628,6 +1639,7 @@ void processing_extensions(const linyaps_box::container &container) } LINYAPS_BOX_DEBUG() << "Successfully set ns_last_pid to " << it->second; + break; } LINYAPS_BOX_DEBUG() << "Container extensions processing completed"; From 04aface6176a1bd56a448be584c7773d6e8a155e Mon Sep 17 00:00:00 2001 From: ComixHe Date: Mon, 13 Oct 2025 11:26:07 +0800 Subject: [PATCH 16/26] chore(tools): add clang-format script for formatting C++ sources Signed-off-by: ComixHe --- tools/format.sh | 83 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100755 tools/format.sh diff --git a/tools/format.sh b/tools/format.sh new file mode 100755 index 0000000..8f1147c --- /dev/null +++ b/tools/format.sh @@ -0,0 +1,83 @@ +#!/usr/bin/env bash + +# SPDX-FileCopyrightText: 2022-2025 UnionTech Software Technology Co., Ltd. +# +# SPDX-License-Identifier: LGPL-3.0-or-later + +# tools/format.sh +# Format all C/C++ source files in the project using clang-format. +# +# Usage: +# ./tools/format.sh # Use system default clang-format +# ./tools/format.sh clang-format-17 # Use a specific clang-format binary +# +# The script automatically skips common build and third-party directories. + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +ROOT_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)" +CLANG_FORMAT="${1:-clang-format}" + +# Check clang-format availability +if ! command -v "${CLANG_FORMAT}" >/dev/null 2>&1; then + echo "Error: ${CLANG_FORMAT} not found. Please install clang-format." >&2 + exit 1 +fi + +# --- Project root validation --- +# Criteria for identifying a valid project root: +# 1. Has CMakeLists.txt, or +# 2. Has .clang-format, or +# 3. Contains app/, src/, or tests/ directories + +VALID_ROOT=false +if [[ -f "${ROOT_DIR}/CMakeLists.txt" ]]; then + VALID_ROOT=true +elif [[ -f "${ROOT_DIR}/.clang-format" ]]; then + VALID_ROOT=true +else + for d in app src tests; do + if [ -d "${ROOT_DIR}/${d}" ]; then + VALID_ROOT=true + break + fi + done +fi + +if [[ ${VALID_ROOT} != true ]]; then + echo "Error: This script must be run inside a valid C++ project root." + echo "Expected to find one of the following in ${ROOT_DIR}:" + echo " - CMakeLists.txt" + echo " - .clang-format or _clang-format" + echo " - app/, src/, or tests/ directories" + exit 1 +fi +# --- End project root validation --- + +CLANG_FORMAT_VERSION=$("${CLANG_FORMAT}" --version | head -n 1 | cut -d ' ' -f 3) +echo "Using clang-format: ${CLANG_FORMAT_VERSION}" +echo "Project root: ${ROOT_DIR}" + +# Only search for .cpp and .h files under app, src, and tests directories +dirs=() +for d in app src tests; do + if [[ -d "${ROOT_DIR}/${d}" ]]; then + dirs+=("${ROOT_DIR}/${d}") + fi +done + +if [[ ${#dirs[@]} -eq 0 ]]; then + echo "Warning: No app/, src/, or tests/ directories found under ${ROOT_DIR}." + exit 0 +fi + +find "${dirs[@]}" \ + \( -name "*.cpp" -o -name "*.h" \) \ + -type f -print | + while read -r file; do + echo "Formatting: ${file}" + "${CLANG_FORMAT}" -i "${file}" + done + +echo "Formatting completed." From 11face2e942a0fb5382aaacd4948384f5016dc96 Mon Sep 17 00:00:00 2001 From: ComixHe Date: Mon, 13 Oct 2025 11:27:00 +0800 Subject: [PATCH 17/26] chore: formatting codes Signed-off-by: ComixHe --- tests/ll-box-ut/src/test.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/ll-box-ut/src/test.cpp b/tests/ll-box-ut/src/test.cpp index db02749..e3bf8b4 100644 --- a/tests/ll-box-ut/src/test.cpp +++ b/tests/ll-box-ut/src/test.cpp @@ -22,6 +22,7 @@ #pragma GCC diagnostic pop #endif -TEST(LINYAPS_BOX, Placeholder1) { - EXPECT_EQ(1, 1); +TEST(LINYAPS_BOX, Placeholder1) +{ + EXPECT_EQ(1, 1); } From 72ca241a20106252b141fb57a13491c056233fb5 Mon Sep 17 00:00:00 2001 From: ComixHe Date: Wed, 15 Oct 2025 15:21:48 +0800 Subject: [PATCH 18/26] chore: update CPM.cmake to 0.42.0 Signed-off-by: ComixHe --- cmake/CPM.cmake | 92 +++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 82 insertions(+), 10 deletions(-) diff --git a/cmake/CPM.cmake b/cmake/CPM.cmake index eea2921..3636ee5 100644 --- a/cmake/CPM.cmake +++ b/cmake/CPM.cmake @@ -45,7 +45,7 @@ endif() if(DEFINED EXTRACTED_CPM_VERSION) set(CURRENT_CPM_VERSION "${EXTRACTED_CPM_VERSION}${CPM_DEVELOPMENT}") else() - set(CURRENT_CPM_VERSION 0.40.8) + set(CURRENT_CPM_VERSION 0.42.0) endif() get_filename_component(CPM_CURRENT_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}" REALPATH) @@ -202,6 +202,60 @@ function(cpm_package_name_from_git_uri URI RESULT) endif() endfunction() +# Find the shortest hash that can be used eg, if origin_hash is +# cccb77ae9609d2768ed80dd42cec54f77b1f1455 the following files will be checked, until one is found +# that is either empty (allowing us to assign origin_hash), or whose contents matches ${origin_hash} +# +# * .../cccb.hash +# * .../cccb77ae.hash +# * .../cccb77ae9609.hash +# * .../cccb77ae9609d276.hash +# * etc +# +# We will be able to use a shorter path with very high probability, but in the (rare) event that the +# first couple characters collide, we will check longer and longer substrings. +function(cpm_get_shortest_hash source_cache_dir origin_hash short_hash_output_var) + # for compatibility with caches populated by a previous version of CPM, check if a directory using + # the full hash already exists + if(EXISTS "${source_cache_dir}/${origin_hash}") + set(${short_hash_output_var} + "${origin_hash}" + PARENT_SCOPE + ) + return() + endif() + + foreach(len RANGE 4 40 4) + string(SUBSTRING "${origin_hash}" 0 ${len} short_hash) + set(hash_lock ${source_cache_dir}/${short_hash}.lock) + set(hash_fp ${source_cache_dir}/${short_hash}.hash) + # Take a lock, so we don't have a race condition with another instance of cmake. We will release + # this lock when we can, however, if there is an error, we want to ensure it gets released on + # it's own on exit from the function. + file(LOCK ${hash_lock} GUARD FUNCTION) + + # Load the contents of .../${short_hash}.hash + file(TOUCH ${hash_fp}) + file(READ ${hash_fp} hash_fp_contents) + + if(hash_fp_contents STREQUAL "") + # Write the origin hash + file(WRITE ${hash_fp} ${origin_hash}) + file(LOCK ${hash_lock} RELEASE) + break() + elseif(hash_fp_contents STREQUAL origin_hash) + file(LOCK ${hash_lock} RELEASE) + break() + else() + file(LOCK ${hash_lock} RELEASE) + endif() + endforeach() + set(${short_hash_output_var} + "${short_hash}" + PARENT_SCOPE + ) +endfunction() + # Try to infer package name and version from a url function(cpm_package_name_and_ver_from_url url outName outVer) if(url MATCHES "[/\\?]([a-zA-Z0-9_\\.-]+)\\.(tar|tar\\.gz|tar\\.bz2|zip|ZIP)(\\?|/|$)") @@ -594,14 +648,6 @@ endfunction() function(CPMAddPackage) cpm_set_policies() - list(LENGTH ARGN argnLength) - if(argnLength EQUAL 1) - cpm_parse_add_package_single_arg("${ARGN}" ARGN) - - # The shorthand syntax implies EXCLUDE_FROM_ALL and SYSTEM - set(ARGN "${ARGN};EXCLUDE_FROM_ALL;YES;SYSTEM;YES;") - endif() - set(oneValueArgs NAME FORCE @@ -624,10 +670,26 @@ function(CPMAddPackage) set(multiValueArgs URL OPTIONS DOWNLOAD_COMMAND PATCHES) + list(LENGTH ARGN argnLength) + + # Parse single shorthand argument + if(argnLength EQUAL 1) + cpm_parse_add_package_single_arg("${ARGN}" ARGN) + + # The shorthand syntax implies EXCLUDE_FROM_ALL and SYSTEM + set(ARGN "${ARGN};EXCLUDE_FROM_ALL;YES;SYSTEM;YES;") + + # Parse URI shorthand argument + elseif(argnLength GREATER 1 AND "${ARGV0}" STREQUAL "URI") + list(REMOVE_AT ARGN 0 1) # remove "URI gh:<...>@version#tag" + cpm_parse_add_package_single_arg("${ARGV1}" ARGV0) + + set(ARGN "${ARGV0};EXCLUDE_FROM_ALL;YES;SYSTEM;YES;${ARGN}") + endif() + cmake_parse_arguments(CPM_ARGS "" "${oneValueArgs}" "${multiValueArgs}" "${ARGN}") # Set default values for arguments - if(NOT DEFINED CPM_ARGS_VERSION) if(DEFINED CPM_ARGS_GIT_TAG) cpm_get_version_from_git_tag("${CPM_ARGS_GIT_TAG}" CPM_ARGS_VERSION) @@ -798,9 +860,19 @@ function(CPMAddPackage) set(download_directory ${CPM_SOURCE_CACHE}/${lower_case_name}/${CPM_ARGS_CUSTOM_CACHE_KEY}) elseif(CPM_USE_NAMED_CACHE_DIRECTORIES) string(SHA1 origin_hash "${origin_parameters};NEW_CACHE_STRUCTURE_TAG") + cpm_get_shortest_hash( + "${CPM_SOURCE_CACHE}/${lower_case_name}" # source cache directory + "${origin_hash}" # Input hash + origin_hash # Computed hash + ) set(download_directory ${CPM_SOURCE_CACHE}/${lower_case_name}/${origin_hash}/${CPM_ARGS_NAME}) else() string(SHA1 origin_hash "${origin_parameters}") + cpm_get_shortest_hash( + "${CPM_SOURCE_CACHE}/${lower_case_name}" # source cache directory + "${origin_hash}" # Input hash + origin_hash # Computed hash + ) set(download_directory ${CPM_SOURCE_CACHE}/${lower_case_name}/${origin_hash}) endif() # Expand `download_directory` relative path. This is important because EXISTS doesn't work for From 56bb0d1e6b235615c1ca89f90942c31fa0382332 Mon Sep 17 00:00:00 2001 From: ComixHe Date: Wed, 15 Oct 2025 15:22:13 +0800 Subject: [PATCH 19/26] build: CPM is disabled by default Signed-off-by: ComixHe --- CMakeLists.txt | 11 +++++------ CMakePresets.json | 9 ++++++--- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3f32b99..68744bd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -91,7 +91,7 @@ set(linyaps-box_ACTIVE_LOG_LEVEL ) set(linyaps-box_ENABLE_CPM - ON + OFF CACHE BOOL "enable CPM") if(CMAKE_VERSION VERSION_LESS "3.14") @@ -105,11 +105,6 @@ set(linyaps-box_CPM_LOCAL_PACKAGES_ONLY OFF CACHE BOOL "use local packages only") -if(linyaps-box_CPM_LOCAL_PACKAGES_ONLY) - message(STATUS "CPM is disabled") - set(linyaps-box_ENABLE_CPM OFF) -endif() - # ============================================================================== set(linyaps-box_LIBRARY linyaps-box) @@ -228,6 +223,10 @@ if(linyaps-box_ENABLE_CPM) list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") include(CPM) + if (linyaps-box_CPM_LOCAL_PACKAGES_ONLY) + set(CPM_USE_LOCAL_PACKAGES ON) + endif() + CPMFindPackage( NAME nlohmann_json VERSION 3.11.3 diff --git a/CMakePresets.json b/CMakePresets.json index d6d16d6..5265a89 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -1,5 +1,5 @@ { - "version": 6, + "version": 10, "cmakeMinimumRequired": { "major": 3, "minor": 25, @@ -21,7 +21,8 @@ "linyaps-box_CPACK_PACKAGING_INSTALL_PREFIX": "", "linyaps-box_ENABLE_SMOKE_TESTS": true, "linyaps-box_DEFAULT_LOG_LEVEL": "7", - "linyaps-box_ACTIVE_LOG_LEVEL": "7" + "linyaps-box_ACTIVE_LOG_LEVEL": "7", + "linyaps-box_ENABLE_CPM": "ON" } }, { @@ -47,7 +48,9 @@ "CMAKE_COLOR_DIAGNOSTICS": true, "CMAKE_CXX_FLAGS": "-fno-asynchronous-unwind-tables -fdata-sections -ffunction-sections -flto=auto $env{CXXFLAGS}", "CMAKE_EXE_LINKER_FLAGS_INIT": "-Wl,--gc-sections,--strip-all,--exclude-libs,ALL -flto=auto", - "linyaps-box_STATIC": true + "linyaps-box_STATIC": true, + "linyaps-box_ENABLE_CPACK": "ON", + "linyaps-box_MAKE_RELEASE": "ON" } }, { From 613cc27af65a9036a91f08a66d0da0b2f855ad74 Mon Sep 17 00:00:00 2001 From: ComixHe Date: Mon, 20 Oct 2025 11:53:50 +0800 Subject: [PATCH 20/26] refactor: standardize preserve_fds type for better portability Change preserve_fds from uint to int type Signed-off-by: ComixHe --- src/linyaps_box/command/options.h | 2 +- src/linyaps_box/container.cpp | 2 +- src/linyaps_box/container.h | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/linyaps_box/command/options.h b/src/linyaps_box/command/options.h index c1c6d8a..de6b739 100644 --- a/src/linyaps_box/command/options.h +++ b/src/linyaps_box/command/options.h @@ -62,7 +62,7 @@ struct run_options std::string ID; std::string bundle; std::string config; - uint preserve_fds; + int preserve_fds; }; struct kill_options diff --git a/src/linyaps_box/container.cpp b/src/linyaps_box/container.cpp index 9cca48d..5f7fcfe 100644 --- a/src/linyaps_box/container.cpp +++ b/src/linyaps_box/container.cpp @@ -1680,7 +1680,7 @@ try { STDOUT_FILENO, STDERR_FILENO, }; - for (uint fd = 0; fd < args.container->preserve_fds(); ++fd) { + for (auto fd = 0; fd < args.container->preserve_fds(); ++fd) { except_fds.insert(fd + 3); } except_fds.insert(static_cast(args.socket.get())); diff --git a/src/linyaps_box/container.h b/src/linyaps_box/container.h index db1f368..5a8c638 100644 --- a/src/linyaps_box/container.h +++ b/src/linyaps_box/container.h @@ -16,7 +16,7 @@ struct container_data; struct create_container_options_t { cgroup_manager_t manager; - uint preserve_fds; + int preserve_fds; std::string ID; std::filesystem::path bundle; std::filesystem::path config; @@ -47,7 +47,7 @@ class container final : public container_ref private: void cgroup_preenter(const cgroup_options &options, utils::file_descriptor &dirfd); - uint preserve_fds_; + int preserve_fds_; gid_t host_gid_; uid_t host_uid_; container_data *data{ nullptr }; From 8f1b042421744499c645c532f54ea50e804302a1 Mon Sep 17 00:00:00 2001 From: ComixHe Date: Mon, 20 Oct 2025 14:44:27 +0800 Subject: [PATCH 21/26] refactor: change the type of mount flag to unsigned int Signed-off-by: ComixHe --- src/linyaps_box/container.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/linyaps_box/container.cpp b/src/linyaps_box/container.cpp index 5f7fcfe..0d9e791 100644 --- a/src/linyaps_box/container.cpp +++ b/src/linyaps_box/container.cpp @@ -42,6 +42,7 @@ #include #include #include +#include #ifdef LINYAPS_BOX_ENABLE_CAP #include @@ -121,7 +122,8 @@ std::ostream &operator<<(std::ostream &os, const sync_message message) struct MountFlag { - std::underlying_type_t flag; + // mount flag should be unsigned int due to MS_NOUSER (1U << 31) + unsigned int flag; std::string_view name; }; From 27c0ae9643011e395b2221b770f1b6a2bc1e2e1c Mon Sep 17 00:00:00 2001 From: ComixHe Date: Mon, 20 Oct 2025 16:00:25 +0800 Subject: [PATCH 22/26] refactor: remove __S_ISTYPE for improving portability __S_ISTYPE is glibc internal macro. Signed-off-by: ComixHe --- src/linyaps_box/container.cpp | 47 ++++++-------- src/linyaps_box/utils/fstat.cpp | 111 ++++++++++++++++++++++++++++++++ src/linyaps_box/utils/fstat.h | 6 ++ 3 files changed, 136 insertions(+), 28 deletions(-) diff --git a/src/linyaps_box/container.cpp b/src/linyaps_box/container.cpp index 0d9e791..9c0522d 100644 --- a/src/linyaps_box/container.cpp +++ b/src/linyaps_box/container.cpp @@ -42,7 +42,6 @@ #include #include #include -#include #ifdef LINYAPS_BOX_ENABLE_CAP #include @@ -1034,14 +1033,16 @@ class mounter void configure_device(const std::filesystem::path &destination, mode_t mode, - int type, + std::filesystem::file_type type, dev_t dev, uid_t uid, gid_t gid) { assert(destination.is_absolute()); - if (type != S_IFCHR && type != S_IFBLK && type != S_IFIFO) { + if (type != std::filesystem::file_type::character + && type != std::filesystem::file_type::block + && type != std::filesystem::file_type::fifo) { throw std::runtime_error("unsupported device type"); } @@ -1057,27 +1058,13 @@ class mounter if (destination_fd.has_value()) { // if already exists, check if it is a required device auto stat = linyaps_box::utils::lstatat(*destination_fd, ""); + auto cur_type = linyaps_box::utils::to_fs_file_type(stat.st_mode); bool satisfied{ true }; - if (__S_ISTYPE(stat.st_mode, type)) { - auto dump_mode = [](mode_t mode) { - if (S_ISCHR(mode)) { - return "Character"; - } - - if (S_ISBLK(mode)) { - return "Block"; - } - - if (S_ISFIFO(mode)) { - return "FIFO"; - } - - return "unknown"; - }; - + if (linyaps_box::utils::is_type(stat.st_mode, type)) { LINYAPS_BOX_DEBUG() << "the type of existing device: " << destination << " is not required\n" - << "expect " << dump_mode(mode) << ", got " << dump_mode(stat.st_mode); + << "expect " << linyaps_box::utils::to_string(type) << ", got " + << linyaps_box::utils::to_string(cur_type); satisfied = false; } @@ -1107,7 +1094,9 @@ class mounter try { auto path = destination.relative_path(); - linyaps_box::utils::mknodat(root, path, mode | type, dev); + auto f_type = static_cast(linyaps_box::utils::to_linux_file_type(type)); + + linyaps_box::utils::mknodat(root, path, mode | f_type, dev); auto new_dev = linyaps_box::utils::open_at(root, path, O_PATH); path = new_dev.proc_path(); @@ -1140,14 +1129,16 @@ class mounter LINYAPS_BOX_DEBUG() << "Configure default devices"; constexpr auto default_mode = 0666; + constexpr auto default_type = std::filesystem::file_type::character; auto uid = container.get_config().process.user.uid; auto gid = container.get_config().process.user.gid; - this->configure_device("/dev/null", default_mode, S_IFCHR, makedev(1, 3), uid, gid); - this->configure_device("/dev/zero", default_mode, S_IFCHR, makedev(1, 5), uid, gid); - this->configure_device("/dev/full", default_mode, S_IFCHR, makedev(1, 7), uid, gid); - this->configure_device("/dev/random", default_mode, S_IFCHR, makedev(1, 8), uid, gid); - this->configure_device("/dev/urandom", default_mode, S_IFCHR, makedev(1, 9), uid, gid); - this->configure_device("/dev/tty", default_mode, S_IFCHR, makedev(5, 0), uid, gid); + + this->configure_device("/dev/null", default_mode, default_type, makedev(1, 3), uid, gid); + this->configure_device("/dev/zero", default_mode, default_type, makedev(1, 5), uid, gid); + this->configure_device("/dev/full", default_mode, default_type, makedev(1, 7), uid, gid); + this->configure_device("/dev/random", default_mode, default_type, makedev(1, 8), uid, gid); + this->configure_device("/dev/urandom", default_mode, default_type, makedev(1, 9), uid, gid); + this->configure_device("/dev/tty", default_mode, default_type, makedev(5, 0), uid, gid); // bind mount /dev/pts/ptmx to /dev/ptmx // https://docs.kernel.org/filesystems/devpts.html diff --git a/src/linyaps_box/utils/fstat.cpp b/src/linyaps_box/utils/fstat.cpp index 85dbd74..935c124 100644 --- a/src/linyaps_box/utils/fstat.cpp +++ b/src/linyaps_box/utils/fstat.cpp @@ -4,6 +4,10 @@ #include "linyaps_box/utils/fstat.h" +#include "linyaps_box/utils/log.h" + +#include + namespace linyaps_box::utils { auto fstatat(const file_descriptor &fd, std::filesystem::path path, int flag) -> struct stat @@ -46,5 +50,112 @@ auto statfs(const file_descriptor &fd) -> struct statfs } return statbuf; + } + +auto +to_linux_file_type(std::filesystem::file_type type) noexcept -> int + +{ + switch (type) { + case std::filesystem::file_type::regular: + return S_IFREG; + case std::filesystem::file_type::directory: + return S_IFDIR; + case std::filesystem::file_type::symlink: + return S_IFLNK; + case std::filesystem::file_type::block: + return S_IFBLK; + case std::filesystem::file_type::character: + return S_IFCHR; + case std::filesystem::file_type::fifo: + return S_IFIFO; + case std::filesystem::file_type::socket: + return S_IFSOCK; + case std::filesystem::file_type::unknown: { + LINYAPS_BOX_WARNING() << "Try to convert unknown type to linux file type"; + return 0; + } + case std::filesystem::file_type::none: { + LINYAPS_BOX_DEBUG() << "Try to convert none type to linux file type"; + assert(false); + return -1; + } + case std::filesystem::file_type::not_found: { + LINYAPS_BOX_WARNING() << "Try to convert not_found type to linux file type"; + assert(false); + return -1; + } + default: { + LINYAPS_BOX_ERR() << "Try to convert unhandled file type " << static_cast(type) + << " to linux file type"; + assert(false); + return -1; + } + } +} + +auto to_fs_file_type(mode_t type) noexcept -> std::filesystem::file_type +{ + switch (type) { + case S_IFREG: + return std::filesystem::file_type::regular; + case S_IFDIR: + return std::filesystem::file_type::directory; + case S_IFLNK: + return std::filesystem::file_type::symlink; + case S_IFBLK: + return std::filesystem::file_type::block; + case S_IFCHR: + return std::filesystem::file_type::character; + case S_IFIFO: + return std::filesystem::file_type::fifo; + case S_IFSOCK: + return std::filesystem::file_type::socket; + default: + return std::filesystem::file_type::unknown; + } +} + +auto is_type(mode_t mode, std::filesystem::file_type type) noexcept -> bool +{ + auto f_type = to_linux_file_type(type); + if (f_type <= 0) { + return false; + } + + return is_type(mode, f_type); +} + +auto is_type(mode_t mode, mode_t type) noexcept -> bool +{ + return (mode & S_IFMT) == type; +} + +auto to_string(std::filesystem::file_type type) noexcept -> std::string_view +{ + switch (type) { + case std::filesystem::file_type::none: + return "None"; + case std::filesystem::file_type::not_found: + return "Not found"; + case std::filesystem::file_type::regular: + return "Regular"; + case std::filesystem::file_type::directory: + return "Directory"; + case std::filesystem::file_type::symlink: + return "Symlink"; + case std::filesystem::file_type::block: + return "Block"; + case std::filesystem::file_type::character: + return "Character"; + case std::filesystem::file_type::fifo: + return "FIFO"; + case std::filesystem::file_type::socket: + return "Socket"; + case std::filesystem::file_type::unknown: + return "Unknown"; + } +} + } // namespace linyaps_box::utils diff --git a/src/linyaps_box/utils/fstat.h b/src/linyaps_box/utils/fstat.h index 541cbf2..5a127a1 100644 --- a/src/linyaps_box/utils/fstat.h +++ b/src/linyaps_box/utils/fstat.h @@ -16,4 +16,10 @@ auto fstatat(const file_descriptor &fd, std::filesystem::path path, int flag) -> auto fstatat(const file_descriptor &fd, const std::filesystem::path &path) -> struct stat; auto lstatat(const file_descriptor &fd, const std::filesystem::path &path) -> struct stat; auto statfs(const file_descriptor &fd) -> struct statfs; + +auto to_linux_file_type(std::filesystem::file_type type) noexcept -> int; +auto to_fs_file_type(mode_t type) noexcept -> std::filesystem::file_type; +auto is_type(mode_t mode, std::filesystem::file_type type) noexcept -> bool; +auto is_type(mode_t mode, mode_t type) noexcept -> bool; +auto to_string(std::filesystem::file_type type) noexcept -> std::string_view; } // namespace linyaps_box::utils From 59ed24f214e987708daac77e72321b55ec4a9e21 Mon Sep 17 00:00:00 2001 From: ComixHe Date: Mon, 20 Oct 2025 16:11:00 +0800 Subject: [PATCH 23/26] refactor: add for mode_t - fix inconsistencies between function parameter implementations and declared types. - change the default permission of touched file. Signed-off-by: ComixHe --- src/linyaps_box/utils/fstat.cpp | 2 ++ src/linyaps_box/utils/mkdir.h | 2 ++ src/linyaps_box/utils/mknod.h | 2 ++ src/linyaps_box/utils/open_file.cpp | 2 +- src/linyaps_box/utils/touch.h | 4 +++- 5 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/linyaps_box/utils/fstat.cpp b/src/linyaps_box/utils/fstat.cpp index 935c124..97e6aa5 100644 --- a/src/linyaps_box/utils/fstat.cpp +++ b/src/linyaps_box/utils/fstat.cpp @@ -156,6 +156,8 @@ auto to_string(std::filesystem::file_type type) noexcept -> std::string_view case std::filesystem::file_type::unknown: return "Unknown"; } + + __builtin_unreachable(); } } // namespace linyaps_box::utils diff --git a/src/linyaps_box/utils/mkdir.h b/src/linyaps_box/utils/mkdir.h index 407475f..04ebf84 100644 --- a/src/linyaps_box/utils/mkdir.h +++ b/src/linyaps_box/utils/mkdir.h @@ -6,6 +6,8 @@ #include "linyaps_box/utils/file_describer.h" +#include + namespace linyaps_box::utils { auto mkdir(const file_descriptor &root, std::filesystem::path path, mode_t mode = 0755) diff --git a/src/linyaps_box/utils/mknod.h b/src/linyaps_box/utils/mknod.h index 4b00e61..e0dab3b 100644 --- a/src/linyaps_box/utils/mknod.h +++ b/src/linyaps_box/utils/mknod.h @@ -8,6 +8,8 @@ #include +#include + namespace linyaps_box::utils { void mknodat(const file_descriptor &root, const std::filesystem::path &path, diff --git a/src/linyaps_box/utils/open_file.cpp b/src/linyaps_box/utils/open_file.cpp index 0b8244a..20f3e8a 100644 --- a/src/linyaps_box/utils/open_file.cpp +++ b/src/linyaps_box/utils/open_file.cpp @@ -27,7 +27,7 @@ namespace { auto open_at_fallback(const linyaps_box::utils::file_descriptor &root, const std::filesystem::path &path, int flag, - uint mode) -> linyaps_box::utils::file_descriptor + mode_t mode) -> linyaps_box::utils::file_descriptor { LINYAPS_BOX_DEBUG() << "fallback openat " << path.c_str() << " at FD=" << root.get() << " with " << linyaps_box::utils::inspect_fcntl_or_open_flags( diff --git a/src/linyaps_box/utils/touch.h b/src/linyaps_box/utils/touch.h index 0105680..f1ffb0f 100644 --- a/src/linyaps_box/utils/touch.h +++ b/src/linyaps_box/utils/touch.h @@ -6,11 +6,13 @@ #include "linyaps_box/utils/file_describer.h" +#include + namespace linyaps_box::utils { auto touch(const file_descriptor &root, const std::filesystem::path &path, int flag, - mode_t mode = 0700) -> file_descriptor; + mode_t mode = 0644) -> file_descriptor; } // namespace linyaps_box::utils From caf2cec0d2a5f0d3bd527c941bc1dfbc7f8a4e75 Mon Sep 17 00:00:00 2001 From: ComixHe Date: Mon, 20 Oct 2025 16:18:40 +0800 Subject: [PATCH 24/26] refactor: Add conditional compilation protection for SIGCLD signal SIGCLD is a legacy signal in System V UNIX. Mapping it with #ifdef SIGCLD in str_to_signal function to improve cross-platform compatibility and avoid compilation errors on platforms where SIGCLD is not defined (e.g. musl). Signed-off-by: ComixHe --- src/linyaps_box/utils/platform.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/linyaps_box/utils/platform.cpp b/src/linyaps_box/utils/platform.cpp index 3500bb5..18ab929 100644 --- a/src/linyaps_box/utils/platform.cpp +++ b/src/linyaps_box/utils/platform.cpp @@ -26,7 +26,10 @@ auto str_to_signal(std::string_view str) -> int { "SIGTTIN", SIGTTIN }, { "SIGTTOU", SIGTTOU }, { "SIGURG", SIGURG }, { "SIGUSR1", SIGUSR1 }, { "SIGUSR2", SIGUSR2 }, { "SIGVTALRM", SIGVTALRM }, { "SIGWINCH", SIGWINCH }, { "SIGXCPU", SIGXCPU }, { "SIGXFSZ", SIGXFSZ }, - { "SIGIO", SIGIO }, { "SIGIOT", SIGIOT }, { "SIGCLD", SIGCLD }, + { "SIGIO", SIGIO }, { "SIGIOT", SIGIOT }, +#ifdef SIGCLD + { "SIGCLD", SIGCLD }, +#endif }; auto it = sigMap.find(str); From e12e4211430ae6358602d2e6e02c1afaf4abf641 Mon Sep 17 00:00:00 2001 From: ComixHe Date: Tue, 21 Oct 2025 16:23:26 +0800 Subject: [PATCH 25/26] chore: Begin development of 2.1.3 Signed-off-by: ComixHe --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 68744bd..e4fc84b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.11.4) # for RHEL 8 project( linyaps-box - VERSION 2.1.0 + VERSION 2.1.3 DESCRIPTION "A simple OCI runtime for desktop applications" HOMEPAGE_URL "https://github.com/OpenAtom-Linyaps/linyaps-box" LANGUAGES CXX) From 5a4eaff29fbd3293ae7612aa6672cf182d5ccd1d Mon Sep 17 00:00:00 2001 From: ComixHe Date: Tue, 21 Oct 2025 17:20:15 +0800 Subject: [PATCH 26/26] fix: explicitly cast MS_NOUSER to unsigned int Signed-off-by: ComixHe --- src/linyaps_box/container.cpp | 60 +++++++++++++++++++---------------- 1 file changed, 32 insertions(+), 28 deletions(-) diff --git a/src/linyaps_box/container.cpp b/src/linyaps_box/container.cpp index 9c0522d..14e6142 100644 --- a/src/linyaps_box/container.cpp +++ b/src/linyaps_box/container.cpp @@ -121,38 +121,42 @@ std::ostream &operator<<(std::ostream &os, const sync_message message) struct MountFlag { - // mount flag should be unsigned int due to MS_NOUSER (1U << 31) unsigned int flag; std::string_view name; }; -constexpr std::array mount_flags{ MountFlag{ MS_RDONLY, "MS_RDONLY" }, - { MS_NOSUID, "MS_NOSUID" }, - { MS_NODEV, "MS_NODEV" }, - { MS_NOEXEC, "MS_NOEXEC" }, - { MS_SYNCHRONOUS, "MS_SYNCHRONOUS" }, - { MS_REMOUNT, "MS_REMOUNT" }, - { MS_MANDLOCK, "MS_MANDLOCK" }, - { MS_DIRSYNC, "MS_DIRSYNC" }, - { LINGYAPS_MS_NOSYMFOLLOW, "MS_NOSYMFOLLOW" }, - { MS_NOATIME, "MS_NOATIME" }, - { MS_NODIRATIME, "MS_NODIRATIME" }, - { MS_BIND, "MS_BIND" }, - { MS_MOVE, "MS_MOVE" }, - { MS_REC, "MS_REC" }, - { MS_SILENT, "MS_SILENT" }, - { MS_POSIXACL, "MS_POSIXACL" }, - { MS_UNBINDABLE, "MS_UNBINDABLE" }, - { MS_PRIVATE, "MS_PRIVATE" }, - { MS_SLAVE, "MS_SLAVE" }, - { MS_SHARED, "MS_SHARED" }, - { MS_RELATIME, "MS_RELATIME" }, - { MS_KERNMOUNT, "MS_KERNMOUNT" }, - { MS_I_VERSION, "MS_I_VERSION" }, - { MS_STRICTATIME, "MS_STRICTATIME" }, - { MS_LAZYTIME, "MS_LAZYTIME" }, - { MS_ACTIVE, "MS_ACTIVE" }, - { MS_NOUSER, "MS_NOUSER" } }; +constexpr std::array mount_flags{ + MountFlag{ MS_RDONLY, "MS_RDONLY" }, + { MS_NOSUID, "MS_NOSUID" }, + { MS_NODEV, "MS_NODEV" }, + { MS_NOEXEC, "MS_NOEXEC" }, + { MS_SYNCHRONOUS, "MS_SYNCHRONOUS" }, + { MS_REMOUNT, "MS_REMOUNT" }, + { MS_MANDLOCK, "MS_MANDLOCK" }, + { MS_DIRSYNC, "MS_DIRSYNC" }, + { LINGYAPS_MS_NOSYMFOLLOW, "MS_NOSYMFOLLOW" }, + { MS_NOATIME, "MS_NOATIME" }, + { MS_NODIRATIME, "MS_NODIRATIME" }, + { MS_BIND, "MS_BIND" }, + { MS_MOVE, "MS_MOVE" }, + { MS_REC, "MS_REC" }, + { MS_SILENT, "MS_SILENT" }, + { MS_POSIXACL, "MS_POSIXACL" }, + { MS_UNBINDABLE, "MS_UNBINDABLE" }, + { MS_PRIVATE, "MS_PRIVATE" }, + { MS_SLAVE, "MS_SLAVE" }, + { MS_SHARED, "MS_SHARED" }, + { MS_RELATIME, "MS_RELATIME" }, + { MS_KERNMOUNT, "MS_KERNMOUNT" }, + { MS_I_VERSION, "MS_I_VERSION" }, + { MS_STRICTATIME, "MS_STRICTATIME" }, + { MS_LAZYTIME, "MS_LAZYTIME" }, + { MS_ACTIVE, "MS_ACTIVE" }, + // MS_NOUSER will be overflowed before 2.42.9000 + // refer: + // https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=3263675250cbcbbcc76ede4f7c660418bd345a11;hp=cd335350021fd0b7ac533c83717ee38832fd9887 + { static_cast(MS_NOUSER), "MS_NOUSER" } +}; [[maybe_unused]] auto dump_mount_flags(unsigned long flags) noexcept -> std::string {