-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
9c2242b
commit 186df54
Showing
5 changed files
with
305 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,150 @@ | ||
#include "UpdateLaunchEnvironment.hpp" | ||
|
||
#include <QDBusArgument> | ||
#include <QDBusConnection> | ||
#include <QDBusMetaType> | ||
#include <QDBusPendingReply> | ||
|
||
#include <QTimer> | ||
#include <qloggingcategory.h> | ||
|
||
#include "wrapper_logging.h" | ||
|
||
class UpdateLaunchEnvironmentJobPrivate | ||
{ | ||
public: | ||
explicit UpdateLaunchEnvironmentJobPrivate(UpdateLaunchEnvironmentJob *q); | ||
void monitorReply(const QDBusPendingReply<> &reply); | ||
|
||
static bool isPosixName(const QString &name); | ||
static bool isSystemdApprovedValue(const QString &value); | ||
|
||
UpdateLaunchEnvironmentJob *q; | ||
QProcessEnvironment environment; | ||
int pendingReplies = 0; | ||
}; | ||
|
||
UpdateLaunchEnvironmentJobPrivate::UpdateLaunchEnvironmentJobPrivate(UpdateLaunchEnvironmentJob *q) | ||
: q(q) | ||
{ | ||
} | ||
|
||
void UpdateLaunchEnvironmentJobPrivate::monitorReply(const QDBusPendingReply<> &reply) | ||
{ | ||
++pendingReplies; | ||
|
||
auto *watcher = new QDBusPendingCallWatcher(reply, q); | ||
QObject::connect(watcher, &QDBusPendingCallWatcher::finished, q, [this](QDBusPendingCallWatcher *watcher) { | ||
watcher->deleteLater(); | ||
--pendingReplies; | ||
|
||
if (pendingReplies == 0) { | ||
Q_EMIT q->finished(); | ||
q->deleteLater(); | ||
} | ||
}); | ||
} | ||
|
||
UpdateLaunchEnvironmentJob::UpdateLaunchEnvironmentJob(const QProcessEnvironment &environment) | ||
: d(new UpdateLaunchEnvironmentJobPrivate(this)) | ||
{ | ||
d->environment = environment; | ||
QTimer::singleShot(0, this, &UpdateLaunchEnvironmentJob::start); | ||
} | ||
|
||
UpdateLaunchEnvironmentJob::~UpdateLaunchEnvironmentJob() = default; | ||
|
||
void UpdateLaunchEnvironmentJob::start() | ||
{ | ||
qDBusRegisterMetaType<QMap<QString, QString>>(); | ||
QMap<QString, QString> dbusActivationEnv; | ||
QStringList systemdUpdates; | ||
|
||
for (const auto &varName : d->environment.keys()) { | ||
if (!UpdateLaunchEnvironmentJobPrivate::isPosixName(varName)) { | ||
qCWarning(KWIN_WRAPPER) << "Skipping syncing of environment variable " << varName << "as name contains unsupported characters"; | ||
continue; | ||
} | ||
const QString value = d->environment.value(varName); | ||
|
||
// plasma-session | ||
QDBusMessage lingmoSessionMsg = QDBusMessage::createMethodCall(QStringLiteral("com.lingmo.Session"), | ||
QStringLiteral("/Session"), | ||
QStringLiteral("com.lingmo.Session"), | ||
QStringLiteral("updateLaunchEnv")); | ||
lingmoSessionMsg.setArguments({QVariant::fromValue(varName), QVariant::fromValue(value)}); | ||
auto plasmaSessionReply = QDBusConnection::sessionBus().asyncCall(lingmoSessionMsg); | ||
d->monitorReply(plasmaSessionReply); | ||
|
||
// DBus-activation environment | ||
dbusActivationEnv.insert(varName, value); | ||
|
||
// _user_ systemd env | ||
// Systemd has stricter parsing of valid environment variables | ||
// https://github.com/systemd/systemd/issues/16704 | ||
// validate here | ||
if (!UpdateLaunchEnvironmentJobPrivate::isSystemdApprovedValue(value)) { | ||
qCWarning(KWIN_WRAPPER) << "Skipping syncing of environment variable " << varName << "as value contains unsupported characters"; | ||
continue; | ||
} | ||
const QString updateString = varName + QStringLiteral("=") + value; | ||
systemdUpdates.append(updateString); | ||
} | ||
|
||
// DBus-activation environment | ||
QDBusMessage dbusActivationMsg = QDBusMessage::createMethodCall(QStringLiteral("org.freedesktop.DBus"), | ||
QStringLiteral("/org/freedesktop/DBus"), | ||
QStringLiteral("org.freedesktop.DBus"), | ||
QStringLiteral("UpdateActivationEnvironment")); | ||
dbusActivationMsg.setArguments({QVariant::fromValue(dbusActivationEnv)}); | ||
|
||
auto dbusActivationReply = QDBusConnection::sessionBus().asyncCall(dbusActivationMsg); | ||
d->monitorReply(dbusActivationReply); | ||
|
||
// _user_ systemd env | ||
QDBusMessage systemdActivationMsg = QDBusMessage::createMethodCall(QStringLiteral("org.freedesktop.systemd1"), | ||
QStringLiteral("/org/freedesktop/systemd1"), | ||
QStringLiteral("org.freedesktop.systemd1.Manager"), | ||
QStringLiteral("SetEnvironment")); | ||
systemdActivationMsg.setArguments({systemdUpdates}); | ||
|
||
auto systemdActivationReply = QDBusConnection::sessionBus().asyncCall(systemdActivationMsg); | ||
d->monitorReply(systemdActivationReply); | ||
} | ||
|
||
bool UpdateLaunchEnvironmentJobPrivate::isPosixName(const QString &name) | ||
{ | ||
// Posix says characters like % should be 'tolerated', but it gives issues in practice. | ||
// https://bugzilla.redhat.com/show_bug.cgi?id=1754395 | ||
// https://bugzilla.redhat.com/show_bug.cgi?id=1879216 | ||
// Ensure systemd compat by only allowing alphanumerics and _ in names. | ||
bool first = true; | ||
for (const QChar c : name) { | ||
if (first && !c.isLetter() && c != QLatin1Char('_')) { | ||
return false; | ||
} else if (first) { | ||
first = false; | ||
} else if (!c.isLetterOrNumber() && c != QLatin1Char('_')) { | ||
return false; | ||
} | ||
} | ||
return !first; | ||
} | ||
|
||
bool UpdateLaunchEnvironmentJobPrivate::isSystemdApprovedValue(const QString &value) | ||
{ | ||
// systemd code checks that a value contains no control characters except \n \t | ||
// effectively copied from systemd's string_has_cc | ||
for (const char &it : value.toLatin1()) { | ||
if (it == QLatin1Char('\n') || it == QLatin1Char('\t')) { | ||
continue; | ||
} | ||
if (it > 0 && it < ' ') { | ||
return false; | ||
} | ||
if (it == 127) { | ||
return false; | ||
} | ||
} | ||
return true; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
/* | ||
SPDX-FileCopyrightText: 2020 Kai Uwe Broulik <[email protected]> | ||
SPDX-FileCopyrightText: 2021 David Edmundson <[email protected]> | ||
SPDX-FileCopyrightText: 2024 Elysia <[email protected]> | ||
SPDX-License-Identifier: LGPL-2.0-or-later | ||
*/ | ||
#ifndef UPDATELAUNCHENVIRONMENT_HPP | ||
#define UPDATELAUNCHENVIRONMENT_HPP | ||
|
||
#include <QProcessEnvironment> | ||
|
||
#include <memory> | ||
|
||
class QString; | ||
class UpdateLaunchEnvironmentJobPrivate; | ||
|
||
/** | ||
* @class UpdateLaunchEnvironmentJob updatelaunchenvironmentjob.h <UpdateLaunchEnvironmentJob> | ||
* | ||
* Job for updating the launch environment. | ||
* | ||
* This job adds or updates an environment variable in process environment that will be used | ||
* when a process is launched: | ||
* This includes: | ||
* - DBus activation | ||
* - Systemd units | ||
* - lingmo-session | ||
* | ||
* Environment variables are sanitized before uploading. | ||
* | ||
* This object deletes itself after completion, similar to KJobs | ||
*/ | ||
class UpdateLaunchEnvironmentJob : public QObject | ||
{ | ||
Q_OBJECT | ||
|
||
public: | ||
explicit UpdateLaunchEnvironmentJob(const QProcessEnvironment &environment); | ||
~UpdateLaunchEnvironmentJob() override; | ||
|
||
Q_SIGNALS: | ||
void finished(); | ||
|
||
private: | ||
void start(); | ||
|
||
private: | ||
std::unique_ptr<UpdateLaunchEnvironmentJobPrivate> const d; | ||
}; | ||
|
||
#endif // UPDATELAUNCHENVIRONMENT_HPP |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
/* | ||
SPDX-FileCopyrightText: 2021 Aleix Pol Gonzalez <[email protected]> | ||
SPDX-License-Identifier: LGPL-2.0-only | ||
*/ | ||
|
||
#include "signalhandler.h" | ||
#include "wrapper_logging.h" | ||
|
||
#include <QDebug> | ||
#include <signal.h> | ||
#include <sys/socket.h> | ||
#include <unistd.h> | ||
|
||
int SignalHandler::signalFd[2]; | ||
|
||
SignalHandler::SignalHandler() | ||
{ | ||
if (::socketpair(AF_UNIX, SOCK_STREAM, 0, signalFd)) { | ||
qCWarning(KWIN_WRAPPER) << "Couldn't create a socketpair"; | ||
return; | ||
} | ||
|
||
m_handler = new QSocketNotifier(signalFd[1], QSocketNotifier::Read, this); | ||
connect(m_handler, &QSocketNotifier::activated, this, &SignalHandler::handleSignal); | ||
} | ||
|
||
SignalHandler::~SignalHandler() | ||
{ | ||
for (int sig : std::as_const(m_signalsRegistered)) { | ||
signal(sig, nullptr); | ||
} | ||
close(signalFd[0]); | ||
close(signalFd[1]); | ||
} | ||
|
||
void SignalHandler::addSignal(int signalToTrack) | ||
{ | ||
m_signalsRegistered.insert(signalToTrack); | ||
signal(signalToTrack, signalHandler); | ||
} | ||
|
||
void SignalHandler::signalHandler(int signal) | ||
{ | ||
::write(signalFd[0], &signal, sizeof(signal)); | ||
} | ||
|
||
void SignalHandler::handleSignal() | ||
{ | ||
m_handler->setEnabled(false); | ||
int signal; | ||
::read(signalFd[1], &signal, sizeof(signal)); | ||
m_handler->setEnabled(true); | ||
|
||
Q_EMIT signalReceived(signal); | ||
} | ||
|
||
SignalHandler *SignalHandler::self() | ||
{ | ||
static SignalHandler s_self; | ||
return &s_self; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
/* | ||
SPDX-FileCopyrightText: 2021 Aleix Pol Gonzalez <[email protected]> | ||
SPDX-License-Identifier: LGPL-2.0-only | ||
*/ | ||
|
||
#pragma once | ||
|
||
#include <QObject> | ||
#include <QSet> | ||
#include <QSocketNotifier> | ||
|
||
/** | ||
* Class to be able to receive ANSI C signals and forward them onto the Qt eventloop | ||
* | ||
* It's a singleton as it relies on static data getting defined. | ||
*/ | ||
class SignalHandler : public QObject | ||
{ | ||
Q_OBJECT | ||
public: | ||
~SignalHandler() override; | ||
void addSignal(int signal); | ||
|
||
static SignalHandler *self(); | ||
|
||
Q_SIGNALS: | ||
void signalReceived(int signal); | ||
|
||
private: | ||
SignalHandler(); | ||
void handleSignal(); | ||
static void signalHandler(int signal); | ||
|
||
QSet<int> m_signalsRegistered; | ||
static int signalFd[2]; | ||
QSocketNotifier *m_handler = nullptr; | ||
}; |