21 #include <config-konsole.h>
27 #include <sys/socket.h>
28 #include <netinet/in.h>
29 #include <arpa/inet.h>
32 #include <sys/param.h>
35 #include <QtCore/QDir>
36 #include <QtCore/QFileInfo>
37 #include <QtCore/QTextStream>
38 #include <QtCore/QStringList>
39 #include <QtNetwork/QHostInfo>
42 #include <KConfigGroup>
44 #include <KSharedConfig>
48 #if defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD) || defined(Q_OS_MAC)
49 #include <sys/sysctl.h>
57 #if defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD)
58 #include <sys/types.h>
60 #include <sys/syslimits.h>
61 # if defined(Q_OS_FREEBSD)
66 using namespace Konsole;
69 : _fields(ARGUMENTS | ENVIRONMENT)
76 , _enableEnvironmentRead(enableEnvironmentRead)
109 while (!ok && currentPid != 0) {
142 output.
replace(
"%d", formatShortDir(dir));
151 static bool forTheFirstTime =
true;
153 if (forTheFirstTime) {
154 const KSharedConfigPtr& config = KGlobal::config();
155 const KConfigGroup& configGroup = config->group(
"ProcessInfo");
158 forTheFirstTime =
false;
161 return _commonDirNames;
179 while (iter.hasPrevious()) {
180 const QString& part = iter.previous();
182 if (dirNamesToShorten.
contains(part)) {
195 *ok = _fields & ARGUMENTS;
202 *ok = _fields & ENVIRONMENT;
209 return _fields & PROCESS_ID;
214 *ok = _fields & PROCESS_ID;
221 *ok = _fields & PARENT_PID;
228 *ok = _fields & FOREGROUND_PID;
230 return _foregroundPid;
235 *ok = _fields & NAME;
265 _fields |= PROCESS_ID;
284 _userHomeDir = KUser(usersName).homeDir();
292 _fields |= PARENT_PID;
296 _foregroundPid = aPid;
297 _fields |= FOREGROUND_PID;
303 *ok = _fields & CURRENT_DIR;
309 _fields |= CURRENT_DIR;
320 _arguments << argument;
330 _environment.
insert(name, value);
336 case QFile::PermissionsError:
366 #if !defined(Q_OS_WIN)
378 bool ok = readProcInfo(aPid);
380 ok |= readArguments(aPid);
381 ok |= readCurrentDir(aPid);
382 if (enableEnvironmentRead) {
383 ok |= readEnvironment(aPid);
392 const int uid =
userId(&ok);
395 struct passwd passwdStruct;
396 struct passwd* getpwResult;
398 long getpwBufferSize;
401 getpwBufferSize = sysconf(_SC_GETPW_R_SIZE_MAX);
402 if (getpwBufferSize == -1)
403 getpwBufferSize = 16384;
405 getpwBuffer =
new char[getpwBufferSize];
406 if (getpwBuffer == NULL)
408 getpwStatus = getpwuid_r(uid, &passwdStruct, getpwBuffer, getpwBufferSize, &getpwResult);
409 if ((getpwStatus == 0) && (getpwResult != NULL)) {
413 kWarning() <<
"getpwuid_r returned error : " << getpwStatus;
415 delete [] getpwBuffer;
419 #if defined(Q_OS_LINUX)
423 LinuxProcessInfo(
int aPid,
bool env) :
428 virtual bool readProcInfo(
int aPid) {
431 const int PARENT_PID_FIELD = 3;
432 const int PROCESS_NAME_FIELD = 1;
433 const int GROUP_PROCESS_FIELD = 7;
445 if (statusInfo.open(QIODevice::ReadOnly)) {
449 statusLine = stream.readLine(0);
451 uidLine = statusLine;
454 uidStrings << uidLine.
split(
'\t', QString::SkipEmptyParts);
457 if (uidStrings.
size() == 5)
458 uidString = uidStrings[1];
459 if (uidString.
size() > 5)
463 const int uid = uidString.
toInt(&ok);
468 setFileError(statusInfo.error());
481 if (processInfo.open(QIODevice::ReadOnly)) {
483 const QString& data = stream.readAll();
489 while (pos < data.
count()) {
494 }
else if (c ==
')') {
496 }
else if (stack == 0 && c ==
' ') {
500 case PARENT_PID_FIELD:
501 parentPidString.
append(c);
503 case PROCESS_NAME_FIELD:
504 processNameString.
append(c);
506 case GROUP_PROCESS_FIELD:
507 foregroundPidString.
append(c);
515 setFileError(processInfo.error());
521 const int foregroundPid = foregroundPidString.
toInt(&ok);
523 setForegroundPid(foregroundPid);
525 const int parentPid = parentPidString.
toInt(&ok);
527 setParentPid(parentPid);
529 if (!processNameString.
isEmpty())
530 setName(processNameString);
538 virtual bool readArguments(
int aPid) {
543 QFile argumentsFile(
QString(
"/proc/%1/cmdline").arg(aPid));
544 if (argumentsFile.open(QIODevice::ReadOnly)) {
546 const QString& data = stream.readAll();
550 foreach(
const QString & entry , argList) {
555 setFileError(argumentsFile.error());
561 virtual bool readCurrentDir(
int aPid) {
562 char path_buffer[MAXPATHLEN + 1];
563 path_buffer[MAXPATHLEN] = 0;
565 const int length = readlink(procCwd.
constData(), path_buffer, MAXPATHLEN);
567 setError(UnknownError);
571 path_buffer[length] =
'\0';
578 virtual bool readEnvironment(
int aPid) {
583 QFile environmentFile(
QString(
"/proc/%1/environ").arg(aPid));
584 if (environmentFile.open(QIODevice::ReadOnly)) {
586 const QString& data = stream.readAll();
590 foreach(
const QString & entry , bindingList) {
594 const int splitPos = entry.
indexOf(
'=');
596 if (splitPos != -1) {
597 name = entry.
mid(0, splitPos);
598 value = entry.
mid(splitPos + 1, -1);
600 addEnvironmentBinding(name, value);
604 setFileError(environmentFile.error());
611 #elif defined(Q_OS_FREEBSD)
615 FreeBSDProcessInfo(
int aPid,
bool readEnvironment) :
620 virtual bool readProcInfo(
int aPid) {
621 int managementInfoBase[4];
623 struct kinfo_proc* kInfoProc;
625 managementInfoBase[0] = CTL_KERN;
626 managementInfoBase[1] = KERN_PROC;
627 managementInfoBase[2] = KERN_PROC_PID;
628 managementInfoBase[3] = aPid;
630 if (sysctl(managementInfoBase, 4, NULL, &mibLength, NULL, 0) == -1)
633 kInfoProc =
new struct kinfo_proc [mibLength];
635 if (sysctl(managementInfoBase, 4, kInfoProc, &mibLength, NULL, 0) == -1) {
640 #if defined(HAVE_OS_DRAGONFLYBSD)
641 setName(kInfoProc->kp_comm);
642 setPid(kInfoProc->kp_pid);
643 setParentPid(kInfoProc->kp_ppid);
644 setForegroundPid(kInfoProc->kp_pgid);
645 setUserId(kInfoProc->kp_uid);
647 setName(kInfoProc->ki_comm);
648 setPid(kInfoProc->ki_pid);
649 setParentPid(kInfoProc->ki_ppid);
650 setForegroundPid(kInfoProc->ki_pgid);
651 setUserId(kInfoProc->ki_uid);
660 virtual bool readArguments(
int aPid) {
662 int managementInfoBase[4];
665 managementInfoBase[0] = CTL_KERN;
666 managementInfoBase[1] = KERN_PROC;
667 managementInfoBase[2] = KERN_PROC_PID;
668 managementInfoBase[3] = aPid;
671 if (sysctl(managementInfoBase, 4, args, &len, NULL, 0) == -1)
683 virtual bool readEnvironment(
int aPid) {
689 virtual bool readCurrentDir(
int aPid) {
690 #if defined(HAVE_OS_DRAGONFLYBSD)
692 int managementInfoBase[4];
695 managementInfoBase[0] = CTL_KERN;
696 managementInfoBase[1] = KERN_PROC;
697 managementInfoBase[2] = KERN_PROC_CWD;
698 managementInfoBase[3] = aPid;
701 if (sysctl(managementInfoBase, 4, buf, &len, NULL, 0) == -1)
709 struct kinfo_file* info = 0;
711 info = kinfo_getfile(aPid, &numrecords);
716 for (
int i = 0; i < numrecords; ++i) {
717 if (info[i].kf_fd == KF_FD_TYPE_CWD) {
718 setCurrentDir(info[i].kf_path);
731 #elif defined(Q_OS_OPENBSD)
735 OpenBSDProcessInfo(
int aPid,
bool readEnvironment) :
740 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 kWarning() <<
"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 kWarning() <<
"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) {
781 int managementInfoBase[4];
783 managementInfoBase[0] = CTL_KERN;
784 managementInfoBase[1] = KERN_PROC_ARGS;
785 managementInfoBase[2] = aPid;
786 managementInfoBase[3] = whatMib;
790 nbuf = realloc(buf, len);
796 rc = ::sysctl(managementInfoBase, 4, buf, &len, NULL, 0);
797 kWarning() <<
"sysctl() call failed with code" << errno;
798 }
while (rc == -1 && errno == ENOMEM);
800 if (nbuf == NULL || rc == -1) {
808 virtual bool readArguments(
int aPid) {
811 argv = readProcArgs(aPid, KERN_PROC_ARGV);
816 for (
char** p = argv; *p != NULL; p++) {
823 virtual bool readEnvironment(
int aPid) {
827 envp = readProcArgs(aPid, KERN_PROC_ENV);
832 for (
char **p = envp; *p != NULL; p++) {
833 eqsign = strchr(*p,
'=');
834 if (eqsign == NULL || eqsign[1] ==
'\0') {
838 addEnvironmentBinding(
QString((
const char *)p),
839 QString((
const char *)eqsign + 1));
845 virtual bool readCurrentDir(
int aPid) {
847 int managementInfoBase[3];
850 managementInfoBase[0] = CTL_KERN;
851 managementInfoBase[1] = KERN_PROC_CWD;
852 managementInfoBase[2] = aPid;
855 if (::sysctl(managementInfoBase, 3, buf, &len, NULL, 0) == -1) {
856 kWarning() <<
"sysctl() call failed with code" << errno;
865 #elif defined(Q_OS_MAC)
869 MacProcessInfo(
int aPid,
bool env) :
874 virtual bool readProcInfo(
int aPid) {
875 int managementInfoBase[4];
877 struct kinfo_proc* kInfoProc;
878 KDE_struct_stat statInfo;
881 managementInfoBase[0] = CTL_KERN;
882 managementInfoBase[1] = KERN_PROC;
883 managementInfoBase[2] = KERN_PROC_PID;
884 managementInfoBase[3] = aPid;
886 if (sysctl(managementInfoBase, 4, NULL, &mibLength, NULL, 0) == -1) {
889 kInfoProc =
new struct kinfo_proc [mibLength];
890 if (sysctl(managementInfoBase, 4, kInfoProc, &mibLength, NULL, 0) == -1) {
894 const QString deviceNumber =
QString(devname(((&kInfoProc->kp_eproc)->e_tdev), S_IFCHR));
899 const char* ttyName = deviceName.
data();
901 if (KDE::stat(ttyName, &statInfo) != 0)
905 managementInfoBase[0] = CTL_KERN;
906 managementInfoBase[1] = KERN_PROC;
907 managementInfoBase[2] = KERN_PROC_TTY;
908 managementInfoBase[3] = statInfo.st_rdev;
911 if (sysctl(managementInfoBase,
sizeof(managementInfoBase) /
sizeof(
int), NULL, &mibLength, NULL, 0) == -1)
914 kInfoProc =
new struct kinfo_proc [mibLength];
915 if (sysctl(managementInfoBase,
sizeof(managementInfoBase) /
sizeof(
int), kInfoProc, &mibLength, NULL, 0) == -1)
919 setName(
QString(kInfoProc->kp_proc.p_comm));
928 virtual bool readArguments(
int aPid) {
932 virtual bool readCurrentDir(
int aPid) {
933 struct proc_vnodepathinfo vpi;
934 const int nb = proc_pidinfo(aPid, PROC_PIDVNODEPATHINFO, 0, &vpi,
sizeof(vpi));
935 if (nb ==
sizeof(vpi)) {
936 setCurrentDir(
QString(vpi.pvi_cdir.vip_path));
941 virtual bool readEnvironment(
int aPid) {
947 #elif defined(Q_OS_SOLARIS)
954 #if defined(_FILE_OFFSET_BITS) && (_FILE_OFFSET_BITS==64)
955 #undef _FILE_OFFSET_BITS
962 SolarisProcessInfo(
int aPid,
bool readEnvironment)
966 virtual bool readProcInfo(
int aPid) {
968 if (psinfo.open(QIODevice::ReadOnly)) {
970 if (psinfo.read((
char *)&info,
sizeof(info)) !=
sizeof(info)) {
974 setParentPid(info.pr_ppid);
975 setForegroundPid(info.pr_pgid);
976 setName(info.pr_fname);
980 info.pr_psargs[PRARGSZ - 1] = 0;
981 addArgument(info.pr_psargs);
986 virtual bool readArguments(
int ) {
991 virtual bool readEnvironment(
int ) {
998 virtual bool readCurrentDir(
int aPid) {
1000 const bool readable = info.isReadable();
1002 if (readable && info.isSymLink()) {
1003 setCurrentDir(info.symLinkTarget());
1007 setError(PermissionsError);
1009 setError(UnknownError);
1025 if (!ok || name !=
"ssh") {
1027 kWarning() <<
"Could not read process info";
1029 kWarning() <<
"Process is not a SSH process";
1041 static const QString noArgumentOptions(
"1246AaCfgKkMNnqsTtVvXxYy");
1043 static const QString singleArgumentOptions(
"bcDeFIiLlmOopRSWw");
1058 for (
int i = 1 ; i < args.
count() ; i++) {
1061 if (args[i].startsWith(
'-')) {
1062 const QChar optionChar = (args[i].length() > 1) ? args[i][1] :
'\0';
1064 const bool optionArgumentCombined = args[i].length() > 2;
1066 if (noArgumentOptions.
contains(optionChar)) {
1068 }
else if (singleArgumentOptions.
contains(optionChar)) {
1070 if (optionArgumentCombined) {
1071 argument = args[i].
mid(2);
1074 if ((i + 1) < args.
count()) {
1075 argument = args[i + 1];
1081 if (optionChar ==
'l')
1084 else if (optionChar ==
'p')
1098 const int separatorPosition = args[i].
indexOf(
'@');
1099 if (separatorPosition != -1) {
1101 _user = args[i].left(separatorPosition);
1102 _host = args[i].
mid(separatorPosition + 1);
1113 kWarning() <<
"Could not read arguments";
1143 bool isIpAddress =
false;
1145 struct in_addr address;
1149 isIpAddress =
false;
1160 output.
replace(
"%c", _command);
1167 #if defined(Q_OS_LINUX)
1168 return new LinuxProcessInfo(aPid, enableEnvironmentRead);
1169 #elif defined(Q_OS_SOLARIS)
1170 return new SolarisProcessInfo(aPid, enableEnvironmentRead);
1171 #elif defined(Q_OS_MAC)
1172 return new MacProcessInfo(aPid, enableEnvironmentRead);
1173 #elif defined(Q_OS_FREEBSD)
1174 return new FreeBSDProcessInfo(aPid, enableEnvironmentRead);
1175 #elif defined(Q_OS_OPENBSD)
1176 return new OpenBSDProcessInfo(aPid, enableEnvironmentRead);
int indexOf(QChar ch, int from, Qt::CaseSensitivity cs) const
QString & append(QChar ch)
QString userHomeDir() const
Returns the user's home directory of the process.
QMap< QString, QString > environment(bool *ok) const
Returns the environment bindings which the process was started with.
QString currentDir(bool *ok) const
Returns the current working directory of the process.
void setError(Error error)
Sets the error.
int indexOf(const T &value, int from) const
QStringList split(const QString &sep, SplitBehavior behavior, Qt::CaseSensitivity cs) const
void setUserName(const QString &name)
Sets the user name of the process as set by readUserName()
QString & prepend(QChar ch)
virtual bool readProcessInfo(int pid, bool readEnvironment)
This is called on construction to read the process state Subclasses should reimplement this function ...
void setCurrentDir(const QString &dir)
Sets the current working directory for the process.
int foregroundPid(bool *ok) const
Returns the id of the current foreground process.
static QString localHost()
Returns the local host.
void setPid(int pid)
Sets the process id associated with this ProcessInfo instance.
QString & remove(int position, int n)
static ProcessInfo * newInstance(int pid, bool readEnvironment=false)
Constructs a new instance of a suitable ProcessInfo sub-class for the current platform which provides...
int pid(bool *ok) const
Returns the process id.
void update()
Updates the information about the process.
NullProcessInfo(int pid, bool readEnvironment=false)
Constructs a new NullProcessInfo instance.
ProcessInfo(int pid, bool readEnvironment=false)
Constructs a new process instance.
QString userName() const
Returns the user name which the user initially logged into on the remote computer.
void setName(const QString &name)
Sets the name of the process as returned by name()
void setUserHomeDir()
Forces the user home directory to be calculated.
QString name(bool *ok) const
Returns the name of the current process.
QString command() const
Returns the command which the user specified to execute on the remote computer when starting the SSH ...
Implementation of ProcessInfo for Unix platforms which uses the /proc filesystem. ...
QString rightJustified(int width, QChar fill, bool truncate) const
void addEnvironmentBinding(const QString &name, const QString &value)
Adds an environment binding for the process, as returned by environment()
int toInt(bool *ok, int base) const
Takes a snapshot of the state of a process and provides access to information such as the process nam...
const char * constData() const
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const
QString format(const QString &text) const
Parses an input string, looking for markers beginning with a '' character and returns a string with t...
UnixProcessInfo(int pid, bool readEnvironment=false)
Constructs a new instance of UnixProcessInfo.
void setUserId(int uid)
Sets the user id associated with this ProcessInfo instance.
QString userName() const
Returns the user's name of the process.
virtual bool readProcessInfo(int pid, bool readEnvironment)
Implementation of ProcessInfo::readProcessInfo(); calls the four private methods below in turn...
QVector< T > mid(int pos, int length) const
QString host() const
Returns the host which the user has connected to.
void setForegroundPid(int pid)
Sets the foreground process id as returned by foregroundPid()
Error
This enum describes the errors which can occur when trying to read a process's information.
QByteArray toLocal8Bit() const
bool contains(QChar ch, Qt::CaseSensitivity cs) const
QString validCurrentDir() const
Returns the current working directory of the process (or its parent)
bool contains(const T &value) const
bool isValid() const
Returns true if the process state was read successfully.
The nature of the error is unknown.
virtual void readUserName(void)
QString & replace(int position, int n, QChar after)
SSHProcessInfo(const ProcessInfo &process)
Constructs a new SSHProcessInfo instance which provides additional information about the specified SS...
QByteArray toLatin1() const
QString mid(int position, int n) const
Implementation of ProcessInfo which does nothing.
QString format(const QString &input) const
Operates in the same way as ProcessInfo::format(), except that the set of markers understood is diffe...
int parentPid(bool *ok) const
Returns the id of the parent process id was read successfully or false otherwise. ...
QVector< QString > arguments(bool *ok) const
Returns the command-line arguments which the process was started with.
int count(const T &value) const
QSet< T > fromList(const QList< T > &list)
QString left(int n) const
void addArgument(const QString &argument)
Adds a commandline argument for the process, as returned by arguments()
Konsole does not have permission to obtain the process information.
iterator insert(const Key &key, const T &value)
void setFileError(QFile::FileError error)
Convenience method.
Error error() const
Returns the last error which occurred.
void setParentPid(int pid)
Sets the parent process id as returned by parentPid()
virtual void readUserName(void)
void clearArguments()
clear the commandline arguments 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 ...
QByteArray encodeName(const QString &fileName)
QString decodeName(const QByteArray &localFileName)
int userId(bool *ok) const
QString port() const
Returns the port on host which the user has connected to.