diff --git a/src/util/externalcommand.h b/src/util/externalcommand.h --- a/src/util/externalcommand.h +++ b/src/util/externalcommand.h @@ -25,28 +25,27 @@ #include #include #include -#include #include #include #include namespace KAuth { class ExecuteJob; } class KJob; -class Report; + class CopySource; class CopyTarget; -class QDBusInterface; +class Report; struct ExternalCommandPrivate; class DBusThread : public QThread { Q_OBJECT - // We register on DBus so the helper can monitor us and terminate if we - // terminate. + // We register on DBus so the helper can monitor us and terminate if we terminate. Q_CLASSINFO("D-Bus Interface", "org.kde.kpmcore.applicationinterface") + void run() override; }; @@ -102,8 +101,6 @@ /**< @return pointer to the Report or nullptr */ Report* report(); - void emitReport(const QVariantMap& report) { emit reportSignal(report); } - /**< Dummy function for QTimer when needed. */ void quit(); @@ -127,10 +124,11 @@ public Q_SLOTS: void emitProgress(KJob*, unsigned long percent) { emit progress(percent); } + void emitReport(const QVariantMap& report) { emit reportSignal(report); } private: void setExitCode(int i); - void onReadOutput(); + // void onReadOutput(); private: std::unique_ptr d; diff --git a/src/util/externalcommand.cpp b/src/util/externalcommand.cpp --- a/src/util/externalcommand.cpp +++ b/src/util/externalcommand.cpp @@ -29,17 +29,13 @@ #include "externalcommandhelper_interface.h" -#include -#include -#include -#include +#include #include -#include #include #include #include -#include #include +#include #include #include @@ -185,9 +181,13 @@ // TODO KF6:Use new signal-slot syntax connect(m_job, SIGNAL(percent(KJob*, unsigned long)), this, SLOT(emitProgress(KJob*, unsigned long))); connect(m_job, &KAuth::ExecuteJob::newData, this, &ExternalCommand::emitReport); - - auto *interface = new org::kde::kpmcore::externalcommand(QStringLiteral("org.kde.kpmcore.externalcommand"), - QStringLiteral("/Helper"), QDBusConnection::systemBus(), this); + + /* + * Remove above signals and connect to the signals emitted by the helper + * as soon as we do not depend upon KAuth anymore + */ + + auto interface = new org::kde::kpmcore::externalcommand(QStringLiteral("org.kde.kpmcore.externalcommand"), QStringLiteral("/Helper"), QDBusConnection::systemBus(), this); interface->setTimeout(10 * 24 * 3600 * 1000); // 10 days QDBusPendingCall pcall = interface->copyblocks(source.path(), source.firstByte(), source.length(), @@ -274,8 +274,8 @@ return start(timeout) /* && exitStatus() == 0*/; } -void ExternalCommand::onReadOutput() -{ +//void ExternalCommand::onReadOutput() +//{ // const QByteArray s = readAllStandardOutput(); // // if(m_Output.length() > 10*1024*1024) { // prevent memory overflow for badly corrupted file systems @@ -288,7 +288,7 @@ // // if (report()) // *report() << QString::fromLocal8Bit(s); -} +//} void ExternalCommand::setCommand(const QString& cmd) { @@ -354,6 +354,7 @@ } QDBusInterface iface(QStringLiteral("org.kde.kpmcore.helperinterface"), QStringLiteral("/Helper"), QStringLiteral("org.kde.kpmcore.externalcommand"), QDBusConnection::systemBus()); + if (iface.isValid()) { exit(0); } @@ -374,6 +375,11 @@ QEventLoop loop; auto exitLoop = [&] () { loop.exit(); }; auto conn = QObject::connect(m_job, &KAuth::ExecuteJob::newData, exitLoop); + /* + * Use helper's reportProgress() and progress(0 signal + * instead of newData which HelperSupport::progressStep() internally sends + */ + QObject::connect(m_job, &KJob::finished, [=] () { if(m_job->error()) exitLoop(); } ); loop.exec(); QObject::disconnect(conn); @@ -384,10 +390,9 @@ void ExternalCommand::stopHelper() { - auto *interface = new org::kde::kpmcore::externalcommand(QStringLiteral("org.kde.kpmcore.externalcommand"), - QStringLiteral("/Helper"), QDBusConnection::systemBus()); + auto interface = new org::kde::kpmcore::externalcommand(QStringLiteral("org.kde.kpmcore.externalcommand"), + QStringLiteral("/Helper"), QDBusConnection::systemBus()); interface->exit(); - } void DBusThread::run() diff --git a/src/util/externalcommandhelper.h b/src/util/externalcommandhelper.h --- a/src/util/externalcommandhelper.h +++ b/src/util/externalcommandhelper.h @@ -1,6 +1,7 @@ /************************************************************************* * Copyright (C) 2017-2018 by Andrius Štikonas * - * * + * Copyright (C) 2019 by Shubham * + * * * 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 * @@ -18,43 +19,40 @@ #ifndef KPMCORE_EXTERNALCOMMANDHELPER_H #define KPMCORE_EXTERNALCOMMANDHELPER_H +#include "util/externalcommand.h" + #include #include -#include - #include -#include #include - -using namespace KAuth; +#include class ExternalCommandHelper : public QObject { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.kde.kpmcore.externalcommand") Q_SIGNALS: - void progress(int); - void quit(); + void progress(int percent); + void reportProgress(const QVariantMap &progress); public: bool readData(const QString& sourceDevice, QByteArray& buffer, const qint64 offset, const qint64 size); bool writeData(const QString& targetDevice, const QByteArray& buffer, const qint64 offset); public Q_SLOTS: - ActionReply init(const QVariantMap& args); + Q_SCRIPTABLE QVariantMap init(QVariantMap reply); Q_SCRIPTABLE QVariantMap start(const QString& command, const QStringList& arguments, const QByteArray& input, const int processChannelMode); Q_SCRIPTABLE QVariantMap copyblocks(const QString& sourceDevice, const qint64 sourceFirstByte, const qint64 sourceLength, const QString& targetDevice, const qint64 targetFirstByte, const qint64 blockSize); Q_SCRIPTABLE bool writeData(const QByteArray& buffer, const QString& targetDevice, const qint64 targetFirstByte); Q_SCRIPTABLE void exit(); private: - void onReadOutput(); - std::unique_ptr m_loop; QProcess m_cmd; -// QByteArray output; + + // void onReadOutput(); }; -#endif +#endif // KPMCORE_EXTERNALCOMMANDHELPER_H diff --git a/src/util/externalcommandhelper.cpp b/src/util/externalcommandhelper.cpp --- a/src/util/externalcommandhelper.cpp +++ b/src/util/externalcommandhelper.cpp @@ -1,5 +1,6 @@ /************************************************************************* * Copyright (C) 2017-2018 by Andrius Štikonas * + * Copyright (C) 2019 by Shubham * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License as * @@ -18,19 +19,20 @@ #include "externalcommandhelper.h" #include "externalcommand_whitelist.h" -#include #include +#include #include #include #include #include #include +#include #include /** Initialize ExternalCommandHelper Daemon and prepare DBus interface * - * KAuth helper runs in the background until application exits. + * Helper runs in the background until application exits. * To avoid forever running helper in case of application crash * ExternalCommand class opens a DBus service that we monitor for changes. * If helper is not busy then it exits when the client services gets @@ -42,16 +44,13 @@ * command execution requests from the application that started the helper. * */ -ActionReply ExternalCommandHelper::init(const QVariantMap& args) -{ - Q_UNUSED(args) - - ActionReply reply; +QVariantMap ExternalCommandHelper::init(QVariantMap reply) +{ if (!QDBusConnection::systemBus().isConnected() || !QDBusConnection::systemBus().registerService(QStringLiteral("org.kde.kpmcore.helperinterface")) || !QDBusConnection::systemBus().registerObject(QStringLiteral("/Helper"), this, QDBusConnection::ExportAllSlots)) { qWarning() << QDBusConnection::systemBus().lastError().message(); - reply.addData(QStringLiteral("success"), false); + reply[QStringLiteral("success")] = false; // Also end the application loop started by KAuth's main() code. Our loop // exits when our client disappears. Without client we have no reason to @@ -62,25 +61,23 @@ } m_loop = std::make_unique(); - HelperSupport::progressStep(QVariantMap()); - - // End the loop and return only once the client is done using us. - auto serviceWatcher = - new QDBusServiceWatcher(QStringLiteral("org.kde.kpmcore.applicationinterface"), - QDBusConnection::systemBus(), - QDBusServiceWatcher::WatchForUnregistration, - this); + emit reportProgress(QVariantMap()); + + // QDBus Srvice watcher which keeps an eye on the client (Main GUI app) + // End the loop and return only once the client has unregistered over the QDBus. + auto serviceWatcher = new QDBusServiceWatcher(QStringLiteral("org.kde.kpmcore.applicationinterface"), + QDBusConnection::systemBus(), + QDBusServiceWatcher::WatchForUnregistration, + this); + connect(serviceWatcher, &QDBusServiceWatcher::serviceUnregistered, [this]() { m_loop->exit(); }); m_loop->exec(); - reply.addData(QStringLiteral("success"), true); + reply[QStringLiteral("success")] = true; - // Also end the application loop started by KAuth's main() code. Our loop - // exits when our client disappears. Without client we have no reason to - // live. qApp->quit(); return reply; @@ -151,7 +148,7 @@ { QVariantMap reply; reply[QStringLiteral("success")] = true; - + const qint64 blocksToCopy = sourceLength / blockSize; qint64 readOffset = sourceFirstByte; qint64 writeOffset = targetFirstByte; @@ -180,8 +177,8 @@ sourceLength, readOffset, writeOffset, copyDirection == 1 ? i18nc("direction: left", "left") : i18nc("direction: right", "right")); - HelperSupport::progressStep(report); - + emit reportProgress(report); + bool rval = true; while (blocksCopied < blocksToCopy && !targetDevice.isEmpty()) { @@ -200,9 +197,9 @@ const qint64 mibsPerSec = (blocksCopied * blockSize / 1024 / 1024) / (t.elapsed() / 1000); const qint64 estSecsLeft = (100 - percent) * t.elapsed() / percent / 1000; report[QStringLiteral("report")]= xi18nc("@info:progress", "Copying %1 MiB/second, estimated time left: %2", mibsPerSec, QTime(0, 0).addSecs(estSecsLeft).toString()); - HelperSupport::progressStep(report); + emit reportProgress(report); } - HelperSupport::progressStep(percent); + emit progress(percent); } } @@ -212,8 +209,11 @@ const qint64 lastBlockReadOffset = copyDirection > 0 ? readOffset + blockSize * blocksCopied : sourceFirstByte; const qint64 lastBlockWriteOffset = copyDirection > 0 ? writeOffset + blockSize * blocksCopied : targetFirstByte; + report[QStringLiteral("report")]= xi18nc("@info:progress", "Copying remainder of block size %1 from %2 to %3.", lastBlock, lastBlockReadOffset, lastBlockWriteOffset); - HelperSupport::progressStep(report); + + emit reportProgress(report); + rval = readData(sourceDevice, buffer, lastBlockReadOffset, lastBlock); if (rval) { @@ -224,13 +224,14 @@ } if (rval) { - HelperSupport::progressStep(100); + emit progress(100); bytesWritten += buffer.size(); } } report[QStringLiteral("report")] = xi18ncp("@info:progress argument 2 is a string such as 7 bytes (localized accordingly)", "Copying 1 block (%2) finished.", "Copying %1 blocks (%2) finished.", blocksCopied, i18np("1 byte", "%1 bytes", bytesWritten)); - HelperSupport::progressStep(report); + + emit reportProgress(report); reply[QStringLiteral("success")] = rval; return reply; @@ -260,20 +261,21 @@ // Compare with command whitelist QString basename = command.mid(command.lastIndexOf(QLatin1Char('/')) + 1); if (std::find(std::begin(allowedCommands), std::end(allowedCommands), basename) == std::end(allowedCommands)) { - qInfo() << command <<" command is not one of the whitelisted command"; + qInfo() << command <<"Command is not one of the whitelisted command"; m_loop->exit(); reply[QStringLiteral("success")] = false; return reply; } -// connect(&cmd, &QProcess::readyReadStandardOutput, this, &ExternalCommandHelper::onReadOutput); + // connect(&cmd, &QProcess::readyReadStandardOutput, this, &ExternalCommandHelper::onReadOutput); m_cmd.setEnvironment( { QStringLiteral("LVM_SUPPRESS_FD_WARNINGS=1") } ); m_cmd.setProcessChannelMode(static_cast(processChannelMode)); m_cmd.start(command, arguments); m_cmd.write(input); m_cmd.closeWriteChannel(); m_cmd.waitForFinished(-1); + QByteArray output = m_cmd.readAllStandardOutput(); reply[QStringLiteral("output")] = output; reply[QStringLiteral("exitCode")] = m_cmd.exitCode(); @@ -289,9 +291,9 @@ QDBusConnection::systemBus().unregisterService(QStringLiteral("org.kde.kpmcore.helperinterface")); } -void ExternalCommandHelper::onReadOutput() +/*void ExternalCommandHelper::onReadOutput() { -/* const QByteArray s = cmd.readAllStandardOutput(); + const QByteArray s = cmd.readAllStandardOutput(); if(output.length() > 10*1024*1024) { // prevent memory overflow for badly corrupted file systems if (report()) @@ -302,7 +304,7 @@ output += s; if (report()) - *report() << QString::fromLocal8Bit(s);*/ -} + *report() << QString::fromLocal8Bit(s); +}*/ KAUTH_HELPER_MAIN("org.kde.kpmcore.externalcommand", ExternalCommandHelper)