a-la-karte/src/gamecenter/systemdusermanager.cpp

184 lines
6.4 KiB
C++
Raw Normal View History

// 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;
}