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 <tobias.hunger@qt.io>
Reviewed-by: Christian Kandeler <christian.kandeler@theqtcompany.com>
This commit is contained in:
Ulf Hermann
2016-04-21 11:49:10 +02:00
parent 8372d2199f
commit 0bef62481b
4 changed files with 49 additions and 6 deletions

View File

@@ -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,7 +308,11 @@ 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) {
if (processId != 0)
signalOperation->interruptProcess(processId);
else
signalOperation->interruptProcess(runnable.executable);
} else {
if (killOperation) // We are already in the process of killing the app.
@@ -312,6 +321,9 @@ void SshDeviceProcess::SshDeviceProcessPrivate::doSignal(QSsh::SshRemoteProcess:
connect(signalOperation.data(), &DeviceProcessSignalOperation::finished, q,
&SshDeviceProcess::handleKillOperationFinished);
killTimer.start(5000);
if (processId != 0)
signalOperation->killProcess(processId);
else
signalOperation->killProcess(runnable.executable);
}
}

View File

@@ -68,6 +68,7 @@ private:
void handleKillOperationTimeout();
virtual QString fullCommandLine(const StandardRunnable &runnable) const;
virtual qint64 processId() const;
class SshDeviceProcessPrivate;
friend class SshDeviceProcessPrivate;

View File

@@ -39,8 +39,11 @@ static QString quote(const QString &s) { return Utils::QtcProcess::quoteArgUnix(
LinuxDeviceProcess::LinuxDeviceProcess(const QSharedPointer<const ProjectExplorer::IDevice> &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(' '));

View File

@@ -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