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, ¶ms) == 0); 0260 break; 0261 case (KSysGuard::Process::RoundRobin): 0262 success = (sched_setscheduler(pid, SCHED_RR, ¶ms) == 0); 0263 break; 0264 case (KSysGuard::Process::Fifo): 0265 success = (sched_setscheduler(pid, SCHED_FIFO, ¶ms) == 0); 0266 break; 0267 #ifdef SCHED_BATCH 0268 case (KSysGuard::Process::Batch): 0269 success = (sched_setscheduler(pid, SCHED_BATCH, ¶ms) == 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 }