2012-10-02 09:12:39 +02:00
|
|
|
/****************************************************************************
|
2011-05-31 12:47:53 +02:00
|
|
|
**
|
2016-01-15 14:57:40 +01:00
|
|
|
** Copyright (C) 2016 The Qt Company Ltd.
|
|
|
|
** Contact: https://www.qt.io/licensing/
|
2011-05-31 12:47:53 +02:00
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
** This file is part of Qt Creator.
|
2011-05-31 12:47:53 +02:00
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
** Commercial License Usage
|
|
|
|
** Licensees holding valid commercial Qt licenses may use this file in
|
|
|
|
** accordance with the commercial license agreement provided with the
|
|
|
|
** Software or, alternatively, in accordance with the terms contained in
|
2016-01-15 14:57:40 +01:00
|
|
|
** a written agreement between you and The Qt Company. For licensing terms
|
|
|
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
|
|
|
** information use the contact form at https://www.qt.io/contact-us.
|
2011-05-31 12:47:53 +02:00
|
|
|
**
|
2016-01-15 14:57:40 +01:00
|
|
|
** GNU General Public License Usage
|
|
|
|
** Alternatively, this file may be used under the terms of the GNU
|
|
|
|
** General Public License version 3 as published by the Free Software
|
|
|
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
|
|
|
** included in the packaging of this file. Please review the following
|
|
|
|
** information to ensure the GNU General Public License requirements will
|
|
|
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
2011-05-31 12:47:53 +02:00
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
****************************************************************************/
|
2012-04-24 15:49:09 +02:00
|
|
|
|
2012-07-27 13:31:13 +02:00
|
|
|
#include "linuxdevice.h"
|
2011-05-31 12:47:53 +02:00
|
|
|
|
2012-04-06 18:28:16 +02:00
|
|
|
#include "genericlinuxdeviceconfigurationwidget.h"
|
2013-08-08 14:05:11 +02:00
|
|
|
#include "linuxdeviceprocess.h"
|
2013-06-27 17:12:08 +02:00
|
|
|
#include "linuxdevicetester.h"
|
2012-04-06 18:28:16 +02:00
|
|
|
#include "publickeydeploymentdialog.h"
|
2011-07-25 11:55:00 +02:00
|
|
|
#include "remotelinux_constants.h"
|
2013-09-16 15:30:30 +02:00
|
|
|
#include "remotelinuxsignaloperation.h"
|
2016-04-06 13:56:32 +02:00
|
|
|
#include "remotelinuxenvironmentreader.h"
|
2011-07-25 11:55:00 +02:00
|
|
|
|
2012-06-05 14:30:31 +02:00
|
|
|
#include <coreplugin/id.h>
|
2012-08-02 14:45:27 +02:00
|
|
|
#include <projectexplorer/devicesupport/sshdeviceprocesslist.h>
|
2018-05-16 15:42:03 +02:00
|
|
|
#include <projectexplorer/runconfiguration.h>
|
2013-09-16 15:30:30 +02:00
|
|
|
#include <ssh/sshremoteprocessrunner.h>
|
2014-06-16 18:25:52 +04:00
|
|
|
#include <utils/algorithm.h>
|
2016-04-19 16:43:30 +02:00
|
|
|
#include <utils/port.h>
|
2012-02-15 14:47:45 -08:00
|
|
|
#include <utils/qtcassert.h>
|
2011-08-02 12:20:16 +02:00
|
|
|
|
2013-09-16 15:30:30 +02:00
|
|
|
#include <QTimer>
|
|
|
|
|
2012-07-26 16:23:20 +02:00
|
|
|
using namespace ProjectExplorer;
|
|
|
|
|
2011-05-31 12:47:53 +02:00
|
|
|
namespace RemoteLinux {
|
2011-08-02 12:20:16 +02:00
|
|
|
|
2012-07-26 17:41:52 +02:00
|
|
|
const char Delimiter0[] = "x--";
|
|
|
|
const char Delimiter1[] = "---";
|
|
|
|
|
|
|
|
static QString visualizeNull(QString s)
|
|
|
|
{
|
|
|
|
return s.replace(QLatin1Char('\0'), QLatin1String("<null>"));
|
|
|
|
}
|
|
|
|
|
2012-08-02 14:45:27 +02:00
|
|
|
class LinuxDeviceProcessList : public SshDeviceProcessList
|
2012-08-01 16:26:27 +02:00
|
|
|
{
|
2012-08-02 14:45:27 +02:00
|
|
|
public:
|
|
|
|
LinuxDeviceProcessList(const IDevice::ConstPtr &device, QObject *parent)
|
|
|
|
: SshDeviceProcessList(device, parent)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2018-11-24 17:06:01 +01:00
|
|
|
QString listProcessesCommandLine() const override
|
2012-08-02 14:45:27 +02:00
|
|
|
{
|
|
|
|
return QString::fromLatin1(
|
2012-08-01 16:26:27 +02:00
|
|
|
"for dir in `ls -d /proc/[0123456789]*`; do "
|
|
|
|
"test -d $dir || continue;" // Decrease the likelihood of a race condition.
|
|
|
|
"echo $dir;"
|
|
|
|
"cat $dir/cmdline;echo;" // cmdline does not end in newline
|
|
|
|
"cat $dir/stat;"
|
|
|
|
"readlink $dir/exe;"
|
2014-05-02 14:32:00 +02:00
|
|
|
"printf '%1''%2';"
|
2012-11-26 14:41:39 +02:00
|
|
|
"done").arg(QLatin1String(Delimiter0)).arg(QLatin1String(Delimiter1));
|
2012-08-02 14:45:27 +02:00
|
|
|
}
|
2012-08-01 16:26:27 +02:00
|
|
|
|
2018-11-24 17:06:01 +01:00
|
|
|
QList<DeviceProcessItem> buildProcessList(const QString &listProcessesReply) const override
|
2012-08-02 14:45:27 +02:00
|
|
|
{
|
2013-08-08 11:13:20 +02:00
|
|
|
QList<DeviceProcessItem> processes;
|
2012-08-02 14:45:27 +02:00
|
|
|
const QStringList lines = listProcessesReply.split(QString::fromLatin1(Delimiter0)
|
|
|
|
+ QString::fromLatin1(Delimiter1), QString::SkipEmptyParts);
|
|
|
|
foreach (const QString &line, lines) {
|
|
|
|
const QStringList elements = line.split(QLatin1Char('\n'));
|
|
|
|
if (elements.count() < 4) {
|
|
|
|
qDebug("%s: Expected four list elements, got %d. Line was '%s'.", Q_FUNC_INFO,
|
|
|
|
elements.count(), qPrintable(visualizeNull(line)));
|
2012-08-01 16:26:27 +02:00
|
|
|
continue;
|
2012-08-02 14:45:27 +02:00
|
|
|
}
|
|
|
|
bool ok;
|
2016-02-03 13:49:53 +01:00
|
|
|
const int pid = elements.first().midRef(6).toInt(&ok);
|
2012-08-02 14:45:27 +02:00
|
|
|
if (!ok) {
|
|
|
|
qDebug("%s: Expected number in %s. Line was '%s'.", Q_FUNC_INFO,
|
|
|
|
qPrintable(elements.first()), qPrintable(visualizeNull(line)));
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
QString command = elements.at(1);
|
|
|
|
command.replace(QLatin1Char('\0'), QLatin1Char(' '));
|
|
|
|
if (command.isEmpty()) {
|
|
|
|
const QString &statString = elements.at(2);
|
|
|
|
const int openParenPos = statString.indexOf(QLatin1Char('('));
|
|
|
|
const int closedParenPos = statString.indexOf(QLatin1Char(')'), openParenPos);
|
|
|
|
if (openParenPos == -1 || closedParenPos == -1)
|
|
|
|
continue;
|
|
|
|
command = QLatin1Char('[')
|
|
|
|
+ statString.mid(openParenPos + 1, closedParenPos - openParenPos - 1)
|
|
|
|
+ QLatin1Char(']');
|
|
|
|
}
|
|
|
|
|
2013-08-08 11:13:20 +02:00
|
|
|
DeviceProcessItem process;
|
2012-08-02 14:45:27 +02:00
|
|
|
process.pid = pid;
|
|
|
|
process.cmdLine = command;
|
|
|
|
process.exe = elements.at(3);
|
|
|
|
processes.append(process);
|
2012-08-01 16:26:27 +02:00
|
|
|
}
|
|
|
|
|
2014-06-16 18:25:52 +04:00
|
|
|
Utils::sort(processes);
|
2012-08-02 14:45:27 +02:00
|
|
|
return processes;
|
2012-08-01 16:26:27 +02:00
|
|
|
}
|
2012-08-02 14:45:27 +02:00
|
|
|
};
|
2012-08-01 16:26:27 +02:00
|
|
|
|
2015-02-03 23:51:02 +02:00
|
|
|
class LinuxPortsGatheringMethod : public PortsGatheringMethod
|
2012-08-01 16:26:27 +02:00
|
|
|
{
|
2018-11-24 17:06:01 +01:00
|
|
|
Runnable runnable(QAbstractSocket::NetworkLayerProtocol protocol) const override
|
2012-08-01 16:26:27 +02:00
|
|
|
{
|
2016-04-15 12:23:23 +02:00
|
|
|
// We might encounter the situation that protocol is given IPv6
|
|
|
|
// but the consumer of the free port information decides to open
|
|
|
|
// an IPv4(only) port. As a result the next IPv6 scan will
|
|
|
|
// report the port again as open (in IPv6 namespace), while the
|
|
|
|
// same port in IPv4 namespace might still be blocked, and
|
|
|
|
// re-use of this port fails.
|
|
|
|
// GDBserver behaves exactly like this.
|
|
|
|
|
|
|
|
Q_UNUSED(protocol)
|
|
|
|
|
|
|
|
// /proc/net/tcp* covers /proc/net/tcp and /proc/net/tcp6
|
2018-05-16 15:42:03 +02:00
|
|
|
Runnable runnable;
|
2017-08-07 18:54:01 +02:00
|
|
|
runnable.executable = "sed";
|
|
|
|
runnable.commandLineArguments = "-e 's/.*: [[:xdigit:]]*:\\([[:xdigit:]]\\{4\\}\\).*/\\1/g' /proc/net/tcp*";
|
|
|
|
return runnable;
|
2012-08-01 16:26:27 +02:00
|
|
|
}
|
|
|
|
|
2018-11-24 17:06:01 +01:00
|
|
|
QList<Utils::Port> usedPorts(const QByteArray &output) const override
|
2012-08-01 16:26:27 +02:00
|
|
|
{
|
2016-04-19 16:43:30 +02:00
|
|
|
QList<Utils::Port> ports;
|
2012-08-01 16:26:27 +02:00
|
|
|
QList<QByteArray> portStrings = output.split('\n');
|
|
|
|
foreach (const QByteArray &portString, portStrings) {
|
2016-04-15 12:23:23 +02:00
|
|
|
if (portString.size() != 4)
|
2012-08-01 16:26:27 +02:00
|
|
|
continue;
|
|
|
|
bool ok;
|
2016-04-19 16:43:30 +02:00
|
|
|
const Utils::Port port(portString.toInt(&ok, 16));
|
2012-08-01 16:26:27 +02:00
|
|
|
if (ok) {
|
|
|
|
if (!ports.contains(port))
|
|
|
|
ports << port;
|
|
|
|
} else {
|
|
|
|
qWarning("%s: Unexpected string '%s' is not a port.",
|
|
|
|
Q_FUNC_INFO, portString.data());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ports;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2012-07-27 13:31:13 +02:00
|
|
|
LinuxDevice::Ptr LinuxDevice::create(const QString &name,
|
2012-05-16 10:46:21 +02:00
|
|
|
Core::Id type, MachineType machineType, Origin origin, Core::Id id)
|
2011-05-31 12:47:53 +02:00
|
|
|
{
|
2012-07-27 13:31:13 +02:00
|
|
|
return Ptr(new LinuxDevice(name, type, machineType, origin, id));
|
2012-03-02 18:09:59 +01:00
|
|
|
}
|
|
|
|
|
2012-07-27 13:31:13 +02:00
|
|
|
QString LinuxDevice::displayType() const
|
2012-04-06 18:28:16 +02:00
|
|
|
{
|
|
|
|
return tr("Generic Linux");
|
|
|
|
}
|
|
|
|
|
2015-02-03 23:51:02 +02:00
|
|
|
IDeviceWidget *LinuxDevice::createWidget()
|
2012-04-06 18:28:16 +02:00
|
|
|
{
|
2012-07-26 17:41:52 +02:00
|
|
|
return new GenericLinuxDeviceConfigurationWidget(sharedFromThis());
|
2012-04-06 18:28:16 +02:00
|
|
|
}
|
|
|
|
|
2012-07-27 13:31:13 +02:00
|
|
|
QList<Core::Id> LinuxDevice::actionIds() const
|
2012-04-06 18:28:16 +02:00
|
|
|
{
|
2013-06-27 17:12:08 +02:00
|
|
|
return QList<Core::Id>() << Core::Id(Constants::GenericDeployKeyToDeviceActionId);
|
2012-04-06 18:28:16 +02:00
|
|
|
}
|
|
|
|
|
2012-07-27 13:31:13 +02:00
|
|
|
QString LinuxDevice::displayNameForActionId(Core::Id actionId) const
|
2012-04-06 18:28:16 +02:00
|
|
|
{
|
|
|
|
QTC_ASSERT(actionIds().contains(actionId), return QString());
|
|
|
|
|
2012-08-03 15:24:33 +02:00
|
|
|
if (actionId == Constants::GenericDeployKeyToDeviceActionId)
|
2012-04-06 18:28:16 +02:00
|
|
|
return tr("Deploy Public Key...");
|
|
|
|
return QString(); // Can't happen.
|
|
|
|
}
|
|
|
|
|
2013-09-16 11:12:31 +02:00
|
|
|
void LinuxDevice::executeAction(Core::Id actionId, QWidget *parent)
|
2012-04-06 18:28:16 +02:00
|
|
|
{
|
2012-05-02 16:03:26 +02:00
|
|
|
QTC_ASSERT(actionIds().contains(actionId), return);
|
2012-04-06 18:28:16 +02:00
|
|
|
|
2018-11-24 17:06:01 +01:00
|
|
|
QDialog *d = nullptr;
|
2012-07-27 13:31:13 +02:00
|
|
|
const LinuxDevice::ConstPtr device = sharedFromThis().staticCast<const LinuxDevice>();
|
2013-06-27 17:12:08 +02:00
|
|
|
if (actionId == Constants::GenericDeployKeyToDeviceActionId)
|
2012-05-02 16:03:26 +02:00
|
|
|
d = PublicKeyDeploymentDialog::createDialog(device, parent);
|
|
|
|
if (d)
|
|
|
|
d->exec();
|
2012-08-02 14:45:27 +02:00
|
|
|
delete d;
|
2012-04-06 18:28:16 +02:00
|
|
|
}
|
|
|
|
|
2017-06-28 17:16:07 +02:00
|
|
|
Utils::OsType LinuxDevice::osType() const
|
|
|
|
{
|
|
|
|
return Utils::OsTypeLinux;
|
|
|
|
}
|
|
|
|
|
2012-07-27 13:31:13 +02:00
|
|
|
LinuxDevice::LinuxDevice(const QString &name, Core::Id type, MachineType machineType,
|
2012-07-25 17:10:20 +02:00
|
|
|
Origin origin, Core::Id id)
|
|
|
|
: IDevice(type, origin, machineType, id)
|
2011-05-31 12:47:53 +02:00
|
|
|
{
|
2012-03-06 12:31:42 +01:00
|
|
|
setDisplayName(name);
|
2011-05-31 12:47:53 +02:00
|
|
|
}
|
|
|
|
|
2018-11-24 17:06:01 +01:00
|
|
|
LinuxDevice::LinuxDevice(const LinuxDevice &other) = default;
|
2011-05-31 12:47:53 +02:00
|
|
|
|
2012-07-27 13:31:13 +02:00
|
|
|
LinuxDevice::Ptr LinuxDevice::create()
|
2012-03-02 18:09:59 +01:00
|
|
|
{
|
2012-07-27 13:31:13 +02:00
|
|
|
return Ptr(new LinuxDevice);
|
2012-03-02 18:09:59 +01:00
|
|
|
}
|
|
|
|
|
2015-02-03 23:51:02 +02:00
|
|
|
IDevice::Ptr LinuxDevice::clone() const
|
2012-03-05 12:37:32 +01:00
|
|
|
{
|
2012-07-27 13:31:13 +02:00
|
|
|
return Ptr(new LinuxDevice(*this));
|
2012-03-05 12:37:32 +01:00
|
|
|
}
|
|
|
|
|
2013-08-08 14:05:11 +02:00
|
|
|
DeviceProcess *LinuxDevice::createProcess(QObject *parent) const
|
|
|
|
{
|
|
|
|
return new LinuxDeviceProcess(sharedFromThis(), parent);
|
|
|
|
}
|
|
|
|
|
2013-04-18 09:31:22 +02:00
|
|
|
bool LinuxDevice::canAutoDetectPorts() const
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2012-08-01 16:26:27 +02:00
|
|
|
PortsGatheringMethod::Ptr LinuxDevice::portsGatheringMethod() const
|
2012-07-26 17:41:52 +02:00
|
|
|
{
|
2012-08-01 16:26:27 +02:00
|
|
|
return LinuxPortsGatheringMethod::Ptr(new LinuxPortsGatheringMethod);
|
2012-07-26 17:41:52 +02:00
|
|
|
}
|
|
|
|
|
2012-08-02 14:45:27 +02:00
|
|
|
DeviceProcessList *LinuxDevice::createProcessListModel(QObject *parent) const
|
|
|
|
{
|
|
|
|
return new LinuxDeviceProcessList(sharedFromThis(), parent);
|
|
|
|
}
|
|
|
|
|
2013-06-27 17:12:08 +02:00
|
|
|
DeviceTester *LinuxDevice::createDeviceTester() const
|
2013-05-30 13:53:28 +02:00
|
|
|
{
|
|
|
|
return new GenericLinuxDeviceTester;
|
|
|
|
}
|
|
|
|
|
2013-09-16 15:30:30 +02:00
|
|
|
DeviceProcessSignalOperation::Ptr LinuxDevice::signalOperation() const
|
|
|
|
{
|
|
|
|
return DeviceProcessSignalOperation::Ptr(new RemoteLinuxSignalOperation(sshParameters()));
|
|
|
|
}
|
|
|
|
|
2016-04-06 13:56:32 +02:00
|
|
|
class LinuxDeviceEnvironmentFetcher : public DeviceEnvironmentFetcher
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
LinuxDeviceEnvironmentFetcher(const IDevice::ConstPtr &device)
|
|
|
|
: m_reader(device)
|
|
|
|
{
|
|
|
|
connect(&m_reader, &Internal::RemoteLinuxEnvironmentReader::finished,
|
|
|
|
this, &LinuxDeviceEnvironmentFetcher::readerFinished);
|
|
|
|
connect(&m_reader, &Internal::RemoteLinuxEnvironmentReader::error,
|
|
|
|
this, &LinuxDeviceEnvironmentFetcher::readerError);
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
void start() override { m_reader.start(); }
|
|
|
|
void readerFinished() { emit finished(m_reader.remoteEnvironment(), true); }
|
|
|
|
void readerError() { emit finished(Utils::Environment(), false); }
|
|
|
|
|
|
|
|
Internal::RemoteLinuxEnvironmentReader m_reader;
|
|
|
|
};
|
|
|
|
|
|
|
|
DeviceEnvironmentFetcher::Ptr LinuxDevice::environmentFetcher() const
|
|
|
|
{
|
|
|
|
return DeviceEnvironmentFetcher::Ptr(new LinuxDeviceEnvironmentFetcher(sharedFromThis()));
|
|
|
|
}
|
|
|
|
|
2011-05-31 12:47:53 +02:00
|
|
|
} // namespace RemoteLinux
|