forked from qt-creator/qt-creator
ProjectExplorer/Debugger: Add a 'Run as root' option for Unix hosts
For local run and GDB debug, with or without terminal. Task-number: QTCREATORBUG-2831 Task-number: QTCREATORBUG-25330 Change-Id: I9b5d2156bcffea4f358474ecdbcad580a4419917 Reviewed-by: Christian Stenger <christian.stenger@qt.io> Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
This commit is contained in:
@@ -94,6 +94,7 @@ public:
|
|||||||
QProcess::ProcessError m_error = QProcess::UnknownError;
|
QProcess::ProcessError m_error = QProcess::UnknownError;
|
||||||
QString m_errorString;
|
QString m_errorString;
|
||||||
bool m_abortOnMetaChars = true;
|
bool m_abortOnMetaChars = true;
|
||||||
|
bool m_runAsRoot = false;
|
||||||
QSettings *m_settings = nullptr;
|
QSettings *m_settings = nullptr;
|
||||||
|
|
||||||
// Used on Unix only
|
// Used on Unix only
|
||||||
@@ -545,6 +546,7 @@ bool ConsoleProcess::start()
|
|||||||
}
|
}
|
||||||
|
|
||||||
d->m_environment.unset(QLatin1String("TERM"));
|
d->m_environment.unset(QLatin1String("TERM"));
|
||||||
|
|
||||||
const QStringList env = d->m_environment.toStringList();
|
const QStringList env = d->m_environment.toStringList();
|
||||||
if (!env.isEmpty()) {
|
if (!env.isEmpty()) {
|
||||||
d->m_tempFile = new QTemporaryFile();
|
d->m_tempFile = new QTemporaryFile();
|
||||||
@@ -571,8 +573,12 @@ bool ConsoleProcess::start()
|
|||||||
|
|
||||||
const QString stubPath = QCoreApplication::applicationDirPath()
|
const QString stubPath = QCoreApplication::applicationDirPath()
|
||||||
+ QLatin1String("/" QTC_REL_TOOLS_PATH "/qtcreator_process_stub");
|
+ QLatin1String("/" QTC_REL_TOOLS_PATH "/qtcreator_process_stub");
|
||||||
QStringList allArgs = terminalArgs.toUnixArgs()
|
|
||||||
<< stubPath
|
QStringList allArgs = terminalArgs.toUnixArgs();
|
||||||
|
if (d->m_runAsRoot)
|
||||||
|
allArgs << "sudo" << "-A";
|
||||||
|
|
||||||
|
allArgs << stubPath
|
||||||
<< modeOption(d->m_mode)
|
<< modeOption(d->m_mode)
|
||||||
<< d->m_stubServer.fullServerName()
|
<< d->m_stubServer.fullServerName()
|
||||||
<< msgPromptToClose()
|
<< msgPromptToClose()
|
||||||
@@ -585,6 +591,7 @@ bool ConsoleProcess::start()
|
|||||||
if (terminal.needsQuotes)
|
if (terminal.needsQuotes)
|
||||||
allArgs = QStringList { QtcProcess::joinArgs(allArgs) };
|
allArgs = QStringList { QtcProcess::joinArgs(allArgs) };
|
||||||
|
|
||||||
|
d->m_process.setEnvironment(env);
|
||||||
d->m_process.start(terminal.command, allArgs);
|
d->m_process.start(terminal.command, allArgs);
|
||||||
if (!d->m_process.waitForStarted()) {
|
if (!d->m_process.waitForStarted()) {
|
||||||
stubServerShutdown();
|
stubServerShutdown();
|
||||||
@@ -958,6 +965,11 @@ Environment ConsoleProcess::environment() const
|
|||||||
return d->m_environment;
|
return d->m_environment;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Utils::ConsoleProcess::setRunAsRoot(bool on)
|
||||||
|
{
|
||||||
|
d->m_runAsRoot = on;
|
||||||
|
}
|
||||||
|
|
||||||
QProcess::ProcessError ConsoleProcess::error() const
|
QProcess::ProcessError ConsoleProcess::error() const
|
||||||
{
|
{
|
||||||
return d->m_error;
|
return d->m_error;
|
||||||
|
@@ -66,6 +66,7 @@ public:
|
|||||||
|
|
||||||
void setCommand(const Utils::CommandLine &command);
|
void setCommand(const Utils::CommandLine &command);
|
||||||
Utils::CommandLine command() const;
|
Utils::CommandLine command() const;
|
||||||
|
|
||||||
void setAbortOnMetaChars(bool abort);
|
void setAbortOnMetaChars(bool abort);
|
||||||
|
|
||||||
void setWorkingDirectory(const QString &dir);
|
void setWorkingDirectory(const QString &dir);
|
||||||
@@ -74,6 +75,8 @@ public:
|
|||||||
void setEnvironment(const Environment &env);
|
void setEnvironment(const Environment &env);
|
||||||
Environment environment() const;
|
Environment environment() const;
|
||||||
|
|
||||||
|
void setRunAsRoot(bool on);
|
||||||
|
|
||||||
QProcess::ProcessError error() const;
|
QProcess::ProcessError error() const;
|
||||||
QString errorString() const;
|
QString errorString() const;
|
||||||
|
|
||||||
|
@@ -169,6 +169,7 @@ public:
|
|||||||
bool breakOnMain = false;
|
bool breakOnMain = false;
|
||||||
bool multiProcess = false; // Whether to set detach-on-fork off.
|
bool multiProcess = false; // Whether to set detach-on-fork off.
|
||||||
bool useTerminal = false;
|
bool useTerminal = false;
|
||||||
|
bool runAsRoot = false;
|
||||||
|
|
||||||
ProjectExplorer::Runnable debugger;
|
ProjectExplorer::Runnable debugger;
|
||||||
QString overrideStartScript; // Used in attach to core and remote debugging
|
QString overrideStartScript; // Used in attach to core and remote debugging
|
||||||
|
@@ -395,6 +395,7 @@ void DebuggerRunTool::setUseTerminal(bool on)
|
|||||||
|
|
||||||
if (on && !d->terminalRunner && !useCdbConsole) {
|
if (on && !d->terminalRunner && !useCdbConsole) {
|
||||||
d->terminalRunner = new TerminalRunner(runControl(), m_runParameters.inferior);
|
d->terminalRunner = new TerminalRunner(runControl(), m_runParameters.inferior);
|
||||||
|
d->terminalRunner->setRunAsRoot(m_runParameters.runAsRoot);
|
||||||
addStartDependency(d->terminalRunner);
|
addStartDependency(d->terminalRunner);
|
||||||
}
|
}
|
||||||
if (!on && d->terminalRunner) {
|
if (!on && d->terminalRunner) {
|
||||||
@@ -402,6 +403,13 @@ void DebuggerRunTool::setUseTerminal(bool on)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DebuggerRunTool::setRunAsRoot(bool on)
|
||||||
|
{
|
||||||
|
m_runParameters.runAsRoot = on;
|
||||||
|
if (d->terminalRunner)
|
||||||
|
d->terminalRunner->setRunAsRoot(on);
|
||||||
|
}
|
||||||
|
|
||||||
void DebuggerRunTool::setCommandsAfterConnect(const QString &commands)
|
void DebuggerRunTool::setCommandsAfterConnect(const QString &commands)
|
||||||
{
|
{
|
||||||
m_runParameters.commandsAfterConnect = commands;
|
m_runParameters.commandsAfterConnect = commands;
|
||||||
@@ -948,6 +956,8 @@ DebuggerRunTool::DebuggerRunTool(RunControl *runControl, AllowTerminal allowTerm
|
|||||||
m_runParameters.symbolFile = symbolsAspect->filePath();
|
m_runParameters.symbolFile = symbolsAspect->filePath();
|
||||||
if (auto terminalAspect = runControl->aspect<TerminalAspect>())
|
if (auto terminalAspect = runControl->aspect<TerminalAspect>())
|
||||||
m_runParameters.useTerminal = terminalAspect->useTerminal();
|
m_runParameters.useTerminal = terminalAspect->useTerminal();
|
||||||
|
if (auto runAsRootAspect = runControl->aspect<RunAsRootAspect>())
|
||||||
|
m_runParameters.runAsRoot = runAsRootAspect->value();
|
||||||
|
|
||||||
Kit *kit = runControl->kit();
|
Kit *kit = runControl->kit();
|
||||||
QTC_ASSERT(kit, return);
|
QTC_ASSERT(kit, return);
|
||||||
|
@@ -108,6 +108,7 @@ public:
|
|||||||
void setUseCtrlCStub(bool on);
|
void setUseCtrlCStub(bool on);
|
||||||
void setBreakOnMain(bool on);
|
void setBreakOnMain(bool on);
|
||||||
void setUseTerminal(bool on);
|
void setUseTerminal(bool on);
|
||||||
|
void setRunAsRoot(bool on);
|
||||||
|
|
||||||
void setCommandsAfterConnect(const QString &commands);
|
void setCommandsAfterConnect(const QString &commands);
|
||||||
void setCommandsForReset(const QString &commands);
|
void setCommandsForReset(const QString &commands);
|
||||||
|
@@ -3853,11 +3853,20 @@ void GdbEngine::setupEngine()
|
|||||||
if (!boolSetting(LoadGdbInit))
|
if (!boolSetting(LoadGdbInit))
|
||||||
gdbCommand.addArg("-n");
|
gdbCommand.addArg("-n");
|
||||||
|
|
||||||
|
Environment gdbEnv = rp.debugger.environment;
|
||||||
|
if (rp.runAsRoot) {
|
||||||
|
CommandLine wrapped("sudo", {"-A"});
|
||||||
|
wrapped.addArgs(gdbCommand);
|
||||||
|
gdbCommand = wrapped;
|
||||||
|
RunControl::provideAskPassEntry(gdbEnv);
|
||||||
|
}
|
||||||
|
|
||||||
showMessage("STARTING " + gdbCommand.toUserOutput());
|
showMessage("STARTING " + gdbCommand.toUserOutput());
|
||||||
|
|
||||||
m_gdbProc.setCommand(gdbCommand);
|
m_gdbProc.setCommand(gdbCommand);
|
||||||
if (QFileInfo(rp.debugger.workingDirectory).isDir())
|
if (QFileInfo(rp.debugger.workingDirectory).isDir())
|
||||||
m_gdbProc.setWorkingDirectory(rp.debugger.workingDirectory);
|
m_gdbProc.setWorkingDirectory(rp.debugger.workingDirectory);
|
||||||
m_gdbProc.setEnvironment(rp.debugger.environment);
|
m_gdbProc.setEnvironment(gdbEnv);
|
||||||
m_gdbProc.start();
|
m_gdbProc.start();
|
||||||
|
|
||||||
if (!m_gdbProc.waitForStarted()) {
|
if (!m_gdbProc.waitForStarted()) {
|
||||||
@@ -4256,7 +4265,15 @@ void GdbEngine::interruptLocalInferior(qint64 pid)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
QString errorMessage;
|
QString errorMessage;
|
||||||
if (interruptProcess(pid, GdbEngineType, &errorMessage)) {
|
if (runParameters().runAsRoot) {
|
||||||
|
Environment env = Environment::systemEnvironment();
|
||||||
|
RunControl::provideAskPassEntry(env);
|
||||||
|
QtcProcess proc;
|
||||||
|
proc.setCommand(CommandLine{"sudo", {"-A", "kill", "-s", "SIGINT", QString::number(pid)}});
|
||||||
|
proc.setEnvironment(env);
|
||||||
|
proc.start();
|
||||||
|
proc.waitForFinished();
|
||||||
|
} else if (interruptProcess(pid, GdbEngineType, &errorMessage)) {
|
||||||
showMessage("Interrupted " + QString::number(pid));
|
showMessage("Interrupted " + QString::number(pid));
|
||||||
} else {
|
} else {
|
||||||
showMessage(errorMessage, LogError);
|
showMessage(errorMessage, LogError);
|
||||||
@@ -4622,10 +4639,13 @@ void GdbEngine::interruptInferior2()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (isTermEngine() || isPlainEngine()) {
|
} else if (isPlainEngine()) {
|
||||||
|
|
||||||
interruptLocalInferior(inferiorPid());
|
interruptLocalInferior(inferiorPid());
|
||||||
|
|
||||||
|
} else if (isTermEngine()) {
|
||||||
|
|
||||||
|
terminal()->interruptProcess();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -188,8 +188,18 @@ void TerminalRunner::interruptProcess()
|
|||||||
m_stubProc.interruptProcess();
|
m_stubProc.interruptProcess();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TerminalRunner::setRunAsRoot(bool on)
|
||||||
|
{
|
||||||
|
m_runAsRoot = on;
|
||||||
|
}
|
||||||
|
|
||||||
void TerminalRunner::start()
|
void TerminalRunner::start()
|
||||||
{
|
{
|
||||||
|
if (m_runAsRoot) {
|
||||||
|
m_stubProc.setRunAsRoot(true);
|
||||||
|
RunControl::provideAskPassEntry(m_stubRunnable.environment);
|
||||||
|
}
|
||||||
|
|
||||||
m_stubProc.setEnvironment(m_stubRunnable.environment);
|
m_stubProc.setEnvironment(m_stubRunnable.environment);
|
||||||
m_stubProc.setWorkingDirectory(m_stubRunnable.workingDirectory);
|
m_stubProc.setWorkingDirectory(m_stubRunnable.workingDirectory);
|
||||||
|
|
||||||
|
@@ -78,6 +78,7 @@ public:
|
|||||||
qint64 applicationMainThreadId() const { return m_applicationMainThreadId; }
|
qint64 applicationMainThreadId() const { return m_applicationMainThreadId; }
|
||||||
|
|
||||||
void interruptProcess();
|
void interruptProcess();
|
||||||
|
void setRunAsRoot(bool on);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void start() final;
|
void start() final;
|
||||||
@@ -90,6 +91,7 @@ private:
|
|||||||
ProjectExplorer::Runnable m_stubRunnable;
|
ProjectExplorer::Runnable m_stubRunnable;
|
||||||
qint64 m_applicationPid = 0;
|
qint64 m_applicationPid = 0;
|
||||||
qint64 m_applicationMainThreadId = 0;
|
qint64 m_applicationMainThreadId = 0;
|
||||||
|
bool m_runAsRoot = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
|
@@ -100,6 +100,7 @@ public:
|
|||||||
ApplicationLauncher *q;
|
ApplicationLauncher *q;
|
||||||
|
|
||||||
bool m_isLocal = true;
|
bool m_isLocal = true;
|
||||||
|
bool m_runAsRoot = false;
|
||||||
|
|
||||||
// Local
|
// Local
|
||||||
QtcProcess m_guiProcess;
|
QtcProcess m_guiProcess;
|
||||||
@@ -179,6 +180,11 @@ void ApplicationLauncher::setUseTerminal(bool on)
|
|||||||
d->m_useTerminal = on;
|
d->m_useTerminal = on;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ApplicationLauncher::setRunAsRoot(bool on)
|
||||||
|
{
|
||||||
|
d->m_runAsRoot = on;
|
||||||
|
}
|
||||||
|
|
||||||
void ApplicationLauncher::stop()
|
void ApplicationLauncher::stop()
|
||||||
{
|
{
|
||||||
d->stop();
|
d->stop();
|
||||||
@@ -368,8 +374,13 @@ void ApplicationLauncherPrivate::start(const Runnable &runnable, const IDevice::
|
|||||||
const QString fixedPath = FileUtils::normalizePathName(runnable.workingDirectory);
|
const QString fixedPath = FileUtils::normalizePathName(runnable.workingDirectory);
|
||||||
m_guiProcess.setWorkingDirectory(fixedPath);
|
m_guiProcess.setWorkingDirectory(fixedPath);
|
||||||
m_consoleProcess.setWorkingDirectory(fixedPath);
|
m_consoleProcess.setWorkingDirectory(fixedPath);
|
||||||
m_guiProcess.setEnvironment(runnable.environment);
|
|
||||||
m_consoleProcess.setEnvironment(runnable.environment);
|
Environment env = runnable.environment;
|
||||||
|
if (m_runAsRoot)
|
||||||
|
RunControl::provideAskPassEntry(env);
|
||||||
|
|
||||||
|
m_guiProcess.setEnvironment(env);
|
||||||
|
m_consoleProcess.setEnvironment(env);
|
||||||
|
|
||||||
m_processRunning = true;
|
m_processRunning = true;
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
@@ -377,13 +388,20 @@ void ApplicationLauncherPrivate::start(const Runnable &runnable, const IDevice::
|
|||||||
WinDebugInterface::instance()->start(); // Try to start listener again...
|
WinDebugInterface::instance()->start(); // Try to start listener again...
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!m_useTerminal) {
|
CommandLine cmdLine = runnable.commandLine();
|
||||||
m_guiProcess.setCommand(runnable.commandLine());
|
if (m_runAsRoot) {
|
||||||
|
CommandLine wrapped("sudo", {"-A"});
|
||||||
|
wrapped.addArgs(cmdLine);
|
||||||
|
cmdLine = wrapped;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_useTerminal) {
|
||||||
|
m_consoleProcess.setCommand(cmdLine);
|
||||||
|
m_consoleProcess.start();
|
||||||
|
} else {
|
||||||
|
m_guiProcess.setCommand(cmdLine);
|
||||||
m_guiProcess.closeWriteChannel();
|
m_guiProcess.closeWriteChannel();
|
||||||
m_guiProcess.start();
|
m_guiProcess.start();
|
||||||
} else {
|
|
||||||
m_consoleProcess.setCommand(runnable.commandLine());
|
|
||||||
m_consoleProcess.start();
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
QTC_ASSERT(m_state == Inactive, return);
|
QTC_ASSERT(m_state == Inactive, return);
|
||||||
|
@@ -54,6 +54,7 @@ public:
|
|||||||
|
|
||||||
void setProcessChannelMode(QProcess::ProcessChannelMode mode);
|
void setProcessChannelMode(QProcess::ProcessChannelMode mode);
|
||||||
void setUseTerminal(bool on);
|
void setUseTerminal(bool on);
|
||||||
|
void setRunAsRoot(bool on);
|
||||||
void start(const Runnable &runnable);
|
void start(const Runnable &runnable);
|
||||||
void start(const Runnable &runnable, const IDevice::ConstPtr &device);
|
void start(const Runnable &runnable, const IDevice::ConstPtr &device);
|
||||||
void stop();
|
void stop();
|
||||||
|
@@ -88,6 +88,9 @@ DesktopRunConfiguration::DesktopRunConfiguration(Target *target, Utils::Id id, K
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (HostOsInfo::isAnyUnixHost())
|
||||||
|
addAspect<RunAsRootAspect>();
|
||||||
|
|
||||||
envAspect->addModifier([this, libAspect](Environment &env) {
|
envAspect->addModifier([this, libAspect](Environment &env) {
|
||||||
BuildTargetInfo bti = buildTargetInfo();
|
BuildTargetInfo bti = buildTargetInfo();
|
||||||
if (bti.runEnvModifier)
|
if (bti.runEnvModifier)
|
||||||
|
@@ -736,4 +736,19 @@ UseDyldSuffixAspect::UseDyldSuffixAspect()
|
|||||||
LabelPlacement::AtCheckBox);
|
LabelPlacement::AtCheckBox);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\class ProjectExplorer::RunAsRootAspect
|
||||||
|
\inmodule QtCreator
|
||||||
|
|
||||||
|
\brief The RunAsRootAspect class lets a user specify whether the
|
||||||
|
application should run with root permissions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
RunAsRootAspect::RunAsRootAspect()
|
||||||
|
{
|
||||||
|
setId("RunAsRoot");
|
||||||
|
setSettingsKey("RunConfiguration.RunAsRoot");
|
||||||
|
setLabel(tr("Run as root user"), LabelPlacement::AtCheckBox);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace ProjectExplorer
|
} // namespace ProjectExplorer
|
||||||
|
@@ -147,6 +147,14 @@ public:
|
|||||||
UseDyldSuffixAspect();
|
UseDyldSuffixAspect();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class PROJECTEXPLORER_EXPORT RunAsRootAspect : public Utils::BoolAspect
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
RunAsRootAspect();
|
||||||
|
};
|
||||||
|
|
||||||
class PROJECTEXPLORER_EXPORT ExecutableAspect : public Utils::BaseAspect
|
class PROJECTEXPLORER_EXPORT ExecutableAspect : public Utils::BaseAspect
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@@ -1154,6 +1154,8 @@ SimpleTargetRunner::SimpleTargetRunner(RunControl *runControl)
|
|||||||
setId("SimpleTargetRunner");
|
setId("SimpleTargetRunner");
|
||||||
if (auto terminalAspect = runControl->aspect<TerminalAspect>())
|
if (auto terminalAspect = runControl->aspect<TerminalAspect>())
|
||||||
m_useTerminal = terminalAspect->useTerminal();
|
m_useTerminal = terminalAspect->useTerminal();
|
||||||
|
if (auto runAsRootAspect = runControl->aspect<RunAsRootAspect>())
|
||||||
|
m_runAsRoot = runAsRootAspect->value();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SimpleTargetRunner::start()
|
void SimpleTargetRunner::start()
|
||||||
@@ -1169,6 +1171,7 @@ void SimpleTargetRunner::doStart(const Runnable &runnable, const IDevice::ConstP
|
|||||||
m_stopReported = false;
|
m_stopReported = false;
|
||||||
m_launcher.disconnect(this);
|
m_launcher.disconnect(this);
|
||||||
m_launcher.setUseTerminal(m_useTerminal);
|
m_launcher.setUseTerminal(m_useTerminal);
|
||||||
|
m_launcher.setRunAsRoot(m_runAsRoot);
|
||||||
|
|
||||||
const bool isDesktop = device.isNull() || device.dynamicCast<const DesktopDevice>();
|
const bool isDesktop = device.isNull() || device.dynamicCast<const DesktopDevice>();
|
||||||
const QString rawDisplayName = runnable.displayName();
|
const QString rawDisplayName = runnable.displayName();
|
||||||
|
@@ -302,6 +302,7 @@ private:
|
|||||||
|
|
||||||
bool m_stopReported = false;
|
bool m_stopReported = false;
|
||||||
bool m_useTerminal = false;
|
bool m_useTerminal = false;
|
||||||
|
bool m_runAsRoot = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
class PROJECTEXPLORER_EXPORT OutputFormatterFactory
|
class PROJECTEXPLORER_EXPORT OutputFormatterFactory
|
||||||
|
Reference in New Issue
Block a user