File indexing completed on 2024-05-19 03:56:25

0001 /*
0002 
0003     This file is part of the KDE Frameworks
0004 
0005     SPDX-FileCopyrightText: 2019 Tobias C. Berner <tcberner@FreeBSD.org>
0006 
0007     SPDX-License-Identifier: LGPL-2.1-only
0008 */
0009 
0010 #pragma once
0011 
0012 #include <sys/param.h>
0013 #include <sys/sysctl.h>
0014 #include <sys/types.h>
0015 #include <sys/user.h>
0016 
0017 #include <sys/queue.h> // Must be included before libprocstat.h, otherwise this fails to build on FreeBSD
0018 
0019 #include <libprocstat.h>
0020 
0021 namespace KProcessList
0022 {
0023 struct ProcStat {
0024 public:
0025     struct procstat *pstat;
0026     ProcStat()
0027     {
0028         pstat = procstat_open_sysctl();
0029     }
0030 
0031     ~ProcStat()
0032     {
0033         procstat_close(pstat);
0034     }
0035 
0036     operator bool() const
0037     {
0038         return pstat;
0039     }
0040 };
0041 
0042 struct ProcStatProcesses {
0043 private:
0044     ProcStat &parent;
0045     unsigned int proc_count;
0046     struct kinfo_proc *procs;
0047 
0048 public:
0049     ProcStatProcesses(ProcStat &pstat)
0050         : parent(pstat)
0051     {
0052         procs = procstat_getprocs(parent.pstat, KERN_PROC_PROC, 0, &proc_count);
0053     }
0054 
0055     ~ProcStatProcesses()
0056     {
0057         if (procs) {
0058             procstat_freeprocs(parent.pstat, procs);
0059         }
0060     }
0061 
0062     operator bool() const
0063     {
0064         return procs && proc_count > 0;
0065     }
0066 
0067     unsigned int count() const
0068     {
0069         return proc_count;
0070     }
0071 
0072     class ProcessIterator
0073     {
0074     private:
0075         const ProcStatProcesses &processes;
0076         unsigned int pos;
0077 
0078     public:
0079         ProcessIterator(const ProcStatProcesses &processes, unsigned int pos)
0080             : processes(processes)
0081             , pos(pos){};
0082 
0083         bool operator!=(const ProcessIterator &other) const
0084         {
0085             return pos != other.pos;
0086         }
0087 
0088         ProcessIterator &operator++()
0089         {
0090             if (pos < processes.count()) {
0091                 ++pos;
0092             }
0093             return *this;
0094         }
0095 
0096         const KProcessInfo operator*()
0097         {
0098             QStringList command_line;
0099             QString command;
0100             struct kinfo_proc *proc = &processes.procs[pos];
0101 
0102             // Don't use procstat_getpathname() because:
0103             // - it can fail, and then it spams a warning to stderr
0104             // - it produces a full path, e.g. /tmp/kde/build/kcoreaddons/bin/kprocesslisttest
0105             //   rather than the command-name, so it fails in tests that check for
0106             //   a process name only.
0107             command = QString::fromLocal8Bit(proc->ki_comm);
0108 
0109             char **args;
0110             args = procstat_getargv(processes.parent.pstat, proc, 0);
0111             if (args) {
0112                 for (int i = 0; args[i] != nullptr; i++) {
0113                     command_line << QString::fromLocal8Bit(args[i]);
0114                 }
0115             }
0116 
0117             pid_t pid = proc->ki_pid;
0118             QString user = QString::fromLocal8Bit(proc->ki_login);
0119             return KProcessInfo(pid, command_line.join(QString::fromLocal8Bit(" ")), command, user);
0120         }
0121     };
0122 
0123     ProcessIterator begin() const
0124     {
0125         return ProcessIterator(*this, 0);
0126     }
0127     ProcessIterator end() const
0128     {
0129         return ProcessIterator(*this, this->count());
0130     }
0131 };
0132 }