forked from qt-creator/qt-creator
Utils: Improve DeviceShell error handling
In case mktemp or mkfifo fails, the device shell script would incorrectly print both success and failure messages. Also cleaning State enum, removing unnecessary values. Fixes possible crash if creation of master process fails. Fixes: QTCREATORBUG-28928 Change-Id: I75fef54dc791b2b0a403bab19dab6813b62643ac Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
@@ -62,7 +62,6 @@ DeviceShell::~DeviceShell()
|
|||||||
*/
|
*/
|
||||||
RunResult DeviceShell::runInShell(const CommandLine &cmd, const QByteArray &stdInData)
|
RunResult DeviceShell::runInShell(const CommandLine &cmd, const QByteArray &stdInData)
|
||||||
{
|
{
|
||||||
QTC_ASSERT(m_shellProcess, return {});
|
|
||||||
Q_ASSERT(QThread::currentThread() != &m_thread);
|
Q_ASSERT(QThread::currentThread() != &m_thread);
|
||||||
|
|
||||||
return run(cmd, stdInData);
|
return run(cmd, stdInData);
|
||||||
@@ -75,7 +74,7 @@ QStringList DeviceShell::missingFeatures() const { return m_missingFeatures; }
|
|||||||
RunResult DeviceShell::run(const CommandLine &cmd, const QByteArray &stdInData)
|
RunResult DeviceShell::run(const CommandLine &cmd, const QByteArray &stdInData)
|
||||||
{
|
{
|
||||||
// If the script failed to install, use QtcProcess directly instead.
|
// If the script failed to install, use QtcProcess directly instead.
|
||||||
bool useProcess = m_shellScriptState == State::NoScript;
|
bool useProcess = m_shellScriptState == State::Failed;
|
||||||
|
|
||||||
// Transferring large amounts of stdInData is slow via the shell script.
|
// Transferring large amounts of stdInData is slow via the shell script.
|
||||||
// Use QtcProcess directly if the size exceeds 100kb.
|
// Use QtcProcess directly if the size exceeds 100kb.
|
||||||
@@ -197,10 +196,7 @@ bool DeviceShell::start()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!installShellScript()) {
|
if (installShellScript()) {
|
||||||
if (m_shellScriptState == State::FailedToStart)
|
|
||||||
closeShellProcess();
|
|
||||||
} else {
|
|
||||||
connect(m_shellProcess.get(),
|
connect(m_shellProcess.get(),
|
||||||
&QtcProcess::readyReadStandardOutput,
|
&QtcProcess::readyReadStandardOutput,
|
||||||
m_shellProcess.get(),
|
m_shellProcess.get(),
|
||||||
@@ -213,6 +209,10 @@ bool DeviceShell::start()
|
|||||||
qCWarning(deviceShellLog)
|
qCWarning(deviceShellLog)
|
||||||
<< "Received unexpected output on stderr:" << stdErr;
|
<< "Received unexpected output on stderr:" << stdErr;
|
||||||
});
|
});
|
||||||
|
} else if (m_shellProcess->isRunning()) {
|
||||||
|
m_shellProcess->kill();
|
||||||
|
m_shellProcess.reset();
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
connect(m_shellProcess.get(), &QtcProcess::done, m_shellProcess.get(), [this] {
|
connect(m_shellProcess.get(), &QtcProcess::done, m_shellProcess.get(), [this] {
|
||||||
@@ -247,7 +247,7 @@ bool DeviceShell::checkCommand(const QByteArray &command)
|
|||||||
}
|
}
|
||||||
QByteArray out = m_shellProcess->readAllRawStandardOutput();
|
QByteArray out = m_shellProcess->readAllRawStandardOutput();
|
||||||
if (out.contains("<missing>")) {
|
if (out.contains("<missing>")) {
|
||||||
m_shellScriptState = State::NoScript;
|
m_shellScriptState = State::Failed;
|
||||||
qCWarning(deviceShellLog) << "Command" << command << "was not found";
|
qCWarning(deviceShellLog) << "Command" << command << "was not found";
|
||||||
m_missingFeatures.append(QString::fromUtf8(command));
|
m_missingFeatures.append(QString::fromUtf8(command));
|
||||||
return false;
|
return false;
|
||||||
@@ -259,7 +259,7 @@ bool DeviceShell::checkCommand(const QByteArray &command)
|
|||||||
bool DeviceShell::installShellScript()
|
bool DeviceShell::installShellScript()
|
||||||
{
|
{
|
||||||
if (m_forceFailScriptInstallation) {
|
if (m_forceFailScriptInstallation) {
|
||||||
m_shellScriptState = State::NoScript;
|
m_shellScriptState = State::Failed;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -290,15 +290,19 @@ bool DeviceShell::installShellScript()
|
|||||||
}
|
}
|
||||||
|
|
||||||
QByteArray out = m_shellProcess->readAllRawStandardError();
|
QByteArray out = m_shellProcess->readAllRawStandardError();
|
||||||
if (out.contains("SCRIPT_INSTALLED")) {
|
if (out.contains("SCRIPT_INSTALLED") && !out.contains("ERROR_INSTALL_SCRIPT")) {
|
||||||
m_shellScriptState = State::Succeeded;
|
m_shellScriptState = State::Succeeded;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (out.contains("ERROR_INSTALL_SCRIPT")) {
|
if (out.contains("ERROR_INSTALL_SCRIPT")) {
|
||||||
m_shellScriptState = State::NoScript;
|
m_shellScriptState = State::Failed;
|
||||||
qCWarning(deviceShellLog) << "Failed installing device shell script";
|
qCWarning(deviceShellLog) << "Failed installing device shell script";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (!out.isEmpty()) {
|
||||||
|
qCWarning(deviceShellLog)
|
||||||
|
<< "Unexpected output while installing device shell script:" << out;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@@ -28,7 +28,7 @@ class QTCREATOR_UTILS_EXPORT DeviceShell : public QObject
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum class State { FailedToStart = -1, Unknown = 0, Succeeded = 1, NoScript = 2 };
|
enum class State { Failed = -1, Unknown = 0, Succeeded = 1 };
|
||||||
|
|
||||||
enum class ParseType {
|
enum class ParseType {
|
||||||
StdOut,
|
StdOut,
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
# Copyright (C) 2022 The Qt Company Ltd.
|
# Copyright (C) 2022 The Qt Company Ltd.
|
||||||
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||||
FINAL_OUT=$(mktemp -u)
|
FINAL_OUT=$(mktemp -u) || exit 2
|
||||||
mkfifo "$FINAL_OUT"
|
mkfifo "$FINAL_OUT" || exit 3
|
||||||
|
|
||||||
finalOutput() {
|
finalOutput() {
|
||||||
local fileInputBuffer
|
local fileInputBuffer
|
||||||
|
@@ -222,7 +222,9 @@ void SshSharedConnection::emitConnected()
|
|||||||
void SshSharedConnection::emitError(QProcess::ProcessError error, const QString &errorString)
|
void SshSharedConnection::emitError(QProcess::ProcessError error, const QString &errorString)
|
||||||
{
|
{
|
||||||
m_state = QProcess::NotRunning;
|
m_state = QProcess::NotRunning;
|
||||||
ProcessResultData resultData = m_masterProcess->resultData();
|
ProcessResultData resultData{-1, QProcess::CrashExit, QProcess::UnknownError, {}};
|
||||||
|
if (m_masterProcess)
|
||||||
|
resultData = m_masterProcess->resultData();
|
||||||
resultData.m_error = error;
|
resultData.m_error = error;
|
||||||
resultData.m_errorString = errorString;
|
resultData.m_errorString = errorString;
|
||||||
emit disconnected(resultData);
|
emit disconnected(resultData);
|
||||||
|
@@ -353,7 +353,7 @@ private slots:
|
|||||||
QFETCH(CommandLine, cmdLine);
|
QFETCH(CommandLine, cmdLine);
|
||||||
|
|
||||||
TestShell shell(cmdLine, true);
|
TestShell shell(cmdLine, true);
|
||||||
QCOMPARE(shell.state(), DeviceShell::State::NoScript);
|
QCOMPARE(shell.state(), DeviceShell::State::Failed);
|
||||||
|
|
||||||
const RunResult result = shell.runInShell({"echo", {"Hello"}});
|
const RunResult result = shell.runInShell({"echo", {"Hello"}});
|
||||||
QCOMPARE(result.exitCode, 0);
|
QCOMPARE(result.exitCode, 0);
|
||||||
|
Reference in New Issue
Block a user