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, ¶ms) == 0); 0251 break; 0252 case (KSysGuard::Process::RoundRobin): 0253 success = (sched_setscheduler(pid, SCHED_RR, ¶ms) == 0); 0254 break; 0255 case (KSysGuard::Process::Fifo): 0256 success = (sched_setscheduler(pid, SCHED_FIFO, ¶ms) == 0); 0257 break; 0258 #ifdef SCHED_BATCH 0259 case (KSysGuard::Process::Batch): 0260 success = (sched_setscheduler(pid, SCHED_BATCH, ¶ms) == 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 }