Module: monitoring-plugins Branch: master Commit: 74d61bbf8ab622c22a08b5460475535860f95d91 Author: Lorenz Kästle <[email protected]> Date: Fri Dec 5 12:28:26 2025 +0100 URL: https://www.monitoring-plugins.org/repositories/monitoring-plugins/commit/?id=74d61bbf
check_real: implement modern output --- plugins/check_real.c | 318 ++++++++++++++++++++++++++---------------- plugins/check_real.d/config.h | 23 +-- plugins/check_time.c | 2 + plugins/utils.c | 1 - plugins/utils.h | 2 - 5 files changed, 215 insertions(+), 131 deletions(-) diff --git a/plugins/check_real.c b/plugins/check_real.c index 66d07f8f..15c8a20c 100644 --- a/plugins/check_real.c +++ b/plugins/check_real.c @@ -28,19 +28,21 @@ * *****************************************************************************/ +#include "output.h" +#include "perfdata.h" #include "states.h" #include <stdio.h> -const char *progname = "check_real"; -const char *copyright = "2000-2024"; -const char *email = "[email protected]"; - #include "common.h" #include "netutils.h" +#include "thresholds.h" #include "utils.h" #include "check_real.d/config.h" -#define EXPECT "RTSP/1." -#define URL "" +const char *progname = "check_real"; +const char *copyright = "2000-2024"; +const char *email = "[email protected]"; + +#define URL "" typedef struct { int errorcode; @@ -68,42 +70,68 @@ int main(int argc, char **argv) { const check_real_config config = tmp_config.config; + if (config.output_format_is_set) { + mp_set_format(config.output_format); + } + /* initialize alarm signal handling */ signal(SIGALRM, socket_timeout_alarm_handler); /* set socket timeout */ alarm(socket_timeout); + time_t start_time; time(&start_time); + mp_check overall = mp_check_init(); + mp_subcheck sc_connect = mp_subcheck_init(); + /* try to connect to the host at the given port number */ int socket; if (my_tcp_connect(config.server_address, config.server_port, &socket) != STATE_OK) { - die(STATE_CRITICAL, _("Unable to connect to %s on port %d\n"), config.server_address, - config.server_port); + xasprintf(&sc_connect.output, _("unable to connect to %s on port %d"), + config.server_address, config.server_port); + sc_connect = mp_set_subcheck_state(sc_connect, STATE_CRITICAL); + mp_add_subcheck_to_check(&overall, sc_connect); + mp_exit(overall); } + xasprintf(&sc_connect.output, _("connected to %s on port %d"), config.server_address, + config.server_port); + sc_connect = mp_set_subcheck_state(sc_connect, STATE_OK); + mp_add_subcheck_to_check(&overall, sc_connect); + /* Part I - Server Check */ + mp_subcheck sc_send = mp_subcheck_init(); /* send the OPTIONS request */ char buffer[MAX_INPUT_BUFFER]; sprintf(buffer, "OPTIONS rtsp://%s:%d RTSP/1.0\r\n", config.host_name, config.server_port); ssize_t sent_bytes = send(socket, buffer, strlen(buffer), 0); if (sent_bytes == -1) { - die(STATE_CRITICAL, _("Sending options to %s failed\n"), config.host_name); + xasprintf(&sc_send.output, _("Sending options to %s failed"), config.host_name); + sc_send = mp_set_subcheck_state(sc_send, STATE_CRITICAL); + mp_add_subcheck_to_check(&overall, sc_send); + mp_exit(overall); } /* send the header sync */ sprintf(buffer, "CSeq: 1\r\n"); sent_bytes = send(socket, buffer, strlen(buffer), 0); if (sent_bytes == -1) { - die(STATE_CRITICAL, _("Sending header sync to %s failed\n"), config.host_name); + xasprintf(&sc_send.output, _("Sending header sync to %s failed"), config.host_name); + sc_send = mp_set_subcheck_state(sc_send, STATE_CRITICAL); + mp_add_subcheck_to_check(&overall, sc_send); + mp_exit(overall); } /* send a newline so the server knows we're done with the request */ sprintf(buffer, "\r\n"); sent_bytes = send(socket, buffer, strlen(buffer), 0); if (sent_bytes == -1) { - die(STATE_CRITICAL, _("Sending newline to %s failed\n"), config.host_name); + xasprintf(&sc_send.output, _("Sending newline to %s failed"), config.host_name); + sc_send = mp_set_subcheck_state(sc_send, STATE_CRITICAL); + mp_add_subcheck_to_check(&overall, sc_send); + mp_exit(overall); } /* watch for the REAL connection string */ @@ -111,60 +139,75 @@ int main(int argc, char **argv) { /* return a CRITICAL status if we couldn't read any data */ if (received_bytes == -1) { - die(STATE_CRITICAL, _("No data received from %s\n"), config.host_name); + xasprintf(&sc_send.output, _("No data received from %s"), config.host_name); + sc_send = mp_set_subcheck_state(sc_send, STATE_CRITICAL); + mp_add_subcheck_to_check(&overall, sc_send); + mp_exit(overall); } - mp_state_enum result = STATE_OK; - char *status_line = NULL; - /* make sure we find the response we are looking for */ - if (!strstr(buffer, config.server_expect)) { - if (config.server_port == PORT) { - printf("%s\n", _("Invalid REAL response received from host")); + time_t end_time; + { + mp_subcheck sc_options_request = mp_subcheck_init(); + mp_state_enum options_result = STATE_OK; + /* make sure we find the response we are looking for */ + if (!strstr(buffer, config.server_expect)) { + if (config.server_port == PORT) { + xasprintf(&sc_options_request.output, "invalid REAL response received from host"); + } else { + xasprintf(&sc_options_request.output, + "invalid REAL response received from host on port %d", + config.server_port); + } } else { - printf(_("Invalid REAL response received from host on port %d\n"), config.server_port); - } - } else { - /* else we got the REAL string, so check the return code */ + /* else we got the REAL string, so check the return code */ + time(&end_time); - time(&end_time); + options_result = STATE_OK; - result = STATE_OK; + char *status_line = strtok(buffer, "\n"); + xasprintf(&sc_options_request.output, "status line: %s", status_line); - status_line = strtok(buffer, "\n"); - - if (strstr(status_line, "200")) { - result = STATE_OK; + if (strstr(status_line, "200")) { + options_result = STATE_OK; + } + /* client errors options_result in a warning state */ + else if (strstr(status_line, "400")) { + options_result = STATE_WARNING; + } else if (strstr(status_line, "401")) { + options_result = STATE_WARNING; + } else if (strstr(status_line, "402")) { + options_result = STATE_WARNING; + } else if (strstr(status_line, "403")) { + options_result = STATE_WARNING; + } else if (strstr(status_line, "404")) { + options_result = STATE_WARNING; + } else if (strstr(status_line, "500")) { + /* server errors options_result in a critical state */ + options_result = STATE_CRITICAL; + } else if (strstr(status_line, "501")) { + options_result = STATE_CRITICAL; + } else if (strstr(status_line, "502")) { + options_result = STATE_CRITICAL; + } else if (strstr(status_line, "503")) { + options_result = STATE_CRITICAL; + } else { + options_result = STATE_UNKNOWN; + } } - /* client errors result in a warning state */ - else if (strstr(status_line, "400")) { - result = STATE_WARNING; - } else if (strstr(status_line, "401")) { - result = STATE_WARNING; - } else if (strstr(status_line, "402")) { - result = STATE_WARNING; - } else if (strstr(status_line, "403")) { - result = STATE_WARNING; - } else if (strstr(status_line, "404")) { - result = STATE_WARNING; - } else if (strstr(status_line, "500")) { - /* server errors result in a critical state */ - result = STATE_CRITICAL; - } else if (strstr(status_line, "501")) { - result = STATE_CRITICAL; - } else if (strstr(status_line, "502")) { - result = STATE_CRITICAL; - } else if (strstr(status_line, "503")) { - result = STATE_CRITICAL; - } else { - result = STATE_UNKNOWN; + sc_options_request = mp_set_subcheck_state(sc_options_request, options_result); + mp_add_subcheck_to_check(&overall, sc_options_request); + + if (options_result != STATE_OK) { + // exit here if Setting options already failed + mp_exit(overall); } } /* Part II - Check stream exists and is ok */ - if ((result == STATE_OK) && (config.server_url != NULL)) { - + if (config.server_url != NULL) { /* Part I - Server Check */ + mp_subcheck sc_describe = mp_subcheck_init(); /* send the DESCRIBE request */ sprintf(buffer, "DESCRIBE rtsp://%s:%d%s RTSP/1.0\r\n", config.host_name, @@ -172,98 +215,115 @@ int main(int argc, char **argv) { ssize_t sent_bytes = send(socket, buffer, strlen(buffer), 0); if (sent_bytes == -1) { - die(STATE_CRITICAL, _("Sending DESCRIBE request to %s failed\n"), config.host_name); + sc_describe = mp_set_subcheck_state(sc_describe, STATE_CRITICAL); + xasprintf(&sc_describe.output, "sending DESCRIBE request to %s failed", + config.host_name); + mp_add_subcheck_to_check(&overall, sc_describe); + mp_exit(overall); } /* send the header sync */ sprintf(buffer, "CSeq: 2\r\n"); sent_bytes = send(socket, buffer, strlen(buffer), 0); if (sent_bytes == -1) { - die(STATE_CRITICAL, _("Sending DESCRIBE request to %s failed\n"), config.host_name); + sc_describe = mp_set_subcheck_state(sc_describe, STATE_CRITICAL); + xasprintf(&sc_describe.output, "sending DESCRIBE request to %s failed", + config.host_name); + mp_add_subcheck_to_check(&overall, sc_describe); + mp_exit(overall); } /* send a newline so the server knows we're done with the request */ sprintf(buffer, "\r\n"); sent_bytes = send(socket, buffer, strlen(buffer), 0); if (sent_bytes == -1) { - die(STATE_CRITICAL, _("Sending DESCRIBE request to %s failed\n"), config.host_name); + sc_describe = mp_set_subcheck_state(sc_describe, STATE_CRITICAL); + xasprintf(&sc_describe.output, "sending DESCRIBE request to %s failed", + config.host_name); + mp_add_subcheck_to_check(&overall, sc_describe); + mp_exit(overall); } /* watch for the REAL connection string */ ssize_t recv_bytes = recv(socket, buffer, MAX_INPUT_BUFFER - 1, 0); if (recv_bytes == -1) { /* return a CRITICAL status if we couldn't read any data */ - printf(_("No data received from host\n")); - result = STATE_CRITICAL; + sc_describe = mp_set_subcheck_state(sc_describe, STATE_CRITICAL); + xasprintf(&sc_describe.output, "No data received from host on DESCRIBE request"); + mp_add_subcheck_to_check(&overall, sc_describe); + mp_exit(overall); } else { - buffer[result] = '\0'; /* null terminate received buffer */ + buffer[recv_bytes] = '\0'; /* null terminate received buffer */ /* make sure we find the response we are looking for */ if (!strstr(buffer, config.server_expect)) { if (config.server_port == PORT) { - printf("%s\n", _("Invalid REAL response received from host")); + xasprintf(&sc_describe.output, "invalid REAL response received from host"); } else { - printf(_("Invalid REAL response received from host on port %d\n"), - config.server_port); + xasprintf(&sc_describe.output, + "invalid REAL response received from host on port %d", + config.server_port); } - } else { + sc_describe = mp_set_subcheck_state(sc_describe, STATE_UNKNOWN); + mp_add_subcheck_to_check(&overall, sc_describe); + mp_exit(overall); + } else { /* else we got the REAL string, so check the return code */ time(&end_time); - result = STATE_OK; - - status_line = strtok(buffer, "\n"); + char *status_line = strtok(buffer, "\n"); + xasprintf(&sc_describe.output, "status line: %s", status_line); + mp_state_enum describe_result; if (strstr(status_line, "200")) { - result = STATE_OK; + describe_result = STATE_OK; } - - /* client errors result in a warning state */ + /* client errors describe_result in a warning state */ else if (strstr(status_line, "400")) { - result = STATE_WARNING; + describe_result = STATE_WARNING; } else if (strstr(status_line, "401")) { - result = STATE_WARNING; + describe_result = STATE_WARNING; } else if (strstr(status_line, "402")) { - result = STATE_WARNING; + describe_result = STATE_WARNING; } else if (strstr(status_line, "403")) { - result = STATE_WARNING; + describe_result = STATE_WARNING; } else if (strstr(status_line, "404")) { - result = STATE_WARNING; + describe_result = STATE_WARNING; } - - /* server errors result in a critical state */ + /* server errors describe_result in a critical state */ else if (strstr(status_line, "500")) { - result = STATE_CRITICAL; + describe_result = STATE_CRITICAL; } else if (strstr(status_line, "501")) { - result = STATE_CRITICAL; + describe_result = STATE_CRITICAL; } else if (strstr(status_line, "502")) { - result = STATE_CRITICAL; + describe_result = STATE_CRITICAL; } else if (strstr(status_line, "503")) { - result = STATE_CRITICAL; + describe_result = STATE_CRITICAL; + } else { + describe_result = STATE_UNKNOWN; } - else { - result = STATE_UNKNOWN; - } + sc_describe = mp_set_subcheck_state(sc_describe, describe_result); + mp_add_subcheck_to_check(&overall, sc_describe); } } } /* Return results */ - if (result == STATE_OK) { - if (config.check_critical_time && (end_time - start_time) > config.critical_time) { - result = STATE_CRITICAL; - } else if (config.check_warning_time && (end_time - start_time) > config.warning_time) { - result = STATE_WARNING; - } + mp_subcheck sc_timing = mp_subcheck_init(); + xasprintf(&sc_timing.output, "response time: %lds", end_time - start_time); + sc_timing = mp_set_subcheck_default_state(sc_timing, STATE_OK); - /* Put some HTML in here to create a dynamic link */ - printf(_("REAL %s - %d second response time\n"), state_text(result), - (int)(end_time - start_time)); - } else { - printf("%s\n", status_line); - } + mp_perfdata pd_response_time = perfdata_init(); + pd_response_time = mp_set_pd_value(pd_response_time, (end_time - start_time)); + pd_response_time.label = "response_time"; + pd_response_time.uom = "s"; + pd_response_time = mp_pd_set_thresholds(pd_response_time, config.time_thresholds); + mp_add_perfdata_to_subcheck(&sc_connect, pd_response_time); + sc_timing = mp_set_subcheck_state(sc_timing, mp_get_pd_status(pd_response_time)); + + mp_add_subcheck_to_check(&overall, sc_timing); /* close the connection */ close(socket); @@ -271,18 +331,28 @@ int main(int argc, char **argv) { /* reset the alarm */ alarm(0); - exit(result); + mp_exit(overall); } /* process command-line arguments */ check_real_config_wrapper process_arguments(int argc, char **argv) { - static struct option longopts[] = { - {"hostname", required_argument, 0, 'H'}, {"IPaddress", required_argument, 0, 'I'}, - {"expect", required_argument, 0, 'e'}, {"url", required_argument, 0, 'u'}, - {"port", required_argument, 0, 'p'}, {"critical", required_argument, 0, 'c'}, - {"warning", required_argument, 0, 'w'}, {"timeout", required_argument, 0, 't'}, - {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, - {"help", no_argument, 0, 'h'}, {0, 0, 0, 0}}; + enum { + output_format_index = CHAR_MAX + 1, + }; + + static struct option longopts[] = {{"hostname", required_argument, 0, 'H'}, + {"IPaddress", required_argument, 0, 'I'}, + {"expect", required_argument, 0, 'e'}, + {"url", required_argument, 0, 'u'}, + {"port", required_argument, 0, 'p'}, + {"critical", required_argument, 0, 'c'}, + {"warning", required_argument, 0, 'w'}, + {"timeout", required_argument, 0, 't'}, + {"verbose", no_argument, 0, 'v'}, + {"version", no_argument, 0, 'V'}, + {"help", no_argument, 0, 'h'}, + {"output-format", required_argument, 0, output_format_index}, + {0, 0, 0, 0}}; check_real_config_wrapper result = { .errorcode = OK, @@ -337,21 +407,23 @@ check_real_config_wrapper process_arguments(int argc, char **argv) { } break; case 'w': /* warning time threshold */ - if (is_intnonneg(optarg)) { - result.config.warning_time = atoi(optarg); - result.config.check_warning_time = true; - } else { - usage4(_("Warning time must be a positive integer")); + { + mp_range_parsed critical_range = mp_parse_range_string(optarg); + if (critical_range.error != MP_PARSING_SUCCES) { + die(STATE_UNKNOWN, "failed to parse warning threshold: %s", optarg); } - break; + result.config.time_thresholds = + mp_thresholds_set_warn(result.config.time_thresholds, critical_range.range); + } break; case 'c': /* critical time threshold */ - if (is_intnonneg(optarg)) { - result.config.critical_time = atoi(optarg); - result.config.check_critical_time = true; - } else { - usage4(_("Critical time must be a positive integer")); + { + mp_range_parsed critical_range = mp_parse_range_string(optarg); + if (critical_range.error != MP_PARSING_SUCCES) { + die(STATE_UNKNOWN, "failed to parse critical threshold: %s", optarg); } - break; + result.config.time_thresholds = + mp_thresholds_set_crit(result.config.time_thresholds, critical_range.range); + } break; case 'v': /* verbose */ verbose = true; break; @@ -368,6 +440,18 @@ check_real_config_wrapper process_arguments(int argc, char **argv) { case 'h': /* help */ print_help(); exit(STATE_UNKNOWN); + case output_format_index: { + parsed_output_format parser = mp_parse_output_format(optarg); + if (!parser.parsing_success) { + // TODO List all available formats here, maybe add anothoer usage function + printf("Invalid output format: %s\n", optarg); + exit(STATE_UNKNOWN); + } + + result.config.output_format_is_set = true; + result.config.output_format = parser.output_format; + break; + } case '?': /* usage */ usage5(); } @@ -390,10 +474,6 @@ check_real_config_wrapper process_arguments(int argc, char **argv) { result.config.host_name = strdup(result.config.server_address); } - if (result.config.server_expect == NULL) { - result.config.server_expect = strdup(EXPECT); - } - return result; } @@ -420,7 +500,7 @@ void print_help(void) { printf(" %s\n", "-u, --url=STRING"); printf(" %s\n", _("Connect to this url")); printf(" %s\n", "-e, --expect=STRING"); - printf(_("String to expect in first line of server response (default: %s)\n"), EXPECT); + printf(_("String to expect in first line of server response (default: %s)\n"), default_expect); printf(UT_WARN_CRIT); diff --git a/plugins/check_real.d/config.h b/plugins/check_real.d/config.h index c4663cf9..2d99ad49 100644 --- a/plugins/check_real.d/config.h +++ b/plugins/check_real.d/config.h @@ -1,12 +1,16 @@ #pragma once #include "../../config.h" +#include "output.h" +#include "thresholds.h" #include <stddef.h> enum { PORT = 554 }; +const char *default_expect = "RTSP/1."; + typedef struct { char *server_address; char *host_name; @@ -14,10 +18,11 @@ typedef struct { char *server_url; char *server_expect; - int warning_time; - bool check_warning_time; - int critical_time; - bool check_critical_time; + + mp_thresholds time_thresholds; + + bool output_format_is_set; + mp_output_format output_format; } check_real_config; check_real_config check_real_config_init() { @@ -27,11 +32,11 @@ check_real_config check_real_config_init() { .server_port = PORT, .server_url = NULL, - .server_expect = NULL, - .warning_time = 0, - .check_warning_time = false, - .critical_time = 0, - .check_critical_time = false, + .server_expect = default_expect, + + .time_thresholds = mp_thresholds_init(), + + .output_format_is_set = false, }; return tmp; } diff --git a/plugins/check_time.c b/plugins/check_time.c index fc9ba3f9..99708ad3 100644 --- a/plugins/check_time.c +++ b/plugins/check_time.c @@ -68,6 +68,7 @@ int main(int argc, char **argv) { /* set socket timeout */ alarm(socket_timeout); + time_t start_time; time(&start_time); int socket; @@ -113,6 +114,7 @@ int main(int argc, char **argv) { close(socket); /* reset the alarm */ + time_t end_time; time(&end_time); alarm(0); diff --git a/plugins/utils.c b/plugins/utils.c index 41fe5fcf..dc6f5a85 100644 --- a/plugins/utils.c +++ b/plugins/utils.c @@ -40,7 +40,6 @@ extern const char *progname; #define STRLEN 64 #define TXTBLK 128 -time_t start_time, end_time; void usage(const char *msg) { printf("%s\n", msg); diff --git a/plugins/utils.h b/plugins/utils.h index 1f0e021b..68ff1630 100644 --- a/plugins/utils.h +++ b/plugins/utils.h @@ -32,8 +32,6 @@ suite of plugins. */ void support(void); void print_revision(const char *, const char *); -extern time_t start_time, end_time; - /* Test input types */ bool is_integer(char *);
