ohmu
·
2026-10-15
1#include "processes.h"
2
3#include "common/debug.h"
4#include "common/io.h"
5#include "common/memrchr.h"
6#include "common/strutil.h"
7
8#include <string.h>
9
10#define PF_KTHREAD 0x00200000 // defined in kernel include/linux/sched.h
11
12const char* ffDetectProcesses(const FFProcessesOptions* options, FFProcessesResult* result) {
13 FF_AUTO_CLOSE_DIR DIR* dir = opendir("/proc");
14 if (dir == nullptr) {
15 FF_DEBUG("opendir(/proc) failed: %s", strerror(errno));
16 return "opendir(\"/proc\") failed";
17 }
18
19 int procfd = dirfd(dir);
20
21 struct dirent* entry;
22 while ((entry = readdir(dir)) != nullptr) {
23 if ((entry->d_type == DT_DIR || entry->d_type == DT_UNKNOWN) && ffCharIsDigit(entry->d_name[0])) {
24 char statPath[32];
25 strcpy(ffStrCopy(statPath, entry->d_name, sizeof(statPath)), "/stat");
26
27 char statBuffer[512];
28 ssize_t statLength = ffReadFileDataRelative(procfd, statPath, sizeof(statBuffer) - 1, statBuffer);
29 if (statLength < 0) {
30 continue;
31 }
32 statBuffer[statLength] = '\0';
33
34 const char* cursor = (const char*) memrchr(statBuffer, ')', (size_t) statLength);
35 if (!cursor) {
36 continue;
37 }
38 cursor += 2; // skip ") "
39 if (__builtin_expect(cursor >= statBuffer + statLength, false)) {
40 goto skip_process;
41 }
42
43 char* p;
44 for (uint32_t field = 3; field <= 20 /*num_threads*/; ++field) {
45 switch (field) {
46 case 9: // flags
47 if ((strtoul(cursor, &p, 10) & PF_KTHREAD) && !options->countKprocs) {
48 goto skip_process;
49 }
50 cursor = p;
51 break;
52
53 case 20: // num_threads
54 result->threads += (uint32_t) strtoul(cursor, &p, 10);
55 cursor = p;
56 break;
57
58 default:
59 while (*cursor != ' ' && __builtin_expect(*cursor != '\0', true)) {
60 ++cursor;
61 }
62 break;
63 }
64
65 ++cursor;
66 if (__builtin_expect(cursor >= statBuffer + statLength, false)) {
67 goto skip_process;
68 }
69 }
70
71 ++result->processes;
72 }
73 skip_process:;
74 }
75
76 return nullptr;
77}