Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: can not install app in chroot #954

Merged
merged 2 commits into from
Jan 9, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 15 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ set(UAB_SPECIAL_INSTALL
OFF
CACHE BOOL "enable special installation of UAB")

if (${UAB_SPECIAL_INSTALL})
add_definitions(-DUAB_SPECIAL_INSTALL)
if(${UAB_SPECIAL_INSTALL})
add_definitions(-DUAB_SPECIAL_INSTALL)
endif()

set(ENABLE_UAB
Expand Down Expand Up @@ -187,6 +187,19 @@ add_definitions("-DQT_NO_KEYWORDS")
# NOTE(black_desk): Enable Qt logging with context.
add_definitions("-DQT_MESSAGELOGCONTEXT")

# FIXME: can not start container since the kernel does not support the
# CLONE_NEWUSER feature in the chroot environment, reference:
# https://man7.org/linux/man-pages/man2/unshare.2.html. so we skip font cache
# generator by LINGLONG_FONT_CACHE_GENERATOR, it can be removed when the above
# problem is solved.
set(ENABLE_FONT_CACHE_GENERATOR
OFF
CACHE BOOL "enable font cache generator")

if(ENABLE_FONT_CACHE_GENERATOR)
add_definitions(-DLINGLONG_FONT_CACHE_GENERATOR)
endif()

# We need to support both Qt5 and Qt6, and according to the Qt documentation, we
# should be using versioned targets and functions. These varible must be set
# before find_package()
Expand Down
2 changes: 1 addition & 1 deletion apps/ll-builder/src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,7 @@ You can report bugs to the linyaps team under this project: https://github.com/O
commandParser.add_subcommand("import-dir", _("Import linyaps layer dir to build repo"))
->group(hiddenGroup);
buildImportDir->usage(_("Usage: ll-builder import-dir PATH"));
buildImportDir->add_option("PATH", layerDir, _("layer dir path"))
buildImportDir->add_option("PATH", layerDir, _("Layer dir path"))
->type_name("PATH")
->required();

Expand Down
4 changes: 3 additions & 1 deletion apps/ll-dialog/src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
//
// SPDX-License-Identifier: LGPL-3.0-or-later

#include "cache_dialog.h"
#include "linglong/utils/configure.h"

Check warning on line 6 in apps/ll-dialog/src/main.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: "linglong/utils/configure.h" not found.
#include "permissionDialog.h"
#include "cache_dialog.h"
#include "tl/expected.hpp"

Check warning on line 8 in apps/ll-dialog/src/main.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: "tl/expected.hpp" not found.

#include <QApplication>

Check warning on line 10 in apps/ll-dialog/src/main.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QApplication> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QCommandLineParser>
#include <QSocketNotifier>
#include <QTimer>
Expand Down Expand Up @@ -159,6 +159,8 @@

int main(int argc, char *argv[])
{
bindtextdomain(PACKAGE_LOCALE_DOMAIN, PACKAGE_LOCALE_DIR);
textdomain(PACKAGE_LOCALE_DOMAIN);
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
QApplication::setAttribute(Qt::ApplicationAttribute::AA_UseHighDpiPixmaps);
QApplication::setAttribute(Qt::ApplicationAttribute::AA_EnableHighDpiScaling);
Expand Down
13 changes: 12 additions & 1 deletion libs/linglong/src/linglong/builder/linglong_builder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -704,6 +704,10 @@ set -e

// initialize the cache dir
QDir appCache = this->workingDir.absoluteFilePath("linglong/cache");
if (!appCache.mkpath(".")) {
return LINGLONG_ERR("make path " + appCache.absolutePath() + ": failed.");
}
#ifdef LINGLONG_FONT_CACHE_GENERATOR
QDir appFontCache = appCache.absoluteFilePath("fontconfig");
if (!appFontCache.mkpath(".")) {
return LINGLONG_ERR("make path " + appFontCache.absolutePath() + ": failed.");
Expand All @@ -712,6 +716,7 @@ set -e
if (!appFonts.mkpath(".")) {
return LINGLONG_ERR("make path " + appFonts.absolutePath() + ": failed.");
}
#endif
// write ld.so.conf
QFile ldsoconf = appCache.absoluteFilePath("ld.so.conf");
if (!ldsoconf.open(QIODevice::WriteOnly)) {
Expand All @@ -728,6 +733,7 @@ include /opt/apps/@id@/files/etc/ld.so.conf)";
ldsoconf.write(ldRawConf.toUtf8());
// must be closed here, this conf will be used later.
ldsoconf.close();
#ifdef LINGLONG_FONT_CACHE_GENERATOR
// write fonts.conf
QFile fontsConf = appFonts.absoluteFilePath("fonts.conf");
if (!fontsConf.open(QIODevice::WriteOnly)) {
Expand All @@ -741,6 +747,7 @@ include /opt/apps/@id@/files/etc/ld.so.conf)";
</fontconfig>)";
fontsRawConf.replace("@id@", QString::fromStdString(this->project.package.id));
fontsConf.write(fontsRawConf.toUtf8());
#endif

opts.mounts.push_back({
.destination = "/run/linglong/cache",
Expand Down Expand Up @@ -1549,31 +1556,35 @@ utils::error::Result<void> Builder::run(const QStringList &modules,
.source = this->workingDir.absoluteFilePath("linglong/cache").toStdString(),
.type = "bind",
});
#ifdef LINGLONG_FONT_CACHE_GENERATOR
// mount font cache
applicationMounts.push_back(ocppi::runtime::config::types::Mount{
.destination = "/var/cache/fontconfig",
.options = { { "rbind", "rw" } },
.source = this->workingDir.absoluteFilePath("linglong/cache/fontconfig").toStdString(),
.type = "bind",
});
#endif

std::vector<ocppi::runtime::config::types::Hook> generateCache{};
std::vector<std::string> ldconfigCmd = { "/sbin/ldconfig",
"-C",
"/run/linglong/cache/ld.so.cache" };
std::vector<std::string> fontconfiCmd = { "fc-cache", "-f" };
generateCache.push_back(ocppi::runtime::config::types::Hook{
.args = std::move(ldconfigCmd),
.env = {},
.path = "/sbin/ldconfig",
.timeout = {},
});
#ifdef LINGLONG_FONT_CACHE_GENERATOR
std::vector<std::string> fontconfiCmd = { "fc-cache", "-f" };
generateCache.push_back(ocppi::runtime::config::types::Hook{
.args = std::move(fontconfiCmd),
.env = {},
.path = "/bin/fc-cache",
.timeout = {},
});
#endif
options.hooks.startContainer = std::move(generateCache);
options.mounts = std::move(applicationMounts);

Expand Down
29 changes: 16 additions & 13 deletions libs/linglong/src/linglong/cli/cli.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,13 @@
#include "linglong/api/types/v1/SubState.hpp"
#include "linglong/api/types/v1/UpgradeListResult.hpp"
#include "linglong/cli/printer.h"
#include "linglong/package/layer_file.h"

Check warning on line 23 in libs/linglong/src/linglong/cli/cli.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: "linglong/package/layer_file.h" not found.
#include "linglong/runtime/container_builder.h"

Check warning on line 24 in libs/linglong/src/linglong/cli/cli.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: "linglong/runtime/container_builder.h" not found.
#include "linglong/utils/configure.h"

Check warning on line 25 in libs/linglong/src/linglong/cli/cli.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: "linglong/utils/configure.h" not found.
#include "linglong/utils/gettext.h"

Check warning on line 26 in libs/linglong/src/linglong/cli/cli.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: "linglong/utils/gettext.h" not found.
#include "linglong/utils/error/error.h"

Check warning on line 27 in libs/linglong/src/linglong/cli/cli.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: "linglong/utils/error/error.h" not found.
#include "linglong/utils/finally/finally.h"

Check warning on line 28 in libs/linglong/src/linglong/cli/cli.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: "linglong/utils/finally/finally.h" not found.
#include "linglong/utils/serialize/json.h"

Check warning on line 29 in libs/linglong/src/linglong/cli/cli.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: "linglong/utils/serialize/json.h" not found.
#include "linglong/utils/xdg/directory.h"
#include "ocppi/runtime/ExecOption.hpp"
#include "ocppi/runtime/RunOption.hpp"
Expand All @@ -50,6 +51,9 @@

using namespace linglong::utils::error;

static const std::string permissionNotifyMsg =
_("Permission deny, please check whether you are running as root.");

namespace {

static std::vector<std::string> getAutoModuleList() noexcept
Expand Down Expand Up @@ -257,7 +261,7 @@
if (dbusReply.isError()) {
if (dbusReply.error().type() == QDBusError::AccessDenied) {
this->notifier->notify(api::types::v1::InteractionRequest{
.summary = "Permission deny, please check whether you are running as root." });
.summary = permissionNotifyMsg });
return;
}

Expand Down Expand Up @@ -664,12 +668,14 @@
.type = "bind",
});

#ifdef LINGLONG_FONT_CACHE_GENERATOR
applicationMounts.push_back(ocppi::runtime::config::types::Mount{
.destination = "/var/cache/fontconfig",
.options = nlohmann::json::array({ "rbind", "ro" }),
.source = *appCache + "/fontconfig",
.type = "bind",
});
#endif

auto container = this->containerBuilder.create({
.appID = curAppRef->id,
Expand Down Expand Up @@ -984,7 +990,7 @@
if (pendingReply.isError()) {
if (pendingReply.error().type() == QDBusError::AccessDenied) {
this->notifier->notify(api::types::v1::InteractionRequest{
.summary = "Permission deny, please check whether you are running as root." });
.summary = permissionNotifyMsg });
return -1;
}
auto err = LINGLONG_ERRV(pendingReply.error().message());
Expand Down Expand Up @@ -1107,7 +1113,7 @@
if (pendingReply.isError()) {
if (pendingReply.error().type() == QDBusError::AccessDenied) {
this->notifier->notify(api::types::v1::InteractionRequest{
.summary = "Permission deny, please check whether you are running as root." });
.summary = permissionNotifyMsg });
return -1;
}

Expand Down Expand Up @@ -1215,7 +1221,7 @@
if (pendingReply.isError()) {
if (pendingReply.error().type() == QDBusError::AccessDenied) {
this->notifier->notify(api::types::v1::InteractionRequest{
.summary = "Permission deny, please check whether you are running as root." });
.summary = permissionNotifyMsg });
return -1;
}

