File indexing completed on 2024-04-28 05:31:39
0001 /* 0002 SPDX-FileCopyrightText: 2007 John Tapsell <tapsell@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "processes_remote_p.h" 0008 #include "process.h" 0009 #include "processcore_debug.h" 0010 0011 #include <QDebug> 0012 #include <QString> 0013 #include <QTimer> 0014 0015 namespace KSysGuard 0016 { 0017 class ProcessesRemote::Private 0018 { 0019 public: 0020 Private() 0021 : numColumns(0) 0022 , freeMemory(0) 0023 { 0024 havePsInfo = false; 0025 pidColumn = 1; 0026 ppidColumn = nameColumn = uidColumn = gidColumn = statusColumn = userColumn = systemColumn = niceColumn = vmSizeColumn = vmRSSColumn = loginColumn = 0027 commandColumn = tracerPidColumn = ttyColumn = ioprioClassColumn = ioprioColumn = vmURSSColumn = noNewPrivilegesColumn = cGroupColumn = 0028 macContextColumn = -1; 0029 usedMemory = freeMemory; 0030 } 0031 ~Private() 0032 { 0033 } 0034 QString host; 0035 QList<QByteArray> lastAnswer; 0036 QSet<long> pids; 0037 QHash<long, QList<QByteArray>> processByPid; 0038 0039 bool havePsInfo; 0040 int pidColumn; 0041 int ppidColumn; 0042 int tracerPidColumn; 0043 int nameColumn; 0044 int uidColumn; 0045 int gidColumn; 0046 int statusColumn; 0047 int userColumn; 0048 int systemColumn; 0049 int niceColumn; 0050 int vmSizeColumn; 0051 int vmRSSColumn; 0052 int vmURSSColumn; 0053 int loginColumn; 0054 int commandColumn; 0055 int ioprioClassColumn; 0056 int ioprioColumn; 0057 int ttyColumn; 0058 int noNewPrivilegesColumn; 0059 int cGroupColumn; 0060 int macContextColumn; 0061 0062 int numColumns; 0063 0064 long freeMemory; 0065 long usedMemory; 0066 0067 Processes::UpdateFlags updateFlags; 0068 }; 0069 ProcessesRemote::ProcessesRemote(const QString &hostname) 0070 : d(new Private()) 0071 { 0072 d->host = hostname; 0073 QTimer::singleShot(0, this, &ProcessesRemote::setup); 0074 } 0075 0076 void ProcessesRemote::setup() 0077 { 0078 Q_EMIT runCommand(QStringLiteral("mem/physical/used"), (int)UsedMemory); 0079 Q_EMIT runCommand(QStringLiteral("mem/physical/free"), (int)FreeMemory); 0080 Q_EMIT runCommand(QStringLiteral("ps?"), (int)PsInfo); 0081 Q_EMIT runCommand(QStringLiteral("ps"), (int)Ps); 0082 } 0083 0084 long ProcessesRemote::getParentPid(long pid) 0085 { 0086 if (!d->processByPid.contains(pid)) { 0087 qCDebug(LIBKSYSGUARD_PROCESSCORE) << "Parent pid requested for pid that we do not have info on " << pid; 0088 return 0; 0089 } 0090 if (d->ppidColumn == -1) { 0091 qCDebug(LIBKSYSGUARD_PROCESSCORE) << "ppid column not known "; 0092 return 0; 0093 } 0094 return d->processByPid[pid].at(d->ppidColumn).toLong(); 0095 } 0096 bool ProcessesRemote::updateProcessInfo(long pid, Process *process) 0097 { 0098 Q_CHECK_PTR(process); 0099 if (!d->processByPid.contains(pid)) { 0100 qCDebug(LIBKSYSGUARD_PROCESSCORE) << "update request for pid that we do not have info on " << pid; 0101 return false; 0102 } 0103 QList<QByteArray> p = d->processByPid[pid]; 0104 0105 if (d->nameColumn != -1) { 0106 process->setName(QString::fromUtf8(p.at(d->nameColumn))); 0107 } 0108 if (d->uidColumn != -1) { 0109 process->setUid(p.at(d->uidColumn).toLong()); 0110 } 0111 if (d->gidColumn != -1) { 0112 process->setGid(p.at(d->gidColumn).toLong()); 0113 } 0114 if (d->statusColumn != -1) { 0115 switch (p.at(d->statusColumn)[0]) { 0116 case 's': 0117 process->setStatus(Process::Sleeping); 0118 break; 0119 case 'r': 0120 process->setStatus(Process::Running); 0121 break; 0122 } 0123 } 0124 if (d->userColumn != -1) { 0125 process->setUserTime(p.at(d->userColumn).toLong()); 0126 } 0127 if (d->systemColumn != -1) { 0128 process->setSysTime(p.at(d->systemColumn).toLong()); 0129 } 0130 if (d->niceColumn != -1) { 0131 process->setNiceLevel(p.at(d->niceColumn).toLong()); 0132 } 0133 if (d->vmSizeColumn != -1) { 0134 process->setVmSize(p.at(d->vmSizeColumn).toLong()); 0135 } 0136 if (d->vmRSSColumn != -1) { 0137 process->setVmRSS(p.at(d->vmRSSColumn).toLong()); 0138 } 0139 if (d->vmURSSColumn != -1) { 0140 process->setVmURSS(p.at(d->vmURSSColumn).toLong()); 0141 } 0142 if (d->loginColumn != -1) { 0143 process->setLogin(QString::fromUtf8(p.at(d->loginColumn).data())); 0144 } 0145 if (d->commandColumn != -1) { 0146 process->setCommand(QString::fromUtf8(p.at(d->commandColumn).data())); 0147 } 0148 if (d->tracerPidColumn != -1) { 0149 process->setTracerpid(p.at(d->tracerPidColumn).toLong()); 0150 } 0151 if (d->vmURSSColumn != -1) { 0152 process->setVmURSS(p.at(d->vmURSSColumn).toLong()); 0153 } 0154 if (d->ttyColumn != -1) { 0155 process->setTty(p.at(d->ttyColumn)); 0156 } 0157 if (d->ioprioColumn != -1) { 0158 process->setIoniceLevel(p.at(d->ioprioColumn).toInt()); 0159 } 0160 if (d->ioprioClassColumn != -1) { 0161 process->setIoPriorityClass((KSysGuard::Process::IoPriorityClass)(p.at(d->ioprioClassColumn).toInt())); 0162 } 0163 if (d->noNewPrivilegesColumn != -1) { 0164 process->setNoNewPrivileges(p.at(d->noNewPrivilegesColumn).toLong()); 0165 } 0166 if (d->cGroupColumn != -1) { 0167 process->setCGroup(QString::fromUtf8(p.at(d->cGroupColumn))); 0168 } 0169 if (d->macContextColumn != -1) { 0170 process->setMACContext(QString::fromUtf8(p.at(d->macContextColumn))); 0171 } 0172 0173 return true; 0174 } 0175 0176 void ProcessesRemote::updateAllProcesses(Processes::UpdateFlags updateFlags) 0177 { 0178 d->updateFlags = updateFlags; 0179 if (!d->havePsInfo) { 0180 Q_EMIT runCommand(QStringLiteral("ps?"), (int)PsInfo); 0181 } 0182 Q_EMIT runCommand(QStringLiteral("ps"), (int)Ps); 0183 } 0184 QSet<long> ProcessesRemote::getAllPids() 0185 { 0186 d->pids.clear(); 0187 d->processByPid.clear(); 0188 Q_FOREACH (const QByteArray &process, d->lastAnswer) { 0189 QList<QByteArray> info = process.split('\t'); 0190 if (info.size() == d->numColumns) { 0191 int pid = info.at(d->pidColumn).toLong(); 0192 Q_ASSERT(!d->pids.contains(pid)); 0193 d->pids << pid; 0194 d->processByPid[pid] = info; 0195 } 0196 } 0197 return d->pids; 0198 } 0199 0200 Processes::Error ProcessesRemote::sendSignal(long pid, int sig) 0201 { 0202 // TODO run the proper command for all these functions below 0203 Q_EMIT runCommand(QStringLiteral("kill ") + QString::number(pid) + QStringLiteral(" ") + QString::number(sig), (int)Kill); 0204 return Processes::NoError; 0205 } 0206 Processes::Error ProcessesRemote::setNiceness(long pid, int priority) 0207 { 0208 Q_EMIT runCommand(QStringLiteral("setpriority ") + QString::number(pid) + QStringLiteral(" ") + QString::number(priority), (int)Renice); 0209 return Processes::NoError; 0210 } 0211 0212 Processes::Error ProcessesRemote::setIoNiceness(long pid, int priorityClass, int priority) 0213 { 0214 Q_EMIT runCommand(QStringLiteral("ionice ") + QString::number(pid) + QStringLiteral(" ") + QString::number(priorityClass) + QStringLiteral(" ") 0215 + QString::number(priority), 0216 (int)Ionice); 0217 return Processes::NoError; 0218 } 0219 0220 Processes::Error ProcessesRemote::setScheduler(long pid, int priorityClass, int priority) 0221 { 0222 Q_UNUSED(pid); 0223 Q_UNUSED(priorityClass); 0224 Q_UNUSED(priority); 0225 0226 return Processes::NotSupported; 0227 } 0228 0229 bool ProcessesRemote::supportsIoNiceness() 0230 { 0231 return true; 0232 } 0233 0234 long long ProcessesRemote::totalPhysicalMemory() 0235 { 0236 return d->usedMemory + d->freeMemory; 0237 } 0238 long ProcessesRemote::numberProcessorCores() 0239 { 0240 return 0; 0241 } 0242 0243 void ProcessesRemote::answerReceived(int id, const QList<QByteArray> &answer) 0244 { 0245 switch (id) { 0246 case PsInfo: { 0247 if (answer.isEmpty()) { 0248 return; // Invalid data 0249 } 0250 QList<QByteArray> info = answer.at(0).split('\t'); 0251 d->numColumns = info.size(); 0252 for (int i = 0; i < d->numColumns; i++) { 0253 if (info[i] == "Name") { 0254 d->nameColumn = i; 0255 } else if (info[i] == "PID") { 0256 d->pidColumn = i; 0257 } else if (info[i] == "PPID") { 0258 d->ppidColumn = i; 0259 } else if (info[i] == "UID") { 0260 d->uidColumn = i; 0261 } else if (info[i] == "GID") { 0262 d->gidColumn = i; 0263 } else if (info[i] == "TracerPID") { 0264 d->tracerPidColumn = i; 0265 } else if (info[i] == "Status") { 0266 d->statusColumn = i; 0267 } else if (info[i] == "User Time") { 0268 d->userColumn = i; 0269 } else if (info[i] == "System Time") { 0270 d->systemColumn = i; 0271 } else if (info[i] == "Nice") { 0272 d->niceColumn = i; 0273 } else if (info[i] == "VmSize") { 0274 d->vmSizeColumn = i; 0275 } else if (info[i] == "VmRss") { 0276 d->vmRSSColumn = i; 0277 } else if (info[i] == "VmURss") { 0278 d->vmURSSColumn = i; 0279 } else if (info[i] == "Login") { 0280 d->loginColumn = i; 0281 } else if (info[i] == "TTY") { 0282 d->ttyColumn = i; 0283 } else if (info[i] == "Command") { 0284 d->commandColumn = i; 0285 } else if (info[i] == "IO Priority Class") { 0286 d->ioprioClassColumn = i; 0287 } else if (info[i] == "IO Priority") { 0288 d->ioprioColumn = i; 0289 } else if (info[i] == "NNP") { 0290 d->noNewPrivilegesColumn = i; 0291 } else if (info[i] == "CGroup") { 0292 d->cGroupColumn = i; 0293 } else if (info[i] == "MAC Context") { 0294 d->macContextColumn = i; 0295 } 0296 } 0297 d->havePsInfo = true; 0298 break; 0299 } 0300 case Ps: 0301 d->lastAnswer = answer; 0302 if (!d->havePsInfo) { 0303 return; // Not setup yet. Should never happen 0304 } 0305 Q_EMIT processesUpdated(); 0306 break; 0307 case FreeMemory: 0308 if (answer.isEmpty()) { 0309 return; // Invalid data 0310 } 0311 d->freeMemory = answer[0].toLong(); 0312 break; 0313 case UsedMemory: 0314 if (answer.isEmpty()) { 0315 return; // Invalid data 0316 } 0317 d->usedMemory = answer[0].toLong(); 0318 break; 0319 } 0320 } 0321 0322 ProcessesRemote::~ProcessesRemote() 0323 { 0324 delete d; 0325 } 0326 0327 }