master ohmu/fastfetch-openbsd / src / common / impl / sysctl.c
ohmu  ·  2026-10-15
  1#include "common/sysctl.h"
  2#include "common/debug.h"
  3
  4#include <errno.h>
  5#include <stdlib.h>
  6#include <string.h>
  7
  8#ifdef __OpenBSD__
  9const char* ffSysctlGetString(int mib1, int mib2, FFstrbuf* result) {
 10    size_t neededLength;
 11    if (sysctl((int[]) { mib1, mib2 }, 2, nullptr, &neededLength, nullptr, 0) != 0 || neededLength == 1) { // neededLength is 1 for empty strings, because of the null terminator
 12        FF_DEBUG("sysctl({%d, %d}) length query failed: %s", mib1, mib2, strerror(errno));
 13        return "sysctl() length query failed";
 14    }
 15
 16    ffStrbufEnsureFree(result, (uint32_t) neededLength - 1);
 17
 18    if (sysctl((int[]) { mib1, mib2 }, 2, result->chars + result->length, &neededLength, nullptr, 0) != 0) {
 19        FF_DEBUG("sysctl({%d, %d}) failed to retrieve %zu bytes: %s", mib1, mib2, neededLength, strerror(errno));
 20        return "sysctl() failed to retrieve string data";
 21    }
 22
 23    result->length += (uint32_t) neededLength - 1;
 24    result->chars[result->length] = '\0';
 25
 26    return nullptr;
 27}
 28
 29int ffSysctlGetInt(int mib1, int mib2, int defaultValue) {
 30    alignas(int) uint8_t result[sizeof(int)];
 31    size_t neededLength = sizeof(result);
 32    if (sysctl((int[]) { mib1, mib2 }, 2, &result, &neededLength, nullptr, 0) != 0) {
 33        return defaultValue;
 34    }
 35    switch (neededLength) {
 36        case sizeof(int32_t):
 37            return *(int32_t*)result;
 38        case sizeof(int16_t):
 39            return *(int16_t*)result;
 40        case sizeof(int8_t):
 41            return *(int8_t*)result;
 42        default:
 43            return defaultValue;
 44    }
 45}
 46
 47int64_t ffSysctlGetInt64(int mib1, int mib2, int64_t defaultValue) {
 48    alignas(int64_t) uint8_t result[sizeof(int64_t)];
 49    size_t neededLength = sizeof(result);
 50    if (sysctl((int[]) { mib1, mib2 }, 2, &result, &neededLength, nullptr, 0) != 0) {
 51        return defaultValue;
 52    }
 53    switch (neededLength) {
 54        case sizeof(int64_t):
 55            return *(int64_t*)result;
 56        case sizeof(int32_t):
 57            return *(int32_t*)result;
 58        case sizeof(int16_t):
 59            return *(int16_t*)result;
 60        case sizeof(int8_t):
 61            return *(int8_t*)result;
 62        default:
 63            return defaultValue;
 64    }
 65}
 66#else
 67const char* ffSysctlGetString(const char* propName, FFstrbuf* result) {
 68    size_t neededLength;
 69    if (sysctlbyname(propName, nullptr, &neededLength, nullptr, 0) != 0 || neededLength == 1) { // neededLength is 1 for empty strings, because of the null terminator
 70        FF_DEBUG("sysctlbyname(%s) length query failed: %s", propName, strerror(errno));
 71        return "sysctlbyname() failed";
 72    }
 73
 74    ffStrbufEnsureFree(result, (uint32_t) neededLength - 1);
 75
 76    if (sysctlbyname(propName, result->chars + result->length, &neededLength, nullptr, 0) != 0) {
 77        FF_DEBUG("sysctlbyname(%s) failed to retrieve %zu bytes: %s", propName, neededLength, strerror(errno));
 78        return "sysctlbyname() failed to retrieve string data";
 79    }
 80
 81    result->length += (uint32_t) neededLength - 1;
 82
 83    result->chars[result->length] = '\0';
 84
 85    return nullptr;
 86}
 87
 88int ffSysctlGetInt(const char* propName, int defaultValue) {
 89    alignas(int) uint8_t result[sizeof(int)];
 90    size_t neededLength = sizeof(result);
 91    if (sysctlbyname(propName, &result, &neededLength, nullptr, 0) != 0) {
 92        return defaultValue;
 93    }
 94    switch (neededLength) {
 95        case sizeof(int32_t):
 96            return *(int32_t*)result;
 97        case sizeof(int16_t):
 98            return *(int16_t*)result;
 99        case sizeof(int8_t):
100            return *(int8_t*)result;
101        default:
102            return defaultValue;
103    }
104}
105
106int64_t ffSysctlGetInt64(const char* propName, int64_t defaultValue) {
107    alignas(int64_t) uint8_t result[sizeof(int64_t)];
108    size_t neededLength = sizeof(result);
109    if (sysctlbyname(propName, &result, &neededLength, nullptr, 0) != 0) {
110        return defaultValue;
111    }
112    switch (neededLength) {
113        case sizeof(int64_t):
114            return *(int64_t*)result;
115        case sizeof(int32_t):
116            return *(int32_t*)result;
117        case sizeof(int16_t):
118            return *(int16_t*)result;
119        case sizeof(int8_t):
120            return *(int8_t*)result;
121        default:
122            return defaultValue;
123    }
124}
125#endif // OpenBSD