File indexing completed on 2024-04-28 05:31:38
0001 /* 0002 SPDX-FileCopyrightText: 2007 Manolo Valdes <nolis71cu@gmail.com> 0003 SPDX-FileCopyrightText: 2010 Alex Hornung <ahornung@gmail.com> 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 <err.h> 0016 #include <sched.h> 0017 #include <signal.h> 0018 #include <stdlib.h> 0019 #include <sys/param.h> 0020 #include <sys/resource.h> 0021 #include <sys/resourcevar.h> 0022 #include <sys/sysctl.h> 0023 #include <sys/types.h> 0024 #include <sys/user.h> 0025 #include <unistd.h> 0026 0027 #define PP(pp, field) ((pp)->kp_##field) 0028 #define LP(pp, field) ((pp)->kp_lwp.kl_##field) 0029 #define VP(pp, field) ((pp)->kp_vm_##field) 0030 0031 namespace KSysGuard 0032 { 0033 class ProcessesLocal::Private 0034 { 0035 public: 0036 Private() 0037 { 0038 } 0039 ~Private() 0040 { 0041 } 0042 inline bool readProc(long pid, struct kinfo_proc *p); 0043 inline void readProcStatus(struct kinfo_proc *p, Process *process); 0044 inline void readProcStat(struct kinfo_proc *p, Process *process); 0045 inline void readProcStatm(struct kinfo_proc *p, Process *process); 0046 inline bool readProcCmdline(long pid, Process *process); 0047 }; 0048 0049 bool ProcessesLocal::Private::readProc(long pid, struct kinfo_proc *p) 0050 { 0051 int mib[4]; 0052 size_t len; 0053 0054 mib[0] = CTL_KERN; 0055 mib[1] = KERN_PROC; 0056 mib[2] = KERN_PROC_PID; 0057 mib[3] = pid; 0058 0059 len = sizeof(struct kinfo_proc); 0060 if (sysctl(mib, 4, p, &len, NULL, 0) == -1 || !len) { 0061 return false; 0062 } 0063 return true; 0064 } 0065 0066 void ProcessesLocal::Private::readProcStatus(struct kinfo_proc *p, Process *process) 0067 { 0068 process->setUid(0); 0069 process->setGid(0); 0070 process->setTracerpid(-1); 0071 0072 process->setEuid(PP(p, uid)); 0073 process->setUid(PP(p, ruid)); 0074 process->setEgid(PP(p, svgid)); 0075 process->setGid(PP(p, rgid)); 0076 process->setName(QString(PP(p, comm))); 0077 } 0078 0079 void ProcessesLocal::Private::readProcStat(struct kinfo_proc *p, Process *ps) 0080 { 0081 ps->setUserTime(LP(p, uticks) / 10000); 0082 ps->setSysTime((LP(p, sticks) + LP(p, iticks)) / 10000); 0083 ps->setNiceLevel(PP(p, nice)); 0084 ps->setVmSize(VP(p, map_size) / 1024); /* convert to KiB */ 0085 ps->setVmRSS(VP(p, prssize) * getpagesize() / 1024); /* convert to KiB */ 0086 0087 // "idle","run","sleep","stop","zombie" 0088 switch (LP(p, stat)) { 0089 case LSRUN: 0090 ps->setStatus(Process::Running); 0091 break; 0092 case LSSLEEP: 0093 ps->setStatus(Process::Sleeping); 0094 break; 0095 case LSSTOP: 0096 ps->setStatus(Process::Stopped); 0097 break; 0098 default: 0099 ps->setStatus(Process::OtherStatus); 0100 break; 0101 } 0102 if (PP(p, stat) == SZOMB) { 0103 ps->setStatus(Process::Zombie); 0104 } 0105 } 0106 0107 void ProcessesLocal::Private::readProcStatm(struct kinfo_proc *p, Process *process) 0108 { 0109 process->setVmURSS(-1); 0110 } 0111 0112 bool ProcessesLocal::Private::readProcCmdline(long pid, Process *process) 0113 { 0114 int mib[4]; 0115 size_t buflen = 256; 0116 char buf[256]; 0117 0118 mib[0] = CTL_KERN; 0119 mib[1] = KERN_PROC; 0120 mib[2] = KERN_PROC_ARGS; 0121 mib[3] = pid; 0122 0123 if (sysctl(mib, 4, buf, &buflen, NULL, 0) == -1 || (buflen == 0)) { 0124 return false; 0125 } 0126 QString command = QString(buf); 0127 0128 // cmdline separates parameters with the NULL character 0129 command.replace('\0', ' '); 0130 process->setCommand(command.trimmed()); 0131 0132 return true; 0133 } 0134 0135 ProcessesLocal::ProcessesLocal() 0136 : d(new Private()) 0137 { 0138 } 0139 0140 long ProcessesLocal::getParentPid(long pid) 0141 { 0142 long long ppid = -1; 0143 struct kinfo_proc p; 0144 0145 if (d->readProc(pid, &p)) { 0146 ppid = PP(&p, ppid); 0147 } 0148 0149 return ppid; 0150 } 0151 0152 bool ProcessesLocal::updateProcessInfo(long pid, Process *process) 0153 { 0154 struct kinfo_proc p; 0155 0156 if (!d->readProc(pid, &p)) { 0157 return false; 0158 } 0159 0160 d->readProcStat(&p, process); 0161 d->readProcStatus(&p, process); 0162 d->readProcStatm(&p, process); 0163 if (!d->readProcCmdline(pid, process)) { 0164 return false; 0165 } 0166 0167 return true; 0168 } 0169 0170 QSet<long> ProcessesLocal::getAllPids() 0171 { 0172 QSet<long> pids; 0173 int mib[3]; 0174 size_t len; 0175 size_t num; 0176 struct kinfo_proc *p; 0177 0178 mib[0] = CTL_KERN; 0179 mib[1] = KERN_PROC; 0180 mib[2] = KERN_PROC_ALL; 0181 if (sysctl(mib, 3, NULL, &len, NULL, 0) == -1) { 0182 return pids; 0183 } 0184 if ((p = (kinfo_proc *)malloc(len)) == NULL) { 0185 return pids; 0186 } 0187 if (sysctl(mib, 3, p, &len, NULL, 0) == -1) { 0188 free(p); 0189 return pids; 0190 } 0191 0192 for (num = 0; num < len / sizeof(struct kinfo_proc); num++) { 0193 long pid = PP((&p[num]), pid); 0194 long long ppid = PP((&p[num]), ppid); 0195 0196 // skip all process with parent id = 0 but init 0197 if (ppid <= 0 && pid != 1) { 0198 continue; 0199 } 0200 pids.insert(pid); 0201 } 0202 free(p); 0203 return pids; 0204 } 0205 0206 Processes::Error ProcessesLocal::sendSignal(long pid, int sig) 0207 { 0208 if (kill((pid_t)pid, sig)) { 0209 // Kill failed 0210 return Processes::Unknown; 0211 } 0212 return Processes::NoError; 0213 } 0214 0215 Processes::Error ProcessesLocal::setNiceness(long pid, int priority) 0216 { 0217 if (setpriority(PRIO_PROCESS, pid, priority)) { 0218 // set niceness failed 0219 return Processes::Unknown; 0220 } 0221 return Processes::NoError; 0222 } 0223 0224 Processes::Error ProcessesLocal::setScheduler(long pid, int priorityClass, int priority) 0225 { 0226 if (priorityClass == KSysGuard::Process::Other || priorityClass == KSysGuard::Process::Batch) { 0227 priority = 0; 0228 } 0229 if (pid <= 0) { 0230 return Processes::InvalidPid; // check the parameters 0231 } 0232 struct sched_param params; 0233 params.sched_priority = priority; 0234 bool success; 0235 switch (priorityClass) { 0236 case (KSysGuard::Process::Other): 0237 success = (sched_setscheduler(pid, SCHED_OTHER, ¶ms) == 0); 0238 break; 0239 case (KSysGuard::Process::RoundRobin): 0240 success = (sched_setscheduler(pid, SCHED_RR, ¶ms) == 0); 0241 break; 0242 case (KSysGuard::Process::Fifo): 0243 success = (sched_setscheduler(pid, SCHED_FIFO, ¶ms) == 0); 0244 break; 0245 #ifdef SCHED_BATCH 0246 case (KSysGuard::Process::Batch): 0247 success = (sched_setscheduler(pid, SCHED_BATCH, ¶ms) == 0); 0248 break; 0249 #endif 0250 } 0251 if (success) { 0252 return Processes::NoError; 0253 } 0254 return Processes::Unknown; 0255 } 0256 0257 Processes::Error ProcessesLocal::setIoNiceness(long pid, int priorityClass, int priority) 0258 { 0259 return Processes::NotSupported; // Not yet supported 0260 } 0261 0262 bool ProcessesLocal::supportsIoNiceness() 0263 { 0264 return false; 0265 } 0266 0267 long long ProcessesLocal::totalPhysicalMemory() 0268 { 0269 size_t Total; 0270 size_t len; 0271 0272 len = sizeof(Total); 0273 if (sysctlbyname("hw.physmem", &Total, &len, NULL, 0) == -1) { 0274 return 0; 0275 } 0276 0277 Total *= getpagesize() / 1024; 0278 return Total; 0279 } 0280 0281 ProcessesLocal::~ProcessesLocal() 0282 { 0283 delete d; 0284 } 0285 0286 }