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)) {
193 *ok = _fields.
testFlag(ENVIRONMENT);
200 return _fields.
testFlag(PROCESS_ID);
219 *ok = _fields.
testFlag(FOREGROUND_PID);
221 return _foregroundPid;
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;
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)
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;
434 QFile statusInfo(QStringLiteral(
"/proc/%1/status").arg(aPid));
439 statusLine = stream.readLine();
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));
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));
537 const QString &data = stream.readAll();
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;
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));
579 const QString &data = stream.readAll();
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)
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)
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)
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++) {
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)
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)
979 virtual bool readProcInfo(
int 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)
1017 const bool readable = info.isReadable();
1019 if (readable && info.isSymLink()) {
1020 setCurrentDir(info.symLinkTarget());
1024 setError(PermissionsError);
1026 setError(UnknownError);
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')
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;
1166 isIpAddress =
false;
1169 output.
replace(QStringLiteral(
"%u"), _user);
1172 output.
replace(QStringLiteral(
"%h"), _host);
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
iterator insert(const Key &key, const T &value)
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
QString left(qsizetype n) 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
QByteArray toLocal8Bit() const const
bool contains(QChar c, Qt::CaseSensitivity cs) const const