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

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