Commit 1219b72b authored by Gustavo Carneiro's avatar Gustavo Carneiro

Move Process Info Classes to a new files.

parent 51a345bf
......@@ -99,6 +99,9 @@ set(konsoleprivate_SRCS ${sessionadaptors_SRCS}
KeyboardTranslatorWriter.cpp
KeyboardTranslatorManager.cpp
ProcessInfo.cpp
NullProcessInfo.cpp
UnixProcessInfo.cpp
SSHProcessInfo.cpp
Profile.cpp
ProfileList.cpp
ProfileReader.cpp
......
/*
Copyright 2007-2008 by Robert Knight <robertknight@gmail.countm>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA.
*/
#include "NullProcessInfo.h"
using namespace Konsole;
NullProcessInfo::NullProcessInfo(int pid)
: ProcessInfo(pid)
{
}
void NullProcessInfo::readProcessInfo(int /*pid*/)
{
}
bool NullProcessInfo::readCurrentDir(int /*pid*/)
{
return false;
}
void NullProcessInfo::readUserName()
{
}
/*
Copyright 2007-2008 by Robert Knight <robertknight@gmail.countm>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA.
*/
#ifndef NULLPROCESSINFO_H
#define NULLPROCESSINFO_H
#include "ProcessInfo.h"
namespace Konsole
{
/**
* Implementation of ProcessInfo which does nothing.
* Used on platforms where a suitable ProcessInfo subclass is not
* available.
*
* isValid() will always return false for instances of NullProcessInfo
*/
class NullProcessInfo : public ProcessInfo
{
public:
/**
* Constructs a new NullProcessInfo instance.
* See ProcessInfo::newInstance()
*/
explicit NullProcessInfo(int pid);
protected:
void readProcessInfo(int pid) override;
bool readCurrentDir(int pid) override;
void readUserName(void) override;
};
}
#endif
......@@ -22,6 +22,11 @@
// Own
#include "ProcessInfo.h"
#include "NullProcessInfo.h"
#if !defined(Q_OS_WIN)
#include "UnixProcessInfo.h"
#endif
#include "SSHProcessInfo.h"
// Unix
#include <sys/socket.h>
......@@ -335,95 +340,6 @@ void ProcessInfo::setFileError(QFile::FileError error)
}
}
//
// ProcessInfo::newInstance() is way at the bottom so it can see all of the
// implementations of the UnixProcessInfo abstract class.
//
NullProcessInfo::NullProcessInfo(int pid) :
ProcessInfo(pid)
{
}
void NullProcessInfo::readProcessInfo(int /*pid*/)
{
}
bool NullProcessInfo::readCurrentDir(int /*pid*/)
{
return false;
}
void NullProcessInfo::readUserName()
{
}
#if !defined(Q_OS_WIN)
UnixProcessInfo::UnixProcessInfo(int pid) :
ProcessInfo(pid)
{
setUserNameRequired(true);
}
void UnixProcessInfo::readProcessInfo(int pid)
{
// prevent _arguments from growing longer and longer each time this
// method is called.
clearArguments();
if (readProcInfo(pid)) {
readArguments(pid);
readCurrentDir(pid);
bool ok = false;
const QString &processNameString = name(&ok);
if (ok && processNameString == QLatin1String("sudo")) {
//Append process name along with sudo
const QVector<QString> &args = arguments(&ok);
if (ok && args.size() > 1) {
setName(processNameString + QStringLiteral(" ") + args[1]);
}
}
}
}
void UnixProcessInfo::readUserName()
{
bool ok = false;
const int uid = userId(&ok);
if (!ok) {
return;
}
struct passwd passwdStruct;
struct passwd *getpwResult;
char *getpwBuffer;
long getpwBufferSize;
int getpwStatus;
getpwBufferSize = sysconf(_SC_GETPW_R_SIZE_MAX);
if (getpwBufferSize == -1) {
getpwBufferSize = 16384;
}
getpwBuffer = new char[getpwBufferSize];
if (getpwBuffer == nullptr) {
return;
}
getpwStatus = getpwuid_r(uid, &passwdStruct, getpwBuffer, getpwBufferSize, &getpwResult);
if ((getpwStatus == 0) && (getpwResult != nullptr)) {
setUserName(QLatin1String(passwdStruct.pw_name));
} else {
setUserName(QString());
qWarning() << "getpwuid_r returned error : " << getpwStatus;
}
delete [] getpwBuffer;
}
#endif
#if defined(Q_OS_LINUX)
class LinuxProcessInfo : public UnixProcessInfo
{
......@@ -1010,180 +926,6 @@ private:
};
#endif
SSHProcessInfo::SSHProcessInfo(const ProcessInfo &process) :
_process(process),
_user(QString()),
_host(QString()),
_port(QString()),
_command(QString())
{
bool ok = false;
// check that this is a SSH process
const QString &name = _process.name(&ok);
if (!ok || name != QLatin1String("ssh")) {
if (!ok) {
qWarning() << "Could not read process info";
} else {
qWarning() << "Process is not a SSH process";
}
return;
}
// read arguments
const QVector<QString> &args = _process.arguments(&ok);
// SSH options
// these are taken from the SSH manual ( accessed via 'man ssh' )
// options which take no arguments
static const QString noArgumentOptions(QStringLiteral("1246AaCfgKkMNnqsTtVvXxYy"));
// options which take one argument
static const QString singleArgumentOptions(QStringLiteral("bcDeFIiLlmOopRSWw"));
if (ok) {
// find the username, host and command arguments
//
// the username/host is assumed to be the first argument
// which is not an option
// ( ie. does not start with a dash '-' character )
// or an argument to a previous option.
//
// the command, if specified, is assumed to be the argument following
// the username and host
//
// note that we skip the argument at index 0 because that is the
// program name ( expected to be 'ssh' in this case )
for (int i = 1; i < args.count(); i++) {
// If this one is an option ...
// Most options together with its argument will be skipped.
if (args[i].startsWith(QLatin1Char('-'))) {
const QChar optionChar = (args[i].length() > 1) ? args[i][1] : QLatin1Char('\0');
// for example: -p2222 or -p 2222 ?
const bool optionArgumentCombined = args[i].length() > 2;
if (noArgumentOptions.contains(optionChar)) {
continue;
} else if (singleArgumentOptions.contains(optionChar)) {
QString argument;
if (optionArgumentCombined) {
argument = args[i].mid(2);
} else {
// Verify correct # arguments are given
if ((i + 1) < args.count()) {
argument = args[i + 1];
}
i++;
}
// support using `-l user` to specify username.
if (optionChar == QLatin1Char('l')) {
_user = argument;
}
// support using `-p port` to specify port.
else if (optionChar == QLatin1Char('p')) {
_port = argument;
}
continue;
}
}
// check whether the host has been found yet
// if not, this must be the username/host argument
if (_host.isEmpty()) {
// check to see if only a hostname is specified, or whether
// both a username and host are specified ( in which case they
// are separated by an '@' character: username@host )
const int separatorPosition = args[i].indexOf(QLatin1Char('@'));
if (separatorPosition != -1) {
// username and host specified
_user = args[i].left(separatorPosition);
_host = args[i].mid(separatorPosition + 1);
} else {
// just the host specified
_host = args[i];
}
} else {
// host has already been found, this must be part of the
// command arguments.
// Note this is not 100% correct. If any of the above
// noArgumentOptions or singleArgumentOptions are found, this
// will not be correct (example ssh server top -i 50)
// Suggest putting ssh command in quotes
if (_command.isEmpty()) {
_command = args[i];
} else {
_command = _command + QLatin1Char(' ') + args[i];
}
}
}
} else {
qWarning() << "Could not read arguments";
return;
}
}
QString SSHProcessInfo::userName() const
{
return _user;
}
QString SSHProcessInfo::host() const
{
return _host;
}
QString SSHProcessInfo::port() const
{
return _port;
}
QString SSHProcessInfo::command() const
{
return _command;
}
QString SSHProcessInfo::format(const QString &input) const
{
QString output(input);
// search for and replace known markers
output.replace(QLatin1String("%u"), _user);
// provide 'user@' if user is defined -- this makes nicer
// remote tabs possible: "%U%h %c" => User@Host Command
// => Host Command
// Depending on whether -l was passed to ssh (which is mostly not the
// case due to ~/.ssh/config).
if (_user.isEmpty()) {
output.remove(QLatin1String("%U"));
} else {
output.replace(QLatin1String("%U"), _user + QLatin1Char('@'));
}
// test whether host is an ip address
// in which case 'short host' and 'full host'
// markers in the input string are replaced with
// the full address
struct in_addr address;
const bool isIpAddress = inet_aton(_host.toLocal8Bit().constData(), &address) != 0;
if (isIpAddress) {
output.replace(QLatin1String("%h"), _host);
} else {
output.replace(QLatin1String("%h"), _host.left(_host.indexOf(QLatin1Char('.'))));
}
output.replace(QLatin1String("%H"), _host);
output.replace(QLatin1String("%c"), _command);
return output;
}
ProcessInfo *ProcessInfo::newInstance(int pid)
{
ProcessInfo *info;
......
......@@ -288,124 +288,6 @@ private:
};
Q_DECLARE_OPERATORS_FOR_FLAGS(ProcessInfo::Fields)
/**
* Implementation of ProcessInfo which does nothing.
* Used on platforms where a suitable ProcessInfo subclass is not
* available.
*
* isValid() will always return false for instances of NullProcessInfo
*/
class NullProcessInfo : public ProcessInfo
{
public:
/**
* Constructs a new NullProcessInfo instance.
* See ProcessInfo::newInstance()
*/
explicit NullProcessInfo(int pid);
protected:
void readProcessInfo(int pid) override;
bool readCurrentDir(int pid) override;
void readUserName(void) override;
};
#if !defined(Q_OS_WIN)
/**
* Implementation of ProcessInfo for Unix platforms which uses
* the /proc filesystem
*/
class UnixProcessInfo : public ProcessInfo
{
public:
/**
* Constructs a new instance of UnixProcessInfo.
* See ProcessInfo::newInstance()
*/
explicit UnixProcessInfo(int pid);
protected:
/**
* Implementation of ProcessInfo::readProcessInfo(); calls the
* four private methods below in turn.
*/
void readProcessInfo(int pid) override;
void readUserName(void) override;
private:
/**
* Read the standard process information -- PID, parent PID, foreground PID.
* @param pid process ID to use
* @return true on success
*/
virtual bool readProcInfo(int pid) = 0;
/**
* Determine what arguments were passed to the process. Sets _arguments.
* @param pid process ID to use
* @return true on success
*/
virtual bool readArguments(int pid) = 0;
};
#endif
/**
* Lightweight class which provides additional information about SSH processes.
*/
class SSHProcessInfo
{
public:
/**
* Constructs a new SSHProcessInfo instance which provides additional
* information about the specified SSH process.
*
* @param process A ProcessInfo instance for a SSH process.
*/
explicit SSHProcessInfo(const ProcessInfo &process);
/**
* Returns the user name which the user initially logged into on
* the remote computer.
*/
QString userName() const;
/**
* Returns the host which the user has connected to.
*/
QString host() const;
/**
* Returns the port on host which the user has connected to.
*/
QString port() const;
/**
* Returns the command which the user specified to execute on the
* remote computer when starting the SSH process.
*/
QString command() const;
/**
* Operates in the same way as ProcessInfo::format(), except
* that the set of markers understood is different:
*
* %u - Replaced with user name which the user initially logged
* into on the remote computer.
* %h - Replaced with the first part of the host name which
* is connected to.
* %H - Replaced with the full host name of the computer which
* is connected to.
* %c - Replaced with the command which the user specified
* to execute when starting the SSH process.
*/
QString format(const QString &input) const;
private:
const ProcessInfo &_process;
QString _user;
QString _host;
QString _port;
QString _command;
};
}
#endif //PROCESSINFO_H
/*
Copyright 2007-2008 by Robert Knight <robertknight@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA.
*/
// Own
#include "SSHProcessInfo.h"
// Unix
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <pwd.h>
#include <sys/param.h>
#include <cerrno>
// Qt
#include <QDebug>
using namespace Konsole;
SSHProcessInfo::SSHProcessInfo(const ProcessInfo &process) :
_process(process),
_user(QString()),
_host(QString()),
_port(QString()),
_command(QString())
{
bool ok = false;
// check that this is a SSH process
const QString &name = _process.name(&ok);
if (!ok || name != QLatin1String("ssh")) {
if (!ok) {
qWarning() << "Could not read process info";
} else {
qWarning() << "Process is not a SSH process";
}
return;
}
// read arguments
const QVector<QString> &args = _process.arguments(&ok);
// SSH options
// these are taken from the SSH manual ( accessed via 'man ssh' )
// options which take no arguments
static const QString noArgumentOptions(QStringLiteral("1246AaCfgKkMNnqsTtVvXxYy"));
// options which take one argument
static const QString singleArgumentOptions(QStringLiteral("bcDeFIiLlmOopRSWw"));
if (ok) {
// find the username, host and command arguments
//
// the username/host is assumed to be the first argument
// which is not an option
// ( ie. does not start with a dash '-' character )
// or an argument to a previous option.
//
// the command, if specified, is assumed to be the argument following
// the username and host
//
// note that we skip the argument at index 0 because that is the
// program name ( expected to be 'ssh' in this case )
for (int i = 1; i < args.count(); i++) {
// If this one is an option ...
// Most options together with its argument will be skipped.
if (args[i].startsWith(QLatin1Char('-'))) {
const QChar optionChar = (args[i].length() > 1) ? args[i][1] : QLatin1Char('\0');
// for example: -p2222 or -p 2222 ?
const bool optionArgumentCombined = args[i].length() > 2;
if (noArgumentOptions.contains(optionChar)) {
continue;
} else if (singleArgumentOptions.contains(optionChar)) {
QString argument;
if (optionArgumentCombined) {
argument = args[i].mid(2);
} else {
// Verify correct # arguments are given
if ((i + 1) < args.count()) {
argument = args[i + 1];
}
i++;
}
// support using `-l user` to specify username.
if (optionChar == QLatin1Char('l')) {
_user = argument;
}
// support using `-p port` to specify port.
else if (optionChar == QLatin1Char('p')) {
_port = argument;
}
continue;
}
}
// check whether the host has been found yet
// if not, this must be the username/host argument
if (_host.isEmpty()) {
// check to see if only a hostname is specified, or whether
// both a username and host are specified ( in which case they
// are separated by an '@' character: username@host )
const int separatorPosition = args[i].indexOf(QLatin1Char('@'));
if (separatorPosition != -1) {
// username and host specified
_user = args[i].left(separatorPosition);
_host = args[i].mid(separatorPosition + 1);
} else {
// just the host specified
_host = args[i];
}
} else {
// host has already been found, this must be part of the
// command arguments.
// Note this is not 100% correct. If any of the above
// noArgumentOptions or singleArgumentOptions are found, this
// will not be correct (example ssh server top -i 50)
// Suggest putting ssh command in quotes
if (_command.isEmpty()) {
_command = args[i];
} else {
_command = _command + QLatin1Char(' ') + args[i];
}
}
}
} else {
qWarning() << "Could not read arguments";
return;
}
}
QString SSHProcessInfo::userName() const
{
return _user;
}
QString SSHProcessInfo::host() const
{
return _host;
}
QString SSHProcessInfo::port() const
{
return _port;
}
QString SSHProcessInfo::command() const
{
return _command;
}
QString SSHProcessInfo::format(const QString &input) const
{
QString output(input);
// search for and replace known markers
output.replace(QLatin1String("%u"), _user);
// provide 'user@' if user is defined -- this makes nicer