Processes: adds option countKprocs

This commit is contained in:
Carter Li
2026-08-28 17:40:57 +08:00
committed by 李通洲
parent 41da49f579
commit 7fe08bddd0
15 changed files with 216 additions and 101 deletions
+2 -1
View File
@@ -813,7 +813,6 @@ elseif(FreeBSD)
src/detection/os/os_linux.c
src/detection/packages/packages_bsd.c
src/detection/poweradapter/poweradapter_nosupport.c
src/detection/processes/processes_bsd.c
src/detection/gtk_qt/qt.c
src/detection/sound/sound_bsd.c
src/detection/swap/swap_bsd.c
@@ -833,12 +832,14 @@ elseif(FreeBSD)
if(DragonFly)
list(APPEND LIBFASTFETCH_SRC
src/detection/bluetooth/bluetooth_nosupport.c
src/detection/processes/processes_dbsd.c
src/detection/top/top_dbsd.c
src/detection/wifi/wifi_nosupport.c
)
else()
list(APPEND LIBFASTFETCH_SRC
src/detection/bluetooth/bluetooth_bsd.c
src/detection/processes/processes_bsd.c
src/detection/top/top_bsd.c
src/detection/wifi/wifi_bsd.c
)
+6 -1
View File
@@ -3984,7 +3984,12 @@
"properties": {
"type": {
"const": "processes",
"description": "Print the number of running processes"
"description": "Print the number of running processes and threads"
},
"countKprocs": {
"description": "Whether to take kernel processes and threads into account",
"type": "boolean",
"default": false
},
"key": {
"$ref": "#/$defs/key"
+2 -1
View File
@@ -1,6 +1,7 @@
#pragma once
#include "fastfetch.h"
#include "modules/processes/option.h"
typedef struct FFProcessesResult
{
@@ -8,4 +9,4 @@ typedef struct FFProcessesResult
uint32_t threads;
} FFProcessesResult;
const char* ffDetectProcesses(FFProcessesResult* result);
const char* ffDetectProcesses(const FFProcessesOptions* options, FFProcessesResult* result);
+32 -12
View File
@@ -1,21 +1,41 @@
#include "processes.h"
#include "common/mallocHelper.h"
#include <sys/sysctl.h>
#import <libproc.h>
const char* ffDetectProcesses(FFProcessesResult* result) {
FF_AUTO_FREE pid_t* pids = malloc(sizeof(pid_t) * 0x1000);
int count = proc_listallpids(pids, 0x1000);
int trdCount = 0;
for (int index = 0; index < count; ++index) {
struct proc_taskinfo taskInfo;
if (proc_pidinfo(pids[index], PROC_PIDTASKINFO, 0, &taskInfo, sizeof(taskInfo)) != sizeof(taskInfo)) {
continue;
}
trdCount += taskInfo.pti_threadnum;
const char* ffDetectProcesses(const FFProcessesOptions* options, FFProcessesResult* result) {
int request[] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL };
size_t length;
if (sysctl(request, ARRAY_SIZE(request), nullptr, &length, nullptr, 0) != 0) {
return "sysctl({CTL_KERN, KERN_PROC, KERN_PROC_ALL, nullptr}) failed";
}
// The process table may change between the two sysctl calls; retry with a larger buffer.
length += length / 8 + sizeof(struct kinfo_proc);
FF_AUTO_FREE struct kinfo_proc* processes = malloc(length);
if (sysctl(request, ARRAY_SIZE(request), processes, &length, nullptr, 0) != 0) {
return "sysctl({CTL_KERN, KERN_PROC, KERN_PROC_ALL, processes}) failed";
}
uint32_t count = (uint32_t) (length / sizeof(struct kinfo_proc));
for (uint32_t i = 0; i < count; ++i) {
const struct kinfo_proc* proc = &processes[i];
if (!options->countKprocs && (proc->kp_proc.p_flag & P_SYSTEM)) {
continue;
}
result->processes++;
pid_t pid = proc->kp_proc.p_pid;
struct proc_taskinfo taskInfo;
if (proc_pidinfo(pid, PROC_PIDTASKINFO, 0, &taskInfo, sizeof(taskInfo)) != sizeof(taskInfo)) {
continue;
}
result->threads += taskInfo.pti_threadnum;
}
result->processes = (uint32_t) count;
result->threads = (uint32_t) trdCount;
return nullptr;
}
+22 -10
View File
@@ -1,23 +1,35 @@
#include "processes.h"
#include "common/mallocHelper.h"
#include <sys/sysctl.h>
#include <sys/types.h>
#include <sys/user.h>
const char* ffDetectProcesses(FFProcessesResult* result) {
int procRequest[] = { CTL_KERN, KERN_PROC, KERN_PROC_PROC };
size_t procLength;
if (sysctl(procRequest, ARRAY_SIZE(procRequest), nullptr, &procLength, nullptr, 0) != 0) {
const char* ffDetectProcesses(const FFProcessesOptions* options, FFProcessesResult* result) {
int request[] = { CTL_KERN, KERN_PROC, KERN_PROC_PROC };
size_t length;
if (sysctl(request, ARRAY_SIZE(request), nullptr, &length, nullptr, 0) != 0) {
return "sysctl({CTL_KERN, KERN_PROC, KERN_PROC_PROC}) failed";
}
int threadRequest[] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL };
size_t threadLength;
if (sysctl(threadRequest, ARRAY_SIZE(threadRequest), nullptr, &threadLength, nullptr, 0) != 0) {
return "sysctl({CTL_KERN, KERN_PROC, KERN_PROC_ALL}) failed";
// The process table may change between the two sysctl calls; retry with a larger buffer.
length += length / 8 + sizeof(struct kinfo_proc);
FF_AUTO_FREE struct kinfo_proc* procs = malloc(length);
if (sysctl(request, ARRAY_SIZE(request), procs, &length, nullptr, 0) != 0) {
return "sysctl({CTL_KERN, KERN_PROC, KERN_PROC_PROC}) failed";
}
uint32_t count = (uint32_t) (length / sizeof(struct kinfo_proc));
for (uint32_t i = 0; i < count; ++i) {
const struct kinfo_proc* proc = &procs[i];
if (!options->countKprocs && (proc->ki_flag & P_KPROC)) {
continue;
}
result->processes++;
result->threads += (uint32_t) proc->ki_numthreads;
}
result->processes = (uint32_t) (procLength / sizeof(struct kinfo_proc));
result->threads = (uint32_t) (threadLength / sizeof(struct kinfo_proc));
return nullptr;
}
+38
View File
@@ -0,0 +1,38 @@
#include "processes.h"
#include "common/mallocHelper.h"
#include <sys/sysctl.h>
#include <sys/types.h>
#include <sys/user.h>
#include <sys/proc.h>
const char* ffDetectProcesses(const FFProcessesOptions* options, FFProcessesResult* result) {
int request[] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL | (options->countKprocs ? KERN_PROC_FLAG_LWKT : 0) };
size_t length;
if (sysctl(request, ARRAY_SIZE(request), nullptr, &length, nullptr, 0) != 0) {
return "sysctl({CTL_KERN, KERN_PROC, KERN_PROC_ALL}) failed";
}
// The process table may change between the two sysctl calls; retry with a larger buffer.
length += length / 8 + sizeof(struct kinfo_proc);
FF_AUTO_FREE struct kinfo_proc* procs = malloc(length);
if (sysctl(request, ARRAY_SIZE(request), procs, &length, nullptr, 0) != 0) {
return "sysctl({CTL_KERN, KERN_PROC, KERN_PROC_ALL}) failed";
}
uint32_t count = (uint32_t) (length / sizeof(struct kinfo_proc));
for (uint32_t i = 0; i < count; ++i) {
const struct kinfo_proc* proc = &procs[i];
if (proc->kp_pid == -1) {
// Kernel thread, only returned when countKprocs is set via KERN_PROC_FLAG_LWKT
result->threads++;
continue;
}
result->processes++;
result->threads += (uint32_t) proc->kp_nthreads;
}
return nullptr;
}
+14 -13
View File
@@ -3,7 +3,7 @@
#include <hurd.h>
#include <ps.h>
const char* ffDetectProcesses(FFProcessesResult* result) {
const char* ffDetectProcesses(const FFProcessesOptions* options, FFProcessesResult* result) {
struct ps_context* context = nullptr;
if (ps_context_create(getproc(), &context) != 0) {
return "ps_context_create(getproc()) failed";
@@ -16,26 +16,27 @@ const char* ffDetectProcesses(FFProcessesResult* result) {
goto done;
}
struct proc_stat **stats = nullptr;
unsigned int numProcs = 0;
if (proc_stat_list_add_all(list, &stats, &numProcs) != 0) {
if (proc_stat_list_add_all(list, nullptr, nullptr) != 0) {
error = "proc_stat_list_add_all() failed";
goto done;
}
uint32_t nthread = 0;
for (unsigned int i = 0; i < numProcs; i++) {
proc_stat_get_basic_info(stats[i]);
nthread += proc_stat_thread_count(stats[i]);
proc_stat_list_set_flags(list, PSTAT_NUM_THREADS);
for (uint32_t i = 0; i < list->num_procs; i++) {
struct proc_stat* stat = list->proc_stats[i];
if (!options->countKprocs && proc_stat_pid(stat) == 2) { // Kernel Task
continue;
}
if (proc_stat_has(stat, PSTAT_NUM_THREADS)) {
result->threads += proc_stat_num_threads(stat);
}
}
result->processes = (uint32_t) numProcs;
result->threads = nthread;
result->processes = (uint32_t) list->num_procs;
done:
if (stats) {
proc_stat_list_free_stats(stats, numProcs);
}
if (list) {
proc_stat_list_free(list);
}
+1 -1
View File
@@ -2,7 +2,7 @@
#include <OS.h>
const char* ffDetectProcesses(FFProcessesResult* result) {
const char* ffDetectProcesses(const FFProcessesOptions*, FFProcessesResult* result) {
system_info info;
if (get_system_info(&info) != B_OK) {
return "Error getting system info";
+33 -20
View File
@@ -4,26 +4,23 @@
#include "common/memrchr.h"
#include "common/strutil.h"
const char* ffDetectProcesses(FFProcessesResult* result) {
#define PF_KTHREAD 0x00200000 // defined in kernel include/linux/sched.h
const char* ffDetectProcesses(const FFProcessesOptions* options, FFProcessesResult* result) {
FF_AUTO_CLOSE_DIR DIR* dir = opendir("/proc");
if (dir == nullptr) {
return "opendir(\"/proc\") failed";
}
uint32_t processes = 0;
uint32_t threads = 0;
int procfd = dirfd(dir);
struct dirent* entry;
while ((entry = readdir(dir)) != nullptr) {
if ((entry->d_type == DT_DIR || entry->d_type == DT_UNKNOWN) && ffCharIsDigit(entry->d_name[0])) {
++processes;
char statPath[32];
strcpy(ffStrCopy(statPath, entry->d_name, sizeof(statPath)), "/stat");
char statBuffer[256];
char statBuffer[512];
ssize_t statLength = ffReadFileDataRelative(procfd, statPath, sizeof(statBuffer) - 1, statBuffer);
if (statLength < 0) {
continue;
@@ -34,27 +31,43 @@ const char* ffDetectProcesses(FFProcessesResult* result) {
if (!cursor) {
continue;
}
++cursor;
cursor += 2; // skip ") "
if (__builtin_expect(cursor >= statBuffer + statLength, false)) {
goto skip_process;
}
for (uint32_t field = 2 /*comm*/; field < 20 /*num_threads*/; ++field) {
while (*cursor != ' ' && __builtin_expect(*cursor != '\0', true)) {
++cursor;
char* p;
for (uint32_t field = 3; field <= 20 /*num_threads*/; ++field) {
switch (field) {
case 9: // flags
if ((strtoul(cursor, &p, 10) & PF_KTHREAD) && !options->countKprocs) {
goto skip_process;
}
cursor = p;
break;
case 20: // num_threads
result->threads += (uint32_t) strtoul(cursor, &p, 10);
cursor = p;
break;
default:
while (*cursor != ' ' && __builtin_expect(*cursor != '\0', true)) {
++cursor;
}
break;
}
++cursor;
if (__builtin_expect(*cursor == '\0', false)) {
break;
if (__builtin_expect(cursor >= statBuffer + statLength, false)) {
goto skip_process;
}
}
if (__builtin_expect(*cursor == '\0', false)) {
continue;
}
threads += (uint32_t) strtoul(cursor, nullptr, 10);
++result->processes;
}
skip_process:;
}
result->processes = processes;
result->threads = threads;
return nullptr;
}
+8 -5
View File
@@ -3,7 +3,7 @@
#include <sys/sysctl.h>
const char* ffDetectProcesses(FFProcessesResult* result) {
const char* ffDetectProcesses(const FFProcessesOptions* options, FFProcessesResult* result) {
int request[] = { CTL_KERN, KERN_PROC2, KERN_PROC_ALL, -1, sizeof(struct kinfo_proc2), INT_MAX };
size_t length = 0;
@@ -17,18 +17,21 @@ const char* ffDetectProcesses(FFProcessesResult* result) {
}
uint32_t procCount = (uint32_t) (length / sizeof(struct kinfo_proc2));
result->processes = procCount;
uint32_t threads = 0;
for (uint32_t i = 0; i < procCount; ++i) {
const struct kinfo_proc2* proc = &procs[i];
if (!options->countKprocs && (proc->p_flag & P_SYSTEM)) {
continue;
}
++result->processes;
int lwpRequest[] = { CTL_KERN, KERN_LWP, procs[i].p_pid, sizeof(struct kinfo_lwp), 0 };
size_t lwpLength = 0;
if (sysctl(lwpRequest, ARRAY_SIZE(lwpRequest), nullptr, &lwpLength, nullptr, 0) == 0) {
threads += (uint32_t) (lwpLength / sizeof(struct kinfo_lwp));
result->threads += (uint32_t) (lwpLength / sizeof(struct kinfo_lwp));
}
}
result->threads = threads;
return nullptr;
}
+24 -14
View File
@@ -1,26 +1,36 @@
#include "processes.h"
#include "common/mallocHelper.h"
#include <sys/param.h>
#include <sys/sysctl.h>
#include <kvm.h>
const char* ffDetectProcesses(FFProcessesResult* result) {
int procRequest[] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0, sizeof(struct kinfo_proc), 0 };
size_t procLength = 0;
if (sysctl(procRequest, ARRAY_SIZE(procRequest), nullptr, &procLength, nullptr, 0) != 0) {
return "sysctl({CTL_KERN, KERN_PROC, KERN_PROC_ALL}) failed";
const char* ffDetectProcesses(const FFProcessesOptions* options, FFProcessesResult* result) {
kvm_t* kd = kvm_open(nullptr, nullptr, nullptr, KVM_NO_FILES, nullptr);
if (!kd) {
return "kvm_open() failed";
}
result->processes = (uint32_t) (procLength / sizeof(struct kinfo_proc));
int threadRequest[] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL | KERN_PROC_SHOW_THREADS, 0, sizeof(struct kinfo_proc), 0 };
size_t threadLength = 0;
if (sysctl(threadRequest, ARRAY_SIZE(threadRequest), nullptr, &threadLength, nullptr, 0) != 0) {
return "sysctl({CTL_KERN, KERN_PROC, KERN_PROC_ALL | KERN_PROC_SHOW_THREADS}) failed";
int count = 0;
// KERN_PROC_ALL returns all user-level processes, excluding kernel processes and threads
const struct kinfo_proc* procs = kvm_getprocs(kd,
(options->countKprocs ? KERN_PROC_KTHREAD : KERN_PROC_ALL) | KERN_PROC_SHOW_THREADS,
0, sizeof(struct kinfo_proc), &count);
if (!procs) {
kvm_close(kd);
return "kvm_getprocs() failed";
}
result->threads = (uint32_t) (threadLength / sizeof(struct kinfo_proc));
for (int i = 0; i < count; ++i) {
const struct kinfo_proc* proc = &procs[i];
++result->threads;
if (proc->p_tid == -1) {
++result->processes;
}
}
kvm_close(kd);
return nullptr;
}
+15 -13
View File
@@ -5,34 +5,36 @@
#include <procfs.h>
const char* ffDetectProcesses(FFProcessesResult* result) {
const char* ffDetectProcesses(const FFProcessesOptions* options, FFProcessesResult* result) {
FF_AUTO_CLOSE_DIR DIR* dir = opendir("/proc");
if (dir == nullptr) {
return "opendir(\"/proc\") failed";
}
uint32_t processes = 0;
uint32_t threads = 0;
int procfd = dirfd(dir);
struct dirent* entry;
while ((entry = readdir(dir)) != nullptr) {
if (ffCharIsDigit(entry->d_name[0])) {
++processes;
char psinfoPath[32];
strcpy(ffStrCopy(psinfoPath, entry->d_name, sizeof(psinfoPath)), "/psinfo");
char path[32];
char* pidEnd = ffStrCopy(path, entry->d_name, sizeof(path));
if (!options->countKprocs) {
pstatus_t status;
strcpy(pidEnd, "/status");
if (ffReadFileDataRelative(procfd, path, sizeof(status), &status) != (ssize_t) sizeof(status) ||
status.pr_flags & PR_ISSYS) {
continue; // The process may have exited, no permission or is a kernel process
}
}
strcpy(pidEnd, "/psinfo");
psinfo_t info;
if (ffReadFileDataRelative(procfd, psinfoPath, sizeof(info), &info) == (ssize_t) sizeof(info)) {
threads += info.pr_nlwp;
if (ffReadFileDataRelative(procfd, path, sizeof(info), &info) == (ssize_t) sizeof(info)) {
++result->processes;
result->threads += (uint32_t) info.pr_nlwp;
}
}
}
result->processes = processes;
result->threads = threads;
return nullptr;
}
+6 -7
View File
@@ -4,7 +4,7 @@
#include <ntstatus.h>
#include <winternl.h>
const char* ffDetectProcesses(FFProcessesResult* result) {
const char* ffDetectProcesses(const FFProcessesOptions* options, FFProcessesResult* result) {
FF_AUTO_FREE SYSTEM_PROCESS_INFORMATION* pstart = nullptr;
// Multiple attempts in case processes change while
@@ -25,17 +25,16 @@ const char* ffDetectProcesses(FFProcessesResult* result) {
}
}
uint32_t processes = 0;
uint32_t threads = 0;
for (SYSTEM_PROCESS_INFORMATION* ptr = pstart; ; ptr = (SYSTEM_PROCESS_INFORMATION*) ((uint8_t*) ptr + ptr->NextEntryOffset)) {
++processes;
threads += ptr->NumberOfThreads;
if (!options->countKprocs && ptr->CreateTime.QuadPart == 0) {
continue;
}
++result->processes;
result->threads += ptr->NumberOfThreads;
if (ptr->NextEntryOffset == 0) {
break;
}
}
result->processes = processes;
result->threads = threads;
return nullptr;
}
+2
View File
@@ -4,6 +4,8 @@
typedef struct FFProcessesOptions {
FFModuleArgs moduleArgs;
bool countKprocs;
} FFProcessesOptions;
static_assert(sizeof(FFProcessesOptions) <= FF_OPTION_MAX_SIZE, "FFProcessesOptions size exceeds maximum allowed size");
+11 -3
View File
@@ -6,7 +6,7 @@
bool ffPrintProcesses(FFProcessesOptions* options) {
FFProcessesResult result = {};
const char* error = ffDetectProcesses(&result);
const char* error = ffDetectProcesses(options, &result);
if (error) {
ffPrintError(FF_MODULE_GET_DISPLAY_NAME(Processes), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "%s", error);
@@ -32,17 +32,23 @@ void ffParseProcessesJsonObject(FFProcessesOptions* options, yyjson_val* module)
continue;
}
if (unsafe_yyjson_equals_str(key, "countKprocs")) {
options->countKprocs = yyjson_get_bool(val);
continue;
}
ffPrintError(FF_MODULE_GET_DISPLAY_NAME(Processes), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "Unknown JSON key %s", unsafe_yyjson_get_str(key));
}
}
void ffGenerateProcessesJsonConfig(FFProcessesOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module) {
ffJsonConfigGenerateModuleArgsConfig(doc, module, &options->moduleArgs);
yyjson_mut_obj_add_bool(doc, module, "countKprocs", options->countKprocs);
}
bool ffGenerateProcessesJsonResult([[maybe_unused]] FFProcessesOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module) {
FFProcessesResult result = {};
const char* error = ffDetectProcesses(&result);
const char* error = ffDetectProcesses(options, &result);
if (error) {
yyjson_mut_obj_add_str(doc, module, "error", error);
@@ -57,6 +63,8 @@ bool ffGenerateProcessesJsonResult([[maybe_unused]] FFProcessesOptions* options,
void ffInitProcessesOptions(FFProcessesOptions* options) {
ffOptionInitModuleArg(&options->moduleArgs, "");
options->countKprocs = false;
}
void ffDestroyProcessesOptions(FFProcessesOptions* options) {
@@ -65,7 +73,7 @@ void ffDestroyProcessesOptions(FFProcessesOptions* options) {
FFModuleBaseInfo ffProcessesModuleInfo = {
.name = "Processes",
.description = "Print number of running processes",
.description = "Print number of running processes and threads",
.displayName = {
.en = "Processes",
.ar = "العمليات",