1 /*
2 SPDX-FileCopyrightText: 2007 Adriaan de Groot <groot@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.0-or-later
5 */
6
7 /* Stop <sys/procfs.h> from crapping out on 32-bit architectures. */
8
9 #if !defined(_LP64) && _FILE_OFFSET_BITS == 64
10 #undef _FILE_OFFSET_BITS
11 #define _FILE_OFFSET_BITS 32
12 #endif
13
14 #include "process.h"
15 #include "processes_local_p.h"
16
17 #include <KLocalizedString>
18
19 #include <QSet>
20
21 #include <dirent.h>
22 #include <errno.h>
23 #include <fcntl.h>
24 #include <procfs.h>
25 #include <pwd.h>
26 #include <sched.h>
27 #include <signal.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <sys/param.h>
32 #include <sys/proc.h>
33 #include <sys/resource.h>
34 #include <sys/types.h>
35 #include <sys/user.h>
36 #include <unistd.h>
37
38 #define PROCESS_BUFFER_SIZE 512
39 #define PROCDIR "/proc"
40
41 namespace KSysGuard
42 {
43 class ProcessesLocal::Private
44 {
45 public:
Private()46 Private()
47 {
48 mProcDir = opendir(PROCDIR);
49 };
~Private()50 ~Private(){};
51 char mBuf[PROCESS_BUFFER_SIZE + 1]; // used as a buffer to read data into
52 DIR *mProcDir;
53 };
54
ProcessesLocal()55 ProcessesLocal::ProcessesLocal()
56 : d(new Private())
57 {
58 }
59
getParentPid(long pid)60 long ProcessesLocal::getParentPid(long pid)
61 {
62 long long ppid = -1;
63 int fd;
64 psinfo_t psinfo;
65
66 snprintf(d->mBuf, PROCESS_BUFFER_SIZE - 1, "%s/%ld/psinfo", PROCDIR, pid);
67 if ((fd = open(d->mBuf, O_RDONLY)) < 0) {
68 return -1; /* process has terminated in the meantime */
69 }
70
71 if (read(fd, &psinfo, sizeof(psinfo_t)) != sizeof(psinfo_t)) {
72 close(fd);
73 return -1;
74 }
75 close(fd);
76 ppid = psinfo.pr_ppid;
77
78 return ppid;
79 }
80
updateProcessInfo(long pid,Process * process)81 bool ProcessesLocal::updateProcessInfo(long pid, Process *process)
82 {
83 int fd, pfd;
84 psinfo_t psinfo;
85 prusage_t prusage;
86
87 snprintf(d->mBuf, PROCESS_BUFFER_SIZE - 1, "%s/%ld/psinfo", PROCDIR, pid);
88 if ((fd = open(d->mBuf, O_RDONLY)) < 0) {
89 return false; /* process has terminated in the meantime */
90 }
91
92 snprintf(d->mBuf, PROCESS_BUFFER_SIZE - 1, "%s/%ld/usage", PROCDIR, pid);
93 if ((pfd = open(d->mBuf, O_RDONLY)) < 0) {
94 close(fd);
95 return false; /* process has terminated in the meantime */
96 }
97
98 process->uid = 0;
99 process->gid = 0;
100 process->tracerpid = -1;
101 process->pid() = pid;
102
103 if (read(fd, &psinfo, sizeof(psinfo_t)) != sizeof(psinfo_t)) {
104 close(fd);
105 return false;
106 }
107 close(fd);
108
109 if (read(pfd, &prusage, sizeof(prusage_t)) != sizeof(prusage_t)) {
110 close(pfd);
111 return false;
112 }
113 close(pfd);
114
115 process->setUid(psinfo.pr_uid);
116 process->setEuid(psinfo.pr_euid);
117 process->setGid(psinfo.pr_gid);
118 process->setEgid(psinfo.pr_egid);
119
120 switch ((int)psinfo.pr_lwp.pr_state) {
121 case SIDL:
122 case SWAIT:
123 case SSLEEP:
124 process->setStatus(Process::Sleeping);
125 break;
126 case SONPROC:
127 case SRUN:
128 process->setStatus(Process::Running);
129 break;
130 case SZOMB:
131 process->setStatus(Process::Zombie);
132 break;
133 case SSTOP:
134 process->setStatus(Process::Stopped);
135 break;
136 default:
137 process->setStatus(Process::OtherStatus);
138 break;
139 }
140
141 process->setVmRSS(psinfo.pr_rssize);
142 process->setVmSize(psinfo.pr_size);
143 process->setVmURSS(-1);
144
145 if (process->command.isNull()) {
146 QString name(psinfo.pr_fname);
147
148 name = name.trimmed();
149 if (!name.isEmpty()) {
150 name.remove(QRegExp("^[^ ]*/"));
151 }
152 process->setName(name);
153 name = psinfo.pr_fname;
154 name.append(psinfo.pr_psargs);
155 process->setCommand(name);
156 }
157
158 // Approximations, not quite accurate. Needs more changes in ksysguard to map
159 // RR and FIFO to current Solaris classes.
160 if (strcmp(psinfo.pr_lwp.pr_clname, "TS") == 0 || strcmp(psinfo.pr_lwp.pr_clname, "SYS") == 0 || strcmp(psinfo.pr_lwp.pr_clname, "FSS") == 0) {
161 process->setscheduler(KSysGuard::Process::Other);
162
163 } else if (strcmp(psinfo.pr_lwp.pr_clname, "FX") == 0 || strcmp(psinfo.pr_lwp.pr_clname, "RT") == 0) {
164 process->setscheduler(KSysGuard::Process::RoundRobin);
165
166 } else if (strcmp(psinfo.pr_lwp.pr_clname, "IA") == 0) {
167 process->setscheduler(KSysGuard::Process::Interactive);
168 }
169 process->setNiceLevel(psinfo.pr_lwp.pr_pri);
170 process->setUserTime(prusage.pr_utime.tv_sec * 100 + prusage.pr_utime.tv_nsec / 10000000.0);
171 process->setSysTime(prusage.pr_stime.tv_sec * 100 + prusage.pr_stime.tv_nsec / 10000000.0);
172 return false;
173 }
174
getAllPids()175 QSet<long> ProcessesLocal::getAllPids()
176 {
177 QSet<long> pids;
178 long pid;
179
180 if (d->mProcDir == NULL)
181 return pids; // There's not much we can do without /proc
182 struct dirent *entry;
183 rewinddir(d->mProcDir);
184 while ((entry = readdir(d->mProcDir)))
185 if (entry->d_name[0] >= '0' && entry->d_name[0] <= '9') {
186 pid = atol(entry->d_name);
187 // Skip all processes with parent id = 0 except init
188 if (pid == 1 || getParentPid(pid) > 0) {
189 pids.insert(pid);
190 }
191 }
192 return pids;
193 }
194
sendSignal(long pid,int sig)195 Processes::Error ProcessesLocal::sendSignal(long pid, int sig)
196 {
197 if (kill((pid_t)pid, sig)) {
198 // Kill failed
199 return Processes::Unknown;
200 }
201 return Processes::NoError;
202 }
203
204 /*
205 *
206 */
setNiceness(long pid,int priority)207 Processes::Error ProcessesLocal::setNiceness(long pid, int priority)
208 {
209 return Processes::NotSupported;
210 }
211
setScheduler(long pid,int priorityClass,int priority)212 Processes::Error ProcessesLocal::setScheduler(long pid, int priorityClass, int priority)
213 {
214 return Processes::NotSupported;
215 }
216
setIoNiceness(long pid,int priorityClass,int priority)217 Processes::Error ProcessesLocal::setIoNiceness(long pid, int priorityClass, int priority)
218 {
219 return Processes::NotSupported; // Not yet supported
220 }
221
supportsIoNiceness()222 bool ProcessesLocal::supportsIoNiceness()
223 {
224 return false;
225 }
226
totalPhysicalMemory()227 long long ProcessesLocal::totalPhysicalMemory()
228 {
229 long long memory = ((long long)sysconf(_SC_PHYS_PAGES)) * (sysconf(_SC_PAGESIZE) / 1024);
230 if (memory > 0)
231 return memory;
232 return 0;
233 }
234
~ProcessesLocal()235 ProcessesLocal::~ProcessesLocal()
236 {
237 delete d;
238 }
239
240 }
241