diff --git a/src/libs/ssh/sshconnection.h b/src/libs/ssh/sshconnection.h index 3447f3c195c..381bd463c91 100644 --- a/src/libs/ssh/sshconnection.h +++ b/src/libs/ssh/sshconnection.h @@ -61,6 +61,7 @@ public: QString host() const { return url.host(); } quint16 port() const { return url.port(); } QString userName() const { return url.userName(); } + QString userAtHost() const { return userName().isEmpty() ? host() : userName() + '@' + host(); } void setHost(const QString &host) { url.setHost(host); } void setPort(int port) { url.setPort(port); } void setUserName(const QString &name) { url.setUserName(name); } diff --git a/src/libs/utils/qtcprocess.cpp b/src/libs/utils/qtcprocess.cpp index 7bd1891efa8..9e56fe0f1be 100644 --- a/src/libs/utils/qtcprocess.cpp +++ b/src/libs/utils/qtcprocess.cpp @@ -563,6 +563,7 @@ public: , q(parent) , m_process(newProcessInstance(parent, processImpl, processMode, terminalMode)) , m_processMode(processMode) + , m_terminalMode(terminalMode) { connect(m_process, &ProcessInterface::started, q, &QtcProcess::started); @@ -604,12 +605,6 @@ public: void defaultStart(const CommandLine &commandLine, const FilePath &workingDirectory, const Environment &environment) { - if (commandLine.executable().needsDevice()) { - QTC_ASSERT(s_deviceHooks.startProcessHook, return); - s_deviceHooks.startProcessHook(*q); - return; - } - if (processLog().isDebugEnabled()) { static int n = 0; qCDebug(processLog) << "STARTING PROCESS: " << ++n << " " << commandLine.toUserOutput(); @@ -696,6 +691,7 @@ public: QtcProcess *q; ProcessInterface *m_process; const ProcessMode m_processMode; + const QtcProcess::TerminalMode m_terminalMode; CommandLine m_commandLine; FilePath m_workingDirectory; Environment m_environment; @@ -788,6 +784,11 @@ ProcessMode QtcProcess::processMode() const return d->m_processMode; } +QtcProcess::TerminalMode QtcProcess::terminalMode() const +{ + return d->m_terminalMode; +} + void QtcProcess::setEnvironment(const Environment &env) { d->m_environment = env; @@ -805,6 +806,11 @@ const Environment &QtcProcess::environment() const return d->m_environment; } +bool QtcProcess::hasEnvironment() const +{ + return d->m_haveEnv; +} + void QtcProcess::setCommand(const CommandLine &cmdLine) { if (d->m_workingDirectory.needsDevice() && cmdLine.executable().needsDevice()) { @@ -845,6 +851,11 @@ void QtcProcess::setUseCtrlCStub(bool enabled) void QtcProcess::start() { + if (d->m_commandLine.executable().needsDevice()) { + QTC_ASSERT(s_deviceHooks.startProcessHook, return); + s_deviceHooks.startProcessHook(*this); + return; + } d->clearForRun(); const CommandLine cmd = d->fullCommandLine(); const Environment env = d->fullEnvironment(); diff --git a/src/libs/utils/qtcprocess.h b/src/libs/utils/qtcprocess.h index d64991f759b..fa844d18955 100644 --- a/src/libs/utils/qtcprocess.h +++ b/src/libs/utils/qtcprocess.h @@ -90,6 +90,7 @@ public: ~QtcProcess(); ProcessMode processMode() const; + TerminalMode terminalMode() const; enum Result { // Finished successfully. Unless an ExitCodeInterpreter is set @@ -111,6 +112,7 @@ public: void setEnvironment(const Environment &env); void unsetEnvironment(); const Environment &environment() const; + bool hasEnvironment() const; void setCommand(const CommandLine &cmdLine); const CommandLine &commandLine() const; diff --git a/src/plugins/remotelinux/linuxdevice.cpp b/src/plugins/remotelinux/linuxdevice.cpp index 0e1962ae9a9..2fa40838e50 100644 --- a/src/plugins/remotelinux/linuxdevice.cpp +++ b/src/plugins/remotelinux/linuxdevice.cpp @@ -286,6 +286,9 @@ public: explicit LinuxDevicePrivate(LinuxDevice *parent); ~LinuxDevicePrivate(); + CommandLine fullLocalCommandLine(const CommandLine &remoteCommand, + QtcProcess::TerminalMode terminalMode, + bool hasDisplay) const; bool setupShell(); bool runInShell(const CommandLine &cmd, const QByteArray &data = {}); QString outputForRunInShell(const QString &cmd); @@ -414,9 +417,7 @@ DeviceEnvironmentFetcher::Ptr LinuxDevice::environmentFetcher() const QString LinuxDevice::userAtHost() const { - if (sshParameters().userName().isEmpty()) - return sshParameters().host(); - return sshParameters().userName() + '@' + sshParameters().host(); + return sshParameters().userAtHost(); } FilePath LinuxDevice::mapToGlobalPath(const FilePath &pathOnDevice) const @@ -438,9 +439,53 @@ bool LinuxDevice::handlesFile(const FilePath &filePath) const return filePath.scheme() == "ssh" && filePath.host() == userAtHost(); } -void LinuxDevice::runProcess(QtcProcess &) const +CommandLine LinuxDevicePrivate::fullLocalCommandLine(const CommandLine &remoteCommand, + QtcProcess::TerminalMode terminalMode, + bool hasDisplay) const { - QTC_CHECK(false); // FIXME: Implement + Utils::CommandLine cmd{SshSettings::sshFilePath()}; + const SshConnectionParameters parameters = q->sshParameters(); + + if (hasDisplay) + cmd.addArg("-X"); + if (terminalMode != QtcProcess::TerminalOff) + cmd.addArg("-tt"); + + cmd.addArg("-q"); + // TODO: currently this drops shared connection (-o ControlPath=socketFilePath) + cmd.addArgs(parameters.connectionOptions(SshSettings::sshFilePath()) << parameters.host()); + + CommandLine remoteWithLocalPath = remoteCommand; + FilePath executable = remoteWithLocalPath.executable(); + executable.setScheme({}); + executable.setHost({}); + remoteWithLocalPath.setExecutable(executable); + cmd.addArg(remoteWithLocalPath.toUserOutput()); + return cmd; +} + +void LinuxDevice::runProcess(QtcProcess &process) const +{ + QTC_ASSERT(!process.isRunning(), return); + + Utils::Environment env = process.hasEnvironment() ? process.environment() + : Utils::Environment::systemEnvironment(); + const bool hasDisplay = env.hasKey("DISPLAY") && (env.value("DISPLAY") != QString(":0")); + if (SshSettings::askpassFilePath().exists()) { + env.set("SSH_ASKPASS", SshSettings::askpassFilePath().toUserOutput()); + + // OpenSSH only uses the askpass program if DISPLAY is set, regardless of the platform. + if (!env.hasKey("DISPLAY")) + env.set("DISPLAY", ":0"); + } + process.setEnvironment(env); + + // Otherwise, ssh will ignore SSH_ASKPASS and read from /dev/tty directly. + process.setDisableUnixTerminal(); + + process.setCommand(d->fullLocalCommandLine(process.commandLine(), process.terminalMode(), + hasDisplay)); + process.start(); } LinuxDevicePrivate::LinuxDevicePrivate(LinuxDevice *parent) diff --git a/src/plugins/remotelinux/linuxdevice.h b/src/plugins/remotelinux/linuxdevice.h index d914e8b223b..d2906b230c3 100644 --- a/src/plugins/remotelinux/linuxdevice.h +++ b/src/plugins/remotelinux/linuxdevice.h @@ -82,7 +82,7 @@ public: QByteArray fileContents(const Utils::FilePath &filePath, qint64 limit, qint64 offset) const override; bool writeFileContents(const Utils::FilePath &filePath, const QByteArray &data) const override; QDateTime lastModified(const Utils::FilePath &filePath) const override; - void runProcess(Utils::QtcProcess &) const override; + void runProcess(Utils::QtcProcess &process) const override; qint64 fileSize(const Utils::FilePath &filePath) const override; qint64 bytesAvailable(const Utils::FilePath &filePath) const override; QFileDevice::Permissions permissions(const Utils::FilePath &filePath) const override;