File indexing completed on 2024-04-28 05:31:40

0001 /*
0002     SPDX-FileCopyrightText: 2007 Adriaan de Groot <groot@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 /* Stop <sys/procfs.h> from crapping out on 32-bit architectures. */
0008 
0009 #if !defined(_LP64) && _FILE_OFFSET_BITS == 64
0010 #undef _FILE_OFFSET_BITS
0011 #define _FILE_OFFSET_BITS 32
0012 #endif
0013 
0014 #include "process.h"
0015 #include "processes_local_p.h"
0016 
0017 #include <KLocalizedString>
0018 
0019 #include <QSet>
0020 
0021 #include <dirent.h>
0022 #include <errno.h>
0023 #include <fcntl.h>
0024 #include <procfs.h>
0025 #include <pwd.h>
0026 #include <sched.h>
0027 #include <signal.h>
0028 #include <stdio.h>
0029 #include <stdlib.h>
0030 #include <string.h>
0031 #include <sys/param.h>
0032 #include <sys/proc.h>
0033 #include <sys/resource.h>
0034 #include <sys/types.h>
0035 #include <sys/user.h>
0036 #include <unistd.h>
0037 
0038 #define PROCESS_BUFFER_SIZE 512
0039 #define PROCDIR "/proc"
0040 
0041 namespace KSysGuard
0042 {
0043 class ProcessesLocal::Private
0044 {
0045 public:
0046     Private()
0047     {
0048         mProcDir = opendir(PROCDIR);
0049     };
0050     ~Private(){};
0051     char mBuf[PROCESS_BUFFER_SIZE + 1]; // used as a buffer to read data into
0052     DIR *mProcDir;
0053 };
0054 
0055 ProcessesLocal::ProcessesLocal()
0056     : d(new Private())
0057 {
0058 }
0059 
0060 long ProcessesLocal::getParentPid(long pid)
0061 {
0062     long long ppid = -1;
0063     int fd;
0064     psinfo_t psinfo;
0065 
0066     snprintf(d->mBuf, PROCESS_BUFFER_SIZE - 1, "%s/%ld/psinfo", PROCDIR, pid);
0067     if ((fd = open(d->mBuf, O_RDONLY)) < 0) {
0068         return -1; /* process has terminated in the meantime */
0069     }
0070 
0071     if (read(fd, &psinfo, sizeof(psinfo_t)) != sizeof(psinfo_t)) {
0072         close(fd);
0073         return -1;
0074     }
0075     close(fd);
0076     ppid = psinfo.pr_ppid;
0077 
0078     return ppid;
0079 }
0080 
0081 bool ProcessesLocal::updateProcessInfo(long pid, Process *process)
0082 {
0083     int fd, pfd;
0084     psinfo_t psinfo;
0085     prusage_t prusage;
0086 
0087     snprintf(d->mBuf, PROCESS_BUFFER_SIZE - 1, "%s/%ld/psinfo", PROCDIR, pid);
0088     if ((fd = open(d->mBuf, O_RDONLY)) < 0) {
0089         return false; /* process has terminated in the meantime */
0090     }
0091 
0092     snprintf(d->mBuf, PROCESS_BUFFER_SIZE - 1, "%s/%ld/usage", PROCDIR, pid);
0093     if ((pfd = open(d->mBuf, O_RDONLY)) < 0) {
0094         close(fd);
0095         return false; /* process has terminated in the meantime */
0096     }
0097 
0098     process->uid = 0;
0099     process->gid = 0;
0100     process->tracerpid = -1;
0101     process->pid() = pid;
0102 
0103     if (read(fd, &psinfo, sizeof(psinfo_t)) != sizeof(psinfo_t)) {
0104         close(fd);
0105         return false;
0106     }
0107     close(fd);
0108 
0109     if (read(pfd, &prusage, sizeof(prusage_t)) != sizeof(prusage_t)) {
0110         close(pfd);
0111         return false;
0112     }
0113     close(pfd);
0114 
0115     process->setUid(psinfo.pr_uid);
0116     process->setEuid(psinfo.pr_euid);
0117     process->setGid(psinfo.pr_gid);
0118     process->setEgid(psinfo.pr_egid);
0119 
0120     switch ((int)psinfo.pr_lwp.pr_state) {
0121     case SIDL:
0122     case SWAIT:
0123     case SSLEEP:
0124         process->setStatus(Process::Sleeping);
0125         break;
0126     case SONPROC:
0127     case SRUN:
0128         process->setStatus(Process::Running);
0129         break;
0130     case SZOMB:
0131         process->setStatus(Process::Zombie);
0132         break;
0133     case SSTOP:
0134         process->setStatus(Process::Stopped);
0135         break;
0136     default:
0137         process->setStatus(Process::OtherStatus);
0138         break;
0139     }
0140 
0141     process->setVmRSS(psinfo.pr_rssize);
0142     process->setVmSize(psinfo.pr_size);
0143     process->setVmURSS(-1);
0144 
0145     if (process->command.isNull()) {
0146         QString name(psinfo.pr_fname);
0147 
0148         name = name.trimmed();
0149         if (!name.isEmpty()) {
0150             name.remove(QRegExp("^[^ ]*/"));
0151         }
0152         process->setName(name);
0153         name = psinfo.pr_fname;
0154         name.append(psinfo.pr_psargs);
0155         process->setCommand(name);
0156     }
0157 
0158     // Approximations, not quite accurate. Needs more changes in ksysguard to map
0159     // RR and FIFO to current Solaris classes.
0160     if (strcmp(psinfo.pr_lwp.pr_clname, "TS") == 0 || strcmp(psinfo.pr_lwp.pr_clname, "SYS") == 0 || strcmp(psinfo.pr_lwp.pr_clname, "FSS") == 0) {
0161         process->setscheduler(KSysGuard::Process::Other);
0162 
0163     } else if (strcmp(psinfo.pr_lwp.pr_clname, "FX") == 0 || strcmp(psinfo.pr_lwp.pr_clname, "RT") == 0) {
0164         process->setscheduler(KSysGuard::Process::RoundRobin);
0165 
0166     } else if (strcmp(psinfo.pr_lwp.pr_clname, "IA") == 0) {
0167         process->setscheduler(KSysGuard::Process::Interactive);
0168     }
0169     process->setNiceLevel(psinfo.pr_lwp.pr_pri);
0170     process->setUserTime(prusage.pr_utime.tv_sec * 100 + prusage.pr_utime.tv_nsec / 10000000.0);
0171     process->setSysTime(prusage.pr_stime.tv_sec * 100 + prusage.pr_stime.tv_nsec / 10000000.0);
0172     return false;
0173 }
0174 
0175 QSet<long> ProcessesLocal::getAllPids()
0176 {
0177     QSet<long> pids;
0178     long pid;
0179 
0180     if (d->mProcDir == NULL) {
0181         return pids; // There's not much we can do without /proc
0182     }
0183     struct dirent *entry;
0184     rewinddir(d->mProcDir);
0185     while ((entry = readdir(d->mProcDir)))
0186         if (entry->d_name[0] >= '0' && entry->d_name[0] <= '9') {
0187             pid = atol(entry->d_name);
0188             // Skip all processes with parent id = 0 except init
0189             if (pid == 1 || getParentPid(pid) > 0) {
0190                 pids.insert(pid);
0191             }
0192         }
0193     return pids;
0194 }
0195 
0196 Processes::Error ProcessesLocal::sendSignal(long pid, int sig)
0197 {
0198     if (kill((pid_t)pid, sig)) {
0199         // Kill failed
0200         return Processes::Unknown;
0201     }
0202     return Processes::NoError;
0203 }
0204 
0205 /*
0206  *
0207  */
0208 Processes::Error ProcessesLocal::setNiceness(long pid, int priority)
0209 {
0210     return Processes::NotSupported;
0211 }
0212 
0213 Processes::Error ProcessesLocal::setScheduler(long pid, int priorityClass, int priority)
0214 {
0215     return Processes::NotSupported;
0216 }
0217 
0218 Processes::Error ProcessesLocal::setIoNiceness(long pid, int priorityClass, int priority)
0219 {
0220     return Processes::NotSupported; // Not yet supported
0221 }
0222 
0223 bool ProcessesLocal::supportsIoNiceness()
0224 {
0225     return false;
0226 }
0227 
0228 long long ProcessesLocal::totalPhysicalMemory()
0229 {
0230     long long memory = ((long long)sysconf(_SC_PHYS_PAGES)) * (sysconf(_SC_PAGESIZE) / 1024);
0231     if (memory > 0) {
0232         return memory;
0233     }
0234     return 0;
0235 }
0236 
0237 ProcessesLocal::~ProcessesLocal()
0238 {
0239     delete d;
0240 }
0241 
0242 }