File indexing completed on 2024-04-28 05:31:40
0001 /* 0002 SPDX-FileCopyrightText: 2007 Adriaan de Groot <groot@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 /* Stop <sys/procfs.h> from crapping out on 32-bit architectures. */ 0008 0009 #if !defined(_LP64) && _FILE_OFFSET_BITS == 64 0010 #undef _FILE_OFFSET_BITS 0011 #define _FILE_OFFSET_BITS 32 0012 #endif 0013 0014 #include "process.h" 0015 #include "processes_local_p.h" 0016 0017 #include <KLocalizedString> 0018 0019 #include <QSet> 0020 0021 #include <dirent.h> 0022 #include <errno.h> 0023 #include <fcntl.h> 0024 #include <procfs.h> 0025 #include <pwd.h> 0026 #include <sched.h> 0027 #include <signal.h> 0028 #include <stdio.h> 0029 #include <stdlib.h> 0030 #include <string.h> 0031 #include <sys/param.h> 0032 #include <sys/proc.h> 0033 #include <sys/resource.h> 0034 #include <sys/types.h> 0035 #include <sys/user.h> 0036 #include <unistd.h> 0037 0038 #define PROCESS_BUFFER_SIZE 512 0039 #define PROCDIR "/proc" 0040 0041 namespace KSysGuard 0042 { 0043 class ProcessesLocal::Private 0044 { 0045 public: 0046 Private() 0047 { 0048 mProcDir = opendir(PROCDIR); 0049 }; 0050 ~Private(){}; 0051 char mBuf[PROCESS_BUFFER_SIZE + 1]; // used as a buffer to read data into 0052 DIR *mProcDir; 0053 }; 0054 0055 ProcessesLocal::ProcessesLocal() 0056 : d(new Private()) 0057 { 0058 } 0059 0060 long ProcessesLocal::getParentPid(long pid) 0061 { 0062 long long ppid = -1; 0063 int fd; 0064 psinfo_t psinfo; 0065 0066 snprintf(d->mBuf, PROCESS_BUFFER_SIZE - 1, "%s/%ld/psinfo", PROCDIR, pid); 0067 if ((fd = open(d->mBuf, O_RDONLY)) < 0) { 0068 return -1; /* process has terminated in the meantime */ 0069 } 0070 0071 if (read(fd, &psinfo, sizeof(psinfo_t)) != sizeof(psinfo_t)) { 0072 close(fd); 0073 return -1; 0074 } 0075 close(fd); 0076 ppid = psinfo.pr_ppid; 0077 0078 return ppid; 0079 } 0080 0081 bool ProcessesLocal::updateProcessInfo(long pid, Process *process) 0082 { 0083 int fd, pfd; 0084 psinfo_t psinfo; 0085 prusage_t prusage; 0086 0087 snprintf(d->mBuf, PROCESS_BUFFER_SIZE - 1, "%s/%ld/psinfo", PROCDIR, pid); 0088 if ((fd = open(d->mBuf, O_RDONLY)) < 0) { 0089 return false; /* process has terminated in the meantime */ 0090 } 0091 0092 snprintf(d->mBuf, PROCESS_BUFFER_SIZE - 1, "%s/%ld/usage", PROCDIR, pid); 0093 if ((pfd = open(d->mBuf, O_RDONLY)) < 0) { 0094 close(fd); 0095 return false; /* process has terminated in the meantime */ 0096 } 0097 0098 process->uid = 0; 0099 process->gid = 0; 0100 process->tracerpid = -1; 0101 process->pid() = pid; 0102 0103 if (read(fd, &psinfo, sizeof(psinfo_t)) != sizeof(psinfo_t)) { 0104 close(fd); 0105 return false; 0106 } 0107 close(fd); 0108 0109 if (read(pfd, &prusage, sizeof(prusage_t)) != sizeof(prusage_t)) { 0110 close(pfd); 0111 return false; 0112 } 0113 close(pfd); 0114 0115 process->setUid(psinfo.pr_uid); 0116 process->setEuid(psinfo.pr_euid); 0117 process->setGid(psinfo.pr_gid); 0118 process->setEgid(psinfo.pr_egid); 0119 0120 switch ((int)psinfo.pr_lwp.pr_state) { 0121 case SIDL: 0122 case SWAIT: 0123 case SSLEEP: 0124 process->setStatus(Process::Sleeping); 0125 break; 0126 case SONPROC: 0127 case SRUN: 0128 process->setStatus(Process::Running); 0129 break; 0130 case SZOMB: 0131 process->setStatus(Process::Zombie); 0132 break; 0133 case SSTOP: 0134 process->setStatus(Process::Stopped); 0135 break; 0136 default: 0137 process->setStatus(Process::OtherStatus); 0138 break; 0139 } 0140 0141 process->setVmRSS(psinfo.pr_rssize); 0142 process->setVmSize(psinfo.pr_size); 0143 process->setVmURSS(-1); 0144 0145 if (process->command.isNull()) { 0146 QString name(psinfo.pr_fname); 0147 0148 name = name.trimmed(); 0149 if (!name.isEmpty()) { 0150 name.remove(QRegExp("^[^ ]*/")); 0151 } 0152 process->setName(name); 0153 name = psinfo.pr_fname; 0154 name.append(psinfo.pr_psargs); 0155 process->setCommand(name); 0156 } 0157 0158 // Approximations, not quite accurate. Needs more changes in ksysguard to map 0159 // RR and FIFO to current Solaris classes. 0160 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) { 0161 process->setscheduler(KSysGuard::Process::Other); 0162 0163 } else if (strcmp(psinfo.pr_lwp.pr_clname, "FX") == 0 || strcmp(psinfo.pr_lwp.pr_clname, "RT") == 0) { 0164 process->setscheduler(KSysGuard::Process::RoundRobin); 0165 0166 } else if (strcmp(psinfo.pr_lwp.pr_clname, "IA") == 0) { 0167 process->setscheduler(KSysGuard::Process::Interactive); 0168 } 0169 process->setNiceLevel(psinfo.pr_lwp.pr_pri); 0170 process->setUserTime(prusage.pr_utime.tv_sec * 100 + prusage.pr_utime.tv_nsec / 10000000.0); 0171 process->setSysTime(prusage.pr_stime.tv_sec * 100 + prusage.pr_stime.tv_nsec / 10000000.0); 0172 return false; 0173 } 0174 0175 QSet<long> ProcessesLocal::getAllPids() 0176 { 0177 QSet<long> pids; 0178 long pid; 0179 0180 if (d->mProcDir == NULL) { 0181 return pids; // There's not much we can do without /proc 0182 } 0183 struct dirent *entry; 0184 rewinddir(d->mProcDir); 0185 while ((entry = readdir(d->mProcDir))) 0186 if (entry->d_name[0] >= '0' && entry->d_name[0] <= '9') { 0187 pid = atol(entry->d_name); 0188 // Skip all processes with parent id = 0 except init 0189 if (pid == 1 || getParentPid(pid) > 0) { 0190 pids.insert(pid); 0191 } 0192 } 0193 return pids; 0194 } 0195 0196 Processes::Error ProcessesLocal::sendSignal(long pid, int sig) 0197 { 0198 if (kill((pid_t)pid, sig)) { 0199 // Kill failed 0200 return Processes::Unknown; 0201 } 0202 return Processes::NoError; 0203 } 0204 0205 /* 0206 * 0207 */ 0208 Processes::Error ProcessesLocal::setNiceness(long pid, int priority) 0209 { 0210 return Processes::NotSupported; 0211 } 0212 0213 Processes::Error ProcessesLocal::setScheduler(long pid, int priorityClass, int priority) 0214 { 0215 return Processes::NotSupported; 0216 } 0217 0218 Processes::Error ProcessesLocal::setIoNiceness(long pid, int priorityClass, int priority) 0219 { 0220 return Processes::NotSupported; // Not yet supported 0221 } 0222 0223 bool ProcessesLocal::supportsIoNiceness() 0224 { 0225 return false; 0226 } 0227 0228 long long ProcessesLocal::totalPhysicalMemory() 0229 { 0230 long long memory = ((long long)sysconf(_SC_PHYS_PAGES)) * (sysconf(_SC_PAGESIZE) / 1024); 0231 if (memory > 0) { 0232 return memory; 0233 } 0234 return 0; 0235 } 0236 0237 ProcessesLocal::~ProcessesLocal() 0238 { 0239 delete d; 0240 } 0241 0242 }