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 }