diff --git a/src/libs/utils/ssh/sshremoteprocessrunner.cpp b/src/libs/utils/ssh/sshremoteprocessrunner.cpp index bc3cf00db18..ad1a7c79665 100644 --- a/src/libs/utils/ssh/sshremoteprocessrunner.cpp +++ b/src/libs/utils/ssh/sshremoteprocessrunner.cpp @@ -62,6 +62,10 @@ public: QByteArray m_command; Utils::SshError m_lastConnectionError; QString m_lastConnectionErrorString; + SshRemoteProcess::ExitStatus m_exitStatus; + QByteArray m_exitSignal; + int m_exitCode; + QString m_processErrorString; State m_state; }; @@ -84,6 +88,8 @@ SshRemoteProcessRunner::~SshRemoteProcessRunner() void SshRemoteProcessRunner::run(const QByteArray &command, const SshConnectionParameters &sshParams) { + QTC_ASSERT(d->m_state == Inactive, return); + d->m_runInTerminal = false; runInternal(command, sshParams); } @@ -99,11 +105,13 @@ void SshRemoteProcessRunner::runInTerminal(const QByteArray &command, void SshRemoteProcessRunner::runInternal(const QByteArray &command, const SshConnectionParameters &sshParams) { - setState(Inactive); setState(Connecting); d->m_lastConnectionError = SshNoError; d->m_lastConnectionErrorString.clear(); + d->m_processErrorString.clear(); + d->m_exitSignal.clear(); + d->m_exitCode = -1; d->m_command = command; d->m_connection = SshConnectionManager::instance().acquireConnection(sshParams); connect(d->m_connection.data(), SIGNAL(error(Utils::SshError)), @@ -158,17 +166,23 @@ void SshRemoteProcessRunner::handleProcessStarted() void SshRemoteProcessRunner::handleProcessFinished(int exitStatus) { - switch (exitStatus) { + d->m_exitStatus = static_cast(exitStatus); + switch (d->m_exitStatus) { case SshRemoteProcess::FailedToStart: QTC_ASSERT(d->m_state == Connected, return); break; case SshRemoteProcess::KilledBySignal: + QTC_ASSERT(d->m_state == ProcessRunning, return); + d->m_exitSignal = d->m_process->exitSignal(); + break; case SshRemoteProcess::ExitedNormally: QTC_ASSERT(d->m_state == ProcessRunning, return); + d->m_exitCode = d->m_process->exitCode(); break; default: Q_ASSERT_X(false, Q_FUNC_INFO, "Impossible exit status."); } + d->m_processErrorString = d->m_process->errorString(); setState(Inactive); emit processClosed(exitStatus); } @@ -190,8 +204,11 @@ void SshRemoteProcessRunner::setState(int newState) d->m_state = static_cast(newState); if (d->m_state == Inactive) { - if (d->m_process) + if (d->m_process) { disconnect(d->m_process.data(), 0, this, 0); + d->m_process->close(); + d->m_process.clear(); + } if (d->m_connection) { disconnect(d->m_connection.data(), 0, this, 0); SshConnectionManager::instance().releaseConnection(d->m_connection); @@ -202,9 +219,53 @@ void SshRemoteProcessRunner::setState(int newState) QByteArray SshRemoteProcessRunner::command() const { return d->m_command; } SshError SshRemoteProcessRunner::lastConnectionError() const { return d->m_lastConnectionError; } -SshRemoteProcess::Ptr SshRemoteProcessRunner::process() const { return d->m_process; } QString SshRemoteProcessRunner::lastConnectionErrorString() const { return d->m_lastConnectionErrorString; } +bool SshRemoteProcessRunner::isProcessRunning() const +{ + return d->m_process && d->m_process->isRunning(); +} + +SshRemoteProcess::ExitStatus SshRemoteProcessRunner::processExitStatus() const +{ + QTC_CHECK(!isProcessRunning()); + return d->m_exitStatus; +} + +QByteArray SshRemoteProcessRunner::processExitSignal() const +{ + QTC_CHECK(processExitStatus() == SshRemoteProcess::KilledBySignal); + return d->m_exitSignal; +} + +int SshRemoteProcessRunner::processExitCode() const +{ + QTC_CHECK(processExitStatus() == SshRemoteProcess::ExitedNormally); + return d->m_exitCode; +} + +QString SshRemoteProcessRunner::processErrorString() const +{ + return d->m_processErrorString; +} + +void SshRemoteProcessRunner::writeDataToProcess(const QByteArray &data) +{ + QTC_ASSERT(isProcessRunning(), return); + d->m_process->write(data); +} + +void SshRemoteProcessRunner::sendSignalToProcess(const QByteArray &signal) +{ + QTC_ASSERT(isProcessRunning(), return); + d->m_process->sendSignal(signal); +} + +void SshRemoteProcessRunner::cancel() +{ + setState(Inactive); +} + } // namespace Utils diff --git a/src/libs/utils/ssh/sshremoteprocessrunner.h b/src/libs/utils/ssh/sshremoteprocessrunner.h index 8c712f3bee8..4e809ba4087 100644 --- a/src/libs/utils/ssh/sshremoteprocessrunner.h +++ b/src/libs/utils/ssh/sshremoteprocessrunner.h @@ -57,7 +57,14 @@ public: Utils::SshError lastConnectionError() const; QString lastConnectionErrorString() const; - SshRemoteProcess::Ptr process() const; + bool isProcessRunning() const; + void writeDataToProcess(const QByteArray &data); + void sendSignalToProcess(const QByteArray &signal); // No effect with OpenSSH server. + void cancel(); // Does not stop remote process, just frees SSH-related process resources. + SshRemoteProcess::ExitStatus processExitStatus() const; + QByteArray processExitSignal() const; + int processExitCode() const; + QString processErrorString() const; private slots: void handleConnected(); diff --git a/src/plugins/debugger/lldb/lldbenginehost.cpp b/src/plugins/debugger/lldb/lldbenginehost.cpp index d5115bbd6ad..5f6892891b5 100644 --- a/src/plugins/debugger/lldb/lldbenginehost.cpp +++ b/src/plugins/debugger/lldb/lldbenginehost.cpp @@ -127,8 +127,7 @@ qint64 SshIODevice::readData (char * data, qint64 maxSize) void SshIODevice::processStarted() { - proc = runner->process(); - proc->write(startupbuffer); + runner->writeDataToProcess(startupbuffer); } void SshIODevice::outputAvailable(const QByteArray &output) @@ -197,10 +196,10 @@ LldbEngineHost::~LldbEngineHost() m_guestProcess->terminate(); m_guestProcess->kill(); } - if (m_ssh && m_ssh->process().data()) { + if (m_ssh && m_ssh->isProcessRunning()) { // TODO: openssh doesn't do that - m_ssh->process()->kill(); + m_ssh->sendSignalToProcess(Utils::SshRemoteProcess::KillSignal); } } diff --git a/src/plugins/madde/maddedevicetester.cpp b/src/plugins/madde/maddedevicetester.cpp index 80090f07d69..0968f206952 100644 --- a/src/plugins/madde/maddedevicetester.cpp +++ b/src/plugins/madde/maddedevicetester.cpp @@ -89,7 +89,7 @@ void MaddeDeviceTester::stopTest() case QtTest: case MadDeveloperTest: case QmlToolingTest: - m_processRunner->process()->close(); + m_processRunner->cancel(); break; } @@ -177,7 +177,7 @@ void MaddeDeviceTester::handleProcessFinished(int exitStatus) void MaddeDeviceTester::handleQtTestFinished(int exitStatus) { if (exitStatus != SshRemoteProcess::ExitedNormally - || m_processRunner->process()->exitCode() != 0) { + || m_processRunner->processExitCode() != 0) { if (!m_stderr.isEmpty()) { emit errorMessage(tr("Error checking for Qt libraries: %1\n") .arg(QString::fromUtf8(m_stderr))); @@ -209,7 +209,7 @@ void MaddeDeviceTester::handleMadDeveloperTestFinished(int exitStatus) emit errorMessage(tr("Error checking for connectivity tool.\n")); } m_result = TestFailure; - } else if (m_processRunner->process()->exitCode() != 0) { + } else if (m_processRunner->processExitCode() != 0) { QString message = tr("Connectivity tool not installed on device. " "Deployment currently not possible."); if (m_deviceConfiguration->osType() == QLatin1String(HarmattanOsType)) { @@ -247,7 +247,7 @@ void MaddeDeviceTester::handleQmlToolingTestFinished(int exitStatus) emit errorMessage(tr("Error checking for QML tooling support.\n")); } m_result = TestFailure; - } else if (m_processRunner->process()->exitCode() != 0) { + } else if (m_processRunner->processExitCode() != 0) { emit errorMessage(tr("Missing directory '%1'. You will not be able to do " "QML debugging on this device.\n").arg(QmlToolingDirectory)); m_result = TestFailure; diff --git a/src/plugins/madde/maemopublisherfremantlefree.cpp b/src/plugins/madde/maemopublisherfremantlefree.cpp index e0cf2f70432..70bd593a0e4 100644 --- a/src/plugins/madde/maemopublisherfremantlefree.cpp +++ b/src/plugins/madde/maemopublisherfremantlefree.cpp @@ -419,11 +419,11 @@ void MaemoPublisherFremantleFree::handleUploadJobFinished(int exitStatus) return); if (m_state != Inactive && (exitStatus != SshRemoteProcess::ExitedNormally - || m_uploader->process()->exitCode() != 0)) { + || m_uploader->processExitCode() != 0)) { QString error; if (exitStatus != SshRemoteProcess::ExitedNormally) { error = tr("Error uploading file: %1.") - .arg(m_uploader->process()->errorString()); + .arg(m_uploader->processErrorString()); } else { error = tr("Error uploading file."); } @@ -447,7 +447,7 @@ void MaemoPublisherFremantleFree::prepareToSendFile() emit progressReport(tr("Uploading file %1 ...") .arg(QDir::toNativeSeparators(nextFilePath))); QFileInfo info(nextFilePath); - m_uploader->process()->write("C0644 " + QByteArray::number(info.size()) + m_uploader->writeDataToProcess("C0644 " + QByteArray::number(info.size()) + ' ' + info.fileName().toUtf8() + '\n'); } @@ -473,13 +473,13 @@ void MaemoPublisherFremantleFree::sendFile() tr("Upload failed.")); return; } - m_uploader->process()->write(data); + m_uploader->writeDataToProcess(data); bytesToSend -= data.size(); QCoreApplication::processEvents(); if (m_state == Inactive) return; } - m_uploader->process()->write(QByteArray(1, '\0')); + m_uploader->writeDataToProcess(QByteArray(1, '\0')); } void MaemoPublisherFremantleFree::handleScpStdOut(const QByteArray &output) diff --git a/src/plugins/madde/maemoremotecopyfacility.cpp b/src/plugins/madde/maemoremotecopyfacility.cpp index 8e50a7e4c35..84780b633fb 100644 --- a/src/plugins/madde/maemoremotecopyfacility.cpp +++ b/src/plugins/madde/maemoremotecopyfacility.cpp @@ -108,7 +108,7 @@ void MaemoRemoteCopyFacility::handleCopyFinished(int exitStatus) return; if (exitStatus != SshRemoteProcess::ExitedNormally - || m_copyRunner->process()->exitCode() != 0) { + || m_copyRunner->processExitCode() != 0) { setFinished(); emit finished(tr("Error: Copy command failed.")); } else { diff --git a/src/plugins/remotelinux/remotelinuxcustomcommanddeployservice.cpp b/src/plugins/remotelinux/remotelinuxcustomcommanddeployservice.cpp index d489d550300..3538edddde1 100644 --- a/src/plugins/remotelinux/remotelinuxcustomcommanddeployservice.cpp +++ b/src/plugins/remotelinux/remotelinuxcustomcommanddeployservice.cpp @@ -115,7 +115,7 @@ void RemoteLinuxCustomCommandDeployService::stopDeployment() QTC_ASSERT(d->state == Running, return); disconnect(d->runner, 0, this, 0); - d->runner->process()->close(); + d->runner->cancel(); d->state = Inactive; handleDeploymentDone(); } @@ -138,9 +138,9 @@ void RemoteLinuxCustomCommandDeployService::handleProcessClosed(int exitStatus) emit errorMessage(tr("Remote process failed to start.")); } else if (exitStatus == SshRemoteProcess::KilledBySignal) { emit errorMessage(tr("Remote process was killed by a signal.")); - } else if (d->runner->process()->exitCode() != 0) { + } else if (d->runner->processExitCode() != 0) { emit errorMessage(tr("Remote process finished with exit code %1.") - .arg(d->runner->process()->exitCode())); + .arg(d->runner->processExitCode())); } else { emit progressMessage(tr("Remote command finished successfully.")); } diff --git a/src/plugins/remotelinux/remotelinuxenvironmentreader.cpp b/src/plugins/remotelinux/remotelinuxenvironmentreader.cpp index ddbff80c58a..cfc7375c7a2 100644 --- a/src/plugins/remotelinux/remotelinuxenvironmentreader.cpp +++ b/src/plugins/remotelinux/remotelinuxenvironmentreader.cpp @@ -118,7 +118,7 @@ void RemoteLinuxEnvironmentReader::remoteProcessFinished(int exitCode) } } else { QString errorMsg = tr("Error running remote process: %1") - .arg(m_remoteProcessRunner->process()->errorString()); + .arg(m_remoteProcessRunner->processErrorString()); if (!m_remoteErrorOutput.isEmpty()) { errorMsg += tr("\nRemote stderr was: '%1'") .arg(QString::fromUtf8(m_remoteErrorOutput)); diff --git a/src/plugins/remotelinux/remotelinuxpackageinstaller.cpp b/src/plugins/remotelinux/remotelinuxpackageinstaller.cpp index 74d1381abd8..b6ef9f10037 100644 --- a/src/plugins/remotelinux/remotelinuxpackageinstaller.cpp +++ b/src/plugins/remotelinux/remotelinuxpackageinstaller.cpp @@ -112,8 +112,7 @@ void AbstractRemoteLinuxPackageInstaller::handleInstallationFinished(int exitSta if (!d->isRunning) return; - if (exitStatus != SshRemoteProcess::ExitedNormally - || d->installer->process()->exitCode() != 0) { + if (exitStatus != SshRemoteProcess::ExitedNormally || d->installer->processExitCode() != 0) { emit finished(tr("Installing package failed.")); } else if (!errorString().isEmpty()) { emit finished(errorString()); diff --git a/src/plugins/remotelinux/remotelinuxprocesslist.cpp b/src/plugins/remotelinux/remotelinuxprocesslist.cpp index c13a3c818f5..c9fecb5ed17 100644 --- a/src/plugins/remotelinux/remotelinuxprocesslist.cpp +++ b/src/plugins/remotelinux/remotelinuxprocesslist.cpp @@ -168,14 +168,14 @@ void AbstractRemoteLinuxProcessList::handleRemoteProcessFinished(int exitStatus) switch (exitStatus) { case SshRemoteProcess::FailedToStart: d->errorMsg = tr("Error: Remote process failed to start: %1") - .arg(d->process.process()->errorString()); + .arg(d->process.processErrorString()); break; case SshRemoteProcess::KilledBySignal: d->errorMsg = tr("Error: Remote process crashed: %1") - .arg(d->process.process()->errorString()); + .arg(d->process.processErrorString()); break; case SshRemoteProcess::ExitedNormally: - if (d->process.process()->exitCode() == 0) { + if (d->process.processExitCode() == 0) { if (d->state == Listing) { d->remoteProcesses = buildProcessList(QString::fromUtf8(d->remoteStdout.data(), d->remoteStdout.count())); diff --git a/src/plugins/remotelinux/remotelinuxusedportsgatherer.cpp b/src/plugins/remotelinux/remotelinuxusedportsgatherer.cpp index 8ee066edd82..a239edfae05 100644 --- a/src/plugins/remotelinux/remotelinuxusedportsgatherer.cpp +++ b/src/plugins/remotelinux/remotelinuxusedportsgatherer.cpp @@ -162,18 +162,18 @@ void RemoteLinuxUsedPortsGatherer::handleProcessClosed(int exitStatus) switch (exitStatus) { case SshRemoteProcess::FailedToStart: errMsg = tr("Could not start remote process: %1") - .arg(d->procRunner.process()->errorString()); + .arg(d->procRunner.processErrorString()); break; case SshRemoteProcess::KilledBySignal: errMsg = tr("Remote process crashed: %1") - .arg(d->procRunner.process()->errorString()); + .arg(d->procRunner.processErrorString()); break; case SshRemoteProcess::ExitedNormally: - if (d->procRunner.process()->exitCode() == 0) { + if (d->procRunner.processExitCode() == 0) { setupUsedPorts(); } else { errMsg = tr("Remote process failed; exit code was %1.") - .arg(d->procRunner.process()->exitCode()); + .arg(d->procRunner.processExitCode()); } break; default: diff --git a/src/plugins/remotelinux/sshkeydeployer.cpp b/src/plugins/remotelinux/sshkeydeployer.cpp index 117eea1f8a2..9908700fd27 100644 --- a/src/plugins/remotelinux/sshkeydeployer.cpp +++ b/src/plugins/remotelinux/sshkeydeployer.cpp @@ -91,11 +91,8 @@ void SshKeyDeployer::handleKeyUploadFinished(int exitStatus) || exitStatus == SshRemoteProcess::KilledBySignal || exitStatus == SshRemoteProcess::ExitedNormally); - if (!d->deployProcess.process()) - return; - - const int exitCode = d->deployProcess.process()->exitCode(); - const QString errorMsg = d->deployProcess.process()->errorString(); + const int exitCode = d->deployProcess.processExitCode(); + const QString errorMsg = d->deployProcess.processErrorString(); cleanup(); if (exitStatus == SshRemoteProcess::ExitedNormally && exitCode == 0) emit finishedSuccessfully(); diff --git a/tests/manual/ssh/remoteprocess/remoteprocesstest.cpp b/tests/manual/ssh/remoteprocess/remoteprocesstest.cpp index 7f5fcd63cda..1979f7e34a6 100644 --- a/tests/manual/ssh/remoteprocess/remoteprocesstest.cpp +++ b/tests/manual/ssh/remoteprocess/remoteprocesstest.cpp @@ -146,7 +146,7 @@ void RemoteProcessTest::handleProcessClosed(int exitStatus) } switch (m_state) { case TestingSuccess: { - const int exitCode = m_remoteRunner->process()->exitCode(); + const int exitCode = m_remoteRunner->processExitCode(); if (exitCode != 0) { std::cerr << "Error: exit code is " << exitCode << ", expected zero." << std::endl; @@ -168,7 +168,7 @@ void RemoteProcessTest::handleProcessClosed(int exitStatus) break; } case TestingFailure: { - const int exitCode = m_remoteRunner->process()->exitCode(); + const int exitCode = m_remoteRunner->processExitCode(); if (exitCode == 0) { std::cerr << "Error: exit code is zero, expected non-zero." << std::endl; @@ -194,7 +194,7 @@ void RemoteProcessTest::handleProcessClosed(int exitStatus) qApp->quit(); break; case TestingTerminal: { - const int exitCode = m_remoteRunner->process()->exitCode(); + const int exitCode = m_remoteRunner->processExitCode(); if (exitCode != 0) { std::cerr << "Error: exit code is " << exitCode << ", expected zero." << std::endl;