From 8544c5a0d6044f858d88fa5d364191a8a25bd066 Mon Sep 17 00:00:00 2001 From: myml Date: Wed, 25 Dec 2024 13:48:59 +0800 Subject: [PATCH] feat: adjust systemd/user priority MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit XDG_DATA_DIRS下面的systemd优先级很高, 会影响系统systemd服务 将应用的systemd导出到其他地方, 再使用user-generator复制到优先级最低的generator.late目录 --- debian/linglong-bin.install | 1 + .../src/linglong/repo/ostree_repo.cpp | 301 +++++++++++------- libs/linglong/src/linglong/repo/ostree_repo.h | 10 +- libs/utils/src/linglong/utils/error/error.h | 51 +-- misc/CMakeLists.txt | 6 + .../linglong-user-systemd-generator | 9 + rpm/linglong.spec | 1 + 7 files changed, 242 insertions(+), 137 deletions(-) create mode 100755 misc/lib/systemd/user-generators/linglong-user-systemd-generator diff --git a/debian/linglong-bin.install b/debian/linglong-bin.install index b6adbc015..581c6572c 100644 --- a/debian/linglong-bin.install +++ b/debian/linglong-bin.install @@ -5,6 +5,7 @@ usr/bin/ll-cli usr/bin/llpkg usr/lib/linglong/* usr/lib/systemd/system-environment-generators/61-linglong +usr/lib/systemd/user-generators/linglong-user-systemd-generator usr/lib/systemd/system/org.deepin.linglong.PackageManager.service lib/systemd/system/ usr/lib/systemd/user/linglong-session-helper.service usr/lib/sysusers.d/linglong.conf diff --git a/libs/linglong/src/linglong/repo/ostree_repo.cpp b/libs/linglong/src/linglong/repo/ostree_repo.cpp index 4ffa93902..9ffea0ddb 100644 --- a/libs/linglong/src/linglong/repo/ostree_repo.cpp +++ b/libs/linglong/src/linglong/repo/ostree_repo.cpp @@ -49,6 +49,7 @@ #include #include #include +#include #include #include #include @@ -1505,7 +1506,7 @@ void OSTreeRepo::unexportReference(const package::Reference &ref) noexcept return; } - QDir entriesDir = this->repoDir.absoluteFilePath("entries/share"); + QDir entriesDir = this->repoDir.absoluteFilePath("entries"); QDirIterator it(entriesDir.absolutePath(), QDir::AllEntries | QDir::NoDot | QDir::NoDotDot | QDir::System, QDirIterator::Subdirectories); @@ -1538,7 +1539,7 @@ void OSTreeRepo::unexportReference(const package::Reference &ref) noexcept void OSTreeRepo::exportReference(const package::Reference &ref) noexcept { - auto entriesDir = QDir(this->repoDir.absoluteFilePath("entries/share")); + auto entriesDir = QDir(this->repoDir.absoluteFilePath("entries")); if (!entriesDir.exists()) { entriesDir.mkpath("."); } @@ -1549,7 +1550,7 @@ void OSTreeRepo::exportReference(const package::Reference &ref) noexcept Q_ASSERT(false); return; } - auto ret = exportEntries(entriesDir, *item); + auto ret = exportEntries(entriesDir.absolutePath().toStdString(), *item); if (!ret.has_value()) { qCritical() << QString("Failed to export %1:").arg(ref.toString()) << ret.error().message(); Q_ASSERT(false); @@ -1558,102 +1559,177 @@ void OSTreeRepo::exportReference(const package::Reference &ref) noexcept this->updateSharedInfo(); } -utils::error::Result OSTreeRepo::exportEntries( - const QDir &entriesDir, const api::types::v1::RepositoryCacheLayersItem &item) noexcept +// 递归源目录所有文件,并在目标目录创建软链接,max_depth 控制递归深度以避免环形链接导致的无限递归 +utils::error::Result OSTreeRepo::exportDir(const std::string &appID, + const std::filesystem::path &source, + const std::filesystem::path &destination, + const int &max_depth) { - LINGLONG_TRACE(QString("export %1").arg(item.info.id.c_str())); - auto layerDir = getMergedModuleDir(item); - if (!layerDir.has_value()) { - return LINGLONG_ERR("get layer dir", layerDir); - } - auto layerEntriesDir = QDir(layerDir->absoluteFilePath("entries/share")); - if (!layerEntriesDir.exists()) { - qCritical() << QString("Failed to export %1:").arg(item.info.id.c_str()) << layerEntriesDir - << "not exists."; + LINGLONG_TRACE(QString("export %1").arg(source.c_str())); + if (max_depth <= 0) { + qWarning() << "ttl reached, skipping export for" << source.c_str(); return LINGLONG_OK; } - const QStringList exportPaths = { - "applications", // Copy desktop files - "mime", // Copy MIME Type files - "icons", // Icons - "dbus-1", // D-Bus service files - "gnome-shell", // Search providers - "appdata", // Copy appdata/metainfo files (legacy path) - "metainfo", // Copy appdata/metainfo files - "plugins", // Copy plugins conf,The configuration files provided by some applications - // maybe used by the host dde-file-manager. - "systemd", // copy systemd service files - "deepin-manual", // copy deepin-manual files - "deepin-elf-verify" // for uab signature - }; - - for (const auto &path : exportPaths) { - QDir exportDir = layerEntriesDir.absoluteFilePath(path); - if (!exportDir.exists()) { + std::error_code ec; + // 检查源目录是否存在 + auto exists = std::filesystem::exists(source, ec); + if (ec) { + return LINGLONG_ERR("check source", ec); + } + if (!exists) { + return LINGLONG_ERR("source directory does not exist"); + } + auto is_directory = std::filesystem::is_directory(source, ec); + if (ec) { + return LINGLONG_ERR("check source", ec); + } + if (!is_directory) { + return LINGLONG_ERR("source is not a directory"); + } + // 检查目标目录是否存在,如果不存在则创建 + exists = std::filesystem::exists(destination, ec); + if (ec) { + return LINGLONG_ERR(QString("Failed to check file existence: ") + destination.c_str(), ec); + } + // 如果目标非目录,则删除它并重新创建 + if (exists && !std::filesystem::is_directory(destination, ec)) { + std::filesystem::remove(destination, ec); + if (ec) { + return LINGLONG_ERR(QString("Failed to remove file: ") + destination.c_str(), ec); + } + // 标记目标不存在 + exists = false; + } + if (!exists) { + std::filesystem::create_directories(destination, ec); + if (ec) { + return LINGLONG_ERR(QString("Failed to create directory: ") + destination.c_str(), ec); + } + } + auto iterator = std::filesystem::directory_iterator(source, ec); + if (ec) { + return LINGLONG_ERR("list directory: " + source.string(), ec); + } + // 遍历源目录中的所有文件和子目录 + for (const auto &entry : iterator) { + const auto &source_path = entry.path(); + const auto &target_path = destination / source_path.filename(); + // 跳过无效的软链接 + exists = std::filesystem::exists(source_path, ec); + if (ec) { + return LINGLONG_ERR("check source existence" + source_path.string(), ec); + } + if (!exists) { continue; } - QDirIterator it(exportDir.absolutePath(), - QDir::AllEntries | QDir::NoDotAndDotDot | QDir::System | QDir::Hidden, - QDirIterator::Subdirectories | QDirIterator::FollowSymlinks); - while (it.hasNext()) { - it.next(); - const auto info = it.fileInfo(); - if (info.isDir()) { - continue; - } - // Check if the target file of the symbolic link exists. - if (info.isSymLink() && !std::filesystem::exists(info.symLinkTarget().toStdString())) { - qCritical() << "Invalid symlink: " << info.filePath(); - continue; + // 如果是文件,创建符号链接 + auto is_regular_file = std::filesystem::is_regular_file(source_path, ec); + if (ec) { + return LINGLONG_ERR("check file type: " + source_path.string(), ec); + } + if (is_regular_file) { + exists = std::filesystem::exists(target_path, ec); + if (ec) { + return LINGLONG_ERR("check file existence", ec); } - - auto ret = IniLikeFileRewrite(info, QString::fromStdString(item.info.id)); - if (!ret) { - qCritical() << ret.error().message(); + if (exists) { + std::filesystem::remove(target_path, ec); + if (ec) { + return LINGLONG_ERR("remove file failed", ec); + } } - - const auto parentDirForLinkPath = - layerEntriesDir.relativeFilePath(it.fileInfo().dir().absolutePath()); - - if (!entriesDir.mkpath(parentDirForLinkPath)) { - qCritical() << "Failed to mkpath" - << entriesDir.absoluteFilePath(parentDirForLinkPath); + auto ret = IniLikeFileRewrite(QFileInfo(source_path.c_str()), appID.c_str()); + if (!ret) { } + std::filesystem::create_symlink(source_path, target_path, ec); + if (ec) { + return LINGLONG_ERR("create symlink failed: " + target_path.string(), ec); } - auto from = std::filesystem::path{ - entriesDir.absoluteFilePath(parentDirForLinkPath).toStdString() - } / it.fileName().toStdString(); - - QDir parentDir(entriesDir.absoluteFilePath(parentDirForLinkPath)); - auto to = std::filesystem::path{ - parentDir.relativeFilePath(info.absoluteFilePath()).toStdString() - }; - - std::error_code ec; - auto status = std::filesystem::symlink_status(from, ec); - if (ec && ec.value() != static_cast(std::errc::no_such_file_or_directory)) { - qCritical() << "symlink_status" << from.c_str() - << "error:" << QString::fromStdString(ec.message()); - continue; + continue; + } + // 如果是目录,进行递归导出 + is_directory = std::filesystem::is_directory(source_path, ec); + if (ec) { + return LINGLONG_ERR("check file type", ec); + } + if (is_directory) { + auto ret = this->exportDir(appID, source_path, target_path, max_depth - 1); + if (!ret.has_value()) { + return ret; } + continue; + } + // 其他情况,报错 + qWarning() << "invalid file: " << source_path.c_str(); + } + return LINGLONG_OK; +} - if (std::filesystem::exists(status)) { - qInfo() << from.c_str() << "symlink already exists, try to remove it"; - if (!std::filesystem::remove(from, ec)) { - qCritical() << "remove" << from.c_str() - << "error:" << QString::fromStdString(ec.message()); - continue; - } - } +utils::error::Result +OSTreeRepo::exportEntries(const std::filesystem::path &rootEntriesDir, + const api::types::v1::RepositoryCacheLayersItem &item) noexcept +{ + LINGLONG_TRACE(QString("export %1").arg(item.info.id.c_str())); + auto layerDir = getMergedModuleDir(item); + if (!layerDir.has_value()) { + return LINGLONG_ERR("get layer dir", layerDir); + } + std::error_code ec; + // 检查目录是否存在 + std::filesystem::path appEntriesDir = layerDir->absoluteFilePath("entries").toStdString(); + auto exists = std::filesystem::exists(appEntriesDir, ec); + if (ec) { + return LINGLONG_ERR("check appEntriesDir exists", ec); + } + if (!exists) { + qCritical() << QString("Failed to export %1:").arg(item.info.id.c_str()) + << appEntriesDir.c_str() << "not exists."; + return LINGLONG_OK; + } + std::vector exportPaths = { + "share/applications", // Copy desktop files + "share/mime", // Copy MIME Type files + "share/icons", // Icons + "share/dbus-1", // D-Bus service files + "share/gnome-shell", // Search providers + "share/appdata", // Copy appdata/metainfo files (legacy path) + "share/metainfo", // Copy appdata/metainfo files + "share/plugins", // Copy plugins conf,The configuration files provided by some applications + // maybe used by the host dde-file-manager. + "share/deepin-manual", // copy deepin-manual files + "share/deepin-elf-verify", // for uab signature - std::filesystem::create_symlink(to, from, ec); - if (ec) { - qCritical().nospace() - << "Failed to create link " << from.c_str() << " -> " << to.c_str() << " : " - << QString::fromStdString(ec.message()); - continue; - } + }; + // 如果存在lib/systemd目录,则导出lib/systemd,否则导出share/systemd + exists = std::filesystem::exists(appEntriesDir / "lib/systemd", ec); + if (ec) { + return LINGLONG_ERR("Failed to check the existence of lib/systemd directory: {}", ec); + } + if (exists) { + exportPaths.push_back("lib/systemd"); + } else { + exportPaths.push_back("share/systemd"); + } + // 导出应用entries目录下的所有文件到玲珑仓库的entries目录下 + for (const auto &path : exportPaths) { + auto source = appEntriesDir / path; + auto destination = rootEntriesDir / path; + // 将 share/systemd 目录下的文件导出到 lib/systemd 目录下 + if (path == "share/systemd") { + destination = rootEntriesDir / "lib/systemd"; + } + // 检查源目录是否存在,跳过不存在的目录 + exists = std::filesystem::exists(source, ec); + if (ec) { + return LINGLONG_ERR(QString("Failed to check file existence: ") + source.c_str(), ec); + } + if (!exists) { + continue; + } + auto ret = this->exportDir(item.info.id, source, destination, 10); + if (!ret.has_value()) { + return ret; } } return LINGLONG_OK; @@ -1663,20 +1739,14 @@ utils::error::Result OSTreeRepo::exportAllEntries() noexcept { LINGLONG_TRACE("export all entries"); std::error_code ec; - // 创建新的share目录 + // 创建一个新的entries目录,使用UUID作为名称 auto id = QUuid::createUuid().toString(QUuid::Id128); - auto entriesDir = QDir(this->repoDir.absoluteFilePath("entries/share_new_" + id)); - if (entriesDir.exists()) { - std::filesystem::remove_all(entriesDir.absolutePath().toStdString(), ec); - if (ec) { - return LINGLONG_ERR("clean temp share directory", ec); - } - } - std::filesystem::create_directory(entriesDir.absolutePath().toStdString(), ec); + std::filesystem::path entriesDir = this->repoDir.filePath("entries_new_" + id).toStdString(); + std::filesystem::create_directory(entriesDir, ec); if (ec) { return LINGLONG_ERR("create temp share directory", ec); } - // 导出所有layer + // 导出所有layer到新entries目录 auto items = this->cache->queryExistingLayerItem(); for (const auto &item : items) { if (item.info.kind != "app") { @@ -1687,27 +1757,29 @@ utils::error::Result OSTreeRepo::exportAllEntries() noexcept return ret; } } - // 用新的share目录替换旧的 - std::filesystem::path workdir = repoDir.absoluteFilePath("entries").toStdString(); - - if (!std::filesystem::exists(workdir / "share")) { - std::filesystem::rename(entriesDir.dirName().toStdString(), workdir / "share", ec); + // 用新的entries目录替换旧的 + std::filesystem::path workdir = repoDir.absolutePath().toStdString(); + auto existsOldEntries = std::filesystem::exists(workdir / "entries", ec); + if (ec) { + return LINGLONG_ERR("check entries directory", ec); + } + if (!existsOldEntries) { + std::filesystem::rename(entriesDir, workdir / "entries", ec); if (ec) { - return LINGLONG_ERR("create new share symlink", ec); + return LINGLONG_ERR("rename new entries directory", ec); } } else { - auto oldshare = "share_old_" + QUuid::createUuid().toString(QUuid::Id128).toStdString(); - std::filesystem::rename(workdir / "share", workdir / oldshare, ec); + auto id = QUuid::createUuid().toString(QUuid::Id128).toStdString(); + auto oldEntriesDir = workdir / ("entries_old_" + id); + std::filesystem::rename(workdir / "entries", oldEntriesDir, ec); if (ec) { return LINGLONG_ERR("rename old share directory", ec); } - std::filesystem::rename(workdir / entriesDir.dirName().toStdString(), - workdir / "share", - ec); + std::filesystem::rename(entriesDir, workdir / "entries", ec); if (ec) { return LINGLONG_ERR("create new share symlink", ec); } - std::filesystem::remove_all(workdir / oldshare, ec); + std::filesystem::remove_all(oldEntriesDir, ec); if (ec) { return LINGLONG_ERR("remove old share directory", ec); } @@ -2219,7 +2291,7 @@ OSTreeRepo::listLocalBy(const linglong::repo::repoCacheQuery &query) const noexc QString getOriginRawExec(const QString &execArgs, const QString &id) { // Note: These strings have appeared in the app-conf-generator.sh of linglong-builder. - // We need to remove them. + // We need to remove them. const QString oldExec = "--exec "; const QString newExec = "-- "; @@ -2234,8 +2306,7 @@ QString getOriginRawExec(const QString &execArgs, const QString &id) return execArgs.mid(index + newExec.length()); } - qCritical() << "'-- ' or '--exec ' is not exist in" << execArgs - << ", return an empty string"; + qCritical() << "'-- ' or '--exec ' is not exist in" << execArgs << ", return an empty string"; return ""; } @@ -2243,7 +2314,7 @@ QString buildDesktopExec(QString origin, const QString &appID) noexcept { auto newExec = QString{ "%1 run %2 " }.arg(LINGLONG_CLIENT_PATH, appID); - if(origin.isEmpty()) { + if (origin.isEmpty()) { Q_ASSERT(false); return newExec; } @@ -2275,8 +2346,7 @@ QString buildDesktopExec(QString origin, const QString &appID) noexcept [[fallthrough]]; case 'F': { origin.insert(next - origin.begin(), '%'); - auto tmp = - QString{ "--file %%1 -- %2" }.arg(std::move(code), std::move(origin)); + auto tmp = QString{ "--file %%1 -- %2" }.arg(std::move(code), std::move(origin)); newExec.append(tmp); return newExec; } @@ -2284,8 +2354,7 @@ QString buildDesktopExec(QString origin, const QString &appID) noexcept [[fallthrough]]; case 'U': { origin.insert(next - origin.begin(), '%'); - auto tmp = - QString{ "--url %%1 -- %2" }.arg(std::move(code), std::move(origin)); + auto tmp = QString{ "--url %%1 -- %2" }.arg(std::move(code), std::move(origin)); newExec.append(tmp); return newExec; } diff --git a/libs/linglong/src/linglong/repo/ostree_repo.h b/libs/linglong/src/linglong/repo/ostree_repo.h index 35bb5b2aa..392198891 100644 --- a/libs/linglong/src/linglong/repo/ostree_repo.h +++ b/libs/linglong/src/linglong/repo/ostree_repo.h @@ -154,10 +154,16 @@ class OSTreeRepo : public QObject [[nodiscard]] utils::error::Result getMergedModuleDir(const api::types::v1::RepositoryCacheLayersItem &layer, bool fallbackLayerDir = true) const noexcept; - utils::error::Result exportEntries( - const QDir &entriesDir, const api::types::v1::RepositoryCacheLayersItem &item) noexcept; + utils::error::Result + exportEntries(const std::filesystem::path &rootEntriesDir, + const api::types::v1::RepositoryCacheLayersItem &item) noexcept; static utils::error::Result IniLikeFileRewrite(const QFileInfo &info, const QString &id) noexcept; + + utils::error::Result exportDir(const std::string &appID, + const std::filesystem::path &source, + const std::filesystem::path &destination, + const int &max_depth); }; } // namespace linglong::repo diff --git a/libs/utils/src/linglong/utils/error/error.h b/libs/utils/src/linglong/utils/error/error.h index 9b18c6124..f78347726 100644 --- a/libs/utils/src/linglong/utils/error/error.h +++ b/libs/utils/src/linglong/utils/error/error.h @@ -20,6 +20,7 @@ #include #include +#include #include namespace linglong::utils::error { @@ -38,11 +39,9 @@ class Error [[nodiscard]] auto message() const { return pImpl->message(); } - static auto Err(const char *file, - int line, - const QString &trace_msg, - const QString &msg, - int code = -1) -> Error + static auto + Err(const char *file, int line, const QString &trace_msg, const QString &msg, int code = -1) + -> Error { return Error(std::make_unique(file, line, @@ -67,8 +66,8 @@ class Error nullptr)); } - static auto - Err(const char *file, int line, const QString &trace_msg, const QFile &qfile) -> Error + static auto Err(const char *file, int line, const QString &trace_msg, const QFile &qfile) + -> Error { return Error(std::make_unique(file, line, @@ -79,11 +78,9 @@ class Error nullptr)); } - static auto Err(const char *file, - int line, - const QString &trace_msg, - std::exception_ptr err, - int code = -1) -> Error + static auto + Err(const char *file, int line, const QString &trace_msg, std::exception_ptr err, int code = -1) + -> Error { QString what = trace_msg + ": "; try { @@ -118,8 +115,8 @@ class Error std::make_unique(file, line, "default", code, what, nullptr)); } - static auto - Err(const char *file, int line, const QString &trace_msg, const std::exception &e) -> Error + static auto Err(const char *file, int line, const QString &trace_msg, const std::exception &e) + -> Error { return Error(std::make_unique(file, line, @@ -156,6 +153,15 @@ class Error return Err(file, line, trace_msg, new_msg); } + static auto Err(const char *file, + int line, + const QString &trace_msg, + const char *msg, + const std::system_error &e) -> Error + { + return Err(file, line, trace_msg, msg, e, e.code().value()); + } + static auto Err(const char *file, int line, const QString &trace_msg, @@ -165,6 +171,15 @@ class Error return Err(file, line, trace_msg, msg, e, e.code().value()); } + static auto Err(const char *file, + int line, + const QString &trace_msg, + const std::string &msg, + const std::system_error &e) -> Error + { + return Err(file, line, trace_msg, msg.c_str(), e, e.code().value()); + } + template static auto Err(const char *file, int line, @@ -198,11 +213,9 @@ class Error std::move(cause.error().pImpl))); } - static auto Err(const char *file, - int line, - const QString &trace_msg, - const QString &msg, - Error &&cause) -> Error + static auto + Err(const char *file, int line, const QString &trace_msg, const QString &msg, Error &&cause) + -> Error { return Error(std::make_unique(file, line, diff --git a/misc/CMakeLists.txt b/misc/CMakeLists.txt index 75c2ac35b..2caa5c196 100644 --- a/misc/CMakeLists.txt +++ b/misc/CMakeLists.txt @@ -38,6 +38,7 @@ configure_files( lib/linglong/container/README.md lib/linglong/generate-xdg-data-dirs.sh lib/systemd/system-environment-generators/61-linglong + lib/systemd/user-generators/linglong-user-systemd-generator lib/systemd/system/org.deepin.linglong.PackageManager.service lib/systemd/system-preset/91-linglong.preset lib/systemd/user/linglong-session-helper.service @@ -149,6 +150,11 @@ install( ${CMAKE_CURRENT_BINARY_DIR}/lib/systemd/system-environment-generators/61-linglong DESTINATION ${SYSTEMD_SYSTEM_GENERATOR_PATH}) +install( + PROGRAMS + ${CMAKE_CURRENT_BINARY_DIR}/lib/systemd/user-generators/linglong-user-systemd-generator + DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/systemd/user-generators) + # sysuser set(SYSTEMD_SYSUSERSDIR ${CMAKE_INSTALL_PREFIX}/lib/sysusers.d) diff --git a/misc/lib/systemd/user-generators/linglong-user-systemd-generator b/misc/lib/systemd/user-generators/linglong-user-systemd-generator new file mode 100755 index 000000000..f398a2216 --- /dev/null +++ b/misc/lib/systemd/user-generators/linglong-user-systemd-generator @@ -0,0 +1,9 @@ +#!/usr/bin/env sh + +# SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. +# +# SPDX-License-Identifier: LGPL-3.0-or-later + +# https://www.freedesktop.org/software/systemd/man/latest/systemd.generator.html +late="$3" +cp -rs @LINGLONG_ROOT@/entries/lib/systemd/user/* "$late/" diff --git a/rpm/linglong.spec b/rpm/linglong.spec index a8b59117c..1d964f22c 100644 --- a/rpm/linglong.spec +++ b/rpm/linglong.spec @@ -85,6 +85,7 @@ cd build %{_prefix}/lib/systemd/system-preset/*.preset %{_prefix}/lib/systemd/user/* %{_prefix}/lib/systemd/system-environment-generators/* +%{_prefix}/lib/systemd/user-generators/* %{_libexecdir}/%{name}/ll-package-manager %{_libexecdir}/%{name}/ll-session-helper %{_libexecdir}/%{name}/ld-cache-generator