// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-FileCopyrightText: 2026 A-La-Karte Contributors #include "systemdusermanager.h" #include #include #include #include #include #include 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(); qDBusRegisterMetaType(); qDBusRegisterMetaType(); qDBusRegisterMetaType(); qDBusRegisterMetaType(); qDBusRegisterMetaType(); 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 SystemdUserManager::startTransientScope(const QString &unitName, const QList &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(10) * 1000 * 1000}); const SystemdAuxUnits aux; const QDBusMessage reply = manager.call(QStringLiteral("StartTransientUnit"), unitName, QStringLiteral("replace"), QVariant::fromValue(props), QVariant::fromValue(aux)); return QDBusReply(reply); } QDBusReply 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(reply); } QDBusReply 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(reply); } QDBusReply 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(reply); } QList 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 pids; const QDBusArgument arg = reply.arguments().first().value(); 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; }