1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 BlackBerry Limited. All rights reserved.
4 ** Contact: KDAB (info@kdab.com)
5 **
6 ** This file is part of Qt Creator.
7 **
8 ** Commercial License Usage
9 ** Licensees holding valid commercial Qt licenses may use this file in
10 ** accordance with the commercial license agreement provided with the
11 ** Software or, alternatively, in accordance with the terms contained in
12 ** a written agreement between you and The Qt Company. For licensing terms
13 ** and conditions see https://www.qt.io/terms-conditions. For further
14 ** information use the contact form at https://www.qt.io/contact-us.
15 **
16 ** GNU General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU
18 ** General Public License version 3 as published by the Free Software
19 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 ** included in the packaging of this file. Please review the following
21 ** information to ensure the GNU General Public License requirements will
22 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 **
24 ****************************************************************************/
25 
26 #include "qnxdevice.h"
27 
28 #include "qnxconstants.h"
29 #include "qnxdevicetester.h"
30 #include "qnxdeviceprocesslist.h"
31 #include "qnxdeviceprocesssignaloperation.h"
32 #include "qnxdeployqtlibrariesdialog.h"
33 #include "qnxdeviceprocess.h"
34 #include "qnxdevicewizard.h"
35 
36 #include <projectexplorer/devicesupport/sshdeviceprocess.h>
37 #include <projectexplorer/runcontrol.h>
38 
39 #include <ssh/sshconnection.h>
40 #include <utils/port.h>
41 #include <utils/qtcassert.h>
42 #include <utils/stringutils.h>
43 
44 #include <QApplication>
45 #include <QRegularExpression>
46 #include <QStringList>
47 #include <QThread>
48 
49 using namespace ProjectExplorer;
50 using namespace Utils;
51 
52 namespace Qnx {
53 namespace Internal {
54 
55 const char QnxVersionKey[] = "QnxVersion";
56 
57 class QnxPortsGatheringMethod : public PortsGatheringMethod
58 {
59     // TODO: The command is probably needlessly complicated because the parsing method
60     // used to be fixed. These two can now be matched to each other.
runnable(QAbstractSocket::NetworkLayerProtocol protocol) const61     Runnable runnable(QAbstractSocket::NetworkLayerProtocol protocol) const override
62     {
63         Q_UNUSED(protocol)
64         Runnable runnable;
65         runnable.executable = FilePath::fromString("netstat");
66         runnable.commandLineArguments = "-na";
67         return runnable;
68     }
69 
usedPorts(const QByteArray & output) const70     QList<Port> usedPorts(const QByteArray &output) const override
71     {
72         QList<Utils::Port> ports;
73         const QList<QByteArray> lines = output.split('\n');
74         for (const QByteArray &line : lines) {
75             const Port port(Utils::parseUsedPortFromNetstatOutput(line));
76             if (port.isValid() && !ports.contains(port))
77                 ports.append(port);
78         }
79         return ports;
80     }
81 };
82 
QnxDevice()83 QnxDevice::QnxDevice()
84 {
85     setDisplayType(tr("QNX"));
86     setDefaultDisplayName(tr("QNX Device"));
87     setOsType(OsTypeOtherUnix);
88 
89     addDeviceAction({tr("Deploy Qt libraries..."), [](const IDevice::Ptr &device, QWidget *parent) {
90         QnxDeployQtLibrariesDialog dialog(device, parent);
91         dialog.exec();
92     }});
93 }
94 
qnxVersion() const95 int QnxDevice::qnxVersion() const
96 {
97     if (m_versionNumber == 0)
98         updateVersionNumber();
99 
100     return m_versionNumber;
101 }
102 
updateVersionNumber() const103 void QnxDevice::updateVersionNumber() const
104 {
105     QEventLoop eventLoop;
106     SshDeviceProcess versionNumberProcess(sharedFromThis());
107     QObject::connect(&versionNumberProcess, &SshDeviceProcess::finished, &eventLoop, &QEventLoop::quit);
108     QObject::connect(&versionNumberProcess, &DeviceProcess::error, &eventLoop, &QEventLoop::quit);
109 
110     Runnable r;
111     r.executable = FilePath::fromString("uname");
112     r.commandLineArguments = QLatin1String("-r");
113     versionNumberProcess.start(r);
114 
115     bool isGuiThread = QThread::currentThread() == QCoreApplication::instance()->thread();
116     if (isGuiThread)
117         QApplication::setOverrideCursor(Qt::WaitCursor);
118 
119     eventLoop.exec(QEventLoop::ExcludeUserInputEvents);
120 
121     QByteArray output = versionNumberProcess.readAllStandardOutput();
122     QString versionMessage = QString::fromLatin1(output);
123     const QRegularExpression versionNumberRegExp("(\\d+)\\.(\\d+)\\.(\\d+)");
124     const QRegularExpressionMatch match = versionNumberRegExp.match(versionMessage);
125     if (match.hasMatch()) {
126         int major = match.captured(1).toInt();
127         int minor = match.captured(2).toInt();
128         int patch = match.captured(3).toInt();
129         m_versionNumber = (major << 16)|(minor<<8)|(patch);
130     }
131 
132     if (isGuiThread)
133         QApplication::restoreOverrideCursor();
134 }
135 
fromMap(const QVariantMap & map)136 void QnxDevice::fromMap(const QVariantMap &map)
137 {
138     m_versionNumber = map.value(QLatin1String(QnxVersionKey), 0).toInt();
139     RemoteLinux::LinuxDevice::fromMap(map);
140 }
141 
toMap() const142 QVariantMap QnxDevice::toMap() const
143 {
144     QVariantMap map(RemoteLinux::LinuxDevice::toMap());
145     map.insert(QLatin1String(QnxVersionKey), m_versionNumber);
146     return map;
147 }
148 
portsGatheringMethod() const149 PortsGatheringMethod::Ptr QnxDevice::portsGatheringMethod() const
150 {
151     return PortsGatheringMethod::Ptr(new QnxPortsGatheringMethod);
152 }
153 
createProcessListModel(QObject * parent) const154 DeviceProcessList *QnxDevice::createProcessListModel(QObject *parent) const
155 {
156     return new QnxDeviceProcessList(sharedFromThis(), parent);
157 }
158 
createDeviceTester() const159 DeviceTester *QnxDevice::createDeviceTester() const
160 {
161     return new QnxDeviceTester;
162 }
163 
createProcess(QObject * parent) const164 DeviceProcess *QnxDevice::createProcess(QObject *parent) const
165 {
166     return new QnxDeviceProcess(sharedFromThis(), parent);
167 }
168 
signalOperation() const169 DeviceProcessSignalOperation::Ptr QnxDevice::signalOperation() const
170 {
171     return DeviceProcessSignalOperation::Ptr(
172                 new QnxDeviceProcessSignalOperation(sshParameters()));
173 }
174 
175 // Factory
176 
QnxDeviceFactory()177 QnxDeviceFactory::QnxDeviceFactory()
178     : ProjectExplorer::IDeviceFactory(Constants::QNX_QNX_OS_TYPE)
179 {
180     setDisplayName(QnxDevice::tr("QNX Device"));
181     setCombinedIcon(":/qnx/images/qnxdevicesmall.png",
182                     ":/qnx/images/qnxdevice.png");
183     setCanCreate(true);
184     setConstructionFunction(&QnxDevice::create);
185 }
186 
create() const187 ProjectExplorer::IDevice::Ptr QnxDeviceFactory::create() const
188 {
189     QnxDeviceWizard wizard;
190     if (wizard.exec() != QDialog::Accepted)
191         return ProjectExplorer::IDevice::Ptr();
192     return wizard.device();
193 }
194 
195 } // namespace Internal
196 } // namespace Qnx
197