1 /*
2 SPDX-FileCopyrightText: 2007 Manolo Valdes <nolis71cu@gmail.com>
3
4 SPDX-License-Identifier: LGPL-2.0-or-later
5 */
6
7 #include "process.h"
8 #include "processes_local_p.h"
9
10 #include <KLocalizedString>
11
12 #include <QSet>
13
14 #include <sys/param.h>
15 #include <sys/resource.h>
16 #include <sys/sysctl.h>
17 #include <sys/types.h>
18 #include <sys/user.h>
19 #if defined(__DragonFly__)
20 #include <err.h>
21 #include <sys/resourcevar.h>
22 #endif
23 #include <signal.h>
24 #include <stdlib.h>
25 #include <unistd.h>
26
27 namespace KSysGuard
28 {
29 class ProcessesLocal::Private
30 {
31 public:
Private()32 Private()
33 {
34 ;
35 }
~Private()36 ~Private()
37 {
38 ;
39 }
40 inline bool readProc(long pid, struct kinfo_proc *p);
41 inline void readProcStatus(struct kinfo_proc *p, Process *process);
42 inline void readProcStat(struct kinfo_proc *p, Process *process);
43 inline void readProcStatm(struct kinfo_proc *p, Process *process);
44 inline bool readProcCmdline(long pid, Process *process);
45 };
46
readProc(long pid,struct kinfo_proc * p)47 bool ProcessesLocal::Private::readProc(long pid, struct kinfo_proc *p)
48 {
49 int mib[4];
50 size_t len;
51
52 mib[0] = CTL_KERN;
53 mib[1] = KERN_PROC;
54 mib[2] = KERN_PROC_PID;
55 mib[3] = pid;
56
57 len = sizeof(struct kinfo_proc);
58 if (sysctl(mib, 4, p, &len, NULL, 0) == -1 || !len)
59 return false;
60 return true;
61 }
62
readProcStatus(struct kinfo_proc * p,Process * process)63 void ProcessesLocal::Private::readProcStatus(struct kinfo_proc *p, Process *process)
64 {
65 process->setUid(0);
66 process->setGid(0);
67 process->setTracerpid(-1);
68
69 #if defined(__FreeBSD__) && __FreeBSD_version >= 500015
70 process->setUid(p->ki_uid);
71 process->setGid(p->ki_pgid);
72 process->setName(QString(p->ki_comm ? p->ki_comm : "????"));
73 #elif defined(__DragonFly__) && __DragonFly_version >= 190000
74 process->setUid(p->kp_uid);
75 process->setGid(p->kp_pgid);
76 process->setName(QString(p->kp_comm ? p->kp_comm : "????"));
77 #else
78 process->setUid(p->kp_eproc.e_ucred.cr_uid);
79 process->setGid(p->kp_eproc.e_pgid);
80 #endif
81 }
82
readProcStat(struct kinfo_proc * p,Process * ps)83 void ProcessesLocal::Private::readProcStat(struct kinfo_proc *p, Process *ps)
84 {
85 int status;
86 struct rusage pru;
87 #if defined(__FreeBSD__) && __FreeBSD_version >= 500015
88 ps->setUserTime(p->ki_runtime / 10000);
89 ps->setNiceLevel(p->ki_nice);
90 ps->setVmSize(p->ki_size);
91 ps->setVmRSS(p->ki_rssize * getpagesize());
92 status = p->ki_stat;
93 #elif defined(__DragonFly__) && __DragonFly_version >= 190000
94 if (!getrusage(p->kp_pid, &pru)) {
95 errx(1, "failed to get rusage info");
96 }
97 ps->setUserTime(pru.ru_utime.tv_usec / 1000); /*p_runtime / 1000*/
98 ps->setNiceLevel(p->kp_nice);
99 ps->setVmSize(p->kp_vm_map_size);
100 ps->setVmRSS(p->kp_vm_rssize * getpagesize());
101 status = p->kp_stat;
102 #else
103 ps->setUserTime(p->kp_proc.p_rtime.tv_sec * 100 + p->kp_proc.p_rtime.tv_usec / 100);
104 ps->setNiceLevel(p->kp_proc.p_nice);
105 ps->setVmSize(p->kp_eproc.e_vm.vm_map.size);
106 ps->setVmRSS(p->kp_eproc.e_vm.vm_rssize * getpagesize());
107 status = p->kp_proc.p_stat;
108 #endif
109 ps->setSysTime(0);
110
111 // "idle","run","sleep","stop","zombie"
112 switch (status) {
113 case '0':
114 ps->setStatus(Process::DiskSleep);
115 break;
116 case '1':
117 ps->setStatus(Process::Running);
118 break;
119 case '2':
120 ps->setStatus(Process::Sleeping);
121 break;
122 case '3':
123 ps->setStatus(Process::Stopped);
124 break;
125 case '4':
126 ps->setStatus(Process::Zombie);
127 break;
128 default:
129 ps->setStatus(Process::OtherStatus);
130 break;
131 }
132 }
133
readProcStatm(struct kinfo_proc * p,Process * process)134 void ProcessesLocal::Private::readProcStatm(struct kinfo_proc *p, Process *process)
135 {
136 // TODO
137
138 // unsigned long shared;
139 // process->setVmURSS(process->vmRSS - (shared * sysconf(_SC_PAGESIZE) / 1024));
140 }
141
readProcCmdline(long pid,Process * process)142 bool ProcessesLocal::Private::readProcCmdline(long pid, Process *process)
143 {
144 int mib[4];
145 struct kinfo_proc p;
146 size_t buflen = 256;
147 char buf[256];
148
149 mib[0] = CTL_KERN;
150 mib[1] = KERN_PROC;
151 mib[2] = KERN_PROC_ARGS;
152 mib[3] = pid;
153
154 if (sysctl(mib, 4, buf, &buflen, NULL, 0) == -1 || !buflen)
155 return false;
156 QString command = QString(buf);
157
158 // cmdline separates parameters with the NULL character
159 command.replace('\0', ' ');
160 process->setCommand(command.trimmed());
161
162 return true;
163 }
164
ProcessesLocal()165 ProcessesLocal::ProcessesLocal()
166 : d(new Private())
167 {
168 }
169
getParentPid(long pid)170 long ProcessesLocal::getParentPid(long pid)
171 {
172 Q_ASSERT(pid != 0);
173 long long ppid = -1;
174 struct kinfo_proc p;
175 if (d->readProc(pid, &p)) {
176 #if defined(__FreeBSD__) && __FreeBSD_version >= 500015
177 ppid = p.ki_ppid;
178 #elif defined(__DragonFly__) && __DragonFly_version >= 190000
179 ppid = p.kp_ppid;
180 #else
181 ppid = p.kp_eproc.e_ppid;
182 #endif
183 }
184 return ppid;
185 }
186
updateProcessInfo(long pid,Process * process)187 bool ProcessesLocal::updateProcessInfo(long pid, Process *process)
188 {
189 struct kinfo_proc p;
190 if (!d->readProc(pid, &p))
191 return false;
192 d->readProcStat(&p, process);
193 d->readProcStatus(&p, process);
194 d->readProcStatm(&p, process);
195 if (!d->readProcCmdline(pid, process))
196 return false;
197
198 return true;
199 }
200
getAllPids()201 QSet<long> ProcessesLocal::getAllPids()
202 {
203 QSet<long> pids;
204 int mib[3];
205 size_t len;
206 size_t num;
207 struct kinfo_proc *p;
208
209 mib[0] = CTL_KERN;
210 mib[1] = KERN_PROC;
211 mib[2] = KERN_PROC_ALL;
212 sysctl(mib, 3, NULL, &len, NULL, 0);
213 p = (kinfo_proc *)malloc(len);
214 sysctl(mib, 3, p, &len, NULL, 0);
215
216 for (num = 0; num < len / sizeof(struct kinfo_proc); num++)
217 #if defined(__FreeBSD__) && __FreeBSD_version >= 500015
218 pids.insert(p[num].ki_pid);
219 #elif defined(__DragonFly__) && __DragonFly_version >= 190000
220 pids.insert(p[num].kp_pid);
221 #else
222 pids.insert(p[num].kp_proc.p_pid);
223 #endif
224 free(p);
225 return pids;
226 }
227
sendSignal(long pid,int sig)228 Processes::Error ProcessesLocal::sendSignal(long pid, int sig)
229 {
230 if (kill((pid_t)pid, sig)) {
231 // Kill failed
232 return Processes::Unknown;
233 }
234 return Processes::NoError;
235 }
236
setNiceness(long pid,int priority)237 Processes::Error ProcessesLocal::setNiceness(long pid, int priority)
238 {
239 if (setpriority(PRIO_PROCESS, pid, priority)) {
240 // set niceness failed
241 return Processes::Unknown;
242 }
243 return Processes::NoError;
244 }
245
setScheduler(long pid,int priorityClass,int priority)246 Processes::Error ProcessesLocal::setScheduler(long pid, int priorityClass, int priority)
247 {
248 if (priorityClass == KSysGuard::Process::Other || priorityClass == KSysGuard::Process::Batch)
249 priority = 0;
250 if (pid <= 0)
251 return Processes::InvalidPid; // check the parameters
252 return Processes::NotSupported;
253 }
254
setIoNiceness(long pid,int priorityClass,int priority)255 Processes::Error ProcessesLocal::setIoNiceness(long pid, int priorityClass, int priority)
256 {
257 return Processes::NotSupported; // Not yet supported
258 }
259
supportsIoNiceness()260 bool ProcessesLocal::supportsIoNiceness()
261 {
262 return false;
263 }
264
totalPhysicalMemory()265 long long ProcessesLocal::totalPhysicalMemory()
266 {
267 static int physmem_mib[] = {CTL_HW, HW_PHYSMEM};
268 /* get the page size with "getpagesize" and calculate pageshift from
269 * it */
270 int pagesize = ::getpagesize();
271 int pageshift = 0;
272 while (pagesize > 1) {
273 pageshift++;
274 pagesize >>= 1;
275 }
276 size_t Total = 0;
277 size_t size = sizeof(Total);
278 sysctl(physmem_mib, 2, &Total, &size, NULL, 0);
279 return Total /= 1024;
280 }
281
numberProcessorCores()282 long int KSysGuard::ProcessesLocal::numberProcessorCores()
283 {
284 int mib[2];
285 int ncpu;
286 size_t len;
287
288 mib[0] = CTL_HW;
289 mib[1] = HW_NCPU;
290 len = sizeof(ncpu);
291
292 if (sysctl(mib, 2, &ncpu, &len, NULL, 0) == -1 || !len)
293 return 1;
294 return len;
295 }
~ProcessesLocal()296 ProcessesLocal::~ProcessesLocal()
297 {
298 delete d;
299 }
300
301 }
302