Expand Down Expand Up @@ -1283,7 +1289,7 @@
if (pendingReply.isError()) {
if (pendingReply.error().type() == QDBusError::AccessDenied) {
this->notifier->notify(api::types::v1::InteractionRequest{
.summary = "Permission deny, please check whether you are running as root." });
.summary = permissionNotifyMsg });
return -1;
}

Expand Down Expand Up @@ -1398,7 +1404,7 @@
if (pendingReply.isError()) {
if (pendingReply.error().type() == QDBusError::AccessDenied) {
this->notifier->notify(api::types::v1::InteractionRequest{
.summary = "Permission deny, please check whether you are running as root." });
.summary = permissionNotifyMsg });
return -1;
}

Expand Down Expand Up @@ -1487,7 +1493,7 @@
if (pendingReply.isError()) {
if (pendingReply.error().type() == QDBusError::AccessDenied) {
this->notifier->notify(api::types::v1::InteractionRequest{
.summary = "Permission deny, please check whether you are running as root." });
.summary = permissionNotifyMsg });
return -1;
}

Expand Down Expand Up @@ -1685,7 +1691,7 @@
if (this->pkgMan.lastError().isValid()) {
if (this->pkgMan.lastError().type() == QDBusError::AccessDenied) {
this->notifier->notify(api::types::v1::InteractionRequest{
.summary = "Permission deny, please check whether you are running as root." });
.summary = permissionNotifyMsg });
return -1;
}

