From aca0531e855fcd7605353fe208c8286197c3fdd6 Mon Sep 17 00:00:00 2001 From: ComixHe Date: Thu, 1 Feb 2024 17:30:59 +0800 Subject: [PATCH] fix: support ExecSearchPath to prevent systemd from not finding binaries In NixOS, maintainer used a patch to modify the DEFAULT_PATH macro of systemd. However, systemd can only find its own binaries under that path. At this point, if you take the relative path of the binary as a parameter to StartTransientUnit, systemd will use DEFAULT_PATH to look for the binary, which will cause systemd to not find it. There may be other Linux distributions that change this path, so add ExecSearchPath to prevent systemd from not finding the binary. Signed-off-by: ComixHe --- apps/app-launch-helper/src/main.cpp | 3 +- src/constant.h | 1 + src/dbus/applicationmanager1service.cpp | 18 +++++++ src/dbus/applicationmanager1service.h | 2 + src/dbus/applicationservice.cpp | 72 +++++++++++++------------ src/dbus/applicationservice.h | 5 -- src/launchoptions.cpp | 19 +++++-- src/launchoptions.h | 22 ++++++-- src/systemdsignaldispatcher.cpp | 21 ++++++++ src/systemdsignaldispatcher.h | 2 + 10 files changed, 118 insertions(+), 47 deletions(-) diff --git a/apps/app-launch-helper/src/main.cpp b/apps/app-launch-helper/src/main.cpp index 995e846..ed7fda7 100644 --- a/apps/app-launch-helper/src/main.cpp +++ b/apps/app-launch-helper/src/main.cpp @@ -142,7 +142,8 @@ int processExecStart(msg_ptr &msg, const std::deque &execArgs) DBusValueType getPropType(std::string_view key) { static std::unordered_map map{{"Environment", DBusValueType::ArrayOfString}, - {"WorkingDirectory", DBusValueType::String}}; + {"WorkingDirectory", DBusValueType::String}, + {"ExecSearchPath", DBusValueType::ArrayOfString}}; if (auto it = map.find(key); it != map.cend()) { return it->second; diff --git a/src/constant.h b/src/constant.h index 9021c42..a76e599 100644 --- a/src/constant.h +++ b/src/constant.h @@ -7,6 +7,7 @@ constexpr auto SystemdService = u8"org.freedesktop.systemd1"; constexpr auto SystemdObjectPath = u8"/org/freedesktop/systemd1"; +constexpr auto SystemdPropInterfaceName = u8"org.freedesktop.DBus.Properties"; constexpr auto SystemdInterfaceName = u8"org.freedesktop.systemd1.Manager"; constexpr auto SystemdUnitInterfaceName = u8"org.freedesktop.systemd1.Unit"; constexpr auto DDEApplicationManager1ServiceName = diff --git a/src/dbus/applicationmanager1service.cpp b/src/dbus/applicationmanager1service.cpp index fca4d76..f885168 100644 --- a/src/dbus/applicationmanager1service.cpp +++ b/src/dbus/applicationmanager1service.cpp @@ -67,6 +67,24 @@ void ApplicationManager1Service::initService(QDBusConnection &connection) noexce this, &ApplicationManager1Service::removeInstanceFromApplication); + auto envToPath = [this](const QStringList &envs) { + if (auto path = std::find_if(envs.cbegin(), envs.cend(), [](const QString &env) { return env.startsWith("PATH="); }); + path != envs.cend()) { + m_systemdPathEnv = path->mid(5).split(':', Qt::SkipEmptyParts); + } + }; + + connect(&dispatcher, &SystemdSignalDispatcher::SystemdEnvironmentChanged, envToPath); + + auto &con = ApplicationManager1DBus::instance().globalDestBus(); + auto envMsg = QDBusMessage::createMethodCall(SystemdService, SystemdObjectPath, SystemdPropInterfaceName, "Get"); + envMsg.setArguments({SystemdInterfaceName, "Environment"}); + auto ret = con.call(envMsg); + if (ret.type() == QDBusMessage::ErrorMessage) { + qFatal("%s", ret.errorMessage().toLocal8Bit().data()); + } + envToPath(qdbus_cast(ret.arguments().first().value().variant())); + auto sysBus = QDBusConnection::systemBus(); if (!sysBus.connect("org.desktopspec.ApplicationUpdateNotifier1", "/org/desktopspec/ApplicationUpdateNotifier1", diff --git a/src/dbus/applicationmanager1service.h b/src/dbus/applicationmanager1service.h index df88cfa..fbcb660 100644 --- a/src/dbus/applicationmanager1service.h +++ b/src/dbus/applicationmanager1service.h @@ -49,6 +49,7 @@ public: [[nodiscard]] const QStringList &applicationHooks() const noexcept { return m_hookElements; } [[nodiscard]] MimeManager1Service &mimeManager() noexcept { return *m_mimeManager; } [[nodiscard]] const MimeManager1Service &mimeManager() const noexcept { return *m_mimeManager; } + [[nodiscard]] const QStringList &systemdPathEnv() const noexcept { return m_systemdPathEnv; } public Q_SLOTS: QString Identify(const QDBusUnixFileDescriptor &pidfd, @@ -69,6 +70,7 @@ private: QScopedPointer m_mimeManager{nullptr}; QScopedPointer m_jobManager{nullptr}; QStringList m_hookElements; + QStringList m_systemdPathEnv; QMap> m_applicationList; void scanMimeInfos() noexcept; diff --git a/src/dbus/applicationservice.cpp b/src/dbus/applicationservice.cpp index cb8190d..ae8c690 100644 --- a/src/dbus/applicationservice.cpp +++ b/src/dbus/applicationservice.cpp @@ -32,6 +32,40 @@ #include #include +double getScaleFactor() noexcept +{ + auto sessionBus = QDBusConnection::sessionBus(); + QDBusMessage reply1 = sessionBus.call(QDBusMessage::createMethodCall( + "org.deepin.dde.XSettings1", "/org/deepin/dde/XSettings1", "org.deepin.dde.XSettings1", "GetScaleFactor")); + + if (reply1.type() != QDBusMessage::ReplyMessage) { + qWarning() << "call GetScaleFactor Failed:" << reply1.errorMessage(); + return 1.0; + } + + QDBusReply ret1(reply1); + double scale = ret1.isValid() ? ret1.value() : 1.0; + scale = scale > 0 ? scale : 1; + return scale; +} + +void appendRuntimeScaleFactor(const ApplicationService &app, QVariantMap &runtimeOptions) noexcept +{ + static QStringList scaleEnvs{"DEEPIN_WINE_SCALE=%1;", "GDK_DPI_SCALE=%1;", "QT_SCALE_FACTOR=%1;", "GDK_SCALE=%1;"}; + QString oldEnv; + + auto factor = app.scaleFactor(); + if (auto it = runtimeOptions.find("env"); it != runtimeOptions.cend()) { + oldEnv = it->value(); + } + + for (const auto &env : scaleEnvs) { + oldEnv.append(env.arg(factor)); + } + + runtimeOptions.insert("env", oldEnv); +} + ApplicationService::ApplicationService(DesktopFile source, ApplicationManager1Service *parent, std::weak_ptr storage) @@ -167,23 +201,6 @@ bool ApplicationService::shouldBeShown(const std::unique_ptr &entr return true; } -void ApplicationService::appendScaleFactor(QVariantMap &optionsMap) const noexcept -{ - static QStringList scaleEnvs{"DEEPIN_WINE_SCALE=%1;", "GDK_DPI_SCALE=%1;", "QT_SCALE_FACTOR=%1;", "GDK_SCALE=%1;"}; - QString oldEnv; - - auto factor = scaleFactor(); - if (auto it = optionsMap.find("env"); it != optionsMap.cend()) { - oldEnv = it->value(); - } - - for (const auto &env : scaleEnvs) { - oldEnv.append(env.arg(factor)); - } - - optionsMap.insert("env", oldEnv); -} - QDBusObjectPath ApplicationService::Launch(const QString &action, const QStringList &fields, const QVariantMap &options, const QString &realExec) { @@ -191,7 +208,7 @@ ApplicationService::Launch(const QString &action, const QStringList &fields, con const auto &supportedActions = actions(); auto optionsMap = options; - appendScaleFactor(optionsMap); + appendRuntimeScaleFactor(*this, optionsMap); if (!realExec.isNull()) { // we want to replace exec of this applications. if (realExec.isEmpty()) { @@ -248,6 +265,8 @@ ApplicationService::Launch(const QString &action, const QStringList &fields, con if (const auto &hooks = parent()->applicationHooks(); !hooks.isEmpty()) { optionsMap.insert("_hooks", hooks); } + optionsMap.insert("_builtIn_searchExec", parent()->systemdPathEnv()); + auto cmds = generateCommand(optionsMap); auto task = unescapeExec(execStr, fields); if (!task) { @@ -1112,20 +1131,3 @@ void ApplicationService::setAutostartSource(AutostartSource &&source) noexcept { m_autostartSource = std::move(source); } - -double getScaleFactor() noexcept -{ - auto sessionBus = QDBusConnection::sessionBus(); - QDBusMessage reply1 = sessionBus.call(QDBusMessage::createMethodCall( - "org.deepin.dde.XSettings1", "/org/deepin/dde/XSettings1", "org.deepin.dde.XSettings1", "GetScaleFactor")); - - if (reply1.type() != QDBusMessage::ReplyMessage) { - qWarning() << "call GetScaleFactor Failed:" << reply1.errorMessage(); - return 1.0; - } - - QDBusReply ret1(reply1); - double scale = ret1.isValid() ? ret1.value() : 1.0; - scale = scale > 0 ? scale : 1; - return scale; -} diff --git a/src/dbus/applicationservice.h b/src/dbus/applicationservice.h index 1159091..a8ad251 100644 --- a/src/dbus/applicationservice.h +++ b/src/dbus/applicationservice.h @@ -23,10 +23,6 @@ #include #include #include -#include -#include - -double getScaleFactor() noexcept; struct AutostartSource { @@ -137,7 +133,6 @@ public: private Q_SLOTS: void onGlobalScaleFactorChanged() noexcept; - void appendScaleFactor(QVariantMap &optionsMap) const noexcept; public Q_SLOTS: // NOTE: 'realExec' only for internal implementation diff --git a/src/launchoptions.cpp b/src/launchoptions.cpp index 8921dcf..04371c9 100644 --- a/src/launchoptions.cpp +++ b/src/launchoptions.cpp @@ -19,8 +19,10 @@ QStringList generateCommand(const QVariantMap &props) noexcept options.emplace_back(std::make_unique(value)); } else if (key == hookLaunchOption::key()) { options.emplace_back(std::make_unique(value)); - } else if (key == setPathLaunchOption::key()) { - options.emplace_back(std::make_unique(value)); + } else if (key == setWorkingPathLaunchOption::key()) { + options.emplace_back(std::make_unique(value)); + } else if (key == builtInSearchExecOption::key()) { + options.emplace_back(std::make_unique(value)); } else { qWarning() << "unsupported options" << key; } @@ -109,7 +111,7 @@ QStringList setEnvLaunchOption::generateCommandLine() const noexcept return QStringList{QString{"--Environment=%1"}.arg(str)}; } -QStringList setPathLaunchOption::generateCommandLine() const noexcept +QStringList setWorkingPathLaunchOption::generateCommandLine() const noexcept { auto str = m_val.toString(); if (str.isEmpty()) { @@ -118,3 +120,14 @@ QStringList setPathLaunchOption::generateCommandLine() const noexcept return QStringList{QString{"--WorkingDirectory=%1"}.arg(str)}; } + +QStringList builtInSearchExecOption::generateCommandLine() const noexcept +{ + auto list = m_val.toStringList(); + if (list.isEmpty()) { + return {}; + } + + auto content = list.join(';'); + return QStringList{QString{"--ExecSearchPath=%1"}.arg(content)}; +} diff --git a/src/launchoptions.h b/src/launchoptions.h index 8775bca..f1deeb2 100644 --- a/src/launchoptions.h +++ b/src/launchoptions.h @@ -88,13 +88,13 @@ struct hookLaunchOption : public LaunchOption } [[nodiscard]] static const QString &key() noexcept { - static QString hook{"hook"}; + static QString hook{"_hooks"}; return hook; } [[nodiscard]] QStringList generateCommandLine() const noexcept override { return m_val.toStringList(); }; }; -struct setPathLaunchOption : public LaunchOption +struct setWorkingPathLaunchOption : public LaunchOption { using LaunchOption::LaunchOption; [[nodiscard]] const QString &type() const noexcept override @@ -104,10 +104,26 @@ struct setPathLaunchOption : public LaunchOption } [[nodiscard]] static const QString &key() noexcept { - static QString path{"path"}; + static QString path{"workingPath"}; return path; } [[nodiscard]] QStringList generateCommandLine() const noexcept override; }; +struct builtInSearchExecOption : public LaunchOption +{ + using LaunchOption::LaunchOption; + [[nodiscard]] const QString &type() const noexcept override + { + static QString tp{systemdOption}; + return tp; + } + [[nodiscard]] static const QString &key() noexcept + { + static QString key{"_builtIn_searchExec"}; + return key; + } + [[nodiscard]] QStringList generateCommandLine() const noexcept override; +}; + QStringList generateCommand(const QVariantMap &props) noexcept; diff --git a/src/systemdsignaldispatcher.cpp b/src/systemdsignaldispatcher.cpp index 4308ef3..df729c8 100644 --- a/src/systemdsignaldispatcher.cpp +++ b/src/systemdsignaldispatcher.cpp @@ -28,9 +28,30 @@ bool SystemdSignalDispatcher::connectToSignals() noexcept return false; } + if (!con.connect(SystemdService, + SystemdObjectPath, + SystemdPropInterfaceName, + "PropertiesChanged", + this, + SLOT(onPropertiesChanged(QString, QVariantMap, QStringList)))) { + qCritical() << "can't connect to PropertiesChanged signal of systemd service."; + return false; + } + return true; } +void SystemdSignalDispatcher::onPropertiesChanged(QString interface, QVariantMap props, [[maybe_unused]] QStringList invalid) +{ + if (interface != SystemdPropInterfaceName) { + return; + } + + if (auto it = props.find("Environment"); it != props.end()) { + emit SystemdEnvironmentChanged(it->toStringList()); + } +} + void SystemdSignalDispatcher::onUnitNew(QString unitName, QDBusObjectPath systemdUnitPath) { if (!unitName.startsWith("app-")) { diff --git a/src/systemdsignaldispatcher.h b/src/systemdsignaldispatcher.h index 6a7cfb9..5bd3ada 100644 --- a/src/systemdsignaldispatcher.h +++ b/src/systemdsignaldispatcher.h @@ -21,10 +21,12 @@ public: Q_SIGNALS: void SystemdUnitNew(QString unitName, QDBusObjectPath systemdUnitPath); void SystemdUnitRemoved(QString unitName, QDBusObjectPath systemdUnitPath); + void SystemdEnvironmentChanged(QStringList envs); private Q_SLOTS: void onUnitNew(QString unitName, QDBusObjectPath systemdUnitPath); void onUnitRemoved(QString unitName, QDBusObjectPath systemdUnitPath); + void onPropertiesChanged(QString interface, QVariantMap props, QStringList invalid); private: explicit SystemdSignalDispatcher(QObject *parent = nullptr)