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