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