From: Michael Tremer Date: Sat, 28 Oct 2023 10:52:24 +0000 (+0000) Subject: os: Implement getting memory stats from /proc/meminfo X-Git-Tag: 0.9.30~1382 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=1d29d610616d2dff3eda0dbfdd1669e24d1f7bbf;p=pakfire.git os: Implement getting memory stats from /proc/meminfo Signed-off-by: Michael Tremer --- diff --git a/src/libpakfire/include/pakfire/os.h b/src/libpakfire/include/pakfire/os.h index 8cf6021e3..dd600e633 100644 --- a/src/libpakfire/include/pakfire/os.h +++ b/src/libpakfire/include/pakfire/os.h @@ -23,6 +23,8 @@ #ifdef PAKFIRE_PRIVATE +#include + // CPU info #define CPU_VENDOR_MAX 16 @@ -35,6 +37,26 @@ struct pakfire_cpuinfo { int pakfire_cpuinfo(struct pakfire_cpuinfo* cpuinfo); +// Meminfo + +struct pakfire_meminfo { + uint64_t total; + uint64_t used; + uint64_t free; + uint64_t available; + uint64_t buffers; + uint64_t cached; + uint64_t active; + uint64_t inactive; + + // Swap + uint64_t swap_total; + uint64_t swap_used; + uint64_t swap_free; +}; + +int pakfire_meminfo(struct pakfire_meminfo* meminfo); + #endif /* PAKFIRE_PRIVATE */ #endif /* PAKFIRE_OS_H */ diff --git a/src/libpakfire/os.c b/src/libpakfire/os.c index 66d03789f..63a225e66 100644 --- a/src/libpakfire/os.c +++ b/src/libpakfire/os.c @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -139,3 +140,105 @@ static int pakfire_parse_cpuinfo(char* line, size_t length, void* data) { int pakfire_cpuinfo(struct pakfire_cpuinfo* cpuinfo) { return pakfire_parse_file("/proc/cpuinfo", pakfire_parse_cpuinfo, cpuinfo); } + +// Meminfo + +static int pakfire_parse_meminfo_value(uint64_t* mem, const char* s) { + char* remainder = NULL; + uint64_t m = 0; + + // Parse the numeric value + m = strtoul(s, &remainder, 10); + if (m == ULONG_MAX) + return -errno; + + // Convert into bytes + if (strcmp(remainder, " kB") == 0) { + // Check if the multiplication won't overflow + if (m > UINT64_MAX / 1024) + return -EOVERFLOW; + + m *= 1024; + + // Fail on anything else + } else if (*remainder) + return -EINVAL; + + // Store the value + *mem = m; + + return 0; +} + +static int pakfire_parse_meminfo(char* line, size_t length, void* data) { + struct pakfire_meminfo* meminfo = data; + int r; + + // Key & Value + const char* k = NULL; + const char* v = NULL; + + // Split the line + r = pakfire_split_line(line, length, &k, &v); + if (r) + return r; + + // If we didn't get a result we skip this line + if (!k || !v) + return 0; + + // Total + if (strcmp(k, "MemTotal") == 0) + return pakfire_parse_meminfo_value(&meminfo->total, v); + + // Free + else if (strcmp(k, "MemFree") == 0) + return pakfire_parse_meminfo_value(&meminfo->free, v); + + // Available + else if (strcmp(k, "MemAvailable") == 0) + return pakfire_parse_meminfo_value(&meminfo->available, v); + + // Buffers + else if (strcmp(k, "Buffers") == 0) + return pakfire_parse_meminfo_value(&meminfo->buffers, v); + + // Cached + else if (strcmp(k, "Cached") == 0) + return pakfire_parse_meminfo_value(&meminfo->cached, v); + + // Active + else if (strcmp(k, "Active") == 0) + return pakfire_parse_meminfo_value(&meminfo->active, v); + + // Inactive + else if (strcmp(k, "Inactive") == 0) + return pakfire_parse_meminfo_value(&meminfo->inactive, v); + + // Swap Total + else if (strcmp(k, "SwapTotal") == 0) + return pakfire_parse_meminfo_value(&meminfo->swap_total, v); + + // Swap Free + else if (strcmp(k, "SwapFree") == 0) + return pakfire_parse_meminfo_value(&meminfo->swap_free, v); + + return 0; +} + +int pakfire_meminfo(struct pakfire_meminfo* meminfo) { + int r; + + // Parse /proc/meminfo + r = pakfire_parse_file("/proc/meminfo", pakfire_parse_meminfo, meminfo); + if (r) + return r; + + // Set used memory + meminfo->used = meminfo->total - meminfo->free; + + // Set used swap + meminfo->swap_used = meminfo->swap_total - meminfo->swap_free; + + return 0; +} diff --git a/tests/libpakfire/os.c b/tests/libpakfire/os.c index 940aec589..e631bad1e 100644 --- a/tests/libpakfire/os.c +++ b/tests/libpakfire/os.c @@ -38,8 +38,34 @@ FAIL: return EXIT_FAILURE; } +// This test parses /proc/meminfo +static int test_meminfo(const struct test* t) { + struct pakfire_meminfo meminfo = {}; + + ASSERT_SUCCESS(pakfire_meminfo(&meminfo)); + + // We can only check is something has been read + ASSERT(meminfo.total > 0); + ASSERT(meminfo.used > 0); + ASSERT(meminfo.free > 0); + ASSERT(meminfo.available > 0); + ASSERT(meminfo.buffers > 0); + ASSERT(meminfo.cached > 0); + ASSERT(meminfo.active > 0); + ASSERT(meminfo.inactive > 0); + ASSERT(meminfo.swap_total >= 0); + ASSERT(meminfo.swap_used >= 0); + ASSERT(meminfo.swap_free >= 0); + + return EXIT_SUCCESS; + +FAIL: + return EXIT_FAILURE; +} + int main(int argc, const char* argv[]) { testsuite_add_test(test_cpuinfo); + testsuite_add_test(test_meminfo); return testsuite_run(argc, argv); }