aboutsummaryrefslogtreecommitdiffstats
path: root/src/libs/utils/processinfo.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/utils/processinfo.cpp')
-rw-r--r--src/libs/utils/processinfo.cpp179
1 files changed, 106 insertions, 73 deletions
diff --git a/src/libs/utils/processinfo.cpp b/src/libs/utils/processinfo.cpp
index 366800d316..0d71e380fb 100644
--- a/src/libs/utils/processinfo.cpp
+++ b/src/libs/utils/processinfo.cpp
@@ -3,14 +3,13 @@
#include "processinfo.h"
-#include "qtcprocess.h"
+#include "algorithm.h"
+#include "process.h"
-#if defined(Q_OS_UNIX)
#include <QDir>
-#include <signal.h>
-#include <errno.h>
-#include <string.h>
-#include <unistd.h>
+#include <QRegularExpression>
+
+#if defined(Q_OS_UNIX)
#elif defined(Q_OS_WIN)
#include "winutils.h"
#ifdef QTCREATOR_PCH_H
@@ -32,82 +31,64 @@ bool ProcessInfo::operator<(const ProcessInfo &other) const
return commandLine < other.commandLine;
}
-#if defined(Q_OS_UNIX)
+// Determine UNIX processes by reading "/proc". Default to ps if
+// it does not exist
-static bool isUnixProcessId(const QString &procname)
+static QList<ProcessInfo> getLocalProcessesUsingProc(const FilePath &procDir)
{
- for (int i = 0; i != procname.size(); ++i)
- if (!procname.at(i).isDigit())
- return false;
- return true;
-}
+ static const QString execs = "-exec test -f {}/exe \\; "
+ "-exec test -f {}/cmdline \\; "
+ "-exec echo -en 'p{}\\ne' \\; "
+ "-exec readlink {}/exe \\; "
+ "-exec echo -n c \\; "
+ "-exec head -n 1 {}/cmdline \\; "
+ "-exec echo \\; "
+ "-exec echo __SKIP_ME__ \\;";
-// Determine UNIX processes by reading "/proc". Default to ps if
-// it does not exist
+ CommandLine cmd{procDir.withNewPath("find"),
+ {procDir.nativePath(), "-maxdepth", "1", "-type", "d", "-name", "[0-9]*"}};
-static const char procDirC[] = "/proc/";
+ cmd.addArgs(execs, CommandLine::Raw);
+
+ Process procProcess;
+ procProcess.setCommand(cmd);
+ procProcess.runBlocking();
-static QList<ProcessInfo> getLocalProcessesUsingProc()
-{
QList<ProcessInfo> processes;
- const QString procDirPath = QLatin1String(procDirC);
- const QDir procDir = QDir(QLatin1String(procDirC));
- const QStringList procIds = procDir.entryList();
- for (const QString &procId : procIds) {
- if (!isUnixProcessId(procId))
- continue;
- ProcessInfo proc;
- proc.processId = procId.toInt();
- const QString root = procDirPath + procId;
-
- const QFile exeFile(root + QLatin1String("/exe"));
- proc.executable = exeFile.symLinkTarget();
-
- QFile cmdLineFile(root + QLatin1String("/cmdline"));
- if (cmdLineFile.open(QIODevice::ReadOnly)) { // process may have exited
- const QList<QByteArray> tokens = cmdLineFile.readAll().split('\0');
- if (!tokens.isEmpty()) {
- if (proc.executable.isEmpty())
- proc.executable = QString::fromLocal8Bit(tokens.front());
- for (const QByteArray &t : tokens) {
- if (!proc.commandLine.isEmpty())
- proc.commandLine.append(QLatin1Char(' '));
- proc.commandLine.append(QString::fromLocal8Bit(t));
- }
- }
- }
- if (proc.executable.isEmpty()) {
- QFile statFile(root + QLatin1String("/stat"));
- if (statFile.open(QIODevice::ReadOnly)) {
- const QStringList data = QString::fromLocal8Bit(statFile.readAll()).split(QLatin1Char(' '));
- if (data.size() < 2)
- continue;
- proc.executable = data.at(1);
- proc.commandLine = data.at(1); // PPID is element 3
- if (proc.executable.startsWith(QLatin1Char('(')) && proc.executable.endsWith(QLatin1Char(')'))) {
- proc.executable.truncate(proc.executable.size() - 1);
- proc.executable.remove(0, 1);
- }
- }
+ const auto lines = procProcess.readAllStandardOutput().split('\n');
+ for (auto it = lines.begin(); it != lines.end(); ++it) {
+ if (it->startsWith('p')) {
+ ProcessInfo proc;
+ bool ok;
+ proc.processId = FilePath::fromUserInput(it->mid(1).trimmed()).fileName().toInt(&ok);
+ QTC_ASSERT(ok, continue);
+ ++it;
+
+ QTC_ASSERT(it->startsWith('e'), continue);
+ proc.executable = it->mid(1).trimmed();
+ ++it;
+
+ QTC_ASSERT(it->startsWith('c'), continue);
+ proc.commandLine = it->mid(1).trimmed().replace('\0', ' ');
+ if (!proc.commandLine.contains("__SKIP_ME__"))
+ processes.append(proc);
}
- if (!proc.executable.isEmpty())
- processes.push_back(proc);
}
+
return processes;
}
// Determine UNIX processes by running ps
-static QMap<qint64, QString> getLocalProcessDataUsingPs(const QString &column)
+static QMap<qint64, QString> getLocalProcessDataUsingPs(const FilePath &deviceRoot,
+ const QString &column)
{
- QtcProcess process;
- process.setCommand({"ps", {"-e", "-o", "pid," + column}});
- process.start();
- if (!process.waitForFinished())
- return {};
+ Process process;
+ process.setCommand({deviceRoot.withNewPath("ps"), {"-e", "-o", "pid," + column}});
+ process.runBlocking();
// Split "457 /Users/foo.app arg1 arg2"
- const QStringList lines = process.stdOut().split(QLatin1Char('\n'));
+ const QStringList lines = process.readAllStandardOutput().split(QLatin1Char('\n'));
QMap<qint64, QString> result;
for (int i = 1; i < lines.size(); ++i) { // Skip header
const QString line = lines.at(i).trimmed();
@@ -118,14 +99,14 @@ static QMap<qint64, QString> getLocalProcessDataUsingPs(const QString &column)
return result;
}
-static QList<ProcessInfo> getLocalProcessesUsingPs()
+static QList<ProcessInfo> getLocalProcessesUsingPs(const FilePath &deviceRoot)
{
QList<ProcessInfo> processes;
// cmdLines are full command lines, usually with absolute path,
// exeNames only the file part of the executable's path.
- const QMap<qint64, QString> exeNames = getLocalProcessDataUsingPs("comm");
- const QMap<qint64, QString> cmdLines = getLocalProcessDataUsingPs("args");
+ const QMap<qint64, QString> exeNames = getLocalProcessDataUsingPs(deviceRoot, "comm");
+ const QMap<qint64, QString> cmdLines = getLocalProcessDataUsingPs(deviceRoot, "args");
for (auto it = exeNames.begin(), end = exeNames.end(); it != end; ++it) {
const qint64 pid = it.key();
@@ -146,16 +127,68 @@ static QList<ProcessInfo> getLocalProcessesUsingPs()
return processes;
}
-QList<ProcessInfo> ProcessInfo::processInfoList()
+static QList<ProcessInfo> getProcessesUsingPidin(const FilePath &pidin)
+{
+ Process process;
+ process.setCommand({pidin, {"-F", "%a %A {/%n}"}});
+ process.runBlocking();
+
+ QList<ProcessInfo> processes;
+ QStringList lines = process.readAllStandardOutput().split(QLatin1Char('\n'));
+ if (lines.isEmpty())
+ return processes;
+
+ lines.pop_front(); // drop headers
+ const QRegularExpression re("\\s*(\\d+)\\s+(.*){(.*)}");
+
+ for (const QString &line : std::as_const(lines)) {
+ const QRegularExpressionMatch match = re.match(line);
+ if (match.hasMatch()) {
+ const QStringList captures = match.capturedTexts();
+ if (captures.size() == 4) {
+ const int pid = captures[1].toInt();
+ const QString args = captures[2];
+ const QString exe = captures[3];
+ ProcessInfo deviceProcess;
+ deviceProcess.processId = pid;
+ deviceProcess.executable = exe.trimmed();
+ deviceProcess.commandLine = args.trimmed();
+ processes.append(deviceProcess);
+ }
+ }
+ }
+
+ return Utils::sorted(std::move(processes));
+}
+
+static QList<ProcessInfo> processInfoListUnix(const FilePath &deviceRoot)
{
- const QDir procDir = QDir(QLatin1String(procDirC));
- return procDir.exists() ? getLocalProcessesUsingProc() : getLocalProcessesUsingPs();
+ const FilePath procDir = deviceRoot.withNewPath("/proc");
+ const FilePath pidin = deviceRoot.withNewPath("pidin").searchInPath();
+
+ if (pidin.isExecutableFile())
+ return getProcessesUsingPidin(pidin);
+
+ if (procDir.isReadableDir())
+ return getLocalProcessesUsingProc(procDir);
+
+ return getLocalProcessesUsingPs(deviceRoot);
+}
+
+#if defined(Q_OS_UNIX)
+
+QList<ProcessInfo> ProcessInfo::processInfoList(const FilePath &deviceRoot)
+{
+ return processInfoListUnix(deviceRoot);
}
#elif defined(Q_OS_WIN)
-QList<ProcessInfo> ProcessInfo::processInfoList()
+QList<ProcessInfo> ProcessInfo::processInfoList(const FilePath &deviceRoot)
{
+ if (deviceRoot.needsDevice())
+ return processInfoListUnix(deviceRoot);
+
QList<ProcessInfo> processes;
PROCESSENTRY32 pe;