/************************************************************************* * Copyright (C) 2008 by Volker Lanz * * Copyright (C) 2016 by Andrius Štikonas * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License as * * published by the Free Software Foundation; either version 3 of * * the License, or (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see .* *************************************************************************/ #include "core/operationrunner.h" #include "core/operationstack.h" #include "ops/operation.h" #include "util/report.h" #include #include #include #include #include /** Constructs an OperationRunner. @param ostack the OperationStack to act on */ OperationRunner::OperationRunner(QObject* parent, OperationStack& ostack) : QThread(parent), m_OperationStack(ostack), m_Report(nullptr), m_SuspendMutex(), m_Cancelling(false) { } /** Runs the operations in the OperationStack. */ void OperationRunner::run() { Q_ASSERT(m_Report); setCancelling(false); bool status = true; // Disable Plasma removable device automounting unsigned int currentUid = getuid(); // 0 if running as root char *login = getlogin(); if (login != nullptr){ passwd* pwnam = getpwnam(login); if (pwnam != nullptr) { unsigned int userId = pwnam->pw_uid; // uid of original user before sudo seteuid(userId); } } QStringList modules; QDBusConnection bus = QDBusConnection::connectToBus(QDBusConnection::SessionBus, QStringLiteral("sessionBus")); QDBusInterface kdedInterface( QStringLiteral("org.kde.kded5"), QStringLiteral("/kded"), QStringLiteral("org.kde.kded5"), bus ); QDBusReply reply = kdedInterface.call( QStringLiteral("loadedModules") ); if ( reply.isValid() ) modules = reply.value(); QString automounterService = QStringLiteral("device_automounter"); bool automounter = modules.contains(automounterService); if (automounter) kdedInterface.call( QStringLiteral("unloadModule"), automounterService ); seteuid(currentUid); for (int i = 0; i < numOperations(); i++) { suspendMutex().lock(); if (!status || isCancelling()) { suspendMutex().unlock(); break; } Operation* op = operationStack().operations()[i]; op->setStatus(Operation::StatusRunning); emit opStarted(i + 1, op); connect(op, &Operation::progress, this, &OperationRunner::progressSub); status = op->execute(report()); op->preview(); disconnect(op, &Operation::progress, this, &OperationRunner::progressSub); emit opFinished(i + 1, op); suspendMutex().unlock(); // Sleep a little to give others a chance to suspend us. This should normally not be // required -- is it possible that the compiler just optimizes our unlock/lock away // if we don't sleep? msleep(5); } if (automounter) kdedInterface.call( QStringLiteral("loadModule"), automounterService ); if (!status) emit error(); else if (isCancelling()) emit cancelled(); else emit finished(); } /** @return the number of Operations to run */ qint32 OperationRunner::numOperations() const { return operationStack().operations().size(); } /** @return the number of Jobs to run */ qint32 OperationRunner::numJobs() const { qint32 result = 0; for (const auto &op : operationStack().operations()) result += op->jobs().size(); return result; } /** @param op the number of the Operation to get a description for @return the Operation's description */ QString OperationRunner::description(qint32 op) const { Q_ASSERT(op >= 0); Q_ASSERT(op < operationStack().size()); return operationStack().operations()[op]->description(); }