[monitoring-plugins] check_ntp_peer: implement new output functionality

Lorenz Kästle git at monitoring-plugins.org
Wed Nov 5 12:20:12 CET 2025


 Module: monitoring-plugins
 Branch: master
 Commit: 6392a0f77635d82b9b68bcbd1be4c6acc478767f
 Author: Lorenz Kästle <12514511+RincewindsHat at users.noreply.github.com>
   Date: Tue Nov  4 10:13:39 2025 +0100
    URL: https://www.monitoring-plugins.org/repositories/monitoring-plugins/commit/?id=6392a0f7

check_ntp_peer: implement new output functionality

---

 plugins/check_ntp_peer.c          | 248 ++++++++++++++++++++------------------
 plugins/check_ntp_peer.d/config.h |  58 +++++----
 2 files changed, 164 insertions(+), 142 deletions(-)

diff --git a/plugins/check_ntp_peer.c b/plugins/check_ntp_peer.c
index 37e481c7..0498a7d4 100644
--- a/plugins/check_ntp_peer.c
+++ b/plugins/check_ntp_peer.c
@@ -39,6 +39,9 @@ const char *progname = "check_ntp_peer";
 const char *copyright = "2006-2024";
 const char *email = "devel at monitoring-plugins.org";
 
+#include "output.h"
+#include "perfdata.h"
+#include <openssl/x509.h>
 #include "thresholds.h"
 #include "common.h"
 #include "netutils.h"
