Changeset View
Changeset View
Standalone View
Standalone View
src/lib/util/kprocesslist_unix.cpp
- This file was added.
1 | /************************************************************************** | ||||
---|---|---|---|---|---|
2 | ** | ||||
3 | ** This file is part of the KDE Frameworks | ||||
4 | ** | ||||
5 | ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). | ||||
6 | ** Copyright (c) 2019 David Hallas <david@davidhallas.dk> | ||||
7 | ** | ||||
8 | ** GNU Lesser General Public License Usage | ||||
9 | ** | ||||
10 | ** This file may be used under the terms of the GNU Lesser General Public | ||||
11 | ** License version 2.1 as published by the Free Software Foundation and | ||||
12 | ** appearing in the file LICENSE.LGPL included in the packaging of this file. | ||||
13 | ** Please review the following information to ensure the GNU Lesser General | ||||
14 | ** Public License version 2.1 requirements will be met: | ||||
15 | ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. | ||||
16 | ** | ||||
17 | ** In addition, as a special exception, Nokia gives you certain additional | ||||
18 | ** rights. These rights are described in the Nokia Qt LGPL Exception | ||||
19 | ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. | ||||
20 | ** | ||||
21 | ** Other Usage | ||||
22 | ** | ||||
23 | ** Alternatively, this file may be used in accordance with the terms and | ||||
24 | ** conditions contained in a signed written agreement between you and Nokia. | ||||
25 | ** | ||||
26 | ** If you have questions regarding the use of this file, please contact | ||||
27 | ** Nokia at info@qt.nokia.com. | ||||
28 | ** | ||||
29 | **************************************************************************/ | ||||
30 | | ||||
31 | #include "kprocesslist.h" | ||||
32 | | ||||
33 | #include <QProcess> | ||||
34 | #include <QDir> | ||||
35 | | ||||
36 | using namespace KProcessList; | ||||
37 | | ||||
38 | namespace { | ||||
39 | | ||||
40 | bool isUnixProcessId(const QString &procname) | ||||
41 | { | ||||
42 | for (int i = 0; i != procname.size(); ++i) { | ||||
43 | if (!procname.at(i).isDigit()) | ||||
44 | return false; | ||||
45 | } | ||||
46 | return true; | ||||
47 | } | ||||
48 | | ||||
49 | // Determine UNIX processes by running ps | ||||
50 | KProcessInfoList unixProcessListPS() | ||||
51 | { | ||||
52 | #ifdef Q_OS_MAC | ||||
53 | // command goes last, otherwise it is cut off | ||||
54 | static const char formatC[] = "pid state user command"; | ||||
55 | #else | ||||
56 | static const char formatC[] = "pid,state,user,cmd"; | ||||
57 | #endif | ||||
58 | KProcessInfoList rc; | ||||
59 | QProcess psProcess; | ||||
60 | QStringList args; | ||||
61 | args << QStringLiteral("-e") << QStringLiteral("-o") << QLatin1String(formatC); | ||||
62 | psProcess.start(QStringLiteral("ps"), args); | ||||
63 | if (!psProcess.waitForStarted()) | ||||
64 | return rc; | ||||
65 | psProcess.waitForFinished(); | ||||
66 | QByteArray output = psProcess.readAllStandardOutput(); | ||||
67 | // Split "457 S+ /Users/foo.app" | ||||
68 | const QStringList lines = QString::fromLocal8Bit(output).split(QLatin1Char('\n')); | ||||
69 | const int lineCount = lines.size(); | ||||
70 | const QChar blank = QLatin1Char(' '); | ||||
71 | for (int l = 1; l < lineCount; l++) { // Skip header | ||||
72 | const QString line = lines.at(l).simplified(); | ||||
73 | // we can't just split on blank as the process name might | ||||
74 | // contain them | ||||
75 | const int endOfPid = line.indexOf(blank); | ||||
76 | const int endOfState = line.indexOf(blank, endOfPid+1); | ||||
77 | const int endOfUser = line.indexOf(blank, endOfState+1); | ||||
78 | if (endOfPid >= 0 && endOfState >= 0 && endOfUser >= 0) { | ||||
79 | qint64 pid = line.left(endOfPid).toUInt(); | ||||
80 | QString user = line.mid(endOfState+1, endOfUser-endOfState-1); | ||||
81 | QString name = line.right(line.size()-endOfUser-1); | ||||
82 | rc.push_back(KProcessInfo(pid, name, user)); | ||||
83 | } | ||||
84 | } | ||||
85 | | ||||
86 | return rc; | ||||
87 | } | ||||
88 | | ||||
89 | } // unnamed namespace | ||||
90 | | ||||
91 | // Determine UNIX processes by reading "/proc". Default to ps if | ||||
92 | // it does not exist | ||||
93 | KProcessInfoList KProcessList::processInfoList() | ||||
94 | { | ||||
95 | const QDir procDir(QStringLiteral("/proc/")); | ||||
96 | #ifdef Q_OS_FREEBSD | ||||
97 | QString statusFileName(QStringLiteral("/status")); | ||||
98 | #else | ||||
99 | QString statusFileName(QStringLiteral("/stat")); | ||||
100 | #endif | ||||
101 | if (!procDir.exists()) | ||||
102 | return unixProcessListPS(); | ||||
103 | KProcessInfoList rc; | ||||
104 | const QStringList procIds = procDir.entryList(); | ||||
105 | if (procIds.isEmpty()) | ||||
106 | return rc; | ||||
107 | for (const QString &procId : procIds) { | ||||
108 | if (!isUnixProcessId(procId)) | ||||
109 | continue; | ||||
110 | QString filename = QStringLiteral("/proc/"); | ||||
111 | filename += procId; | ||||
112 | filename += statusFileName; | ||||
113 | QFile file(filename); | ||||
114 | if (!file.open(QIODevice::ReadOnly)) | ||||
115 | continue; // process may have exited | ||||
116 | | ||||
117 | const QStringList data = QString::fromLocal8Bit(file.readAll()).split(QLatin1Char(' ')); | ||||
118 | qint64 pid = procId.toUInt(); | ||||
119 | QString name = data.at(1); | ||||
120 | if (name.startsWith(QLatin1Char('(')) && name.endsWith(QLatin1Char(')'))) { | ||||
121 | name.truncate(name.size() - 1); | ||||
122 | name.remove(0, 1); | ||||
123 | } | ||||
124 | // State is element 2 | ||||
125 | // PPID is element 3 | ||||
126 | QString user = QFileInfo(file).owner(); | ||||
127 | file.close(); | ||||
128 | | ||||
129 | QFile cmdFile(QLatin1String("/proc/") + procId + QLatin1String("/cmdline")); | ||||
130 | if (cmdFile.open(QFile::ReadOnly)) { | ||||
131 | QByteArray cmd = cmdFile.readAll(); | ||||
132 | cmd.replace('\0', ' '); | ||||
133 | if (!cmd.isEmpty()) | ||||
134 | name = QString::fromLocal8Bit(cmd).trimmed(); | ||||
135 | } | ||||
136 | cmdFile.close(); | ||||
137 | rc.push_back(KProcessInfo(pid, name, user)); | ||||
138 | } | ||||
139 | return rc; | ||||
140 | } |