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

0001 /*
0002     SPDX-FileCopyrightText: 2007 Manolo Valdes <nolis71cu@gmail.com>
0003     SPDX-FileCopyrightText: 2007 Mark Davies <mark@mcs.vuw.ac.nz>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-or-later
0006 */
0007 
0008 #include "process.h"
0009 #include "processes_local_p.h"
0010 
0011 #include <KLocalizedString>
0012 
0013 #include <QSet>
0014 
0015 #include <kvm.h>
0016 #include <sched.h>
0017 #include <signal.h>
0018 #include <stdlib.h>
0019 #include <sys/param.h>
0020 #include <sys/stat.h>
0021 #include <sys/sysctl.h>
0022 #include <sys/types.h>
0023 #include <sys/user.h>
0024 #include <unistd.h>
0025 
0026 namespace KSysGuard
0027 {
0028 class ProcessesLocal::Private
0029 {
0030 public:
0031     Private()
0032     {
0033         kd = kvm_open(NULL, NULL, NULL, KVM_NO_FILES, "kvm_open");
0034     }
0035     ~Private()
0036     {
0037         kvm_close(kd);
0038     }
0039     inline bool readProc(long pid, struct kinfo_proc2 **p, int *num);
0040     inline void readProcStatus(struct kinfo_proc2 *p, Process *process);
0041     inline void readProcStat(struct kinfo_proc2 *p, Process *process);
0042     inline void readProcStatm(struct kinfo_proc2 *p, Process *process);
0043     inline bool readProcCmdline(struct kinfo_proc2 *p, Process *process);
0044 
0045     kvm_t *kd;
0046 };
0047 
0048 #ifndef _SC_NPROCESSORS_ONLN
0049 long int KSysGuard::ProcessesLocal::numberProcessorCores()
0050 {
0051     int mib[2];
0052     int ncpu;
0053     size_t len;
0054 
0055     mib[0] = CTL_HW;
0056     mib[1] = HW_NCPU;
0057     len = sizeof(ncpu);
0058 
0059     if (sysctl(mib, 2, &ncpu, &len, NULL, 0) == -1 || !len) {
0060         return 1;
0061     }
0062     return len;
0063 }
0064 #endif
0065 
0066 bool ProcessesLocal::Private::readProc(long pid, struct kinfo_proc2 **p, int *num)
0067 {
0068     int len;
0069     int op, arg;
0070 
0071     if (pid == 0) {
0072         op = KERN_PROC_ALL;
0073         arg = 0;
0074     } else {
0075         op = KERN_PROC_PID;
0076         arg = pid;
0077     }
0078     *p = kvm_getproc2(kd, op, arg, sizeof(struct kinfo_proc2), &len);
0079 
0080     if (len < 1) {
0081         return false;
0082     }
0083 
0084     if (num != NULL) {
0085         *num = len;
0086     }
0087     return true;
0088 }
0089 
0090 void ProcessesLocal::Private::readProcStatus(struct kinfo_proc2 *p, Process *process)
0091 {
0092     process->setUid(p->p_ruid);
0093     process->setEuid(p->p_uid);
0094     process->setGid(p->p_rgid);
0095     process->setEgid(p->p_gid);
0096     process->setTracerpid(-1);
0097 
0098     process->setName(QString(p->p_comm ? p->p_comm : "????"));
0099 }
0100 
0101 void ProcessesLocal::Private::readProcStat(struct kinfo_proc2 *p, Process *ps)
0102 {
0103     const char *ttname;
0104     dev_t dev;
0105 
0106     ps->setUserTime(p->p_uutime_sec * 100 + p->p_uutime_usec / 10000);
0107     ps->setSysTime(p->p_ustime_sec * 100 + p->p_ustime_usec / 10000);
0108 
0109     ps->setUserUsage(100.0 * ((double)(p->p_pctcpu) / FSCALE));
0110     ps->setSysUsage(0);
0111 
0112     ps->setNiceLevel(p->p_nice - NZERO);
0113     ps->setVmSize((p->p_vm_tsize + p->p_vm_dsize + p->p_vm_ssize) * getpagesize());
0114     ps->setVmRSS(p->p_vm_rssize * getpagesize());
0115 
0116     // "idle","run","sleep","stop","zombie"
0117     switch (p->p_stat) {
0118     case LSRUN:
0119         ps->setStatus(Process::Running);
0120         break;
0121     case LSSLEEP:
0122         ps->setStatus(Process::Sleeping);
0123         break;
0124     case LSSTOP:
0125         ps->setStatus(Process::Stopped);
0126         break;
0127     case LSZOMB:
0128         ps->setStatus(Process::Zombie);
0129         break;
0130     case LSONPROC:
0131         ps->setStatus(Process::Running);
0132         break;
0133     default:
0134         ps->setStatus(Process::OtherStatus);
0135         break;
0136     }
0137 
0138     dev = p->p_tdev;
0139     if (dev == NODEV || (ttname = devname(dev, S_IFCHR)) == NULL) {
0140         ps->setTty(QByteArray());
0141     } else {
0142         ps->setTty(QByteArray(ttname));
0143     }
0144 }
0145 
0146 void ProcessesLocal::Private::readProcStatm(struct kinfo_proc2 *p, Process *process)
0147 {
0148     // TODO
0149 
0150     //     unsigned long shared;
0151     //     process->vmURSS = process->vmRSS - (shared * sysconf(_SC_PAGESIZE) / 1024);
0152     process->setVmURSS(-1);
0153 }
0154 
0155 bool ProcessesLocal::Private::readProcCmdline(struct kinfo_proc2 *p, Process *process)
0156 {
0157     char **argv;
0158 
0159     if ((argv = kvm_getargv2(kd, p, 256)) == NULL) {
0160         return false;
0161     }
0162 
0163     QString command = QString("");
0164 
0165     while (*argv) {
0166         command += *argv;
0167         command += " ";
0168         argv++;
0169     }
0170     process->setCommand(command.trimmed());
0171 
0172     return true;
0173 }
0174 
0175 ProcessesLocal::ProcessesLocal()
0176     : d(new Private())
0177 {
0178 }
0179 
0180 long ProcessesLocal::getParentPid(long pid)
0181 {
0182     long long ppid = -1;
0183     struct kinfo_proc2 *p;
0184     if (d->readProc(pid, &p, 0)) {
0185         ppid = p->p_ppid;
0186     }
0187     return ppid;
0188 }
0189 
0190 bool ProcessesLocal::updateProcessInfo(long pid, Process *process)
0191 {
0192     struct kinfo_proc2 *p;
0193     if (!d->readProc(pid, &p, NULL)) {
0194         return false;
0195     }
0196     d->readProcStat(p, process);
0197     d->readProcStatus(p, process);
0198     d->readProcStatm(p, process);
0199     if (!d->readProcCmdline(p, process)) {
0200         return false;
0201     }
0202 
0203     return true;
0204 }
0205 
0206 QSet<long> ProcessesLocal::getAllPids()
0207 {
0208     QSet<long> pids;
0209     int len;
0210     int num;
0211     struct kinfo_proc2 *p;
0212 
0213     d->readProc(0, &p, &len);
0214 
0215     for (num = 0; num < len; num++) {
0216         long pid = p[num].p_pid;
0217         long long ppid = p[num].p_ppid;
0218 
0219         // skip all process with parent id = 0 but init
0220         if (ppid <= 0 && pid != 1) {
0221             continue;
0222         }
0223         pids.insert(pid);
0224     }
0225     return pids;
0226 }
0227 
0228 Processes::Error ProcessesLocal::sendSignal(long pid, int sig)
0229 {
0230     if (kill((pid_t)pid, sig)) {
0231         // Kill failed
0232         return Processes::Unknown;
0233     }
0234     return Processes::NoError;
0235 }
0236 
0237 Processes::Error ProcessesLocal::setNiceness(long pid, int priority)
0238 {
0239     if (setpriority(PRIO_PROCESS, pid, priority)) {
0240         // set niceness failed
0241         return Processes::Unknown;
0242     }
0243     return Processes::NoError;
0244 }
0245 
0246 Processes::Error ProcessesLocal::setScheduler(long pid, int priorityClass, int priority)
0247 {
0248     if (priorityClass == KSysGuard::Process::Other || priorityClass == KSysGuard::Process::Batch) {
0249         priority = 0;
0250     }
0251     if (pid <= 0) {
0252         return Processes::InvalidPid; // check the parameters
0253     }
0254     struct sched_param params;
0255     params.sched_priority = priority;
0256     bool success;
0257     switch (priorityClass) {
0258     case (KSysGuard::Process::Other):
0259         success = (sched_setscheduler(pid, SCHED_OTHER, &params) == 0);
0260         break;
0261     case (KSysGuard::Process::RoundRobin):
0262         success = (sched_setscheduler(pid, SCHED_RR, &params) == 0);
0263         break;
0264     case (KSysGuard::Process::Fifo):
0265         success = (sched_setscheduler(pid, SCHED_FIFO, &params) == 0);
0266         break;
0267 #ifdef SCHED_BATCH
0268     case (KSysGuard::Process::Batch):
0269         success = (sched_setscheduler(pid, SCHED_BATCH, &params) == 0);
0270         break;
0271 #endif
0272     }
0273     if (success) {
0274         return Processes::NoError;
0275     }
0276     return Processes::Unknown;
0277 }
0278 
0279 Processes::Error ProcessesLocal::setIoNiceness(long pid, int priorityClass, int priority)
0280 {
0281     return Processes::NotSupported; // Not yet supported
0282 }
0283 
0284 bool ProcessesLocal::supportsIoNiceness()
0285 {
0286     return false;
0287 }
0288 
0289 long long ProcessesLocal::totalPhysicalMemory()
0290 {
0291     size_t Total;
0292     size_t len;
0293     len = sizeof(Total);
0294     sysctlbyname("hw.physmem", &Total, &len, NULL, 0);
0295     return Total /= 1024;
0296 }
0297 
0298 ProcessesLocal::~ProcessesLocal()
0299 {
0300     delete d;
0301 }
0302 
0303 }