1 /**************************************************************************
3 ** This code is part of Qt Creator
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
7 ** Contact: Nokia Corporation (info@qt.nokia.com)
10 ** GNU Lesser General Public License Usage
12 ** This file may be used under the terms of the GNU Lesser General Public
13 ** License version 2.1 as published by the Free Software Foundation and
14 ** appearing in the file LICENSE.LGPL included in the packaging of this file.
15 ** Please review the following information to ensure the GNU Lesser General
16 ** Public License version 2.1 requirements will be met:
17 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
19 ** In addition, as a special exception, Nokia gives you certain additional
20 ** rights. These rights are described in the Nokia Qt LGPL Exception
21 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
25 ** Alternatively, this file may be used in accordance with the terms and
26 ** conditions contained in a signed written agreement between you and Nokia.
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at info@qt.nokia.com.
31 **************************************************************************/
33 #include "processlist.h"
41 static bool isUnixProcessId(const QString
&procname
)
43 for (int i
= 0; i
!= procname
.size(); ++i
) {
44 if (!procname
.at(i
).isDigit()) {
51 static bool processIsQtApp(const QString
&pid
)
55 args
<< QLatin1String("-Fn") << QLatin1String("-n") << QLatin1String("-p") << pid
;
56 lsofProcess
.start(QLatin1String("lsof"), args
);
57 if (!lsofProcess
.waitForStarted()) {
61 lsofProcess
.waitForFinished();
62 const QByteArray output
= lsofProcess
.readAllStandardOutput();
64 if (output
.contains("QtCore")) {
71 struct PidAndNameMatch
: public std::unary_function
<ProcData
,bool> {
73 explicit PidAndNameMatch(const QString
&ppid
, const QString
&name
)
74 : m_ppid(ppid
), m_name(name
)
78 bool operator()(const ProcData
&p
) const
80 return p
.ppid
== m_ppid
&& m_name
== p
.name
;
87 // Determine UNIX processes by running ps
88 static ProcDataList
unixProcessListPS(const ProcDataList
&previous
)
91 // command goes last, otherwise it is cut off
92 static const char formatC
[] = "pid state user command";
94 static const char formatC
[] = "pid,state,user,cmd";
99 args
<< QLatin1String("-e") << QLatin1String("-o") << QLatin1String(formatC
);
100 psProcess
.start(QLatin1String("ps"), args
);
101 if (!psProcess
.waitForStarted()) {
104 psProcess
.waitForFinished();
105 QByteArray output
= psProcess
.readAllStandardOutput();
106 // Split "457 S+ /Users/foo.app"
107 const QStringList lines
= QString::fromLocal8Bit(output
).split(QLatin1Char('\n'));
108 const int lineCount
= lines
.size();
109 const QChar blank
= QLatin1Char(' ');
110 for (int l
= 1; l
< lineCount
; l
++) { // Skip header
111 const QString line
= lines
.at(l
).simplified();
112 // we can't just split on blank as the process name might
114 const int endOfPid
= line
.indexOf(blank
);
115 const int endOfState
= line
.indexOf(blank
, endOfPid
+1);
116 const int endOfUser
= line
.indexOf(blank
, endOfState
+1);
117 if (endOfPid
>= 0 && endOfState
>= 0 && endOfUser
>= 0) {
119 procData
.ppid
= line
.left(endOfPid
);
120 procData
.state
= line
.mid(endOfPid
+1, endOfState
-endOfPid
-1);
121 procData
.user
= line
.mid(endOfState
+1, endOfUser
-endOfState
-1);
122 procData
.name
= line
.right(line
.size()-endOfUser
-1);
123 ProcDataList::ConstIterator it
=
124 std::find_if(previous
.constBegin(), previous
.constEnd(),
125 PidAndNameMatch(procData
.ppid
, procData
.name
));
126 if (it
!= previous
.constEnd()) {
127 procData
.type
= it
->type
;
129 procData
.type
= processIsQtApp(procData
.ppid
) ?
133 rc
.push_back(procData
);
140 // Determine UNIX processes by reading "/proc". Default to ps if
142 ProcDataList
processList(const ProcDataList
&previous
)
144 const QDir
procDir(QLatin1String("/proc/"));
145 if (!procDir
.exists()) {
146 return unixProcessListPS(previous
);
149 const QStringList procIds
= procDir
.entryList();
150 if (procIds
.isEmpty()) {
153 foreach (const QString
&procId
, procIds
) {
154 if (!isUnixProcessId(procId
)) {
157 QString filename
= QLatin1String("/proc/");
159 filename
+= QLatin1String("/stat");
160 QFile
file(filename
);
161 if (!file
.open(QIODevice::ReadOnly
)) {
162 continue; // process may have exited
165 const QStringList data
= QString::fromLocal8Bit(file
.readAll()).split(' ');
168 proc
.name
= data
.at(1);
169 if (proc
.name
.startsWith(QLatin1Char('(')) && proc
.name
.endsWith(QLatin1Char(')'))) {
170 proc
.name
.truncate(proc
.name
.size() - 1);
171 proc
.name
.remove(0, 1);
173 proc
.state
= data
.at(2);
176 proc
.user
= QFileInfo(file
).owner();
179 QFile
cmdFile(QLatin1String("/proc/") + procId
+ QLatin1String("/cmdline"));
180 if(cmdFile
.open(QFile::ReadOnly
)) {
181 QByteArray cmd
= cmdFile
.readAll();
182 cmd
.replace('\0', ' ');
183 if (!cmd
.isEmpty()) {
184 proc
.name
= QString::fromLocal8Bit(cmd
);
189 QFile
maps(QLatin1String("/proc/") + procId
+ QLatin1String("/maps"));
190 if (!maps
.open(QIODevice::ReadOnly
)) {
191 continue; // process may have exited
194 proc
.type
= ProcData::NoQtApp
;
196 const QByteArray line
= maps
.readLine();
197 if (line
.isEmpty()) {
200 if (line
.contains(QByteArray("/libQtCore.so"))) {
201 proc
.type
= ProcData::QtApp
;