Expand Down Expand Up @@ -1808,7 +1814,7 @@
if (this->pkgMan.lastError().isValid()) {
if (this->pkgMan.lastError().type() == QDBusError::AccessDenied) {
this->notifier->notify(api::types::v1::InteractionRequest{
.summary = "Permission deny, please check whether you are running as root." });
.summary = permissionNotifyMsg });
return -1;
}

Expand Down Expand Up @@ -2403,10 +2409,7 @@
if (ret != 0) {
this->notifier->notify(api::types::v1::InteractionRequest{
.summary =
"The cache generation failed, please uninstall and reinstall the application." });
} else {
this->notifier->notify(
api::types::v1::InteractionRequest{ .summary = "The cache has been regenerated." });
_("The cache generation failed, please uninstall and reinstall the application.") });
}
process.close();

Expand Down
43 changes: 32 additions & 11 deletions libs/linglong/src/linglong/package_manager/package_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,7 @@ PackageManager::removeAfterInstall(const package::Reference &oldRef,
<< tmp.message();
}
if (module == "binary" || module == "runtime") {
auto ret = this->generateCache(oldRef);
auto ret = this->tryGenerateCache(oldRef);
if (!ret) {
qCritical() << ret.error().message();
}
Expand Down Expand Up @@ -691,7 +691,7 @@ QVariantMap PackageManager::installFromLayer(const QDBusUnixFileDescriptor &fd,
return;
}

auto generateCacheRet = this->generateCache(*newRef);
auto generateCacheRet = this->tryGenerateCache(*newRef);
if (!generateCacheRet) {
taskRef.reportError(std::move(generateCacheRet).error());
return;
Expand All @@ -712,7 +712,7 @@ QVariantMap PackageManager::installFromLayer(const QDBusUnixFileDescriptor &fd,
return;
}

auto generateCacheRet = this->generateCache(*newRef);
auto generateCacheRet = this->tryGenerateCache(*newRef);
if (!generateCacheRet) {
taskRef.reportError(std::move(generateCacheRet).error());
return;
Expand Down Expand Up @@ -1047,7 +1047,7 @@ QVariantMap PackageManager::installFromUAB(const QDBusUnixFileDescriptor &fd,
}

this->repo.exportReference(newAppRef);
auto result = this->generateCache(newAppRef);
auto result = this->tryGenerateCache(newAppRef);
if (!result) {
taskRef.updateState(linglong::api::types::v1::State::Failed,
"Failed to generate some cache.\n" + result.error().message());
Expand Down Expand Up @@ -1355,7 +1355,7 @@ void PackageManager::Install(PackageTask &taskContext,
} else {
this->repo.exportReference(newRef);
}
auto result = this->generateCache(newRef);
auto result = this->tryGenerateCache(newRef);
if (!result) {
taskContext.updateState(linglong::api::types::v1::State::Failed,
"Failed to generate some cache.\n" + result.error().message());
Expand Down Expand Up @@ -1590,7 +1590,7 @@ void PackageManager::UninstallRef(PackageTask &taskContext,
<< ref.toString();
}
if (module == "binary" || module == "runtime") {
auto ret = this->generateCache(ref);
auto ret = this->tryGenerateCache(ref);
if (!ret) {
qCritical() << ret.error().message();
}
Expand Down Expand Up @@ -1805,7 +1805,7 @@ void PackageManager::Update(PackageTask &taskContext,
return;
}

auto result = this->generateCache(newRef);
auto result = this->tryGenerateCache(newRef);
dengbo11 marked this conversation as resolved.
Show resolved Hide resolved
if (!result) {
taskContext.updateState(linglong::api::types::v1::State::Failed,
"Failed to generate some cache.\n" + result.error().message());
Expand Down Expand Up @@ -2179,19 +2179,22 @@ utils::error::Result<void> PackageManager::generateCache(const package::Referenc
}

const auto appCache = std::filesystem::path(LINGLONG_ROOT) / "cache" / layerItem->commit;
const auto appFontCache = appCache / "fontconfig";
const std::string appCacheDest = "/run/linglong/cache";
const std::string generatorDest = "/run/linglong/generator";
const std::string ldGenerator = generatorDest + "/ld-cache-generator";
const std::string fontGenerator = generatorDest + "/font-cache-generator";

utils::Transaction transaction;

#ifdef LINGLONG_FONT_CACHE_GENERATOR
const auto appFontCache = appCache / "fontconfig";
const std::string fontGenerator = generatorDest + "/font-cache-generator";
#endif
std::error_code ec;
if (!std::filesystem::exists(appFontCache, ec)) {
if (!std::filesystem::exists(appCache, ec)) {
if (ec) {
return LINGLONG_ERR(QString::fromStdString(ec.message()));
}
if (!std::filesystem::create_directories(appFontCache, ec)) {
if (!std::filesystem::create_directories(appCache, ec)) {
return LINGLONG_ERR(QString::fromStdString(ec.message()));
}
}
Expand All @@ -2212,13 +2215,15 @@ utils::error::Result<void> PackageManager::generateCache(const package::Referenc
.source = appCache,
.type = "bind",
});
#ifdef LINGLONG_FONT_CACHE_GENERATOR
// bind mount font cache
applicationMounts.push_back(ocppi::runtime::config::types::Mount{
.destination = "/var/cache/fontconfig",
.options = nlohmann::json::array({ "rbind", "rw" }),
.source = appFontCache,
.type = "bind",
});
#endif
// bind mount generator
applicationMounts.push_back(ocppi::runtime::config::types::Mount{
.destination = generatorDest,
Expand Down Expand Up @@ -2275,9 +2280,13 @@ utils::error::Result<void> PackageManager::generateCache(const package::Referenc
// font-cache-generator [cacheRoot] [id]
const std::string ldGenerateCmd = ldGenerator + " " + appCacheDest + " " + ref.id.toStdString()
+ " " + currentArch->getTriplet().toStdString();
#ifdef LINGLONG_FONT_CACHE_GENERATOR
const std::string fontGenerateCmd =
fontGenerator + " " + appCacheDest + " " + ref.id.toStdString();
process.args = std::vector<std::string>{ "bash", "-c", ldGenerateCmd + ";" + fontGenerateCmd };
#endif

process.args = std::vector<std::string>{ "bash", "-c", ldGenerateCmd };

// Note: XDG_RUNTIME_DIR is not set in PM, the ll-box will finally fallback to /run/ll-box.
// But PM has no write permission in that place, so we should specific the root path.
Expand All @@ -2296,6 +2305,18 @@ utils::error::Result<void> PackageManager::generateCache(const package::Referenc
return LINGLONG_OK;
}

// we should allow cache generation to fail, skip it when an error occurs by. the function can be
// removed later when the kernel clone new_user problem is solved.
utils::error::Result<void> PackageManager::tryGenerateCache(const package::Reference &ref) noexcept
{
auto ret = generateCache(ref);
if (!ret) {
qWarning() << "failed to generate cache" << ret.error();
}

return LINGLONG_OK;
}

utils::error::Result<void> PackageManager::removeCache(const package::Reference &ref) noexcept
{
LINGLONG_TRACE("remove the cache of " + ref.toString());
Expand Down
Loading
Loading