From 21d8291f39a802bd605c3a828c3cc6b9d31bd33a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lorenz=20K=C3=A4stle?= <12514511+RincewindsHat@users.noreply.github.com> Date: Fri, 11 Sep 2026 16:34:07 +0200 Subject: [PATCH] Fix check_swap for FreeBSD with multiple swap volumes On FreeBSD check_swap got a wrong result if multiple swap volumes are online and swapinfo displays a summary line ("Total") at the bottom which was counted twice. This patch changes the behaviour to find that line and ignore it. --- configure.ac | 4 ++-- plugins/check_swap.d/swap.c | 45 +++++++++++++++++++++++++++++++++++-- 2 files changed, 45 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index 3ee89e2e9..4972da155 100644 --- a/configure.ac +++ b/configure.ac @@ -1633,7 +1633,7 @@ then if [$PATH_TO_SWAPINFO -k 2>/dev/null | grep -E -i "^Device +1K-blocks +Used +Avail" >/dev/null] then - ac_cv_swap_format=["%*s %lf %*d %lf"] + ac_cv_swap_format=["%s %lf %*d %lf"] ac_cv_swap_conv=1024 AC_MSG_RESULT([using FreeBSD format swapinfo]) fi @@ -1642,7 +1642,7 @@ elif [$PATH_TO_SWAPINFO -dfM 2>/dev/null | grep -E -i "^TYPE +AVAIL +USED +FREE" then ac_cv_have_swap=yes ac_cv_swap_command="$PATH_TO_SWAPINFO -dfM" - ac_cv_swap_format=["%*s %lu %*d %lu"] + ac_cv_swap_format=["%s %lu %*d %lu"] ac_cv_swap_conv=1024 AC_MSG_RESULT([using HP-UX format swapinfo]) fi diff --git a/plugins/check_swap.d/swap.c b/plugins/check_swap.d/swap.c index a3a1a6f38..c7fd5fb11 100644 --- a/plugins/check_swap.d/swap.c +++ b/plugins/check_swap.d/swap.c @@ -2,6 +2,7 @@ #include "../popen.h" #include "../utils.h" #include "common.h" +#include extern int verbose; @@ -210,7 +211,23 @@ swap_result getSwapFromSwapCommand(swap_config config, const char swap_command[] */ if (config.on_aix && !config.allswaps) { fgets(input_buffer, MAX_INPUT_BUFFER - 1, child_process); /* Ignore first line */ - sscanf(input_buffer, swap_format, &total_swap_mb, &used_swap_mb); + int sscanf_result = sscanf(input_buffer, swap_format, &total_swap_mb, &used_swap_mb); + switch (sscanf_result) { + case 3: { + // everything matched, we are good + break; + } + case EOF: { + DBG_PRINT_1("sscanf input error"); + result.errorcode = 1; + return result; + } + default: { + DBG_PRINT_1("sscanf failed to match everything"); + result.errorcode = 1; + return result; + } + } free_swap_mb = total_swap_mb * (100 - used_swap_mb) / 100; used_swap_mb = total_swap_mb - free_swap_mb; @@ -220,7 +237,31 @@ swap_result getSwapFromSwapCommand(swap_config config, const char swap_command[] } } else { while (fgets(input_buffer, MAX_INPUT_BUFFER - 1, child_process)) { - sscanf(input_buffer, swap_format, &dsktotal_mb, &dskfree_mb); + char label[256] = {}; // 256 is just a random guess + int sscanf_result = + sscanf(input_buffer, swap_format, &label, &dsktotal_mb, &dskfree_mb); + + switch (sscanf_result) { + case 3: { + // everything matched, we are good + break; + } + case EOF: { + DBG_PRINT_1("sscanf input error"); + result.errorcode = 1; + return result; + } + default: { + DBG_PRINT_1("sscanf failed to match everything"); + result.errorcode = 1; + return result; + } + } + + if (strcasecmp(label, "Total") == 0) { + // Total line, ignore this + continue; + } dsktotal_mb = dsktotal_mb / config.conversion_factor; /* AIX lists percent used, so this converts to dskfree in MBs */