d/control: Recommend gdb
[gammaray-debian.git] / launcher / processlist_unix.cpp
blobcb2dabdcbc6f8663a05a421c3e7dd7775cf18156
1 /**************************************************************************
2 **
3 ** This code is part of Qt Creator
4 **
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
6 **
7 ** Contact: Nokia Corporation (info@qt.nokia.com)
8 **
9 **
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.
23 ** Other Usage
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"
35 #include <QProcess>
36 #include <QDir>
38 #include <algorithm>
39 #include <functional>
41 static bool isUnixProcessId(const QString &procname)
43 for (int i = 0; i != procname.size(); ++i) {
44 if (!procname.at(i).isDigit()) {
45 return false;
48 return true;
51 static bool processIsQtApp(const QString &pid)
53 QProcess lsofProcess;
54 QStringList args;
55 args << QLatin1String("-Fn") << QLatin1String("-n") << QLatin1String("-p") << pid;
56 lsofProcess.start(QLatin1String("lsof"), args);
57 if (!lsofProcess.waitForStarted()) {
58 return false;
61 lsofProcess.waitForFinished();
62 const QByteArray output = lsofProcess.readAllStandardOutput();
64 if (output.contains("QtCore")) {
65 return true;
68 return false;
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;
83 const QString m_ppid;
84 const QString m_name;
87 // Determine UNIX processes by running ps
88 static ProcDataList unixProcessListPS(const ProcDataList &previous)
90 #ifdef Q_OS_MAC
91 // command goes last, otherwise it is cut off
92 static const char formatC[] = "pid state user command";
93 #else
94 static const char formatC[] = "pid,state,user,cmd";
95 #endif
96 ProcDataList rc;
97 QProcess psProcess;
98 QStringList args;
99 args << QLatin1String("-e") << QLatin1String("-o") << QLatin1String(formatC);
100 psProcess.start(QLatin1String("ps"), args);
101 if (!psProcess.waitForStarted()) {
102 return rc;
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
113 // contain them
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) {
118 ProcData procData;
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;
128 } else {
129 procData.type = processIsQtApp(procData.ppid) ?
130 ProcData::QtApp :
131 ProcData::NoQtApp;
133 rc.push_back(procData);
137 return rc;
140 // Determine UNIX processes by reading "/proc". Default to ps if
141 // it does not exist
142 ProcDataList processList(const ProcDataList &previous)
144 const QDir procDir(QLatin1String("/proc/"));
145 if (!procDir.exists()) {
146 return unixProcessListPS(previous);
148 ProcDataList rc;
149 const QStringList procIds = procDir.entryList();
150 if (procIds.isEmpty()) {
151 return rc;
153 foreach (const QString &procId, procIds) {
154 if (!isUnixProcessId(procId)) {
155 continue;
157 QString filename = QLatin1String("/proc/");
158 filename += procId;
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(' ');
166 ProcData proc;
167 proc.ppid = procId;
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);
174 // PPID is element 3
176 proc.user = QFileInfo(file).owner();
177 file.close();
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);
187 cmdFile.close();
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;
195 forever {
196 const QByteArray line = maps.readLine();
197 if (line.isEmpty()) {
198 break;
200 if (line.contains(QByteArray("/libQtCore.so"))) {
201 proc.type = ProcData::QtApp;
202 break;
206 rc.push_back(proc);
208 return rc;