From b35853ee4e10c4485a9521d77c95aecae6573e64 Mon Sep 17 00:00:00 2001 From: Lorenz Kästle <12514511+RincewindsHat@users.noreply.github.com> Date: Tue, 4 Nov 2025 12:08:59 +0100 Subject: check_ntp_time: implement modern output --- plugins/check_ntp_time.c | 160 ++++++++++++++++++++++++----------------------- 1 file changed, 82 insertions(+), 78 deletions(-) (limited to 'plugins/check_ntp_time.c') 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@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@monitoring-plugins.org"; static int verbose = 0; +const char *progname = "check_ntp_time"; +const char *copyright = "2006-2024"; +const char *email = "devel@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) { -- cgit v1.2.3-74-g34f1