KCoreAddons

kprocesslist_unix.cpp
1 /*
2  This file is part of the KDE Frameworks
3 
4  SPDX-FileCopyrightText: 2011 Nokia Corporation and/or its subsidiary(-ies).
5  SPDX-FileCopyrightText: 2019 David Hallas <[email protected]>
6 
7  SPDX-License-Identifier: LGPL-2.1-only WITH Qt-LGPL-exception-1.1 OR LicenseRef-Qt-Commercial
8 */
9 
10 #include "kprocesslist.h"
11 
12 #include <QProcess>
13 #include <QDir>
14 
15 using namespace KProcessList;
16 
17 namespace {
18 
19 bool isUnixProcessId(const QString &procname)
20 {
21  for (int i = 0; i != procname.size(); ++i) {
22  if (!procname.at(i).isDigit())
23  return false;
24  }
25  return true;
26 }
27 
28 // Determine UNIX processes by running ps
29 KProcessInfoList unixProcessListPS()
30 {
32  QProcess psProcess;
33  const QStringList args {
34  QStringLiteral("-e"),
35  QStringLiteral("-o"),
36 #ifdef Q_OS_MAC
37  // command goes last, otherwise it is cut off
38  QStringLiteral("pid state user comm command"),
39 #else
40  QStringLiteral("pid,state,user,comm,cmd"),
41 #endif
42  };
43  psProcess.start(QStringLiteral("ps"), args);
44  if (!psProcess.waitForStarted())
45  return rc;
46  psProcess.waitForFinished();
47  QByteArray output = psProcess.readAllStandardOutput();
48  // Split "457 S+ /Users/foo.app"
49  const QStringList lines = QString::fromLocal8Bit(output).split(QLatin1Char('\n'));
50  const int lineCount = lines.size();
51  const QChar blank = QLatin1Char(' ');
52  for (int l = 1; l < lineCount; l++) { // Skip header
53  const QString line = lines.at(l).simplified();
54  // we can't just split on blank as the process name might
55  // contain them
56  const int endOfPid = line.indexOf(blank);
57  const int endOfState = line.indexOf(blank, endOfPid+1);
58  const int endOfUser = line.indexOf(blank, endOfState+1);
59  const int endOfName = line.indexOf(blank, endOfUser+1);
60 
61  if (endOfPid >= 0 && endOfState >= 0 && endOfUser >= 0) {
62  qint64 pid = line.leftRef(endOfPid).toUInt();
63  QString user = line.mid(endOfState+1, endOfUser-endOfState-1);
64  QString name = line.mid(endOfUser+1, endOfName-endOfUser-1);
65  QString command = line.right(line.size()-endOfName-1);
66  rc.push_back(KProcessInfo(pid, command, name, user));
67  }
68  }
69 
70  return rc;
71 }
72 
73 bool getProcessInfo(const QString& procId, KProcessInfo& processInfo)
74 {
75  if (!isUnixProcessId(procId))
76  return false;
77 #ifdef Q_OS_FREEBSD
78  QString statusFileName(QStringLiteral("/status"));
79 #else
80  QString statusFileName(QStringLiteral("/stat"));
81 #endif
82  QString filename = QStringLiteral("/proc/");
83  filename += procId;
84  filename += statusFileName;
85  QFile file(filename);
86  if (!file.open(QIODevice::ReadOnly))
87  return false; // process may have exited
88 
89  const QStringList data = QString::fromLocal8Bit(file.readAll()).split(QLatin1Char(' '));
90  qint64 pid = procId.toUInt();
91  QString name = data.at(1);
92  if (name.startsWith(QLatin1Char('(')) && name.endsWith(QLatin1Char(')'))) {
93  name.chop(1);
94  name.remove(0, 1);
95  }
96  // State is element 2
97  // PPID is element 3
98  QString user = QFileInfo(file).owner();
99  file.close();
100 
101  QString command = name;
102 
103  QFile cmdFile(QLatin1String("/proc/") + procId + QLatin1String("/cmdline"));
104  if (cmdFile.open(QFile::ReadOnly)) {
105  QByteArray cmd = cmdFile.readAll();
106 
107  if (!cmd.isEmpty()) {
108  // extract non-truncated name from cmdline
109  int zeroIndex = cmd.indexOf('\0');
110  int processNameStart = cmd.lastIndexOf('/', zeroIndex);
111  if (processNameStart == -1) {
112  processNameStart = 0;
113  } else {
114  processNameStart++;
115  }
116  name = QString::fromLocal8Bit(cmd.mid(processNameStart, zeroIndex - processNameStart));
117 
118  cmd.replace('\0', ' ');
119  command = QString::fromLocal8Bit(cmd).trimmed();
120  }
121  }
122  cmdFile.close();
123  processInfo = KProcessInfo(pid, command, name, user);
124  return true;
125 }
126 
127 } // unnamed namespace
128 
129 // Determine UNIX processes by reading "/proc". Default to ps if
130 // it does not exist
131 KProcessInfoList KProcessList::processInfoList()
132 {
133  const QDir procDir(QStringLiteral("/proc/"));
134  if (!procDir.exists())
135  return unixProcessListPS();
136  KProcessInfoList rc;
137  const QStringList procIds = procDir.entryList();
138  for (const QString &procId : procIds) {
139  KProcessInfo processInfo;
140  if (getProcessInfo(procId, processInfo)) {
141  rc.push_back(processInfo);
142  }
143  }
144  return rc;
145 }
146 
147 KProcessInfo KProcessList::processInfo(qint64 pid)
148 {
149  KProcessInfo processInfo;
150  getProcessInfo(QString::number(pid), processInfo);
151  return processInfo;
152 }
int indexOf(QChar ch, int from, Qt::CaseSensitivity cs) const const
Contains information about a process.
Definition: kprocesslist.h:28
void push_back(const T &value)
int lastIndexOf(char ch, int from) const const
QStringList split(const QString &sep, QString::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
bool isDigit() const const
const T & at(int i) const const
int size() const const
bool isEmpty() const const
QString & remove(int position, int n)
void chop(int n)
int size() const const
QString name(StandardShortcut id)
int indexOf(char ch, int from) const const
QString number(int n, int base)
QString fromLocal8Bit(const char *str, int size)
QStringRef leftRef(int n) const const
QString trimmed() const const
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const const
QByteArray & replace(int pos, int len, const char *after)
bool endsWith(const QString &s, Qt::CaseSensitivity cs) const const
QByteArray mid(int pos, int len) const const
QString right(int n) const const
bool waitForStarted(int msecs)
QString owner() const const
uint toUInt(bool *ok, int base) const const
QString mid(int position, int n) const const
const QChar at(int position) const const
QByteArray readAllStandardOutput()
void start(const QString &program, const QStringList &arguments, QIODevice::OpenMode mode)
uint toUInt(bool *ok, int base) const const
bool waitForFinished(int msecs)
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Sun May 31 2020 23:11:13 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.