File indexing completed on 2024-04-28 16:49:57

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     struct dirent *entry;
0183     rewinddir(d->mProcDir);
0184     while ((entry = readdir(d->mProcDir)))
0185         if (entry->d_name[0] >= '0' && entry->d_name[0] <= '9') {
0186             pid = atol(entry->d_name);
0187             // Skip all processes with parent id = 0 except init
0188             if (pid == 1 || getParentPid(pid) > 0) {
0189                 pids.insert(pid);
0190             }
0191         }
0192     return pids;
0193 }
0194 
0195 Processes::Error ProcessesLocal::sendSignal(long pid, int sig)
0196 {
0197     if (kill((pid_t)pid, sig)) {
0198         // Kill failed
0199         return Processes::Unknown;
0200     }
0201     return Processes::NoError;
0202 }
0203 
0204 /*
0205  *
0206  */
0207 Processes::Error ProcessesLocal::setNiceness(long pid, int priority)
0208 {
0209     return Processes::NotSupported;
0210 }
0211 
0212 Processes::Error ProcessesLocal::setScheduler(long pid, int priorityClass, int priority)
0213 {
0214     return Processes::NotSupported;
0215 }
0216 
0217 Processes::Error ProcessesLocal::setIoNiceness(long pid, int priorityClass, int priority)
0218 {
0219     return Processes::NotSupported; // Not yet supported
0220 }
0221 
0222 bool ProcessesLocal::supportsIoNiceness()
0223 {
0224     return false;
0225 }
0226 
0227 long long ProcessesLocal::totalPhysicalMemory()
0228 {
0229     long long memory = ((long long)sysconf(_SC_PHYS_PAGES)) * (sysconf(_SC_PAGESIZE) / 1024);
0230     if (memory > 0)
0231         return memory;
0232     return 0;
0233 }
0234 
0235 ProcessesLocal::~ProcessesLocal()
0236 {
0237     delete d;
0238 }
0239 
0240 }