[monitoring-plugins] check_ntp_time: implement modern output
Lorenz Kästle
git at monitoring-plugins.org
Wed Nov 5 11:00:16 CET 2025
Module: monitoring-plugins
Branch: master
Commit: b35853ee4e10c4485a9521d77c95aecae6573e64
Author: Lorenz Kästle <12514511+RincewindsHat at users.noreply.github.com>
Date: Tue Nov 4 12:08:59 2025 +0100
URL: https://www.monitoring-plugins.org/repositories/monitoring-plugins/commit/?id=b35853ee
check_ntp_time: implement modern output
---
plugins/check_ntp_time.c | 160 +++++++++++++++++++-------------------
plugins/check_ntp_time.d/config.h | 13 +++-
2 files changed, 93 insertions(+), 80 deletions(-)
diff --git a/plugins/check_ntp_time.c b/plugins/check_ntp_time.c
index ad69b804..eee9c298 100644
--- a/plugins/check_ntp_time.c
+++ b/plugins/check_ntp_time.c
@@ -34,12 +34,10 @@
*
*****************************************************************************/
-const char *progname = "check_ntp_time";
-const char *copyright = "2006-2024";
-const char *email = "devel at monitoring-plugins.org";
-
+#include "output.h"
#include "common.h"
#include "netutils.h"
+#include "perfdata.h"
#include "utils.h"
#include "states.h"
#include "thresholds.h"
@@ -47,6 +45,10 @@ const char *email = "devel at monitoring-plugins.org";
static int verbose = 0;
+const char *progname = "check_ntp_time";
+const char *copyright = "2006-2024";
+const char *email = "devel at monitoring-plugins.org";
+
typedef struct {
int errorcode;
check_ntp_time_config config;
@@ -61,9 +63,6 @@ void print_usage(void);
# define AVG_NUM 4
#endif
-/* max size of control message data */
-#define MAX_CM_SIZE 468
-
/* this structure holds everything in an ntp request/response as per rfc1305 */
typedef struct {
uint8_t flags; /* byte with leapindicator,vers,mode. see macros */
@@ -169,7 +168,9 @@ typedef struct {
: 0)
/* convert a struct timeval to a double */
-#define TVasDOUBLE(x) (double)(x.tv_sec + (0.000001 * x.tv_usec))
+static double TVasDOUBLE(struct timeval time) {
+ return ((double)time.tv_sec + (0.000001 * (double)time.tv_usec));
+}
/* convert an ntp 64-bit fp number to a struct timeval */
#define NTP64toTV(n, t) \
@@ -262,8 +263,8 @@ void setup_request(ntp_message *message) {
/* select the "best" server from a list of servers, and return its index.
* this is done by filtering servers based on stratum, dispersion, and
* finally round-trip delay. */
-int best_offset_server(const ntp_server_results *slist, int nservers) {
- int best_server = -1;
+static int best_offset_server(const ntp_server_results *slist, int nservers) {
+ int best_server_index = -1;
/* for each server */
for (int cserver = 0; cserver < nservers; cserver++) {
@@ -286,33 +287,33 @@ int best_offset_server(const ntp_server_results *slist, int nservers) {
}
/* If we don't have a server yet, use the first one */
- if (best_server == -1) {
- best_server = cserver;
- DBG(printf("using peer %d as our first candidate\n", best_server));
+ if (best_server_index == -1) {
+ best_server_index = cserver;
+ DBG(printf("using peer %d as our first candidate\n", best_server_index));
continue;
}
/* compare the server to the best one we've seen so far */
/* does it have an equal or better stratum? */
- DBG(printf("comparing peer %d with peer %d\n", cserver, best_server));
- if (slist[cserver].stratum <= slist[best_server].stratum) {
- DBG(printf("stratum for peer %d <= peer %d\n", cserver, best_server));
+ DBG(printf("comparing peer %d with peer %d\n", cserver, best_server_index));
+ if (slist[cserver].stratum <= slist[best_server_index].stratum) {
+ DBG(printf("stratum for peer %d <= peer %d\n", cserver, best_server_index));
/* does it have an equal or better dispersion? */
- if (slist[cserver].rtdisp <= slist[best_server].rtdisp) {
- DBG(printf("dispersion for peer %d <= peer %d\n", cserver, best_server));
+ if (slist[cserver].rtdisp <= slist[best_server_index].rtdisp) {
+ DBG(printf("dispersion for peer %d <= peer %d\n", cserver, best_server_index));
/* does it have a better rtdelay? */
- if (slist[cserver].rtdelay < slist[best_server].rtdelay) {
- DBG(printf("rtdelay for peer %d < peer %d\n", cserver, best_server));
- best_server = cserver;
- DBG(printf("peer %d is now our best candidate\n", best_server));
+ if (slist[cserver].rtdelay < slist[best_server_index].rtdelay) {
+ DBG(printf("rtdelay for peer %d < peer %d\n", cserver, best_server_index));
+ best_server_index = cserver;
+ DBG(printf("peer %d is now our best candidate\n", best_server_index));
}
}
}
}
- if (best_server >= 0) {
- DBG(printf("best server selected: peer %d\n", best_server));
- return best_server;
+ if (best_server_index >= 0) {
+ DBG(printf("best server selected: peer %d\n", best_server_index));
+ return best_server_index;
}
DBG(printf("no peers meeting synchronization criteria :(\n"));
return -1;
@@ -323,7 +324,11 @@ int best_offset_server(const ntp_server_results *slist, int nservers) {
* we don't waste time sitting around waiting for single packets.
* - we also "manually" handle resolving host names and connecting, because
* we have to do it in a way that our lazy macros don't handle currently :( */
-double offset_request(const char *host, const char *port, mp_state_enum *status, int time_offset) {
+typedef struct {
+ mp_state_enum offset_result;
+ double offset;
+} offset_request_wrapper;
+static offset_request_wrapper offset_request(const char *host, const char *port, int time_offset) {
/* setup hints to only return results from getaddrinfo that we'd like */
struct addrinfo hints;
memset(&hints, 0, sizeof(struct addrinfo));
@@ -462,11 +467,16 @@ double offset_request(const char *host, const char *port, mp_state_enum *status,
die(STATE_CRITICAL, "NTP CRITICAL: No response from NTP server\n");
}
+ offset_request_wrapper result = {
+ .offset = 0,
+ .offset_result = STATE_UNKNOWN,
+ };
+
/* now, pick the best server from the list */
double avg_offset = 0.;
int best_index = best_offset_server(servers, num_hosts);
if (best_index < 0) {
- *status = STATE_UNKNOWN;
+ result.offset_result = STATE_UNKNOWN;
} else {
/* finally, calculate the average offset */
for (int i = 0; i < servers[best_index].num_responses; i++) {
@@ -488,10 +498,12 @@ double offset_request(const char *host, const char *port, mp_state_enum *status,
if (verbose) {
printf("overall average offset: %.10g\n", avg_offset);
}
- return avg_offset;
+
+ result.offset = avg_offset;
+ return result;
}
-check_ntp_time_config_wrapper process_arguments(int argc, char **argv) {
+static check_ntp_time_config_wrapper process_arguments(int argc, char **argv) {
static struct option longopts[] = {{"version", no_argument, 0, 'V'},
{"help", no_argument, 0, 'h'},
{"verbose", no_argument, 0, 'v'},
@@ -515,9 +527,6 @@ check_ntp_time_config_wrapper process_arguments(int argc, char **argv) {
.config = check_ntp_time_config_init(),
};
- char *owarn = "60";
- char *ocrit = "120";
-
while (true) {
int option = 0;
int option_char = getopt_long(argc, argv, "Vhv46qw:c:t:H:p:o:", longopts, &option);
@@ -540,12 +549,24 @@ check_ntp_time_config_wrapper process_arguments(int argc, char **argv) {
case 'q':
result.config.quiet = true;
break;
- case 'w':
- owarn = optarg;
- break;
- case 'c':
- ocrit = optarg;
- break;
+ case 'w': {
+ mp_range_parsed tmp = mp_parse_range_string(optarg);
+ if (tmp.error != MP_PARSING_SUCCES) {
+ die(STATE_UNKNOWN, "failed to parse warning threshold");
+ }
+
+ result.config.offset_thresholds =
+ 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 crit threshold");
+ }
+
+ result.config.offset_thresholds =
+ mp_thresholds_set_crit(result.config.offset_thresholds, tmp.range);
+ } break;
case 'H':
if (!is_host(optarg)) {
usage2(_("Invalid hostname/address"), optarg);
@@ -582,16 +603,9 @@ check_ntp_time_config_wrapper process_arguments(int argc, char **argv) {
usage4(_("Hostname was not supplied"));
}
- set_thresholds(&result.config.offset_thresholds, owarn, ocrit);
-
return result;
}
-char *perfd_offset(double offset, thresholds *offset_thresholds) {
- return fperfdata("offset", offset, "s", true, offset_thresholds->warning->end, true,
- offset_thresholds->critical->end, false, 0, false, 0);
-}
-
int main(int argc, char *argv[]) {
setlocale(LC_ALL, "");
bindtextdomain(PACKAGE, LOCALEDIR);
@@ -614,46 +628,36 @@ int main(int argc, char *argv[]) {
/* set socket timeout */
alarm(socket_timeout);
- mp_state_enum offset_result = STATE_OK;
- mp_state_enum result = STATE_OK;
- double offset =
- offset_request(config.server_address, config.port, &offset_result, config.time_offset);
- if (offset_result == STATE_UNKNOWN) {
- result = ((!config.quiet) ? STATE_UNKNOWN : STATE_CRITICAL);
- } else {
- result = get_status(fabs(offset), config.offset_thresholds);
- }
+ mp_check overall = mp_check_init();
- 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;
- }
+ mp_subcheck sc_offset = mp_subcheck_init();
+ offset_request_wrapper offset_result =
+ offset_request(config.server_address, config.port, config.time_offset);
- char *perfdata_line;
- if (offset_result == STATE_UNKNOWN) {
- xasprintf(&result_line, "%s %s", result_line, _("Offset unknown"));
- xasprintf(&perfdata_line, "");
- } else {
- xasprintf(&result_line, "%s %s %.10g secs", result_line, _("Offset"), offset);
- xasprintf(&perfdata_line, "%s", perfd_offset(offset, config.offset_thresholds));
+ if (offset_result.offset_result == STATE_UNKNOWN) {
+ sc_offset =
+ mp_set_subcheck_state(sc_offset, (!config.quiet) ? STATE_UNKNOWN : STATE_CRITICAL);
+ xasprintf(&sc_offset.output, "Offset unknown");
+ mp_add_subcheck_to_check(&overall, sc_offset);
+ mp_exit(overall);
}
- printf("%s|%s\n", result_line, perfdata_line);
+
+ xasprintf(&sc_offset.output, "Offset: %.10g s", offset_result.offset);
+
+ mp_perfdata pd_offset = perfdata_init();
+ pd_offset = mp_set_pd_value(pd_offset, fabs(offset_result.offset));
+ pd_offset.label = "offset";
+ pd_offset = mp_pd_set_thresholds(pd_offset, config.offset_thresholds);
+
+ sc_offset = mp_set_subcheck_state(sc_offset, mp_get_pd_status(pd_offset));
+
+ mp_add_perfdata_to_subcheck(&sc_offset, pd_offset);
+ mp_add_subcheck_to_check(&overall, sc_offset);
if (config.server_address != NULL) {
free(config.server_address);
}
- exit(result);
+ mp_exit(overall);
}
void print_help(void) {
diff --git a/plugins/check_ntp_time.d/config.h b/plugins/check_ntp_time.d/config.h
index 99dabbbd..a62e4ceb 100644
--- a/plugins/check_ntp_time.d/config.h
+++ b/plugins/check_ntp_time.d/config.h
@@ -11,7 +11,7 @@ typedef struct {
bool quiet;
int time_offset;
- thresholds *offset_thresholds;
+ mp_thresholds offset_thresholds;
} check_ntp_time_config;
check_ntp_time_config check_ntp_time_config_init() {
@@ -22,7 +22,16 @@ check_ntp_time_config check_ntp_time_config_init() {
.quiet = false,
.time_offset = 0,
- .offset_thresholds = NULL,
+ .offset_thresholds = mp_thresholds_init(),
};
+
+ mp_range warning = mp_range_init();
+ warning = mp_range_set_end(warning, mp_create_pd_value(60));
+ tmp.offset_thresholds = mp_thresholds_set_warn(tmp.offset_thresholds, warning);
+
+ mp_range critical = mp_range_init();
+ critical = mp_range_set_end(warning, mp_create_pd_value(120));
+ tmp.offset_thresholds = mp_thresholds_set_crit(tmp.offset_thresholds, critical);
+
return tmp;
}
More information about the Commits
mailing list