diff --git a/apps/ll-init/src/ll-init.cpp b/apps/ll-init/src/ll-init.cpp index 5b94a14c2..df1119922 100644 --- a/apps/ll-init/src/ll-init.cpp +++ b/apps/ll-init/src/ll-init.cpp @@ -9,15 +9,15 @@ #include #include #include -#include #include #include #include // no need to block these signals -constexpr std::array unblock_signals{ SIGABRT, SIGBUS, SIGFPE, SIGILL, SIGSEGV, SIGSYS, - SIGTRAP, SIGXCPU, SIGXFSZ, SIGTTIN, SIGTTOU }; +constexpr std::array unblock_signals{ SIGABRT, SIGBUS, SIGFPE, SIGILL, SIGSEGV, + SIGSYS, SIGTRAP, SIGXCPU, SIGXFSZ, SIGTTIN, + SIGTTOU, SIGINT, SIGTERM }; struct sig_conf { @@ -25,8 +25,12 @@ struct sig_conf sigset_t old_set{}; struct sigaction ttin_action{}; struct sigaction ttou_action{}; + struct sigaction int_action{}; + struct sigaction term_action{}; }; +sig_atomic_t received_signal{ 0 }; + namespace { void print_sys_error(std::string_view msg) noexcept @@ -36,7 +40,14 @@ void print_sys_error(std::string_view msg) noexcept void print_info(std::string_view msg) noexcept { - std::cout << msg << std::endl; + std::cerr << msg << std::endl; +} + +// ATTENTION: there is a potential risk that the signal will be overridden if multiple signals are +// received at the same time. +void sig_forward(int signo) noexcept +{ + received_signal = signo; } using sig_result = std::variant; @@ -49,6 +60,7 @@ sig_result handle_signals() noexcept ::sigdelset(&conf.cur_set, signal); } + // ignore the rest of the signals auto ret = ::sigprocmask(SIG_SETMASK, &conf.cur_set, &conf.old_set); if (ret == -1) { print_sys_error("Failed to set signal mask"); @@ -71,6 +83,21 @@ sig_result handle_signals() noexcept return -1; } + // we only forward SIGINT, SIGTERM to the child process + struct sigaction forward_action{}; + forward_action.sa_handler = sig_forward; + forward_action.sa_flags = 0; + + if (::sigaction(SIGINT, &forward_action, &conf.int_action) == -1) { + print_sys_error("Failed to forward SIGINT"); + return -1; + } + + if (::sigaction(SIGTERM, &forward_action, &conf.term_action) == -1) { + print_sys_error("Failed to forward SIGTERM"); + return -1; + } + return conf; } @@ -124,32 +151,28 @@ pid_t run(std::vector args, const sig_conf &conf) noexcept return -1; } + ret = ::sigaction(SIGINT, &conf.int_action, nullptr); + if (ret == -1) { + print_sys_error("Failed to restore SIGINT action"); + return -1; + } + + ret = ::sigaction(SIGTERM, &conf.term_action, nullptr); + if (ret == -1) { + print_sys_error("Failed to restore SIGTERM action"); + return -1; + } + args.emplace_back(nullptr); ::execv(args[0], const_cast(args.data())); print_sys_error("Failed to exec"); - return -1; + ::_exit(EXIT_FAILURE); } return pid; } -std::optional handle_exited_child(pid_t child) noexcept -{ - int status{}; - while (true) { - auto ret = ::waitpid(-1, &status, WNOHANG); - if (ret == 0) { - break; - } - - if (ret == child) { - return status; - } - } - - return std::nullopt; -} } // namespace int main(int argc, char *argv[]) @@ -175,48 +198,42 @@ int main(int argc, char *argv[]) auto child = run(args, conf); if (child == -1) { - return -1; - } - - auto sigfd = ::signalfd(-1, &conf.cur_set, 0); - if (sigfd == -1) { - print_sys_error("Failed to create signalfd"); + print_info("Failed to run child process"); return -1; } int child_status{}; - signalfd_siginfo info{}; while (true) { - std::memset(&info, 0, sizeof(info)); - auto ret = ::read(sigfd, &info, sizeof(info)); - if (ret == -1) { - print_sys_error("Failed to read from signalfd"); - return -1; + ret = waitpid(-1, &child_status, 0); + if (ret != -1) { + if (ret == child) { + // if child process already exited, we will send the signal to all processes in this + // pid namespace + child = -1; + } + + continue; } - if (info.ssi_signo != SIGCHLD) { - ret = ::kill(child, info.ssi_signo); + if (errno == EINTR) { + ret = ::kill(child, received_signal); if (ret == -1) { - auto msg = std::string("Failed to forward signal ") + ::strsignal(info.ssi_signo); + auto msg = std::string("Failed to forward signal ") + ::strsignal(received_signal); print_sys_error(msg); } } - auto child_exited = handle_exited_child(child); - if (child_exited) { - child_status = *child_exited; + if (errno == ECHILD) { break; } } - ::close(sigfd); - if (WIFEXITED(child_status)) { - print_info("Child exited with status " + std::to_string(WEXITSTATUS(child_status))); + print_info("Last child exited with status " + std::to_string(WEXITSTATUS(child_status))); } else if (WIFSIGNALED(child_status)) { - print_info("Child exited with signal " + std::to_string(WTERMSIG(child_status))); + print_info("Last child exited with signal " + std::to_string(WTERMSIG(child_status))); } else { - print_info("Child exited with unknown status"); + print_info("Last child exited with unknown status"); } return 0; diff --git a/libs/oci-cfg-generators/src/linglong/oci-cfg-generators/90_legacy.cpp b/libs/oci-cfg-generators/src/linglong/oci-cfg-generators/90_legacy.cpp deleted file mode 100644 index df7466d4a..000000000 --- a/libs/oci-cfg-generators/src/linglong/oci-cfg-generators/90_legacy.cpp +++ /dev/null @@ -1,174 +0,0 @@ -// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: LGPL-3.0-or-later - -#include "90_legacy.h" - -#include -#include -#include -#include -#include - -namespace linglong::generator { - -bool Legacy::generate(ocppi::runtime::config::types::Config &config) const noexcept -{ - if (config.ociVersion != "1.0.1") { - std::cerr << "OCI version mismatched." << std::endl; - return false; - } - - if (!config.annotations) { - std::cerr << "no annotations." << std::endl; - return false; - } - - auto onlyApp = config.annotations->find("org.deepin.linglong.onlyApp"); - if (onlyApp != config.annotations->end() && onlyApp->second == "true") { - return true; - } - - auto appID = config.annotations->find("org.deepin.linglong.appID"); - if (appID == config.annotations->end()) { - std::cerr << "appID not found." << std::endl; - return false; - } - - if (appID->second.empty()) { - std::cerr << "appID is empty." << std::endl; - return false; - } - - auto process = config.process.value_or(ocppi::runtime::config::types::Process{}); - auto env = process.env.value_or(std::vector{}); - auto mounts = config.mounts.value_or(std::vector{}); - - // FIXME: time zone in the container does not change when the host time zone changes,need to be - // repaired later. - std::multimap roMountMap{ - { "/etc/resolvconf", "/run/host/etc/resolvconf" }, - { "/etc/hosts", "/run/host/etc/hosts" }, - { "/etc/hosts", "/etc/hosts" }, - { "/etc/machine-id", "/run/host/etc/machine-id" }, - { "/etc/machine-id", "/etc/machine-id" }, - { "/etc/ssl/certs", "/run/host/etc/ssl/certs" }, - { "/etc/ssl/certs", "/etc/ssl/certs" }, - { "/var/cache/fontconfig", "/run/host/appearance/fonts-cache" }, - // FIXME: app can not display normally due to missing cjk font cache file,so we need bind - // /var/cache/fontconfig to container. this is just a temporary solution,need to be removed - // when font cache solution implemented - { "/var/cache/fontconfig", "/var/cache/fontconfig" }, - { "/usr/share/fonts", "/usr/share/fonts" }, - { "/usr/lib/locale/", "/usr/lib/locale/" }, - { "/usr/share/themes", "/usr/share/themes" }, - { "/usr/share/icons", "/usr/share/icons" }, - { "/usr/share/zoneinfo", "/usr/share/zoneinfo" }, - { "/etc/resolvconf", "/etc/resolvconf" }, - }; - - std::error_code ec; - for (const auto [source, destination] : roMountMap) { - if (!std::filesystem::exists(source, ec)) { - if (ec) { - std::cerr << "Failed to check existence of " << source << ": " << ec.message() - << std::endl; - continue; - } - - std::cerr << source << " not exists on host." << std::endl; - continue; - } - - mounts.push_back(ocppi::runtime::config::types::Mount{ - .destination = std::string{ destination }, - .options = string_list{ "ro", "rbind" }, - .source = std::string{ source }, - .type = "bind", - }); - }; - - { - // FIXME: com.360.browser-stable - // 需要一个所有用户都有可读可写权限的目录(/apps-data/private/com.360.browser-stable) - if (::getenv("LINGLONG_SKIP_HOME_GENERATE") == nullptr - && "com.360.browser-stable" == appID->second) { - auto *home = ::getenv("HOME"); - if (home == nullptr) { - std::cerr << "Couldn't get HOME." << std::endl; - return -1; - } - - auto homeDir = std::filesystem::path(home); - if (!std::filesystem::exists(homeDir)) { - std::cerr << "Home " << homeDir << "doesn't exists." << std::endl; - return -1; - } - - std::error_code ec; - std::string app360DataSourcePath = - homeDir / ".linglong" / appID->second / "share" / "appdata"; - - auto appDataDir = std::filesystem::path(app360DataSourcePath); - std::filesystem::create_directories(appDataDir, ec); - if (ec) { - std::cerr << "Check appDataDir failed:" << ec.message() << std::endl; - return -1; - } - - std::string app360DataPath = "/apps-data"; - std::string app360DataDestPath = app360DataPath + "/private/com.360.browser-stable"; - - mounts.push_back(ocppi::runtime::config::types::Mount{ - .destination = std::move(app360DataPath), - .options = string_list{ " nodev ", " nosuid ", " mode = 777 " }, - .source = "tmpfs", - .type = "tmpfs", - }); - - mounts.push_back(ocppi::runtime::config::types::Mount{ - .destination = std::move(app360DataDestPath), - .options = string_list{ "rw", "rbind" }, - .source = std::move(app360DataSourcePath), - .type = "bind", - }); - } - } - - // randomize mount points to avoid path dependency. - auto now = std::chrono::system_clock::now(); - auto timestamp = - std::chrono::duration_cast(now.time_since_epoch()).count(); - auto shareDir = std::filesystem::path("/run/linglong/usr/share_" + std::to_string(timestamp)); - // add mount points to XDG_DATA_DIRS - // 查找是否存在XDG_DATA_DIRS开头的环境变量,如果存在追加到尾部,不存在则添加 - auto it = std::find_if(env.begin(), env.end(), [](const std::string &var) { - return var.find("XDG_DATA_DIRS=") == 0; - }); - if (it != env.end()) { - // 如果存在,追加到尾部 - *it += ":" + shareDir.string(); - } else { - // 如果不存在,添加到末尾 - env.push_back("XDG_DATA_DIRS=" + shareDir.string()); - } - - ec.clear(); - // mount for dtk - if (std::filesystem::exists("/usr/share/deepin/distribution.info", ec)) { - mounts.push_back(ocppi::runtime::config::types::Mount{ - .destination = shareDir / "deepin/distribution.info", - .options = string_list{ "ro", "rbind" }, - .source = "/usr/share/deepin/distribution.info", - .type = "bind", - }); - } - - process.env = std::move(env); - config.process = std::move(process); - config.mounts = std::move(mounts); - - return true; -} - -} // namespace linglong::generator