#include "kiogui_debug.h" #include "managerinterface.h" #include "scopedprocessrunner_p.h" #include "systemdprocessrunner_p.h" #include #include using namespace org::freedesktop; ScopedProcessRunner::ScopedProcessRunner() : ForkingProcessRunner() { } void ScopedProcessRunner::startProcess() { std::function oldModifier = m_process->childProcessModifier(); int efd = eventfd(0, EFD_CLOEXEC); m_process->setChildProcessModifier([efd, oldModifier]() { // wait for the parent process to be done registering the transient unit eventfd_read(efd, nullptr); if (oldModifier) oldModifier(); }); // actually start ForkingProcessRunner::startProcess(); m_process->setChildProcessModifier(oldModifier); Q_ASSERT(m_process->processId()); // As specified in "XDG standardization for applications" in https://systemd.io/DESKTOP_ENVIRONMENTS/ const QString serviceName = QStringLiteral("app-%1-%2.scope").arg(escapeUnitName(resolveServiceAlias()), QUuid::createUuid().toString(QUuid::Id128)); const auto manager = new systemd1::Manager(systemdService, systemdPath, QDBusConnection::sessionBus(), this); // Ask systemd for a new transient service const auto startReply = manager->StartTransientUnit(serviceName, QStringLiteral("fail"), // mode defines what to do in the case of a name conflict, in this case, just do nothing {// Properties of the transient service unit {QStringLiteral("Slice"), QStringLiteral("app.slice")}, {QStringLiteral("Description"), m_description}, {QStringLiteral("SourcePath"), m_desktopFilePath}, {QStringLiteral("PIDs"), QVariant::fromValue(QList{static_cast(m_process->processId())})}}, {} // aux is currently unused and should be passed as empty array. ); m_transientUnitStartupwatcher = new QDBusPendingCallWatcher(startReply, this); connect(m_transientUnitStartupwatcher, &QDBusPendingCallWatcher::finished, [serviceName, efd](QDBusPendingCallWatcher *watcher) { QDBusPendingReply reply = *watcher; watcher->deleteLater(); if (reply.isError()) { qCWarning(KIO_GUI) << "Failed to register new cgroup:" << serviceName << reply.error().name() << reply.error().message(); } else { qCDebug(KIO_GUI) << "Successfully registered new cgroup:" << serviceName; } // release child and close the eventfd eventfd_write(efd, 1); close(efd); }); } bool ScopedProcessRunner::waitForStarted(int timeout) { if (m_process->state() == QProcess::NotRunning || m_waitingForXdgToken || !m_transientUnitStartupwatcher->isFinished()) { QEventLoop loop; QObject::connect(m_process.get(), &QProcess::stateChanged, &loop, &QEventLoop::quit); QObject::connect(m_transientUnitStartupwatcher, &QDBusPendingCallWatcher::finished, &loop, &QEventLoop::quit); QTimer::singleShot(timeout, &loop, &QEventLoop::quit); loop.exec(); } return m_process->waitForStarted(timeout); } #include "moc_scopedprocessrunner_p.cpp"