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;
|
||||
QString m_errorString;
|
||||
bool m_abortOnMetaChars = true;
|
||||
bool m_runAsRoot = false;
|
||||
QSettings *m_settings = nullptr;
|
||||
|
||||
// Used on Unix only
|
||||
@@ -545,6 +546,7 @@ bool ConsoleProcess::start()
|
||||
}
|
||||
|
||||
d->m_environment.unset(QLatin1String("TERM"));
|
||||
|
||||
const QStringList env = d->m_environment.toStringList();
|
||||
if (!env.isEmpty()) {
|
||||
d->m_tempFile = new QTemporaryFile();
|
||||
@@ -571,20 +573,25 @@ bool ConsoleProcess::start()
|
||||
|
||||
const QString stubPath = QCoreApplication::applicationDirPath()
|
||||
+ QLatin1String("/" QTC_REL_TOOLS_PATH "/qtcreator_process_stub");
|
||||
QStringList allArgs = terminalArgs.toUnixArgs()
|
||||
<< stubPath
|
||||
<< modeOption(d->m_mode)
|
||||
<< d->m_stubServer.fullServerName()
|
||||
<< msgPromptToClose()
|
||||
<< workingDirectory()
|
||||
<< (d->m_tempFile ? d->m_tempFile->fileName() : QString())
|
||||
<< QString::number(getpid())
|
||||
<< pcmd
|
||||
<< pargs.toUnixArgs();
|
||||
|
||||
QStringList allArgs = terminalArgs.toUnixArgs();
|
||||
if (d->m_runAsRoot)
|
||||
allArgs << "sudo" << "-A";
|
||||
|
||||
allArgs << stubPath
|
||||
<< modeOption(d->m_mode)
|
||||
<< d->m_stubServer.fullServerName()
|
||||
<< msgPromptToClose()
|
||||
<< workingDirectory()
|
||||
<< (d->m_tempFile ? d->m_tempFile->fileName() : QString())
|
||||
<< QString::number(getpid())
|
||||
<< pcmd
|
||||
<< pargs.toUnixArgs();
|
||||
|
||||
if (terminal.needsQuotes)
|
||||
allArgs = QStringList { QtcProcess::joinArgs(allArgs) };
|
||||
|
||||
d->m_process.setEnvironment(env);
|
||||
d->m_process.start(terminal.command, allArgs);
|
||||
if (!d->m_process.waitForStarted()) {
|
||||
stubServerShutdown();
|
||||
@@ -958,6 +965,11 @@ Environment ConsoleProcess::environment() const
|
||||
return d->m_environment;
|
||||
}
|
||||
|
||||
void Utils::ConsoleProcess::setRunAsRoot(bool on)
|
||||
{
|
||||
d->m_runAsRoot = on;
|
||||
}
|
||||
|
||||
QProcess::ProcessError ConsoleProcess::error() const
|
||||
{
|
||||
return d->m_error;
|
||||
|
@@ -66,6 +66,7 @@ public:
|
||||
|
||||
void setCommand(const Utils::CommandLine &command);
|
||||
Utils::CommandLine command() const;
|
||||
|
||||
void setAbortOnMetaChars(bool abort);
|
||||
|
||||
void setWorkingDirectory(const QString &dir);
|
||||
@@ -74,6 +75,8 @@ public:
|
||||
void setEnvironment(const Environment &env);
|
||||
Environment environment() const;
|
||||
|
||||
void setRunAsRoot(bool on);
|
||||
|
||||
QProcess::ProcessError error() const;
|
||||
QString errorString() const;
|
||||
|
||||
|
@@ -169,6 +169,7 @@ public:
|
||||
bool breakOnMain = false;
|
||||
bool multiProcess = false; // Whether to set detach-on-fork off.
|
||||
bool useTerminal = false;
|
||||
bool runAsRoot = false;
|
||||
|
||||
ProjectExplorer::Runnable debugger;
|
||||
QString overrideStartScript; // Used in attach to core and remote debugging
|
||||
|
@@ -395,6 +395,7 @@ void DebuggerRunTool::setUseTerminal(bool on)
|
||||
|
||||
if (on && !d->terminalRunner && !useCdbConsole) {
|
||||
d->terminalRunner = new TerminalRunner(runControl(), m_runParameters.inferior);
|
||||
d->terminalRunner->setRunAsRoot(m_runParameters.runAsRoot);
|
||||
addStartDependency(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)
|
||||
{
|
||||
m_runParameters.commandsAfterConnect = commands;
|
||||
@@ -948,6 +956,8 @@ DebuggerRunTool::DebuggerRunTool(RunControl *runControl, AllowTerminal allowTerm
|
||||
m_runParameters.symbolFile = symbolsAspect->filePath();
|
||||
if (auto terminalAspect = runControl->aspect<TerminalAspect>())
|
||||
m_runParameters.useTerminal = terminalAspect->useTerminal();
|
||||
if (auto runAsRootAspect = runControl->aspect<RunAsRootAspect>())
|
||||
m_runParameters.runAsRoot = runAsRootAspect->value();
|
||||
|
||||
Kit *kit = runControl->kit();
|
||||
QTC_ASSERT(kit, return);
|
||||
|
@@ -108,6 +108,7 @@ public:
|
||||
void setUseCtrlCStub(bool on);
|
||||
void setBreakOnMain(bool on);
|
||||
void setUseTerminal(bool on);
|
||||
void setRunAsRoot(bool on);
|
||||
|
||||
void setCommandsAfterConnect(const QString &commands);
|
||||
void setCommandsForReset(const QString &commands);
|
||||
|
@@ -3853,11 +3853,20 @@ void GdbEngine::setupEngine()
|
||||
if (!boolSetting(LoadGdbInit))
|
||||
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());
|
||||
|
||||
m_gdbProc.setCommand(gdbCommand);
|
||||
if (QFileInfo(rp.debugger.workingDirectory).isDir())
|
||||
m_gdbProc.setWorkingDirectory(rp.debugger.workingDirectory);
|
||||
m_gdbProc.setEnvironment(rp.debugger.environment);
|
||||
m_gdbProc.setEnvironment(gdbEnv);
|
||||
m_gdbProc.start();
|
||||
|
||||
if (!m_gdbProc.waitForStarted()) {
|
||||
@@ -4256,7 +4265,15 @@ void GdbEngine::interruptLocalInferior(qint64 pid)
|
||||
return;
|
||||
}
|
||||
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));
|
||||
} else {
|
||||
showMessage(errorMessage, LogError);
|
||||
@@ -4622,10 +4639,13 @@ void GdbEngine::interruptInferior2()
|
||||
}
|
||||
}
|
||||
|
||||
} else if (isTermEngine() || isPlainEngine()) {
|
||||
} else if (isPlainEngine()) {
|
||||
|
||||
interruptLocalInferior(inferiorPid());
|
||||
|
||||
} else if (isTermEngine()) {
|
||||
|
||||
terminal()->interruptProcess();
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -188,8 +188,18 @@ void TerminalRunner::interruptProcess()
|
||||
m_stubProc.interruptProcess();
|
||||
}
|
||||
|
||||
void TerminalRunner::setRunAsRoot(bool on)
|
||||
{
|
||||
m_runAsRoot = on;
|
||||
}
|
||||
|
||||
void TerminalRunner::start()
|
||||
{
|
||||
if (m_runAsRoot) {
|
||||
m_stubProc.setRunAsRoot(true);
|
||||
RunControl::provideAskPassEntry(m_stubRunnable.environment);
|
||||
}
|
||||
|
||||
m_stubProc.setEnvironment(m_stubRunnable.environment);
|
||||
m_stubProc.setWorkingDirectory(m_stubRunnable.workingDirectory);
|
||||
|
||||
|
@@ -78,6 +78,7 @@ public:
|
||||
qint64 applicationMainThreadId() const { return m_applicationMainThreadId; }
|
||||
|
||||
void interruptProcess();
|
||||
void setRunAsRoot(bool on);
|
||||
|
||||
private:
|
||||
void start() final;
|
||||
@@ -90,6 +91,7 @@ private:
|
||||
ProjectExplorer::Runnable m_stubRunnable;
|
||||
qint64 m_applicationPid = 0;
|
||||
qint64 m_applicationMainThreadId = 0;
|
||||
bool m_runAsRoot = false;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
|
@@ -100,6 +100,7 @@ public:
|
||||
ApplicationLauncher *q;
|
||||
|
||||
bool m_isLocal = true;
|
||||
bool m_runAsRoot = false;
|
||||
|
||||
// Local
|
||||
QtcProcess m_guiProcess;
|
||||
@@ -179,6 +180,11 @@ void ApplicationLauncher::setUseTerminal(bool on)
|
||||
d->m_useTerminal = on;
|
||||
}
|
||||
|
||||
void ApplicationLauncher::setRunAsRoot(bool on)
|
||||
{
|
||||
d->m_runAsRoot = on;
|
||||
}
|
||||
|
||||
void ApplicationLauncher::stop()
|
||||
{
|
||||
d->stop();
|
||||
@@ -368,8 +374,13 @@ void ApplicationLauncherPrivate::start(const Runnable &runnable, const IDevice::
|
||||
const QString fixedPath = FileUtils::normalizePathName(runnable.workingDirectory);
|
||||
m_guiProcess.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;
|
||||
#ifdef Q_OS_WIN
|
||||
@@ -377,13 +388,20 @@ void ApplicationLauncherPrivate::start(const Runnable &runnable, const IDevice::
|
||||
WinDebugInterface::instance()->start(); // Try to start listener again...
|
||||
#endif
|
||||
|
||||
if (!m_useTerminal) {
|
||||
m_guiProcess.setCommand(runnable.commandLine());
|
||||
CommandLine cmdLine = 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.start();
|
||||
} else {
|
||||
m_consoleProcess.setCommand(runnable.commandLine());
|
||||
m_consoleProcess.start();
|
||||
}
|
||||
} else {
|
||||
QTC_ASSERT(m_state == Inactive, return);
|
||||
|
@@ -54,6 +54,7 @@ public:
|
||||
|
||||
void setProcessChannelMode(QProcess::ProcessChannelMode mode);
|
||||
void setUseTerminal(bool on);
|
||||
void setRunAsRoot(bool on);
|
||||
void start(const Runnable &runnable);
|
||||
void start(const Runnable &runnable, const IDevice::ConstPtr &device);
|
||||
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) {
|
||||
BuildTargetInfo bti = buildTargetInfo();
|
||||
if (bti.runEnvModifier)
|
||||
|
@@ -736,4 +736,19 @@ UseDyldSuffixAspect::UseDyldSuffixAspect()
|
||||
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
|
||||
|
@@ -147,6 +147,14 @@ public:
|
||||
UseDyldSuffixAspect();
|
||||
};
|
||||
|
||||
class PROJECTEXPLORER_EXPORT RunAsRootAspect : public Utils::BoolAspect
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
RunAsRootAspect();
|
||||
};
|
||||
|
||||
class PROJECTEXPLORER_EXPORT ExecutableAspect : public Utils::BaseAspect
|
||||
{
|
||||
Q_OBJECT
|
||||
|
@@ -1154,6 +1154,8 @@ SimpleTargetRunner::SimpleTargetRunner(RunControl *runControl)
|
||||
setId("SimpleTargetRunner");
|
||||
if (auto terminalAspect = runControl->aspect<TerminalAspect>())
|
||||
m_useTerminal = terminalAspect->useTerminal();
|
||||
if (auto runAsRootAspect = runControl->aspect<RunAsRootAspect>())
|
||||
m_runAsRoot = runAsRootAspect->value();
|
||||
}
|
||||
|
||||
void SimpleTargetRunner::start()
|
||||
@@ -1169,6 +1171,7 @@ void SimpleTargetRunner::doStart(const Runnable &runnable, const IDevice::ConstP
|
||||
m_stopReported = false;
|
||||
m_launcher.disconnect(this);
|
||||
m_launcher.setUseTerminal(m_useTerminal);
|
||||
m_launcher.setRunAsRoot(m_runAsRoot);
|
||||
|
||||
const bool isDesktop = device.isNull() || device.dynamicCast<const DesktopDevice>();
|
||||
const QString rawDisplayName = runnable.displayName();
|
||||
|
@@ -302,6 +302,7 @@ private:
|
||||
|
||||
bool m_stopReported = false;
|
||||
bool m_useTerminal = false;
|
||||
bool m_runAsRoot = false;
|
||||
};
|
||||
|
||||
class PROJECTEXPLORER_EXPORT OutputFormatterFactory
|
||||
|
Reference in New Issue
Block a user