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