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 <heyuming@deepin.org>
This commit is contained in:
parent
bcb9d0c3e5
commit
aca0531e85
@ -142,7 +142,8 @@ int processExecStart(msg_ptr &msg, const std::deque<std::string_view> &execArgs)
|
|||||||
DBusValueType getPropType(std::string_view key)
|
DBusValueType getPropType(std::string_view key)
|
||||||
{
|
{
|
||||||
static std::unordered_map<std::string_view, DBusValueType> map{{"Environment", DBusValueType::ArrayOfString},
|
static std::unordered_map<std::string_view, DBusValueType> map{{"Environment", DBusValueType::ArrayOfString},
|
||||||
{"WorkingDirectory", DBusValueType::String}};
|
{"WorkingDirectory", DBusValueType::String},
|
||||||
|
{"ExecSearchPath", DBusValueType::ArrayOfString}};
|
||||||
|
|
||||||
if (auto it = map.find(key); it != map.cend()) {
|
if (auto it = map.find(key); it != map.cend()) {
|
||||||
return it->second;
|
return it->second;
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
constexpr auto SystemdService = u8"org.freedesktop.systemd1";
|
constexpr auto SystemdService = u8"org.freedesktop.systemd1";
|
||||||
constexpr auto SystemdObjectPath = 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 SystemdInterfaceName = u8"org.freedesktop.systemd1.Manager";
|
||||||
constexpr auto SystemdUnitInterfaceName = u8"org.freedesktop.systemd1.Unit";
|
constexpr auto SystemdUnitInterfaceName = u8"org.freedesktop.systemd1.Unit";
|
||||||
constexpr auto DDEApplicationManager1ServiceName =
|
constexpr auto DDEApplicationManager1ServiceName =
|
||||||
|
@ -67,6 +67,24 @@ void ApplicationManager1Service::initService(QDBusConnection &connection) noexce
|
|||||||
this,
|
this,
|
||||||
&ApplicationManager1Service::removeInstanceFromApplication);
|
&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<QStringList>(ret.arguments().first().value<QDBusVariant>().variant()));
|
||||||
|
|
||||||
auto sysBus = QDBusConnection::systemBus();
|
auto sysBus = QDBusConnection::systemBus();
|
||||||
if (!sysBus.connect("org.desktopspec.ApplicationUpdateNotifier1",
|
if (!sysBus.connect("org.desktopspec.ApplicationUpdateNotifier1",
|
||||||
"/org/desktopspec/ApplicationUpdateNotifier1",
|
"/org/desktopspec/ApplicationUpdateNotifier1",
|
||||||
|
@ -49,6 +49,7 @@ public:
|
|||||||
[[nodiscard]] const QStringList &applicationHooks() const noexcept { return m_hookElements; }
|
[[nodiscard]] const QStringList &applicationHooks() const noexcept { return m_hookElements; }
|
||||||
[[nodiscard]] MimeManager1Service &mimeManager() noexcept { return *m_mimeManager; }
|
[[nodiscard]] MimeManager1Service &mimeManager() noexcept { return *m_mimeManager; }
|
||||||
[[nodiscard]] const MimeManager1Service &mimeManager() const 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:
|
public Q_SLOTS:
|
||||||
QString Identify(const QDBusUnixFileDescriptor &pidfd,
|
QString Identify(const QDBusUnixFileDescriptor &pidfd,
|
||||||
@ -69,6 +70,7 @@ private:
|
|||||||
QScopedPointer<MimeManager1Service> m_mimeManager{nullptr};
|
QScopedPointer<MimeManager1Service> m_mimeManager{nullptr};
|
||||||
QScopedPointer<JobManager1Service> m_jobManager{nullptr};
|
QScopedPointer<JobManager1Service> m_jobManager{nullptr};
|
||||||
QStringList m_hookElements;
|
QStringList m_hookElements;
|
||||||
|
QStringList m_systemdPathEnv;
|
||||||
QMap<QDBusObjectPath, QSharedPointer<ApplicationService>> m_applicationList;
|
QMap<QDBusObjectPath, QSharedPointer<ApplicationService>> m_applicationList;
|
||||||
|
|
||||||
void scanMimeInfos() noexcept;
|
void scanMimeInfos() noexcept;
|
||||||
|
@ -32,6 +32,40 @@
|
|||||||
#include <utility>
|
#include <utility>
|
||||||
#include <wordexp.h>
|
#include <wordexp.h>
|
||||||
|
|
||||||
|
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<double> 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<QString>();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto &env : scaleEnvs) {
|
||||||
|
oldEnv.append(env.arg(factor));
|
||||||
|
}
|
||||||
|
|
||||||
|
runtimeOptions.insert("env", oldEnv);
|
||||||
|
}
|
||||||
|
|
||||||
ApplicationService::ApplicationService(DesktopFile source,
|
ApplicationService::ApplicationService(DesktopFile source,
|
||||||
ApplicationManager1Service *parent,
|
ApplicationManager1Service *parent,
|
||||||
std::weak_ptr<ApplicationManager1Storage> storage)
|
std::weak_ptr<ApplicationManager1Storage> storage)
|
||||||
@ -167,23 +201,6 @@ bool ApplicationService::shouldBeShown(const std::unique_ptr<DesktopEntry> &entr
|
|||||||
return true;
|
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<QString>();
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto &env : scaleEnvs) {
|
|
||||||
oldEnv.append(env.arg(factor));
|
|
||||||
}
|
|
||||||
|
|
||||||
optionsMap.insert("env", oldEnv);
|
|
||||||
}
|
|
||||||
|
|
||||||
QDBusObjectPath
|
QDBusObjectPath
|
||||||
ApplicationService::Launch(const QString &action, const QStringList &fields, const QVariantMap &options, const QString &realExec)
|
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();
|
const auto &supportedActions = actions();
|
||||||
auto optionsMap = options;
|
auto optionsMap = options;
|
||||||
|
|
||||||
appendScaleFactor(optionsMap);
|
appendRuntimeScaleFactor(*this, optionsMap);
|
||||||
|
|
||||||
if (!realExec.isNull()) { // we want to replace exec of this applications.
|
if (!realExec.isNull()) { // we want to replace exec of this applications.
|
||||||
if (realExec.isEmpty()) {
|
if (realExec.isEmpty()) {
|
||||||
@ -248,6 +265,8 @@ ApplicationService::Launch(const QString &action, const QStringList &fields, con
|
|||||||
if (const auto &hooks = parent()->applicationHooks(); !hooks.isEmpty()) {
|
if (const auto &hooks = parent()->applicationHooks(); !hooks.isEmpty()) {
|
||||||
optionsMap.insert("_hooks", hooks);
|
optionsMap.insert("_hooks", hooks);
|
||||||
}
|
}
|
||||||
|
optionsMap.insert("_builtIn_searchExec", parent()->systemdPathEnv());
|
||||||
|
|
||||||
auto cmds = generateCommand(optionsMap);
|
auto cmds = generateCommand(optionsMap);
|
||||||
auto task = unescapeExec(execStr, fields);
|
auto task = unescapeExec(execStr, fields);
|
||||||
if (!task) {
|
if (!task) {
|
||||||
@ -1112,20 +1131,3 @@ void ApplicationService::setAutostartSource(AutostartSource &&source) noexcept
|
|||||||
{
|
{
|
||||||
m_autostartSource = std::move(source);
|
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<double> ret1(reply1);
|
|
||||||
double scale = ret1.isValid() ? ret1.value() : 1.0;
|
|
||||||
scale = scale > 0 ? scale : 1;
|
|
||||||
return scale;
|
|
||||||
}
|
|
||||||
|
@ -23,10 +23,6 @@
|
|||||||
#include <QTextStream>
|
#include <QTextStream>
|
||||||
#include <QUuid>
|
#include <QUuid>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <qcontainerfwd.h>
|
|
||||||
#include <qvariant.h>
|
|
||||||
|
|
||||||
double getScaleFactor() noexcept;
|
|
||||||
|
|
||||||
struct AutostartSource
|
struct AutostartSource
|
||||||
{
|
{
|
||||||
@ -137,7 +133,6 @@ public:
|
|||||||
|
|
||||||
private Q_SLOTS:
|
private Q_SLOTS:
|
||||||
void onGlobalScaleFactorChanged() noexcept;
|
void onGlobalScaleFactorChanged() noexcept;
|
||||||
void appendScaleFactor(QVariantMap &optionsMap) const noexcept;
|
|
||||||
|
|
||||||
public Q_SLOTS:
|
public Q_SLOTS:
|
||||||
// NOTE: 'realExec' only for internal implementation
|
// NOTE: 'realExec' only for internal implementation
|
||||||
|
@ -19,8 +19,10 @@ QStringList generateCommand(const QVariantMap &props) noexcept
|
|||||||
options.emplace_back(std::make_unique<setEnvLaunchOption>(value));
|
options.emplace_back(std::make_unique<setEnvLaunchOption>(value));
|
||||||
} else if (key == hookLaunchOption::key()) {
|
} else if (key == hookLaunchOption::key()) {
|
||||||
options.emplace_back(std::make_unique<hookLaunchOption>(value));
|
options.emplace_back(std::make_unique<hookLaunchOption>(value));
|
||||||
} else if (key == setPathLaunchOption::key()) {
|
} else if (key == setWorkingPathLaunchOption::key()) {
|
||||||
options.emplace_back(std::make_unique<setPathLaunchOption>(value));
|
options.emplace_back(std::make_unique<setWorkingPathLaunchOption>(value));
|
||||||
|
} else if (key == builtInSearchExecOption::key()) {
|
||||||
|
options.emplace_back(std::make_unique<builtInSearchExecOption>(value));
|
||||||
} else {
|
} else {
|
||||||
qWarning() << "unsupported options" << key;
|
qWarning() << "unsupported options" << key;
|
||||||
}
|
}
|
||||||
@ -109,7 +111,7 @@ QStringList setEnvLaunchOption::generateCommandLine() const noexcept
|
|||||||
return QStringList{QString{"--Environment=%1"}.arg(str)};
|
return QStringList{QString{"--Environment=%1"}.arg(str)};
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList setPathLaunchOption::generateCommandLine() const noexcept
|
QStringList setWorkingPathLaunchOption::generateCommandLine() const noexcept
|
||||||
{
|
{
|
||||||
auto str = m_val.toString();
|
auto str = m_val.toString();
|
||||||
if (str.isEmpty()) {
|
if (str.isEmpty()) {
|
||||||
@ -118,3 +120,14 @@ QStringList setPathLaunchOption::generateCommandLine() const noexcept
|
|||||||
|
|
||||||
return QStringList{QString{"--WorkingDirectory=%1"}.arg(str)};
|
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)};
|
||||||
|
}
|
||||||
|
@ -88,13 +88,13 @@ struct hookLaunchOption : public LaunchOption
|
|||||||
}
|
}
|
||||||
[[nodiscard]] static const QString &key() noexcept
|
[[nodiscard]] static const QString &key() noexcept
|
||||||
{
|
{
|
||||||
static QString hook{"hook"};
|
static QString hook{"_hooks"};
|
||||||
return hook;
|
return hook;
|
||||||
}
|
}
|
||||||
[[nodiscard]] QStringList generateCommandLine() const noexcept override { return m_val.toStringList(); };
|
[[nodiscard]] QStringList generateCommandLine() const noexcept override { return m_val.toStringList(); };
|
||||||
};
|
};
|
||||||
|
|
||||||
struct setPathLaunchOption : public LaunchOption
|
struct setWorkingPathLaunchOption : public LaunchOption
|
||||||
{
|
{
|
||||||
using LaunchOption::LaunchOption;
|
using LaunchOption::LaunchOption;
|
||||||
[[nodiscard]] const QString &type() const noexcept override
|
[[nodiscard]] const QString &type() const noexcept override
|
||||||
@ -104,10 +104,26 @@ struct setPathLaunchOption : public LaunchOption
|
|||||||
}
|
}
|
||||||
[[nodiscard]] static const QString &key() noexcept
|
[[nodiscard]] static const QString &key() noexcept
|
||||||
{
|
{
|
||||||
static QString path{"path"};
|
static QString path{"workingPath"};
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
[[nodiscard]] QStringList generateCommandLine() const noexcept override;
|
[[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;
|
QStringList generateCommand(const QVariantMap &props) noexcept;
|
||||||
|
@ -28,9 +28,30 @@ bool SystemdSignalDispatcher::connectToSignals() noexcept
|
|||||||
return false;
|
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;
|
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)
|
void SystemdSignalDispatcher::onUnitNew(QString unitName, QDBusObjectPath systemdUnitPath)
|
||||||
{
|
{
|
||||||
if (!unitName.startsWith("app-")) {
|
if (!unitName.startsWith("app-")) {
|
||||||
|
@ -21,10 +21,12 @@ public:
|
|||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void SystemdUnitNew(QString unitName, QDBusObjectPath systemdUnitPath);
|
void SystemdUnitNew(QString unitName, QDBusObjectPath systemdUnitPath);
|
||||||
void SystemdUnitRemoved(QString unitName, QDBusObjectPath systemdUnitPath);
|
void SystemdUnitRemoved(QString unitName, QDBusObjectPath systemdUnitPath);
|
||||||
|
void SystemdEnvironmentChanged(QStringList envs);
|
||||||
|
|
||||||
private Q_SLOTS:
|
private Q_SLOTS:
|
||||||
void onUnitNew(QString unitName, QDBusObjectPath systemdUnitPath);
|
void onUnitNew(QString unitName, QDBusObjectPath systemdUnitPath);
|
||||||
void onUnitRemoved(QString unitName, QDBusObjectPath systemdUnitPath);
|
void onUnitRemoved(QString unitName, QDBusObjectPath systemdUnitPath);
|
||||||
|
void onPropertiesChanged(QString interface, QVariantMap props, QStringList invalid);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
explicit SystemdSignalDispatcher(QObject *parent = nullptr)
|
explicit SystemdSignalDispatcher(QObject *parent = nullptr)
|
||||||
|
Loading…
Reference in New Issue
Block a user