diff options
Diffstat (limited to 'src/libs/utils/processinfo.cpp')
-rw-r--r-- | src/libs/utils/processinfo.cpp | 179 |
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; |