master ohmu/fastfetch-openbsd / src / detection / poweradapter / poweradapter_linux.c
ohmu  ·  2026-10-15
 1#include "poweradapter.h"
 2#include "common/debug.h"
 3#include "common/io.h"
 4#include "common/strutil.h"
 5
 6#include <dirent.h>
 7#include <unistd.h>
 8#include <fcntl.h>
 9#include <string.h>
10
11static void parsePowerAdapter(int dfd, const char* id, FFlist* results) {
12    FF_STRBUF_AUTO_DESTROY tmpBuffer = ffStrbufCreate();
13
14    {
15        char present = '\0';
16        if (ffReadFileDataRelative(dfd, "present", 1, &present) && present == '0') {
17            return;
18        }
19    }
20
21    // type must exist and be "Mains"
22    if (ffReadFileBufferRelative(dfd, "type", &tmpBuffer)) {
23        ffStrbufTrimRightSpace(&tmpBuffer);
24    }
25
26    if (!ffStrbufEqualS(&tmpBuffer, "Mains")) {
27        return;
28    }
29
30    // scope may not exist or must not be "Device" (?)
31    if (ffReadFileBufferRelative(dfd, "scope", &tmpBuffer)) {
32        ffStrbufTrimRightSpace(&tmpBuffer);
33
34        if (ffStrbufEqualS(&tmpBuffer, "Device")) {
35            return;
36        }
37    }
38
39    char online = '\0';
40    ffReadFileDataRelative(dfd, "online", sizeof(online), &online);
41
42    if (online != '1') {
43        return;
44    }
45
46    // input_power_limit must exist and be not empty
47    if (!ffReadFileBufferRelative(dfd, "input_power_limit", &tmpBuffer) || tmpBuffer.length == 0) {
48        return;
49    }
50
51    FFPowerAdapterResult* result = FF_LIST_ADD(FFPowerAdapterResult, *results);
52    ffStrbufInit(&result->name);
53    ffStrbufInit(&result->description);
54    result->watts = (int) (ffStrbufToDouble(&tmpBuffer, 0) / 1e6 + 0.5);
55    ffStrbufInit(&result->manufacturer);
56    ffStrbufInit(&result->modelName);
57    ffStrbufInit(&result->serial);
58
59    if (ffReadFileBufferRelative(dfd, "manufacturer", &result->manufacturer)) {
60        ffStrbufTrimRightSpace(&result->manufacturer);
61    } else if (ffStrEquals(id, "macsmc-ac")) { // asahi
62        ffStrbufSetStatic(&result->manufacturer, "Apple Inc.");
63    }
64
65    if (ffReadFileBufferRelative(dfd, "model_name", &result->modelName)) {
66        ffStrbufTrimRightSpace(&result->modelName);
67    }
68
69    if (ffReadFileBufferRelative(dfd, "serial_number", &result->serial)) {
70        ffStrbufTrimRightSpace(&result->serial);
71    }
72}
73
74const char* ffDetectPowerAdapter(FFlist* results) {
75    FF_AUTO_CLOSE_DIR DIR* dirp = opendir("/sys/class/power_supply/");
76    if (dirp == nullptr) {
77        FF_DEBUG("opendir(\"/sys/class/power_supply/\") failed: %s", strerror(errno));
78        return "opendir(\"/sys/class/power_supply/\") == nullptr";
79    }
80
81    struct dirent* entry;
82    while ((entry = readdir(dirp)) != nullptr) {
83        if (entry->d_name[0] == '.') {
84            continue;
85        }
86
87        FF_AUTO_CLOSE_FD int dfd = openat(dirfd(dirp), entry->d_name, O_RDONLY | O_CLOEXEC);
88        if (dfd > 0) {
89            parsePowerAdapter(dfd, entry->d_name, results);
90        }
91    }
92
93    return nullptr;
94}