mirror of
https://invent.kde.org/marcoa/a-la-karte.git
synced 2026-02-09 21:13:08 +00:00
184 lines
6.4 KiB
C++
184 lines
6.4 KiB
C++
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||
|
|
// SPDX-FileCopyrightText: 2026 A-La-Karte Contributors
|
||
|
|
|
||
|
|
#include "systemdusermanager.h"
|
||
|
|
|
||
|
|
#include <QDBusArgument>
|
||
|
|
#include <QDBusConnection>
|
||
|
|
#include <QDBusInterface>
|
||
|
|
#include <QDBusMessage>
|
||
|
|
#include <QDBusMetaType>
|
||
|
|
#include <QDBusVariant>
|
||
|
|
|
||
|
|
static QDBusArgument &operator<<(QDBusArgument &argument, const SystemdProperty &prop)
|
||
|
|
{
|
||
|
|
argument.beginStructure();
|
||
|
|
argument << prop.name << QDBusVariant(prop.value);
|
||
|
|
argument.endStructure();
|
||
|
|
return argument;
|
||
|
|
}
|
||
|
|
|
||
|
|
static const QDBusArgument &operator>>(const QDBusArgument &argument, SystemdProperty &prop)
|
||
|
|
{
|
||
|
|
QDBusVariant variant;
|
||
|
|
|
||
|
|
argument.beginStructure();
|
||
|
|
argument >> prop.name >> variant;
|
||
|
|
argument.endStructure();
|
||
|
|
|
||
|
|
prop.value = variant.variant();
|
||
|
|
return argument;
|
||
|
|
}
|
||
|
|
|
||
|
|
static QDBusArgument &operator<<(QDBusArgument &argument, const SystemdAuxUnit &unit)
|
||
|
|
{
|
||
|
|
argument.beginStructure();
|
||
|
|
argument << unit.name << unit.properties;
|
||
|
|
argument.endStructure();
|
||
|
|
return argument;
|
||
|
|
}
|
||
|
|
|
||
|
|
static const QDBusArgument &operator>>(const QDBusArgument &argument, SystemdAuxUnit &unit)
|
||
|
|
{
|
||
|
|
argument.beginStructure();
|
||
|
|
argument >> unit.name >> unit.properties;
|
||
|
|
argument.endStructure();
|
||
|
|
return argument;
|
||
|
|
}
|
||
|
|
|
||
|
|
static QDBusArgument &operator<<(QDBusArgument &argument, const SystemdUnitInfo &info)
|
||
|
|
{
|
||
|
|
argument.beginStructure();
|
||
|
|
argument << info.name << info.description << info.loadState << info.activeState << info.subState << info.following << info.objectPath << info.jobId
|
||
|
|
<< info.jobType << info.jobPath;
|
||
|
|
argument.endStructure();
|
||
|
|
return argument;
|
||
|
|
}
|
||
|
|
|
||
|
|
static const QDBusArgument &operator>>(const QDBusArgument &argument, SystemdUnitInfo &info)
|
||
|
|
{
|
||
|
|
argument.beginStructure();
|
||
|
|
argument >> info.name >> info.description >> info.loadState >> info.activeState >> info.subState >> info.following >> info.objectPath >> info.jobId
|
||
|
|
>> info.jobType >> info.jobPath;
|
||
|
|
argument.endStructure();
|
||
|
|
return argument;
|
||
|
|
}
|
||
|
|
|
||
|
|
SystemdUserManager::SystemdUserManager(QObject *parent)
|
||
|
|
: QObject(parent)
|
||
|
|
{
|
||
|
|
ensureTypesRegistered();
|
||
|
|
}
|
||
|
|
|
||
|
|
void SystemdUserManager::ensureTypesRegistered()
|
||
|
|
{
|
||
|
|
static bool registered = false;
|
||
|
|
if (registered) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
qDBusRegisterMetaType<SystemdProperty>();
|
||
|
|
qDBusRegisterMetaType<SystemdProperties>();
|
||
|
|
qDBusRegisterMetaType<SystemdAuxUnit>();
|
||
|
|
qDBusRegisterMetaType<SystemdAuxUnits>();
|
||
|
|
qDBusRegisterMetaType<SystemdUnitInfo>();
|
||
|
|
qDBusRegisterMetaType<SystemdUnitInfoList>();
|
||
|
|
|
||
|
|
registered = true;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool SystemdUserManager::isAvailable() const
|
||
|
|
{
|
||
|
|
QDBusInterface manager(QStringLiteral("org.freedesktop.systemd1"),
|
||
|
|
QStringLiteral("/org/freedesktop/systemd1"),
|
||
|
|
QStringLiteral("org.freedesktop.systemd1.Manager"),
|
||
|
|
QDBusConnection::sessionBus());
|
||
|
|
|
||
|
|
return manager.isValid();
|
||
|
|
}
|
||
|
|
|
||
|
|
QDBusReply<QDBusObjectPath> SystemdUserManager::startTransientScope(const QString &unitName, const QList<uint> &pids, const QString &description)
|
||
|
|
{
|
||
|
|
QDBusInterface manager(QStringLiteral("org.freedesktop.systemd1"),
|
||
|
|
QStringLiteral("/org/freedesktop/systemd1"),
|
||
|
|
QStringLiteral("org.freedesktop.systemd1.Manager"),
|
||
|
|
QDBusConnection::sessionBus());
|
||
|
|
|
||
|
|
SystemdProperties props;
|
||
|
|
props.push_back({QStringLiteral("Description"), description});
|
||
|
|
props.push_back({QStringLiteral("PIDs"), QVariant::fromValue(pids)});
|
||
|
|
props.push_back({QStringLiteral("CollectMode"), QStringLiteral("inactive-or-failed")});
|
||
|
|
props.push_back({QStringLiteral("KillMode"), QStringLiteral("control-group")});
|
||
|
|
props.push_back({QStringLiteral("SendSIGKILL"), true});
|
||
|
|
props.push_back({QStringLiteral("TimeoutStopUSec"), static_cast<qulonglong>(10) * 1000 * 1000});
|
||
|
|
|
||
|
|
const SystemdAuxUnits aux;
|
||
|
|
|
||
|
|
const QDBusMessage reply =
|
||
|
|
manager.call(QStringLiteral("StartTransientUnit"), unitName, QStringLiteral("replace"), QVariant::fromValue(props), QVariant::fromValue(aux));
|
||
|
|
return QDBusReply<QDBusObjectPath>(reply);
|
||
|
|
}
|
||
|
|
|
||
|
|
QDBusReply<QDBusObjectPath> SystemdUserManager::stopUnit(const QString &unitName, const QString &mode)
|
||
|
|
{
|
||
|
|
QDBusInterface manager(QStringLiteral("org.freedesktop.systemd1"),
|
||
|
|
QStringLiteral("/org/freedesktop/systemd1"),
|
||
|
|
QStringLiteral("org.freedesktop.systemd1.Manager"),
|
||
|
|
QDBusConnection::sessionBus());
|
||
|
|
|
||
|
|
const QDBusMessage reply = manager.call(QStringLiteral("StopUnit"), unitName, mode);
|
||
|
|
return QDBusReply<QDBusObjectPath>(reply);
|
||
|
|
}
|
||
|
|
|
||
|
|
QDBusReply<QDBusObjectPath> SystemdUserManager::getUnit(const QString &unitName)
|
||
|
|
{
|
||
|
|
QDBusInterface manager(QStringLiteral("org.freedesktop.systemd1"),
|
||
|
|
QStringLiteral("/org/freedesktop/systemd1"),
|
||
|
|
QStringLiteral("org.freedesktop.systemd1.Manager"),
|
||
|
|
QDBusConnection::sessionBus());
|
||
|
|
|
||
|
|
const QDBusMessage reply = manager.call(QStringLiteral("GetUnit"), unitName);
|
||
|
|
return QDBusReply<QDBusObjectPath>(reply);
|
||
|
|
}
|
||
|
|
|
||
|
|
QDBusReply<SystemdUnitInfoList> SystemdUserManager::listUnits()
|
||
|
|
{
|
||
|
|
QDBusInterface manager(QStringLiteral("org.freedesktop.systemd1"),
|
||
|
|
QStringLiteral("/org/freedesktop/systemd1"),
|
||
|
|
QStringLiteral("org.freedesktop.systemd1.Manager"),
|
||
|
|
QDBusConnection::sessionBus());
|
||
|
|
|
||
|
|
const QDBusMessage reply = manager.call(QStringLiteral("ListUnits"));
|
||
|
|
return QDBusReply<SystemdUnitInfoList>(reply);
|
||
|
|
}
|
||
|
|
|
||
|
|
QList<uint> SystemdUserManager::scopePids(const QDBusObjectPath &unitPath)
|
||
|
|
{
|
||
|
|
QDBusInterface unit(QStringLiteral("org.freedesktop.systemd1"),
|
||
|
|
unitPath.path(),
|
||
|
|
QStringLiteral("org.freedesktop.systemd1.Unit"),
|
||
|
|
QDBusConnection::sessionBus());
|
||
|
|
|
||
|
|
const QDBusMessage reply = unit.call(QStringLiteral("GetProcesses"));
|
||
|
|
if (reply.type() != QDBusMessage::ReplyMessage || reply.arguments().isEmpty()) {
|
||
|
|
return {};
|
||
|
|
}
|
||
|
|
|
||
|
|
QList<uint> pids;
|
||
|
|
const QDBusArgument arg = reply.arguments().first().value<QDBusArgument>();
|
||
|
|
arg.beginArray();
|
||
|
|
while (!arg.atEnd()) {
|
||
|
|
arg.beginStructure();
|
||
|
|
QString cgroupPath;
|
||
|
|
uint pid = 0;
|
||
|
|
QString cmdline;
|
||
|
|
arg >> cgroupPath >> pid >> cmdline;
|
||
|
|
arg.endStructure();
|
||
|
|
if (pid > 0) {
|
||
|
|
pids.push_back(pid);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
arg.endArray();
|
||
|
|
return pids;
|
||
|
|
}
|