File indexing completed on 2024-04-28 16:49:57
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 <sys/param.h> 0015 #include <sys/resource.h> 0016 #include <sys/sysctl.h> 0017 #include <sys/types.h> 0018 #include <sys/user.h> 0019 #if defined(__DragonFly__) 0020 #include <err.h> 0021 #include <sys/resourcevar.h> 0022 #endif 0023 #include <signal.h> 0024 #include <stdlib.h> 0025 #include <unistd.h> 0026 0027 namespace KSysGuard 0028 { 0029 class ProcessesLocal::Private 0030 { 0031 public: 0032 Private() 0033 { 0034 ; 0035 } 0036 ~Private() 0037 { 0038 ; 0039 } 0040 inline bool readProc(long pid, struct kinfo_proc *p); 0041 inline void readProcStatus(struct kinfo_proc *p, Process *process); 0042 inline void readProcStat(struct kinfo_proc *p, Process *process); 0043 inline void readProcStatm(struct kinfo_proc *p, Process *process); 0044 inline bool readProcCmdline(long pid, Process *process); 0045 }; 0046 0047 bool ProcessesLocal::Private::readProc(long pid, struct kinfo_proc *p) 0048 { 0049 int mib[4]; 0050 size_t len; 0051 0052 mib[0] = CTL_KERN; 0053 mib[1] = KERN_PROC; 0054 mib[2] = KERN_PROC_PID; 0055 mib[3] = pid; 0056 0057 len = sizeof(struct kinfo_proc); 0058 if (sysctl(mib, 4, p, &len, NULL, 0) == -1 || !len) 0059 return false; 0060 return true; 0061 } 0062 0063 void ProcessesLocal::Private::readProcStatus(struct kinfo_proc *p, Process *process) 0064 { 0065 process->setUid(0); 0066 process->setGid(0); 0067 process->setTracerpid(-1); 0068 0069 #if defined(__FreeBSD__) && __FreeBSD_version >= 500015 0070 process->setUid(p->ki_uid); 0071 process->setGid(p->ki_pgid); 0072 process->setName(QString(p->ki_comm ? p->ki_comm : "????")); 0073 #elif defined(__DragonFly__) && __DragonFly_version >= 190000 0074 process->setUid(p->kp_uid); 0075 process->setGid(p->kp_pgid); 0076 process->setName(QString(p->kp_comm ? p->kp_comm : "????")); 0077 #else 0078 process->setUid(p->kp_eproc.e_ucred.cr_uid); 0079 process->setGid(p->kp_eproc.e_pgid); 0080 #endif 0081 } 0082 0083 void ProcessesLocal::Private::readProcStat(struct kinfo_proc *p, Process *ps) 0084 { 0085 int status; 0086 struct rusage pru; 0087 #if defined(__FreeBSD__) && __FreeBSD_version >= 500015 0088 ps->setUserTime(p->ki_runtime / 10000); 0089 ps->setNiceLevel(p->ki_nice); 0090 ps->setVmSize(p->ki_size); 0091 ps->setVmRSS(p->ki_rssize * getpagesize()); 0092 status = p->ki_stat; 0093 #elif defined(__DragonFly__) && __DragonFly_version >= 190000 0094 if (!getrusage(p->kp_pid, &pru)) { 0095 errx(1, "failed to get rusage info"); 0096 } 0097 ps->setUserTime(pru.ru_utime.tv_usec / 1000); /*p_runtime / 1000*/ 0098 ps->setNiceLevel(p->kp_nice); 0099 ps->setVmSize(p->kp_vm_map_size); 0100 ps->setVmRSS(p->kp_vm_rssize * getpagesize()); 0101 status = p->kp_stat; 0102 #else 0103 ps->setUserTime(p->kp_proc.p_rtime.tv_sec * 100 + p->kp_proc.p_rtime.tv_usec / 100); 0104 ps->setNiceLevel(p->kp_proc.p_nice); 0105 ps->setVmSize(p->kp_eproc.e_vm.vm_map.size); 0106 ps->setVmRSS(p->kp_eproc.e_vm.vm_rssize * getpagesize()); 0107 status = p->kp_proc.p_stat; 0108 #endif 0109 ps->setSysTime(0); 0110 0111 // "idle","run","sleep","stop","zombie" 0112 switch (status) { 0113 case '0': 0114 ps->setStatus(Process::DiskSleep); 0115 break; 0116 case '1': 0117 ps->setStatus(Process::Running); 0118 break; 0119 case '2': 0120 ps->setStatus(Process::Sleeping); 0121 break; 0122 case '3': 0123 ps->setStatus(Process::Stopped); 0124 break; 0125 case '4': 0126 ps->setStatus(Process::Zombie); 0127 break; 0128 default: 0129 ps->setStatus(Process::OtherStatus); 0130 break; 0131 } 0132 } 0133 0134 void ProcessesLocal::Private::readProcStatm(struct kinfo_proc *p, Process *process) 0135 { 0136 // TODO 0137 0138 // unsigned long shared; 0139 // process->setVmURSS(process->vmRSS - (shared * sysconf(_SC_PAGESIZE) / 1024)); 0140 } 0141 0142 bool ProcessesLocal::Private::readProcCmdline(long pid, Process *process) 0143 { 0144 int mib[4]; 0145 struct kinfo_proc p; 0146 size_t buflen = 256; 0147 char buf[256]; 0148 0149 mib[0] = CTL_KERN; 0150 mib[1] = KERN_PROC; 0151 mib[2] = KERN_PROC_ARGS; 0152 mib[3] = pid; 0153 0154 if (sysctl(mib, 4, buf, &buflen, NULL, 0) == -1 || !buflen) 0155 return false; 0156 QString command = QString(buf); 0157 0158 // cmdline separates parameters with the NULL character 0159 command.replace('\0', ' '); 0160 process->setCommand(command.trimmed()); 0161 0162 return true; 0163 } 0164 0165 ProcessesLocal::ProcessesLocal() 0166 : d(new Private()) 0167 { 0168 } 0169 0170 long ProcessesLocal::getParentPid(long pid) 0171 { 0172 Q_ASSERT(pid != 0); 0173 long long ppid = -1; 0174 struct kinfo_proc p; 0175 if (d->readProc(pid, &p)) { 0176 #if defined(__FreeBSD__) && __FreeBSD_version >= 500015 0177 ppid = p.ki_ppid; 0178 #elif defined(__DragonFly__) && __DragonFly_version >= 190000 0179 ppid = p.kp_ppid; 0180 #else 0181 ppid = p.kp_eproc.e_ppid; 0182 #endif 0183 } 0184 return ppid; 0185 } 0186 0187 bool ProcessesLocal::updateProcessInfo(long pid, Process *process) 0188 { 0189 struct kinfo_proc p; 0190 if (!d->readProc(pid, &p)) 0191 return false; 0192 d->readProcStat(&p, process); 0193 d->readProcStatus(&p, process); 0194 d->readProcStatm(&p, process); 0195 if (!d->readProcCmdline(pid, process)) 0196 return false; 0197 0198 return true; 0199 } 0200 0201 QSet<long> ProcessesLocal::getAllPids() 0202 { 0203 QSet<long> pids; 0204 int mib[3]; 0205 size_t len; 0206 size_t num; 0207 struct kinfo_proc *p; 0208 0209 mib[0] = CTL_KERN; 0210 mib[1] = KERN_PROC; 0211 mib[2] = KERN_PROC_ALL; 0212 sysctl(mib, 3, NULL, &len, NULL, 0); 0213 p = (kinfo_proc *)malloc(len); 0214 sysctl(mib, 3, p, &len, NULL, 0); 0215 0216 for (num = 0; num < len / sizeof(struct kinfo_proc); num++) 0217 #if defined(__FreeBSD__) && __FreeBSD_version >= 500015 0218 pids.insert(p[num].ki_pid); 0219 #elif defined(__DragonFly__) && __DragonFly_version >= 190000 0220 pids.insert(p[num].kp_pid); 0221 #else 0222 pids.insert(p[num].kp_proc.p_pid); 0223 #endif 0224 free(p); 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 if (pid <= 0) 0251 return Processes::InvalidPid; // check the parameters 0252 return Processes::NotSupported; 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 static int physmem_mib[] = {CTL_HW, HW_PHYSMEM}; 0268 /* get the page size with "getpagesize" and calculate pageshift from 0269 * it */ 0270 int pagesize = ::getpagesize(); 0271 int pageshift = 0; 0272 while (pagesize > 1) { 0273 pageshift++; 0274 pagesize >>= 1; 0275 } 0276 size_t Total = 0; 0277 size_t size = sizeof(Total); 0278 sysctl(physmem_mib, 2, &Total, &size, NULL, 0); 0279 return Total /= 1024; 0280 } 0281 0282 long int KSysGuard::ProcessesLocal::numberProcessorCores() 0283 { 0284 int mib[2]; 0285 int ncpu; 0286 size_t len; 0287 0288 mib[0] = CTL_HW; 0289 mib[1] = HW_NCPU; 0290 len = sizeof(ncpu); 0291 0292 if (sysctl(mib, 2, &ncpu, &len, NULL, 0) == -1 || !len) 0293 return 1; 0294 return len; 0295 } 0296 ProcessesLocal::~ProcessesLocal() 0297 { 0298 delete d; 0299 } 0300 0301 }