master ohmu/fastfetch-openbsd / src / detection / top / top_apple.c
ohmu  ·  2026-10-15
 1#include "top.h"
 2#include "common/debug.h"
 3#include "common/mallocHelper.h"
 4
 5#include <errno.h>
 6#include <string.h>
 7#include <sys/sysctl.h>
 8#include <libproc.h>
 9
10const char* ffTopGetProcessSnapshot(FFlist* snapshots, FFTopTypes showTypes) {
11    int npids = proc_listallpids(nullptr, 0);
12    if (npids <= 0) {
13        FF_DEBUG("proc_listallpids(nullptr, 0) failed: %s", strerror(errno));
14        return "proc_listallpids(nullptr, 0) failed";
15    }
16    // `proc_listallpids` returns the number of pids, but it wants the size of the buffer in bytes:
17    // passing the count back would only let the kernel fill a quarter of it.
18    const int pidCapacity = npids + npids / 8 + 1;
19    FF_AUTO_FREE pid_t* pids = malloc((size_t) pidCapacity * sizeof(pid_t));
20    if (pids == nullptr) {
21        FF_DEBUG("malloc(%zu) for %d pids failed", (size_t) pidCapacity * sizeof(pid_t), pidCapacity);
22        return "malloc() failed";
23    }
24    npids = proc_listallpids(pids, pidCapacity * (int) sizeof(pid_t));
25    if (npids <= 0) {
26        FF_DEBUG("proc_listallpids(pids, %d) failed: %s", pidCapacity * (int) sizeof(pid_t), strerror(errno));
27        return "proc_listallpids(pids, bufferSize) failed";
28    }
29
30    uint32_t count = (uint32_t) npids;
31
32    for (uint32_t i = 0; i < count; ++i) {
33        pid_t pid = pids[i];
34
35        struct proc_taskallinfo proc;
36        if (proc_pidinfo(pid, PROC_PIDTASKALLINFO, 0, &proc, sizeof(proc)) != sizeof(proc)) {
37            continue;
38        }
39
40        if (proc.pbsd.pbi_flags & PROC_FLAG_SYSTEM) {
41            continue;
42        }
43
44        FFTopProcessSnapshot* item = FF_LIST_ADD(FFTopProcessSnapshot, *snapshots);
45        ffStrbufInitS(&item->name, proc.pbsd.pbi_name);
46        if (item->name.length == 0) {
47            ffStrbufInitS(&item->name, proc.pbsd.pbi_comm);
48        }
49        item->pid = (uint32_t) pid;
50        item->cpuTime = (proc.ptinfo.pti_total_user + proc.ptinfo.pti_total_system) / 1000000u; // ns -> ms
51        item->memBytes = proc.ptinfo.pti_resident_size;
52        item->startTime = proc.pbsd.pbi_start_tvsec * 1000u + proc.pbsd.pbi_start_tvusec / 1000u; // convert to ms
53        item->threads = (uint32_t) proc.ptinfo.pti_threadnum;
54
55        // FF_LIST_ADD does not zero the element, and top.c subtracts both counters for every
56        // process it samples, whether or not they were collected.
57        item->bytesRead = 0;
58        item->bytesWritten = 0;
59        if (showTypes & FF_TOP_TYPE_DISK) {
60            struct rusage_info_v2 rusage;
61            if (proc_pid_rusage(pid, RUSAGE_INFO_V2, (rusage_info_t*) &rusage) == 0) {
62                item->bytesRead = rusage.ri_diskio_bytesread;
63                item->bytesWritten = rusage.ri_diskio_byteswritten;
64            }
65        }
66    }
67
68    return nullptr;
69}