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

0001 /*
0002     SPDX-FileCopyrightText: 2007 Manolo Valdes <nolis71cu@gmail.com>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "process.h"
0008 #include "processes_local_p.h"
0009 
0010 #include <KLocalizedString>
0011 
0012 #include <QSet>
0013 
0014 #include <sched.h>
0015 #include <signal.h>
0016 #include <stdlib.h>
0017 #include <sys/param.h>
0018 #include <sys/resource.h>
0019 #include <sys/sysctl.h>
0020 #include <sys/types.h>
0021 #include <sys/user.h>
0022 #include <unistd.h>
0023 
0024 namespace KSysGuard
0025 {
0026 class ProcessesLocal::Private
0027 {
0028 public:
0029     Private()
0030     {
0031         ;
0032     }
0033     ~Private()
0034     {
0035         ;
0036     }
0037     inline bool readProc(long pid, struct kinfo_proc *p);
0038     inline void readProcStatus(struct kinfo_proc *p, Process *process);
0039     inline void readProcStat(struct kinfo_proc *p, Process *process);
0040     inline void readProcStatm(struct kinfo_proc *p, Process *process);
0041     inline bool readProcCmdline(long pid, Process *process);
0042 };
0043 
0044 bool ProcessesLocal::Private::readProc(long pid, struct kinfo_proc *p)
0045 {
0046     int mib[4];
0047     size_t len;
0048 
0049     mib[0] = CTL_KERN;
0050     mib[1] = KERN_PROC;
0051     mib[2] = KERN_PROC_PID;
0052     mib[3] = pid;
0053 
0054     len = sizeof(struct kinfo_proc);
0055     if (sysctl(mib, 4, p, &len, NULL, 0) == -1 || !len) {
0056         return false;
0057     }
0058     return true;
0059 }
0060 
0061 void ProcessesLocal::Private::readProcStatus(struct kinfo_proc *p, Process *process)
0062 {
0063     process->setUid(0);
0064     process->setGid(0);
0065     process->setTracerpid(-1);
0066 
0067     process->setEuid(p->ki_uid);
0068     process->setUid(p->ki_ruid);
0069     process->setEgid(p->ki_svgid);
0070     process->setGid(p->ki_rgid);
0071     process->setName(QString::fromUtf8(p->ki_comm ? p->ki_comm : "????"));
0072 }
0073 
0074 void ProcessesLocal::Private::readProcStat(struct kinfo_proc *p, Process *ps)
0075 {
0076     int status;
0077     struct rusage pru;
0078 
0079     ps->setUserTime(p->ki_rusage.ru_utime.tv_sec * 100 + p->ki_rusage.ru_utime.tv_usec / 10000);
0080     ps->setSysTime(p->ki_rusage.ru_stime.tv_sec * 100 + p->ki_rusage.ru_stime.tv_usec / 10000);
0081     ps->setNiceLevel(p->ki_nice);
0082     ps->setVmSize(p->ki_size / 1024);
0083     ps->setVmRSS(p->ki_rssize * getpagesize() / 1024);
0084     status = p->ki_stat;
0085 
0086     // "idle","run","sleep","stop","zombie"
0087     switch (status) {
0088     case SRUN:
0089         ps->setStatus(Process::Running);
0090         break;
0091     case SSLEEP:
0092     case SWAIT:
0093     case SLOCK:
0094         ps->setStatus(Process::Sleeping);
0095         break;
0096     case SSTOP:
0097         ps->setStatus(Process::Stopped);
0098         break;
0099     case SZOMB:
0100         ps->setStatus(Process::Zombie);
0101         break;
0102     default:
0103         ps->setStatus(Process::OtherStatus);
0104         break;
0105     }
0106 }
0107 
0108 void ProcessesLocal::Private::readProcStatm(struct kinfo_proc *p, Process *process)
0109 {
0110     process->setVmURSS(-1);
0111 }
0112 
0113 bool ProcessesLocal::Private::readProcCmdline(long pid, Process *process)
0114 {
0115     int mib[4];
0116     struct kinfo_proc p;
0117     size_t buflen = 256;
0118     char buf[256];
0119 
0120     mib[0] = CTL_KERN;
0121     mib[1] = KERN_PROC;
0122     mib[2] = KERN_PROC_ARGS;
0123     mib[3] = pid;
0124 
0125     if (sysctl(mib, 4, buf, &buflen, NULL, 0) == -1 || !buflen) {
0126         return false;
0127     }
0128     QString command = QString::fromUtf8(buf);
0129 
0130     // cmdline separates parameters with the NULL character
0131     command.replace(QLatin1Char('\0'), QLatin1Char(' '));
0132     process->setCommand(command.trimmed());
0133 
0134     return true;
0135 }
0136 
0137 ProcessesLocal::ProcessesLocal()
0138     : d(new Private())
0139 {
0140 }
0141 
0142 long ProcessesLocal::getParentPid(long pid)
0143 {
0144     long long ppid = 0;
0145     struct kinfo_proc p;
0146     if (d->readProc(pid, &p)) {
0147         ppid = p.ki_ppid;
0148     }
0149     return ppid;
0150 }
0151 
0152 bool ProcessesLocal::updateProcessInfo(long pid, Process *process)
0153 {
0154     struct kinfo_proc p;
0155     if (!d->readProc(pid, &p)) {
0156         return false;
0157     }
0158     d->readProcStat(&p, process);
0159     d->readProcStatus(&p, process);
0160     d->readProcStatm(&p, process);
0161     if (!d->readProcCmdline(pid, process)) {
0162         return false;
0163     }
0164 
0165     return true;
0166 }
0167 
0168 QSet<long> ProcessesLocal::getAllPids()
0169 {
0170     QSet<long> pids;
0171     int mib[3];
0172     size_t len;
0173     size_t num;
0174     struct kinfo_proc *p;
0175 
0176     mib[0] = CTL_KERN;
0177     mib[1] = KERN_PROC;
0178     mib[2] = KERN_PROC_ALL;
0179     if (sysctl(mib, 3, NULL, &len, NULL, 0) == -1) {
0180         return pids;
0181     }
0182     if ((p = (kinfo_proc *)malloc(len)) == NULL) {
0183         return pids;
0184     }
0185     if (sysctl(mib, 3, p, &len, NULL, 0) == -1) {
0186         free(p);
0187         return pids;
0188     }
0189 
0190     for (num = 0; num < len / sizeof(struct kinfo_proc); num++) {
0191         long pid = p[num].ki_pid;
0192         long long ppid = p[num].ki_ppid;
0193 
0194         // skip all process with parent id = 0 but init
0195         if (ppid <= 0 && pid != 1) {
0196             continue;
0197         }
0198         pids.insert(pid);
0199     }
0200     free(p);
0201     return pids;
0202 }
0203 
0204 Processes::Error ProcessesLocal::sendSignal(long pid, int sig)
0205 {
0206     if (kill((pid_t)pid, sig)) {
0207         // Kill failed
0208         return Processes::Unknown;
0209     }
0210     return Processes::NoError;
0211 }
0212 
0213 Processes::Error ProcessesLocal::setNiceness(long pid, int priority)
0214 {
0215     if (setpriority(PRIO_PROCESS, pid, priority)) {
0216         // set niceness failed
0217         return Processes::Unknown;
0218     }
0219     return Processes::NoError;
0220 }
0221 
0222 Processes::Error ProcessesLocal::setScheduler(long pid, int priorityClass, int priority)
0223 {
0224     if (priorityClass == KSysGuard::Process::Other || priorityClass == KSysGuard::Process::Batch) {
0225         priority = 0;
0226     }
0227     if (pid <= 0) {
0228         return Processes::InvalidPid; // check the parameters
0229     }
0230     struct sched_param params;
0231     params.sched_priority = priority;
0232     bool success = false;
0233     switch (priorityClass) {
0234     case (KSysGuard::Process::Other):
0235         success = (sched_setscheduler(pid, SCHED_OTHER, &params) == 0);
0236         break;
0237     case (KSysGuard::Process::RoundRobin):
0238         success = (sched_setscheduler(pid, SCHED_RR, &params) == 0);
0239         break;
0240     case (KSysGuard::Process::Fifo):
0241         success = (sched_setscheduler(pid, SCHED_FIFO, &params) == 0);
0242         break;
0243 #ifdef SCHED_BATCH
0244     case (KSysGuard::Process::Batch):
0245         success = (sched_setscheduler(pid, SCHED_BATCH, &params) == 0);
0246         break;
0247 #endif
0248     }
0249     if (success) {
0250         return Processes::NoError;
0251     }
0252     return Processes::Unknown;
0253 }
0254 
0255 Processes::Error ProcessesLocal::setIoNiceness(long pid, int priorityClass, int priority)
0256 {
0257     return Processes::NotSupported; // Not yet supported
0258 }
0259 
0260 bool ProcessesLocal::supportsIoNiceness()
0261 {
0262     return false;
0263 }
0264 
0265 long long ProcessesLocal::totalPhysicalMemory()
0266 {
0267     size_t Total;
0268     size_t len;
0269 
0270     len = sizeof(Total);
0271     if (sysctlbyname("hw.physmem", &Total, &len, NULL, 0) == -1) {
0272         return 0;
0273     }
0274 
0275     return Total /= 1024;
0276 }
0277 
0278 ProcessesLocal::~ProcessesLocal()
0279 {
0280     delete d;
0281 }
0282 
0283 }