1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of Qt Creator.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file. Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights. These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
40 ****************************************************************************/
42 #include "maemoremoteprocesslist.h"
44 #include "maemodeviceconfigurations.h"
46 #include <utils/ssh/sshremoteprocessrunner.h>
48 #include <QtCore/QStringList>
50 using namespace Utils;
52 namespace Qt4ProjectManager {
55 const QByteArray LineSeparator1("---");
56 const QByteArray LineSeparator2("QTCENDOFLINE---");
57 const QByteArray LineSeparator = LineSeparator1 + LineSeparator2;
58 } // anonymous namespace
60 MaemoRemoteProcessList::MaemoRemoteProcessList(const MaemoDeviceConfig::ConstPtr &devConfig,
62 : QAbstractTableModel(parent),
63 m_process(SshRemoteProcessRunner::create(devConfig->sshParameters())),
65 m_devConfig(devConfig)
69 MaemoRemoteProcessList::~MaemoRemoteProcessList() {}
71 void MaemoRemoteProcessList::update()
73 if (m_state != Inactive) {
74 qDebug("%s: Did not expect state to be %d.", Q_FUNC_INFO, m_state);
78 m_remoteProcs.clear();
81 // The ps command on Fremantle ignores all command line options, so
82 // we have to collect the information in /proc manually.
83 if (m_devConfig->osVersion() == MaemoGlobal::Maemo5) {
84 command = "sep1=" + LineSeparator1 + '\n'
85 + "sep2=" + LineSeparator2 + '\n'
86 + "pidlist=`ls /proc |grep -E '^[[:digit:]]+$' |sort -n`; "
87 + "for pid in $pidlist\n"
89 + " echo -n \"$pid \"\n"
90 + " tr '\\0' ' ' < /proc/$pid/cmdline\n"
91 + " echo -n \"$sep1$sep2\"\n"
95 command = "ps -eo pid,args";
98 startProcess(command, Listing);
101 void MaemoRemoteProcessList::killProcess(int row)
103 Q_ASSERT(row >= 0 && row < m_remoteProcs.count());
104 const QByteArray command
105 = "kill -9 " + QByteArray::number(m_remoteProcs.at(row).pid);
106 startProcess(command, Killing);
109 void MaemoRemoteProcessList::startProcess(const QByteArray &cmdLine,
112 if (m_state != Inactive) {
113 qDebug("%s: Did not expect state to be %d.", Q_FUNC_INFO, m_state);
117 connect(m_process.data(), SIGNAL(connectionError(Utils::SshError)),
118 SLOT(handleConnectionError()));
119 connect(m_process.data(), SIGNAL(processOutputAvailable(QByteArray)),
120 SLOT(handleRemoteStdOut(QByteArray)));
121 connect(m_process.data(),
122 SIGNAL(processErrorOutputAvailable(QByteArray)),
123 SLOT(handleRemoteStdErr(QByteArray)));
124 connect(m_process.data(), SIGNAL(processClosed(int)),
125 SLOT(handleRemoteProcessFinished(int)));
126 m_remoteStdout.clear();
127 m_remoteStderr.clear();
129 m_process->run(cmdLine);
132 void MaemoRemoteProcessList::handleConnectionError()
134 if (m_state == Inactive)
137 emit error(tr("Connection failure: %1")
138 .arg(m_process->connection()->errorString()));
142 void MaemoRemoteProcessList::handleRemoteStdOut(const QByteArray &output)
144 if (m_state == Listing)
145 m_remoteStdout += output;
148 void MaemoRemoteProcessList::handleRemoteStdErr(const QByteArray &output)
150 if (m_state != Inactive)
151 m_remoteStderr += output;
154 void MaemoRemoteProcessList::handleRemoteProcessFinished(int exitStatus)
156 if (m_state == Inactive)
159 switch (exitStatus) {
160 case SshRemoteProcess::FailedToStart:
161 m_errorMsg = tr("Error: Remote process failed to start: %1")
162 .arg(m_process->process()->errorString());
164 case SshRemoteProcess::KilledBySignal:
165 m_errorMsg = tr("Error: Remote process crashed: %1")
166 .arg(m_process->process()->errorString());
168 case SshRemoteProcess::ExitedNormally:
169 if (m_process->process()->exitCode() == 0) {
170 if (m_state == Listing)
173 m_errorMsg = tr("Remote process failed.");
177 Q_ASSERT_X(false, Q_FUNC_INFO, "Invalid exit status");
180 if (!m_errorMsg.isEmpty()) {
181 if (!m_remoteStderr.isEmpty()) {
182 m_errorMsg += tr("\nRemote stderr was: %1")
183 .arg(QString::fromUtf8(m_remoteStderr));
185 emit error(m_errorMsg);
190 void MaemoRemoteProcessList::stop()
192 if (m_state == Inactive)
195 disconnect(m_process.data(), 0, this, 0);
196 if (m_state == Listing)
198 else if (m_errorMsg.isEmpty())
199 emit processKilled();
203 void MaemoRemoteProcessList::buildProcessList()
205 const bool isFremantle = m_devConfig->osVersion() == MaemoGlobal::Maemo5;
206 const QString remoteOutput = QString::fromUtf8(m_remoteStdout);
207 const QByteArray lineSeparator = isFremantle ? LineSeparator : "\n";
208 QStringList lines = remoteOutput.split(QString::fromUtf8(lineSeparator));
210 lines.removeFirst(); // column headers
211 foreach (const QString &line, lines) {
212 const QString &trimmedLine = line.trimmed();
213 const int pidEndPos = trimmedLine.indexOf(' ');
217 const int pid = trimmedLine.left(pidEndPos).toInt(&isNumber);
219 qDebug("%s: Non-integer value where pid was expected. Line was: '%s'",
220 Q_FUNC_INFO, qPrintable(trimmedLine));
223 m_remoteProcs << RemoteProc(pid, trimmedLine.mid(pidEndPos));
227 int MaemoRemoteProcessList::rowCount(const QModelIndex &parent) const
229 return parent.isValid() ? 0 : m_remoteProcs.count();
232 int MaemoRemoteProcessList::columnCount(const QModelIndex &parent) const
238 QVariant MaemoRemoteProcessList::headerData(int section,
239 Qt::Orientation orientation, int role) const
241 if (orientation != Qt::Horizontal || role != Qt::DisplayRole
242 || section < 0 || section >= columnCount())
247 return tr("Command Line");
250 QVariant MaemoRemoteProcessList::data(const QModelIndex &index, int role) const
252 if (!index.isValid() || index.row() >= rowCount(index.parent())
253 || index.column() >= columnCount() || role != Qt::DisplayRole)
255 const RemoteProc &proc = m_remoteProcs.at(index.row());
256 if (index.column() == 0)
262 } // namespace Internal
263 } // namespace Qt4ProjectManager