18#include "ProcessInfo.h" 
   22#include <netinet/in.h> 
   25#include <sys/socket.h> 
   30#include <QtCore/QFileInfo> 
   31#include <QtCore/QFlags> 
   32#include <QtCore/QStringList> 
   33#include <QtCore/QTextStream> 
   34#include <QtNetwork/QHostInfo> 
   41#if defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD) || defined(Q_OS_MAC) 
   42#include <sys/sysctl.h> 
   49#if defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD) 
   50#include <sys/syslimits.h> 
   53#if defined(Q_OS_FREEBSD) 
   58using namespace Konsole;
 
   61    : _fields(ARGUMENTS | ENVIRONMENT) 
 
   68    , _enableEnvironmentRead(enableEnvironmentRead)
 
 
  101    while (!ok && currentPid != 0) {
 
  104        currentPid = current->parentPid(&ok);
 
  105        dir = current->currentDir(&ok);
 
 
  131        output.
replace(QStringLiteral(
"%D"), tempDir);
 
  133    output.
replace(QStringLiteral(
"%d"), formatShortDir(dir));
 
 
  152    return _commonDirNames;
 
  170    while (iter.hasPrevious()) {
 
  171        const QString &part = iter.previous();
 
  173        if (dirNamesToShorten.
contains(part)) {
 
  186    *ok = _fields.testFlag(ARGUMENTS);
 
 
  193    *ok = _fields.testFlag(ENVIRONMENT);
 
 
  200    return _fields.testFlag(PROCESS_ID);
 
 
  205    *ok = _fields.testFlag(PROCESS_ID);
 
 
  212    *ok = _fields.testFlag(PARENT_PID);
 
 
  219    *ok = _fields.testFlag(FOREGROUND_PID);
 
  221    return _foregroundPid;
 
 
  226    *ok = _fields.testFlag(NAME);
 
 
  231int ProcessInfo::userId(
bool *ok)
 const 
  256    _fields |= PROCESS_ID;
 
 
  279    _fields |= PARENT_PID;
 
 
  283    _foregroundPid = aPid;
 
  284    _fields |= FOREGROUND_PID;
 
 
  290        *ok = _fields & CURRENT_DIR;
 
 
  296    _fields |= CURRENT_DIR;
 
 
  307    _arguments << argument;
 
 
  317    _environment.insert(
name, value);
 
 
  349void NullProcessInfo::readUserName()
 
  353#if !defined(Q_OS_WIN) 
  365    bool ok = readProcInfo(aPid);
 
  367        ok |= readArguments(aPid);
 
  368        ok |= readCurrentDir(aPid);
 
  369        if (enableEnvironmentRead) {
 
  370            ok |= readEnvironment(aPid);
 
 
  376void UnixProcessInfo::readUserName()
 
  379    const int uid = userId(&ok);
 
  383    struct passwd passwdStruct;
 
  384    struct passwd *getpwResult;
 
  386    long getpwBufferSize;
 
  389    getpwBufferSize = sysconf(_SC_GETPW_R_SIZE_MAX);
 
  390    if (getpwBufferSize == -1)
 
  391        getpwBufferSize = 16384;
 
  393    getpwBuffer = 
new char[getpwBufferSize];
 
  394    if (getpwBuffer == 
nullptr)
 
  396    getpwStatus = getpwuid_r(uid, &passwdStruct, getpwBuffer, getpwBufferSize, &getpwResult);
 
  397    if ((getpwStatus == 0) && (getpwResult != 
nullptr)) {
 
  401        qWarning() << 
"getpwuid_r returned error : " << getpwStatus;
 
  403    delete[] getpwBuffer;
 
  407#if defined(Q_OS_LINUX) 
  411    LinuxProcessInfo(
int aPid, 
bool env)
 
  412        : UnixProcessInfo(aPid, env)
 
  417    bool readProcInfo(
int aPid)
 override 
  421        const int PARENT_PID_FIELD = 3;
 
  422        const int PROCESS_NAME_FIELD = 1;
 
  423        const int GROUP_PROCESS_FIELD = 7;
 
  425        QString parentPidString;
 
  426        QString processNameString;
 
  427        QString foregroundPidString;
 
  430        QStringList uidStrings;
 
  434        QFile statusInfo(QStringLiteral(
"/proc/%1/status").arg(aPid));
 
  436            QTextStream stream(&statusInfo);
 
  439                statusLine = stream.readLine();
 
  440                if (statusLine.
startsWith(QLatin1String(
"Uid:")))
 
  441                    uidLine = statusLine;
 
  447            if (uidStrings.
size() == 5)
 
  448                uidString = uidStrings[1];
 
  449            if (uidString.
size() > 5)
 
  453            const int uid = uidString.
toInt(&ok);
 
  458            setFileError(statusInfo.error());
 
  470        QFile processInfo(QStringLiteral(
"/proc/%1/stat").arg(aPid));
 
  472            QTextStream stream(&processInfo);
 
  473            const QString &data = stream.readAll();
 
  479            while (pos < data.
size()) {
 
  484                } 
else if (c == u
')') {
 
  486                } 
else if (stack == 0 && c == u
' ') {
 
  490                    case PARENT_PID_FIELD:
 
  491                        parentPidString.
append(c);
 
  493                    case PROCESS_NAME_FIELD:
 
  494                        processNameString.
append(c);
 
  496                    case GROUP_PROCESS_FIELD:
 
  497                        foregroundPidString.
append(c);
 
  505            setFileError(processInfo.error());
 
  511        const int foregroundPid = foregroundPidString.
toInt(&ok);
 
  513            setForegroundPid(foregroundPid);
 
  515        const int parentPid = parentPidString.
toInt(&ok);
 
  517            setParentPid(parentPid);
 
  519        if (!processNameString.
isEmpty())
 
  520            setName(processNameString);
 
  528    bool readArguments(
int aPid)
 override 
  534        QFile argumentsFile(QStringLiteral(
"/proc/%1/cmdline").arg(aPid));
 
  536            QTextStream stream(&argumentsFile);
 
  537            const QString &data = stream.readAll();
 
  539            const QStringList &argList = data.
split(QChar(u
'\0'));
 
  541            for (
const QString &entry : argList) {
 
  542                if (!entry.isEmpty())
 
  546            setFileError(argumentsFile.error());
 
  552    bool readCurrentDir(
int aPid)
 override 
  554        char path_buffer[MAXPATHLEN + 1];
 
  555        path_buffer[MAXPATHLEN] = 0;
 
  556        QByteArray procCwd = 
QFile::encodeName(QStringLiteral(
"/proc/%1/cwd").arg(aPid));
 
  557        const int length = readlink(procCwd.
constData(), path_buffer, MAXPATHLEN);
 
  559            setError(UnknownError);
 
  563        path_buffer[length] = 
'\0';
 
  570    bool readEnvironment(
int aPid)
 override 
  576        QFile environmentFile(QStringLiteral(
"/proc/%1/environ").arg(aPid));
 
  578            QTextStream stream(&environmentFile);
 
  579            const QString &data = stream.readAll();
 
  581            const QStringList &bindingList = data.
split(QChar(u
'\0'));
 
  583            for (
const QString &entry : bindingList) {
 
  587                const int splitPos = entry.
indexOf(u
'=');
 
  589                if (splitPos != -1) {
 
  591                    value = entry.
mid(splitPos + 1, -1);
 
  593                    addEnvironmentBinding(name, value);
 
  597            setFileError(environmentFile.error());
 
  604#elif defined(Q_OS_FREEBSD) 
  608    FreeBSDProcessInfo(
int aPid, 
bool readEnvironment)
 
  609        : UnixProcessInfo(aPid, readEnvironment)
 
  614    virtual bool readProcInfo(
int aPid)
 
  616        int managementInfoBase[4];
 
  618        struct kinfo_proc *kInfoProc;
 
  620        managementInfoBase[0] = CTL_KERN;
 
  621        managementInfoBase[1] = KERN_PROC;
 
  622        managementInfoBase[2] = KERN_PROC_PID;
 
  623        managementInfoBase[3] = aPid;
 
  625        if (sysctl(managementInfoBase, 4, NULL, &mibLength, NULL, 0) == -1)
 
  628        kInfoProc = 
new struct kinfo_proc[mibLength];
 
  630        if (sysctl(managementInfoBase, 4, kInfoProc, &mibLength, NULL, 0) == -1) {
 
  635#if defined(HAVE_OS_DRAGONFLYBSD) 
  637        setPid(kInfoProc->kp_pid);
 
  638        setParentPid(kInfoProc->kp_ppid);
 
  639        setForegroundPid(kInfoProc->kp_pgid);
 
  640        setUserId(kInfoProc->kp_uid);
 
  643        setPid(kInfoProc->ki_pid);
 
  644        setParentPid(kInfoProc->ki_ppid);
 
  645        setForegroundPid(kInfoProc->ki_pgid);
 
  646        setUserId(kInfoProc->ki_uid);
 
  655    virtual bool readArguments(
int aPid)
 
  658        int managementInfoBase[4];
 
  661        managementInfoBase[0] = CTL_KERN;
 
  662        managementInfoBase[1] = KERN_PROC;
 
  663        managementInfoBase[2] = KERN_PROC_PID;
 
  664        managementInfoBase[3] = aPid;
 
  667        if (sysctl(managementInfoBase, 4, args, &len, NULL, 0) == -1)
 
  672        for (QStringList::const_iterator it = argumentList.
begin(); it != argumentList.
end(); ++it) {
 
  679    virtual bool readEnvironment(
int aPid)
 
  686    virtual bool readCurrentDir(
int aPid)
 
  688#if defined(HAVE_OS_DRAGONFLYBSD) 
  690        int managementInfoBase[4];
 
  693        managementInfoBase[0] = CTL_KERN;
 
  694        managementInfoBase[1] = KERN_PROC;
 
  695        managementInfoBase[2] = KERN_PROC_CWD;
 
  696        managementInfoBase[3] = aPid;
 
  699        if (sysctl(managementInfoBase, 4, buf, &len, NULL, 0) == -1)
 
  707        struct kinfo_file *info = 
nullptr;
 
  709        info = kinfo_getfile(aPid, &numrecords);
 
  714        for (
int i = 0; i < numrecords; ++i) {
 
  715            if (info[i].kf_fd == KF_FD_TYPE_CWD) {
 
  729#elif defined(Q_OS_OPENBSD) 
  733    OpenBSDProcessInfo(
int aPid, 
bool readEnvironment)
 
  734        : UnixProcessInfo(aPid, readEnvironment)
 
  739    virtual bool readProcInfo(
int aPid)
 
  741        int managementInfoBase[6];
 
  743        struct kinfo_proc *kInfoProc;
 
  745        managementInfoBase[0] = CTL_KERN;
 
  746        managementInfoBase[1] = KERN_PROC;
 
  747        managementInfoBase[2] = KERN_PROC_PID;
 
  748        managementInfoBase[3] = aPid;
 
  749        managementInfoBase[4] = 
sizeof(
struct kinfo_proc);
 
  750        managementInfoBase[5] = 1;
 
  752        if (::sysctl(managementInfoBase, 6, NULL, &mibLength, NULL, 0) == -1) {
 
  753            qWarning() << 
"first sysctl() call failed with code" << errno;
 
  757        kInfoProc = (
struct kinfo_proc *)malloc(mibLength);
 
  759        if (::sysctl(managementInfoBase, 6, kInfoProc, &mibLength, NULL, 0) == -1) {
 
  760            qWarning() << 
"second sysctl() call failed with code" << errno;
 
  765        setName(kInfoProc->p_comm);
 
  766        setPid(kInfoProc->p_pid);
 
  767        setParentPid(kInfoProc->p_ppid);
 
  768        setForegroundPid(kInfoProc->p_tpgid);
 
  769        setUserId(kInfoProc->p_uid);
 
  770        setUserName(kInfoProc->p_login);
 
  776    char **readProcArgs(
int aPid, 
int whatMib)
 
  782        int managementInfoBase[4];
 
  784        managementInfoBase[0] = CTL_KERN;
 
  785        managementInfoBase[1] = KERN_PROC_ARGS;
 
  786        managementInfoBase[2] = aPid;
 
  787        managementInfoBase[3] = whatMib;
 
  791            nbuf = realloc(buf, len);
 
  797            rc = ::sysctl(managementInfoBase, 4, buf, &len, NULL, 0);
 
  798            qWarning() << 
"sysctl() call failed with code" << errno;
 
  799        } 
while (rc == -1 && errno == ENOMEM);
 
  801        if (nbuf == NULL || rc == -1) {
 
  809    virtual bool readArguments(
int aPid)
 
  813        argv = readProcArgs(aPid, KERN_PROC_ARGV);
 
  818        for (
char **p = argv; *p != NULL; p++) {
 
  819            addArgument(QString(*p));
 
  825    virtual bool readEnvironment(
int aPid)
 
  830        envp = readProcArgs(aPid, KERN_PROC_ENV);
 
  835        for (
char **p = envp; *p != NULL; p++) {
 
  836            eqsign = strchr(*p, 
'=');
 
  837            if (eqsign == NULL || eqsign[1] == 
'\0') {
 
  841            addEnvironmentBinding(QString((
const char *)p), QString((
const char *)eqsign + 1));
 
  847    virtual bool readCurrentDir(
int aPid)
 
  850        int managementInfoBase[3];
 
  853        managementInfoBase[0] = CTL_KERN;
 
  854        managementInfoBase[1] = KERN_PROC_CWD;
 
  855        managementInfoBase[2] = aPid;
 
  858        if (::sysctl(managementInfoBase, 3, buf, &len, NULL, 0) == -1) {
 
  859            qWarning() << 
"sysctl() call failed with code" << errno;
 
  868#elif defined(Q_OS_MAC) 
  872    MacProcessInfo(
int aPid, 
bool env)
 
  873        : UnixProcessInfo(aPid, env)
 
  878    virtual bool readProcInfo(
int aPid)
 
  880        int managementInfoBase[4];
 
  882        struct kinfo_proc *kInfoProc;
 
  936    virtual bool readArguments(
int aPid)
 
  941    virtual bool readCurrentDir(
int aPid)
 
  943        struct proc_vnodepathinfo vpi;
 
  944        const int nb = proc_pidinfo(aPid, PROC_PIDVNODEPATHINFO, 0, &vpi, 
sizeof(vpi));
 
  945        if (nb == 
sizeof(vpi)) {
 
  946            setCurrentDir(QString(vpi.pvi_cdir.vip_path));
 
  951    virtual bool readEnvironment(
int aPid)
 
  958#elif defined(Q_OS_SOLARIS) 
  965#if defined(_FILE_OFFSET_BITS) && (_FILE_OFFSET_BITS == 64) 
  966#undef _FILE_OFFSET_BITS 
  973    SolarisProcessInfo(
int aPid, 
bool readEnvironment)
 
  974        : UnixProcessInfo(aPid, readEnvironment)
 
  979    virtual bool readProcInfo(
int aPid)
 
  981        QFile psinfo(QString(
"/proc/%1/psinfo").arg(aPid));
 
  984            if (psinfo.read((
char *)&info, 
sizeof(info)) != 
sizeof(info)) {
 
  988            setParentPid(info.pr_ppid);
 
  989            setForegroundPid(info.pr_pgid);
 
  990            setName(info.pr_fname);
 
  994            info.pr_psargs[PRARGSZ - 1] = 0;
 
  995            addArgument(info.pr_psargs);
 
 1000    virtual bool readArguments(
int )
 
 1006    virtual bool readEnvironment(
int )
 
 1014    virtual bool readCurrentDir(
int aPid)
 
 1016        QFileInfo info(QString(
"/proc/%1/path/cwd").arg(aPid));
 
 1017        const bool readable = info.isReadable();
 
 1019        if (readable && info.isSymLink()) {
 
 1020            setCurrentDir(info.symLinkTarget());
 
 1024                setError(PermissionsError);
 
 1026                setError(UnknownError);
 
 1040    const QString &name = _process.name(&ok);
 
 1042    if (!ok || name != u
"ssh") {
 
 1044            qWarning() << 
"Could not read process info";
 
 1046            qWarning() << 
"Process is not a SSH process";
 
 1058    static const QStringView noArgumentOptions(u
"1246AaCfgKkMNnqsTtVvXxYy");
 
 1060    static const QStringView singleArgumentOptions(u
"bcDeFIiLlmOopRSWw");
 
 1075        for (
int i = 1; i < args.
size(); i++) {
 
 1078            if (args[i].startsWith(u
'-')) {
 
 1079                const QChar optionChar = (args[i].
length() > 1) ? args[i][1] : u
'\0';
 
 1081                const bool optionArgumentCombined = args[i].
length() > 2;
 
 1083                if (noArgumentOptions.
contains(optionChar)) {
 
 1085                } 
else if (singleArgumentOptions.
contains(optionChar)) {
 
 1087                    if (optionArgumentCombined) {
 
 1088                        argument = args[i].
mid(2);
 
 1091                        if ((i + 1) < args.
size()) {
 
 1092                            argument = args[i + 1];
 
 1098                    if (optionChar == u
'l')
 
 1101                    else if (optionChar == u
'p')
 
 1110            if (_host.isEmpty()) {
 
 1115                const int separatorPosition = args[i].
indexOf(u
'@');
 
 1116                if (separatorPosition != -1) {
 
 1118                    _user = args[i].left(separatorPosition);
 
 1119                    _host = args[i].
mid(separatorPosition + 1);
 
 1130        qWarning() << 
"Could not read arguments";
 
 
 1160    bool isIpAddress = 
false;
 
 1162    struct in_addr address;
 
 1163    if (inet_aton(_host.toLocal8Bit().constData(), &address) != 0)
 
 1166        isIpAddress = 
false;
 
 1169    output.
replace(QStringLiteral(
"%u"), _user);
 
 1172        output.
replace(QStringLiteral(
"%h"), _host);
 
 1174        output.
replace(QStringLiteral(
"%h"), _host.left(_host.indexOf(u
'.')));
 
 1176    output.
replace(QStringLiteral(
"%H"), _host);
 
 1177    output.
replace(QStringLiteral(
"%c"), _command);
 
 
 1184#if defined(Q_OS_LINUX) 
 1185    return std::make_unique<LinuxProcessInfo>(aPid, enableEnvironmentRead);
 
 1186#elif defined(Q_OS_SOLARIS) 
 1187    return std::make_unique<SolarisProcessInfo>(aPid, enableEnvironmentRead);
 
 1188#elif defined(Q_OS_MAC) 
 1189    return std::make_unique<MacProcessInfo>(aPid, enableEnvironmentRead);
 
 1190#elif defined(Q_OS_FREEBSD) 
 1191    return std::make_unique<FreeBSDProcessInfo>(aPid, enableEnvironmentRead);
 
 1192#elif defined(Q_OS_OPENBSD) 
 1193    return std::make_unique<OpenBSDProcessInfo>(aPid, enableEnvironmentRead);
 
 1195    return std::make_unique<NullProcessInfo>(aPid, enableEnvironmentRead);
 
 
bool readProcessInfo(int pid, bool readEnvironment) override
This is called on construction to read the process state Subclasses should reimplement this function ...
 
NullProcessInfo(int pid, bool readEnvironment=false)
Constructs a new NullProcessInfo instance.
 
Takes a snapshot of the state of a process and provides access to information such as the process nam...
 
int parentPid(bool *ok) const
Returns the id of the parent process id was read successfully or false otherwise.
 
void setUserName(const QString &name)
Sets the user name of the process as set by readUserName()
 
void clearArguments()
clear the commandline arguments for the process, as returned by arguments()
 
void setUserHomeDir()
Forces the user home directory to be calculated.
 
ProcessInfo(int pid, bool readEnvironment=false)
Constructs a new process instance.
 
static QString localHost()
Returns the local host.
 
void addEnvironmentBinding(const QString &name, const QString &value)
Adds an environment binding for the process, as returned by environment()
 
void setName(const QString &name)
Sets the name of the process as returned by name()
 
Error
This enum describes the errors which can occur when trying to read a process's information.
 
@ PermissionsError
Konsole does not have permission to obtain the process information.
 
@ UnknownError
The nature of the error is unknown.
 
@ NoError
No error occurred.
 
QString currentDir(bool *ok) const
Returns the current working directory of the process.
 
void setFileError(QFile::FileError error)
Convenience method.
 
void setParentPid(int pid)
Sets the parent process id as returned by parentPid()
 
void setPid(int pid)
Sets the process id associated with this ProcessInfo instance.
 
int pid(bool *ok) const
Returns the process id.
 
int foregroundPid(bool *ok) const
Returns the id of the current foreground process.
 
void setError(Error error)
Sets the error.
 
void setCurrentDir(const QString &dir)
Sets the current working directory for the process.
 
QMap< QString, QString > environment(bool *ok) const
Returns the environment bindings which the process was started with.
 
bool isValid() const
Returns true if the process state was read successfully.
 
QString userHomeDir() const
Returns the user's home directory of the process.
 
QString format(const QString &text) const
Parses an input string, looking for markers beginning with a '' character and returns a string with t...
 
void update()
Updates the information about the process.
 
Error error() const
Returns the last error which occurred.
 
QString name(bool *ok) const
Returns the name of the current process.
 
void setUserId(int uid)
Sets the user id associated with this ProcessInfo instance.
 
QString validCurrentDir() const
Returns the current working directory of the process (or its parent)
 
void setForegroundPid(int pid)
Sets the foreground process id as returned by foregroundPid()
 
QVector< QString > arguments(bool *ok) const
Returns the command-line arguments which the process was started with.
 
QString userName() const
Returns the user's name of the process.
 
static std::unique_ptr< ProcessInfo > newInstance(int pid, bool readEnvironment=false)
Constructs a new instance of a suitable ProcessInfo sub-class for the current platform which provides...
 
void addArgument(const QString &argument)
Adds a commandline argument for the process, as returned by arguments()
 
virtual bool readProcessInfo(int pid, bool readEnvironment)=0
This is called on construction to read the process state Subclasses should reimplement this function ...
 
QString format(const QString &input) const
Operates in the same way as ProcessInfo::format(), except that the set of markers understood is diffe...
 
QString userName() const
Returns the user name which the user initially logged into on the remote computer.
 
QString host() const
Returns the host which the user has connected to.
 
QString command() const
Returns the command which the user specified to execute on the remote computer when starting the SSH ...
 
QString port() const
Returns the port on host which the user has connected to.
 
SSHProcessInfo(const ProcessInfo &process)
Constructs a new SSHProcessInfo instance which provides additional information about the specified SS...
 
Implementation of ProcessInfo for Unix platforms which uses the /proc filesystem.
 
UnixProcessInfo(int pid, bool readEnvironment=false)
Constructs a new instance of UnixProcessInfo.
 
bool readProcessInfo(int pid, bool readEnvironment) override
Implementation of ProcessInfo::readProcessInfo(); calls the four private methods below in turn.
 
QString path(const QString &relativePath)
 
QString name(StandardAction id)
 
const char * constData() const const
 
QString decodeName(const QByteArray &localFileName)
 
QByteArray encodeName(const QString &fileName)
 
bool testFlag(Enum flag) const const
 
qsizetype indexOf(const AT &value, qsizetype from) const const
 
qsizetype length() const const
 
QList< T > mid(qsizetype pos, qsizetype length) const const
 
qsizetype size() const const
 
bool contains(const QSet< T > &other) const const
 
QString & append(QChar ch)
 
bool contains(QChar ch, Qt::CaseSensitivity cs) const const
 
QString fromLatin1(QByteArrayView str)
 
qsizetype indexOf(QChar ch, qsizetype from, Qt::CaseSensitivity cs) const const
 
bool isEmpty() const const
 
bool isNull() const const
 
qsizetype length() const const
 
QString mid(qsizetype position, qsizetype n) const const
 
QString & prepend(QChar ch)
 
QString & remove(QChar ch, Qt::CaseSensitivity cs)
 
QString & replace(QChar before, QChar after, Qt::CaseSensitivity cs)
 
qsizetype size() const const
 
QStringList split(QChar sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
 
bool startsWith(QChar c, Qt::CaseSensitivity cs) const const
 
int toInt(bool *ok, int base) const const
 
bool contains(QChar c, Qt::CaseSensitivity cs) const const