From 0bef62481bc1b91ca360a1b6e2045fa5f52cfb10 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Thu, 21 Apr 2016 11:49:10 +0200 Subject: [PATCH] RemoteLinux: Allow killing processes by ID Killing every process on the system that happens to have the same name as the one we've started is error prone and dangerous. We might kill processes we haven't started and other processes might rename themselves at runtime so that we don't find them anymore. The process ID is obtained by outputting it as very first thing on stdout and then starting the process with "exec", so that it isn't forked. Change-Id: Icc51bd1968afc47f4dc42f9e90e5dcbd0b1e40a7 Reviewed-by: Tobias Hunger Reviewed-by: Christian Kandeler --- .../devicesupport/sshdeviceprocess.cpp | 16 +++++++-- .../devicesupport/sshdeviceprocess.h | 1 + .../remotelinux/linuxdeviceprocess.cpp | 33 ++++++++++++++++--- src/plugins/remotelinux/linuxdeviceprocess.h | 5 +++ 4 files changed, 49 insertions(+), 6 deletions(-) diff --git a/src/plugins/projectexplorer/devicesupport/sshdeviceprocess.cpp b/src/plugins/projectexplorer/devicesupport/sshdeviceprocess.cpp index 686d4ce7126..e784536d3a6 100644 --- a/src/plugins/projectexplorer/devicesupport/sshdeviceprocess.cpp +++ b/src/plugins/projectexplorer/devicesupport/sshdeviceprocess.cpp @@ -172,6 +172,11 @@ void SshDeviceProcess::setSshServerSupportsSignals(bool signalsSupported) d->serverSupportsSignals = signalsSupported; } +qint64 SshDeviceProcess::processId() const +{ + return 0; +} + void SshDeviceProcess::handleConnected() { QTC_ASSERT(d->state == SshDeviceProcessPrivate::Connecting, return); @@ -303,8 +308,12 @@ void SshDeviceProcess::SshDeviceProcessPrivate::doSignal(QSsh::SshRemoteProcess: process->sendSignal(signal); } else { DeviceProcessSignalOperation::Ptr signalOperation = q->device()->signalOperation(); + quint64 processId = q->processId(); if (signal == QSsh::SshRemoteProcess::IntSignal) { - signalOperation->interruptProcess(runnable.executable); + if (processId != 0) + signalOperation->interruptProcess(processId); + else + signalOperation->interruptProcess(runnable.executable); } else { if (killOperation) // We are already in the process of killing the app. return; @@ -312,7 +321,10 @@ void SshDeviceProcess::SshDeviceProcessPrivate::doSignal(QSsh::SshRemoteProcess: connect(signalOperation.data(), &DeviceProcessSignalOperation::finished, q, &SshDeviceProcess::handleKillOperationFinished); killTimer.start(5000); - signalOperation->killProcess(runnable.executable); + if (processId != 0) + signalOperation->killProcess(processId); + else + signalOperation->killProcess(runnable.executable); } } break; diff --git a/src/plugins/projectexplorer/devicesupport/sshdeviceprocess.h b/src/plugins/projectexplorer/devicesupport/sshdeviceprocess.h index 34cd908f2c4..e21b9e629cf 100644 --- a/src/plugins/projectexplorer/devicesupport/sshdeviceprocess.h +++ b/src/plugins/projectexplorer/devicesupport/sshdeviceprocess.h @@ -68,6 +68,7 @@ private: void handleKillOperationTimeout(); virtual QString fullCommandLine(const StandardRunnable &runnable) const; + virtual qint64 processId() const; class SshDeviceProcessPrivate; friend class SshDeviceProcessPrivate; diff --git a/src/plugins/remotelinux/linuxdeviceprocess.cpp b/src/plugins/remotelinux/linuxdeviceprocess.cpp index 4cd28c975ce..64ae87ebfda 100644 --- a/src/plugins/remotelinux/linuxdeviceprocess.cpp +++ b/src/plugins/remotelinux/linuxdeviceprocess.cpp @@ -39,8 +39,11 @@ static QString quote(const QString &s) { return Utils::QtcProcess::quoteArgUnix( LinuxDeviceProcess::LinuxDeviceProcess(const QSharedPointer &device, QObject *parent) - : ProjectExplorer::SshDeviceProcess(device, parent) + : ProjectExplorer::SshDeviceProcess(device, parent), m_processId(0) { + connect(this, &DeviceProcess::finished, this, [this]() { + m_processId = 0; + }); } void LinuxDeviceProcess::setRcFilesToSource(const QStringList &filePaths) @@ -48,6 +51,28 @@ void LinuxDeviceProcess::setRcFilesToSource(const QStringList &filePaths) m_rcFilesToSource = filePaths; } +QByteArray LinuxDeviceProcess::readAllStandardOutput() +{ + QByteArray output = SshDeviceProcess::readAllStandardOutput(); + if (m_processId != 0) + return output; + + m_processIdString.append(output); + int cut = m_processIdString.indexOf('\n'); + if (cut != -1) { + m_processId = m_processIdString.left(cut).toLongLong(); + output = m_processIdString.mid(cut + 1); + m_processIdString.clear(); + return output; + } + return QByteArray(); +} + +qint64 LinuxDeviceProcess::processId() const +{ + return m_processId; +} + QString LinuxDeviceProcess::fullCommandLine(const StandardRunnable &runnable) const { const Environment env = runnable.environment; @@ -66,10 +91,10 @@ QString LinuxDeviceProcess::fullCommandLine(const StandardRunnable &runnable) co envString.append(it.key()).append(QLatin1String("='")).append(it.value()) .append(QLatin1Char('\'')); } + fullCommandLine.append("echo $$ && "); if (!envString.isEmpty()) - fullCommandLine.append(QLatin1Char(' ')).append(envString); - if (!fullCommandLine.isEmpty()) - fullCommandLine += QLatin1Char(' '); + fullCommandLine.append(envString); + fullCommandLine.append(" exec "); fullCommandLine.append(quote(runnable.executable)); if (!runnable.commandLineArguments.isEmpty()) { fullCommandLine.append(QLatin1Char(' ')); diff --git a/src/plugins/remotelinux/linuxdeviceprocess.h b/src/plugins/remotelinux/linuxdeviceprocess.h index 9948d6ad07f..b4610246027 100644 --- a/src/plugins/remotelinux/linuxdeviceprocess.h +++ b/src/plugins/remotelinux/linuxdeviceprocess.h @@ -43,12 +43,17 @@ public: // Files to source before executing the command (if they exist). Overrides the default. void setRcFilesToSource(const QStringList &filePaths); + QByteArray readAllStandardOutput() override; + private: QString fullCommandLine(const ProjectExplorer::StandardRunnable &) const override; + qint64 processId() const override; QStringList rcFilesToSource() const; QStringList m_rcFilesToSource; + QByteArray m_processIdString; + qint64 m_processId; }; } // namespace RemoteLinux