master ohmu/fastfetch-openbsd / src / detection / top / top_obsd.c
ohmu  ·  2026-10-15
 1#include "top.h"
 2
 3#include "common/debug.h"
 4#include "common/mallocHelper.h"
 5
 6#include <errno.h>
 7#include <string.h>
 8#include <sys/types.h>
 9#include <sys/param.h> // DEV_BSIZE
10#include <sys/sysctl.h>
11
12const char* ffTopGetProcessSnapshot(FFlist* snapshots, FFTopTypes showTypes) {
13    int request[] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0, (int) sizeof(struct kinfo_proc), 0 };
14    size_t length = 0;
15
16    if (sysctl(request, ARRAY_SIZE(request), nullptr, &length, nullptr, 0) != 0) {
17        FF_DEBUG("sysctl({CTL_KERN, KERN_PROC, KERN_PROC_ALL}, nullptr) failed: %s", strerror(errno));
18        return "sysctl({CTL_KERN, KERN_PROC, KERN_PROC_ALL}, nullptr) failed";
19    }
20
21    FF_AUTO_FREE struct kinfo_proc* processes = (struct kinfo_proc*) malloc(length);
22    request[5] = (int) (length / sizeof(struct kinfo_proc)); // count must be non-zero for data fetch
23    if (sysctl(request, ARRAY_SIZE(request), processes, &length, nullptr, 0) != 0) {
24        FF_DEBUG("sysctl({CTL_KERN, KERN_PROC, KERN_PROC_ALL}, processes) failed: %s", strerror(errno));
25        return "sysctl({CTL_KERN, KERN_PROC, KERN_PROC_ALL}, processes) failed";
26    }
27
28    int count = (int) (length / sizeof(struct kinfo_proc));
29    const uint32_t pageSizeShift = instance.state.platform.sysinfo.pageSizeShift;
30
31    for (int i = 0; i < count; ++i) {
32        const struct kinfo_proc* proc = &processes[i];
33
34        if (!proc->p_uvalid) { // Zombie process; p_u* members are invalid
35            continue;
36        }
37
38        FFTopProcessSnapshot* item = FF_LIST_ADD(FFTopProcessSnapshot, *snapshots);
39        ffStrbufInitS(&item->name, proc->p_comm);
40        item->pid = (uint32_t) proc->p_pid;
41        item->cpuTime = ((uint64_t) proc->p_uutime_sec * 1000 + (uint64_t) proc->p_uutime_usec / 1000) +
42            ((uint64_t) proc->p_ustime_sec * 1000 + (uint64_t) proc->p_ustime_usec / 1000);
43        item->memBytes = (uint64_t) proc->p_vm_rssize << pageSizeShift;
44        item->startTime = (uint64_t) proc->p_ustart_sec * 1000 + (uint64_t) proc->p_ustart_usec / 1000;
45        item->bytesRead = (uint64_t) proc->p_uru_inblock * DEV_BSIZE;
46        item->bytesWritten = (uint64_t) proc->p_uru_oublock * DEV_BSIZE;
47        item->threads = 0;
48    }
49
50    if (showTypes & FF_TOP_TYPE_THREADS) {
51        int threadRequest[] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL | KERN_PROC_SHOW_THREADS, 0, (int) sizeof(struct kinfo_proc), 0 };
52        size_t threadLength = 0;
53        if (sysctl(threadRequest, ARRAY_SIZE(threadRequest), nullptr, &threadLength, nullptr, 0) == 0 && threadLength > 0) {
54            FF_AUTO_FREE struct kinfo_proc* threads = (struct kinfo_proc*) malloc(threadLength);
55            threadRequest[5] = (int) (threadLength / sizeof(struct kinfo_proc)); // count must be non-zero for data fetch
56            if (sysctl(threadRequest, ARRAY_SIZE(threadRequest), threads, &threadLength, nullptr, 0) == 0) {
57                int threadCount = (int) (threadLength / sizeof(struct kinfo_proc));
58                for (uint32_t i = 0; i < snapshots->length; ++i) {
59                    FFTopProcessSnapshot* item = FF_LIST_GET(FFTopProcessSnapshot, *snapshots, i);
60                    for (int j = 0; j < threadCount; ++j) {
61                        if (threads[j].p_pid == (pid_t) item->pid && threads[j].p_tid != -1) {
62                            ++item->threads;
63                        }
64                    }
65                }
66            }
67        }
68    }
69
70    return nullptr;
71}