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 <sys/param.h>
0015 #include <sys/resource.h>
0016 #include <sys/sysctl.h>
0017 #include <sys/types.h>
0018 #include <sys/user.h>
0019 #if defined(__DragonFly__)
0020 #include <err.h>
0021 #include <sys/resourcevar.h>
0022 #endif
0023 #include <signal.h>
0024 #include <stdlib.h>
0025 #include <unistd.h>
0026 
0027 namespace KSysGuard
0028 {
0029 class ProcessesLocal::Private
0030 {
0031 public:
0032     Private()
0033     {
0034         ;
0035     }
0036     ~Private()
0037     {
0038         ;
0039     }
0040     inline bool readProc(long pid, struct kinfo_proc *p);
0041     inline void readProcStatus(struct kinfo_proc *p, Process *process);
0042     inline void readProcStat(struct kinfo_proc *p, Process *process);
0043     inline void readProcStatm(struct kinfo_proc *p, Process *process);
0044     inline bool readProcCmdline(long pid, Process *process);
0045 };
0046 
0047 bool ProcessesLocal::Private::readProc(long pid, struct kinfo_proc *p)
0048 {
0049     int mib[4];
0050     size_t len;
0051 
0052     mib[0] = CTL_KERN;
0053     mib[1] = KERN_PROC;
0054     mib[2] = KERN_PROC_PID;
0055     mib[3] = pid;
0056 
0057     len = sizeof(struct kinfo_proc);
0058     if (sysctl(mib, 4, p, &len, NULL, 0) == -1 || !len) {
0059         return false;
0060     }
0061     return true;
0062 }
0063 
0064 void ProcessesLocal::Private::readProcStatus(struct kinfo_proc *p, Process *process)
0065 {
0066     process->setUid(0);
0067     process->setGid(0);
0068     process->setTracerpid(-1);
0069 
0070 #if defined(__FreeBSD__) && __FreeBSD_version >= 500015
0071     process->setUid(p->ki_uid);
0072     process->setGid(p->ki_pgid);
0073     process->setName(QString(p->ki_comm ? p->ki_comm : "????"));
0074 #elif defined(__DragonFly__) && __DragonFly_version >= 190000
0075     process->setUid(p->kp_uid);
0076     process->setGid(p->kp_pgid);
0077     process->setName(QString(p->kp_comm ? p->kp_comm : "????"));
0078 #else
0079     process->setUid(p->kp_eproc.e_ucred.cr_uid);
0080     process->setGid(p->kp_eproc.e_pgid);
0081 #endif
0082 }
0083 
0084 void ProcessesLocal::Private::readProcStat(struct kinfo_proc *p, Process *ps)
0085 {
0086     int status;
0087     struct rusage pru;
0088 #if defined(__FreeBSD__) && __FreeBSD_version >= 500015
0089     ps->setUserTime(p->ki_runtime / 10000);
0090     ps->setNiceLevel(p->ki_nice);
0091     ps->setVmSize(p->ki_size);
0092     ps->setVmRSS(p->ki_rssize * getpagesize());
0093     status = p->ki_stat;
0094 #elif defined(__DragonFly__) && __DragonFly_version >= 190000
0095     if (!getrusage(p->kp_pid, &pru)) {
0096         errx(1, "failed to get rusage info");
0097     }
0098     ps->setUserTime(pru.ru_utime.tv_usec / 1000); /*p_runtime / 1000*/
0099     ps->setNiceLevel(p->kp_nice);
0100     ps->setVmSize(p->kp_vm_map_size);
0101     ps->setVmRSS(p->kp_vm_rssize * getpagesize());
0102     status = p->kp_stat;
0103 #else
0104     ps->setUserTime(p->kp_proc.p_rtime.tv_sec * 100 + p->kp_proc.p_rtime.tv_usec / 100);
0105     ps->setNiceLevel(p->kp_proc.p_nice);
0106     ps->setVmSize(p->kp_eproc.e_vm.vm_map.size);
0107     ps->setVmRSS(p->kp_eproc.e_vm.vm_rssize * getpagesize());
0108     status = p->kp_proc.p_stat;
0109 #endif
0110     ps->setSysTime(0);
0111 
0112     // "idle","run","sleep","stop","zombie"
0113     switch (status) {
0114     case '0':
0115         ps->setStatus(Process::DiskSleep);
0116         break;
0117     case '1':
0118         ps->setStatus(Process::Running);
0119         break;
0120     case '2':
0121         ps->setStatus(Process::Sleeping);
0122         break;
0123     case '3':
0124         ps->setStatus(Process::Stopped);
0125         break;
0126     case '4':
0127         ps->setStatus(Process::Zombie);
0128         break;
0129     default:
0130         ps->setStatus(Process::OtherStatus);
0131         break;
0132     }
0133 }
0134 
0135 void ProcessesLocal::Private::readProcStatm(struct kinfo_proc *p, Process *process)
0136 {
0137     // TODO
0138 
0139     //     unsigned long shared;
0140     //     process->setVmURSS(process->vmRSS - (shared * sysconf(_SC_PAGESIZE) / 1024));
0141 }
0142 
0143 bool ProcessesLocal::Private::readProcCmdline(long pid, Process *process)
0144 {
0145     int mib[4];
0146     struct kinfo_proc p;
0147     size_t buflen = 256;
0148     char buf[256];
0149 
0150     mib[0] = CTL_KERN;
0151     mib[1] = KERN_PROC;
0152     mib[2] = KERN_PROC_ARGS;
0153     mib[3] = pid;
0154 
0155     if (sysctl(mib, 4, buf, &buflen, NULL, 0) == -1 || !buflen) {
0156         return false;
0157     }
0158     QString command = QString(buf);
0159 
0160     // cmdline separates parameters with the NULL character
0161     command.replace('\0', ' ');
0162     process->setCommand(command.trimmed());
0163 
0164     return true;
0165 }
0166 
0167 ProcessesLocal::ProcessesLocal()
0168     : d(new Private())
0169 {
0170 }
0171 
0172 long ProcessesLocal::getParentPid(long pid)
0173 {
0174     Q_ASSERT(pid != 0);
0175     long long ppid = -1;
0176     struct kinfo_proc p;
0177     if (d->readProc(pid, &p)) {
0178 #if defined(__FreeBSD__) && __FreeBSD_version >= 500015
0179         ppid = p.ki_ppid;
0180 #elif defined(__DragonFly__) && __DragonFly_version >= 190000
0181         ppid = p.kp_ppid;
0182 #else
0183         ppid = p.kp_eproc.e_ppid;
0184 #endif
0185     }
0186     return ppid;
0187 }
0188 
0189 bool ProcessesLocal::updateProcessInfo(long pid, Process *process)
0190 {
0191     struct kinfo_proc p;
0192     if (!d->readProc(pid, &p)) {
0193         return false;
0194     }
0195     d->readProcStat(&p, process);
0196     d->readProcStatus(&p, process);
0197     d->readProcStatm(&p, process);
0198     if (!d->readProcCmdline(pid, process)) {
0199         return false;
0200     }
0201 
0202     return true;
0203 }
0204 
0205 QSet<long> ProcessesLocal::getAllPids()
0206 {
0207     QSet<long> pids;
0208     int mib[3];
0209     size_t len;
0210     size_t num;
0211     struct kinfo_proc *p;
0212 
0213     mib[0] = CTL_KERN;
0214     mib[1] = KERN_PROC;
0215     mib[2] = KERN_PROC_ALL;
0216     sysctl(mib, 3, NULL, &len, NULL, 0);
0217     p = (kinfo_proc *)malloc(len);
0218     sysctl(mib, 3, p, &len, NULL, 0);
0219 
0220     for (num = 0; num < len / sizeof(struct kinfo_proc); num++) {
0221 #if defined(__FreeBSD__) && __FreeBSD_version >= 500015
0222         pids.insert(p[num].ki_pid);
0223 #elif defined(__DragonFly__) && __DragonFly_version >= 190000
0224         pids.insert(p[num].kp_pid);
0225 #else
0226         pids.insert(p[num].kp_proc.p_pid);
0227 #endif
0228     }
0229     free(p);
0230     return pids;
0231 }
0232 
0233 Processes::Error ProcessesLocal::sendSignal(long pid, int sig)
0234 {
0235     if (kill((pid_t)pid, sig)) {
0236         // Kill failed
0237         return Processes::Unknown;
0238     }
0239     return Processes::NoError;
0240 }
0241 
0242 Processes::Error ProcessesLocal::setNiceness(long pid, int priority)
0243 {
0244     if (setpriority(PRIO_PROCESS, pid, priority)) {
0245         // set niceness failed
0246         return Processes::Unknown;
0247     }
0248     return Processes::NoError;
0249 }
0250 
0251 Processes::Error ProcessesLocal::setScheduler(long pid, int priorityClass, int priority)
0252 {
0253     if (priorityClass == KSysGuard::Process::Other || priorityClass == KSysGuard::Process::Batch) {
0254         priority = 0;
0255     }
0256     if (pid <= 0) {
0257         return Processes::InvalidPid; // check the parameters
0258     }
0259     return Processes::NotSupported;
0260 }
0261 
0262 Processes::Error ProcessesLocal::setIoNiceness(long pid, int priorityClass, int priority)
0263 {
0264     return Processes::NotSupported; // Not yet supported
0265 }
0266 
0267 bool ProcessesLocal::supportsIoNiceness()
0268 {
0269     return false;
0270 }
0271 
0272 long long ProcessesLocal::totalPhysicalMemory()
0273 {
0274     static int physmem_mib[] = {CTL_HW, HW_PHYSMEM};
0275     /* get the page size with "getpagesize" and calculate pageshift from
0276      * it */
0277     int pagesize = ::getpagesize();
0278     int pageshift = 0;
0279     while (pagesize > 1) {
0280         pageshift++;
0281         pagesize >>= 1;
0282     }
0283     size_t Total = 0;
0284     size_t size = sizeof(Total);
0285     sysctl(physmem_mib, 2, &Total, &size, NULL, 0);
0286     return Total /= 1024;
0287 }
0288 
0289 long int KSysGuard::ProcessesLocal::numberProcessorCores()
0290 {
0291     int mib[2];
0292     int ncpu;
0293     size_t len;
0294 
0295     mib[0] = CTL_HW;
0296     mib[1] = HW_NCPU;
0297     len = sizeof(ncpu);
0298 
0299     if (sysctl(mib, 2, &ncpu, &len, NULL, 0) == -1 || !len) {
0300         return 1;
0301     }
0302     return len;
0303 }
0304 ProcessesLocal::~ProcessesLocal()
0305 {
0306     delete d;
0307 }
0308 
0309 }