summaryrefslogtreecommitdiffstats
path: root/plugins/check_ntp_peer.c
diff options
context:
space:
mode:
authorLorenz Kästle <12514511+RincewindsHat@users.noreply.github.com>2025-11-05 13:54:43 +0100
committerLorenz Kästle <12514511+RincewindsHat@users.noreply.github.com>2025-11-05 13:54:43 +0100
commit8e5cb31dc1fac2760233352e7d8e3b09812a80a1 (patch)
treed4d84c58cd7746e1e0298d3eff0aebedefdab3dc /plugins/check_ntp_peer.c
parentba6f90373333246bce196dbba494fa4af0bd9253 (diff)
parentad7acf4618f1ac8a49277a482fb4ca391a26f584 (diff)
downloadmonitoring-plugins-8e5cb31dc1fac2760233352e7d8e3b09812a80a1.tar.gz
Merge branch 'master' into modern_output/check_pgsql
Diffstat (limited to 'plugins/check_ntp_peer.c')
-rw-r--r--plugins/check_ntp_peer.c360
1 files changed, 212 insertions, 148 deletions
diff --git a/plugins/check_ntp_peer.c b/plugins/check_ntp_peer.c
index 24d1c9b5..f7cad630 100644
--- a/plugins/check_ntp_peer.c
+++ b/plugins/check_ntp_peer.c
@@ -35,11 +35,14 @@
35 * 35 *
36 *****************************************************************************/ 36 *****************************************************************************/
37 37
38#include "thresholds.h"
39const char *progname = "check_ntp_peer"; 38const char *progname = "check_ntp_peer";
40const char *copyright = "2006-2024"; 39const char *copyright = "2006-2024";
41const char *email = "devel@monitoring-plugins.org"; 40const char *email = "devel@monitoring-plugins.org";
42 41
42#include "output.h"
43#include "perfdata.h"
44#include <openssl/x509.h>
45#include "thresholds.h"
43#include "common.h" 46#include "common.h"
44#include "netutils.h" 47#include "netutils.h"
45#include "utils.h" 48#include "utils.h"
@@ -47,8 +50,6 @@ const char *email = "devel@monitoring-plugins.org";
47#include "check_ntp_peer.d/config.h" 50#include "check_ntp_peer.d/config.h"
48 51
49static int verbose = 0; 52static int verbose = 0;
50static bool syncsource_found = false;
51static bool li_alarm = false;
52 53
53typedef struct { 54typedef struct {
54 int errorcode; 55 int errorcode;
@@ -198,9 +199,7 @@ void setup_control_request(ntp_control_message *message, uint8_t opcode, uint16_
198 * positive value means a success retrieving the value. 199 * positive value means a success retrieving the value.
199 * - status is set to WARNING if there's no sync.peer (otherwise OK) and is 200 * - status is set to WARNING if there's no sync.peer (otherwise OK) and is
200 * the return value of the function. 201 * the return value of the function.
201 * status is pretty much useless as syncsource_found is a global variable 202 */
202 * used later in main to check is the server was synchronized. It works
203 * so I left it alone */
204typedef struct { 203typedef struct {
205 mp_state_enum state; 204 mp_state_enum state;
206 mp_state_enum offset_result; 205 mp_state_enum offset_result;
@@ -208,6 +207,8 @@ typedef struct {
208 double jitter; 207 double jitter;
209 long stratum; 208 long stratum;
210 int num_truechimers; 209 int num_truechimers;
210 bool syncsource_found;
211 bool li_alarm;
211} ntp_request_result; 212} ntp_request_result;
212ntp_request_result ntp_request(const check_ntp_peer_config config) { 213ntp_request_result ntp_request(const check_ntp_peer_config config) {
213 214
@@ -217,6 +218,8 @@ ntp_request_result ntp_request(const check_ntp_peer_config config) {
217 .jitter = -1, 218 .jitter = -1,
218 .stratum = -1, 219 .stratum = -1,
219 .num_truechimers = 0, 220 .num_truechimers = 0,
221 .syncsource_found = false,
222 .li_alarm = false,
220 }; 223 };
221 224
222 /* Long-winded explanation: 225 /* Long-winded explanation:
@@ -235,19 +238,16 @@ ntp_request_result ntp_request(const check_ntp_peer_config config) {
235 * 4) Extract the offset, jitter and stratum value from the data[] 238 * 4) Extract the offset, jitter and stratum value from the data[]
236 * (it's ASCII) 239 * (it's ASCII)
237 */ 240 */
238 int min_peer_sel = PEER_INCLUDED;
239 int num_candidates = 0;
240 void *tmp;
241 ntp_assoc_status_pair *peers = NULL;
242 int peer_offset = 0;
243 size_t peers_size = 0;
244 size_t npeers = 0;
245 int conn = -1; 241 int conn = -1;
246 my_udp_connect(config.server_address, config.port, &conn); 242 my_udp_connect(config.server_address, config.port, &conn);
247 243
248 /* keep sending requests until the server stops setting the 244 /* keep sending requests until the server stops setting the
249 * REM_MORE bit, though usually this is only 1 packet. */ 245 * REM_MORE bit, though usually this is only 1 packet. */
250 ntp_control_message req; 246 ntp_control_message req;
247 ntp_assoc_status_pair *peers = NULL;
248 int peer_offset = 0;
249 size_t peers_size = 0;
250 size_t npeers = 0;
251 do { 251 do {
252 setup_control_request(&req, OP_READSTAT, 1); 252 setup_control_request(&req, OP_READSTAT, 1);
253 DBG(printf("sending READSTAT request")); 253 DBG(printf("sending READSTAT request"));
@@ -269,12 +269,13 @@ ntp_request_result ntp_request(const check_ntp_peer_config config) {
269 } while (!(req.op & OP_READSTAT && ntohs(req.seq) == 1)); 269 } while (!(req.op & OP_READSTAT && ntohs(req.seq) == 1));
270 270
271 if (LI(req.flags) == LI_ALARM) { 271 if (LI(req.flags) == LI_ALARM) {
272 li_alarm = true; 272 result.li_alarm = true;
273 } 273 }
274 /* Each peer identifier is 4 bytes in the data section, which 274 /* Each peer identifier is 4 bytes in the data section, which
275 * we represent as a ntp_assoc_status_pair datatype. 275 * we represent as a ntp_assoc_status_pair datatype.
276 */ 276 */
277 peers_size += ntohs(req.count); 277 peers_size += ntohs(req.count);
278 void *tmp;
278 if ((tmp = realloc(peers, peers_size)) == NULL) { 279 if ((tmp = realloc(peers, peers_size)) == NULL) {
279 free(peers), die(STATE_UNKNOWN, "can not (re)allocate 'peers' buffer\n"); 280 free(peers), die(STATE_UNKNOWN, "can not (re)allocate 'peers' buffer\n");
280 } 281 }
@@ -287,13 +288,15 @@ ntp_request_result ntp_request(const check_ntp_peer_config config) {
287 /* first, let's find out if we have a sync source, or if there are 288 /* first, let's find out if we have a sync source, or if there are
288 * at least some candidates. In the latter case we'll issue 289 * at least some candidates. In the latter case we'll issue
289 * a warning but go ahead with the check on them. */ 290 * a warning but go ahead with the check on them. */
291 int min_peer_sel = PEER_INCLUDED;
292 int num_candidates = 0;
290 for (size_t i = 0; i < npeers; i++) { 293 for (size_t i = 0; i < npeers; i++) {
291 if (PEER_SEL(peers[i].status) >= PEER_TRUECHIMER) { 294 if (PEER_SEL(peers[i].status) >= PEER_TRUECHIMER) {
292 result.num_truechimers++; 295 result.num_truechimers++;
293 if (PEER_SEL(peers[i].status) >= PEER_INCLUDED) { 296 if (PEER_SEL(peers[i].status) >= PEER_INCLUDED) {
294 num_candidates++; 297 num_candidates++;
295 if (PEER_SEL(peers[i].status) >= PEER_SYNCSOURCE) { 298 if (PEER_SEL(peers[i].status) >= PEER_SYNCSOURCE) {
296 syncsource_found = true; 299 result.syncsource_found = true;
297 min_peer_sel = PEER_SYNCSOURCE; 300 min_peer_sel = PEER_SYNCSOURCE;
298 } 301 }
299 } 302 }
@@ -302,18 +305,18 @@ ntp_request_result ntp_request(const check_ntp_peer_config config) {
302 305
303 if (verbose) { 306 if (verbose) {
304 printf("%d candidate peers available\n", num_candidates); 307 printf("%d candidate peers available\n", num_candidates);
305 } 308 if (result.syncsource_found) {
306 if (verbose && syncsource_found) { 309 printf("synchronization source found\n");
307 printf("synchronization source found\n"); 310 }
308 } 311 }
309 312
310 if (!syncsource_found) { 313 if (!result.syncsource_found) {
311 result.state = STATE_WARNING; 314 result.state = STATE_WARNING;
312 if (verbose) { 315 if (verbose) {
313 printf("warning: no synchronization source found\n"); 316 printf("warning: no synchronization source found\n");
314 } 317 }
315 } 318 }
316 if (li_alarm) { 319 if (result.li_alarm) {
317 result.state = STATE_WARNING; 320 result.state = STATE_WARNING;
318 if (verbose) { 321 if (verbose) {
319 printf("warning: LI_ALARM bit is set\n"); 322 printf("warning: LI_ALARM bit is set\n");
@@ -329,7 +332,7 @@ ntp_request_result ntp_request(const check_ntp_peer_config config) {
329 if (verbose) { 332 if (verbose) {
330 printf("Getting offset, jitter and stratum for peer %.2x\n", ntohs(peers[i].assoc)); 333 printf("Getting offset, jitter and stratum for peer %.2x\n", ntohs(peers[i].assoc));
331 } 334 }
332 xasprintf(&data, ""); 335 data = strdup("");
333 do { 336 do {
334 setup_control_request(&req, OP_READVAR, 2); 337 setup_control_request(&req, OP_READVAR, 2);
335 req.assoc = peers[i].assoc; 338 req.assoc = peers[i].assoc;
@@ -475,16 +478,30 @@ ntp_request_result ntp_request(const check_ntp_peer_config config) {
475} 478}
476 479
477check_ntp_peer_config_wrapper process_arguments(int argc, char **argv) { 480check_ntp_peer_config_wrapper process_arguments(int argc, char **argv) {
478 static struct option longopts[] = { 481
479 {"version", no_argument, 0, 'V'}, {"help", no_argument, 0, 'h'}, 482 enum {
480 {"verbose", no_argument, 0, 'v'}, {"use-ipv4", no_argument, 0, '4'}, 483 output_format_index = CHAR_MAX + 1,
481 {"use-ipv6", no_argument, 0, '6'}, {"quiet", no_argument, 0, 'q'}, 484 };
482 {"warning", required_argument, 0, 'w'}, {"critical", required_argument, 0, 'c'}, 485
483 {"swarn", required_argument, 0, 'W'}, {"scrit", required_argument, 0, 'C'}, 486 static struct option longopts[] = {{"version", no_argument, 0, 'V'},
484 {"jwarn", required_argument, 0, 'j'}, {"jcrit", required_argument, 0, 'k'}, 487 {"help", no_argument, 0, 'h'},
485 {"twarn", required_argument, 0, 'm'}, {"tcrit", required_argument, 0, 'n'}, 488 {"verbose", no_argument, 0, 'v'},
486 {"timeout", required_argument, 0, 't'}, {"hostname", required_argument, 0, 'H'}, 489 {"use-ipv4", no_argument, 0, '4'},
487 {"port", required_argument, 0, 'p'}, {0, 0, 0, 0}}; 490 {"use-ipv6", no_argument, 0, '6'},
491 {"quiet", no_argument, 0, 'q'},
492 {"warning", required_argument, 0, 'w'},
493 {"critical", required_argument, 0, 'c'},
494 {"swarn", required_argument, 0, 'W'},
495 {"scrit", required_argument, 0, 'C'},
496 {"jwarn", required_argument, 0, 'j'},
497 {"jcrit", required_argument, 0, 'k'},
498 {"twarn", required_argument, 0, 'm'},
499 {"tcrit", required_argument, 0, 'n'},
500 {"timeout", required_argument, 0, 't'},
501 {"hostname", required_argument, 0, 'H'},
502 {"port", required_argument, 0, 'p'},
503 {"output-format", required_argument, 0, output_format_index},
504 {0, 0, 0, 0}};
488 505
489 if (argc < 2) { 506 if (argc < 2) {
490 usage("\n"); 507 usage("\n");
@@ -504,6 +521,17 @@ check_ntp_peer_config_wrapper process_arguments(int argc, char **argv) {
504 } 521 }
505 522
506 switch (option_char) { 523 switch (option_char) {
524 case output_format_index: {
525 parsed_output_format parser = mp_parse_output_format(optarg);
526 if (!parser.parsing_success) {
527 printf("Invalid output format: %s\n", optarg);
528 exit(STATE_UNKNOWN);
529 }
530
531 result.config.output_format_is_set = true;
532 result.config.output_format = parser.output_format;
533 break;
534 }
507 case 'h': 535 case 'h':
508 print_help(); 536 print_help();
509 exit(STATE_UNKNOWN); 537 exit(STATE_UNKNOWN);
@@ -518,36 +546,84 @@ check_ntp_peer_config_wrapper process_arguments(int argc, char **argv) {
518 case 'q': 546 case 'q':
519 result.config.quiet = true; 547 result.config.quiet = true;
520 break; 548 break;
521 case 'w': 549 case 'w': {
522 result.config.owarn = optarg; 550 mp_range_parsed tmp = mp_parse_range_string(optarg);
523 break; 551 if (tmp.error != MP_PARSING_SUCCES) {
524 case 'c': 552 die(STATE_UNKNOWN, "failed to parse warning offset threshold");
525 result.config.ocrit = optarg; 553 }
526 break; 554
527 case 'W': 555 result.config.offset_thresholds =
556 mp_thresholds_set_warn(result.config.offset_thresholds, tmp.range);
557 } break;
558 case 'c': {
559 mp_range_parsed tmp = mp_parse_range_string(optarg);
560 if (tmp.error != MP_PARSING_SUCCES) {
561 die(STATE_UNKNOWN, "failed to parse critical offset threshold");
562 }
563
564 result.config.offset_thresholds =
565 mp_thresholds_set_crit(result.config.offset_thresholds, tmp.range);
566 } break;
567 case 'W': {
528 result.config.do_stratum = true; 568 result.config.do_stratum = true;
529 result.config.swarn = optarg; 569 mp_range_parsed tmp = mp_parse_range_string(optarg);
530 break; 570 if (tmp.error != MP_PARSING_SUCCES) {
531 case 'C': 571 die(STATE_UNKNOWN, "failed to parse warning stratum threshold");
572 }
573
574 result.config.stratum_thresholds =
575 mp_thresholds_set_warn(result.config.stratum_thresholds, tmp.range);
576 } break;
577 case 'C': {
532 result.config.do_stratum = true; 578 result.config.do_stratum = true;
533 result.config.scrit = optarg; 579 mp_range_parsed tmp = mp_parse_range_string(optarg);
534 break; 580 if (tmp.error != MP_PARSING_SUCCES) {
535 case 'j': 581 die(STATE_UNKNOWN, "failed to parse critical stratum threshold");
582 }
583
584 result.config.stratum_thresholds =
585 mp_thresholds_set_crit(result.config.stratum_thresholds, tmp.range);
586 } break;
587 case 'j': {
536 result.config.do_jitter = true; 588 result.config.do_jitter = true;
537 result.config.jwarn = optarg; 589 mp_range_parsed tmp = mp_parse_range_string(optarg);
538 break; 590 if (tmp.error != MP_PARSING_SUCCES) {
539 case 'k': 591 die(STATE_UNKNOWN, "failed to parse warning jitter threshold");
592 }
593
594 result.config.jitter_thresholds =
595 mp_thresholds_set_warn(result.config.jitter_thresholds, tmp.range);
596 } break;
597 case 'k': {
540 result.config.do_jitter = true; 598 result.config.do_jitter = true;
541 result.config.jcrit = optarg; 599 mp_range_parsed tmp = mp_parse_range_string(optarg);
542 break; 600 if (tmp.error != MP_PARSING_SUCCES) {
543 case 'm': 601 die(STATE_UNKNOWN, "failed to parse critical jitter threshold");
602 }
603
604 result.config.jitter_thresholds =
605 mp_thresholds_set_crit(result.config.jitter_thresholds, tmp.range);
606 } break;
607 case 'm': {
544 result.config.do_truechimers = true; 608 result.config.do_truechimers = true;
545 result.config.twarn = optarg; 609 mp_range_parsed tmp = mp_parse_range_string(optarg);
546 break; 610 if (tmp.error != MP_PARSING_SUCCES) {
547 case 'n': 611 die(STATE_UNKNOWN, "failed to parse warning truechimer threshold");
612 }
613
614 result.config.truechimer_thresholds =
615 mp_thresholds_set_warn(result.config.truechimer_thresholds, tmp.range);
616 } break;
617 case 'n': {
548 result.config.do_truechimers = true; 618 result.config.do_truechimers = true;
549 result.config.tcrit = optarg; 619 mp_range_parsed tmp = mp_parse_range_string(optarg);
550 break; 620 if (tmp.error != MP_PARSING_SUCCES) {
621 die(STATE_UNKNOWN, "failed to parse critical truechimer threshold");
622 }
623
624 result.config.truechimer_thresholds =
625 mp_thresholds_set_crit(result.config.truechimer_thresholds, tmp.range);
626 } break;
551 case 'H': 627 case 'H':
552 if (!is_host(optarg)) { 628 if (!is_host(optarg)) {
553 usage2(_("Invalid hostname/address"), optarg); 629 usage2(_("Invalid hostname/address"), optarg);
@@ -581,11 +657,6 @@ check_ntp_peer_config_wrapper process_arguments(int argc, char **argv) {
581 usage4(_("Hostname was not supplied")); 657 usage4(_("Hostname was not supplied"));
582 } 658 }
583 659
584 set_thresholds(&result.config.offset_thresholds, result.config.owarn, result.config.ocrit);
585 set_thresholds(&result.config.jitter_thresholds, result.config.jwarn, result.config.jcrit);
586 set_thresholds(&result.config.stratum_thresholds, result.config.swarn, result.config.scrit);
587 set_thresholds(&result.config.truechimer_thresholds, result.config.twarn, result.config.tcrit);
588
589 return result; 660 return result;
590} 661}
591 662
@@ -627,6 +698,10 @@ int main(int argc, char *argv[]) {
627 698
628 const check_ntp_peer_config config = tmp_config.config; 699 const check_ntp_peer_config config = tmp_config.config;
629 700
701 if (config.output_format_is_set) {
702 mp_set_format(config.output_format);
703 }
704
630 /* initialize alarm signal handling */ 705 /* initialize alarm signal handling */
631 signal(SIGALRM, socket_timeout_alarm_handler); 706 signal(SIGALRM, socket_timeout_alarm_handler);
632 707
@@ -634,125 +709,113 @@ int main(int argc, char *argv[]) {
634 alarm(socket_timeout); 709 alarm(socket_timeout);
635 710
636 /* This returns either OK or WARNING (See comment preceding ntp_request) */ 711 /* This returns either OK or WARNING (See comment preceding ntp_request) */
637 ntp_request_result ntp_res = ntp_request(config); 712 const ntp_request_result ntp_res = ntp_request(config);
638 mp_state_enum result = STATE_UNKNOWN; 713 mp_check overall = mp_check_init();
639 714
715 mp_subcheck sc_offset = mp_subcheck_init();
716 xasprintf(&sc_offset.output, "offset");
640 if (ntp_res.offset_result == STATE_UNKNOWN) { 717 if (ntp_res.offset_result == STATE_UNKNOWN) {
641 /* if there's no sync peer (this overrides ntp_request output): */ 718 /* if there's no sync peer (this overrides ntp_request output): */
642 result = (config.quiet ? STATE_UNKNOWN : STATE_CRITICAL); 719 sc_offset =
720 mp_set_subcheck_state(sc_offset, (config.quiet ? STATE_UNKNOWN : STATE_CRITICAL));
721 xasprintf(&sc_offset.output, "%s unknown", sc_offset.output);
643 } else { 722 } else {
644 /* Be quiet if there's no candidates either */ 723 /* Be quiet if there's no candidates either */
645 if (config.quiet && result == STATE_WARNING) { 724 mp_state_enum tmp = STATE_OK;
646 result = STATE_UNKNOWN; 725 if (config.quiet && ntp_res.state == STATE_WARNING) {
726 tmp = STATE_UNKNOWN;
647 } 727 }
648 result = max_state_alt(result, get_status(fabs(ntp_res.offset), config.offset_thresholds)); 728
729 xasprintf(&sc_offset.output, "%s: %.6fs", sc_offset.output, ntp_res.offset);
730
731 mp_perfdata pd_offset = perfdata_init();
732 pd_offset.value = mp_create_pd_value(fabs(ntp_res.offset));
733 pd_offset = mp_pd_set_thresholds(pd_offset, config.offset_thresholds);
734 pd_offset.label = "offset";
735 pd_offset.uom = "s";
736 mp_add_perfdata_to_subcheck(&sc_offset, pd_offset);
737
738 tmp = max_state_alt(tmp, mp_get_pd_status(pd_offset));
739 sc_offset = mp_set_subcheck_state(sc_offset, tmp);
649 } 740 }
650 741
651 mp_state_enum oresult = result; 742 mp_add_subcheck_to_check(&overall, sc_offset);
652 mp_state_enum tresult = STATE_UNKNOWN;
653 743
744 // truechimers
654 if (config.do_truechimers) { 745 if (config.do_truechimers) {
655 tresult = get_status(ntp_res.num_truechimers, config.truechimer_thresholds); 746 mp_subcheck sc_truechimers = mp_subcheck_init();
656 result = max_state_alt(result, tresult); 747 xasprintf(&sc_truechimers.output, "truechimers: %i", ntp_res.num_truechimers);
657 }
658 748
659 mp_state_enum sresult = STATE_UNKNOWN; 749 mp_perfdata pd_truechimers = perfdata_init();
750 pd_truechimers.value = mp_create_pd_value(ntp_res.num_truechimers);
751 pd_truechimers.label = "truechimers";
752 pd_truechimers = mp_pd_set_thresholds(pd_truechimers, config.truechimer_thresholds);
660 753
661 if (config.do_stratum) { 754 mp_add_perfdata_to_subcheck(&sc_truechimers, pd_truechimers);
662 sresult = get_status((double)ntp_res.stratum, config.stratum_thresholds);
663 result = max_state_alt(result, sresult);
664 }
665 755
666 mp_state_enum jresult = STATE_UNKNOWN; 756 sc_truechimers = mp_set_subcheck_state(sc_truechimers, mp_get_pd_status(pd_truechimers));
667 757
668 if (config.do_jitter) { 758 mp_add_subcheck_to_check(&overall, sc_truechimers);
669 jresult = get_status(ntp_res.jitter, config.jitter_thresholds);
670 result = max_state_alt(result, jresult);
671 } 759 }
672 760
673 char *result_line; 761 if (config.do_stratum) {
674 switch (result) { 762 mp_subcheck sc_stratum = mp_subcheck_init();
675 case STATE_CRITICAL: 763 xasprintf(&sc_stratum.output, "stratum: %li", ntp_res.stratum);
676 xasprintf(&result_line, _("NTP CRITICAL:"));
677 break;
678 case STATE_WARNING:
679 xasprintf(&result_line, _("NTP WARNING:"));
680 break;
681 case STATE_OK:
682 xasprintf(&result_line, _("NTP OK:"));
683 break;
684 default:
685 xasprintf(&result_line, _("NTP UNKNOWN:"));
686 break;
687 }
688 764
689 if (!syncsource_found) { 765 mp_perfdata pd_stratum = perfdata_init();
690 xasprintf(&result_line, "%s %s,", result_line, _("Server not synchronized")); 766 pd_stratum.value = mp_create_pd_value(ntp_res.stratum);
691 } else if (li_alarm) { 767 pd_stratum = mp_pd_set_thresholds(pd_stratum, config.stratum_thresholds);
692 xasprintf(&result_line, "%s %s,", result_line, _("Server has the LI_ALARM bit set")); 768 pd_stratum.label = "stratum";
693 }
694 769
695 char *perfdata_line; 770 mp_add_perfdata_to_subcheck(&sc_stratum, pd_stratum);
696 if (ntp_res.offset_result == STATE_UNKNOWN) { 771
697 xasprintf(&result_line, "%s %s", result_line, _("Offset unknown")); 772 sc_stratum = mp_set_subcheck_state(sc_stratum, mp_get_pd_status(pd_stratum));
698 xasprintf(&perfdata_line, ""); 773
699 } else if (oresult == STATE_WARNING) { 774 mp_add_subcheck_to_check(&overall, sc_stratum);
700 xasprintf(&result_line, "%s %s %.10g secs (WARNING)", result_line, _("Offset"),
701 ntp_res.offset);
702 } else if (oresult == STATE_CRITICAL) {
703 xasprintf(&result_line, "%s %s %.10g secs (CRITICAL)", result_line, _("Offset"),
704 ntp_res.offset);
705 } else {
706 xasprintf(&result_line, "%s %s %.10g secs", result_line, _("Offset"), ntp_res.offset);
707 } 775 }
708 xasprintf(&perfdata_line, "%s", perfd_offset(ntp_res.offset, config.offset_thresholds));
709 776
710 if (config.do_jitter) { 777 if (config.do_jitter) {
711 if (jresult == STATE_WARNING) { 778 mp_subcheck sc_jitter = mp_subcheck_init();
712 xasprintf(&result_line, "%s, jitter=%f (WARNING)", result_line, ntp_res.jitter); 779 xasprintf(&sc_jitter.output, "jitter: %f", ntp_res.jitter);
713 } else if (jresult == STATE_CRITICAL) {
714 xasprintf(&result_line, "%s, jitter=%f (CRITICAL)", result_line, ntp_res.jitter);
715 } else {
716 xasprintf(&result_line, "%s, jitter=%f", result_line, ntp_res.jitter);
717 }
718 xasprintf(&perfdata_line, "%s %s", perfdata_line,
719 perfd_jitter(ntp_res.jitter, config.do_jitter, config.jitter_thresholds));
720 }
721 780
722 if (config.do_stratum) { 781 mp_perfdata pd_jitter = perfdata_init();
723 if (sresult == STATE_WARNING) { 782 pd_jitter.value = mp_create_pd_value(ntp_res.jitter);
724 xasprintf(&result_line, "%s, stratum=%li (WARNING)", result_line, ntp_res.stratum); 783 pd_jitter = mp_pd_set_thresholds(pd_jitter, config.jitter_thresholds);
725 } else if (sresult == STATE_CRITICAL) { 784 pd_jitter.label = "jitter";
726 xasprintf(&result_line, "%s, stratum=%li (CRITICAL)", result_line, ntp_res.stratum); 785
727 } else { 786 mp_add_perfdata_to_subcheck(&sc_jitter, pd_jitter);
728 xasprintf(&result_line, "%s, stratum=%li", result_line, ntp_res.stratum); 787
729 } 788 sc_jitter = mp_set_subcheck_state(sc_jitter, mp_get_pd_status(pd_jitter));
730 xasprintf(&perfdata_line, "%s %s", perfdata_line, 789 mp_add_subcheck_to_check(&overall, sc_jitter);
731 perfd_stratum(ntp_res.stratum, config.do_stratum, config.stratum_thresholds));
732 } 790 }
733 791
734 if (config.do_truechimers) { 792 mp_subcheck sc_other_info = mp_subcheck_init();
735 if (tresult == STATE_WARNING) { 793 sc_other_info = mp_set_subcheck_default_state(sc_other_info, STATE_OK);
736 xasprintf(&result_line, "%s, truechimers=%i (WARNING)", result_line, 794 if (!ntp_res.syncsource_found) {
737 ntp_res.num_truechimers); 795 xasprintf(&sc_other_info.output, "%s", _("Server not synchronized"));
738 } else if (tresult == STATE_CRITICAL) { 796 mp_add_subcheck_to_check(&overall, sc_other_info);
739 xasprintf(&result_line, "%s, truechimers=%i (CRITICAL)", result_line, 797 } else if (ntp_res.li_alarm) {
740 ntp_res.num_truechimers); 798 xasprintf(&sc_other_info.output, "%s", _("Server has the LI_ALARM bit set"));
741 } else { 799 mp_add_subcheck_to_check(&overall, sc_other_info);
742 xasprintf(&result_line, "%s, truechimers=%i", result_line, ntp_res.num_truechimers);
743 }
744 xasprintf(&perfdata_line, "%s %s", perfdata_line,
745 perfd_truechimers(ntp_res.num_truechimers, config.do_truechimers,
746 config.truechimer_thresholds));
747 } 800 }
748 801
749 printf("%s|%s\n", result_line, perfdata_line); 802 {
803 mp_subcheck sc_offset = mp_subcheck_init();
804 sc_offset = mp_set_subcheck_default_state(sc_offset, STATE_OK);
805 xasprintf(&sc_offset.output, "offset: %.10gs", ntp_res.offset);
806
807 mp_perfdata pd_offset = perfdata_init();
808 pd_offset.value = mp_create_pd_value(ntp_res.offset);
809 pd_offset = mp_pd_set_thresholds(pd_offset, config.offset_thresholds);
810
811 sc_offset = mp_set_subcheck_state(sc_offset, ntp_res.offset_result);
812 }
750 813
751 if (config.server_address != NULL) { 814 if (config.server_address != NULL) {
752 free(config.server_address); 815 free(config.server_address);
753 } 816 }
754 817
755 exit(result); 818 mp_exit(overall);
756} 819}
757 820
758void print_help(void) { 821void print_help(void) {
@@ -791,6 +854,7 @@ void print_help(void) {
791 printf(" %s\n", _("Critical threshold for number of usable time sources (\"truechimers\")")); 854 printf(" %s\n", _("Critical threshold for number of usable time sources (\"truechimers\")"));
792 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 855 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
793 printf(UT_VERBOSE); 856 printf(UT_VERBOSE);
857 printf(UT_OUTPUT_FORMAT);
794 858
795 printf("\n"); 859 printf("\n");
796 printf("%s\n", _("This plugin checks an NTP server independent of any commandline")); 860 printf("%s\n", _("This plugin checks an NTP server independent of any commandline"));