Module: monitoring-plugins
 Branch: master
 Commit: b35853ee4e10c4485a9521d77c95aecae6573e64
 Author: Lorenz Kästle <[email protected]>
   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 = "[email protected]";
-
+#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 = "[email protected]";
 
 static int verbose = 0;
 
+const char *progname = "check_ntp_time";
+const char *copyright = "2006-2024";
+const char *email = "[email protected]";
+
 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;
 }

Reply via email to