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

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     return len;
0062 }
0063 #endif
0064 
0065 bool ProcessesLocal::Private::readProc(long pid, struct kinfo_proc2 **p, int *num)
0066 {
0067     int len;
0068     int op, arg;
0069 
0070     if (pid == 0) {
0071         op = KERN_PROC_ALL;
0072         arg = 0;
0073     } else {
0074         op = KERN_PROC_PID;
0075         arg = pid;
0076     }
0077     *p = kvm_getproc2(kd, op, arg, sizeof(struct kinfo_proc2), &len);
0078 
0079     if (len < 1)
0080         return false;
0081 
0082     if (num != NULL)
0083         *num = len;
0084     return true;
0085 }
0086 
0087 void ProcessesLocal::Private::readProcStatus(struct kinfo_proc2 *p, Process *process)
0088 {
0089     process->setUid(p->p_ruid);
0090     process->setEuid(p->p_uid);
0091     process->setGid(p->p_rgid);
0092     process->setEgid(p->p_gid);
0093     process->setTracerpid(-1);
0094 
0095     process->setName(QString(p->p_comm ? p->p_comm : "????"));
0096 }
0097 
0098 void ProcessesLocal::Private::readProcStat(struct kinfo_proc2 *p, Process *ps)
0099 {
0100     const char *ttname;
0101     dev_t dev;
0102 
0103     ps->setUserTime(p->p_uutime_sec * 100 + p->p_uutime_usec / 10000);
0104     ps->setSysTime(p->p_ustime_sec * 100 + p->p_ustime_usec / 10000);
0105 
0106     ps->setUserUsage(100.0 * ((double)(p->p_pctcpu) / FSCALE));
0107     ps->setSysUsage(0);
0108 
0109     ps->setNiceLevel(p->p_nice - NZERO);
0110     ps->setVmSize((p->p_vm_tsize + p->p_vm_dsize + p->p_vm_ssize) * getpagesize());
0111     ps->setVmRSS(p->p_vm_rssize * getpagesize());
0112 
0113     // "idle","run","sleep","stop","zombie"
0114     switch (p->p_stat) {
0115     case LSRUN:
0116         ps->setStatus(Process::Running);
0117         break;
0118     case LSSLEEP:
0119         ps->setStatus(Process::Sleeping);
0120         break;
0121     case LSSTOP:
0122         ps->setStatus(Process::Stopped);
0123         break;
0124     case LSZOMB:
0125         ps->setStatus(Process::Zombie);
0126         break;
0127     case LSONPROC:
0128         ps->setStatus(Process::Running);
0129         break;
0130     default:
0131         ps->setStatus(Process::OtherStatus);
0132         break;
0133     }
0134 
0135     dev = p->p_tdev;
0136     if (dev == NODEV || (ttname = devname(dev, S_IFCHR)) == NULL) {
0137         ps->setTty(QByteArray());
0138     } else {
0139         ps->setTty(QByteArray(ttname));
0140     }
0141 }
0142 
0143 void ProcessesLocal::Private::readProcStatm(struct kinfo_proc2 *p, Process *process)
0144 {
0145     // TODO
0146 
0147     //     unsigned long shared;
0148     //     process->vmURSS = process->vmRSS - (shared * sysconf(_SC_PAGESIZE) / 1024);
0149     process->setVmURSS(-1);
0150 }
0151 
0152 bool ProcessesLocal::Private::readProcCmdline(struct kinfo_proc2 *p, Process *process)
0153 {
0154     char **argv;
0155 
0156     if ((argv = kvm_getargv2(kd, p, 256)) == NULL)
0157         return false;
0158 
0159     QString command = QString("");
0160 
0161     while (*argv) {
0162         command += *argv;
0163         command += " ";
0164         argv++;
0165     }
0166     process->setCommand(command.trimmed());
0167 
0168     return true;
0169 }
0170 
0171 ProcessesLocal::ProcessesLocal()
0172     : d(new Private())
0173 {
0174 }
0175 
0176 long ProcessesLocal::getParentPid(long pid)
0177 {
0178     long long ppid = -1;
0179     struct kinfo_proc2 *p;
0180     if (d->readProc(pid, &p, 0)) {
0181         ppid = p->p_ppid;
0182     }
0183     return ppid;
0184 }
0185 
0186 bool ProcessesLocal::updateProcessInfo(long pid, Process *process)
0187 {
0188     struct kinfo_proc2 *p;
0189     if (!d->readProc(pid, &p, NULL))
0190         return false;
0191     d->readProcStat(p, process);
0192     d->readProcStatus(p, process);
0193     d->readProcStatm(p, process);
0194     if (!d->readProcCmdline(p, process))
0195         return false;
0196 
0197     return true;
0198 }
0199 
0200 QSet<long> ProcessesLocal::getAllPids()
0201 {
0202     QSet<long> pids;
0203     int len;
0204     int num;
0205     struct kinfo_proc2 *p;
0206 
0207     d->readProc(0, &p, &len);
0208 
0209     for (num = 0; num < len; num++) {
0210         long pid = p[num].p_pid;
0211         long long ppid = p[num].p_ppid;
0212 
0213         // skip all process with parent id = 0 but init
0214         if (ppid <= 0 && pid != 1)
0215             continue;
0216         pids.insert(pid);
0217     }
0218     return pids;
0219 }
0220 
0221 Processes::Error ProcessesLocal::sendSignal(long pid, int sig)
0222 {
0223     if (kill((pid_t)pid, sig)) {
0224         // Kill failed
0225         return Processes::Unknown;
0226     }
0227     return Processes::NoError;
0228 }
0229 
0230 Processes::Error ProcessesLocal::setNiceness(long pid, int priority)
0231 {
0232     if (setpriority(PRIO_PROCESS, pid, priority)) {
0233         // set niceness failed
0234         return Processes::Unknown;
0235     }
0236     return Processes::NoError;
0237 }
0238 
0239 Processes::Error ProcessesLocal::setScheduler(long pid, int priorityClass, int priority)
0240 {
0241     if (priorityClass == KSysGuard::Process::Other || priorityClass == KSysGuard::Process::Batch)
0242         priority = 0;
0243     if (pid <= 0)
0244         return Processes::InvalidPid; // check the parameters
0245     struct sched_param params;
0246     params.sched_priority = priority;
0247     bool success;
0248     switch (priorityClass) {
0249     case (KSysGuard::Process::Other):
0250         success = (sched_setscheduler(pid, SCHED_OTHER, &params) == 0);
0251         break;
0252     case (KSysGuard::Process::RoundRobin):
0253         success = (sched_setscheduler(pid, SCHED_RR, &params) == 0);
0254         break;
0255     case (KSysGuard::Process::Fifo):
0256         success = (sched_setscheduler(pid, SCHED_FIFO, &params) == 0);
0257         break;
0258 #ifdef SCHED_BATCH
0259     case (KSysGuard::Process::Batch):
0260         success = (sched_setscheduler(pid, SCHED_BATCH, &params) == 0);
0261         break;
0262 #endif
0263     }
0264     if (success) {
0265         return Processes::NoError;
0266     }
0267     return Processes::Unknown;
0268 }
0269 
0270 Processes::Error ProcessesLocal::setIoNiceness(long pid, int priorityClass, int priority)
0271 {
0272     return Processes::NotSupported; // Not yet supported
0273 }
0274 
0275 bool ProcessesLocal::supportsIoNiceness()
0276 {
0277     return false;
0278 }
0279 
0280 long long ProcessesLocal::totalPhysicalMemory()
0281 {
0282     size_t Total;
0283     size_t len;
0284     len = sizeof(Total);
0285     sysctlbyname("hw.physmem", &Total, &len, NULL, 0);
0286     return Total /= 1024;
0287 }
0288 
0289 ProcessesLocal::~ProcessesLocal()
0290 {
0291     delete d;
0292 }
0293 
0294 }