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