@@ -329,7 +332,7 @@ ntp_request_result ntp_request(const check_ntp_peer_config config) {
 			if (verbose) {
 				printf("Getting offset, jitter and stratum for peer %.2x\n", ntohs(peers[i].assoc));
 			}
-			xasprintf(&data, "");
+			data = strdup("");
 			do {
 				setup_control_request(&req, OP_READVAR, 2);
 				req.assoc = peers[i].assoc;
@@ -518,36 +521,76 @@ check_ntp_peer_config_wrapper process_arguments(int argc, char **argv) {
 		case 'q':
 			result.config.quiet = true;
 			break;
-		case 'w':
-			result.config.owarn = optarg;
-			break;
-		case 'c':
-			result.config.ocrit = optarg;
-			break;
-		case 'W':
+		case 'w': {
+			mp_range_parsed tmp = mp_parse_range_string(optarg);
+			if (tmp.error != MP_PARSING_SUCCES) {
+				die(STATE_UNKNOWN, "failed to parse warning offset threshold");
+			}
+
+			mp_thresholds_set_warn(result.config.offset_thresholds, tmp.range);
+		} break;
+		case 'c': {
+			mp_range_parsed tmp = mp_parse_range_string(optarg);
+			if (tmp.error != MP_PARSING_SUCCES) {
+				die(STATE_UNKNOWN, "failed to parse critical offset threshold");
+			}
+
+			mp_thresholds_set_crit(result.config.offset_thresholds, tmp.range);
+		} break;
+		case 'W': {
 			result.config.do_stratum = true;
-			result.config.swarn = optarg;
-			break;
-		case 'C':
+			mp_range_parsed tmp = mp_parse_range_string(optarg);
+			if (tmp.error != MP_PARSING_SUCCES) {
+				die(STATE_UNKNOWN, "failed to parse warning stratum threshold");
+			}
+
+			mp_thresholds_set_warn(result.config.stratum_thresholds, tmp.range);
+		} break;
+		case 'C': {
 			result.config.do_stratum = true;
-			result.config.scrit = optarg;
-			break;
-		case 'j':
+			mp_range_parsed tmp = mp_parse_range_string(optarg);
+			if (tmp.error != MP_PARSING_SUCCES) {
+				die(STATE_UNKNOWN, "failed to parse critical stratum threshold");
+			}
+
+			mp_thresholds_set_crit(result.config.stratum_thresholds, tmp.range);
+		} break;
+		case 'j': {
 			result.config.do_jitter = true;
-			result.config.jwarn = optarg;
-			break;
-		case 'k':
+			mp_range_parsed tmp = mp_parse_range_string(optarg);
+			if (tmp.error != MP_PARSING_SUCCES) {
+				die(STATE_UNKNOWN, "failed to parse warning jitter threshold");
+			}
+
+			mp_thresholds_set_warn(result.config.jitter_thresholds, tmp.range);
+		} break;
+		case 'k': {
 			result.config.do_jitter = true;
-			result.config.jcrit = optarg;
-			break;
-		case 'm':
+			mp_range_parsed tmp = mp_parse_range_string(optarg);
+			if (tmp.error != MP_PARSING_SUCCES) {
+				die(STATE_UNKNOWN, "failed to parse critical jitter threshold");
+			}
+
+			mp_thresholds_set_crit(result.config.jitter_thresholds, tmp.range);
+		} break;
+		case 'm': {
 			result.config.do_truechimers = true;
-			result.config.twarn = optarg;
-			break;
-		case 'n':
+			mp_range_parsed tmp = mp_parse_range_string(optarg);
+			if (tmp.error != MP_PARSING_SUCCES) {
+				die(STATE_UNKNOWN, "failed to parse warning truechimer threshold");
+			}
+
+			mp_thresholds_set_warn(result.config.truechimer_thresholds, tmp.range);
+		} break;
+		case 'n': {
 			result.config.do_truechimers = true;
-			result.config.tcrit = optarg;
-			break;
+			mp_range_parsed tmp = mp_parse_range_string(optarg);
+			if (tmp.error != MP_PARSING_SUCCES) {
+				die(STATE_UNKNOWN, "failed to parse critical truechimer threshold");
+			}
+
+			mp_thresholds_set_crit(result.config.truechimer_thresholds, tmp.range);
+		} break;
 		case 'H':
 			if (!is_host(optarg)) {
 				usage2(_("Invalid hostname/address"), optarg);
@@ -581,11 +624,6 @@ check_ntp_peer_config_wrapper process_arguments(int argc, char **argv) {
 		usage4(_("Hostname was not supplied"));
 	}
 
-	set_thresholds(&result.config.offset_thresholds, result.config.owarn, result.config.ocrit);
-	set_thresholds(&result.config.jitter_thresholds, result.config.jwarn, result.config.jcrit);
-	set_thresholds(&result.config.stratum_thresholds, result.config.swarn, result.config.scrit);
-	set_thresholds(&result.config.truechimer_thresholds, result.config.twarn, result.config.tcrit);
-
 	return result;
 }
 
@@ -635,124 +673,100 @@ int main(int argc, char *argv[]) {
 
 	/* This returns either OK or WARNING (See comment preceding ntp_request) */
 	const ntp_request_result ntp_res = ntp_request(config);
-	mp_state_enum result = STATE_UNKNOWN;
+	mp_check overall = mp_check_init();
 
+	mp_subcheck sc_offset = mp_subcheck_init();
+	xasprintf(&sc_offset.output, "offset");
 	if (ntp_res.offset_result == STATE_UNKNOWN) {
 		/* if there's no sync peer (this overrides ntp_request output): */
-		result = (config.quiet ? STATE_UNKNOWN : STATE_CRITICAL);
+		sc_offset =
+			mp_set_subcheck_state(sc_offset, (config.quiet ? STATE_UNKNOWN : STATE_CRITICAL));
 	} else {
 		/* Be quiet if there's no candidates either */
-		if (config.quiet && result == STATE_WARNING) {
-			result = STATE_UNKNOWN;
+		mp_state_enum tmp = STATE_OK;
+		if (config.quiet && ntp_res.state == STATE_WARNING) {
+			tmp = STATE_UNKNOWN;
 		}
-		result = max_state_alt(result, get_status(fabs(ntp_res.offset), config.offset_thresholds));
+
+		mp_perfdata pd_offset = perfdata_init();
+		pd_offset.value = mp_create_pd_value(fabs(ntp_res.offset));
+		pd_offset = mp_pd_set_thresholds(pd_offset, config.offset_thresholds);
+
+		tmp = max_state_alt(tmp, mp_get_pd_status(pd_offset));
+		sc_offset = mp_set_subcheck_state(sc_offset, tmp);
 	}
 
-	mp_state_enum oresult = result;
-	mp_state_enum tresult = STATE_UNKNOWN;
+	mp_add_subcheck_to_check(&overall, sc_offset);
 
+	// truechimers
 	if (config.do_truechimers) {
-		tresult = get_status(ntp_res.num_truechimers, config.truechimer_thresholds);
-		result = max_state_alt(result, tresult);
-	}
+		mp_subcheck sc_truechimers;
+		xasprintf(&sc_truechimers.output, "truechimers: %i", ntp_res.num_truechimers);
 
-	mp_state_enum sresult = STATE_UNKNOWN;
+		mp_perfdata pd_truechimers = perfdata_init();
+		pd_truechimers.value = mp_create_pd_value(ntp_res.num_truechimers);
+		mp_pd_set_thresholds(pd_truechimers, config.truechimer_thresholds);
+		mp_add_perfdata_to_subcheck(&sc_truechimers, pd_truechimers);
 
-	if (config.do_stratum) {
-		sresult = get_status((double)ntp_res.stratum, config.stratum_thresholds);
-		result = max_state_alt(result, sresult);
+		sc_truechimers = mp_set_subcheck_state(sc_truechimers, mp_get_pd_status(pd_truechimers));
+
+		mp_add_subcheck_to_check(&overall, sc_truechimers);
 	}
 
-	mp_state_enum jresult = STATE_UNKNOWN;
+	if (config.do_stratum) {
+		mp_subcheck sc_stratum = mp_subcheck_init();
+		xasprintf(&sc_stratum.output, "stratum: %li", ntp_res.stratum);
 
-	if (config.do_jitter) {
-		jresult = get_status(ntp_res.jitter, config.jitter_thresholds);
-		result = max_state_alt(result, jresult);
+		mp_perfdata pd_stratum = perfdata_init();
+		pd_stratum.value = mp_create_pd_value(ntp_res.stratum);
+		pd_stratum = mp_pd_set_thresholds(pd_stratum, config.stratum_thresholds);
+		mp_add_perfdata_to_subcheck(&sc_stratum, pd_stratum);
+
+		sc_stratum = mp_set_subcheck_state(sc_stratum, mp_get_pd_status(pd_stratum));
+
+		mp_add_subcheck_to_check(&overall, sc_stratum);
 	}
 
-	char *result_line;
-	switch (result) {
-	case STATE_CRITICAL:
-		xasprintf(&result_line, _("NTP CRITICAL:"));
-		break;
-	case STATE_WARNING:
-		xasprintf(&result_line, _("NTP WARNING:"));
-		break;
-	case STATE_OK:
-		xasprintf(&result_line, _("NTP OK:"));
-		break;
-	default:
-		xasprintf(&result_line, _("NTP UNKNOWN:"));
-		break;
+	if (config.do_jitter) {
+		mp_subcheck sc_jitter = mp_subcheck_init();
+		xasprintf(&sc_jitter.output, "jitter: %f", ntp_res.jitter);
+
+		mp_perfdata pd_jitter = perfdata_init();
+		pd_jitter.value = mp_create_pd_value(ntp_res.jitter);
+		pd_jitter = mp_pd_set_thresholds(pd_jitter, config.jitter_thresholds);
+		mp_add_perfdata_to_subcheck(&sc_jitter, pd_jitter);
+
+		sc_jitter = mp_set_subcheck_state(sc_jitter, mp_get_pd_status(pd_jitter));
+		mp_add_subcheck_to_check(&overall, sc_jitter);
 	}
 
+	mp_subcheck sc_other_info = mp_subcheck_init();
+	sc_other_info = mp_set_subcheck_default_state(sc_other_info, STATE_OK);
 	if (!ntp_res.syncsource_found) {
-		xasprintf(&result_line, "%s %s,", result_line, _("Server not synchronized"));
+		xasprintf(&sc_other_info.output, "%s", _("Server not synchronized"));
+		mp_add_subcheck_to_check(&overall, sc_other_info);
 	} else if (ntp_res.li_alarm) {
-		xasprintf(&result_line, "%s %s,", result_line, _("Server has the LI_ALARM bit set"));
+		xasprintf(&sc_other_info.output, "%s", _("Server has the LI_ALARM bit set"));
+		mp_add_subcheck_to_check(&overall, sc_other_info);
 	}
 
-	char *perfdata_line;
-	if (ntp_res.offset_result == STATE_UNKNOWN) {
-		xasprintf(&result_line, "%s %s", result_line, _("Offset unknown"));
-		xasprintf(&perfdata_line, "");
-	} else if (oresult == STATE_WARNING) {
-		xasprintf(&result_line, "%s %s %.10g secs (WARNING)", result_line, _("Offset"),
-				  ntp_res.offset);
-	} else if (oresult == STATE_CRITICAL) {
-		xasprintf(&result_line, "%s %s %.10g secs (CRITICAL)", result_line, _("Offset"),
-				  ntp_res.offset);
-	} else {
-		xasprintf(&result_line, "%s %s %.10g secs", result_line, _("Offset"), ntp_res.offset);
-	}
-	xasprintf(&perfdata_line, "%s", perfd_offset(ntp_res.offset, config.offset_thresholds));
-
-	if (config.do_jitter) {
-		if (jresult == STATE_WARNING) {
-			xasprintf(&result_line, "%s, jitter=%f (WARNING)", result_line, ntp_res.jitter);
-		} else if (jresult == STATE_CRITICAL) {
-			xasprintf(&result_line, "%s, jitter=%f (CRITICAL)", result_line, ntp_res.jitter);
-		} else {
-			xasprintf(&result_line, "%s, jitter=%f", result_line, ntp_res.jitter);
-		}
-		xasprintf(&perfdata_line, "%s %s", perfdata_line,
-				  perfd_jitter(ntp_res.jitter, config.do_jitter, config.jitter_thresholds));
-	}
+	{
+		mp_subcheck sc_offset = mp_subcheck_init();
+		sc_offset = mp_set_subcheck_default_state(sc_offset, STATE_OK);
+		xasprintf(&sc_offset.output, "offset: %.10gs", ntp_res.offset);
 
-	if (config.do_stratum) {
-		if (sresult == STATE_WARNING) {
-			xasprintf(&result_line, "%s, stratum=%li (WARNING)", result_line, ntp_res.stratum);
-		} else if (sresult == STATE_CRITICAL) {
-			xasprintf(&result_line, "%s, stratum=%li (CRITICAL)", result_line, ntp_res.stratum);
-		} else {
-			xasprintf(&result_line, "%s, stratum=%li", result_line, ntp_res.stratum);
-		}
-		xasprintf(&perfdata_line, "%s %s", perfdata_line,
-				  perfd_stratum(ntp_res.stratum, config.do_stratum, config.stratum_thresholds));
-	}
+		mp_perfdata pd_offset = perfdata_init();
+		pd_offset.value = mp_create_pd_value(ntp_res.offset);
+		pd_offset = mp_pd_set_thresholds(pd_offset, config.offset_thresholds);
 
-	if (config.do_truechimers) {
-		if (tresult == STATE_WARNING) {
-			xasprintf(&result_line, "%s, truechimers=%i (WARNING)", result_line,
-					  ntp_res.num_truechimers);
-		} else if (tresult == STATE_CRITICAL) {
-			xasprintf(&result_line, "%s, truechimers=%i (CRITICAL)", result_line,
-					  ntp_res.num_truechimers);
-		} else {
-			xasprintf(&result_line, "%s, truechimers=%i", result_line, ntp_res.num_truechimers);
-		}
-		xasprintf(&perfdata_line, "%s %s", perfdata_line,
-				  perfd_truechimers(ntp_res.num_truechimers, config.do_truechimers,
-									config.truechimer_thresholds));
+		sc_offset = mp_set_subcheck_state(sc_offset, ntp_res.offset_result);
 	}
 
-	printf("%s|%s\n", result_line, perfdata_line);
-
 	if (config.server_address != NULL) {
 		free(config.server_address);
 	}
 
-	exit(result);
+	mp_exit(overall);
 }
 
 void print_help(void) {
diff --git a/plugins/check_ntp_peer.d/config.h b/plugins/check_ntp_peer.d/config.h
index 00e6b05d..396edea6 100644
--- a/plugins/check_ntp_peer.d/config.h
+++ b/plugins/check_ntp_peer.d/config.h
@@ -1,6 +1,7 @@
 #pragma once
 
 #include "../../config.h"
+#include "perfdata.h"
 #include "thresholds.h"
 #include <stddef.h>
 
@@ -16,26 +17,18 @@ typedef struct {
 
 	// truechimer stuff
 	bool do_truechimers;
-	char *twarn;
-	char *tcrit;
-	thresholds *truechimer_thresholds;
+	mp_thresholds truechimer_thresholds;
 
-	char *owarn;
-	char *ocrit;
-	thresholds *offset_thresholds;
+	// offset thresholds
+	mp_thresholds offset_thresholds;
 
 	// stratum stuff
 	bool do_stratum;
-	char *swarn;
-	char *scrit;
-	thresholds *stratum_thresholds;
+	mp_thresholds stratum_thresholds;
 
 	// jitter stuff
 	bool do_jitter;
-	char *jwarn;
-	char *jcrit;
-	thresholds *jitter_thresholds;
-
+	mp_thresholds jitter_thresholds;
 } check_ntp_peer_config;
 
 check_ntp_peer_config check_ntp_peer_config_init() {
@@ -45,23 +38,38 @@ check_ntp_peer_config check_ntp_peer_config_init() {
 
 		.quiet = false,
 		.do_truechimers = false,
-		.twarn = "0:",
-		.tcrit = "0:",
-		.truechimer_thresholds = NULL,
+		.truechimer_thresholds = mp_thresholds_init(),
 
-		.owarn = "60",
-		.ocrit = "120",
-		.offset_thresholds = NULL,
+		.offset_thresholds = mp_thresholds_init(),
 
 		.do_stratum = false,
-		.swarn = "-1:16",
-		.scrit = "-1:16",
-		.stratum_thresholds = NULL,
+		.stratum_thresholds = mp_thresholds_init(),
 
 		.do_jitter = false,
-		.jwarn = "-1:5000",
-		.jcrit = "-1:10000",
-		.jitter_thresholds = NULL,
+		.jitter_thresholds = mp_thresholds_init(),
 	};
+
+	mp_range stratum_default = mp_range_init();
+	stratum_default = mp_range_set_start(stratum_default, mp_create_pd_value(-1));
+	stratum_default = mp_range_set_end(stratum_default, mp_create_pd_value(16));
+	tmp.stratum_thresholds = mp_thresholds_set_warn(tmp.stratum_thresholds, stratum_default);
+	tmp.stratum_thresholds = mp_thresholds_set_crit(tmp.stratum_thresholds, stratum_default);
+
+	mp_range jitter_w_default = mp_range_init();
+	jitter_w_default = mp_range_set_start(jitter_w_default, mp_create_pd_value(-1));
+	jitter_w_default = mp_range_set_end(jitter_w_default, mp_create_pd_value(5000));
+	tmp.jitter_thresholds = mp_thresholds_set_warn(tmp.jitter_thresholds, jitter_w_default);
+
+	mp_range jitter_c_default = mp_range_init();
+	jitter_c_default = mp_range_set_start(jitter_c_default, mp_create_pd_value(-1));
+	jitter_c_default = mp_range_set_end(jitter_c_default, mp_create_pd_value(10000));
+	tmp.jitter_thresholds = mp_thresholds_set_crit(tmp.jitter_thresholds, jitter_c_default);
+
+	mp_range offset_w_default = mp_range_init();
+	offset_w_default = mp_range_set_start(offset_w_default, mp_create_pd_value(60));
+	tmp.offset_thresholds = mp_thresholds_set_warn(tmp.offset_thresholds, offset_w_default);
+	mp_range offset_c_default = mp_range_init();
+	offset_c_default = mp_range_set_start(offset_c_default, mp_create_pd_value(120));
+	tmp.offset_thresholds = mp_thresholds_set_crit(tmp.offset_thresholds, offset_c_default);
 	return tmp;
 }



More information about the Commits mailing list