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 }