[monitoring-plugins] Fix check_swap for FreeBSD with multiple swap ...

Lorenz Kästle git at monitoring-plugins.org
Tue Sep 15 12:40:14 CEST 2026


 Module: monitoring-plugins
 Branch: master
 Commit: 21d8291f39a802bd605c3a828c3cc6b9d31bd33a
 Author: Lorenz Kästle <12514511+RincewindsHat at users.noreply.github.com>
   Date: Fri Sep 11 16:34:07 2026 +0200
    URL: https://www.monitoring-plugins.org/repositories/monitoring-plugins/commit/?id=21d8291f

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 3ee89e2e..4972da15 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 a3a1a6f3..c7fd5fb1 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 <strings.h>
 
 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 */



More information about the Commits mailing list