File indexing completed on 2024-04-21 05:51:27

0001 /*
0002     SPDX-FileCopyrightText: 2007-2008 Robert Knight <robertknight@gmail.com>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 // Own
0008 #include "UnixProcessInfo.h"
0009 
0010 #ifndef Q_OS_WIN
0011 // Unix
0012 #include <arpa/inet.h>
0013 #include <cerrno>
0014 #include <netinet/in.h>
0015 #include <pwd.h>
0016 #include <sys/param.h>
0017 #include <sys/socket.h>
0018 #include <unistd.h>
0019 
0020 // Qt
0021 #include <QDebug>
0022 #include <QtGlobal>
0023 
0024 #if defined(Q_OS_FREEBSD) || defined(Q_OS_OPEN_BSD) || defined(Q_OS_MACOS)
0025 #include <QSharedPointer>
0026 #include <sys/sysctl.h>
0027 #endif
0028 
0029 using namespace Konsole;
0030 
0031 UnixProcessInfo::UnixProcessInfo(int pid)
0032     : ProcessInfo(pid)
0033 {
0034     setUserNameRequired(true);
0035 }
0036 
0037 void UnixProcessInfo::readProcessInfo(int pid)
0038 {
0039     // prevent _arguments from growing longer and longer each time this
0040     // method is called.
0041     clearArguments();
0042 
0043     if (readProcInfo(pid)) {
0044         readArguments(pid);
0045         readCurrentDir(pid);
0046 
0047         bool ok = false;
0048         const QString &processNameString = name(&ok);
0049 
0050         if (ok && processNameString == QLatin1String("sudo")) {
0051             // Append process name along with sudo
0052             const QVector<QString> &args = arguments(&ok);
0053 
0054             if (ok && args.size() > 1) {
0055                 setName(processNameString + QStringLiteral(" ") + args[1]);
0056             }
0057         }
0058     }
0059 }
0060 
0061 void UnixProcessInfo::readUserName()
0062 {
0063     bool ok = false;
0064     const int uid = userId(&ok);
0065     if (!ok) {
0066         return;
0067     }
0068 
0069     struct passwd passwdStruct;
0070     struct passwd *getpwResult;
0071     char *getpwBuffer;
0072     long getpwBufferSize;
0073     int getpwStatus;
0074 
0075     getpwBufferSize = sysconf(_SC_GETPW_R_SIZE_MAX);
0076     if (getpwBufferSize == -1) {
0077         getpwBufferSize = 16384;
0078     }
0079 
0080     getpwBuffer = new char[getpwBufferSize];
0081     if (getpwBuffer == nullptr) {
0082         return;
0083     }
0084     getpwStatus = getpwuid_r(uid, &passwdStruct, getpwBuffer, getpwBufferSize, &getpwResult);
0085     if ((getpwStatus == 0) && (getpwResult != nullptr)) {
0086         setUserName(QLatin1String(passwdStruct.pw_name));
0087     } else {
0088         setUserName(QString());
0089         qWarning() << "getpwuid_r returned error : " << getpwStatus;
0090     }
0091     delete[] getpwBuffer;
0092 }
0093 
0094 bool UnixProcessInfo::readArguments(int pid)
0095 {
0096     // used for LinuxProcessInfo and SolarisProcessInfo
0097     // read command-line arguments file found at /proc/<pid>/cmdline
0098     // the expected format is a list of strings delimited by null characters,
0099     // and ending in a double null character pair.
0100 
0101     QFile argumentsFile(QStringLiteral("/proc/%1/cmdline").arg(pid));
0102     if (argumentsFile.open(QIODevice::ReadOnly)) {
0103         QTextStream stream(&argumentsFile);
0104         const QString &data = stream.readAll();
0105 
0106         const QStringList &argList = data.split(QLatin1Char('\0'));
0107 
0108         for (const QString &entry : argList) {
0109             if (!entry.isEmpty()) {
0110                 addArgument(entry);
0111             }
0112         }
0113     } else {
0114         setFileError(argumentsFile.error());
0115     }
0116 
0117     return true;
0118 }
0119 
0120 #if defined(Q_OS_FREEBSD) || defined(Q_OS_OPEN_BSD) || defined(Q_OS_MACOS)
0121 QSharedPointer<struct kinfo_proc> UnixProcessInfo::getProcInfoStruct(int *managementInfoBase, int mibCount)
0122 {
0123     size_t structLength;
0124 
0125     if (::sysctl(managementInfoBase, mibCount, NULL, &structLength, NULL, 0) == -1) {
0126         qWarning() << "first sysctl() call failed with code " << errno;
0127         return nullptr;
0128     }
0129 
0130     QSharedPointer<struct kinfo_proc> kInfoProc(new struct kinfo_proc[structLength]);
0131 
0132     if (::sysctl(managementInfoBase, mibCount, kInfoProc.get(), &structLength, NULL, 0) == -1) {
0133         qWarning() << "second sysctl() call failed with code " << errno;
0134         return nullptr;
0135     }
0136 
0137     return kInfoProc;
0138 }
0139 #endif
0140 
0141 #endif // Q_OS_WIN