1#include "kiogui_debug.h"
2#include "managerinterface.h"
3#include "scopedprocessrunner_p.h"
4#include "systemdprocessrunner_p.h"
5
6#include <sys/eventfd.h>
7
8using namespace org::freedesktop;
9
10ScopedProcessRunner::ScopedProcessRunner()
11 : ForkingProcessRunner()
12{
13}
14
15void ScopedProcessRunner::startProcess()
16{
17 std::function oldModifier = m_process->childProcessModifier();
18 int efd = eventfd(count: 0, EFD_CLOEXEC);
19 m_process->setChildProcessModifier([efd, oldModifier]() {
20 // wait for the parent process to be done registering the transient unit
21 eventfd_read(fd: efd, value: nullptr);
22 if (oldModifier)
23 oldModifier();
24 });
25
26 // actually start
27 ForkingProcessRunner::startProcess();
28 m_process->setChildProcessModifier(oldModifier);
29
30 Q_ASSERT(m_process->processId());
31
32 // As specified in "XDG standardization for applications" in https://systemd.io/DESKTOP_ENVIRONMENTS/
33 const QString serviceName = QStringLiteral("app-%1-%2.scope").arg(args: escapeUnitName(input: resolveServiceAlias()), args: QUuid::createUuid().toString(mode: QUuid::Id128));
34
35 const auto manager = new systemd1::Manager(systemdService, systemdPath, QDBusConnection::sessionBus(), this);
36
37 // Ask systemd for a new transient service
38 const auto startReply =
39 manager->StartTransientUnit(name: serviceName,
40 QStringLiteral("fail"), // mode defines what to do in the case of a name conflict, in this case, just do nothing
41 properties: {// Properties of the transient service unit
42 {QStringLiteral("Slice"), QStringLiteral("app.slice")},
43 {QStringLiteral("Description"), .value: m_description},
44 {QStringLiteral("SourcePath"), .value: m_desktopFilePath},
45 {QStringLiteral("PIDs"), .value: QVariant::fromValue(value: QList<uint>{static_cast<uint>(m_process->processId())})}},
46 aux: {} // aux is currently unused and should be passed as empty array.
47 );
48
49 connect(sender: new QDBusPendingCallWatcher(startReply, this), signal: &QDBusPendingCallWatcher::finished, slot: [serviceName, efd](QDBusPendingCallWatcher *watcher) {
50 QDBusPendingReply<QDBusObjectPath> reply = *watcher;
51 watcher->deleteLater();
52 if (reply.isError()) {
53 qCWarning(KIO_GUI) << "Failed to register new cgroup:" << serviceName << reply.error().name() << reply.error().message();
54 } else {
55 qCDebug(KIO_GUI) << "Successfully registered new cgroup:" << serviceName;
56 }
57
58 // release child and close the eventfd
59 eventfd_write(fd: efd, value: 1);
60 close(fd: efd);
61 });
62}
63
64#include "moc_scopedprocessrunner_p.cpp"
65

source code of kio/src/gui/systemd/scopedprocessrunner.cpp