diff options
Diffstat (limited to 'plugins')
43 files changed, 1729 insertions, 2541 deletions
diff --git a/plugins/Makefile.am b/plugins/Makefile.am index 1a9399f0..a35f273e 100644 --- a/plugins/Makefile.am +++ b/plugins/Makefile.am | |||
| @@ -33,7 +33,7 @@ MATHLIBS = @MATHLIBS@ | |||
| 33 | #AM_CFLAGS = -Wall | 33 | #AM_CFLAGS = -Wall |
| 34 | 34 | ||
| 35 | libexec_PROGRAMS = check_apt check_cluster check_disk check_dummy check_http check_load \ | 35 | libexec_PROGRAMS = check_apt check_cluster check_disk check_dummy check_http check_load \ |
| 36 | check_mrtg check_mrtgtraf check_ntp check_ntp_peer check_ping \ | 36 | check_mrtg check_mrtgtraf check_ntp_peer check_ping \ |
| 37 | check_real check_smtp check_ssh check_tcp check_time check_ntp_time \ | 37 | check_real check_smtp check_ssh check_tcp check_time check_ntp_time \ |
| 38 | check_ups check_users negate \ | 38 | check_ups check_users negate \ |
| 39 | urlize @EXTRAS@ \ | 39 | urlize @EXTRAS@ \ |
| @@ -44,7 +44,7 @@ check_tcp_programs = check_ftp check_imap check_nntp check_pop \ | |||
| 44 | 44 | ||
| 45 | EXTRA_PROGRAMS = check_mysql check_radius check_pgsql check_hpjd \ | 45 | EXTRA_PROGRAMS = check_mysql check_radius check_pgsql check_hpjd \ |
| 46 | check_swap check_fping check_ldap check_game check_dig \ | 46 | check_swap check_fping check_ldap check_game check_dig \ |
| 47 | check_nagios check_by_ssh check_dns check_nt check_ide_smart \ | 47 | check_nagios check_by_ssh check_dns check_ide_smart \ |
| 48 | check_procs check_mysql_query check_apt check_dbi check_curl \ | 48 | check_procs check_mysql_query check_apt check_dbi check_curl \ |
| 49 | \ | 49 | \ |
| 50 | tests/test_check_swap \ | 50 | tests/test_check_swap \ |
| @@ -66,6 +66,7 @@ EXTRA_DIST = t \ | |||
| 66 | check_hpjd.d \ | 66 | check_hpjd.d \ |
| 67 | check_game.d \ | 67 | check_game.d \ |
| 68 | check_radius.d \ | 68 | check_radius.d \ |
| 69 | check_ide_smart.d \ | ||
| 69 | check_curl.d \ | 70 | check_curl.d \ |
| 70 | check_disk.d \ | 71 | check_disk.d \ |
| 71 | check_time.d \ | 72 | check_time.d \ |
| @@ -76,7 +77,6 @@ EXTRA_DIST = t \ | |||
| 76 | check_tcp.d \ | 77 | check_tcp.d \ |
| 77 | check_real.d \ | 78 | check_real.d \ |
| 78 | check_ssh.d \ | 79 | check_ssh.d \ |
| 79 | check_nt.d \ | ||
| 80 | check_dns.d \ | 80 | check_dns.d \ |
| 81 | check_mrtgtraf.d \ | 81 | check_mrtgtraf.d \ |
| 82 | check_mysql_query.d \ | 82 | check_mysql_query.d \ |
| @@ -157,8 +157,6 @@ check_mysql_query_CFLAGS = $(AM_CFLAGS) $(MYSQLCFLAGS) | |||
| 157 | check_mysql_query_CPPFLAGS = $(AM_CPPFLAGS) $(MYSQLINCLUDE) | 157 | check_mysql_query_CPPFLAGS = $(AM_CPPFLAGS) $(MYSQLINCLUDE) |
| 158 | check_mysql_query_LDADD = $(NETLIBS) $(MYSQLLIBS) | 158 | check_mysql_query_LDADD = $(NETLIBS) $(MYSQLLIBS) |
| 159 | check_nagios_LDADD = $(BASEOBJS) | 159 | check_nagios_LDADD = $(BASEOBJS) |
| 160 | check_nt_LDADD = $(NETLIBS) | ||
| 161 | check_ntp_LDADD = $(NETLIBS) $(MATHLIBS) | ||
| 162 | check_ntp_peer_LDADD = $(NETLIBS) $(MATHLIBS) | 160 | check_ntp_peer_LDADD = $(NETLIBS) $(MATHLIBS) |
| 163 | check_pgsql_LDADD = $(NETLIBS) $(PGLIBS) | 161 | check_pgsql_LDADD = $(NETLIBS) $(PGLIBS) |
| 164 | check_ping_LDADD = $(NETLIBS) | 162 | check_ping_LDADD = $(NETLIBS) |
| @@ -167,7 +165,7 @@ check_radius_LDADD = $(NETLIBS) $(RADIUSLIBS) | |||
| 167 | check_real_LDADD = $(NETLIBS) | 165 | check_real_LDADD = $(NETLIBS) |
| 168 | check_snmp_SOURCES = check_snmp.c check_snmp.d/check_snmp_helpers.c | 166 | check_snmp_SOURCES = check_snmp.c check_snmp.d/check_snmp_helpers.c |
| 169 | check_snmp_LDADD = $(BASEOBJS) | 167 | check_snmp_LDADD = $(BASEOBJS) |
| 170 | check_snmp_LDFLAGS = $(AM_LDFLAGS) `net-snmp-config --libs` | 168 | check_snmp_LDFLAGS = $(AM_LDFLAGS) -lm `net-snmp-config --libs` |
| 171 | check_snmp_CFLAGS = $(AM_CFLAGS) `net-snmp-config --cflags` | 169 | check_snmp_CFLAGS = $(AM_CFLAGS) `net-snmp-config --cflags` |
| 172 | check_smtp_LDADD = $(SSLOBJS) | 170 | check_smtp_LDADD = $(SSLOBJS) |
| 173 | check_ssh_LDADD = $(NETLIBS) | 171 | check_ssh_LDADD = $(NETLIBS) |
diff --git a/plugins/check_by_ssh.c b/plugins/check_by_ssh.c index df8907d9..7ffa0ded 100644 --- a/plugins/check_by_ssh.c +++ b/plugins/check_by_ssh.c | |||
| @@ -98,7 +98,7 @@ int main(int argc, char **argv) { | |||
| 98 | if (child_result.cmd_error_code == 255 && config.unknown_timeout) { | 98 | if (child_result.cmd_error_code == 255 && config.unknown_timeout) { |
| 99 | mp_subcheck sc_ssh_execution = mp_subcheck_init(); | 99 | mp_subcheck sc_ssh_execution = mp_subcheck_init(); |
| 100 | xasprintf(&sc_ssh_execution.output, "SSH connection failed: %s", | 100 | xasprintf(&sc_ssh_execution.output, "SSH connection failed: %s", |
| 101 | child_result.stderr.lines > 0 ? child_result.stderr.line[0] | 101 | child_result.err.lines > 0 ? child_result.err.line[0] |
| 102 | : "(no error output)"); | 102 | : "(no error output)"); |
| 103 | 103 | ||
| 104 | sc_ssh_execution = mp_set_subcheck_state(sc_ssh_execution, STATE_UNKNOWN); | 104 | sc_ssh_execution = mp_set_subcheck_state(sc_ssh_execution, STATE_UNKNOWN); |
| @@ -107,34 +107,34 @@ int main(int argc, char **argv) { | |||
| 107 | } | 107 | } |
| 108 | 108 | ||
| 109 | if (verbose) { | 109 | if (verbose) { |
| 110 | for (size_t i = 0; i < child_result.stdout.lines; i++) { | 110 | for (size_t i = 0; i < child_result.out.lines; i++) { |
| 111 | printf("stdout: %s\n", child_result.stdout.line[i]); | 111 | printf("stdout: %s\n", child_result.out.line[i]); |
| 112 | } | 112 | } |
| 113 | for (size_t i = 0; i < child_result.stderr.lines; i++) { | 113 | for (size_t i = 0; i < child_result.err.lines; i++) { |
| 114 | printf("stderr: %s\n", child_result.stderr.line[i]); | 114 | printf("stderr: %s\n", child_result.err.line[i]); |
| 115 | } | 115 | } |
| 116 | } | 116 | } |
| 117 | 117 | ||
| 118 | size_t skip_stdout = 0; | 118 | size_t skip_stdout = 0; |
| 119 | if (config.skip_stdout) { /* --skip-stdout specified without argument */ | 119 | if (config.skip_stdout) { /* --skip-stdout specified without argument */ |
| 120 | skip_stdout = child_result.stdout.lines; | 120 | skip_stdout = child_result.out.lines; |
| 121 | } else { | 121 | } else { |
| 122 | skip_stdout = config.stdout_lines_to_ignore; | 122 | skip_stdout = config.stdout_lines_to_ignore; |
| 123 | } | 123 | } |
| 124 | 124 | ||
| 125 | size_t skip_stderr = 0; | 125 | size_t skip_stderr = 0; |
| 126 | if (config.skip_stderr) { /* --skip-stderr specified without argument */ | 126 | if (config.skip_stderr) { /* --skip-stderr specified without argument */ |
| 127 | skip_stderr = child_result.stderr.lines; | 127 | skip_stderr = child_result.err.lines; |
| 128 | } else { | 128 | } else { |
| 129 | skip_stderr = config.sterr_lines_to_ignore; | 129 | skip_stderr = config.sterr_lines_to_ignore; |
| 130 | } | 130 | } |
| 131 | 131 | ||
| 132 | /* Allow UNKNOWN or WARNING state for (non-skipped) output found on stderr */ | 132 | /* Allow UNKNOWN or WARNING state for (non-skipped) output found on stderr */ |
| 133 | if (child_result.stderr.lines > skip_stderr && | 133 | if (child_result.err.lines > skip_stderr && |
| 134 | (config.unknown_on_stderr || config.warn_on_stderr)) { | 134 | (config.unknown_on_stderr || config.warn_on_stderr)) { |
| 135 | mp_subcheck sc_stderr = mp_subcheck_init(); | 135 | mp_subcheck sc_stderr = mp_subcheck_init(); |
| 136 | xasprintf(&sc_stderr.output, "remote command execution failed: %s", | 136 | xasprintf(&sc_stderr.output, "remote command execution failed: %s", |
| 137 | child_result.stderr.line[skip_stderr]); | 137 | child_result.err.line[skip_stderr]); |
| 138 | 138 | ||
| 139 | if (config.unknown_on_stderr) { | 139 | if (config.unknown_on_stderr) { |
| 140 | sc_stderr = mp_set_subcheck_state(sc_stderr, STATE_UNKNOWN); | 140 | sc_stderr = mp_set_subcheck_state(sc_stderr, STATE_UNKNOWN); |
| @@ -154,10 +154,10 @@ int main(int argc, char **argv) { | |||
| 154 | mp_subcheck sc_active_check = mp_subcheck_init(); | 154 | mp_subcheck sc_active_check = mp_subcheck_init(); |
| 155 | xasprintf(&sc_active_check.output, "command stdout:"); | 155 | xasprintf(&sc_active_check.output, "command stdout:"); |
| 156 | 156 | ||
| 157 | if (child_result.stdout.lines > skip_stdout) { | 157 | if (child_result.out.lines > skip_stdout) { |
| 158 | for (size_t i = skip_stdout; i < child_result.stdout.lines; i++) { | 158 | for (size_t i = skip_stdout; i < child_result.out.lines; i++) { |
| 159 | xasprintf(&sc_active_check.output, "%s\n%s", sc_active_check.output, | 159 | xasprintf(&sc_active_check.output, "%s\n%s", sc_active_check.output, |
| 160 | child_result.stdout.line[i]); | 160 | child_result.out.line[i]); |
| 161 | } | 161 | } |
| 162 | } else { | 162 | } else { |
| 163 | xasprintf(&sc_active_check.output, "remote command '%s' returned status %d", | 163 | xasprintf(&sc_active_check.output, "remote command '%s' returned status %d", |
| @@ -209,10 +209,10 @@ int main(int argc, char **argv) { | |||
| 209 | char *status_text; | 209 | char *status_text; |
| 210 | int cresult; | 210 | int cresult; |
| 211 | mp_subcheck sc_parse_passive = mp_subcheck_init(); | 211 | mp_subcheck sc_parse_passive = mp_subcheck_init(); |
| 212 | for (size_t i = skip_stdout; i < child_result.stdout.lines; i++) { | 212 | for (size_t i = skip_stdout; i < child_result.out.lines; i++) { |
| 213 | status_text = child_result.stdout.line[i++]; | 213 | status_text = child_result.out.line[i++]; |
| 214 | if (i == child_result.stdout.lines || | 214 | if (i == child_result.out.lines || |
| 215 | strstr(child_result.stdout.line[i], "STATUS CODE: ") == NULL) { | 215 | strstr(child_result.out.line[i], "STATUS CODE: ") == NULL) { |
| 216 | 216 | ||
| 217 | sc_parse_passive = mp_set_subcheck_state(sc_parse_passive, STATE_UNKNOWN); | 217 | sc_parse_passive = mp_set_subcheck_state(sc_parse_passive, STATE_UNKNOWN); |
| 218 | xasprintf(&sc_parse_passive.output, "failed to parse output"); | 218 | xasprintf(&sc_parse_passive.output, "failed to parse output"); |
| @@ -221,7 +221,7 @@ int main(int argc, char **argv) { | |||
| 221 | } | 221 | } |
| 222 | 222 | ||
| 223 | if (config.service[commands] && status_text && | 223 | if (config.service[commands] && status_text && |
| 224 | sscanf(child_result.stdout.line[i], "STATUS CODE: %d", &cresult) == 1) { | 224 | sscanf(child_result.out.line[i], "STATUS CODE: %d", &cresult) == 1) { |
| 225 | fprintf(output_file, "[%d] PROCESS_SERVICE_CHECK_RESULT;%s;%s;%d;%s\n", (int)local_time, | 225 | fprintf(output_file, "[%d] PROCESS_SERVICE_CHECK_RESULT;%s;%s;%d;%s\n", (int)local_time, |
| 226 | config.host_shortname, config.service[commands++], cresult, status_text); | 226 | config.host_shortname, config.service[commands++], cresult, status_text); |
| 227 | } | 227 | } |
diff --git a/plugins/check_curl.c b/plugins/check_curl.c index fc704171..1dec8a2a 100644 --- a/plugins/check_curl.c +++ b/plugins/check_curl.c | |||
| @@ -69,10 +69,6 @@ const char *email = "devel@monitoring-plugins.org"; | |||
| 69 | #include <netdb.h> | 69 | #include <netdb.h> |
| 70 | 70 | ||
| 71 | enum { | 71 | enum { |
| 72 | MAX_IPV4_HOSTLENGTH = 255, | ||
| 73 | }; | ||
| 74 | |||
| 75 | enum { | ||
| 76 | REGS = 2, | 72 | REGS = 2, |
| 77 | }; | 73 | }; |
| 78 | 74 | ||
| @@ -96,16 +92,16 @@ typedef struct { | |||
| 96 | static check_curl_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/); | 92 | static check_curl_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/); |
| 97 | 93 | ||
| 98 | static mp_subcheck check_http(check_curl_config /*config*/, check_curl_working_state workingState, | 94 | static mp_subcheck check_http(check_curl_config /*config*/, check_curl_working_state workingState, |
| 99 | int redir_depth); | 95 | long redir_depth); |
| 100 | 96 | ||
| 101 | typedef struct { | 97 | typedef struct { |
| 102 | int redir_depth; | 98 | long redir_depth; |
| 103 | check_curl_working_state working_state; | 99 | check_curl_working_state working_state; |
| 104 | int error_code; | 100 | int error_code; |
| 105 | check_curl_global_state curl_state; | 101 | check_curl_global_state curl_state; |
| 106 | } redir_wrapper; | 102 | } redir_wrapper; |
| 107 | static redir_wrapper redir(curlhelp_write_curlbuf * /*header_buf*/, check_curl_config /*config*/, | 103 | static redir_wrapper redir(curlhelp_write_curlbuf * /*header_buf*/, check_curl_config /*config*/, |
| 108 | int redir_depth, check_curl_working_state working_state); | 104 | long redir_depth, check_curl_working_state working_state); |
| 109 | 105 | ||
| 110 | static void print_help(void); | 106 | static void print_help(void); |
| 111 | void print_usage(void); | 107 | void print_usage(void); |
| @@ -202,7 +198,7 @@ CURLcode sslctxfun(CURL *curl, SSL_CTX *sslctx, void *parm) { | |||
| 202 | #endif /* HAVE_SSL */ | 198 | #endif /* HAVE_SSL */ |
| 203 | 199 | ||
| 204 | mp_subcheck check_http(const check_curl_config config, check_curl_working_state workingState, | 200 | mp_subcheck check_http(const check_curl_config config, check_curl_working_state workingState, |
| 205 | int redir_depth) { | 201 | long redir_depth) { |
| 206 | 202 | ||
| 207 | // ======================= | 203 | // ======================= |
| 208 | // Initialisation for curl | 204 | // Initialisation for curl |
| @@ -445,19 +441,19 @@ mp_subcheck check_http(const check_curl_config config, check_curl_working_state | |||
| 445 | "CURLINFO_REDIRECT_COUNT"); | 441 | "CURLINFO_REDIRECT_COUNT"); |
| 446 | 442 | ||
| 447 | if (verbose >= 2) { | 443 | if (verbose >= 2) { |
| 448 | printf(_("* curl LIBINFO_REDIRECT_COUNT is %d\n"), redir_depth); | 444 | printf(_("* curl LIBINFO_REDIRECT_COUNT is %ld\n"), redir_depth); |
| 449 | } | 445 | } |
| 450 | 446 | ||
| 451 | mp_subcheck sc_redir_depth = mp_subcheck_init(); | 447 | mp_subcheck sc_redir_depth = mp_subcheck_init(); |
| 452 | if (redir_depth > config.max_depth) { | 448 | if (redir_depth > config.max_depth) { |
| 453 | xasprintf(&sc_redir_depth.output, | 449 | xasprintf(&sc_redir_depth.output, |
| 454 | "maximum redirection depth %d exceeded in libcurl", | 450 | "maximum redirection depth %ld exceeded in libcurl", |
| 455 | config.max_depth); | 451 | config.max_depth); |
| 456 | sc_redir_depth = mp_set_subcheck_state(sc_redir_depth, STATE_CRITICAL); | 452 | sc_redir_depth = mp_set_subcheck_state(sc_redir_depth, STATE_CRITICAL); |
| 457 | mp_add_subcheck_to_subcheck(&sc_result, sc_redir_depth); | 453 | mp_add_subcheck_to_subcheck(&sc_result, sc_redir_depth); |
| 458 | return sc_result; | 454 | return sc_result; |
| 459 | } | 455 | } |
| 460 | xasprintf(&sc_redir_depth.output, "redirection depth %d (of a maximum %d)", | 456 | xasprintf(&sc_redir_depth.output, "redirection depth %ld (of a maximum %ld)", |
| 461 | redir_depth, config.max_depth); | 457 | redir_depth, config.max_depth); |
| 462 | mp_add_subcheck_to_subcheck(&sc_result, sc_redir_depth); | 458 | mp_add_subcheck_to_subcheck(&sc_result, sc_redir_depth); |
| 463 | 459 | ||
| @@ -657,7 +653,7 @@ char *uri_string(const UriTextRangeA range, char *buf, size_t buflen) { | |||
| 657 | } | 653 | } |
| 658 | 654 | ||
| 659 | redir_wrapper redir(curlhelp_write_curlbuf *header_buf, const check_curl_config config, | 655 | redir_wrapper redir(curlhelp_write_curlbuf *header_buf, const check_curl_config config, |
| 660 | int redir_depth, check_curl_working_state working_state) { | 656 | long redir_depth, check_curl_working_state working_state) { |
| 661 | curlhelp_statusline status_line; | 657 | curlhelp_statusline status_line; |
| 662 | struct phr_header headers[255]; | 658 | struct phr_header headers[255]; |
| 663 | size_t msglen; | 659 | size_t msglen; |
| @@ -672,12 +668,17 @@ redir_wrapper redir(curlhelp_write_curlbuf *header_buf, const check_curl_config | |||
| 672 | 668 | ||
| 673 | char *location = get_header_value(headers, nof_headers, "location"); | 669 | char *location = get_header_value(headers, nof_headers, "location"); |
| 674 | 670 | ||
| 671 | if (location == NULL) { | ||
| 672 | // location header not found | ||
| 673 | die(STATE_UNKNOWN, "HTTP UNKNOWN - could not find \"location\" header\n"); | ||
| 674 | } | ||
| 675 | |||
| 675 | if (verbose >= 2) { | 676 | if (verbose >= 2) { |
| 676 | printf(_("* Seen redirect location %s\n"), location); | 677 | printf(_("* Seen redirect location %s\n"), location); |
| 677 | } | 678 | } |
| 678 | 679 | ||
| 679 | if (++redir_depth > config.max_depth) { | 680 | if (++redir_depth > config.max_depth) { |
| 680 | die(STATE_WARNING, _("HTTP WARNING - maximum redirection depth %d exceeded - %s\n"), | 681 | die(STATE_WARNING, _("HTTP WARNING - maximum redirection depth %ld exceeded - %s\n"), |
| 681 | config.max_depth, location); | 682 | config.max_depth, location); |
| 682 | } | 683 | } |
| 683 | 684 | ||
| @@ -760,7 +761,7 @@ redir_wrapper redir(curlhelp_write_curlbuf *header_buf, const check_curl_config | |||
| 760 | } | 761 | } |
| 761 | 762 | ||
| 762 | /* compose new path */ | 763 | /* compose new path */ |
| 763 | /* TODO: handle fragments and query part of URL */ | 764 | /* TODO: handle fragments of URL */ |
| 764 | char *new_url = (char *)calloc(1, DEFAULT_BUFFER_SIZE); | 765 | char *new_url = (char *)calloc(1, DEFAULT_BUFFER_SIZE); |
| 765 | if (uri.pathHead) { | 766 | if (uri.pathHead) { |
| 766 | for (UriPathSegmentA *pathSegment = uri.pathHead; pathSegment; | 767 | for (UriPathSegmentA *pathSegment = uri.pathHead; pathSegment; |
| @@ -771,6 +772,29 @@ redir_wrapper redir(curlhelp_write_curlbuf *header_buf, const check_curl_config | |||
| 771 | } | 772 | } |
| 772 | } | 773 | } |
| 773 | 774 | ||
| 775 | /* missing components have null,null in their UriTextRangeA | ||
| 776 | * add query parameters if they exist. | ||
| 777 | */ | ||
| 778 | if (uri.query.first && uri.query.afterLast) { | ||
| 779 | // Ensure we have space for '?' + query_str + '\0' ahead of time, instead of calling strncat | ||
| 780 | // twice | ||
| 781 | size_t current_len = strlen(new_url); | ||
| 782 | size_t remaining_space = DEFAULT_BUFFER_SIZE - current_len - 1; | ||
| 783 | |||
| 784 | const char *query_str = uri_string(uri.query, buf, DEFAULT_BUFFER_SIZE); | ||
| 785 | size_t query_str_len = strlen(query_str); | ||
| 786 | |||
| 787 | if (remaining_space >= query_str_len + 1) { | ||
| 788 | strcat(new_url, "?"); | ||
| 789 | strcat(new_url, query_str); | ||
| 790 | } else { | ||
| 791 | die(STATE_UNKNOWN, | ||
| 792 | _("HTTP UNKNOWN - No space to add query part of size %zu to the buffer, buffer has " | ||
| 793 | "remaining size %zu"), | ||
| 794 | query_str_len, current_len); | ||
| 795 | } | ||
| 796 | } | ||
| 797 | |||
| 774 | if (working_state.serverPort == new_port && | 798 | if (working_state.serverPort == new_port && |
| 775 | !strncmp(working_state.server_address, new_host, MAX_IPV4_HOSTLENGTH) && | 799 | !strncmp(working_state.server_address, new_host, MAX_IPV4_HOSTLENGTH) && |
| 776 | (working_state.host_name && | 800 | (working_state.host_name && |
| @@ -784,21 +808,21 @@ redir_wrapper redir(curlhelp_write_curlbuf *header_buf, const check_curl_config | |||
| 784 | /* set new values for redirected request */ | 808 | /* set new values for redirected request */ |
| 785 | 809 | ||
| 786 | if (!(config.followsticky & STICKY_HOST)) { | 810 | if (!(config.followsticky & STICKY_HOST)) { |
| 787 | free(working_state.server_address); | 811 | // free(working_state.server_address); |
| 788 | working_state.server_address = strndup(new_host, MAX_IPV4_HOSTLENGTH); | 812 | working_state.server_address = strndup(new_host, MAX_IPV4_HOSTLENGTH); |
| 789 | } | 813 | } |
| 790 | if (!(config.followsticky & STICKY_PORT)) { | 814 | if (!(config.followsticky & STICKY_PORT)) { |
| 791 | working_state.serverPort = (unsigned short)new_port; | 815 | working_state.serverPort = (unsigned short)new_port; |
| 792 | } | 816 | } |
| 793 | 817 | ||
| 794 | free(working_state.host_name); | 818 | // free(working_state.host_name); |
| 795 | working_state.host_name = strndup(new_host, MAX_IPV4_HOSTLENGTH); | 819 | working_state.host_name = strndup(new_host, MAX_IPV4_HOSTLENGTH); |
| 796 | 820 | ||
| 797 | /* reset virtual port */ | 821 | /* reset virtual port */ |
| 798 | working_state.virtualPort = working_state.serverPort; | 822 | working_state.virtualPort = working_state.serverPort; |
| 799 | 823 | ||
| 800 | free(new_host); | 824 | free(new_host); |
| 801 | free(working_state.server_url); | 825 | // free(working_state.server_url); |
| 802 | working_state.server_url = new_url; | 826 | working_state.server_url = new_url; |
| 803 | 827 | ||
| 804 | uriFreeUriMembersA(&uri); | 828 | uriFreeUriMembersA(&uri); |
| @@ -1399,7 +1423,7 @@ check_curl_config_wrapper process_arguments(int argc, char **argv) { | |||
| 1399 | } | 1423 | } |
| 1400 | #endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 54, 0) */ | 1424 | #endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 54, 0) */ |
| 1401 | if (verbose >= 2) { | 1425 | if (verbose >= 2) { |
| 1402 | printf(_("* Set SSL/TLS version to %d\n"), result.config.curl_config.ssl_version); | 1426 | printf(_("* Set SSL/TLS version to %ld\n"), result.config.curl_config.ssl_version); |
| 1403 | } | 1427 | } |
| 1404 | if (!specify_port) { | 1428 | if (!specify_port) { |
| 1405 | result.config.initial_config.serverPort = HTTPS_PORT; | 1429 | result.config.initial_config.serverPort = HTTPS_PORT; |
| @@ -1480,7 +1504,9 @@ void print_help(void) { | |||
| 1480 | printf(" %s\n", _("Append a port to include it in the header (eg: example.com:5000)")); | 1504 | printf(" %s\n", _("Append a port to include it in the header (eg: example.com:5000)")); |
| 1481 | printf(" %s\n", "-I, --IP-address=ADDRESS"); | 1505 | printf(" %s\n", "-I, --IP-address=ADDRESS"); |
| 1482 | printf(" %s\n", | 1506 | printf(" %s\n", |
| 1483 | _("IP address or name (use numeric address if possible to bypass DNS lookup).")); | 1507 | "IP address or name (use numeric address if possible to bypass DNS lookup)."); |
| 1508 | printf(" %s\n", "This overwrites the network address of the target while leaving everything " | ||
| 1509 | "else (HTTP headers) as they are"); | ||
| 1484 | printf(" %s\n", "-p, --port=INTEGER"); | 1510 | printf(" %s\n", "-p, --port=INTEGER"); |
| 1485 | printf(" %s", _("Port number (default: ")); | 1511 | printf(" %s", _("Port number (default: ")); |
| 1486 | printf("%d)\n", HTTP_PORT); | 1512 | printf("%d)\n", HTTP_PORT); |
| @@ -1544,6 +1570,8 @@ void print_help(void) { | |||
| 1544 | printf(" %s\n", _("String to expect in the content")); | 1570 | printf(" %s\n", _("String to expect in the content")); |
| 1545 | printf(" %s\n", "-u, --url=PATH"); | 1571 | printf(" %s\n", "-u, --url=PATH"); |
| 1546 | printf(" %s\n", _("URL to GET or POST (default: /)")); | 1572 | printf(" %s\n", _("URL to GET or POST (default: /)")); |
| 1573 | printf(" %s\n", _("This is the part after the address in a URL, so for " | ||
| 1574 | "\"https://example.com/index.html\" it would be '-u /index.html'")); | ||
| 1547 | printf(" %s\n", "-P, --post=STRING"); | 1575 | printf(" %s\n", "-P, --post=STRING"); |
| 1548 | printf(" %s\n", _("URL decoded http POST data")); | 1576 | printf(" %s\n", _("URL decoded http POST data")); |
| 1549 | printf(" %s\n", | 1577 | printf(" %s\n", |
| @@ -1556,7 +1584,7 @@ void print_help(void) { | |||
| 1556 | printf(" %s\n", _("Warn if document is more than SECONDS old. the number can also be of")); | 1584 | printf(" %s\n", _("Warn if document is more than SECONDS old. the number can also be of")); |
| 1557 | printf(" %s\n", _("the form \"10m\" for minutes, \"10h\" for hours, or \"10d\" for days.")); | 1585 | printf(" %s\n", _("the form \"10m\" for minutes, \"10h\" for hours, or \"10d\" for days.")); |
| 1558 | printf(" %s\n", "-T, --content-type=STRING"); | 1586 | printf(" %s\n", "-T, --content-type=STRING"); |
| 1559 | printf(" %s\n", _("specify Content-Type header media type when POSTing\n")); | 1587 | printf(" %s\n", _("specify Content-Type header media type when POSTing")); |
| 1560 | printf(" %s\n", "-l, --linespan"); | 1588 | printf(" %s\n", "-l, --linespan"); |
| 1561 | printf(" %s\n", _("Allow regex to span newlines (must precede -r or -R)")); | 1589 | printf(" %s\n", _("Allow regex to span newlines (must precede -r or -R)")); |
| 1562 | printf(" %s\n", "-r, --regex, --ereg=STRING"); | 1590 | printf(" %s\n", "-r, --regex, --ereg=STRING"); |
| @@ -1644,6 +1672,8 @@ void print_help(void) { | |||
| 1644 | printf(" %s\n", _("certificate matches the hostname of the server, or if the certificate")); | 1672 | printf(" %s\n", _("certificate matches the hostname of the server, or if the certificate")); |
| 1645 | printf(" %s\n", _("has a valid chain of trust to one of the locally installed CAs.")); | 1673 | printf(" %s\n", _("has a valid chain of trust to one of the locally installed CAs.")); |
| 1646 | printf("\n"); | 1674 | printf("\n"); |
| 1675 | printf(" %s\n", _("To also verify certificates, please set --verify-cert.")); | ||
| 1676 | printf("\n"); | ||
| 1647 | printf("%s\n", _("Examples:")); | 1677 | printf("%s\n", _("Examples:")); |
| 1648 | printf(" %s\n\n", "CHECK CONTENT: check_curl -w 5 -c 10 --ssl -H www.verisign.com"); | 1678 | printf(" %s\n\n", "CHECK CONTENT: check_curl -w 5 -c 10 --ssl -H www.verisign.com"); |
| 1649 | printf(" %s\n", _("When the 'www.verisign.com' server returns its content within 5 seconds,")); | 1679 | printf(" %s\n", _("When the 'www.verisign.com' server returns its content within 5 seconds,")); |
| @@ -1653,16 +1683,18 @@ void print_help(void) { | |||
| 1653 | _("the 5-second threshold, a STATE_WARNING will be returned. When an error occurs,")); | 1683 | _("the 5-second threshold, a STATE_WARNING will be returned. When an error occurs,")); |
| 1654 | printf(" %s\n", _("a STATE_CRITICAL will be returned.")); | 1684 | printf(" %s\n", _("a STATE_CRITICAL will be returned.")); |
| 1655 | printf("\n"); | 1685 | printf("\n"); |
| 1656 | printf(" %s\n\n", "CHECK CERTIFICATE: check_curl -H www.verisign.com -C 14"); | 1686 | printf(" %s\n\n", "CHECK CERTIFICATE: check_curl -H www.verisign.com -C 14 -D"); |
| 1657 | printf(" %s\n", | 1687 | printf(" %s\n", |
| 1658 | _("When the certificate of 'www.verisign.com' is valid for more than 14 days,")); | 1688 | _("When the certificate of 'www.verisign.com' is valid for more than 14 days,")); |
| 1659 | printf(" %s\n", | 1689 | printf(" %s\n", |
| 1660 | _("a STATE_OK is returned. When the certificate is still valid, but for less than")); | 1690 | _("a STATE_OK is returned. When the certificate is still valid, but for less than")); |
| 1661 | printf(" %s\n", | 1691 | printf(" %s\n", |
| 1662 | _("14 days, a STATE_WARNING is returned. A STATE_CRITICAL will be returned when")); | 1692 | _("14 days, a STATE_WARNING is returned. A STATE_CRITICAL will be returned when")); |
| 1663 | printf(" %s\n\n", _("the certificate is expired.")); | 1693 | printf(" %s\n", _("the certificate is expired.")); |
| 1694 | printf("\n"); | ||
| 1695 | printf(" %s\n", _("The -D flag enforces a certificate validation beyond expiration time.")); | ||
| 1664 | printf("\n"); | 1696 | printf("\n"); |
| 1665 | printf(" %s\n\n", "CHECK CERTIFICATE: check_curl -H www.verisign.com -C 30,14"); | 1697 | printf(" %s\n\n", "CHECK CERTIFICATE: check_curl -H www.verisign.com -C 30,14 -D"); |
| 1666 | printf(" %s\n", | 1698 | printf(" %s\n", |
| 1667 | _("When the certificate of 'www.verisign.com' is valid for more than 30 days,")); | 1699 | _("When the certificate of 'www.verisign.com' is valid for more than 30 days,")); |
| 1668 | printf(" %s\n", | 1700 | printf(" %s\n", |
| @@ -1685,7 +1717,8 @@ void print_help(void) { | |||
| 1685 | printf(" %s\n", _("It is recommended to use an environment proxy like:")); | 1717 | printf(" %s\n", _("It is recommended to use an environment proxy like:")); |
| 1686 | printf(" %s\n", | 1718 | printf(" %s\n", |
| 1687 | _("https_proxy=http://192.168.100.35:3128 ./check_curl -H www.verisign.com -S")); | 1719 | _("https_proxy=http://192.168.100.35:3128 ./check_curl -H www.verisign.com -S")); |
| 1688 | printf(" %s\n", _("legacy proxy requests in check_http style still work:")); | 1720 | printf(" %s\n", _("legacy proxy requests in check_http style might still work, but are frowned " |
| 1721 | "upon, so DONT:")); | ||
| 1689 | printf(" %s\n", _("check_curl -I 192.168.100.35 -p 3128 -u https://www.verisign.com/ -S -j " | 1722 | printf(" %s\n", _("check_curl -I 192.168.100.35 -p 3128 -u https://www.verisign.com/ -S -j " |
| 1690 | "CONNECT -H www.verisign.com ")); | 1723 | "CONNECT -H www.verisign.com ")); |
| 1691 | printf(" %s\n", _("all these options are needed: -I <proxy> -p <proxy-port> -u <check-url> " | 1724 | printf(" %s\n", _("all these options are needed: -I <proxy> -p <proxy-port> -u <check-url> " |
diff --git a/plugins/check_curl.d/check_curl_helpers.c b/plugins/check_curl.d/check_curl_helpers.c index d49d8f07..5af00973 100644 --- a/plugins/check_curl.d/check_curl_helpers.c +++ b/plugins/check_curl.d/check_curl_helpers.c | |||
| @@ -19,7 +19,7 @@ bool add_sslctx_verify_fun = false; | |||
| 19 | check_curl_configure_curl_wrapper | 19 | check_curl_configure_curl_wrapper |
| 20 | check_curl_configure_curl(const check_curl_static_curl_config config, | 20 | check_curl_configure_curl(const check_curl_static_curl_config config, |
| 21 | check_curl_working_state working_state, bool check_cert, | 21 | check_curl_working_state working_state, bool check_cert, |
| 22 | bool on_redirect_dependent, int follow_method, int max_depth) { | 22 | bool on_redirect_dependent, int follow_method, long max_depth) { |
| 23 | check_curl_configure_curl_wrapper result = { | 23 | check_curl_configure_curl_wrapper result = { |
| 24 | .errorcode = OK, | 24 | .errorcode = OK, |
| 25 | .curl_state = | 25 | .curl_state = |
| @@ -57,7 +57,7 @@ check_curl_configure_curl(const check_curl_static_curl_config config, | |||
| 57 | result.curl_state.curl_easy_initialized = true; | 57 | result.curl_state.curl_easy_initialized = true; |
| 58 | 58 | ||
| 59 | if (verbose >= 1) { | 59 | if (verbose >= 1) { |
| 60 | handle_curl_option_return_code(curl_easy_setopt(result.curl_state.curl, CURLOPT_VERBOSE, 1), | 60 | handle_curl_option_return_code(curl_easy_setopt(result.curl_state.curl, CURLOPT_VERBOSE, 1L), |
| 61 | "CURLOPT_VERBOSE"); | 61 | "CURLOPT_VERBOSE"); |
| 62 | } | 62 | } |
| 63 | 63 | ||
| @@ -128,8 +128,20 @@ check_curl_configure_curl(const check_curl_static_curl_config config, | |||
| 128 | char dnscache[DEFAULT_BUFFER_SIZE]; | 128 | char dnscache[DEFAULT_BUFFER_SIZE]; |
| 129 | char addrstr[DEFAULT_BUFFER_SIZE / 2]; | 129 | char addrstr[DEFAULT_BUFFER_SIZE / 2]; |
| 130 | if (working_state.use_ssl && working_state.host_name != NULL) { | 130 | if (working_state.use_ssl && working_state.host_name != NULL) { |
| 131 | char *tmp_mod_address; | ||
| 132 | |||
| 133 | /* lookup_host() requires an IPv6 address without the brackets. */ | ||
| 134 | if ((strnlen(working_state.server_address, MAX_IPV4_HOSTLENGTH) > 2) && | ||
| 135 | (working_state.server_address[0] == '[')) { | ||
| 136 | // Duplicate and strip the leading '[' | ||
| 137 | tmp_mod_address = | ||
| 138 | strndup(working_state.server_address + 1, strlen(working_state.server_address) - 2); | ||
| 139 | } else { | ||
| 140 | tmp_mod_address = working_state.server_address; | ||
| 141 | } | ||
| 142 | |||
| 131 | int res; | 143 | int res; |
| 132 | if ((res = lookup_host(working_state.server_address, addrstr, DEFAULT_BUFFER_SIZE / 2, | 144 | if ((res = lookup_host(tmp_mod_address, addrstr, DEFAULT_BUFFER_SIZE / 2, |
| 133 | config.sin_family)) != 0) { | 145 | config.sin_family)) != 0) { |
| 134 | die(STATE_CRITICAL, | 146 | die(STATE_CRITICAL, |
| 135 | _("Unable to lookup IP address for '%s': getaddrinfo returned %d - %s"), | 147 | _("Unable to lookup IP address for '%s': getaddrinfo returned %d - %s"), |
| @@ -202,10 +214,10 @@ check_curl_configure_curl(const check_curl_static_curl_config config, | |||
| 202 | if (working_state.http_method) { | 214 | if (working_state.http_method) { |
| 203 | if (!strcmp(working_state.http_method, "POST")) { | 215 | if (!strcmp(working_state.http_method, "POST")) { |
| 204 | handle_curl_option_return_code( | 216 | handle_curl_option_return_code( |
| 205 | curl_easy_setopt(result.curl_state.curl, CURLOPT_POST, 1), "CURLOPT_POST"); | 217 | curl_easy_setopt(result.curl_state.curl, CURLOPT_POST, 1L), "CURLOPT_POST"); |
| 206 | } else if (!strcmp(working_state.http_method, "PUT")) { | 218 | } else if (!strcmp(working_state.http_method, "PUT")) { |
| 207 | handle_curl_option_return_code( | 219 | handle_curl_option_return_code( |
| 208 | curl_easy_setopt(result.curl_state.curl, CURLOPT_UPLOAD, 1), "CURLOPT_UPLOAD"); | 220 | curl_easy_setopt(result.curl_state.curl, CURLOPT_UPLOAD, 1L), "CURLOPT_UPLOAD"); |
| 209 | } else { | 221 | } else { |
| 210 | handle_curl_option_return_code(curl_easy_setopt(result.curl_state.curl, | 222 | handle_curl_option_return_code(curl_easy_setopt(result.curl_state.curl, |
| 211 | CURLOPT_CUSTOMREQUEST, | 223 | CURLOPT_CUSTOMREQUEST, |
| @@ -288,10 +300,10 @@ check_curl_configure_curl(const check_curl_static_curl_config config, | |||
| 288 | /* per default if we have a CA verify both the peer and the | 300 | /* per default if we have a CA verify both the peer and the |
| 289 | * hostname in the certificate, can be switched off later */ | 301 | * hostname in the certificate, can be switched off later */ |
| 290 | handle_curl_option_return_code( | 302 | handle_curl_option_return_code( |
| 291 | curl_easy_setopt(result.curl_state.curl, CURLOPT_SSL_VERIFYPEER, 1), | 303 | curl_easy_setopt(result.curl_state.curl, CURLOPT_SSL_VERIFYPEER, 1L), |
| 292 | "CURLOPT_SSL_VERIFYPEER"); | 304 | "CURLOPT_SSL_VERIFYPEER"); |
| 293 | handle_curl_option_return_code( | 305 | handle_curl_option_return_code( |
| 294 | curl_easy_setopt(result.curl_state.curl, CURLOPT_SSL_VERIFYHOST, 2), | 306 | curl_easy_setopt(result.curl_state.curl, CURLOPT_SSL_VERIFYHOST, 2L), |
| 295 | "CURLOPT_SSL_VERIFYHOST"); | 307 | "CURLOPT_SSL_VERIFYHOST"); |
| 296 | } else { | 308 | } else { |
| 297 | /* backward-compatible behaviour, be tolerant in checks | 309 | /* backward-compatible behaviour, be tolerant in checks |
| @@ -299,10 +311,10 @@ check_curl_configure_curl(const check_curl_static_curl_config config, | |||
| 299 | * to be less tolerant about ssl verfications | 311 | * to be less tolerant about ssl verfications |
| 300 | */ | 312 | */ |
| 301 | handle_curl_option_return_code( | 313 | handle_curl_option_return_code( |
| 302 | curl_easy_setopt(result.curl_state.curl, CURLOPT_SSL_VERIFYPEER, 0), | 314 | curl_easy_setopt(result.curl_state.curl, CURLOPT_SSL_VERIFYPEER, 0L), |
| 303 | "CURLOPT_SSL_VERIFYPEER"); | 315 | "CURLOPT_SSL_VERIFYPEER"); |
| 304 | handle_curl_option_return_code( | 316 | handle_curl_option_return_code( |
| 305 | curl_easy_setopt(result.curl_state.curl, CURLOPT_SSL_VERIFYHOST, 0), | 317 | curl_easy_setopt(result.curl_state.curl, CURLOPT_SSL_VERIFYHOST, 0L), |
| 306 | "CURLOPT_SSL_VERIFYHOST"); | 318 | "CURLOPT_SSL_VERIFYHOST"); |
| 307 | } | 319 | } |
| 308 | 320 | ||
| @@ -426,7 +438,7 @@ check_curl_configure_curl(const check_curl_static_curl_config config, | |||
| 426 | if (on_redirect_dependent) { | 438 | if (on_redirect_dependent) { |
| 427 | if (follow_method == FOLLOW_LIBCURL) { | 439 | if (follow_method == FOLLOW_LIBCURL) { |
| 428 | handle_curl_option_return_code( | 440 | handle_curl_option_return_code( |
| 429 | curl_easy_setopt(result.curl_state.curl, CURLOPT_FOLLOWLOCATION, 1), | 441 | curl_easy_setopt(result.curl_state.curl, CURLOPT_FOLLOWLOCATION, 1L), |
| 430 | "CURLOPT_FOLLOWLOCATION"); | 442 | "CURLOPT_FOLLOWLOCATION"); |
| 431 | 443 | ||
| 432 | /* default -1 is infinite, not good, could lead to zombie plugins! | 444 | /* default -1 is infinite, not good, could lead to zombie plugins! |
| @@ -462,7 +474,7 @@ check_curl_configure_curl(const check_curl_static_curl_config config, | |||
| 462 | } | 474 | } |
| 463 | /* no-body */ | 475 | /* no-body */ |
| 464 | if (working_state.no_body) { | 476 | if (working_state.no_body) { |
| 465 | handle_curl_option_return_code(curl_easy_setopt(result.curl_state.curl, CURLOPT_NOBODY, 1), | 477 | handle_curl_option_return_code(curl_easy_setopt(result.curl_state.curl, CURLOPT_NOBODY, 1L), |
| 466 | "CURLOPT_NOBODY"); | 478 | "CURLOPT_NOBODY"); |
| 467 | } | 479 | } |
| 468 | 480 | ||
| @@ -784,15 +796,17 @@ mp_subcheck check_document_dates(const curlhelp_write_curlbuf *header_buf, const | |||
| 784 | ((float)last_modified) / (60 * 60 * 24)); | 796 | ((float)last_modified) / (60 * 60 * 24)); |
| 785 | sc_document_dates = mp_set_subcheck_state(sc_document_dates, STATE_CRITICAL); | 797 | sc_document_dates = mp_set_subcheck_state(sc_document_dates, STATE_CRITICAL); |
| 786 | } else { | 798 | } else { |
| 787 | xasprintf(&sc_document_dates.output, _("Last modified %ld:%02ld:%02ld ago"), | 799 | xasprintf(&sc_document_dates.output, _("Last modified %lld:%02d:%02d ago"), |
| 788 | last_modified / (60 * 60), (last_modified / 60) % 60, last_modified % 60); | 800 | (long long)last_modified / (60 * 60), (int)(last_modified / 60) % 60, |
| 801 | (int)last_modified % 60); | ||
| 789 | sc_document_dates = mp_set_subcheck_state(sc_document_dates, STATE_CRITICAL); | 802 | sc_document_dates = mp_set_subcheck_state(sc_document_dates, STATE_CRITICAL); |
| 790 | } | 803 | } |
| 791 | } else { | 804 | } else { |
| 792 | // TODO is this the OK case? | 805 | // TODO is this the OK case? |
| 793 | time_t last_modified = (srv_data - doc_data); | 806 | time_t last_modified = (srv_data - doc_data); |
| 794 | xasprintf(&sc_document_dates.output, _("Last modified %ld:%02ld:%02ld ago"), | 807 | xasprintf(&sc_document_dates.output, _("Last modified %lld:%02d:%02d ago"), |
| 795 | last_modified / (60 * 60), (last_modified / 60) % 60, last_modified % 60); | 808 | (long long)last_modified / (60 * 60), (int)(last_modified / 60) % 60, |
| 809 | (int)last_modified % 60); | ||
| 796 | sc_document_dates = mp_set_subcheck_state(sc_document_dates, STATE_OK); | 810 | sc_document_dates = mp_set_subcheck_state(sc_document_dates, STATE_OK); |
| 797 | } | 811 | } |
| 798 | } | 812 | } |
| @@ -1200,7 +1214,7 @@ mp_subcheck check_curl_certificate_checks(CURL *curl, X509 *cert, int warn_days_ | |||
| 1200 | 1214 | ||
| 1201 | cert_ptr_union cert_ptr = {0}; | 1215 | cert_ptr_union cert_ptr = {0}; |
| 1202 | cert_ptr.to_info = NULL; | 1216 | cert_ptr.to_info = NULL; |
| 1203 | CURLcode res = curl_easy_getinfo(curl, CURLINFO_CERTINFO, &cert_ptr.to_info); | 1217 | CURLcode res = curl_easy_getinfo(curl, CURLINFO_CERTINFO, &cert_ptr.to_certinfo); |
| 1204 | if (!res && cert_ptr.to_info) { | 1218 | if (!res && cert_ptr.to_info) { |
| 1205 | # ifdef USE_OPENSSL | 1219 | # ifdef USE_OPENSSL |
| 1206 | /* We have no OpenSSL in libcurl, but we can use OpenSSL for X509 cert | 1220 | /* We have no OpenSSL in libcurl, but we can use OpenSSL for X509 cert |
diff --git a/plugins/check_curl.d/check_curl_helpers.h b/plugins/check_curl.d/check_curl_helpers.h index 87e45a9d..e77b763b 100644 --- a/plugins/check_curl.d/check_curl_helpers.h +++ b/plugins/check_curl.d/check_curl_helpers.h | |||
| @@ -7,6 +7,10 @@ | |||
| 7 | # include <openssl/opensslv.h> | 7 | # include <openssl/opensslv.h> |
| 8 | #endif | 8 | #endif |
| 9 | 9 | ||
| 10 | enum { | ||
| 11 | MAX_IPV4_HOSTLENGTH = 255, | ||
| 12 | }; | ||
| 13 | |||
| 10 | /* for buffers for header and body */ | 14 | /* for buffers for header and body */ |
| 11 | typedef struct { | 15 | typedef struct { |
| 12 | size_t buflen; | 16 | size_t buflen; |
| @@ -76,7 +80,7 @@ check_curl_configure_curl_wrapper check_curl_configure_curl(check_curl_static_cu | |||
| 76 | check_curl_working_state working_state, | 80 | check_curl_working_state working_state, |
| 77 | bool check_cert, | 81 | bool check_cert, |
| 78 | bool on_redirect_dependent, | 82 | bool on_redirect_dependent, |
| 79 | int follow_method, int max_depth); | 83 | int follow_method, long max_depth); |
| 80 | 84 | ||
| 81 | void handle_curl_option_return_code(CURLcode res, const char *option); | 85 | void handle_curl_option_return_code(CURLcode res, const char *option); |
| 82 | 86 | ||
diff --git a/plugins/check_curl.d/config.h b/plugins/check_curl.d/config.h index f51b2ee9..61067d46 100644 --- a/plugins/check_curl.d/config.h +++ b/plugins/check_curl.d/config.h | |||
| @@ -57,10 +57,10 @@ typedef struct { | |||
| 57 | bool haproxy_protocol; | 57 | bool haproxy_protocol; |
| 58 | long socket_timeout; | 58 | long socket_timeout; |
| 59 | sa_family_t sin_family; | 59 | sa_family_t sin_family; |
| 60 | int curl_http_version; | 60 | long curl_http_version; |
| 61 | char **http_opt_headers; | 61 | char **http_opt_headers; |
| 62 | size_t http_opt_headers_count; | 62 | size_t http_opt_headers_count; |
| 63 | int ssl_version; | 63 | long ssl_version; |
| 64 | char *client_cert; | 64 | char *client_cert; |
| 65 | char *client_privkey; | 65 | char *client_privkey; |
| 66 | char *ca_cert; | 66 | char *ca_cert; |
| @@ -76,7 +76,7 @@ typedef struct { | |||
| 76 | check_curl_working_state initial_config; | 76 | check_curl_working_state initial_config; |
| 77 | 77 | ||
| 78 | check_curl_static_curl_config curl_config; | 78 | check_curl_static_curl_config curl_config; |
| 79 | int max_depth; | 79 | long max_depth; |
| 80 | int followmethod; | 80 | int followmethod; |
| 81 | int followsticky; | 81 | int followsticky; |
| 82 | 82 | ||
diff --git a/plugins/check_dbi.c b/plugins/check_dbi.c index 9bc68eb3..81d92952 100644 --- a/plugins/check_dbi.c +++ b/plugins/check_dbi.c | |||
| @@ -688,6 +688,8 @@ void print_help(void) { | |||
| 688 | 688 | ||
| 689 | printf(UT_VERBOSE); | 689 | printf(UT_VERBOSE); |
| 690 | 690 | ||
| 691 | printf(UT_OUTPUT_FORMAT); | ||
| 692 | |||
| 691 | printf("\n"); | 693 | printf("\n"); |
| 692 | printf(" %s\n", _("A DBI driver (-d option) is required. If the specified metric operates")); | 694 | printf(" %s\n", _("A DBI driver (-d option) is required. If the specified metric operates")); |
| 693 | printf(" %s\n\n", _("on a query, one has to be specified (-q option).")); | 695 | printf(" %s\n\n", _("on a query, one has to be specified (-q option).")); |
diff --git a/plugins/check_dig.c b/plugins/check_dig.c index c27e5f13..9ea19e6a 100644 --- a/plugins/check_dig.c +++ b/plugins/check_dig.c | |||
| @@ -3,7 +3,7 @@ | |||
| 3 | * Monitoring check_dig plugin | 3 | * Monitoring check_dig plugin |
| 4 | * | 4 | * |
| 5 | * License: GPL | 5 | * License: GPL |
| 6 | * Copyright (c) 2002-2024 Monitoring Plugins Development Team | 6 | * Copyright (c) 2002-2025 Monitoring Plugins Development Team |
| 7 | * | 7 | * |
| 8 | * Description: | 8 | * Description: |
| 9 | * | 9 | * |
| @@ -33,9 +33,10 @@ | |||
| 33 | * because on some architectures those strings are in non-writable memory */ | 33 | * because on some architectures those strings are in non-writable memory */ |
| 34 | 34 | ||
| 35 | const char *progname = "check_dig"; | 35 | const char *progname = "check_dig"; |
| 36 | const char *copyright = "2002-2024"; | 36 | const char *copyright = "2002-2025"; |
| 37 | const char *email = "devel@monitoring-plugins.org"; | 37 | const char *email = "devel@monitoring-plugins.org"; |
| 38 | 38 | ||
| 39 | #include <ctype.h> | ||
| 39 | #include "common.h" | 40 | #include "common.h" |
| 40 | #include "netutils.h" | 41 | #include "netutils.h" |
| 41 | #include "utils.h" | 42 | #include "utils.h" |
| @@ -56,6 +57,12 @@ void print_usage(void); | |||
| 56 | 57 | ||
| 57 | static int verbose = 0; | 58 | static int verbose = 0; |
| 58 | 59 | ||
| 60 | /* helpers for flag parsing */ | ||
| 61 | static flag_list parse_flags_line(const char *line); | ||
| 62 | static flag_list split_csv_trim(const char *csv); | ||
| 63 | static bool flag_list_contains(const flag_list *list, const char *needle); | ||
| 64 | static void free_flag_list(flag_list *list); | ||
| 65 | |||
| 59 | int main(int argc, char **argv) { | 66 | int main(int argc, char **argv) { |
| 60 | setlocale(LC_ALL, ""); | 67 | setlocale(LC_ALL, ""); |
| 61 | bindtextdomain(PACKAGE, LOCALEDIR); | 68 | bindtextdomain(PACKAGE, LOCALEDIR); |
| @@ -101,13 +108,35 @@ int main(int argc, char **argv) { | |||
| 101 | output chld_out; | 108 | output chld_out; |
| 102 | output chld_err; | 109 | output chld_err; |
| 103 | char *msg = NULL; | 110 | char *msg = NULL; |
| 111 | flag_list dig_flags = {.items = NULL, .count = 0}; | ||
| 104 | mp_state_enum result = STATE_UNKNOWN; | 112 | mp_state_enum result = STATE_UNKNOWN; |
| 113 | |||
| 105 | /* run the command */ | 114 | /* run the command */ |
| 106 | if (np_runcmd(command_line, &chld_out, &chld_err, 0) != 0) { | 115 | if (np_runcmd(command_line, &chld_out, &chld_err, 0) != 0) { |
| 107 | result = STATE_WARNING; | 116 | result = STATE_WARNING; |
| 108 | msg = (char *)_("dig returned an error status"); | 117 | msg = (char *)_("dig returned an error status"); |
| 109 | } | 118 | } |
| 110 | 119 | ||
| 120 | /* extract ';; flags: ...' from stdout (first occurrence) */ | ||
| 121 | for (size_t i = 0; i < chld_out.lines; i++) { | ||
| 122 | if (strstr(chld_out.line[i], "flags:")) { | ||
| 123 | if (verbose) { | ||
| 124 | printf("Raw flags line: %s\n", chld_out.line[i]); | ||
| 125 | } | ||
| 126 | |||
| 127 | dig_flags = parse_flags_line(chld_out.line[i]); | ||
| 128 | |||
| 129 | if (verbose && dig_flags.count > 0) { | ||
| 130 | printf(_("Parsed flags:")); | ||
| 131 | for (size_t k = 0; k < dig_flags.count; k++) { | ||
| 132 | printf(" %s", dig_flags.items[k]); | ||
| 133 | } | ||
| 134 | printf("\n"); | ||
| 135 | } | ||
| 136 | break; | ||
| 137 | } | ||
| 138 | } | ||
| 139 | |||
| 111 | for (size_t i = 0; i < chld_out.lines; i++) { | 140 | for (size_t i = 0; i < chld_out.lines; i++) { |
| 112 | /* the server is responding, we just got the host name... */ | 141 | /* the server is responding, we just got the host name... */ |
| 113 | if (strstr(chld_out.line[i], ";; ANSWER SECTION:")) { | 142 | if (strstr(chld_out.line[i], ";; ANSWER SECTION:")) { |
| @@ -174,6 +203,44 @@ int main(int argc, char **argv) { | |||
| 174 | result = STATE_WARNING; | 203 | result = STATE_WARNING; |
| 175 | } | 204 | } |
| 176 | 205 | ||
| 206 | /* Optional: evaluate dig flags only if -E/-X were provided */ | ||
| 207 | if ((config.require_flags.count > 0) || (config.forbid_flags.count > 0)) { | ||
| 208 | if (dig_flags.count > 0) { | ||
| 209 | for (size_t r = 0; r < config.require_flags.count; r++) { | ||
| 210 | if (!flag_list_contains(&dig_flags, config.require_flags.items[r])) { | ||
| 211 | result = STATE_CRITICAL; | ||
| 212 | if (!msg) { | ||
| 213 | xasprintf(&msg, _("Missing required DNS flag: %s"), | ||
| 214 | config.require_flags.items[r]); | ||
| 215 | } else { | ||
| 216 | char *newmsg = NULL; | ||
| 217 | xasprintf(&newmsg, _("%s; missing required DNS flag: %s"), msg, | ||
| 218 | config.require_flags.items[r]); | ||
| 219 | msg = newmsg; | ||
| 220 | } | ||
| 221 | } | ||
| 222 | } | ||
| 223 | |||
| 224 | for (size_t r = 0; r < config.forbid_flags.count; r++) { | ||
| 225 | if (flag_list_contains(&dig_flags, config.forbid_flags.items[r])) { | ||
| 226 | result = STATE_CRITICAL; | ||
| 227 | if (!msg) { | ||
| 228 | xasprintf(&msg, _("Forbidden DNS flag present: %s"), | ||
| 229 | config.forbid_flags.items[r]); | ||
| 230 | } else { | ||
| 231 | char *newmsg = NULL; | ||
| 232 | xasprintf(&newmsg, _("%s; forbidden DNS flag present: %s"), msg, | ||
| 233 | config.forbid_flags.items[r]); | ||
| 234 | msg = newmsg; | ||
| 235 | } | ||
| 236 | } | ||
| 237 | } | ||
| 238 | } | ||
| 239 | } | ||
| 240 | |||
| 241 | /* cleanup flags buffer */ | ||
| 242 | free_flag_list(&dig_flags); | ||
| 243 | |||
| 177 | printf("DNS %s - %.3f seconds response time (%s)|%s\n", state_text(result), elapsed_time, | 244 | printf("DNS %s - %.3f seconds response time (%s)|%s\n", state_text(result), elapsed_time, |
| 178 | msg ? msg : _("Probably a non-existent host/domain"), | 245 | msg ? msg : _("Probably a non-existent host/domain"), |
| 179 | fperfdata("time", elapsed_time, "s", (config.warning_interval > UNDEFINED), | 246 | fperfdata("time", elapsed_time, "s", (config.warning_interval > UNDEFINED), |
| @@ -190,6 +257,8 @@ check_dig_config_wrapper process_arguments(int argc, char **argv) { | |||
| 190 | {"critical", required_argument, 0, 'c'}, | 257 | {"critical", required_argument, 0, 'c'}, |
| 191 | {"timeout", required_argument, 0, 't'}, | 258 | {"timeout", required_argument, 0, 't'}, |
| 192 | {"dig-arguments", required_argument, 0, 'A'}, | 259 | {"dig-arguments", required_argument, 0, 'A'}, |
| 260 | {"require-flags", required_argument, 0, 'E'}, | ||
| 261 | {"forbid-flags", required_argument, 0, 'X'}, | ||
| 193 | {"verbose", no_argument, 0, 'v'}, | 262 | {"verbose", no_argument, 0, 'v'}, |
| 194 | {"version", no_argument, 0, 'V'}, | 263 | {"version", no_argument, 0, 'V'}, |
| 195 | {"help", no_argument, 0, 'h'}, | 264 | {"help", no_argument, 0, 'h'}, |
| @@ -212,7 +281,8 @@ check_dig_config_wrapper process_arguments(int argc, char **argv) { | |||
| 212 | 281 | ||
| 213 | int option = 0; | 282 | int option = 0; |
| 214 | while (true) { | 283 | while (true) { |
| 215 | int option_index = getopt_long(argc, argv, "hVvt:l:H:w:c:T:p:a:A:46", longopts, &option); | 284 | int option_index = |
| 285 | getopt_long(argc, argv, "hVvt:l:H:w:c:T:p:a:A:E:X:46", longopts, &option); | ||
| 216 | 286 | ||
| 217 | if (option_index == -1 || option_index == EOF) { | 287 | if (option_index == -1 || option_index == EOF) { |
| 218 | break; | 288 | break; |
| @@ -263,6 +333,12 @@ check_dig_config_wrapper process_arguments(int argc, char **argv) { | |||
| 263 | case 'A': /* dig arguments */ | 333 | case 'A': /* dig arguments */ |
| 264 | result.config.dig_args = strdup(optarg); | 334 | result.config.dig_args = strdup(optarg); |
| 265 | break; | 335 | break; |
| 336 | case 'E': /* require flags */ | ||
| 337 | result.config.require_flags = split_csv_trim(optarg); | ||
| 338 | break; | ||
| 339 | case 'X': /* forbid flags */ | ||
| 340 | result.config.forbid_flags = split_csv_trim(optarg); | ||
| 341 | break; | ||
| 266 | case 'v': /* verbose */ | 342 | case 'v': /* verbose */ |
| 267 | verbose++; | 343 | verbose++; |
| 268 | break; | 344 | break; |
| @@ -343,6 +419,10 @@ void print_help(void) { | |||
| 343 | printf(" %s\n", _("was in -l")); | 419 | printf(" %s\n", _("was in -l")); |
| 344 | printf(" %s\n", "-A, --dig-arguments=STRING"); | 420 | printf(" %s\n", "-A, --dig-arguments=STRING"); |
| 345 | printf(" %s\n", _("Pass STRING as argument(s) to dig")); | 421 | printf(" %s\n", _("Pass STRING as argument(s) to dig")); |
| 422 | printf(" %s\n", "-E, --require-flags=LIST"); | ||
| 423 | printf(" %s\n", _("Comma-separated dig flags that must be present (e.g. 'aa,qr')")); | ||
| 424 | printf(" %s\n", "-X, --forbid-flags=LIST"); | ||
| 425 | printf(" %s\n", _("Comma-separated dig flags that must NOT be present")); | ||
| 346 | printf(UT_WARN_CRIT); | 426 | printf(UT_WARN_CRIT); |
| 347 | printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); | 427 | printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); |
| 348 | printf(UT_VERBOSE); | 428 | printf(UT_VERBOSE); |
| @@ -359,5 +439,185 @@ void print_usage(void) { | |||
| 359 | printf("%s\n", _("Usage:")); | 439 | printf("%s\n", _("Usage:")); |
| 360 | printf("%s -l <query_address> [-H <host>] [-p <server port>]\n", progname); | 440 | printf("%s -l <query_address> [-H <host>] [-p <server port>]\n", progname); |
| 361 | printf(" [-T <query type>] [-w <warning interval>] [-c <critical interval>]\n"); | 441 | printf(" [-T <query type>] [-w <warning interval>] [-c <critical interval>]\n"); |
| 362 | printf(" [-t <timeout>] [-a <expected answer address>] [-v]\n"); | 442 | printf(" [-t <timeout>] [-a <expected answer address>] [-E <flags>] [-X <flags>] [-v]\n"); |
| 443 | } | ||
| 444 | |||
| 445 | /* helpers */ | ||
| 446 | |||
| 447 | /** | ||
| 448 | * parse_flags_line - Parse a dig output line and extract DNS header flags. | ||
| 449 | * | ||
| 450 | * Input: | ||
| 451 | * line - NUL terminated dig output line, e.g. ";; flags: qr rd ra; ..." | ||
| 452 | * | ||
| 453 | * Returns: | ||
| 454 | * flag_list where: | ||
| 455 | * - items: array of NUL terminated flag strings (heap allocated) | ||
| 456 | * - count: number of entries in items | ||
| 457 | * On parse failure or if no flags were found, count is 0 and items is NULL. | ||
| 458 | */ | ||
| 459 | static flag_list parse_flags_line(const char *line) { | ||
| 460 | flag_list result = {.items = NULL, .count = 0}; | ||
| 461 | |||
| 462 | if (!line) { | ||
| 463 | return result; | ||
| 464 | } | ||
| 465 | |||
| 466 | /* Locate start of DNS header flags in dig output */ | ||
| 467 | const char *p = strstr(line, "flags:"); | ||
| 468 | if (!p) { | ||
| 469 | return result; | ||
| 470 | } | ||
| 471 | p += 6; /* skip literal "flags:" */ | ||
| 472 | |||
| 473 | /* Skip whitespace after "flags:" */ | ||
| 474 | while (*p && isspace((unsigned char)*p)) { | ||
| 475 | p++; | ||
| 476 | } | ||
| 477 | |||
| 478 | /* Flags are terminated by the next semicolon e.g. "qr rd ra;" */ | ||
| 479 | const char *q = strchr(p, ';'); | ||
| 480 | if (!q) { | ||
| 481 | return result; | ||
| 482 | } | ||
| 483 | |||
| 484 | /* Extract substring containing the flag block */ | ||
| 485 | size_t len = (size_t)(q - p); | ||
| 486 | if (len == 0) { | ||
| 487 | return result; | ||
| 488 | } | ||
| 489 | |||
| 490 | char *buf = (char *)malloc(len + 1); | ||
| 491 | if (!buf) { | ||
| 492 | return result; | ||
| 493 | } | ||
| 494 | memcpy(buf, p, len); | ||
| 495 | buf[len] = '\0'; | ||
| 496 | |||
| 497 | /* Tokenize flags separated by whitespace */ | ||
| 498 | char **arr = NULL; | ||
| 499 | size_t cnt = 0; | ||
| 500 | char *saveptr = NULL; | ||
| 501 | char *tok = strtok_r(buf, " \t", &saveptr); | ||
| 502 | |||
| 503 | while (tok) { | ||
| 504 | /* Expand array for the next flag token */ | ||
| 505 | char **tmp = (char **)realloc(arr, (cnt + 1) * sizeof(char *)); | ||
| 506 | if (!tmp) { | ||
| 507 | /* On allocation failure keep what we have and return it */ | ||
| 508 | break; | ||
| 509 | } | ||
| 510 | arr = tmp; | ||
| 511 | arr[cnt++] = strdup(tok); | ||
| 512 | tok = strtok_r(NULL, " \t", &saveptr); | ||
| 513 | } | ||
| 514 | |||
| 515 | free(buf); | ||
| 516 | |||
| 517 | result.items = arr; | ||
| 518 | result.count = cnt; | ||
| 519 | return result; | ||
| 520 | } | ||
| 521 | |||
| 522 | /** | ||
| 523 | * split_csv_trim - Split a comma separated string into trimmed tokens. | ||
| 524 | * | ||
| 525 | * Input: | ||
| 526 | * csv - NUL terminated string, e.g. "aa, qr , rd" | ||
| 527 | * | ||
| 528 | * Returns: | ||
| 529 | * flag_list where: | ||
| 530 | * - items: array of NUL terminated tokens (heap allocated, whitespace trimmed) | ||
| 531 | * - count: number of tokens | ||
| 532 | * On empty input, count is 0 and items is NULL | ||
| 533 | */ | ||
| 534 | static flag_list split_csv_trim(const char *csv) { | ||
| 535 | flag_list result = {.items = NULL, .count = 0}; | ||
| 536 | |||
| 537 | if (!csv || !*csv) { | ||
| 538 | return result; | ||
| 539 | } | ||
| 540 | |||
| 541 | char *tmp = strdup(csv); | ||
| 542 | if (!tmp) { | ||
| 543 | return result; | ||
| 544 | } | ||
| 545 | |||
| 546 | char *s = tmp; | ||
| 547 | char *token = NULL; | ||
| 548 | |||
| 549 | /* Split CSV by commas, trimming whitespace on each token */ | ||
| 550 | while ((token = strsep(&s, ",")) != NULL) { | ||
| 551 | /* trim leading whitespace */ | ||
| 552 | while (*token && isspace((unsigned char)*token)) { | ||
| 553 | token++; | ||
| 554 | } | ||
| 555 | |||
| 556 | /* trim trailing whitespace */ | ||
| 557 | char *end = token + strlen(token); | ||
| 558 | while (end > token && isspace((unsigned char)end[-1])) { | ||
| 559 | *--end = '\0'; | ||
| 560 | } | ||
| 561 | |||
| 562 | if (*token) { | ||
| 563 | /* Expand the items array and append the token */ | ||
| 564 | char **arr = (char **)realloc(result.items, (result.count + 1) * sizeof(char *)); | ||
| 565 | if (!arr) { | ||
| 566 | /* Allocation failed, stop and return what we have */ | ||
| 567 | break; | ||
| 568 | } | ||
| 569 | result.items = arr; | ||
| 570 | result.items[result.count++] = strdup(token); | ||
| 571 | } | ||
| 572 | } | ||
| 573 | |||
| 574 | free(tmp); | ||
| 575 | return result; | ||
| 576 | } | ||
| 577 | |||
| 578 | /** | ||
| 579 | * flag_list_contains - Case-insensitive membership test in a flag_list. | ||
| 580 | * | ||
| 581 | * Input: | ||
| 582 | * list - pointer to a flag_list | ||
| 583 | * needle - NUL terminated string to search for | ||
| 584 | * | ||
| 585 | * Returns: | ||
| 586 | * true if needle is contained in list (strcasecmp) | ||
| 587 | * false otherwise | ||
| 588 | */ | ||
| 589 | static bool flag_list_contains(const flag_list *list, const char *needle) { | ||
| 590 | if (!list || !needle || !*needle) { | ||
| 591 | return false; | ||
| 592 | } | ||
| 593 | |||
| 594 | for (size_t i = 0; i < list->count; i++) { | ||
| 595 | if (strcasecmp(list->items[i], needle) == 0) { | ||
| 596 | return true; | ||
| 597 | } | ||
| 598 | } | ||
| 599 | return false; | ||
| 600 | } | ||
| 601 | |||
| 602 | /** | ||
| 603 | * free_flag_list - Release all heap allocations held by a flag_list. | ||
| 604 | * | ||
| 605 | * Input: | ||
| 606 | * list - pointer to a flag_list whose items were allocated by | ||
| 607 | * parse_flags_line() or split_csv_trim(). | ||
| 608 | * | ||
| 609 | * After this call list->items is NULL and list->count is 0. | ||
| 610 | */ | ||
| 611 | static void free_flag_list(flag_list *list) { | ||
| 612 | if (!list || !list->items) { | ||
| 613 | return; | ||
| 614 | } | ||
| 615 | |||
| 616 | for (size_t i = 0; i < list->count; i++) { | ||
| 617 | free(list->items[i]); | ||
| 618 | } | ||
| 619 | free(list->items); | ||
| 620 | |||
| 621 | list->items = NULL; | ||
| 622 | list->count = 0; | ||
| 363 | } | 623 | } |
diff --git a/plugins/check_dig.d/config.h b/plugins/check_dig.d/config.h index a570b633..dd1f58b5 100644 --- a/plugins/check_dig.d/config.h +++ b/plugins/check_dig.d/config.h | |||
| @@ -8,6 +8,11 @@ | |||
| 8 | #define DEFAULT_TRIES 2 | 8 | #define DEFAULT_TRIES 2 |
| 9 | 9 | ||
| 10 | typedef struct { | 10 | typedef struct { |
| 11 | char **items; | ||
| 12 | size_t count; | ||
| 13 | } flag_list; | ||
| 14 | |||
| 15 | typedef struct { | ||
| 11 | char *query_address; | 16 | char *query_address; |
| 12 | char *record_type; | 17 | char *record_type; |
| 13 | char *expected_address; | 18 | char *expected_address; |
| @@ -19,6 +24,8 @@ typedef struct { | |||
| 19 | 24 | ||
| 20 | double warning_interval; | 25 | double warning_interval; |
| 21 | double critical_interval; | 26 | double critical_interval; |
| 27 | flag_list require_flags; | ||
| 28 | flag_list forbid_flags; | ||
| 22 | } check_dig_config; | 29 | } check_dig_config; |
| 23 | 30 | ||
| 24 | check_dig_config check_dig_config_init() { | 31 | check_dig_config check_dig_config_init() { |
| @@ -34,7 +41,8 @@ check_dig_config check_dig_config_init() { | |||
| 34 | 41 | ||
| 35 | .warning_interval = UNDEFINED, | 42 | .warning_interval = UNDEFINED, |
| 36 | .critical_interval = UNDEFINED, | 43 | .critical_interval = UNDEFINED, |
| 37 | 44 | .require_flags = {.count = 0, .items = NULL}, | |
| 45 | .forbid_flags = {.count = 0, .items = NULL}, | ||
| 38 | }; | 46 | }; |
| 39 | return tmp; | 47 | return tmp; |
| 40 | } | 48 | } |
diff --git a/plugins/check_disk.c b/plugins/check_disk.c index d42b5486..e1a2baff 100644 --- a/plugins/check_disk.c +++ b/plugins/check_disk.c | |||
| @@ -1262,6 +1262,10 @@ mp_subcheck evaluate_filesystem(measurement_unit measurement_unit, bool display_ | |||
| 1262 | double free_inode_percentage = | 1262 | double free_inode_percentage = |
| 1263 | calculate_percent(measurement_unit.inodes_free, measurement_unit.inodes_total); | 1263 | calculate_percent(measurement_unit.inodes_free, measurement_unit.inodes_total); |
| 1264 | 1264 | ||
| 1265 | mp_perfdata inode_percentage_pd = perfdata_init(); | ||
| 1266 | inode_percentage_pd = mp_set_pd_value(inode_percentage_pd, free_inode_percentage); | ||
| 1267 | inode_percentage_pd = mp_pd_set_thresholds(inode_percentage_pd, measurement_unit.freeinodes_percent_thresholds); | ||
| 1268 | |||
| 1265 | if (verbose > 0) { | 1269 | if (verbose > 0) { |
| 1266 | printf("free inode percentage computed: %g\n", free_inode_percentage); | 1270 | printf("free inode percentage computed: %g\n", free_inode_percentage); |
| 1267 | } | 1271 | } |
| @@ -1293,7 +1297,7 @@ mp_subcheck evaluate_filesystem(measurement_unit measurement_unit, bool display_ | |||
| 1293 | inodes_pd = mp_pd_set_thresholds(inodes_pd, absolut_inode_thresholds); | 1297 | inodes_pd = mp_pd_set_thresholds(inodes_pd, absolut_inode_thresholds); |
| 1294 | 1298 | ||
| 1295 | freeindodes_percent_sc = | 1299 | freeindodes_percent_sc = |
| 1296 | mp_set_subcheck_state(freeindodes_percent_sc, mp_get_pd_status(inodes_pd)); | 1300 | mp_set_subcheck_state(freeindodes_percent_sc, mp_get_pd_status(inode_percentage_pd)); |
| 1297 | if (display_inodes_perfdata) { | 1301 | if (display_inodes_perfdata) { |
| 1298 | mp_add_perfdata_to_subcheck(&freeindodes_percent_sc, inodes_pd); | 1302 | mp_add_perfdata_to_subcheck(&freeindodes_percent_sc, inodes_pd); |
| 1299 | } | 1303 | } |
diff --git a/plugins/check_http.c b/plugins/check_http.c index d264b95d..d2f080c7 100644 --- a/plugins/check_http.c +++ b/plugins/check_http.c | |||
| @@ -1036,7 +1036,7 @@ int check_http(void) { | |||
| 1036 | printf("SSL initialized\n"); | 1036 | printf("SSL initialized\n"); |
| 1037 | } | 1037 | } |
| 1038 | if (result != STATE_OK) { | 1038 | if (result != STATE_OK) { |
| 1039 | die(STATE_CRITICAL, NULL); | 1039 | die(STATE_CRITICAL, _("HTTP CRITICAL - SSL error\n")); |
| 1040 | } | 1040 | } |
| 1041 | microsec_ssl = deltime(tv_temp); | 1041 | microsec_ssl = deltime(tv_temp); |
| 1042 | elapsed_time_ssl = (double)microsec_ssl / 1.0e6; | 1042 | elapsed_time_ssl = (double)microsec_ssl / 1.0e6; |
diff --git a/plugins/check_ide_smart.c b/plugins/check_ide_smart.c index 16fe3d01..c1325cf9 100644 --- a/plugins/check_ide_smart.c +++ b/plugins/check_ide_smart.c | |||
| @@ -39,6 +39,8 @@ const char *email = "devel@monitoring-plugins.org"; | |||
| 39 | 39 | ||
| 40 | #include "common.h" | 40 | #include "common.h" |
| 41 | #include "utils.h" | 41 | #include "utils.h" |
| 42 | #include "check_ide_smart.d/config.h" | ||
| 43 | #include "states.h" | ||
| 42 | 44 | ||
| 43 | static void print_help(void); | 45 | static void print_help(void); |
| 44 | void print_usage(void); | 46 | void print_usage(void); |
| @@ -46,6 +48,7 @@ void print_usage(void); | |||
| 46 | #include <sys/stat.h> | 48 | #include <sys/stat.h> |
| 47 | #include <sys/ioctl.h> | 49 | #include <sys/ioctl.h> |
| 48 | #include <fcntl.h> | 50 | #include <fcntl.h> |
| 51 | |||
| 49 | #ifdef __linux__ | 52 | #ifdef __linux__ |
| 50 | # include <linux/hdreg.h> | 53 | # include <linux/hdreg.h> |
| 51 | # include <linux/types.h> | 54 | # include <linux/types.h> |
| @@ -77,30 +80,30 @@ void print_usage(void); | |||
| 77 | #define OPERATIONAL 0 | 80 | #define OPERATIONAL 0 |
| 78 | #define UNKNOWN -1 | 81 | #define UNKNOWN -1 |
| 79 | 82 | ||
| 80 | typedef struct threshold_s { | 83 | typedef struct { |
| 81 | uint8_t id; | 84 | uint8_t id; |
| 82 | uint8_t threshold; | 85 | uint8_t threshold; |
| 83 | uint8_t reserved[10]; | 86 | uint8_t reserved[10]; |
| 84 | } __attribute__((packed)) threshold_t; | 87 | } __attribute__((packed)) smart_threshold; |
| 85 | 88 | ||
| 86 | typedef struct thresholds_s { | 89 | typedef struct { |
| 87 | uint16_t revision; | 90 | uint16_t revision; |
| 88 | threshold_t thresholds[NR_ATTRIBUTES]; | 91 | smart_threshold thresholds[NR_ATTRIBUTES]; |
| 89 | uint8_t reserved[18]; | 92 | uint8_t reserved[18]; |
| 90 | uint8_t vendor[131]; | 93 | uint8_t vendor[131]; |
| 91 | uint8_t checksum; | 94 | uint8_t checksum; |
| 92 | } __attribute__((packed)) thresholds_t; | 95 | } __attribute__((packed)) smart_thresholds; |
| 93 | 96 | ||
| 94 | typedef struct value_s { | 97 | typedef struct { |
| 95 | uint8_t id; | 98 | uint8_t id; |
| 96 | uint16_t status; | 99 | uint16_t status; |
| 97 | uint8_t value; | 100 | uint8_t value; |
| 98 | uint8_t vendor[8]; | 101 | uint8_t vendor[8]; |
| 99 | } __attribute__((packed)) value_t; | 102 | } __attribute__((packed)) smart_value; |
| 100 | 103 | ||
| 101 | typedef struct values_s { | 104 | typedef struct { |
| 102 | uint16_t revision; | 105 | uint16_t revision; |
| 103 | value_t values[NR_ATTRIBUTES]; | 106 | smart_value values[NR_ATTRIBUTES]; |
| 104 | uint8_t offline_status; | 107 | uint8_t offline_status; |
| 105 | uint8_t vendor1; | 108 | uint8_t vendor1; |
| 106 | uint16_t offline_timeout; | 109 | uint16_t offline_timeout; |
| @@ -110,7 +113,7 @@ typedef struct values_s { | |||
| 110 | uint8_t reserved[16]; | 113 | uint8_t reserved[16]; |
| 111 | uint8_t vendor[125]; | 114 | uint8_t vendor[125]; |
| 112 | uint8_t checksum; | 115 | uint8_t checksum; |
| 113 | } __attribute__((packed)) values_t; | 116 | } __attribute__((packed)) smart_values; |
| 114 | 117 | ||
| 115 | static struct { | 118 | static struct { |
| 116 | uint8_t value; | 119 | uint8_t value; |
| @@ -133,25 +136,20 @@ enum SmartCommand { | |||
| 133 | SMART_CMD_AUTO_OFFLINE | 136 | SMART_CMD_AUTO_OFFLINE |
| 134 | }; | 137 | }; |
| 135 | 138 | ||
| 136 | static char *get_offline_text(int); | 139 | static char *get_offline_text(int /*status*/); |
| 137 | static int smart_read_values(int, values_t *); | 140 | static int smart_read_values(int /*fd*/, smart_values * /*values*/); |
| 138 | static int nagios(values_t *, thresholds_t *); | 141 | static mp_state_enum compare_values_and_thresholds(smart_values * /*p*/, smart_thresholds * /*t*/); |
| 139 | static void print_value(value_t *, threshold_t *); | 142 | static void print_value(smart_value * /*p*/, smart_threshold * /*t*/); |
| 140 | static void print_values(values_t *, thresholds_t *); | 143 | static void print_values(smart_values * /*p*/, smart_thresholds * /*t*/); |
| 141 | static int smart_cmd_simple(int, enum SmartCommand, uint8_t, bool); | 144 | static mp_state_enum smart_cmd_simple(int /*fd*/, enum SmartCommand /*command*/, uint8_t /*val0*/, bool /*show_error*/); |
| 142 | static int smart_read_thresholds(int, thresholds_t *); | 145 | static int smart_read_thresholds(int /*fd*/, smart_thresholds * /*thresholds*/); |
| 143 | static bool verbose = false; | 146 | static int verbose = 0; |
| 144 | 147 | ||
| 145 | int main(int argc, char *argv[]) { | 148 | typedef struct { |
| 146 | char *device = NULL; | 149 | int errorcode; |
| 147 | int o; | 150 | check_ide_smart_config config; |
| 148 | int longindex; | 151 | } check_ide_smart_config_wrapper; |
| 149 | int retval = 0; | 152 | static check_ide_smart_config_wrapper process_arguments(int argc, char **argv) { |
| 150 | |||
| 151 | thresholds_t thresholds; | ||
| 152 | values_t values; | ||
| 153 | int fd; | ||
| 154 | |||
| 155 | static struct option longopts[] = {{"device", required_argument, 0, 'd'}, | 153 | static struct option longopts[] = {{"device", required_argument, 0, 'd'}, |
| 156 | {"immediate", no_argument, 0, 'i'}, | 154 | {"immediate", no_argument, 0, 'i'}, |
| 157 | {"quiet-check", no_argument, 0, 'q'}, | 155 | {"quiet-check", no_argument, 0, 'q'}, |
| @@ -162,24 +160,22 @@ int main(int argc, char *argv[]) { | |||
| 162 | {"version", no_argument, 0, 'V'}, | 160 | {"version", no_argument, 0, 'V'}, |
| 163 | {0, 0, 0, 0}}; | 161 | {0, 0, 0, 0}}; |
| 164 | 162 | ||
| 165 | /* Parse extra opts if any */ | 163 | check_ide_smart_config_wrapper result = { |
| 166 | argv = np_extra_opts(&argc, argv, progname); | 164 | .errorcode = OK, |
| 167 | 165 | .config = check_ide_smart_init(), | |
| 168 | setlocale(LC_ALL, ""); | 166 | }; |
| 169 | bindtextdomain(PACKAGE, LOCALEDIR); | ||
| 170 | textdomain(PACKAGE); | ||
| 171 | 167 | ||
| 172 | while (true) { | 168 | while (true) { |
| 169 | int longindex = 0; | ||
| 170 | int option_index = getopt_long(argc, argv, "+d:iq10nhVv", longopts, &longindex); | ||
| 173 | 171 | ||
| 174 | o = getopt_long(argc, argv, "+d:iq10nhVv", longopts, &longindex); | 172 | if (option_index == -1 || option_index == EOF || option_index == 1) { |
| 175 | |||
| 176 | if (o == -1 || o == EOF || o == 1) { | ||
| 177 | break; | 173 | break; |
| 178 | } | 174 | } |
| 179 | 175 | ||
| 180 | switch (o) { | 176 | switch (option_index) { |
| 181 | case 'd': | 177 | case 'd': |
| 182 | device = optarg; | 178 | result.config.device = optarg; |
| 183 | break; | 179 | break; |
| 184 | case 'q': | 180 | case 'q': |
| 185 | fprintf(stderr, "%s\n", _("DEPRECATION WARNING: the -q switch (quiet output) is no longer \"quiet\".")); | 181 | fprintf(stderr, "%s\n", _("DEPRECATION WARNING: the -q switch (quiet output) is no longer \"quiet\".")); |
| @@ -189,84 +185,103 @@ int main(int argc, char *argv[]) { | |||
| 189 | case '1': | 185 | case '1': |
| 190 | case '0': | 186 | case '0': |
| 191 | printf("%s\n", _("SMART commands are broken and have been disabled (See Notes in --help).")); | 187 | printf("%s\n", _("SMART commands are broken and have been disabled (See Notes in --help).")); |
| 192 | return STATE_CRITICAL; | 188 | result.errorcode = ERROR; |
| 189 | return result; | ||
| 193 | break; | 190 | break; |
| 194 | case 'n': | 191 | case 'n': |
| 195 | fprintf(stderr, "%s\n", _("DEPRECATION WARNING: the -n switch (Nagios-compatible output) is now the")); | 192 | fprintf(stderr, "%s\n", _("DEPRECATION WARNING: the -n switch (Nagios-compatible output) is now the")); |
| 196 | fprintf(stderr, "%s\n", _("default and will be removed from future releases.")); | 193 | fprintf(stderr, "%s\n", _("default and will be removed from future releases.")); |
| 197 | break; | 194 | break; |
| 198 | case 'v': /* verbose */ | 195 | case 'v': /* verbose */ |
| 199 | verbose = true; | 196 | verbose++; |
| 200 | break; | 197 | break; |
| 201 | case 'h': | 198 | case 'h': |
| 202 | print_help(); | 199 | print_help(); |
| 203 | return STATE_UNKNOWN; | 200 | exit(STATE_UNKNOWN); |
| 204 | case 'V': | 201 | case 'V': |
| 205 | print_revision(progname, NP_VERSION); | 202 | print_revision(progname, NP_VERSION); |
| 206 | return STATE_UNKNOWN; | 203 | exit(STATE_UNKNOWN); |
| 207 | default: | 204 | default: |
| 208 | usage5(); | 205 | usage5(); |
| 209 | } | 206 | } |
| 210 | } | 207 | } |
| 211 | 208 | ||
| 212 | if (optind < argc) { | 209 | if (optind < argc) { |
| 213 | device = argv[optind]; | 210 | result.config.device = argv[optind]; |
| 214 | } | 211 | } |
| 215 | 212 | ||
| 216 | if (!device) { | 213 | if (result.config.device == NULL) { |
| 217 | print_help(); | 214 | print_help(); |
| 218 | return STATE_UNKNOWN; | 215 | exit(STATE_UNKNOWN); |
| 216 | } | ||
| 217 | |||
| 218 | return result; | ||
| 219 | } | ||
| 220 | |||
| 221 | int main(int argc, char *argv[]) { | ||
| 222 | setlocale(LC_ALL, ""); | ||
| 223 | bindtextdomain(PACKAGE, LOCALEDIR); | ||
| 224 | textdomain(PACKAGE); | ||
| 225 | |||
| 226 | /* Parse extra opts if any */ | ||
| 227 | argv = np_extra_opts(&argc, argv, progname); | ||
| 228 | |||
| 229 | check_ide_smart_config_wrapper tmp_config = process_arguments(argc, argv); | ||
| 230 | |||
| 231 | if (tmp_config.errorcode != OK) { | ||
| 232 | die(STATE_UNKNOWN, _("Failed to parse commandline")); | ||
| 219 | } | 233 | } |
| 220 | 234 | ||
| 221 | fd = open(device, OPEN_MODE); | 235 | check_ide_smart_config config = tmp_config.config; |
| 222 | 236 | ||
| 223 | if (fd < 0) { | 237 | int device_file_descriptor = open(config.device, OPEN_MODE); |
| 224 | printf(_("CRITICAL - Couldn't open device %s: %s\n"), device, strerror(errno)); | 238 | |
| 239 | if (device_file_descriptor < 0) { | ||
| 240 | printf(_("CRITICAL - Couldn't open device %s: %s\n"), config.device, strerror(errno)); | ||
| 225 | return STATE_CRITICAL; | 241 | return STATE_CRITICAL; |
| 226 | } | 242 | } |
| 227 | 243 | ||
| 228 | if (smart_cmd_simple(fd, SMART_CMD_ENABLE, 0, false)) { | 244 | if (smart_cmd_simple(device_file_descriptor, SMART_CMD_ENABLE, 0, false)) { |
| 229 | printf(_("CRITICAL - SMART_CMD_ENABLE\n")); | 245 | printf(_("CRITICAL - SMART_CMD_ENABLE\n")); |
| 230 | return STATE_CRITICAL; | 246 | return STATE_CRITICAL; |
| 231 | } | 247 | } |
| 232 | 248 | ||
| 233 | smart_read_values(fd, &values); | 249 | smart_values values; |
| 234 | smart_read_thresholds(fd, &thresholds); | 250 | smart_read_values(device_file_descriptor, &values); |
| 235 | retval = nagios(&values, &thresholds); | 251 | smart_thresholds thresholds; |
| 252 | smart_read_thresholds(device_file_descriptor, &thresholds); | ||
| 253 | mp_state_enum retval = compare_values_and_thresholds(&values, &thresholds); | ||
| 236 | if (verbose) { | 254 | if (verbose) { |
| 237 | print_values(&values, &thresholds); | 255 | print_values(&values, &thresholds); |
| 238 | } | 256 | } |
| 239 | 257 | ||
| 240 | close(fd); | 258 | close(device_file_descriptor); |
| 241 | return retval; | 259 | return retval; |
| 242 | } | 260 | } |
| 243 | 261 | ||
| 244 | char *get_offline_text(int status) { | 262 | char *get_offline_text(int status) { |
| 245 | int i; | 263 | for (int index = 0; offline_status_text[index].text; index++) { |
| 246 | for (i = 0; offline_status_text[i].text; i++) { | 264 | if (offline_status_text[index].value == status) { |
| 247 | if (offline_status_text[i].value == status) { | 265 | return offline_status_text[index].text; |
| 248 | return offline_status_text[i].text; | ||
| 249 | } | 266 | } |
| 250 | } | 267 | } |
| 251 | return "UNKNOWN"; | 268 | return "UNKNOWN"; |
| 252 | } | 269 | } |
| 253 | 270 | ||
| 254 | int smart_read_values(int fd, values_t *values) { | 271 | int smart_read_values(int file_descriptor, smart_values *values) { |
| 255 | #ifdef __linux__ | 272 | #ifdef __linux__ |
| 256 | int e; | ||
| 257 | uint8_t args[4 + 512]; | 273 | uint8_t args[4 + 512]; |
| 258 | args[0] = WIN_SMART; | 274 | args[0] = WIN_SMART; |
| 259 | args[1] = 0; | 275 | args[1] = 0; |
| 260 | args[2] = SMART_READ_VALUES; | 276 | args[2] = SMART_READ_VALUES; |
| 261 | args[3] = 1; | 277 | args[3] = 1; |
| 262 | if (ioctl(fd, HDIO_DRIVE_CMD, &args)) { | 278 | if (ioctl(file_descriptor, HDIO_DRIVE_CMD, &args)) { |
| 263 | e = errno; | 279 | int errno_storage = errno; |
| 264 | printf(_("CRITICAL - SMART_READ_VALUES: %s\n"), strerror(errno)); | 280 | printf(_("CRITICAL - SMART_READ_VALUES: %s\n"), strerror(errno)); |
| 265 | return e; | 281 | return errno_storage; |
| 266 | } | 282 | } |
| 267 | memcpy(values, args + 4, 512); | 283 | memcpy(values, args + 4, 512); |
| 268 | #endif /* __linux__ */ | 284 | #elif defined __NetBSD__ |
| 269 | #ifdef __NetBSD__ | ||
| 270 | struct atareq req; | 285 | struct atareq req; |
| 271 | unsigned char inbuf[DEV_BSIZE]; | 286 | unsigned char inbuf[DEV_BSIZE]; |
| 272 | 287 | ||
| @@ -281,34 +296,37 @@ int smart_read_values(int fd, values_t *values) { | |||
| 281 | req.datalen = sizeof(inbuf); | 296 | req.datalen = sizeof(inbuf); |
| 282 | req.cylinder = WDSMART_CYL; | 297 | req.cylinder = WDSMART_CYL; |
| 283 | 298 | ||
| 284 | if (ioctl(fd, ATAIOCCOMMAND, &req) == 0) { | 299 | if (ioctl(file_descriptor, ATAIOCCOMMAND, &req) == 0) { |
| 285 | if (req.retsts != ATACMD_OK) { | 300 | if (req.retsts != ATACMD_OK) { |
| 286 | errno = ENODEV; | 301 | errno = ENODEV; |
| 287 | } | 302 | } |
| 288 | } | 303 | } |
| 289 | 304 | ||
| 290 | if (errno != 0) { | 305 | if (errno != 0) { |
| 291 | int e = errno; | 306 | int errno_storage = errno; |
| 292 | printf(_("CRITICAL - SMART_READ_VALUES: %s\n"), strerror(errno)); | 307 | printf(_("CRITICAL - SMART_READ_VALUES: %s\n"), strerror(errno)); |
| 293 | return e; | 308 | return errno_storage; |
| 294 | } | 309 | } |
| 295 | 310 | ||
| 296 | (void)memcpy(values, inbuf, 512); | 311 | (void)memcpy(values, inbuf, 512); |
| 297 | #endif /* __NetBSD__ */ | 312 | #else // __linux__ || __NetBSD__ |
| 313 | # error Not implemented for this OS | ||
| 314 | #endif | ||
| 315 | |||
| 298 | return 0; | 316 | return 0; |
| 299 | } | 317 | } |
| 300 | 318 | ||
| 301 | int nagios(values_t *p, thresholds_t *t) { | 319 | mp_state_enum compare_values_and_thresholds(smart_values *values, smart_thresholds *thresholds) { |
| 302 | value_t *value = p->values; | 320 | smart_value *value = values->values; |
| 303 | threshold_t *threshold = t->thresholds; | 321 | smart_threshold *threshold = thresholds->thresholds; |
| 322 | |||
| 304 | int status = OPERATIONAL; | 323 | int status = OPERATIONAL; |
| 305 | int prefailure = 0; | 324 | int prefailure = 0; |
| 306 | int advisory = 0; | 325 | int advisory = 0; |
| 307 | int failed = 0; | 326 | int failed = 0; |
| 308 | int passed = 0; | 327 | int passed = 0; |
| 309 | int total = 0; | 328 | int total = 0; |
| 310 | int i; | 329 | for (int i = 0; i < NR_ATTRIBUTES; i++) { |
| 311 | for (i = 0; i < NR_ATTRIBUTES; i++) { | ||
| 312 | if (value->id && threshold->id && value->id == threshold->id) { | 330 | if (value->id && threshold->id && value->id == threshold->id) { |
| 313 | if (value->value < threshold->threshold) { | 331 | if (value->value < threshold->threshold) { |
| 314 | ++failed; | 332 | ++failed; |
| @@ -327,6 +345,7 @@ int nagios(values_t *p, thresholds_t *t) { | |||
| 327 | ++value; | 345 | ++value; |
| 328 | ++threshold; | 346 | ++threshold; |
| 329 | } | 347 | } |
| 348 | |||
| 330 | switch (status) { | 349 | switch (status) { |
| 331 | case PREFAILURE: | 350 | case PREFAILURE: |
| 332 | printf(_("CRITICAL - %d Harddrive PreFailure%cDetected! %d/%d tests failed.\n"), prefailure, prefailure > 1 ? 's' : ' ', failed, | 351 | printf(_("CRITICAL - %d Harddrive PreFailure%cDetected! %d/%d tests failed.\n"), prefailure, prefailure > 1 ? 's' : ' ', failed, |
| @@ -349,50 +368,51 @@ int nagios(values_t *p, thresholds_t *t) { | |||
| 349 | return status; | 368 | return status; |
| 350 | } | 369 | } |
| 351 | 370 | ||
| 352 | void print_value(value_t *p, threshold_t *t) { | 371 | void print_value(smart_value *value_pointer, smart_threshold *threshold_pointer) { |
| 353 | printf("Id=%3d, Status=%2d {%s , %s}, Value=%3d, Threshold=%3d, %s\n", p->id, p->status, p->status & 1 ? "PreFailure" : "Advisory ", | 372 | printf("Id=%3d, Status=%2d {%s , %s}, Value=%3d, Threshold=%3d, %s\n", value_pointer->id, value_pointer->status, |
| 354 | p->status & 2 ? "OnLine " : "OffLine", p->value, t->threshold, p->value >= t->threshold ? "Passed" : "Failed"); | 373 | value_pointer->status & 1 ? "PreFailure" : "Advisory ", value_pointer->status & 2 ? "OnLine " : "OffLine", |
| 374 | value_pointer->value, threshold_pointer->threshold, value_pointer->value >= threshold_pointer->threshold ? "Passed" : "Failed"); | ||
| 355 | } | 375 | } |
| 356 | 376 | ||
| 357 | void print_values(values_t *p, thresholds_t *t) { | 377 | void print_values(smart_values *values, smart_thresholds *thresholds) { |
| 358 | value_t *value = p->values; | 378 | smart_value *value = values->values; |
| 359 | threshold_t *threshold = t->thresholds; | 379 | smart_threshold *threshold = thresholds->thresholds; |
| 360 | int i; | 380 | for (int i = 0; i < NR_ATTRIBUTES; i++) { |
| 361 | for (i = 0; i < NR_ATTRIBUTES; i++) { | ||
| 362 | if (value->id && threshold->id && value->id == threshold->id) { | 381 | if (value->id && threshold->id && value->id == threshold->id) { |
| 363 | print_value(value++, threshold++); | 382 | print_value(value++, threshold++); |
| 364 | } | 383 | } |
| 365 | } | 384 | } |
| 366 | printf(_("OffLineStatus=%d {%s}, AutoOffLine=%s, OffLineTimeout=%d minutes\n"), p->offline_status, | 385 | printf(_("OffLineStatus=%d {%s}, AutoOffLine=%s, OffLineTimeout=%d minutes\n"), values->offline_status, |
| 367 | get_offline_text(p->offline_status & 0x7f), (p->offline_status & 0x80 ? "Yes" : "No"), p->offline_timeout / 60); | 386 | get_offline_text(values->offline_status & 0x7f), (values->offline_status & 0x80 ? "Yes" : "No"), values->offline_timeout / 60); |
| 368 | printf(_("OffLineCapability=%d {%s %s %s}\n"), p->offline_capability, p->offline_capability & 1 ? "Immediate" : "", | 387 | printf(_("OffLineCapability=%d {%s %s %s}\n"), values->offline_capability, values->offline_capability & 1 ? "Immediate" : "", |
| 369 | p->offline_capability & 2 ? "Auto" : "", p->offline_capability & 4 ? "AbortOnCmd" : "SuspendOnCmd"); | 388 | values->offline_capability & 2 ? "Auto" : "", values->offline_capability & 4 ? "AbortOnCmd" : "SuspendOnCmd"); |
| 370 | printf(_("SmartRevision=%d, CheckSum=%d, SmartCapability=%d {%s %s}\n"), p->revision, p->checksum, p->smart_capability, | 389 | printf(_("SmartRevision=%d, CheckSum=%d, SmartCapability=%d {%s %s}\n"), values->revision, values->checksum, values->smart_capability, |
| 371 | p->smart_capability & 1 ? "SaveOnStandBy" : "", p->smart_capability & 2 ? "AutoSave" : ""); | 390 | values->smart_capability & 1 ? "SaveOnStandBy" : "", values->smart_capability & 2 ? "AutoSave" : ""); |
| 372 | } | 391 | } |
| 373 | 392 | ||
| 374 | int smart_cmd_simple(int fd, enum SmartCommand command, uint8_t val0, bool show_error) { | 393 | mp_state_enum smart_cmd_simple(int file_descriptor, enum SmartCommand command, uint8_t val0, bool show_error) { |
| 375 | int e = STATE_UNKNOWN; | 394 | mp_state_enum result = STATE_UNKNOWN; |
| 376 | #ifdef __linux__ | 395 | #ifdef __linux__ |
| 377 | uint8_t args[4]; | 396 | uint8_t args[4] = { |
| 378 | args[0] = WIN_SMART; | 397 | WIN_SMART, |
| 379 | args[1] = val0; | 398 | val0, |
| 380 | args[2] = smart_command[command].value; | 399 | smart_command[command].value, |
| 381 | args[3] = 0; | 400 | 0, |
| 382 | if (ioctl(fd, HDIO_DRIVE_CMD, &args)) { | 401 | }; |
| 383 | e = STATE_CRITICAL; | 402 | |
| 403 | if (ioctl(file_descriptor, HDIO_DRIVE_CMD, &args)) { | ||
| 404 | result = STATE_CRITICAL; | ||
| 384 | if (show_error) { | 405 | if (show_error) { |
| 385 | printf(_("CRITICAL - %s: %s\n"), smart_command[command].text, strerror(errno)); | 406 | printf(_("CRITICAL - %s: %s\n"), smart_command[command].text, strerror(errno)); |
| 386 | } | 407 | } |
| 387 | } else { | 408 | } else { |
| 388 | e = STATE_OK; | 409 | result = STATE_OK; |
| 389 | if (show_error) { | 410 | if (show_error) { |
| 390 | printf(_("OK - Command sent (%s)\n"), smart_command[command].text); | 411 | printf(_("OK - Command sent (%s)\n"), smart_command[command].text); |
| 391 | } | 412 | } |
| 392 | } | 413 | } |
| 393 | 414 | ||
| 394 | #endif /* __linux__ */ | 415 | #elif defined __NetBSD__ |
| 395 | #ifdef __NetBSD__ | ||
| 396 | struct atareq req; | 416 | struct atareq req; |
| 397 | 417 | ||
| 398 | memset(&req, 0, sizeof(req)); | 418 | memset(&req, 0, sizeof(req)); |
| @@ -403,7 +423,7 @@ int smart_cmd_simple(int fd, enum SmartCommand command, uint8_t val0, bool show_ | |||
| 403 | req.cylinder = WDSMART_CYL; | 423 | req.cylinder = WDSMART_CYL; |
| 404 | req.sec_count = val0; | 424 | req.sec_count = val0; |
| 405 | 425 | ||
| 406 | if (ioctl(fd, ATAIOCCOMMAND, &req) == 0) { | 426 | if (ioctl(file_descriptor, ATAIOCCOMMAND, &req) == 0) { |
| 407 | if (req.retsts != ATACMD_OK) { | 427 | if (req.retsts != ATACMD_OK) { |
| 408 | errno = ENODEV; | 428 | errno = ENODEV; |
| 409 | } | 429 | } |
| @@ -413,42 +433,42 @@ int smart_cmd_simple(int fd, enum SmartCommand command, uint8_t val0, bool show_ | |||
| 413 | } | 433 | } |
| 414 | 434 | ||
| 415 | if (errno != 0) { | 435 | if (errno != 0) { |
| 416 | e = STATE_CRITICAL; | 436 | result = STATE_CRITICAL; |
| 417 | if (show_error) { | 437 | if (show_error) { |
| 418 | printf(_("CRITICAL - %s: %s\n"), smart_command[command].text, strerror(errno)); | 438 | printf(_("CRITICAL - %s: %s\n"), smart_command[command].text, strerror(errno)); |
| 419 | } | 439 | } |
| 420 | } else { | 440 | } else { |
| 421 | e = STATE_OK; | 441 | result = STATE_OK; |
| 422 | if (show_error) { | 442 | if (show_error) { |
| 423 | printf(_("OK - Command sent (%s)\n"), smart_command[command].text); | 443 | printf(_("OK - Command sent (%s)\n"), smart_command[command].text); |
| 424 | } | 444 | } |
| 425 | } | 445 | } |
| 426 | 446 | #else | |
| 447 | # error Not implemented for this OS | ||
| 427 | #endif /* __NetBSD__ */ | 448 | #endif /* __NetBSD__ */ |
| 428 | return e; | 449 | |
| 450 | return result; | ||
| 429 | } | 451 | } |
| 430 | 452 | ||
| 431 | int smart_read_thresholds(int fd, thresholds_t *thresholds) { | 453 | int smart_read_thresholds(int file_descriptor, smart_thresholds *thresholds) { |
| 432 | #ifdef __linux__ | 454 | #ifdef __linux__ |
| 433 | int e; | ||
| 434 | uint8_t args[4 + 512]; | 455 | uint8_t args[4 + 512]; |
| 435 | args[0] = WIN_SMART; | 456 | args[0] = WIN_SMART; |
| 436 | args[1] = 0; | 457 | args[1] = 0; |
| 437 | args[2] = SMART_READ_THRESHOLDS; | 458 | args[2] = SMART_READ_THRESHOLDS; |
| 438 | args[3] = 1; | 459 | args[3] = 1; |
| 439 | if (ioctl(fd, HDIO_DRIVE_CMD, &args)) { | 460 | if (ioctl(file_descriptor, HDIO_DRIVE_CMD, &args)) { |
| 440 | e = errno; | 461 | int errno_storage = errno; |
| 441 | printf(_("CRITICAL - SMART_READ_THRESHOLDS: %s\n"), strerror(errno)); | 462 | printf(_("CRITICAL - SMART_READ_THRESHOLDS: %s\n"), strerror(errno)); |
| 442 | return e; | 463 | return errno_storage; |
| 443 | } | 464 | } |
| 444 | memcpy(thresholds, args + 4, 512); | 465 | memcpy(thresholds, args + 4, 512); |
| 445 | #endif /* __linux__ */ | 466 | #elif defined __NetBSD__ |
| 446 | #ifdef __NetBSD__ | ||
| 447 | struct atareq req; | 467 | struct atareq req; |
| 448 | unsigned char inbuf[DEV_BSIZE]; | ||
| 449 | |||
| 450 | memset(&req, 0, sizeof(req)); | 468 | memset(&req, 0, sizeof(req)); |
| 451 | req.timeout = 1000; | 469 | req.timeout = 1000; |
| 470 | |||
| 471 | unsigned char inbuf[DEV_BSIZE]; | ||
| 452 | memset(&inbuf, 0, sizeof(inbuf)); | 472 | memset(&inbuf, 0, sizeof(inbuf)); |
| 453 | 473 | ||
| 454 | req.flags = ATACMD_READ; | 474 | req.flags = ATACMD_READ; |
| @@ -458,20 +478,23 @@ int smart_read_thresholds(int fd, thresholds_t *thresholds) { | |||
| 458 | req.datalen = sizeof(inbuf); | 478 | req.datalen = sizeof(inbuf); |
| 459 | req.cylinder = WDSMART_CYL; | 479 | req.cylinder = WDSMART_CYL; |
| 460 | 480 | ||
| 461 | if (ioctl(fd, ATAIOCCOMMAND, &req) == 0) { | 481 | if (ioctl(file_descriptor, ATAIOCCOMMAND, &req) == 0) { |
| 462 | if (req.retsts != ATACMD_OK) { | 482 | if (req.retsts != ATACMD_OK) { |
| 463 | errno = ENODEV; | 483 | errno = ENODEV; |
| 464 | } | 484 | } |
| 465 | } | 485 | } |
| 466 | 486 | ||
| 467 | if (errno != 0) { | 487 | if (errno != 0) { |
| 468 | int e = errno; | 488 | int errno_storage = errno; |
| 469 | printf(_("CRITICAL - SMART_READ_THRESHOLDS: %s\n"), strerror(errno)); | 489 | printf(_("CRITICAL - SMART_READ_THRESHOLDS: %s\n"), strerror(errno)); |
| 470 | return e; | 490 | return errno_storage; |
| 471 | } | 491 | } |
| 472 | 492 | ||
| 473 | (void)memcpy(thresholds, inbuf, 512); | 493 | (void)memcpy(thresholds, inbuf, 512); |
| 494 | #else | ||
| 495 | # error Not implemented for this OS | ||
| 474 | #endif /* __NetBSD__ */ | 496 | #endif /* __NetBSD__ */ |
| 497 | |||
| 475 | return 0; | 498 | return 0; |
| 476 | } | 499 | } |
| 477 | 500 | ||
diff --git a/plugins/check_ide_smart.d/config.h b/plugins/check_ide_smart.d/config.h new file mode 100644 index 00000000..36899abe --- /dev/null +++ b/plugins/check_ide_smart.d/config.h | |||
| @@ -0,0 +1,15 @@ | |||
| 1 | #pragma once | ||
| 2 | |||
| 3 | #include "../../config.h" | ||
| 4 | #include <stddef.h> | ||
| 5 | |||
| 6 | typedef struct { | ||
| 7 | char *device; | ||
| 8 | } check_ide_smart_config; | ||
| 9 | |||
| 10 | check_ide_smart_config check_ide_smart_init() { | ||
| 11 | check_ide_smart_config tmp = { | ||
| 12 | .device = NULL, | ||
| 13 | }; | ||
| 14 | return tmp; | ||
| 15 | } | ||
diff --git a/plugins/check_ldap.c b/plugins/check_ldap.c index 77a33304..1b2e2826 100644 --- a/plugins/check_ldap.c +++ b/plugins/check_ldap.c | |||
| @@ -27,12 +27,11 @@ | |||
| 27 | *****************************************************************************/ | 27 | *****************************************************************************/ |
| 28 | 28 | ||
| 29 | /* progname may be check_ldaps */ | 29 | /* progname may be check_ldaps */ |
| 30 | char *progname = "check_ldap"; | 30 | #include "output.h" |
| 31 | const char *copyright = "2000-2024"; | ||
| 32 | const char *email = "devel@monitoring-plugins.org"; | ||
| 33 | |||
| 34 | #include "common.h" | 31 | #include "common.h" |
| 35 | #include "netutils.h" | 32 | #include "netutils.h" |
| 33 | #include "perfdata.h" | ||
| 34 | #include "thresholds.h" | ||
| 36 | #include "utils.h" | 35 | #include "utils.h" |
| 37 | #include "check_ldap.d/config.h" | 36 | #include "check_ldap.d/config.h" |
| 38 | 37 | ||
| @@ -41,6 +40,10 @@ const char *email = "devel@monitoring-plugins.org"; | |||
| 41 | #define LDAP_DEPRECATED 1 | 40 | #define LDAP_DEPRECATED 1 |
| 42 | #include <ldap.h> | 41 | #include <ldap.h> |
| 43 | 42 | ||
| 43 | char *progname = "check_ldap"; | ||
| 44 | const char *copyright = "2000-2024"; | ||
| 45 | const char *email = "devel@monitoring-plugins.org"; | ||
| 46 | |||
| 44 | enum { | 47 | enum { |
| 45 | DEFAULT_PORT = 389 | 48 | DEFAULT_PORT = 389 |
| 46 | }; | 49 | }; |
| @@ -79,6 +82,10 @@ int main(int argc, char *argv[]) { | |||
| 79 | 82 | ||
| 80 | const check_ldap_config config = tmp_config.config; | 83 | const check_ldap_config config = tmp_config.config; |
| 81 | 84 | ||
| 85 | if (config.output_format_is_set) { | ||
| 86 | mp_set_format(config.output_format); | ||
| 87 | } | ||
| 88 | |||
| 82 | /* initialize alarm signal handling */ | 89 | /* initialize alarm signal handling */ |
| 83 | signal(SIGALRM, socket_timeout_alarm_handler); | 90 | signal(SIGALRM, socket_timeout_alarm_handler); |
| 84 | 91 | ||
| @@ -89,101 +96,172 @@ int main(int argc, char *argv[]) { | |||
| 89 | struct timeval start_time; | 96 | struct timeval start_time; |
| 90 | gettimeofday(&start_time, NULL); | 97 | gettimeofday(&start_time, NULL); |
| 91 | 98 | ||
| 99 | mp_check overall = mp_check_init(); | ||
| 100 | |||
| 92 | LDAP *ldap_connection; | 101 | LDAP *ldap_connection; |
| 93 | /* initialize ldap */ | 102 | /* initialize ldap */ |
| 103 | { | ||
| 94 | #ifdef HAVE_LDAP_INIT | 104 | #ifdef HAVE_LDAP_INIT |
| 95 | if (!(ldap_connection = ldap_init(config.ld_host, config.ld_port))) { | 105 | mp_subcheck sc_ldap_init = mp_subcheck_init(); |
| 96 | printf("Could not connect to the server at port %i\n", config.ld_port); | 106 | if (!(ldap_connection = ldap_init(config.ld_host, config.ld_port))) { |
| 97 | return STATE_CRITICAL; | 107 | xasprintf(&sc_ldap_init.output, "could not connect to the server at port %i", |
| 98 | } | 108 | config.ld_port); |
| 109 | sc_ldap_init = mp_set_subcheck_state(sc_ldap_init, STATE_CRITICAL); | ||
| 110 | mp_add_subcheck_to_check(&overall, sc_ldap_init); | ||
| 111 | mp_exit(overall); | ||
| 112 | } else { | ||
| 113 | xasprintf(&sc_ldap_init.output, "connected to the server at port %i", config.ld_port); | ||
| 114 | sc_ldap_init = mp_set_subcheck_state(sc_ldap_init, STATE_OK); | ||
| 115 | mp_add_subcheck_to_check(&overall, sc_ldap_init); | ||
| 116 | } | ||
| 99 | #else | 117 | #else |
| 100 | if (!(ld = ldap_open(config.ld_host, config.ld_port))) { | 118 | mp_subcheck sc_ldap_init = mp_subcheck_init(); |
| 101 | if (verbose) { | 119 | if (!(ld = ldap_open(config.ld_host, config.ld_port))) { |
| 102 | ldap_perror(ldap_connection, "ldap_open"); | 120 | if (verbose) { |
| 121 | ldap_perror(ldap_connection, "ldap_open"); | ||
| 122 | } | ||
| 123 | xasprintf(&sc_ldap_init.output, "Could not connect to the server at port %i"), config.ld_port); | ||
| 124 | sc_ldap_init = mp_set_subcheck_state(sc_ldap_init, STATE_CRITICAL); | ||
| 125 | mp_add_subcheck_to_check(&overall, sc_ldap_init); | ||
| 126 | mp_exit(overall); | ||
| 127 | } else { | ||
| 128 | xasprintf(&sc_ldap_init.output, "connected to the server at port %i", config.ld_port); | ||
| 129 | sc_ldap_init = mp_set_subcheck_state(sc_ldap_init, STATE_OK); | ||
| 130 | mp_add_subcheck_to_check(&overall, sc_ldap_init); | ||
| 103 | } | 131 | } |
| 104 | printf(_("Could not connect to the server at port %i\n"), config.ld_port); | ||
| 105 | return STATE_CRITICAL; | ||
| 106 | } | ||
| 107 | #endif /* HAVE_LDAP_INIT */ | 132 | #endif /* HAVE_LDAP_INIT */ |
| 133 | } | ||
| 108 | 134 | ||
| 109 | #ifdef HAVE_LDAP_SET_OPTION | 135 | #ifdef HAVE_LDAP_SET_OPTION |
| 110 | /* set ldap options */ | 136 | /* set ldap options */ |
| 137 | mp_subcheck sc_ldap_set_opts = mp_subcheck_init(); | ||
| 111 | if (ldap_set_option(ldap_connection, LDAP_OPT_PROTOCOL_VERSION, &config.ld_protocol) != | 138 | if (ldap_set_option(ldap_connection, LDAP_OPT_PROTOCOL_VERSION, &config.ld_protocol) != |
| 112 | LDAP_OPT_SUCCESS) { | 139 | LDAP_OPT_SUCCESS) { |
| 113 | printf(_("Could not set protocol version %d\n"), config.ld_protocol); | 140 | xasprintf(&sc_ldap_set_opts.output, "Could not set protocol version %d", |
| 114 | return STATE_CRITICAL; | 141 | config.ld_protocol); |
| 142 | sc_ldap_set_opts = mp_set_subcheck_state(sc_ldap_set_opts, STATE_CRITICAL); | ||
| 143 | mp_add_subcheck_to_check(&overall, sc_ldap_set_opts); | ||
| 144 | mp_exit(overall); | ||
| 145 | } else { | ||
| 146 | xasprintf(&sc_ldap_set_opts.output, "set protocol version %d", config.ld_protocol); | ||
| 147 | sc_ldap_set_opts = mp_set_subcheck_state(sc_ldap_set_opts, STATE_OK); | ||
| 148 | mp_add_subcheck_to_check(&overall, sc_ldap_set_opts); | ||
| 115 | } | 149 | } |
| 116 | #endif | 150 | #endif |
| 117 | 151 | ||
| 118 | int version = 3; | 152 | int version = 3; |
| 119 | int tls; | 153 | int tls; |
| 120 | if (config.ld_port == LDAPS_PORT || config.ssl_on_connect) { | 154 | { |
| 155 | if (config.ld_port == LDAPS_PORT || config.ssl_on_connect) { | ||
| 121 | #if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_X_TLS) | 156 | #if defined(HAVE_LDAP_SET_OPTION) && defined(LDAP_OPT_X_TLS) |
| 122 | /* ldaps: set option tls */ | 157 | /* ldaps: set option tls */ |
| 123 | tls = LDAP_OPT_X_TLS_HARD; | 158 | tls = LDAP_OPT_X_TLS_HARD; |
| 124 | 159 | ||
| 125 | if (ldap_set_option(ldap_connection, LDAP_OPT_X_TLS, &tls) != LDAP_SUCCESS) { | 160 | mp_subcheck sc_ldap_tls_init = mp_subcheck_init(); |
| 126 | if (verbose) { | 161 | if (ldap_set_option(ldap_connection, LDAP_OPT_X_TLS, &tls) != LDAP_SUCCESS) { |
| 127 | ldap_perror(ldap_connection, "ldaps_option"); | 162 | if (verbose) { |
| 163 | ldap_perror(ldap_connection, "ldaps_option"); | ||
| 164 | } | ||
| 165 | xasprintf(&sc_ldap_tls_init.output, "could not init TLS at port %i!", | ||
| 166 | config.ld_port); | ||
| 167 | sc_ldap_tls_init = mp_set_subcheck_state(sc_ldap_tls_init, STATE_CRITICAL); | ||
| 168 | mp_add_subcheck_to_check(&overall, sc_ldap_tls_init); | ||
| 169 | mp_exit(overall); | ||
| 170 | } else { | ||
| 171 | xasprintf(&sc_ldap_tls_init.output, "initiated TLS at port %i!", config.ld_port); | ||
| 172 | sc_ldap_tls_init = mp_set_subcheck_state(sc_ldap_tls_init, STATE_OK); | ||
| 173 | mp_add_subcheck_to_check(&overall, sc_ldap_tls_init); | ||
| 128 | } | 174 | } |
| 129 | printf(_("Could not init TLS at port %i!\n"), config.ld_port); | ||
| 130 | return STATE_CRITICAL; | ||
| 131 | } | ||
| 132 | #else | 175 | #else |
| 133 | printf(_("TLS not supported by the libraries!\n")); | 176 | printf(_("TLS not supported by the libraries!\n")); |
| 134 | return STATE_CRITICAL; | 177 | exit(STATE_CRITICAL); |
| 135 | #endif /* LDAP_OPT_X_TLS */ | 178 | #endif /* LDAP_OPT_X_TLS */ |
| 136 | } else if (config.starttls) { | 179 | } else if (config.starttls) { |
| 137 | #if defined(HAVE_LDAP_SET_OPTION) && defined(HAVE_LDAP_START_TLS_S) | 180 | #if defined(HAVE_LDAP_SET_OPTION) && defined(HAVE_LDAP_START_TLS_S) |
| 138 | /* ldap with startTLS: set option version */ | 181 | /* ldap with startTLS: set option version */ |
| 139 | if (ldap_get_option(ldap_connection, LDAP_OPT_PROTOCOL_VERSION, &version) == | 182 | if (ldap_get_option(ldap_connection, LDAP_OPT_PROTOCOL_VERSION, &version) == |
| 140 | LDAP_OPT_SUCCESS) { | 183 | LDAP_OPT_SUCCESS) { |
| 141 | if (version < LDAP_VERSION3) { | 184 | if (version < LDAP_VERSION3) { |
| 142 | version = LDAP_VERSION3; | 185 | version = LDAP_VERSION3; |
| 143 | ldap_set_option(ldap_connection, LDAP_OPT_PROTOCOL_VERSION, &version); | 186 | ldap_set_option(ldap_connection, LDAP_OPT_PROTOCOL_VERSION, &version); |
| 187 | } | ||
| 144 | } | 188 | } |
| 145 | } | 189 | /* call start_tls */ |
| 146 | /* call start_tls */ | 190 | mp_subcheck sc_ldap_starttls = mp_subcheck_init(); |
| 147 | if (ldap_start_tls_s(ldap_connection, NULL, NULL) != LDAP_SUCCESS) { | 191 | if (ldap_start_tls_s(ldap_connection, NULL, NULL) != LDAP_SUCCESS) { |
| 148 | if (verbose) { | 192 | if (verbose) { |
| 149 | ldap_perror(ldap_connection, "ldap_start_tls"); | 193 | ldap_perror(ldap_connection, "ldap_start_tls"); |
| 194 | } | ||
| 195 | xasprintf(&sc_ldap_starttls.output, "could not init STARTTLS at port %i!", | ||
| 196 | config.ld_port); | ||
| 197 | sc_ldap_starttls = mp_set_subcheck_state(sc_ldap_starttls, STATE_CRITICAL); | ||
| 198 | mp_add_subcheck_to_check(&overall, sc_ldap_starttls); | ||
| 199 | mp_exit(overall); | ||
| 200 | } else { | ||
| 201 | xasprintf(&sc_ldap_starttls.output, "initiated STARTTLS at port %i!", | ||
| 202 | config.ld_port); | ||
| 203 | sc_ldap_starttls = mp_set_subcheck_state(sc_ldap_starttls, STATE_OK); | ||
| 204 | mp_add_subcheck_to_check(&overall, sc_ldap_starttls); | ||
| 150 | } | 205 | } |
| 151 | printf(_("Could not init startTLS at port %i!\n"), config.ld_port); | ||
| 152 | return STATE_CRITICAL; | ||
| 153 | } | ||
| 154 | #else | 206 | #else |
| 155 | printf(_("startTLS not supported by the library, needs LDAPv3!\n")); | 207 | printf(_("startTLS not supported by the library, needs LDAPv3!\n")); |
| 156 | return STATE_CRITICAL; | 208 | exit(STATE_CRITICAL); |
| 157 | #endif /* HAVE_LDAP_START_TLS_S */ | 209 | #endif /* HAVE_LDAP_START_TLS_S */ |
| 210 | } | ||
| 158 | } | 211 | } |
| 159 | 212 | ||
| 160 | /* bind to the ldap server */ | 213 | /* bind to the ldap server */ |
| 161 | if (ldap_bind_s(ldap_connection, config.ld_binddn, config.ld_passwd, LDAP_AUTH_SIMPLE) != | 214 | { |
| 162 | LDAP_SUCCESS) { | 215 | mp_subcheck sc_ldap_bind = mp_subcheck_init(); |
| 163 | if (verbose) { | 216 | int ldap_error = |
| 164 | ldap_perror(ldap_connection, "ldap_bind"); | 217 | ldap_bind_s(ldap_connection, config.ld_binddn, config.ld_passwd, LDAP_AUTH_SIMPLE); |
| 218 | if (ldap_error != LDAP_SUCCESS) { | ||
| 219 | if (verbose) { | ||
| 220 | ldap_perror(ldap_connection, "ldap_bind"); | ||
| 221 | } | ||
| 222 | |||
| 223 | xasprintf(&sc_ldap_bind.output, "could not bind to the LDAP server: %s", | ||
| 224 | ldap_err2string(ldap_error)); | ||
| 225 | sc_ldap_bind = mp_set_subcheck_state(sc_ldap_bind, STATE_CRITICAL); | ||
| 226 | mp_add_subcheck_to_check(&overall, sc_ldap_bind); | ||
| 227 | mp_exit(overall); | ||
| 228 | } else { | ||
| 229 | xasprintf(&sc_ldap_bind.output, "execute bind to the LDAP server"); | ||
| 230 | sc_ldap_bind = mp_set_subcheck_state(sc_ldap_bind, STATE_OK); | ||
| 231 | mp_add_subcheck_to_check(&overall, sc_ldap_bind); | ||
| 165 | } | 232 | } |
| 166 | printf(_("Could not bind to the LDAP server\n")); | ||
| 167 | return STATE_CRITICAL; | ||
| 168 | } | 233 | } |
| 169 | 234 | ||
| 170 | LDAPMessage *result; | 235 | LDAPMessage *result; |
| 171 | int num_entries = 0; | ||
| 172 | /* do a search of all objectclasses in the base dn */ | 236 | /* do a search of all objectclasses in the base dn */ |
| 173 | if (ldap_search_s(ldap_connection, config.ld_base, | 237 | { |
| 174 | (config.crit_entries != NULL || config.warn_entries != NULL) | 238 | mp_subcheck sc_ldap_search = mp_subcheck_init(); |
| 175 | ? LDAP_SCOPE_SUBTREE | 239 | int ldap_error = ldap_search_s( |
| 176 | : LDAP_SCOPE_BASE, | 240 | ldap_connection, config.ld_base, |
| 177 | config.ld_attr, NULL, 0, &result) != LDAP_SUCCESS) { | 241 | (config.entries_thresholds.warning_is_set || config.entries_thresholds.critical_is_set) |
| 178 | if (verbose) { | 242 | ? LDAP_SCOPE_SUBTREE |
| 179 | ldap_perror(ldap_connection, "ldap_search"); | 243 | : LDAP_SCOPE_BASE, |
| 244 | config.ld_attr, NULL, 0, &result); | ||
| 245 | |||
| 246 | if (ldap_error != LDAP_SUCCESS) { | ||
| 247 | if (verbose) { | ||
| 248 | ldap_perror(ldap_connection, "ldap_search"); | ||
| 249 | } | ||
| 250 | xasprintf(&sc_ldap_search.output, "could not search/find objectclasses in %s: %s", | ||
| 251 | config.ld_base, ldap_err2string(ldap_error)); | ||
| 252 | sc_ldap_search = mp_set_subcheck_state(sc_ldap_search, STATE_CRITICAL); | ||
| 253 | mp_add_subcheck_to_check(&overall, sc_ldap_search); | ||
| 254 | mp_exit(overall); | ||
| 255 | } else { | ||
| 256 | xasprintf(&sc_ldap_search.output, "search/find objectclasses in %s", config.ld_base); | ||
| 257 | sc_ldap_search = mp_set_subcheck_state(sc_ldap_search, STATE_OK); | ||
| 258 | mp_add_subcheck_to_check(&overall, sc_ldap_search); | ||
| 180 | } | 259 | } |
| 181 | printf(_("Could not search/find objectclasses in %s\n"), config.ld_base); | ||
| 182 | return STATE_CRITICAL; | ||
| 183 | } | 260 | } |
| 184 | 261 | ||
| 185 | if (config.crit_entries != NULL || config.warn_entries != NULL) { | 262 | int num_entries = ldap_count_entries(ldap_connection, result); |
| 186 | num_entries = ldap_count_entries(ldap_connection, result); | 263 | if (verbose) { |
| 264 | printf("entries found: %d\n", num_entries); | ||
| 187 | } | 265 | } |
| 188 | 266 | ||
| 189 | /* unbind from the ldap server */ | 267 | /* unbind from the ldap server */ |
| @@ -193,50 +271,50 @@ int main(int argc, char *argv[]) { | |||
| 193 | alarm(0); | 271 | alarm(0); |
| 194 | 272 | ||
| 195 | /* calculate the elapsed time and compare to thresholds */ | 273 | /* calculate the elapsed time and compare to thresholds */ |
| 196 | |||
| 197 | long microsec = deltime(start_time); | 274 | long microsec = deltime(start_time); |
| 198 | double elapsed_time = (double)microsec / 1.0e6; | 275 | double elapsed_time = (double)microsec / 1.0e6; |
| 199 | mp_state_enum status = STATE_UNKNOWN; | 276 | mp_perfdata pd_connection_time = perfdata_init(); |
| 200 | if (config.crit_time_set && elapsed_time > config.crit_time) { | 277 | pd_connection_time.label = "time"; |
| 201 | status = STATE_CRITICAL; | 278 | pd_connection_time.value = mp_create_pd_value(elapsed_time); |
| 202 | } else if (config.warn_time_set && elapsed_time > config.warn_time) { | 279 | pd_connection_time = mp_pd_set_thresholds(pd_connection_time, config.connection_time_threshold); |
| 203 | status = STATE_WARNING; | ||
| 204 | } else { | ||
| 205 | status = STATE_OK; | ||
| 206 | } | ||
| 207 | 280 | ||
| 208 | if (config.entries_thresholds != NULL) { | 281 | mp_subcheck sc_connection_time = mp_subcheck_init(); |
| 209 | if (verbose) { | 282 | mp_add_perfdata_to_subcheck(&sc_connection_time, pd_connection_time); |
| 210 | printf("entries found: %d\n", num_entries); | 283 | |
| 211 | print_thresholds("entry thresholds", config.entries_thresholds); | 284 | mp_state_enum connection_time_state = mp_get_pd_status(pd_connection_time); |
| 212 | } | 285 | sc_connection_time = mp_set_subcheck_state(sc_connection_time, connection_time_state); |
| 213 | mp_state_enum status_entries = get_status(num_entries, config.entries_thresholds); | ||
| 214 | if (status_entries == STATE_CRITICAL) { | ||
| 215 | status = STATE_CRITICAL; | ||
| 216 | } else if (status != STATE_CRITICAL) { | ||
| 217 | status = status_entries; | ||
| 218 | } | ||
| 219 | } | ||
| 220 | 286 | ||
| 221 | /* print out the result */ | 287 | if (connection_time_state == STATE_OK) { |
| 222 | if (config.crit_entries != NULL || config.warn_entries != NULL) { | 288 | xasprintf(&sc_connection_time.output, "connection time %.3fs is within thresholds", |
| 223 | printf(_("LDAP %s - found %d entries in %.3f seconds|%s %s\n"), state_text(status), | 289 | elapsed_time); |
| 224 | num_entries, elapsed_time, | ||
| 225 | fperfdata("time", elapsed_time, "s", config.warn_time_set, config.warn_time, | ||
| 226 | config.crit_time_set, config.crit_time, true, 0, false, 0), | ||
| 227 | sperfdata("entries", (double)num_entries, "", config.warn_entries, | ||
| 228 | config.crit_entries, true, 0.0, false, 0.0)); | ||
| 229 | } else { | 290 | } else { |
| 230 | printf(_("LDAP %s - %.3f seconds response time|%s\n"), state_text(status), elapsed_time, | 291 | xasprintf(&sc_connection_time.output, "connection time %.3fs is violating thresholds", |
| 231 | fperfdata("time", elapsed_time, "s", config.warn_time_set, config.warn_time, | 292 | elapsed_time); |
| 232 | config.crit_time_set, config.crit_time, true, 0, false, 0)); | ||
| 233 | } | 293 | } |
| 234 | 294 | ||
| 235 | exit(status); | 295 | mp_add_subcheck_to_check(&overall, sc_connection_time); |
| 296 | |||
| 297 | mp_perfdata pd_num_entries = perfdata_init(); | ||
| 298 | pd_num_entries.label = "entries"; | ||
| 299 | pd_num_entries.value = mp_create_pd_value(num_entries); | ||
| 300 | pd_num_entries = mp_pd_set_thresholds(pd_num_entries, config.entries_thresholds); | ||
| 301 | |||
| 302 | mp_subcheck sc_num_entries = mp_subcheck_init(); | ||
| 303 | mp_add_perfdata_to_subcheck(&sc_num_entries, pd_num_entries); | ||
| 304 | xasprintf(&sc_num_entries.output, "found %d entries", num_entries); | ||
| 305 | sc_num_entries = mp_set_subcheck_state(sc_num_entries, mp_get_pd_status(pd_num_entries)); | ||
| 306 | |||
| 307 | mp_add_subcheck_to_check(&overall, sc_num_entries); | ||
| 308 | |||
| 309 | mp_exit(overall); | ||
| 236 | } | 310 | } |
| 237 | 311 | ||
| 238 | /* process command-line arguments */ | 312 | /* process command-line arguments */ |
| 239 | check_ldap_config_wrapper process_arguments(int argc, char **argv) { | 313 | check_ldap_config_wrapper process_arguments(int argc, char **argv) { |
| 314 | enum { | ||
| 315 | output_format_index = CHAR_MAX + 1, | ||
| 316 | }; | ||
| 317 | |||
| 240 | /* initialize the long option struct */ | 318 | /* initialize the long option struct */ |
| 241 | static struct option longopts[] = {{"help", no_argument, 0, 'h'}, | 319 | static struct option longopts[] = {{"help", no_argument, 0, 'h'}, |
| 242 | {"version", no_argument, 0, 'V'}, | 320 | {"version", no_argument, 0, 'V'}, |
| @@ -260,6 +338,7 @@ check_ldap_config_wrapper process_arguments(int argc, char **argv) { | |||
| 260 | {"warn-entries", required_argument, 0, 'W'}, | 338 | {"warn-entries", required_argument, 0, 'W'}, |
| 261 | {"crit-entries", required_argument, 0, 'C'}, | 339 | {"crit-entries", required_argument, 0, 'C'}, |
| 262 | {"verbose", no_argument, 0, 'v'}, | 340 | {"verbose", no_argument, 0, 'v'}, |
| 341 | {"output-format", required_argument, 0, output_format_index}, | ||
| 263 | {0, 0, 0, 0}}; | 342 | {0, 0, 0, 0}}; |
| 264 | 343 | ||
| 265 | check_ldap_config_wrapper result = { | 344 | check_ldap_config_wrapper result = { |
| @@ -319,20 +398,38 @@ check_ldap_config_wrapper process_arguments(int argc, char **argv) { | |||
| 319 | case 'P': | 398 | case 'P': |
| 320 | result.config.ld_passwd = optarg; | 399 | result.config.ld_passwd = optarg; |
| 321 | break; | 400 | break; |
| 322 | case 'w': | 401 | case 'w': { |
| 323 | result.config.warn_time_set = true; | 402 | mp_range_parsed tmp = mp_parse_range_string(optarg); |
| 324 | result.config.warn_time = strtod(optarg, NULL); | 403 | if (tmp.error != MP_PARSING_SUCCES) { |
| 325 | break; | 404 | die(STATE_UNKNOWN, "failed to parse warning connection time threshold"); |
| 326 | case 'c': | 405 | } |
| 327 | result.config.crit_time_set = true; | 406 | result.config.connection_time_threshold = |
| 328 | result.config.crit_time = strtod(optarg, NULL); | 407 | mp_thresholds_set_warn(result.config.connection_time_threshold, tmp.range); |
| 329 | break; | 408 | } break; |
| 330 | case 'W': | 409 | case 'c': { |
| 331 | result.config.warn_entries = optarg; | 410 | mp_range_parsed tmp = mp_parse_range_string(optarg); |
| 332 | break; | 411 | if (tmp.error != MP_PARSING_SUCCES) { |
| 333 | case 'C': | 412 | die(STATE_UNKNOWN, "failed to parse critical connection time threshold"); |
| 334 | result.config.crit_entries = optarg; | 413 | } |
| 335 | break; | 414 | result.config.connection_time_threshold = |
| 415 | mp_thresholds_set_crit(result.config.connection_time_threshold, tmp.range); | ||
| 416 | } break; | ||
| 417 | case 'W': { | ||
| 418 | mp_range_parsed tmp = mp_parse_range_string(optarg); | ||
| 419 | if (tmp.error != MP_PARSING_SUCCES) { | ||
| 420 | die(STATE_UNKNOWN, "failed to parse number of entries warning threshold"); | ||
| 421 | } | ||
| 422 | result.config.entries_thresholds = | ||
| 423 | mp_thresholds_set_warn(result.config.entries_thresholds, tmp.range); | ||
| 424 | } break; | ||
| 425 | case 'C': { | ||
| 426 | mp_range_parsed tmp = mp_parse_range_string(optarg); | ||
| 427 | if (tmp.error != MP_PARSING_SUCCES) { | ||
| 428 | die(STATE_UNKNOWN, "failed to parse number of entries critical threshold"); | ||
| 429 | } | ||
| 430 | result.config.entries_thresholds = | ||
| 431 | mp_thresholds_set_crit(result.config.entries_thresholds, tmp.range); | ||
| 432 | } break; | ||
| 336 | #ifdef HAVE_LDAP_SET_OPTION | 433 | #ifdef HAVE_LDAP_SET_OPTION |
| 337 | case '2': | 434 | case '2': |
| 338 | result.config.ld_protocol = 2; | 435 | result.config.ld_protocol = 2; |
| @@ -371,6 +468,18 @@ check_ldap_config_wrapper process_arguments(int argc, char **argv) { | |||
| 371 | usage(_("IPv6 support not available\n")); | 468 | usage(_("IPv6 support not available\n")); |
| 372 | #endif | 469 | #endif |
| 373 | break; | 470 | break; |
| 471 | case output_format_index: { | ||
| 472 | parsed_output_format parser = mp_parse_output_format(optarg); | ||
| 473 | if (!parser.parsing_success) { | ||
| 474 | // TODO List all available formats here, maybe add anothoer usage function | ||
| 475 | printf("Invalid output format: %s\n", optarg); | ||
| 476 | exit(STATE_UNKNOWN); | ||
| 477 | } | ||
| 478 | |||
| 479 | result.config.output_format_is_set = true; | ||
| 480 | result.config.output_format = parser.output_format; | ||
| 481 | break; | ||
| 482 | } | ||
| 374 | default: | 483 | default: |
| 375 | usage5(); | 484 | usage5(); |
| 376 | } | 485 | } |
| @@ -406,11 +515,6 @@ check_ldap_config_wrapper validate_arguments(check_ldap_config_wrapper config_wr | |||
| 406 | usage4(_("Please specify the LDAP base\n")); | 515 | usage4(_("Please specify the LDAP base\n")); |
| 407 | } | 516 | } |
| 408 | 517 | ||
| 409 | if (config_wrapper.config.crit_entries != NULL || config_wrapper.config.warn_entries != NULL) { | ||
| 410 | set_thresholds(&config_wrapper.config.entries_thresholds, | ||
| 411 | config_wrapper.config.warn_entries, config_wrapper.config.crit_entries); | ||
| 412 | } | ||
| 413 | |||
| 414 | if (config_wrapper.config.ld_passwd == NULL) { | 518 | if (config_wrapper.config.ld_passwd == NULL) { |
| 415 | config_wrapper.config.ld_passwd = getenv("LDAP_PASSWORD"); | 519 | config_wrapper.config.ld_passwd = getenv("LDAP_PASSWORD"); |
| 416 | } | 520 | } |
| @@ -471,6 +575,7 @@ void print_help(void) { | |||
| 471 | printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); | 575 | printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); |
| 472 | 576 | ||
| 473 | printf(UT_VERBOSE); | 577 | printf(UT_VERBOSE); |
| 578 | printf(UT_OUTPUT_FORMAT); | ||
| 474 | 579 | ||
| 475 | printf("\n"); | 580 | printf("\n"); |
| 476 | printf("%s\n", _("Notes:")); | 581 | printf("%s\n", _("Notes:")); |
diff --git a/plugins/check_ldap.d/config.h b/plugins/check_ldap.d/config.h index c8a40610..50191725 100644 --- a/plugins/check_ldap.d/config.h +++ b/plugins/check_ldap.d/config.h | |||
| @@ -1,6 +1,7 @@ | |||
| 1 | #pragma once | 1 | #pragma once |
| 2 | 2 | ||
| 3 | #include "../../config.h" | 3 | #include "../../config.h" |
| 4 | #include "output.h" | ||
| 4 | #include "thresholds.h" | 5 | #include "thresholds.h" |
| 5 | #include <stddef.h> | 6 | #include <stddef.h> |
| 6 | 7 | ||
| @@ -25,13 +26,11 @@ typedef struct { | |||
| 25 | int ld_protocol; | 26 | int ld_protocol; |
| 26 | #endif | 27 | #endif |
| 27 | 28 | ||
| 28 | char *warn_entries; | 29 | mp_thresholds entries_thresholds; |
| 29 | char *crit_entries; | 30 | mp_thresholds connection_time_threshold; |
| 30 | thresholds *entries_thresholds; | 31 | |
| 31 | bool warn_time_set; | 32 | bool output_format_is_set; |
| 32 | double warn_time; | 33 | mp_output_format output_format; |
| 33 | bool crit_time_set; | ||
| 34 | double crit_time; | ||
| 35 | } check_ldap_config; | 34 | } check_ldap_config; |
| 36 | 35 | ||
| 37 | check_ldap_config check_ldap_config_init() { | 36 | check_ldap_config check_ldap_config_init() { |
| @@ -48,13 +47,10 @@ check_ldap_config check_ldap_config_init() { | |||
| 48 | .ld_protocol = DEFAULT_PROTOCOL, | 47 | .ld_protocol = DEFAULT_PROTOCOL, |
| 49 | #endif | 48 | #endif |
| 50 | 49 | ||
| 51 | .warn_entries = NULL, | 50 | .entries_thresholds = mp_thresholds_init(), |
| 52 | .crit_entries = NULL, | 51 | .connection_time_threshold = mp_thresholds_init(), |
| 53 | .entries_thresholds = NULL, | 52 | |
| 54 | .warn_time_set = false, | 53 | .output_format_is_set = false, |
| 55 | .warn_time = 0, | ||
| 56 | .crit_time_set = false, | ||
| 57 | .crit_time = 0, | ||
| 58 | }; | 54 | }; |
| 59 | return tmp; | 55 | return tmp; |
| 60 | } | 56 | } |
diff --git a/plugins/check_mrtg.c b/plugins/check_mrtg.c index 4a17049a..cdc2a035 100644 --- a/plugins/check_mrtg.c +++ b/plugins/check_mrtg.c | |||
| @@ -29,14 +29,18 @@ | |||
| 29 | * | 29 | * |
| 30 | *****************************************************************************/ | 30 | *****************************************************************************/ |
| 31 | 31 | ||
| 32 | const char *progname = "check_mrtg"; | ||
| 33 | const char *copyright = "1999-2024"; | ||
| 34 | const char *email = "devel@monitoring-plugins.org"; | ||
| 35 | |||
| 36 | #include "common.h" | 32 | #include "common.h" |
| 33 | #include "output.h" | ||
| 34 | #include "perfdata.h" | ||
| 35 | #include "states.h" | ||
| 36 | #include "thresholds.h" | ||
| 37 | #include "utils.h" | 37 | #include "utils.h" |
| 38 | #include "check_mrtg.d/config.h" | 38 | #include "check_mrtg.d/config.h" |
| 39 | 39 | ||
| 40 | const char *progname = "check_mrtg"; | ||
| 41 | const char *copyright = "1999-2024"; | ||
| 42 | const char *email = "devel@monitoring-plugins.org"; | ||
| 43 | |||
| 40 | typedef struct { | 44 | typedef struct { |
| 41 | int errorcode; | 45 | int errorcode; |
| 42 | check_mrtg_config config; | 46 | check_mrtg_config config; |
| @@ -62,11 +66,24 @@ int main(int argc, char **argv) { | |||
| 62 | 66 | ||
| 63 | const check_mrtg_config config = tmp_config.config; | 67 | const check_mrtg_config config = tmp_config.config; |
| 64 | 68 | ||
| 69 | if (config.output_format_is_set) { | ||
| 70 | mp_set_format(config.output_format); | ||
| 71 | } | ||
| 72 | |||
| 73 | mp_check overall = mp_check_init(); | ||
| 74 | |||
| 65 | /* open the MRTG log file for reading */ | 75 | /* open the MRTG log file for reading */ |
| 76 | mp_subcheck sc_open_mrtg_log_file = mp_subcheck_init(); | ||
| 66 | FILE *mtrg_log_file = fopen(config.log_file, "r"); | 77 | FILE *mtrg_log_file = fopen(config.log_file, "r"); |
| 67 | if (mtrg_log_file == NULL) { | 78 | if (mtrg_log_file == NULL) { |
| 68 | printf(_("Unable to open MRTG log file\n")); | 79 | xasprintf(&sc_open_mrtg_log_file.output, "unable to open MRTG log file"); |
| 69 | return STATE_UNKNOWN; | 80 | sc_open_mrtg_log_file = mp_set_subcheck_state(sc_open_mrtg_log_file, STATE_UNKNOWN); |
| 81 | mp_add_subcheck_to_check(&overall, sc_open_mrtg_log_file); | ||
| 82 | mp_exit(overall); | ||
| 83 | } else { | ||
| 84 | xasprintf(&sc_open_mrtg_log_file.output, "opened MRTG log file"); | ||
| 85 | sc_open_mrtg_log_file = mp_set_subcheck_state(sc_open_mrtg_log_file, STATE_OK); | ||
| 86 | mp_add_subcheck_to_check(&overall, sc_open_mrtg_log_file); | ||
| 70 | } | 87 | } |
| 71 | 88 | ||
| 72 | time_t timestamp = 0; | 89 | time_t timestamp = 0; |
| @@ -120,18 +137,32 @@ int main(int argc, char **argv) { | |||
| 120 | fclose(mtrg_log_file); | 137 | fclose(mtrg_log_file); |
| 121 | 138 | ||
| 122 | /* if we couldn't read enough data, return an unknown error */ | 139 | /* if we couldn't read enough data, return an unknown error */ |
| 140 | mp_subcheck sc_process_mrtg_log_file = mp_subcheck_init(); | ||
| 123 | if (line <= 2) { | 141 | if (line <= 2) { |
| 124 | printf(_("Unable to process MRTG log file\n")); | 142 | xasprintf(&sc_process_mrtg_log_file.output, "unable to process MRTG log file"); |
| 125 | return STATE_UNKNOWN; | 143 | sc_process_mrtg_log_file = mp_set_subcheck_state(sc_process_mrtg_log_file, STATE_UNKNOWN); |
| 144 | mp_exit(overall); | ||
| 145 | } else { | ||
| 146 | xasprintf(&sc_process_mrtg_log_file.output, "processed MRTG log file"); | ||
| 147 | sc_process_mrtg_log_file = mp_set_subcheck_state(sc_process_mrtg_log_file, STATE_OK); | ||
| 148 | mp_add_subcheck_to_check(&overall, sc_process_mrtg_log_file); | ||
| 126 | } | 149 | } |
| 127 | 150 | ||
| 128 | /* make sure the MRTG data isn't too old */ | 151 | /* make sure the MRTG data isn't too old */ |
| 129 | time_t current_time; | 152 | time_t current_time; |
| 130 | time(¤t_time); | 153 | time(¤t_time); |
| 154 | mp_subcheck sc_data_expired = mp_subcheck_init(); | ||
| 131 | if (config.expire_minutes > 0 && (current_time - timestamp) > (config.expire_minutes * 60)) { | 155 | if (config.expire_minutes > 0 && (current_time - timestamp) > (config.expire_minutes * 60)) { |
| 132 | printf(_("MRTG data has expired (%d minutes old)\n"), | 156 | xasprintf(&sc_data_expired.output, "MRTG data has expired (%d minutes old)", |
| 133 | (int)((current_time - timestamp) / 60)); | 157 | (int)((current_time - timestamp) / 60)); |
| 134 | return STATE_WARNING; | 158 | sc_data_expired = mp_set_subcheck_state(sc_data_expired, STATE_WARNING); |
| 159 | mp_add_subcheck_to_check(&overall, sc_data_expired); | ||
| 160 | mp_exit(overall); | ||
| 161 | } else { | ||
| 162 | xasprintf(&sc_data_expired.output, "MRTG data should be valid (%d minutes old)", | ||
| 163 | (int)((current_time - timestamp) / 60)); | ||
| 164 | sc_data_expired = mp_set_subcheck_state(sc_data_expired, STATE_OK); | ||
| 165 | mp_add_subcheck_to_check(&overall, sc_data_expired); | ||
| 135 | } | 166 | } |
| 136 | 167 | ||
| 137 | unsigned long rate = 0L; | 168 | unsigned long rate = 0L; |
| @@ -142,24 +173,27 @@ int main(int argc, char **argv) { | |||
| 142 | rate = maximum_value_rate; | 173 | rate = maximum_value_rate; |
| 143 | } | 174 | } |
| 144 | 175 | ||
| 145 | int result = STATE_OK; | 176 | mp_subcheck sc_values = mp_subcheck_init(); |
| 146 | if (config.value_critical_threshold_set && rate > config.value_critical_threshold) { | 177 | mp_perfdata pd_value = perfdata_init(); |
| 147 | result = STATE_CRITICAL; | 178 | pd_value = mp_set_pd_value(pd_value, rate); |
| 148 | } else if (config.value_warning_threshold_set && rate > config.value_warning_threshold) { | 179 | pd_value.label = config.label; |
| 149 | result = STATE_WARNING; | 180 | pd_value = mp_pd_set_thresholds(pd_value, config.values_threshold); |
| 150 | } | ||
| 151 | 181 | ||
| 152 | printf("%s. %s = %lu %s|%s\n", (config.use_average) ? _("Avg") : _("Max"), config.label, rate, | 182 | sc_values = mp_set_subcheck_state(sc_values, mp_get_pd_status(pd_value)); |
| 153 | config.units, | 183 | xasprintf(&sc_values.output, "%s. %s = %lu %s", (config.use_average) ? _("Avg") : _("Max"), |
| 154 | perfdata(config.label, (long)rate, config.units, config.value_warning_threshold_set, | 184 | config.label, rate, config.units); |
| 155 | (long)config.value_warning_threshold, config.value_critical_threshold_set, | ||
| 156 | (long)config.value_critical_threshold, 0, 0, 0, 0)); | ||
| 157 | 185 | ||
| 158 | return result; | 186 | mp_add_subcheck_to_check(&overall, sc_values); |
| 187 | |||
| 188 | mp_exit(overall); | ||
| 159 | } | 189 | } |
| 160 | 190 | ||
| 161 | /* process command-line arguments */ | 191 | /* process command-line arguments */ |
| 162 | check_mrtg_config_wrapper process_arguments(int argc, char **argv) { | 192 | check_mrtg_config_wrapper process_arguments(int argc, char **argv) { |
| 193 | enum { | ||
| 194 | output_format_index, | ||
| 195 | }; | ||
| 196 | |||
| 163 | static struct option longopts[] = {{"logfile", required_argument, 0, 'F'}, | 197 | static struct option longopts[] = {{"logfile", required_argument, 0, 'F'}, |
| 164 | {"expires", required_argument, 0, 'e'}, | 198 | {"expires", required_argument, 0, 'e'}, |
| 165 | {"aggregation", required_argument, 0, 'a'}, | 199 | {"aggregation", required_argument, 0, 'a'}, |
| @@ -171,6 +205,7 @@ check_mrtg_config_wrapper process_arguments(int argc, char **argv) { | |||
| 171 | {"variable", required_argument, 0, 'v'}, | 205 | {"variable", required_argument, 0, 'v'}, |
| 172 | {"version", no_argument, 0, 'V'}, | 206 | {"version", no_argument, 0, 'V'}, |
| 173 | {"help", no_argument, 0, 'h'}, | 207 | {"help", no_argument, 0, 'h'}, |
| 208 | {"output-format", required_argument, 0, output_format_index}, | ||
| 174 | {0, 0, 0, 0}}; | 209 | {0, 0, 0, 0}}; |
| 175 | 210 | ||
| 176 | check_mrtg_config_wrapper result = { | 211 | check_mrtg_config_wrapper result = { |
| @@ -218,14 +253,22 @@ check_mrtg_config_wrapper process_arguments(int argc, char **argv) { | |||
| 218 | usage4(_("Invalid variable number")); | 253 | usage4(_("Invalid variable number")); |
| 219 | } | 254 | } |
| 220 | break; | 255 | break; |
| 221 | case 'w': /* critical time threshold */ | 256 | case 'w': /* critical time threshold */ { |
| 222 | result.config.value_warning_threshold_set = true; | 257 | mp_range_parsed tmp = mp_parse_range_string(optarg); |
| 223 | result.config.value_warning_threshold = strtoul(optarg, NULL, 10); | 258 | if (tmp.error != MP_PARSING_SUCCES) { |
| 224 | break; | 259 | die(STATE_UNKNOWN, "failed to parse warning threshold"); |
| 225 | case 'c': /* warning time threshold */ | 260 | } |
| 226 | result.config.value_critical_threshold_set = true; | 261 | result.config.values_threshold = |
| 227 | result.config.value_critical_threshold = strtoul(optarg, NULL, 10); | 262 | mp_thresholds_set_warn(result.config.values_threshold, tmp.range); |
| 228 | break; | 263 | } break; |
| 264 | case 'c': /* warning time threshold */ { | ||
| 265 | mp_range_parsed tmp = mp_parse_range_string(optarg); | ||
| 266 | if (tmp.error != MP_PARSING_SUCCES) { | ||
| 267 | die(STATE_UNKNOWN, "failed to parse critical threshold"); | ||
| 268 | } | ||
| 269 | result.config.values_threshold = | ||
| 270 | mp_thresholds_set_crit(result.config.values_threshold, tmp.range); | ||
| 271 | } break; | ||
| 229 | case 'l': /* label */ | 272 | case 'l': /* label */ |
| 230 | result.config.label = optarg; | 273 | result.config.label = optarg; |
| 231 | break; | 274 | break; |
| @@ -240,6 +283,17 @@ check_mrtg_config_wrapper process_arguments(int argc, char **argv) { | |||
| 240 | exit(STATE_UNKNOWN); | 283 | exit(STATE_UNKNOWN); |
| 241 | case '?': /* help */ | 284 | case '?': /* help */ |
| 242 | usage5(); | 285 | usage5(); |
| 286 | case output_format_index: { | ||
| 287 | parsed_output_format parser = mp_parse_output_format(optarg); | ||
| 288 | if (!parser.parsing_success) { | ||
| 289 | printf("Invalid output format: %s\n", optarg); | ||
| 290 | exit(STATE_UNKNOWN); | ||
| 291 | } | ||
| 292 | |||
| 293 | result.config.output_format_is_set = true; | ||
| 294 | result.config.output_format = parser.output_format; | ||
| 295 | break; | ||
| 296 | } | ||
| 243 | } | 297 | } |
| 244 | } | 298 | } |
| 245 | 299 | ||
| @@ -274,14 +328,22 @@ check_mrtg_config_wrapper process_arguments(int argc, char **argv) { | |||
| 274 | } | 328 | } |
| 275 | } | 329 | } |
| 276 | 330 | ||
| 277 | if (argc > option_char && !result.config.value_warning_threshold_set) { | 331 | if (argc > option_char && !result.config.values_threshold.warning_is_set) { |
| 278 | result.config.value_warning_threshold_set = true; | 332 | mp_range_parsed tmp = mp_parse_range_string(argv[option_char++]); |
| 279 | result.config.value_warning_threshold = strtoul(argv[option_char++], NULL, 10); | 333 | if (tmp.error != MP_PARSING_SUCCES) { |
| 334 | die(STATE_UNKNOWN, "failed to parse warning threshold"); | ||
| 335 | } | ||
| 336 | result.config.values_threshold = | ||
| 337 | mp_thresholds_set_warn(result.config.values_threshold, tmp.range); | ||
| 280 | } | 338 | } |
| 281 | 339 | ||
| 282 | if (argc > option_char && !result.config.value_critical_threshold_set) { | 340 | if (argc > option_char && !result.config.values_threshold.critical_is_set) { |
| 283 | result.config.value_critical_threshold_set = true; | 341 | mp_range_parsed tmp = mp_parse_range_string(argv[option_char++]); |
| 284 | result.config.value_critical_threshold = strtoul(argv[option_char++], NULL, 10); | 342 | if (tmp.error != MP_PARSING_SUCCES) { |
| 343 | die(STATE_UNKNOWN, "failed to parse critical threshold"); | ||
| 344 | } | ||
| 345 | result.config.values_threshold = | ||
| 346 | mp_thresholds_set_crit(result.config.values_threshold, tmp.range); | ||
| 285 | } | 347 | } |
| 286 | 348 | ||
| 287 | if (argc > option_char && strlen(result.config.label) == 0) { | 349 | if (argc > option_char && strlen(result.config.label) == 0) { |
| @@ -345,6 +407,8 @@ void print_help(void) { | |||
| 345 | printf(" %s\n", _("Option units label for data (Example: Packets/Sec, Errors/Sec,")); | 407 | printf(" %s\n", _("Option units label for data (Example: Packets/Sec, Errors/Sec,")); |
| 346 | printf(" %s\n", _("\"Bytes Per Second\", \"%% Utilization\")")); | 408 | printf(" %s\n", _("\"Bytes Per Second\", \"%% Utilization\")")); |
| 347 | 409 | ||
| 410 | printf(UT_OUTPUT_FORMAT); | ||
| 411 | |||
| 348 | printf("\n"); | 412 | printf("\n"); |
| 349 | printf(" %s\n", | 413 | printf(" %s\n", |
| 350 | _("If the value exceeds the <vwl> threshold, a WARNING status is returned. If")); | 414 | _("If the value exceeds the <vwl> threshold, a WARNING status is returned. If")); |
diff --git a/plugins/check_mrtg.d/config.h b/plugins/check_mrtg.d/config.h index 96b849a2..4a5b5595 100644 --- a/plugins/check_mrtg.d/config.h +++ b/plugins/check_mrtg.d/config.h | |||
| @@ -1,6 +1,8 @@ | |||
| 1 | #pragma once | 1 | #pragma once |
| 2 | 2 | ||
| 3 | #include "../../config.h" | 3 | #include "../../config.h" |
| 4 | #include "output.h" | ||
| 5 | #include "thresholds.h" | ||
| 4 | #include <stddef.h> | 6 | #include <stddef.h> |
| 5 | #include <stdlib.h> | 7 | #include <stdlib.h> |
| 6 | 8 | ||
| @@ -12,10 +14,10 @@ typedef struct { | |||
| 12 | char *units; | 14 | char *units; |
| 13 | char *log_file; | 15 | char *log_file; |
| 14 | 16 | ||
| 15 | bool value_warning_threshold_set; | 17 | mp_thresholds values_threshold; |
| 16 | unsigned long value_warning_threshold; | 18 | |
| 17 | bool value_critical_threshold_set; | 19 | bool output_format_is_set; |
| 18 | unsigned long value_critical_threshold; | 20 | mp_output_format output_format; |
| 19 | } check_mrtg_config; | 21 | } check_mrtg_config; |
| 20 | 22 | ||
| 21 | check_mrtg_config check_mrtg_config_init() { | 23 | check_mrtg_config check_mrtg_config_init() { |
| @@ -27,10 +29,9 @@ check_mrtg_config check_mrtg_config_init() { | |||
| 27 | .units = NULL, | 29 | .units = NULL, |
| 28 | .log_file = NULL, | 30 | .log_file = NULL, |
| 29 | 31 | ||
| 30 | .value_warning_threshold_set = false, | 32 | .values_threshold = mp_thresholds_init(), |
| 31 | .value_warning_threshold = 0, | 33 | |
| 32 | .value_critical_threshold_set = false, | 34 | .output_format_is_set = false, |
| 33 | .value_critical_threshold = 0, | ||
| 34 | }; | 35 | }; |
| 35 | return tmp; | 36 | return tmp; |
| 36 | } | 37 | } |
diff --git a/plugins/check_mrtgtraf.c b/plugins/check_mrtgtraf.c index 10ce936f..46b94f57 100644 --- a/plugins/check_mrtgtraf.c +++ b/plugins/check_mrtgtraf.c | |||
| @@ -29,14 +29,18 @@ | |||
| 29 | * | 29 | * |
| 30 | *****************************************************************************/ | 30 | *****************************************************************************/ |
| 31 | 31 | ||
| 32 | const char *progname = "check_mrtgtraf"; | ||
| 33 | const char *copyright = "1999-2024"; | ||
| 34 | const char *email = "devel@monitoring-plugins.org"; | ||
| 35 | |||
| 36 | #include "check_mrtgtraf.d/config.h" | 32 | #include "check_mrtgtraf.d/config.h" |
| 37 | #include "common.h" | 33 | #include "common.h" |
| 34 | #include "output.h" | ||
| 35 | #include "perfdata.h" | ||
| 36 | #include "states.h" | ||
| 37 | #include "thresholds.h" | ||
| 38 | #include "utils.h" | 38 | #include "utils.h" |
| 39 | 39 | ||
| 40 | const char *progname = "check_mrtgtraf"; | ||
| 41 | const char *copyright = "1999-2024"; | ||
| 42 | const char *email = "devel@monitoring-plugins.org"; | ||
| 43 | |||
| 40 | typedef struct { | 44 | typedef struct { |
| 41 | int errorcode; | 45 | int errorcode; |
| 42 | check_mrtgtraf_config config; | 46 | check_mrtgtraf_config config; |
| @@ -61,10 +65,24 @@ int main(int argc, char **argv) { | |||
| 61 | 65 | ||
| 62 | const check_mrtgtraf_config config = tmp_config.config; | 66 | const check_mrtgtraf_config config = tmp_config.config; |
| 63 | 67 | ||
| 68 | if (config.output_format_is_set) { | ||
| 69 | mp_set_format(config.output_format); | ||
| 70 | } | ||
| 71 | |||
| 72 | mp_check overall = mp_check_init(); | ||
| 73 | mp_subcheck sc_open_mrtg_log_file = mp_subcheck_init(); | ||
| 74 | |||
| 64 | /* open the MRTG log file for reading */ | 75 | /* open the MRTG log file for reading */ |
| 65 | FILE *mrtg_log_file_ptr = fopen(config.log_file, "r"); | 76 | FILE *mrtg_log_file_ptr = fopen(config.log_file, "r"); |
| 66 | if (mrtg_log_file_ptr == NULL) { | 77 | if (mrtg_log_file_ptr == NULL) { |
| 67 | usage4(_("Unable to open MRTG log file")); | 78 | sc_open_mrtg_log_file = mp_set_subcheck_state(sc_open_mrtg_log_file, STATE_UNKNOWN); |
| 79 | xasprintf(&sc_open_mrtg_log_file.output, "unable to open MRTG log file"); | ||
| 80 | mp_add_subcheck_to_check(&overall, sc_open_mrtg_log_file); | ||
| 81 | mp_exit(overall); | ||
| 82 | } else { | ||
| 83 | sc_open_mrtg_log_file = mp_set_subcheck_state(sc_open_mrtg_log_file, STATE_OK); | ||
| 84 | xasprintf(&sc_open_mrtg_log_file.output, "opened MRTG log file"); | ||
| 85 | mp_add_subcheck_to_check(&overall, sc_open_mrtg_log_file); | ||
| 68 | } | 86 | } |
| 69 | 87 | ||
| 70 | time_t timestamp = 0L; | 88 | time_t timestamp = 0L; |
| @@ -75,7 +93,6 @@ int main(int argc, char **argv) { | |||
| 75 | unsigned long maximum_outgoing_rate = 0L; | 93 | unsigned long maximum_outgoing_rate = 0L; |
| 76 | int line = 0; | 94 | int line = 0; |
| 77 | while (fgets(input_buffer, MAX_INPUT_BUFFER - 1, mrtg_log_file_ptr)) { | 95 | while (fgets(input_buffer, MAX_INPUT_BUFFER - 1, mrtg_log_file_ptr)) { |
| 78 | |||
| 79 | line++; | 96 | line++; |
| 80 | 97 | ||
| 81 | /* skip the first line of the log file */ | 98 | /* skip the first line of the log file */ |
| @@ -121,11 +138,20 @@ int main(int argc, char **argv) { | |||
| 121 | /* make sure the MRTG data isn't too old */ | 138 | /* make sure the MRTG data isn't too old */ |
| 122 | time_t current_time; | 139 | time_t current_time; |
| 123 | time(¤t_time); | 140 | time(¤t_time); |
| 141 | mp_subcheck sc_expired = mp_subcheck_init(); | ||
| 124 | if ((config.expire_minutes > 0) && (current_time - timestamp) > (config.expire_minutes * 60)) { | 142 | if ((config.expire_minutes > 0) && (current_time - timestamp) > (config.expire_minutes * 60)) { |
| 125 | die(STATE_WARNING, _("MRTG data has expired (%d minutes old)\n"), | 143 | xasprintf(&sc_expired.output, "MRTG data has expired (%d minutes old)", |
| 126 | (int)((current_time - timestamp) / 60)); | 144 | (int)((current_time - timestamp) / 60)); |
| 145 | sc_expired = mp_set_subcheck_state(sc_expired, STATE_WARNING); | ||
| 146 | mp_add_subcheck_to_check(&overall, sc_expired); | ||
| 147 | mp_exit(overall); | ||
| 127 | } | 148 | } |
| 128 | 149 | ||
| 150 | xasprintf(&sc_expired.output, "MRTG data should be valid (%d minutes old)", | ||
| 151 | (int)((current_time - timestamp) / 60)); | ||
| 152 | sc_expired = mp_set_subcheck_state(sc_expired, STATE_WARNING); | ||
| 153 | mp_add_subcheck_to_check(&overall, sc_expired); | ||
| 154 | |||
| 129 | unsigned long incoming_rate = 0L; | 155 | unsigned long incoming_rate = 0L; |
| 130 | unsigned long outgoing_rate = 0L; | 156 | unsigned long outgoing_rate = 0L; |
| 131 | /* else check the incoming/outgoing rates */ | 157 | /* else check the incoming/outgoing rates */ |
| @@ -148,65 +174,72 @@ int main(int argc, char **argv) { | |||
| 148 | /* report incoming traffic in KBytes/sec */ | 174 | /* report incoming traffic in KBytes/sec */ |
| 149 | else if (incoming_rate < (1024 * 1024)) { | 175 | else if (incoming_rate < (1024 * 1024)) { |
| 150 | strcpy(incoming_speed_rating, "KB"); | 176 | strcpy(incoming_speed_rating, "KB"); |
| 151 | adjusted_incoming_rate = (double)(incoming_rate / 1024.0); | 177 | adjusted_incoming_rate = ((double)incoming_rate / 1024.0); |
| 152 | } | 178 | } |
| 153 | 179 | ||
| 154 | /* report incoming traffic in MBytes/sec */ | 180 | /* report incoming traffic in MBytes/sec */ |
| 155 | else { | 181 | else { |
| 156 | strcpy(incoming_speed_rating, "MB"); | 182 | strcpy(incoming_speed_rating, "MB"); |
| 157 | adjusted_incoming_rate = (double)(incoming_rate / 1024.0 / 1024.0); | 183 | adjusted_incoming_rate = ((double)incoming_rate / 1024.0 / 1024.0); |
| 158 | } | 184 | } |
| 159 | 185 | ||
| 160 | double adjusted_outgoing_rate = 0.0; | 186 | double adjusted_outgoing_rate = 0.0; |
| 161 | char outgoing_speed_rating[8]; | 187 | char outgoing_speed_rating[8]; |
| 162 | /* report outgoing traffic in Bytes/sec */ | ||
| 163 | if (outgoing_rate < 1024) { | 188 | if (outgoing_rate < 1024) { |
| 189 | /* report outgoing traffic in Bytes/sec */ | ||
| 164 | strcpy(outgoing_speed_rating, "B"); | 190 | strcpy(outgoing_speed_rating, "B"); |
| 165 | adjusted_outgoing_rate = (double)outgoing_rate; | 191 | adjusted_outgoing_rate = (double)outgoing_rate; |
| 166 | } | 192 | } else if (outgoing_rate < (1024 * 1024)) { |
| 167 | 193 | /* report outgoing traffic in KBytes/sec */ | |
| 168 | /* report outgoing traffic in KBytes/sec */ | ||
| 169 | else if (outgoing_rate < (1024 * 1024)) { | ||
| 170 | strcpy(outgoing_speed_rating, "KB"); | 194 | strcpy(outgoing_speed_rating, "KB"); |
| 171 | adjusted_outgoing_rate = (double)(outgoing_rate / 1024.0); | 195 | adjusted_outgoing_rate = ((double)outgoing_rate / 1024.0); |
| 172 | } | 196 | } else { |
| 173 | 197 | /* report outgoing traffic in MBytes/sec */ | |
| 174 | /* report outgoing traffic in MBytes/sec */ | ||
| 175 | else { | ||
| 176 | strcpy(outgoing_speed_rating, "MB"); | 198 | strcpy(outgoing_speed_rating, "MB"); |
| 177 | adjusted_outgoing_rate = (outgoing_rate / 1024.0 / 1024.0); | 199 | adjusted_outgoing_rate = ((double)outgoing_rate / 1024.0 / 1024.0); |
| 178 | } | 200 | } |
| 179 | 201 | ||
| 180 | int result = STATE_OK; | 202 | mp_perfdata pd_rate_in = perfdata_init(); |
| 181 | if (incoming_rate > config.incoming_critical_threshold || | 203 | pd_rate_in.label = "in"; |
| 182 | outgoing_rate > config.outgoing_critical_threshold) { | 204 | pd_rate_in = mp_set_pd_value(pd_rate_in, incoming_rate); |
| 183 | result = STATE_CRITICAL; | 205 | pd_rate_in.uom = "B"; |
| 184 | } else if (incoming_rate > config.incoming_warning_threshold || | 206 | pd_rate_in = mp_pd_set_thresholds(pd_rate_in, config.incoming_thresholds); |
| 185 | outgoing_rate > config.outgoing_warning_threshold) { | 207 | |
| 186 | result = STATE_WARNING; | 208 | mp_perfdata pd_rate_out = perfdata_init(); |
| 187 | } | 209 | pd_rate_out.label = "out"; |
| 188 | 210 | pd_rate_out = mp_set_pd_value(pd_rate_out, outgoing_rate); | |
| 189 | char *error_message; | 211 | pd_rate_out.uom = "B"; |
| 190 | xasprintf(&error_message, _("%s. In = %0.1f %s/s, %s. Out = %0.1f %s/s|%s %s\n"), | 212 | pd_rate_out = mp_pd_set_thresholds(pd_rate_out, config.outgoing_thresholds); |
| 191 | (config.use_average) ? _("Avg") : _("Max"), adjusted_incoming_rate, | 213 | |
| 192 | incoming_speed_rating, (config.use_average) ? _("Avg") : _("Max"), | 214 | mp_subcheck sc_rate_in = mp_subcheck_init(); |
| 193 | adjusted_outgoing_rate, outgoing_speed_rating, | 215 | sc_rate_in = mp_set_subcheck_state(sc_rate_in, mp_get_pd_status(pd_rate_in)); |
| 194 | fperfdata("in", adjusted_incoming_rate, incoming_speed_rating, | 216 | mp_add_perfdata_to_subcheck(&sc_rate_in, pd_rate_in); |
| 195 | (int)config.incoming_warning_threshold, config.incoming_warning_threshold, | 217 | xasprintf(&sc_rate_in.output, "%s. In = %0.1f %s/s", (config.use_average) ? _("Avg") : _("Max"), |
| 196 | (int)config.incoming_critical_threshold, config.incoming_critical_threshold, | 218 | adjusted_incoming_rate, incoming_speed_rating); |
| 197 | true, 0, false, 0), | 219 | |
| 198 | fperfdata("out", adjusted_outgoing_rate, outgoing_speed_rating, | 220 | mp_subcheck sc_rate_out = mp_subcheck_init(); |
| 199 | (int)config.outgoing_warning_threshold, config.outgoing_warning_threshold, | 221 | sc_rate_out = mp_set_subcheck_state(sc_rate_out, mp_get_pd_status(pd_rate_out)); |
| 200 | (int)config.outgoing_critical_threshold, config.outgoing_critical_threshold, | 222 | mp_add_perfdata_to_subcheck(&sc_rate_out, pd_rate_out); |
| 201 | true, 0, false, 0)); | 223 | xasprintf(&sc_rate_out.output, "%s. Out = %0.1f %s/s", |
| 202 | 224 | (config.use_average) ? _("Avg") : _("Max"), adjusted_outgoing_rate, | |
| 203 | printf(_("Traffic %s - %s\n"), state_text(result), error_message); | 225 | outgoing_speed_rating); |
| 204 | 226 | ||
| 205 | return result; | 227 | mp_subcheck sc_rate = mp_subcheck_init(); |
| 228 | xasprintf(&sc_rate.output, "Traffic"); | ||
| 229 | mp_add_subcheck_to_subcheck(&sc_rate, sc_rate_in); | ||
| 230 | mp_add_subcheck_to_subcheck(&sc_rate, sc_rate_out); | ||
| 231 | |||
| 232 | mp_add_subcheck_to_check(&overall, sc_rate); | ||
| 233 | |||
| 234 | mp_exit(overall); | ||
| 206 | } | 235 | } |
| 207 | 236 | ||
| 208 | /* process command-line arguments */ | 237 | /* process command-line arguments */ |
| 209 | check_mrtgtraf_config_wrapper process_arguments(int argc, char **argv) { | 238 | check_mrtgtraf_config_wrapper process_arguments(int argc, char **argv) { |
| 239 | enum { | ||
| 240 | output_format_index = CHAR_MAX + 1, | ||
| 241 | }; | ||
| 242 | |||
| 210 | static struct option longopts[] = {{"filename", required_argument, 0, 'F'}, | 243 | static struct option longopts[] = {{"filename", required_argument, 0, 'F'}, |
| 211 | {"expires", required_argument, 0, 'e'}, | 244 | {"expires", required_argument, 0, 'e'}, |
| 212 | {"aggregation", required_argument, 0, 'a'}, | 245 | {"aggregation", required_argument, 0, 'a'}, |
| @@ -214,6 +247,7 @@ check_mrtgtraf_config_wrapper process_arguments(int argc, char **argv) { | |||
| 214 | {"warning", required_argument, 0, 'w'}, | 247 | {"warning", required_argument, 0, 'w'}, |
| 215 | {"version", no_argument, 0, 'V'}, | 248 | {"version", no_argument, 0, 'V'}, |
| 216 | {"help", no_argument, 0, 'h'}, | 249 | {"help", no_argument, 0, 'h'}, |
| 250 | {"output-format", required_argument, 0, output_format_index}, | ||
| 217 | {0, 0, 0, 0}}; | 251 | {0, 0, 0, 0}}; |
| 218 | 252 | ||
| 219 | check_mrtgtraf_config_wrapper result = { | 253 | check_mrtgtraf_config_wrapper result = { |
| @@ -237,6 +271,14 @@ check_mrtgtraf_config_wrapper process_arguments(int argc, char **argv) { | |||
| 237 | 271 | ||
| 238 | int option_char; | 272 | int option_char; |
| 239 | int option = 0; | 273 | int option = 0; |
| 274 | unsigned long incoming_warning_threshold = 0; | ||
| 275 | unsigned long incoming_critical_threshold = 0; | ||
| 276 | unsigned long outgoing_warning_threshold = 0; | ||
| 277 | unsigned long outgoing_critical_threshold = 0; | ||
| 278 | bool incoming_warning_set = false; | ||
| 279 | bool incoming_critical_set = false; | ||
| 280 | bool outgoing_warning_set = false; | ||
| 281 | bool outgoing_critical_set = false; | ||
| 240 | while (true) { | 282 | while (true) { |
| 241 | option_char = getopt_long(argc, argv, "hVF:e:a:c:w:", longopts, &option); | 283 | option_char = getopt_long(argc, argv, "hVF:e:a:c:w:", longopts, &option); |
| 242 | 284 | ||
| @@ -254,13 +296,15 @@ check_mrtgtraf_config_wrapper process_arguments(int argc, char **argv) { | |||
| 254 | case 'a': /* aggregation (AVE or MAX) */ | 296 | case 'a': /* aggregation (AVE or MAX) */ |
| 255 | result.config.use_average = (bool)(strcmp(optarg, "MAX")); | 297 | result.config.use_average = (bool)(strcmp(optarg, "MAX")); |
| 256 | break; | 298 | break; |
| 257 | case 'c': /* warning threshold */ | 299 | case 'c': /* critical threshold */ |
| 258 | sscanf(optarg, "%lu,%lu", &result.config.incoming_critical_threshold, | 300 | sscanf(optarg, "%lu,%lu", &incoming_critical_threshold, &outgoing_critical_threshold); |
| 259 | &result.config.outgoing_critical_threshold); | 301 | incoming_critical_set = true; |
| 302 | outgoing_critical_set = true; | ||
| 260 | break; | 303 | break; |
| 261 | case 'w': /* critical threshold */ | 304 | case 'w': /* warning threshold */ |
| 262 | sscanf(optarg, "%lu,%lu", &result.config.incoming_warning_threshold, | 305 | sscanf(optarg, "%lu,%lu", &incoming_warning_threshold, &outgoing_warning_threshold); |
| 263 | &result.config.outgoing_warning_threshold); | 306 | incoming_warning_set = true; |
| 307 | incoming_critical_set = true; | ||
| 264 | break; | 308 | break; |
| 265 | case 'V': /* version */ | 309 | case 'V': /* version */ |
| 266 | print_revision(progname, NP_VERSION); | 310 | print_revision(progname, NP_VERSION); |
| @@ -270,6 +314,17 @@ check_mrtgtraf_config_wrapper process_arguments(int argc, char **argv) { | |||
| 270 | exit(STATE_UNKNOWN); | 314 | exit(STATE_UNKNOWN); |
| 271 | case '?': /* help */ | 315 | case '?': /* help */ |
| 272 | usage5(); | 316 | usage5(); |
| 317 | case output_format_index: { | ||
| 318 | parsed_output_format parser = mp_parse_output_format(optarg); | ||
| 319 | if (!parser.parsing_success) { | ||
| 320 | printf("Invalid output format: %s\n", optarg); | ||
| 321 | exit(STATE_UNKNOWN); | ||
| 322 | } | ||
| 323 | |||
| 324 | result.config.output_format_is_set = true; | ||
| 325 | result.config.output_format = parser.output_format; | ||
| 326 | break; | ||
| 327 | } | ||
| 273 | } | 328 | } |
| 274 | } | 329 | } |
| 275 | 330 | ||
| @@ -290,22 +345,62 @@ check_mrtgtraf_config_wrapper process_arguments(int argc, char **argv) { | |||
| 290 | option_char++; | 345 | option_char++; |
| 291 | } | 346 | } |
| 292 | 347 | ||
| 293 | if (argc > option_char && result.config.incoming_warning_threshold == 0) { | 348 | if (argc > option_char && incoming_warning_threshold == 0) { |
| 294 | result.config.incoming_warning_threshold = strtoul(argv[option_char++], NULL, 10); | 349 | incoming_warning_threshold = strtoul(argv[option_char++], NULL, 10); |
| 350 | incoming_warning_set = true; | ||
| 351 | } | ||
| 352 | |||
| 353 | if (argc > option_char && incoming_critical_threshold == 0) { | ||
| 354 | incoming_critical_threshold = strtoul(argv[option_char++], NULL, 10); | ||
| 355 | incoming_critical_set = true; | ||
| 356 | } | ||
| 357 | |||
| 358 | if (argc > option_char && outgoing_warning_threshold == 0) { | ||
| 359 | outgoing_warning_threshold = strtoul(argv[option_char++], NULL, 10); | ||
| 360 | outgoing_warning_set = true; | ||
| 361 | } | ||
| 362 | |||
| 363 | if (argc > option_char && outgoing_critical_threshold == 0) { | ||
| 364 | outgoing_critical_threshold = strtoul(argv[option_char++], NULL, 10); | ||
| 365 | outgoing_critical_set = true; | ||
| 366 | } | ||
| 367 | |||
| 368 | mp_range incoming_warning = mp_range_init(); | ||
| 369 | if (incoming_warning_set) { | ||
| 370 | incoming_warning = | ||
| 371 | mp_range_set_end(incoming_warning, mp_create_pd_value(incoming_warning_threshold)); | ||
| 295 | } | 372 | } |
| 296 | 373 | ||
| 297 | if (argc > option_char && result.config.incoming_critical_threshold == 0) { | 374 | result.config.incoming_thresholds = |
| 298 | result.config.incoming_critical_threshold = strtoul(argv[option_char++], NULL, 10); | 375 | mp_thresholds_set_warn(result.config.incoming_thresholds, incoming_warning); |
| 376 | |||
| 377 | mp_range incoming_critical = mp_range_init(); | ||
| 378 | if (incoming_critical_set) { | ||
| 379 | incoming_critical = | ||
| 380 | mp_range_set_end(incoming_critical, mp_create_pd_value(incoming_critical_threshold)); | ||
| 299 | } | 381 | } |
| 300 | 382 | ||
| 301 | if (argc > option_char && result.config.outgoing_warning_threshold == 0) { | 383 | result.config.incoming_thresholds = |
| 302 | result.config.outgoing_warning_threshold = strtoul(argv[option_char++], NULL, 10); | 384 | mp_thresholds_set_crit(result.config.incoming_thresholds, incoming_critical); |
| 385 | |||
| 386 | mp_range outgoing_warning = mp_range_init(); | ||
| 387 | if (outgoing_warning_set) { | ||
| 388 | outgoing_warning = | ||
| 389 | mp_range_set_end(outgoing_warning, mp_create_pd_value(outgoing_warning_threshold)); | ||
| 303 | } | 390 | } |
| 304 | 391 | ||
| 305 | if (argc > option_char && result.config.outgoing_critical_threshold == 0) { | 392 | result.config.outgoing_thresholds = |
| 306 | result.config.outgoing_critical_threshold = strtoul(argv[option_char++], NULL, 10); | 393 | mp_thresholds_set_warn(result.config.outgoing_thresholds, outgoing_warning); |
| 394 | |||
| 395 | mp_range outgoing_critical = mp_range_init(); | ||
| 396 | if (outgoing_critical_set) { | ||
| 397 | outgoing_critical = | ||
| 398 | mp_range_set_end(outgoing_critical, mp_create_pd_value(outgoing_critical_threshold)); | ||
| 307 | } | 399 | } |
| 308 | 400 | ||
| 401 | result.config.outgoing_thresholds = | ||
| 402 | mp_thresholds_set_crit(result.config.outgoing_thresholds, outgoing_critical); | ||
| 403 | |||
| 309 | return result; | 404 | return result; |
| 310 | } | 405 | } |
| 311 | 406 | ||
| @@ -340,6 +435,8 @@ void print_help(void) { | |||
| 340 | printf(" %s\n", "-c, --critical"); | 435 | printf(" %s\n", "-c, --critical"); |
| 341 | printf(" %s\n", _("Critical threshold pair <incoming>,<outgoing>")); | 436 | printf(" %s\n", _("Critical threshold pair <incoming>,<outgoing>")); |
| 342 | 437 | ||
| 438 | printf(UT_OUTPUT_FORMAT); | ||
| 439 | |||
| 343 | printf("\n"); | 440 | printf("\n"); |
| 344 | printf("%s\n", _("Notes:")); | 441 | printf("%s\n", _("Notes:")); |
| 345 | printf(" %s\n", _("- MRTG stands for Multi Router Traffic Grapher. It can be downloaded from")); | 442 | printf(" %s\n", _("- MRTG stands for Multi Router Traffic Grapher. It can be downloaded from")); |
diff --git a/plugins/check_mrtgtraf.d/config.h b/plugins/check_mrtgtraf.d/config.h index 94929ff7..d9737243 100644 --- a/plugins/check_mrtgtraf.d/config.h +++ b/plugins/check_mrtgtraf.d/config.h | |||
| @@ -1,6 +1,8 @@ | |||
| 1 | #pragma once | 1 | #pragma once |
| 2 | 2 | ||
| 3 | #include "../../config.h" | 3 | #include "../../config.h" |
| 4 | #include "output.h" | ||
| 5 | #include "thresholds.h" | ||
| 4 | #include <stddef.h> | 6 | #include <stddef.h> |
| 5 | #include <stdlib.h> | 7 | #include <stdlib.h> |
| 6 | 8 | ||
| @@ -8,11 +10,12 @@ typedef struct { | |||
| 8 | char *log_file; | 10 | char *log_file; |
| 9 | int expire_minutes; | 11 | int expire_minutes; |
| 10 | bool use_average; | 12 | bool use_average; |
| 11 | unsigned long incoming_warning_threshold; | ||
| 12 | unsigned long incoming_critical_threshold; | ||
| 13 | unsigned long outgoing_warning_threshold; | ||
| 14 | unsigned long outgoing_critical_threshold; | ||
| 15 | 13 | ||
| 14 | mp_thresholds incoming_thresholds; | ||
| 15 | mp_thresholds outgoing_thresholds; | ||
| 16 | |||
| 17 | bool output_format_is_set; | ||
| 18 | mp_output_format output_format; | ||
| 16 | } check_mrtgtraf_config; | 19 | } check_mrtgtraf_config; |
| 17 | 20 | ||
| 18 | check_mrtgtraf_config check_mrtgtraf_config_init() { | 21 | check_mrtgtraf_config check_mrtgtraf_config_init() { |
| @@ -21,10 +24,10 @@ check_mrtgtraf_config check_mrtgtraf_config_init() { | |||
| 21 | .expire_minutes = -1, | 24 | .expire_minutes = -1, |
| 22 | .use_average = true, | 25 | .use_average = true, |
| 23 | 26 | ||
| 24 | .incoming_warning_threshold = 0, | 27 | .incoming_thresholds = mp_thresholds_init(), |
| 25 | .incoming_critical_threshold = 0, | 28 | .outgoing_thresholds = mp_thresholds_init(), |
| 26 | .outgoing_warning_threshold = 0, | 29 | |
| 27 | .outgoing_critical_threshold = 0, | 30 | .output_format_is_set = false, |
| 28 | }; | 31 | }; |
| 29 | return tmp; | 32 | return tmp; |
| 30 | } | 33 | } |
diff --git a/plugins/check_mysql.c b/plugins/check_mysql.c index 9d8094c0..26730d4c 100644 --- a/plugins/check_mysql.c +++ b/plugins/check_mysql.c | |||
| @@ -96,6 +96,10 @@ int main(int argc, char **argv) { | |||
| 96 | 96 | ||
| 97 | const check_mysql_config config = tmp_config.config; | 97 | const check_mysql_config config = tmp_config.config; |
| 98 | 98 | ||
| 99 | if (config.output_format_is_set) { | ||
| 100 | mp_set_format(config.output_format); | ||
| 101 | } | ||
| 102 | |||
| 99 | MYSQL mysql; | 103 | MYSQL mysql; |
| 100 | /* initialize mysql */ | 104 | /* initialize mysql */ |
| 101 | mysql_init(&mysql); | 105 | mysql_init(&mysql); |
| @@ -341,37 +345,23 @@ int main(int argc, char **argv) { | |||
| 341 | int replica_io_field = -1; | 345 | int replica_io_field = -1; |
| 342 | int replica_sql_field = -1; | 346 | int replica_sql_field = -1; |
| 343 | int seconds_behind_field = -1; | 347 | int seconds_behind_field = -1; |
| 344 | int num_fields; | 348 | unsigned int num_fields = mysql_num_fields(res); |
| 345 | MYSQL_FIELD *fields; | 349 | MYSQL_FIELD *fields = mysql_fetch_fields(res); |
| 346 | num_fields = mysql_num_fields(res); | 350 | for (int i = 0; i < (int)num_fields; i++) { |
| 347 | fields = mysql_fetch_fields(res); | 351 | if ((strcasecmp(fields[i].name, "Slave_IO_Running") == 0) || |
| 348 | for (int i = 0; i < num_fields; i++) { | 352 | (strcasecmp(fields[i].name, "Replica_IO_Running") == 0)) { |
| 349 | if (use_deprecated_slave_status) { | 353 | replica_io_field = i; |
| 350 | if (strcmp(fields[i].name, "Slave_IO_Running") == 0) { | 354 | continue; |
| 351 | replica_io_field = i; | 355 | } |
| 352 | continue; | 356 | if ((strcasecmp(fields[i].name, "Slave_SQL_Running") == 0) || |
| 353 | } | 357 | (strcasecmp(fields[i].name, "Replica_SQL_Running") == 0)) { |
| 354 | if (strcmp(fields[i].name, "Slave_SQL_Running") == 0) { | 358 | replica_sql_field = i; |
| 355 | replica_sql_field = i; | 359 | continue; |
| 356 | continue; | 360 | } |
| 357 | } | 361 | if ((strcasecmp(fields[i].name, "Seconds_Behind_Master") == 0) || |
| 358 | if (strcmp(fields[i].name, "Seconds_Behind_Master") == 0) { | 362 | (strcasecmp(fields[i].name, "Seconds_Behind_Source") == 0)) { |
| 359 | seconds_behind_field = i; | 363 | seconds_behind_field = i; |
| 360 | continue; | 364 | continue; |
| 361 | } | ||
| 362 | } else { | ||
| 363 | if (strcmp(fields[i].name, "Replica_IO_Running") == 0) { | ||
| 364 | replica_io_field = i; | ||
| 365 | continue; | ||
| 366 | } | ||
| 367 | if (strcmp(fields[i].name, "Replica_SQL_Running") == 0) { | ||
| 368 | replica_sql_field = i; | ||
| 369 | continue; | ||
| 370 | } | ||
| 371 | if (strcmp(fields[i].name, "Seconds_Behind_Source") == 0) { | ||
| 372 | seconds_behind_field = i; | ||
| 373 | continue; | ||
| 374 | } | ||
| 375 | } | 365 | } |
| 376 | } | 366 | } |
| 377 | 367 | ||
| @@ -471,6 +461,7 @@ check_mysql_config_wrapper process_arguments(int argc, char **argv) { | |||
| 471 | 461 | ||
| 472 | enum { | 462 | enum { |
| 473 | CHECK_REPLICA_OPT = CHAR_MAX + 1, | 463 | CHECK_REPLICA_OPT = CHAR_MAX + 1, |
| 464 | output_format_index, | ||
| 474 | }; | 465 | }; |
| 475 | 466 | ||
| 476 | static struct option longopts[] = {{"hostname", required_argument, 0, 'H'}, | 467 | static struct option longopts[] = {{"hostname", required_argument, 0, 'H'}, |
| @@ -495,6 +486,7 @@ check_mysql_config_wrapper process_arguments(int argc, char **argv) { | |||
| 495 | {"cert", required_argument, 0, 'a'}, | 486 | {"cert", required_argument, 0, 'a'}, |
| 496 | {"ca-dir", required_argument, 0, 'D'}, | 487 | {"ca-dir", required_argument, 0, 'D'}, |
| 497 | {"ciphers", required_argument, 0, 'L'}, | 488 | {"ciphers", required_argument, 0, 'L'}, |
| 489 | {"output-format", required_argument, 0, output_format_index}, | ||
| 498 | {0, 0, 0, 0}}; | 490 | {0, 0, 0, 0}}; |
| 499 | 491 | ||
| 500 | check_mysql_config_wrapper result = { | 492 | check_mysql_config_wrapper result = { |
| @@ -605,6 +597,17 @@ check_mysql_config_wrapper process_arguments(int argc, char **argv) { | |||
| 605 | break; | 597 | break; |
| 606 | case '?': /* help */ | 598 | case '?': /* help */ |
| 607 | usage5(); | 599 | usage5(); |
| 600 | case output_format_index: { | ||
| 601 | parsed_output_format parser = mp_parse_output_format(optarg); | ||
| 602 | if (!parser.parsing_success) { | ||
| 603 | printf("Invalid output format: %s\n", optarg); | ||
| 604 | exit(STATE_UNKNOWN); | ||
| 605 | } | ||
| 606 | |||
| 607 | result.config.output_format_is_set = true; | ||
| 608 | result.config.output_format = parser.output_format; | ||
| 609 | break; | ||
| 610 | } | ||
| 608 | } | 611 | } |
| 609 | } | 612 | } |
| 610 | 613 | ||
| @@ -711,6 +714,8 @@ void print_help(void) { | |||
| 711 | printf(" %s\n", "-L, --ciphers=STRING"); | 714 | printf(" %s\n", "-L, --ciphers=STRING"); |
| 712 | printf(" %s\n", _("List of valid SSL ciphers")); | 715 | printf(" %s\n", _("List of valid SSL ciphers")); |
| 713 | 716 | ||
| 717 | printf(UT_OUTPUT_FORMAT); | ||
| 718 | |||
| 714 | printf("\n"); | 719 | printf("\n"); |
| 715 | printf(" %s\n", | 720 | printf(" %s\n", |
| 716 | _("There are no required arguments. By default, the local database is checked")); | 721 | _("There are no required arguments. By default, the local database is checked")); |
diff --git a/plugins/check_mysql.d/config.h b/plugins/check_mysql.d/config.h index ef086cfc..1d8c82bb 100644 --- a/plugins/check_mysql.d/config.h +++ b/plugins/check_mysql.d/config.h | |||
| @@ -1,6 +1,7 @@ | |||
| 1 | #pragma once | 1 | #pragma once |
| 2 | 2 | ||
| 3 | #include "../../config.h" | 3 | #include "../../config.h" |
| 4 | #include "output.h" | ||
| 4 | #include "thresholds.h" | 5 | #include "thresholds.h" |
| 5 | #include <stddef.h> | 6 | #include <stddef.h> |
| 6 | #include <mysql.h> | 7 | #include <mysql.h> |
| @@ -26,6 +27,8 @@ typedef struct { | |||
| 26 | 27 | ||
| 27 | mp_thresholds replica_thresholds; | 28 | mp_thresholds replica_thresholds; |
| 28 | 29 | ||
| 30 | bool output_format_is_set; | ||
| 31 | mp_output_format output_format; | ||
| 29 | } check_mysql_config; | 32 | } check_mysql_config; |
| 30 | 33 | ||
| 31 | check_mysql_config check_mysql_config_init() { | 34 | check_mysql_config check_mysql_config_init() { |
| @@ -49,6 +52,8 @@ check_mysql_config check_mysql_config_init() { | |||
| 49 | .ignore_auth = false, | 52 | .ignore_auth = false, |
| 50 | 53 | ||
| 51 | .replica_thresholds = mp_thresholds_init(), | 54 | .replica_thresholds = mp_thresholds_init(), |
| 55 | |||
| 56 | .output_format_is_set = false, | ||
| 52 | }; | 57 | }; |
| 53 | return tmp; | 58 | return tmp; |
| 54 | } | 59 | } |
diff --git a/plugins/check_mysql_query.c b/plugins/check_mysql_query.c index 8af378d5..ae6cc15d 100644 --- a/plugins/check_mysql_query.c +++ b/plugins/check_mysql_query.c | |||
| @@ -73,6 +73,10 @@ int main(int argc, char **argv) { | |||
| 73 | 73 | ||
| 74 | const check_mysql_query_config config = tmp_config.config; | 74 | const check_mysql_query_config config = tmp_config.config; |
| 75 | 75 | ||
| 76 | if (config.output_format_is_set) { | ||
| 77 | mp_set_format(config.output_format); | ||
| 78 | } | ||
| 79 | |||
| 76 | MYSQL mysql; | 80 | MYSQL mysql; |
| 77 | /* initialize mysql */ | 81 | /* initialize mysql */ |
| 78 | mysql_init(&mysql); | 82 | mysql_init(&mysql); |
| @@ -185,6 +189,10 @@ int main(int argc, char **argv) { | |||
| 185 | 189 | ||
| 186 | /* process command-line arguments */ | 190 | /* process command-line arguments */ |
| 187 | check_mysql_query_config_wrapper process_arguments(int argc, char **argv) { | 191 | check_mysql_query_config_wrapper process_arguments(int argc, char **argv) { |
| 192 | enum { | ||
| 193 | output_format_index = CHAR_MAX + 1, | ||
| 194 | }; | ||
| 195 | |||
| 188 | static struct option longopts[] = {{"hostname", required_argument, 0, 'H'}, | 196 | static struct option longopts[] = {{"hostname", required_argument, 0, 'H'}, |
| 189 | {"socket", required_argument, 0, 's'}, | 197 | {"socket", required_argument, 0, 's'}, |
| 190 | {"database", required_argument, 0, 'd'}, | 198 | {"database", required_argument, 0, 'd'}, |
| @@ -199,6 +207,7 @@ check_mysql_query_config_wrapper process_arguments(int argc, char **argv) { | |||
| 199 | {"query", required_argument, 0, 'q'}, | 207 | {"query", required_argument, 0, 'q'}, |
| 200 | {"warning", required_argument, 0, 'w'}, | 208 | {"warning", required_argument, 0, 'w'}, |
| 201 | {"critical", required_argument, 0, 'c'}, | 209 | {"critical", required_argument, 0, 'c'}, |
| 210 | {"output-format", required_argument, 0, output_format_index}, | ||
| 202 | {0, 0, 0, 0}}; | 211 | {0, 0, 0, 0}}; |
| 203 | 212 | ||
| 204 | check_mysql_query_config_wrapper result = { | 213 | check_mysql_query_config_wrapper result = { |
| @@ -282,6 +291,17 @@ check_mysql_query_config_wrapper process_arguments(int argc, char **argv) { | |||
| 282 | } break; | 291 | } break; |
| 283 | case '?': /* help */ | 292 | case '?': /* help */ |
| 284 | usage5(); | 293 | usage5(); |
| 294 | case output_format_index: { | ||
| 295 | parsed_output_format parser = mp_parse_output_format(optarg); | ||
| 296 | if (!parser.parsing_success) { | ||
| 297 | printf("Invalid output format: %s\n", optarg); | ||
| 298 | exit(STATE_UNKNOWN); | ||
| 299 | } | ||
| 300 | |||
| 301 | result.config.output_format_is_set = true; | ||
| 302 | result.config.output_format = parser.output_format; | ||
| 303 | break; | ||
| 304 | } | ||
| 285 | } | 305 | } |
| 286 | } | 306 | } |
| 287 | 307 | ||
| @@ -344,6 +364,8 @@ void print_help(void) { | |||
| 344 | printf(" ==> %s <==\n", _("IMPORTANT: THIS FORM OF AUTHENTICATION IS NOT SECURE!!!")); | 364 | printf(" ==> %s <==\n", _("IMPORTANT: THIS FORM OF AUTHENTICATION IS NOT SECURE!!!")); |
| 345 | printf(" %s\n", _("Your clear-text password could be visible as a process table entry")); | 365 | printf(" %s\n", _("Your clear-text password could be visible as a process table entry")); |
| 346 | 366 | ||
| 367 | printf(UT_OUTPUT_FORMAT); | ||
| 368 | |||
| 347 | printf("\n"); | 369 | printf("\n"); |
| 348 | printf(" %s\n", _("A query is required. The result from the query should be numeric.")); | 370 | printf(" %s\n", _("A query is required. The result from the query should be numeric.")); |
| 349 | printf(" %s\n", _("For extra security, create a user with minimal access.")); | 371 | printf(" %s\n", _("For extra security, create a user with minimal access.")); |
diff --git a/plugins/check_mysql_query.d/config.h b/plugins/check_mysql_query.d/config.h index 1c9952e5..32ab455a 100644 --- a/plugins/check_mysql_query.d/config.h +++ b/plugins/check_mysql_query.d/config.h | |||
| @@ -1,6 +1,7 @@ | |||
| 1 | #pragma once | 1 | #pragma once |
| 2 | 2 | ||
| 3 | #include "../../config.h" | 3 | #include "../../config.h" |
| 4 | #include "output.h" | ||
| 4 | #include "thresholds.h" | 5 | #include "thresholds.h" |
| 5 | #include <mysql.h> | 6 | #include <mysql.h> |
| 6 | 7 | ||
| @@ -16,6 +17,9 @@ typedef struct { | |||
| 16 | 17 | ||
| 17 | char *sql_query; | 18 | char *sql_query; |
| 18 | mp_thresholds thresholds; | 19 | mp_thresholds thresholds; |
| 20 | |||
| 21 | bool output_format_is_set; | ||
| 22 | mp_output_format output_format; | ||
| 19 | } check_mysql_query_config; | 23 | } check_mysql_query_config; |
| 20 | 24 | ||
| 21 | check_mysql_query_config check_mysql_query_config_init() { | 25 | check_mysql_query_config check_mysql_query_config_init() { |
| @@ -31,6 +35,8 @@ check_mysql_query_config check_mysql_query_config_init() { | |||
| 31 | 35 | ||
| 32 | .sql_query = NULL, | 36 | .sql_query = NULL, |
| 33 | .thresholds = mp_thresholds_init(), | 37 | .thresholds = mp_thresholds_init(), |
| 38 | |||
| 39 | .output_format_is_set = false, | ||
| 34 | }; | 40 | }; |
| 35 | return tmp; | 41 | return tmp; |
| 36 | } | 42 | } |
diff --git a/plugins/check_nt.c b/plugins/check_nt.c deleted file mode 100644 index 35ca92cd..00000000 --- a/plugins/check_nt.c +++ /dev/null | |||
| @@ -1,789 +0,0 @@ | |||
| 1 | /***************************************************************************** | ||
| 2 | * | ||
| 3 | * Monitoring check_nt plugin | ||
| 4 | * | ||
| 5 | * License: GPL | ||
| 6 | * Copyright (c) 2000-2002 Yves Rubin (rubiyz@yahoo.com) | ||
| 7 | * Copyright (c) 2003-2024 Monitoring Plugins Development Team | ||
| 8 | * | ||
| 9 | * Description: | ||
| 10 | * | ||
| 11 | * This file contains the check_nt plugin | ||
| 12 | * | ||
| 13 | * This plugin collects data from the NSClient service running on a | ||
| 14 | * Windows NT/2000/XP/2003 server. | ||
| 15 | * This plugin requires NSClient software to run on NT | ||
| 16 | * (https://nsclient.org/) | ||
| 17 | * | ||
| 18 | * | ||
| 19 | * This program is free software: you can redistribute it and/or modify | ||
| 20 | * it under the terms of the GNU General Public License as published by | ||
| 21 | * the Free Software Foundation, either version 3 of the License, or | ||
| 22 | * (at your option) any later version. | ||
| 23 | * | ||
| 24 | * This program is distributed in the hope that it will be useful, | ||
| 25 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 26 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 27 | * GNU General Public License for more details. | ||
| 28 | * | ||
| 29 | * You should have received a copy of the GNU General Public License | ||
| 30 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 31 | * | ||
| 32 | * | ||
| 33 | *****************************************************************************/ | ||
| 34 | |||
| 35 | const char *progname = "check_nt"; | ||
| 36 | const char *copyright = "2000-2024"; | ||
| 37 | const char *email = "devel@monitoring-plugins.org"; | ||
| 38 | |||
| 39 | #include "common.h" | ||
| 40 | #include "netutils.h" | ||
| 41 | #include "utils.h" | ||
| 42 | #include "check_nt.d/config.h" | ||
| 43 | |||
| 44 | enum { | ||
| 45 | MAX_VALUE_LIST = 30, | ||
| 46 | }; | ||
| 47 | |||
| 48 | static char recv_buffer[MAX_INPUT_BUFFER]; | ||
| 49 | |||
| 50 | static void fetch_data(const char *address, int port, const char *sendb); | ||
| 51 | |||
| 52 | typedef struct { | ||
| 53 | int errorcode; | ||
| 54 | check_nt_config config; | ||
| 55 | } check_nt_config_wrapper; | ||
| 56 | static check_nt_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/); | ||
| 57 | |||
| 58 | static void preparelist(char *string); | ||
| 59 | static bool strtoularray(unsigned long *array, char *string, const char *delim); | ||
| 60 | static void print_help(void); | ||
| 61 | void print_usage(void); | ||
| 62 | |||
| 63 | int main(int argc, char **argv) { | ||
| 64 | setlocale(LC_ALL, ""); | ||
| 65 | bindtextdomain(PACKAGE, LOCALEDIR); | ||
| 66 | textdomain(PACKAGE); | ||
| 67 | |||
| 68 | /* Parse extra opts if any */ | ||
| 69 | argv = np_extra_opts(&argc, argv, progname); | ||
| 70 | |||
| 71 | check_nt_config_wrapper tmp_config = process_arguments(argc, argv); | ||
| 72 | if (tmp_config.errorcode == ERROR) { | ||
| 73 | usage4(_("Could not parse arguments")); | ||
| 74 | } | ||
| 75 | |||
| 76 | const check_nt_config config = tmp_config.config; | ||
| 77 | |||
| 78 | /* initialize alarm signal handling */ | ||
| 79 | signal(SIGALRM, socket_timeout_alarm_handler); | ||
| 80 | |||
| 81 | /* set socket timeout */ | ||
| 82 | alarm(socket_timeout); | ||
| 83 | |||
| 84 | int return_code = STATE_UNKNOWN; | ||
| 85 | char *send_buffer = NULL; | ||
| 86 | char *output_message = NULL; | ||
| 87 | char *perfdata = NULL; | ||
| 88 | char *temp_string = NULL; | ||
| 89 | char *temp_string_perf = NULL; | ||
| 90 | char *description = NULL; | ||
| 91 | char *counter_unit = NULL; | ||
| 92 | char *errcvt = NULL; | ||
| 93 | unsigned long lvalue_list[MAX_VALUE_LIST]; | ||
| 94 | switch (config.vars_to_check) { | ||
| 95 | case CHECK_CLIENTVERSION: | ||
| 96 | xasprintf(&send_buffer, "%s&1", config.req_password); | ||
| 97 | fetch_data(config.server_address, config.server_port, send_buffer); | ||
| 98 | if (config.value_list != NULL && strcmp(recv_buffer, config.value_list) != 0) { | ||
| 99 | xasprintf(&output_message, _("Wrong client version - running: %s, required: %s"), | ||
| 100 | recv_buffer, config.value_list); | ||
| 101 | return_code = STATE_WARNING; | ||
| 102 | } else { | ||
| 103 | xasprintf(&output_message, "%s", recv_buffer); | ||
| 104 | return_code = STATE_OK; | ||
| 105 | } | ||
| 106 | break; | ||
| 107 | case CHECK_CPULOAD: | ||
| 108 | if (config.value_list == NULL) { | ||
| 109 | output_message = strdup(_("missing -l parameters")); | ||
| 110 | } else if (!strtoularray(lvalue_list, config.value_list, ",")) { | ||
| 111 | output_message = strdup(_("wrong -l parameter.")); | ||
| 112 | } else { | ||
| 113 | /* -l parameters is present with only integers */ | ||
| 114 | return_code = STATE_OK; | ||
| 115 | temp_string = strdup(_("CPU Load")); | ||
| 116 | temp_string_perf = strdup(" "); | ||
| 117 | |||
| 118 | /* loop until one of the parameters is wrong or not present */ | ||
| 119 | int offset = 0; | ||
| 120 | while (lvalue_list[0 + offset] > (unsigned long)0 && | ||
| 121 | lvalue_list[0 + offset] <= (unsigned long)17280 && | ||
| 122 | lvalue_list[1 + offset] > (unsigned long)0 && | ||
| 123 | lvalue_list[1 + offset] <= (unsigned long)100 && | ||
| 124 | lvalue_list[2 + offset] > (unsigned long)0 && | ||
| 125 | lvalue_list[2 + offset] <= (unsigned long)100) { | ||
| 126 | |||
| 127 | /* Send request and retrieve data */ | ||
| 128 | xasprintf(&send_buffer, "%s&2&%lu", config.req_password, lvalue_list[0 + offset]); | ||
| 129 | fetch_data(config.server_address, config.server_port, send_buffer); | ||
| 130 | |||
| 131 | unsigned long utilization = strtoul(recv_buffer, NULL, 10); | ||
| 132 | |||
| 133 | /* Check if any of the request is in a warning or critical state */ | ||
| 134 | if (utilization >= lvalue_list[2 + offset]) { | ||
| 135 | return_code = STATE_CRITICAL; | ||
| 136 | } else if (utilization >= lvalue_list[1 + offset] && return_code < STATE_WARNING) { | ||
| 137 | return_code = STATE_WARNING; | ||
| 138 | } | ||
| 139 | |||
| 140 | xasprintf(&output_message, _(" %lu%% (%lu min average)"), utilization, | ||
| 141 | lvalue_list[0 + offset]); | ||
| 142 | xasprintf(&temp_string, "%s%s", temp_string, output_message); | ||
| 143 | xasprintf(&perfdata, _(" '%lu min avg Load'=%lu%%;%lu;%lu;0;100"), | ||
| 144 | lvalue_list[0 + offset], utilization, lvalue_list[1 + offset], | ||
| 145 | lvalue_list[2 + offset]); | ||
| 146 | xasprintf(&temp_string_perf, "%s%s", temp_string_perf, perfdata); | ||
| 147 | offset += 3; /* move across the array */ | ||
| 148 | } | ||
| 149 | |||
| 150 | if (strlen(temp_string) > 10) { /* we had at least one loop */ | ||
| 151 | output_message = strdup(temp_string); | ||
| 152 | perfdata = temp_string_perf; | ||
| 153 | } else { | ||
| 154 | output_message = strdup(_("not enough values for -l parameters")); | ||
| 155 | } | ||
| 156 | } | ||
| 157 | break; | ||
| 158 | case CHECK_UPTIME: { | ||
| 159 | char *tmp_value_list = config.value_list; | ||
| 160 | if (config.value_list == NULL) { | ||
| 161 | tmp_value_list = "minutes"; | ||
| 162 | } | ||
| 163 | if (strncmp(tmp_value_list, "seconds", strlen("seconds") + 1) && | ||
| 164 | strncmp(tmp_value_list, "minutes", strlen("minutes") + 1) && | ||
| 165 | strncmp(config.value_list, "hours", strlen("hours") + 1) && | ||
| 166 | strncmp(tmp_value_list, "days", strlen("days") + 1)) { | ||
| 167 | |||
| 168 | output_message = strdup(_("wrong -l argument")); | ||
| 169 | } else { | ||
| 170 | xasprintf(&send_buffer, "%s&3", config.req_password); | ||
| 171 | fetch_data(config.server_address, config.server_port, send_buffer); | ||
| 172 | unsigned long uptime = strtoul(recv_buffer, NULL, 10); | ||
| 173 | int updays = uptime / 86400; | ||
| 174 | int uphours = (uptime % 86400) / 3600; | ||
| 175 | int upminutes = ((uptime % 86400) % 3600) / 60; | ||
| 176 | |||
| 177 | if (!strncmp(tmp_value_list, "minutes", strlen("minutes"))) { | ||
| 178 | uptime = uptime / 60; | ||
| 179 | } else if (!strncmp(tmp_value_list, "hours", strlen("hours"))) { | ||
| 180 | uptime = uptime / 3600; | ||
| 181 | } else if (!strncmp(tmp_value_list, "days", strlen("days"))) { | ||
| 182 | uptime = uptime / 86400; | ||
| 183 | } | ||
| 184 | /* else uptime in seconds, nothing to do */ | ||
| 185 | |||
| 186 | xasprintf(&output_message, | ||
| 187 | _("System Uptime - %u day(s) %u hour(s) %u minute(s) |uptime=%lu"), updays, | ||
| 188 | uphours, upminutes, uptime); | ||
| 189 | |||
| 190 | if (config.check_critical_value && uptime <= config.critical_value) { | ||
| 191 | return_code = STATE_CRITICAL; | ||
| 192 | } else if (config.check_warning_value && uptime <= config.warning_value) { | ||
| 193 | return_code = STATE_WARNING; | ||
| 194 | } else { | ||
| 195 | return_code = STATE_OK; | ||
| 196 | } | ||
| 197 | } | ||
| 198 | } break; | ||
| 199 | case CHECK_USEDDISKSPACE: | ||
| 200 | if (config.value_list == NULL) { | ||
| 201 | output_message = strdup(_("missing -l parameters")); | ||
| 202 | } else if (strlen(config.value_list) != 1) { | ||
| 203 | output_message = strdup(_("wrong -l argument")); | ||
| 204 | } else { | ||
| 205 | xasprintf(&send_buffer, "%s&4&%s", config.req_password, config.value_list); | ||
| 206 | fetch_data(config.server_address, config.server_port, send_buffer); | ||
| 207 | char *fds = strtok(recv_buffer, "&"); | ||
| 208 | char *tds = strtok(NULL, "&"); | ||
| 209 | double total_disk_space = 0; | ||
| 210 | double free_disk_space = 0; | ||
| 211 | if (fds != NULL) { | ||
| 212 | free_disk_space = atof(fds); | ||
| 213 | } | ||
| 214 | if (tds != NULL) { | ||
| 215 | total_disk_space = atof(tds); | ||
| 216 | } | ||
| 217 | |||
| 218 | if (total_disk_space > 0 && free_disk_space >= 0) { | ||
| 219 | double percent_used_space = | ||
| 220 | ((total_disk_space - free_disk_space) / total_disk_space) * 100; | ||
| 221 | double warning_used_space = ((float)config.warning_value / 100) * total_disk_space; | ||
| 222 | double critical_used_space = | ||
| 223 | ((float)config.critical_value / 100) * total_disk_space; | ||
| 224 | |||
| 225 | xasprintf( | ||
| 226 | &temp_string, | ||
| 227 | _("%s:\\ - total: %.2f Gb - used: %.2f Gb (%.0f%%) - free %.2f Gb (%.0f%%)"), | ||
| 228 | config.value_list, total_disk_space / 1073741824, | ||
| 229 | (total_disk_space - free_disk_space) / 1073741824, percent_used_space, | ||
| 230 | free_disk_space / 1073741824, (free_disk_space / total_disk_space) * 100); | ||
| 231 | xasprintf(&temp_string_perf, _("'%s:\\ Used Space'=%.2fGb;%.2f;%.2f;0.00;%.2f"), | ||
| 232 | config.value_list, (total_disk_space - free_disk_space) / 1073741824, | ||
| 233 | warning_used_space / 1073741824, critical_used_space / 1073741824, | ||
| 234 | total_disk_space / 1073741824); | ||
| 235 | |||
| 236 | if (config.check_critical_value && percent_used_space >= config.critical_value) { | ||
| 237 | return_code = STATE_CRITICAL; | ||
| 238 | } else if (config.check_warning_value && | ||
| 239 | percent_used_space >= config.warning_value) { | ||
| 240 | return_code = STATE_WARNING; | ||
| 241 | } else { | ||
| 242 | return_code = STATE_OK; | ||
| 243 | } | ||
| 244 | |||
| 245 | output_message = strdup(temp_string); | ||
| 246 | perfdata = temp_string_perf; | ||
| 247 | } else { | ||
| 248 | output_message = strdup(_("Free disk space : Invalid drive")); | ||
| 249 | return_code = STATE_UNKNOWN; | ||
| 250 | } | ||
| 251 | } | ||
| 252 | break; | ||
| 253 | case CHECK_SERVICESTATE: | ||
| 254 | case CHECK_PROCSTATE: | ||
| 255 | if (config.value_list == NULL) { | ||
| 256 | output_message = strdup(_("No service/process specified")); | ||
| 257 | } else { | ||
| 258 | preparelist( | ||
| 259 | config.value_list); /* replace , between services with & to send the request */ | ||
| 260 | xasprintf(&send_buffer, "%s&%u&%s&%s", config.req_password, | ||
| 261 | (config.vars_to_check == CHECK_SERVICESTATE) ? 5 : 6, | ||
| 262 | (config.show_all) ? "ShowAll" : "ShowFail", config.value_list); | ||
| 263 | fetch_data(config.server_address, config.server_port, send_buffer); | ||
| 264 | char *numstr = strtok(recv_buffer, "&"); | ||
| 265 | if (numstr == NULL) { | ||
| 266 | die(STATE_UNKNOWN, _("could not fetch information from server\n")); | ||
| 267 | } | ||
| 268 | return_code = atoi(numstr); | ||
| 269 | temp_string = strtok(NULL, "&"); | ||
| 270 | output_message = strdup(temp_string); | ||
| 271 | } | ||
| 272 | break; | ||
| 273 | case CHECK_MEMUSE: | ||
| 274 | xasprintf(&send_buffer, "%s&7", config.req_password); | ||
| 275 | fetch_data(config.server_address, config.server_port, send_buffer); | ||
| 276 | char *numstr = strtok(recv_buffer, "&"); | ||
| 277 | if (numstr == NULL) { | ||
| 278 | die(STATE_UNKNOWN, _("could not fetch information from server\n")); | ||
| 279 | } | ||
| 280 | double mem_commitLimit = atof(numstr); | ||
| 281 | numstr = strtok(NULL, "&"); | ||
| 282 | if (numstr == NULL) { | ||
| 283 | die(STATE_UNKNOWN, _("could not fetch information from server\n")); | ||
| 284 | } | ||
| 285 | double mem_commitByte = atof(numstr); | ||
| 286 | double percent_used_space = (mem_commitByte / mem_commitLimit) * 100; | ||
| 287 | double warning_used_space = ((float)config.warning_value / 100) * mem_commitLimit; | ||
| 288 | double critical_used_space = ((float)config.critical_value / 100) * mem_commitLimit; | ||
| 289 | |||
| 290 | /* Divisor should be 1048567, not 3044515, as we are measuring "Commit Charge" here, | ||
| 291 | which equals RAM + Pagefiles. */ | ||
| 292 | xasprintf( | ||
| 293 | &output_message, | ||
| 294 | _("Memory usage: total:%.2f MB - used: %.2f MB (%.0f%%) - free: %.2f MB (%.0f%%)"), | ||
| 295 | mem_commitLimit / 1048567, mem_commitByte / 1048567, percent_used_space, | ||
| 296 | (mem_commitLimit - mem_commitByte) / 1048567, | ||
| 297 | (mem_commitLimit - mem_commitByte) / mem_commitLimit * 100); | ||
| 298 | xasprintf(&perfdata, _("'Memory usage'=%.2fMB;%.2f;%.2f;0.00;%.2f"), | ||
| 299 | mem_commitByte / 1048567, warning_used_space / 1048567, | ||
| 300 | critical_used_space / 1048567, mem_commitLimit / 1048567); | ||
| 301 | |||
| 302 | return_code = STATE_OK; | ||
| 303 | if (config.check_critical_value && percent_used_space >= config.critical_value) { | ||
| 304 | return_code = STATE_CRITICAL; | ||
| 305 | } else if (config.check_warning_value && percent_used_space >= config.warning_value) { | ||
| 306 | return_code = STATE_WARNING; | ||
| 307 | } | ||
| 308 | |||
| 309 | break; | ||
| 310 | case CHECK_COUNTER: { | ||
| 311 | /* | ||
| 312 | CHECK_COUNTER has been modified to provide extensive perfdata information. | ||
| 313 | In order to do this, some modifications have been done to the code | ||
| 314 | and some constraints have been introduced. | ||
| 315 | |||
| 316 | 1) For the sake of simplicity of the code, perfdata information will only be | ||
| 317 | provided when the "description" field is added. | ||
| 318 | |||
| 319 | 2) If the counter you're going to measure is percent-based, the code will detect | ||
| 320 | the percent sign in its name and will attribute minimum (0%) and maximum (100%) | ||
| 321 | values automagically, as well the "%" sign to graph units. | ||
| 322 | |||
| 323 | 3) OTOH, if the counter is "absolute", you'll have to provide the following | ||
| 324 | the counter unit - that is, the dimensions of the counter you're getting. Examples: | ||
| 325 | pages/s, packets transferred, etc. | ||
| 326 | |||
| 327 | 4) If you want, you may provide the minimum and maximum values to expect. They aren't | ||
| 328 | mandatory, but once specified they MUST have the same order of magnitude and units of -w and | ||
| 329 | -c; otherwise. strange things will happen when you make graphs of your data. | ||
| 330 | */ | ||
| 331 | |||
| 332 | double counter_value = 0.0; | ||
| 333 | if (config.value_list == NULL) { | ||
| 334 | output_message = strdup(_("No counter specified")); | ||
| 335 | } else { | ||
| 336 | preparelist( | ||
| 337 | config.value_list); /* replace , between services with & to send the request */ | ||
| 338 | bool isPercent = (strchr(config.value_list, '%') != NULL); | ||
| 339 | |||
| 340 | strtok(config.value_list, "&"); /* burn the first parameters */ | ||
| 341 | description = strtok(NULL, "&"); | ||
| 342 | counter_unit = strtok(NULL, "&"); | ||
| 343 | xasprintf(&send_buffer, "%s&8&%s", config.req_password, config.value_list); | ||
| 344 | fetch_data(config.server_address, config.server_port, send_buffer); | ||
| 345 | counter_value = atof(recv_buffer); | ||
| 346 | |||
| 347 | bool allRight = false; | ||
| 348 | if (description == NULL) { | ||
| 349 | xasprintf(&output_message, "%.f", counter_value); | ||
| 350 | } else if (isPercent) { | ||
| 351 | counter_unit = strdup("%"); | ||
| 352 | allRight = true; | ||
| 353 | } | ||
| 354 | |||
| 355 | char *minval = NULL; | ||
| 356 | char *maxval = NULL; | ||
| 357 | double fminval = 0; | ||
| 358 | double fmaxval = 0; | ||
| 359 | if ((counter_unit != NULL) && (!allRight)) { | ||
| 360 | minval = strtok(NULL, "&"); | ||
| 361 | maxval = strtok(NULL, "&"); | ||
| 362 | |||
| 363 | /* All parameters specified. Let's check the numbers */ | ||
| 364 | |||
| 365 | fminval = (minval != NULL) ? strtod(minval, &errcvt) : -1; | ||
| 366 | fmaxval = (minval != NULL) ? strtod(maxval, &errcvt) : -1; | ||
| 367 | |||
| 368 | if ((fminval == 0) && (minval == errcvt)) { | ||
| 369 | output_message = strdup(_("Minimum value contains non-numbers")); | ||
| 370 | } else { | ||
| 371 | if ((fmaxval == 0) && (maxval == errcvt)) { | ||
| 372 | output_message = strdup(_("Maximum value contains non-numbers")); | ||
| 373 | } else { | ||
| 374 | allRight = true; /* Everything is OK. */ | ||
| 375 | } | ||
| 376 | } | ||
| 377 | } else if ((counter_unit == NULL) && (description != NULL)) { | ||
| 378 | output_message = strdup(_("No unit counter specified")); | ||
| 379 | } | ||
| 380 | |||
| 381 | if (allRight) { | ||
| 382 | /* Let's format the output string, finally... */ | ||
| 383 | if (strstr(description, "%") == NULL) { | ||
| 384 | xasprintf(&output_message, "%s = %.2f %s", description, counter_value, | ||
| 385 | counter_unit); | ||
| 386 | } else { | ||
| 387 | /* has formatting, will segv if wrong */ | ||
| 388 | xasprintf(&output_message, description, counter_value); | ||
| 389 | } | ||
| 390 | xasprintf(&output_message, "%s |", output_message); | ||
| 391 | xasprintf(&output_message, "%s %s", output_message, | ||
| 392 | fperfdata(description, counter_value, counter_unit, 1, | ||
| 393 | config.warning_value, 1, config.critical_value, | ||
| 394 | (!(isPercent) && (minval != NULL)), fminval, | ||
| 395 | (!(isPercent) && (minval != NULL)), fmaxval)); | ||
| 396 | } | ||
| 397 | } | ||
| 398 | |||
| 399 | if (config.critical_value > config.warning_value) { /* Normal thresholds */ | ||
| 400 | if (config.check_critical_value && counter_value >= config.critical_value) { | ||
| 401 | return_code = STATE_CRITICAL; | ||
| 402 | } else if (config.check_warning_value && counter_value >= config.warning_value) { | ||
| 403 | return_code = STATE_WARNING; | ||
| 404 | } else { | ||
| 405 | return_code = STATE_OK; | ||
| 406 | } | ||
| 407 | } else { /* inverse thresholds */ | ||
| 408 | return_code = STATE_OK; | ||
| 409 | if (config.check_critical_value && counter_value <= config.critical_value) { | ||
| 410 | return_code = STATE_CRITICAL; | ||
| 411 | } else if (config.check_warning_value && counter_value <= config.warning_value) { | ||
| 412 | return_code = STATE_WARNING; | ||
| 413 | } | ||
| 414 | } | ||
| 415 | } break; | ||
| 416 | case CHECK_FILEAGE: | ||
| 417 | if (config.value_list == NULL) { | ||
| 418 | output_message = strdup(_("No counter specified")); | ||
| 419 | } else { | ||
| 420 | preparelist( | ||
| 421 | config.value_list); /* replace , between services with & to send the request */ | ||
| 422 | xasprintf(&send_buffer, "%s&9&%s", config.req_password, config.value_list); | ||
| 423 | fetch_data(config.server_address, config.server_port, send_buffer); | ||
| 424 | unsigned long age_in_minutes = atoi(strtok(recv_buffer, "&")); | ||
| 425 | description = strtok(NULL, "&"); | ||
| 426 | output_message = strdup(description); | ||
| 427 | |||
| 428 | if (config.critical_value > config.warning_value) { /* Normal thresholds */ | ||
| 429 | if (config.check_critical_value && age_in_minutes >= config.critical_value) { | ||
| 430 | return_code = STATE_CRITICAL; | ||
| 431 | } else if (config.check_warning_value && age_in_minutes >= config.warning_value) { | ||
| 432 | return_code = STATE_WARNING; | ||
| 433 | } else { | ||
| 434 | return_code = STATE_OK; | ||
| 435 | } | ||
| 436 | } else { /* inverse thresholds */ | ||
| 437 | if (config.check_critical_value && age_in_minutes <= config.critical_value) { | ||
| 438 | return_code = STATE_CRITICAL; | ||
| 439 | } else if (config.check_warning_value && age_in_minutes <= config.warning_value) { | ||
| 440 | return_code = STATE_WARNING; | ||
| 441 | } else { | ||
| 442 | return_code = STATE_OK; | ||
| 443 | } | ||
| 444 | } | ||
| 445 | } | ||
| 446 | break; | ||
| 447 | |||
| 448 | case CHECK_INSTANCES: | ||
| 449 | if (config.value_list == NULL) { | ||
| 450 | output_message = strdup(_("No counter specified")); | ||
| 451 | } else { | ||
| 452 | xasprintf(&send_buffer, "%s&10&%s", config.req_password, config.value_list); | ||
| 453 | fetch_data(config.server_address, config.server_port, send_buffer); | ||
| 454 | if (!strncmp(recv_buffer, "ERROR", 5)) { | ||
| 455 | printf("NSClient - %s\n", recv_buffer); | ||
| 456 | exit(STATE_UNKNOWN); | ||
| 457 | } | ||
| 458 | xasprintf(&output_message, "%s", recv_buffer); | ||
| 459 | return_code = STATE_OK; | ||
| 460 | } | ||
| 461 | break; | ||
| 462 | |||
| 463 | case CHECK_NONE: | ||
| 464 | default: | ||
| 465 | usage4(_("Please specify a variable to check")); | ||
| 466 | break; | ||
| 467 | } | ||
| 468 | |||
| 469 | /* reset timeout */ | ||
| 470 | alarm(0); | ||
| 471 | |||
| 472 | if (perfdata == NULL) { | ||
| 473 | printf("%s\n", output_message); | ||
| 474 | } else { | ||
| 475 | printf("%s | %s\n", output_message, perfdata); | ||
| 476 | } | ||
| 477 | return return_code; | ||
| 478 | } | ||
| 479 | |||
| 480 | /* process command-line arguments */ | ||
| 481 | check_nt_config_wrapper process_arguments(int argc, char **argv) { | ||
| 482 | static struct option longopts[] = {{"port", required_argument, 0, 'p'}, | ||
| 483 | {"timeout", required_argument, 0, 't'}, | ||
| 484 | {"critical", required_argument, 0, 'c'}, | ||
| 485 | {"warning", required_argument, 0, 'w'}, | ||
| 486 | {"variable", required_argument, 0, 'v'}, | ||
| 487 | {"hostname", required_argument, 0, 'H'}, | ||
| 488 | {"params", required_argument, 0, 'l'}, | ||
| 489 | {"secret", required_argument, 0, 's'}, | ||
| 490 | {"display", required_argument, 0, 'd'}, | ||
| 491 | {"unknown-timeout", no_argument, 0, 'u'}, | ||
| 492 | {"version", no_argument, 0, 'V'}, | ||
| 493 | {"help", no_argument, 0, 'h'}, | ||
| 494 | {0, 0, 0, 0}}; | ||
| 495 | |||
| 496 | check_nt_config_wrapper result = { | ||
| 497 | .errorcode = OK, | ||
| 498 | .config = check_nt_config_init(), | ||
| 499 | }; | ||
| 500 | |||
| 501 | /* no options were supplied */ | ||
| 502 | if (argc < 2) { | ||
| 503 | result.errorcode = ERROR; | ||
| 504 | return result; | ||
| 505 | } | ||
| 506 | |||
| 507 | /* backwards compatibility */ | ||
| 508 | if (!is_option(argv[1])) { | ||
| 509 | result.config.server_address = strdup(argv[1]); | ||
| 510 | argv[1] = argv[0]; | ||
| 511 | argv = &argv[1]; | ||
| 512 | argc--; | ||
| 513 | } | ||
| 514 | |||
| 515 | for (int index = 1; index < argc; index++) { | ||
| 516 | if (strcmp("-to", argv[index]) == 0) { | ||
| 517 | strcpy(argv[index], "-t"); | ||
| 518 | } else if (strcmp("-wv", argv[index]) == 0) { | ||
| 519 | strcpy(argv[index], "-w"); | ||
| 520 | } else if (strcmp("-cv", argv[index]) == 0) { | ||
| 521 | strcpy(argv[index], "-c"); | ||
| 522 | } | ||
| 523 | } | ||
| 524 | |||
| 525 | int option = 0; | ||
| 526 | while (true) { | ||
| 527 | int option_index = getopt_long(argc, argv, "+hVH:t:c:w:p:v:l:s:d:u", longopts, &option); | ||
| 528 | |||
| 529 | if (option_index == -1 || option_index == EOF || option_index == 1) { | ||
| 530 | break; | ||
| 531 | } | ||
| 532 | |||
| 533 | switch (option_index) { | ||
| 534 | case '?': /* print short usage statement if args not parsable */ | ||
| 535 | usage5(); | ||
| 536 | case 'h': /* help */ | ||
| 537 | print_help(); | ||
| 538 | exit(STATE_UNKNOWN); | ||
| 539 | case 'V': /* version */ | ||
| 540 | print_revision(progname, NP_VERSION); | ||
| 541 | exit(STATE_UNKNOWN); | ||
| 542 | case 'H': /* hostname */ | ||
| 543 | result.config.server_address = optarg; | ||
| 544 | break; | ||
| 545 | case 's': /* password */ | ||
| 546 | result.config.req_password = optarg; | ||
| 547 | break; | ||
| 548 | case 'p': /* port */ | ||
| 549 | if (is_intnonneg(optarg)) { | ||
| 550 | result.config.server_port = atoi(optarg); | ||
| 551 | } else { | ||
| 552 | die(STATE_UNKNOWN, _("Server port must be an integer\n")); | ||
| 553 | } | ||
| 554 | break; | ||
| 555 | case 'v': | ||
| 556 | if (strlen(optarg) < 4) { | ||
| 557 | result.errorcode = ERROR; | ||
| 558 | return result; | ||
| 559 | } | ||
| 560 | if (!strcmp(optarg, "CLIENTVERSION")) { | ||
| 561 | result.config.vars_to_check = CHECK_CLIENTVERSION; | ||
| 562 | } else if (!strcmp(optarg, "CPULOAD")) { | ||
| 563 | result.config.vars_to_check = CHECK_CPULOAD; | ||
| 564 | } else if (!strcmp(optarg, "UPTIME")) { | ||
| 565 | result.config.vars_to_check = CHECK_UPTIME; | ||
| 566 | } else if (!strcmp(optarg, "USEDDISKSPACE")) { | ||
| 567 | result.config.vars_to_check = CHECK_USEDDISKSPACE; | ||
| 568 | } else if (!strcmp(optarg, "SERVICESTATE")) { | ||
| 569 | result.config.vars_to_check = CHECK_SERVICESTATE; | ||
| 570 | } else if (!strcmp(optarg, "PROCSTATE")) { | ||
| 571 | result.config.vars_to_check = CHECK_PROCSTATE; | ||
| 572 | } else if (!strcmp(optarg, "MEMUSE")) { | ||
| 573 | result.config.vars_to_check = CHECK_MEMUSE; | ||
| 574 | } else if (!strcmp(optarg, "COUNTER")) { | ||
| 575 | result.config.vars_to_check = CHECK_COUNTER; | ||
| 576 | } else if (!strcmp(optarg, "FILEAGE")) { | ||
| 577 | result.config.vars_to_check = CHECK_FILEAGE; | ||
| 578 | } else if (!strcmp(optarg, "INSTANCES")) { | ||
| 579 | result.config.vars_to_check = CHECK_INSTANCES; | ||
| 580 | } else { | ||
| 581 | result.errorcode = ERROR; | ||
| 582 | return result; | ||
| 583 | } | ||
| 584 | break; | ||
| 585 | case 'l': /* value list */ | ||
| 586 | result.config.value_list = optarg; | ||
| 587 | break; | ||
| 588 | case 'w': /* warning threshold */ | ||
| 589 | result.config.warning_value = strtoul(optarg, NULL, 10); | ||
| 590 | result.config.check_warning_value = true; | ||
| 591 | break; | ||
| 592 | case 'c': /* critical threshold */ | ||
| 593 | result.config.critical_value = strtoul(optarg, NULL, 10); | ||
| 594 | result.config.check_critical_value = true; | ||
| 595 | break; | ||
| 596 | case 'd': /* Display select for services */ | ||
| 597 | if (!strcmp(optarg, "SHOWALL")) { | ||
| 598 | result.config.show_all = true; | ||
| 599 | } | ||
| 600 | break; | ||
| 601 | case 'u': | ||
| 602 | socket_timeout_state = STATE_UNKNOWN; | ||
| 603 | break; | ||
| 604 | case 't': /* timeout */ | ||
| 605 | socket_timeout = atoi(optarg); | ||
| 606 | if (socket_timeout <= 0) { | ||
| 607 | result.errorcode = ERROR; | ||
| 608 | return result; | ||
| 609 | } | ||
| 610 | } | ||
| 611 | } | ||
| 612 | if (result.config.server_address == NULL) { | ||
| 613 | usage4(_("You must provide a server address or host name")); | ||
| 614 | } | ||
| 615 | |||
| 616 | if (result.config.vars_to_check == CHECK_NONE) { | ||
| 617 | result.errorcode = ERROR; | ||
| 618 | return result; | ||
| 619 | } | ||
| 620 | |||
| 621 | if (result.config.req_password == NULL) { | ||
| 622 | result.config.req_password = strdup(_("None")); | ||
| 623 | } | ||
| 624 | |||
| 625 | return result; | ||
| 626 | } | ||
| 627 | |||
| 628 | void fetch_data(const char *address, int port, const char *sendb) { | ||
| 629 | int result = process_tcp_request(address, port, sendb, recv_buffer, sizeof(recv_buffer)); | ||
| 630 | |||
| 631 | if (result != STATE_OK) { | ||
| 632 | die(result, _("could not fetch information from server\n")); | ||
| 633 | } | ||
| 634 | |||
| 635 | if (!strncmp(recv_buffer, "ERROR", 5)) { | ||
| 636 | die(STATE_UNKNOWN, "NSClient - %s\n", recv_buffer); | ||
| 637 | } | ||
| 638 | } | ||
| 639 | |||
| 640 | bool strtoularray(unsigned long *array, char *string, const char *delim) { | ||
| 641 | /* split a <delim> delimited string into a long array */ | ||
| 642 | for (int idx = 0; idx < MAX_VALUE_LIST; idx++) { | ||
| 643 | array[idx] = 0; | ||
| 644 | } | ||
| 645 | |||
| 646 | int idx = 0; | ||
| 647 | for (char *t1 = strtok(string, delim); t1 != NULL; t1 = strtok(NULL, delim)) { | ||
| 648 | if (is_numeric(t1) && idx < MAX_VALUE_LIST) { | ||
| 649 | array[idx] = strtoul(t1, NULL, 10); | ||
| 650 | idx++; | ||
| 651 | } else { | ||
| 652 | return false; | ||
| 653 | } | ||
| 654 | } | ||
| 655 | return true; | ||
| 656 | } | ||
| 657 | |||
| 658 | void preparelist(char *string) { | ||
| 659 | /* Replace all , with & which is the delimiter for the request */ | ||
| 660 | for (int i = 0; (size_t)i < strlen(string); i++) { | ||
| 661 | if (string[i] == ',') { | ||
| 662 | string[i] = '&'; | ||
| 663 | } | ||
| 664 | } | ||
| 665 | } | ||
| 666 | |||
| 667 | void print_help(void) { | ||
| 668 | print_revision(progname, NP_VERSION); | ||
| 669 | |||
| 670 | printf("Copyright (c) 2000 Yves Rubin (rubiyz@yahoo.com)\n"); | ||
| 671 | printf(COPYRIGHT, copyright, email); | ||
| 672 | |||
| 673 | printf("%s\n", _("This plugin collects data from the NSClient service running on a")); | ||
| 674 | printf("%s\n", _("Windows NT/2000/XP/2003 server.")); | ||
| 675 | |||
| 676 | printf("\n\n"); | ||
| 677 | |||
| 678 | print_usage(); | ||
| 679 | |||
| 680 | printf(UT_HELP_VRSN); | ||
| 681 | printf(UT_EXTRA_OPTS); | ||
| 682 | |||
| 683 | printf("%s\n", _("Options:")); | ||
| 684 | printf(" %s\n", "-H, --hostname=HOST"); | ||
| 685 | printf(" %s\n", _("Name of the host to check")); | ||
| 686 | printf(" %s\n", "-p, --port=INTEGER"); | ||
| 687 | printf(" %s", _("Optional port number (default: ")); | ||
| 688 | printf("%d)\n", PORT); | ||
| 689 | printf(" %s\n", "-s, --secret=<password>"); | ||
| 690 | printf(" %s\n", _("Password needed for the request")); | ||
| 691 | printf(" %s\n", "-w, --warning=INTEGER"); | ||
| 692 | printf(" %s\n", _("Threshold which will result in a warning status")); | ||
| 693 | printf(" %s\n", "-c, --critical=INTEGER"); | ||
| 694 | printf(" %s\n", _("Threshold which will result in a critical status")); | ||
| 695 | printf(" %s\n", "-t, --timeout=INTEGER"); | ||
| 696 | printf(" %s", _("Seconds before connection attempt times out (default: ")); | ||
| 697 | printf(" %s\n", "-l, --params=<parameters>"); | ||
| 698 | printf(" %s", _("Parameters passed to specified check (see below)")); | ||
| 699 | printf(" %s\n", "-d, --display={SHOWALL}"); | ||
| 700 | printf(" %s", _("Display options (currently only SHOWALL works)")); | ||
| 701 | printf(" %s\n", "-u, --unknown-timeout"); | ||
| 702 | printf(" %s", _("Return UNKNOWN on timeouts")); | ||
| 703 | printf("%d)\n", DEFAULT_SOCKET_TIMEOUT); | ||
| 704 | printf(" %s\n", "-h, --help"); | ||
| 705 | printf(" %s\n", _("Print this help screen")); | ||
| 706 | printf(" %s\n", "-V, --version"); | ||
| 707 | printf(" %s\n", _("Print version information")); | ||
| 708 | printf(" %s\n", "-v, --variable=STRING"); | ||
| 709 | printf(" %s\n\n", _("Variable to check")); | ||
| 710 | printf("%s\n", _("Valid variables are:")); | ||
| 711 | printf(" %s", "CLIENTVERSION ="); | ||
| 712 | printf(" %s\n", _("Get the NSClient version")); | ||
| 713 | printf(" %s\n", _("If -l <version> is specified, will return warning if versions differ.")); | ||
| 714 | printf(" %s\n", "CPULOAD ="); | ||
| 715 | printf(" %s\n", _("Average CPU load on last x minutes.")); | ||
| 716 | printf(" %s\n", _("Request a -l parameter with the following syntax:")); | ||
| 717 | printf(" %s\n", _("-l <minutes range>,<warning threshold>,<critical threshold>.")); | ||
| 718 | printf(" %s\n", _("<minute range> should be less than 24*60.")); | ||
| 719 | printf(" %s\n", _("Thresholds are percentage and up to 10 requests can be done in one shot.")); | ||
| 720 | printf(" %s\n", "ie: -l 60,90,95,120,90,95"); | ||
| 721 | printf(" %s\n", "UPTIME ="); | ||
| 722 | printf(" %s\n", _("Get the uptime of the machine.")); | ||
| 723 | printf(" %s\n", _("-l <unit> ")); | ||
| 724 | printf(" %s\n", _("<unit> = seconds, minutes, hours, or days. (default: minutes)")); | ||
| 725 | printf(" %s\n", _("Thresholds will use the unit specified above.")); | ||
| 726 | printf(" %s\n", "USEDDISKSPACE ="); | ||
| 727 | printf(" %s\n", _("Size and percentage of disk use.")); | ||
| 728 | printf(" %s\n", _("Request a -l parameter containing the drive letter only.")); | ||
| 729 | printf(" %s\n", _("Warning and critical thresholds can be specified with -w and -c.")); | ||
| 730 | printf(" %s\n", "MEMUSE ="); | ||
| 731 | printf(" %s\n", _("Memory use.")); | ||
| 732 | printf(" %s\n", _("Warning and critical thresholds can be specified with -w and -c.")); | ||
| 733 | printf(" %s\n", "SERVICESTATE ="); | ||
| 734 | printf(" %s\n", _("Check the state of one or several services.")); | ||
| 735 | printf(" %s\n", _("Request a -l parameters with the following syntax:")); | ||
| 736 | printf(" %s\n", _("-l <service1>,<service2>,<service3>,...")); | ||
| 737 | printf(" %s\n", _("You can specify -d SHOWALL in case you want to see working services")); | ||
| 738 | printf(" %s\n", _("in the returned string.")); | ||
| 739 | printf(" %s\n", "PROCSTATE ="); | ||
| 740 | printf(" %s\n", _("Check if one or several process are running.")); | ||
| 741 | printf(" %s\n", _("Same syntax as SERVICESTATE.")); | ||
| 742 | printf(" %s\n", "COUNTER ="); | ||
| 743 | printf(" %s\n", _("Check any performance counter of Windows NT/2000.")); | ||
| 744 | printf(" %s\n", _("Request a -l parameters with the following syntax:")); | ||
| 745 | printf(" %s\n", _("-l \"\\\\<performance object>\\\\counter\",\"<description>")); | ||
| 746 | printf(" %s\n", _("The <description> parameter is optional and is given to a printf ")); | ||
| 747 | printf(" %s\n", _("output command which requires a float parameter.")); | ||
| 748 | printf(" %s\n", _("If <description> does not include \"%%\", it is used as a label.")); | ||
| 749 | printf(" %s\n", _("Some examples:")); | ||
| 750 | printf(" %s\n", "\"Paging file usage is %%.2f %%%%\""); | ||
| 751 | printf(" %s\n", "\"%%.f %%%% paging file used.\""); | ||
| 752 | printf(" %s\n", "INSTANCES ="); | ||
| 753 | printf(" %s\n", _("Check any performance counter object of Windows NT/2000.")); | ||
| 754 | printf(" %s\n", | ||
| 755 | _("Syntax: check_nt -H <hostname> -p <port> -v INSTANCES -l <counter object>")); | ||
| 756 | printf(" %s\n", _("<counter object> is a Windows Perfmon Counter object (eg. Process),")); | ||
| 757 | printf(" %s\n", _("if it is two words, it should be enclosed in quotes")); | ||
| 758 | printf(" %s\n", _("The returned results will be a comma-separated list of instances on ")); | ||
| 759 | printf(" %s\n", _(" the selected computer for that object.")); | ||
| 760 | printf(" %s\n", | ||
| 761 | _("The purpose of this is to be run from command line to determine what instances")); | ||
| 762 | printf(" %s\n", | ||
| 763 | _(" are available for monitoring without having to log onto the Windows server")); | ||
| 764 | printf(" %s\n", _(" to run Perfmon directly.")); | ||
| 765 | printf(" %s\n", | ||
| 766 | _("It can also be used in scripts that automatically create the monitoring service")); | ||
| 767 | printf(" %s\n", _(" configuration files.")); | ||
| 768 | printf(" %s\n", _("Some examples:")); | ||
| 769 | printf(" %s\n\n", _("check_nt -H 192.168.1.1 -p 1248 -v INSTANCES -l Process")); | ||
| 770 | |||
| 771 | printf("%s\n", _("Notes:")); | ||
| 772 | printf(" %s\n", | ||
| 773 | _("- The NSClient service should be running on the server to get any information")); | ||
| 774 | printf(" %s\n", "(http://nsclient.ready2run.nl)."); | ||
| 775 | printf(" %s\n", _("- Critical thresholds should be lower than warning thresholds")); | ||
| 776 | printf(" %s\n", _("- Default port 1248 is sometimes in use by other services. The error")); | ||
| 777 | printf(" %s\n", | ||
| 778 | _("output when this happens contains \"Cannot map xxxxx to protocol number\".")); | ||
| 779 | printf(" %s\n", _("One fix for this is to change the port to something else on check_nt ")); | ||
| 780 | printf(" %s\n", _("and on the client service it\'s connecting to.")); | ||
| 781 | |||
| 782 | printf(UT_SUPPORT); | ||
| 783 | } | ||
| 784 | |||
| 785 | void print_usage(void) { | ||
| 786 | printf("%s\n", _("Usage:")); | ||
| 787 | printf("%s -H host -v variable [-p port] [-w warning] [-c critical]\n", progname); | ||
| 788 | printf("[-l params] [-d SHOWALL] [-u] [-t timeout]\n"); | ||
| 789 | } | ||
diff --git a/plugins/check_nt.d/config.h b/plugins/check_nt.d/config.h deleted file mode 100644 index 431889cb..00000000 --- a/plugins/check_nt.d/config.h +++ /dev/null | |||
| @@ -1,53 +0,0 @@ | |||
| 1 | #pragma once | ||
| 2 | |||
| 3 | #include "../../config.h" | ||
| 4 | #include <stddef.h> | ||
| 5 | |||
| 6 | enum { | ||
| 7 | PORT = 1248, | ||
| 8 | }; | ||
| 9 | |||
| 10 | enum checkvars { | ||
| 11 | CHECK_NONE, | ||
| 12 | CHECK_CLIENTVERSION, | ||
| 13 | CHECK_CPULOAD, | ||
| 14 | CHECK_UPTIME, | ||
| 15 | CHECK_USEDDISKSPACE, | ||
| 16 | CHECK_SERVICESTATE, | ||
| 17 | CHECK_PROCSTATE, | ||
| 18 | CHECK_MEMUSE, | ||
| 19 | CHECK_COUNTER, | ||
| 20 | CHECK_FILEAGE, | ||
| 21 | CHECK_INSTANCES | ||
| 22 | }; | ||
| 23 | |||
| 24 | typedef struct { | ||
| 25 | char *server_address; | ||
| 26 | int server_port; | ||
| 27 | char *req_password; | ||
| 28 | enum checkvars vars_to_check; | ||
| 29 | bool show_all; | ||
| 30 | char *value_list; | ||
| 31 | bool check_warning_value; | ||
| 32 | unsigned long warning_value; | ||
| 33 | bool check_critical_value; | ||
| 34 | unsigned long critical_value; | ||
| 35 | } check_nt_config; | ||
| 36 | |||
| 37 | check_nt_config check_nt_config_init() { | ||
| 38 | check_nt_config tmp = { | ||
| 39 | .server_address = NULL, | ||
| 40 | .server_port = PORT, | ||
| 41 | .req_password = NULL, | ||
| 42 | |||
| 43 | .vars_to_check = CHECK_NONE, | ||
| 44 | .show_all = false, | ||
| 45 | .value_list = NULL, | ||
| 46 | |||
| 47 | .check_warning_value = false, | ||
| 48 | .warning_value = 0, | ||
| 49 | .check_critical_value = false, | ||
| 50 | .critical_value = 0, | ||
| 51 | }; | ||
| 52 | return tmp; | ||
| 53 | } | ||
diff --git a/plugins/check_ntp.c b/plugins/check_ntp.c deleted file mode 100644 index b22cc3c1..00000000 --- a/plugins/check_ntp.c +++ /dev/null | |||
| @@ -1,947 +0,0 @@ | |||
| 1 | /***************************************************************************** | ||
| 2 | * | ||
| 3 | * Monitoring check_ntp plugin | ||
| 4 | * | ||
| 5 | * License: GPL | ||
| 6 | * Copyright (c) 2006 Sean Finney <seanius@seanius.net> | ||
| 7 | * Copyright (c) 2006-2024 Monitoring Plugins Development Team | ||
| 8 | * | ||
| 9 | * Description: | ||
| 10 | * | ||
| 11 | * This file contains the check_ntp plugin | ||
| 12 | * | ||
| 13 | * This plugin to check ntp servers independent of any commandline | ||
| 14 | * programs or external libraries. | ||
| 15 | * | ||
| 16 | * | ||
| 17 | * This program is free software: you can redistribute it and/or modify | ||
| 18 | * it under the terms of the GNU General Public License as published by | ||
| 19 | * the Free Software Foundation, either version 3 of the License, or | ||
| 20 | * (at your option) any later version. | ||
| 21 | * | ||
| 22 | * This program is distributed in the hope that it will be useful, | ||
| 23 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 24 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 25 | * GNU General Public License for more details. | ||
| 26 | * | ||
| 27 | * You should have received a copy of the GNU General Public License | ||
| 28 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 29 | * | ||
| 30 | * | ||
| 31 | *****************************************************************************/ | ||
| 32 | |||
| 33 | const char *progname = "check_ntp"; | ||
| 34 | const char *copyright = "2006-2024"; | ||
| 35 | const char *email = "devel@monitoring-plugins.org"; | ||
| 36 | |||
| 37 | #include "common.h" | ||
| 38 | #include "netutils.h" | ||
| 39 | #include "utils.h" | ||
| 40 | |||
| 41 | static char *server_address = NULL; | ||
| 42 | static int verbose = 0; | ||
| 43 | static bool do_offset = false; | ||
| 44 | static char *owarn = "60"; | ||
| 45 | static char *ocrit = "120"; | ||
| 46 | static bool do_jitter = false; | ||
| 47 | static char *jwarn = "5000"; | ||
| 48 | static char *jcrit = "10000"; | ||
| 49 | |||
| 50 | static int process_arguments(int /*argc*/, char ** /*argv*/); | ||
| 51 | static thresholds *offset_thresholds = NULL; | ||
| 52 | static thresholds *jitter_thresholds = NULL; | ||
| 53 | static void print_help(void); | ||
| 54 | void print_usage(void); | ||
| 55 | |||
| 56 | /* number of times to perform each request to get a good average. */ | ||
| 57 | #ifndef AVG_NUM | ||
| 58 | # define AVG_NUM 4 | ||
| 59 | #endif | ||
| 60 | |||
| 61 | /* max size of control message data */ | ||
| 62 | #define MAX_CM_SIZE 468 | ||
| 63 | |||
| 64 | /* this structure holds everything in an ntp request/response as per rfc1305 */ | ||
| 65 | typedef struct { | ||
| 66 | uint8_t flags; /* byte with leapindicator,vers,mode. see macros */ | ||
| 67 | uint8_t stratum; /* clock stratum */ | ||
| 68 | int8_t poll; /* polling interval */ | ||
| 69 | int8_t precision; /* precision of the local clock */ | ||
| 70 | int32_t rtdelay; /* total rt delay, as a fixed point num. see macros */ | ||
| 71 | uint32_t rtdisp; /* like above, but for max err to primary src */ | ||
| 72 | uint32_t refid; /* ref clock identifier */ | ||
| 73 | uint64_t refts; /* reference timestamp. local time local clock */ | ||
| 74 | uint64_t origts; /* time at which request departed client */ | ||
| 75 | uint64_t rxts; /* time at which request arrived at server */ | ||
| 76 | uint64_t txts; /* time at which request departed server */ | ||
| 77 | } ntp_message; | ||
| 78 | |||
| 79 | /* this structure holds data about results from querying offset from a peer */ | ||
| 80 | typedef struct { | ||
| 81 | time_t waiting; /* ts set when we started waiting for a response */ | ||
| 82 | int num_responses; /* number of successfully received responses */ | ||
| 83 | uint8_t stratum; /* copied verbatim from the ntp_message */ | ||
| 84 | double rtdelay; /* converted from the ntp_message */ | ||
| 85 | double rtdisp; /* converted from the ntp_message */ | ||
| 86 | double offset[AVG_NUM]; /* offsets from each response */ | ||
| 87 | uint8_t flags; /* byte with leapindicator,vers,mode. see macros */ | ||
| 88 | } ntp_server_results; | ||
| 89 | |||
| 90 | /* this structure holds everything in an ntp control message as per rfc1305 */ | ||
| 91 | typedef struct { | ||
| 92 | uint8_t flags; /* byte with leapindicator,vers,mode. see macros */ | ||
| 93 | uint8_t op; /* R,E,M bits and Opcode */ | ||
| 94 | uint16_t seq; /* Packet sequence */ | ||
| 95 | uint16_t status; /* Clock status */ | ||
| 96 | uint16_t assoc; /* Association */ | ||
| 97 | uint16_t offset; /* Similar to TCP sequence # */ | ||
| 98 | uint16_t count; /* # bytes of data */ | ||
| 99 | char data[MAX_CM_SIZE]; /* ASCII data of the request */ | ||
| 100 | /* NB: not necessarily NULL terminated! */ | ||
| 101 | } ntp_control_message; | ||
| 102 | |||
| 103 | /* this is an association/status-word pair found in control packet responses */ | ||
| 104 | typedef struct { | ||
| 105 | uint16_t assoc; | ||
| 106 | uint16_t status; | ||
| 107 | } ntp_assoc_status_pair; | ||
| 108 | |||
| 109 | /* bits 1,2 are the leap indicator */ | ||
| 110 | #define LI_MASK 0xc0 | ||
| 111 | #define LI(x) ((x & LI_MASK) >> 6) | ||
| 112 | #define LI_SET(x, y) \ | ||
| 113 | do { \ | ||
| 114 | x |= ((y << 6) & LI_MASK); \ | ||
| 115 | } while (0) | ||
| 116 | /* and these are the values of the leap indicator */ | ||
| 117 | #define LI_NOWARNING 0x00 | ||
| 118 | #define LI_EXTRASEC 0x01 | ||
| 119 | #define LI_MISSINGSEC 0x02 | ||
| 120 | #define LI_ALARM 0x03 | ||
| 121 | /* bits 3,4,5 are the ntp version */ | ||
| 122 | #define VN_MASK 0x38 | ||
| 123 | #define VN(x) ((x & VN_MASK) >> 3) | ||
| 124 | #define VN_SET(x, y) \ | ||
| 125 | do { \ | ||
| 126 | x |= ((y << 3) & VN_MASK); \ | ||
| 127 | } while (0) | ||
| 128 | #define VN_RESERVED 0x02 | ||
| 129 | /* bits 6,7,8 are the ntp mode */ | ||
| 130 | #define MODE_MASK 0x07 | ||
| 131 | #define MODE(x) (x & MODE_MASK) | ||
| 132 | #define MODE_SET(x, y) \ | ||
| 133 | do { \ | ||
| 134 | x |= (y & MODE_MASK); \ | ||
| 135 | } while (0) | ||
| 136 | /* here are some values */ | ||
| 137 | #define MODE_CLIENT 0x03 | ||
| 138 | #define MODE_CONTROLMSG 0x06 | ||
| 139 | /* In control message, bits 8-10 are R,E,M bits */ | ||
| 140 | #define REM_MASK 0xe0 | ||
| 141 | #define REM_RESP 0x80 | ||
| 142 | #define REM_ERROR 0x40 | ||
| 143 | #define REM_MORE 0x20 | ||
| 144 | /* In control message, bits 11 - 15 are opcode */ | ||
| 145 | #define OP_MASK 0x1f | ||
| 146 | #define OP_SET(x, y) \ | ||
| 147 | do { \ | ||
| 148 | x |= (y & OP_MASK); \ | ||
| 149 | } while (0) | ||
| 150 | #define OP_READSTAT 0x01 | ||
| 151 | #define OP_READVAR 0x02 | ||
| 152 | /* In peer status bytes, bits 6,7,8 determine clock selection status */ | ||
| 153 | #define PEER_SEL(x) ((ntohs(x) >> 8) & 0x07) | ||
| 154 | #define PEER_INCLUDED 0x04 | ||
| 155 | #define PEER_SYNCSOURCE 0x06 | ||
| 156 | |||
| 157 | /** | ||
| 158 | ** a note about the 32-bit "fixed point" numbers: | ||
| 159 | ** | ||
| 160 | they are divided into halves, each being a 16-bit int in network byte order: | ||
| 161 | - the first 16 bits are an int on the left side of a decimal point. | ||
| 162 | - the second 16 bits represent a fraction n/(2^16) | ||
| 163 | likewise for the 64-bit "fixed point" numbers with everything doubled :) | ||
| 164 | **/ | ||
| 165 | |||
| 166 | /* macros to access the left/right 16 bits of a 32-bit ntp "fixed point" | ||
| 167 | number. note that these can be used as lvalues too */ | ||
| 168 | #define L16(x) (((uint16_t *)&x)[0]) | ||
| 169 | #define R16(x) (((uint16_t *)&x)[1]) | ||
| 170 | /* macros to access the left/right 32 bits of a 64-bit ntp "fixed point" | ||
| 171 | number. these too can be used as lvalues */ | ||
| 172 | #define L32(x) (((uint32_t *)&x)[0]) | ||
| 173 | #define R32(x) (((uint32_t *)&x)[1]) | ||
| 174 | |||
| 175 | /* ntp wants seconds since 1/1/00, epoch is 1/1/70. this is the difference */ | ||
| 176 | #define EPOCHDIFF 0x83aa7e80UL | ||
| 177 | |||
| 178 | /* extract a 32-bit ntp fixed point number into a double */ | ||
| 179 | #define NTP32asDOUBLE(x) (ntohs(L16(x)) + (double)ntohs(R16(x)) / 65536.0) | ||
| 180 | |||
| 181 | /* likewise for a 64-bit ntp fp number */ | ||
| 182 | #define NTP64asDOUBLE(n) \ | ||
| 183 | (double)(((uint64_t)n) ? (ntohl(L32(n)) - EPOCHDIFF) + \ | ||
| 184 | (.00000001 * (0.5 + (double)(ntohl(R32(n)) / 42.94967296))) \ | ||
| 185 | : 0) | ||
| 186 | |||
| 187 | /* convert a struct timeval to a double */ | ||
| 188 | #define TVasDOUBLE(x) (double)(x.tv_sec + (0.000001 * x.tv_usec)) | ||
| 189 | |||
| 190 | /* convert an ntp 64-bit fp number to a struct timeval */ | ||
| 191 | #define NTP64toTV(n, t) \ | ||
| 192 | do { \ | ||
| 193 | if (!n) \ | ||
| 194 | t.tv_sec = t.tv_usec = 0; \ | ||
| 195 | else { \ | ||
| 196 | t.tv_sec = ntohl(L32(n)) - EPOCHDIFF; \ | ||
| 197 | t.tv_usec = (int)(0.5 + (double)(ntohl(R32(n)) / 4294.967296)); \ | ||
| 198 | } \ | ||
| 199 | } while (0) | ||
| 200 | |||
| 201 | /* convert a struct timeval to an ntp 64-bit fp number */ | ||
| 202 | #define TVtoNTP64(t, n) \ | ||
| 203 | do { \ | ||
| 204 | if (!t.tv_usec && !t.tv_sec) \ | ||
| 205 | n = 0x0UL; \ | ||
| 206 | else { \ | ||
| 207 | L32(n) = htonl(t.tv_sec + EPOCHDIFF); \ | ||
| 208 | R32(n) = htonl((uint64_t)((4294.967296 * t.tv_usec) + .5)); \ | ||
| 209 | } \ | ||
| 210 | } while (0) | ||
| 211 | |||
| 212 | /* NTP control message header is 12 bytes, plus any data in the data | ||
| 213 | * field, plus null padding to the nearest 32-bit boundary per rfc. | ||
| 214 | */ | ||
| 215 | #define SIZEOF_NTPCM(m) \ | ||
| 216 | (12 + ntohs(m.count) + ((ntohs(m.count) % 4) ? 4 - (ntohs(m.count) % 4) : 0)) | ||
| 217 | |||
| 218 | /* finally, a little helper or two for debugging: */ | ||
| 219 | #define DBG(x) \ | ||
| 220 | do { \ | ||
| 221 | if (verbose > 1) { \ | ||
| 222 | x; \ | ||
| 223 | } \ | ||
| 224 | } while (0); | ||
| 225 | #define PRINTSOCKADDR(x) \ | ||
| 226 | do { \ | ||
| 227 | printf("%u.%u.%u.%u", (x >> 24) & 0xff, (x >> 16) & 0xff, (x >> 8) & 0xff, x & 0xff); \ | ||
| 228 | } while (0); | ||
| 229 | |||
| 230 | /* calculate the offset of the local clock */ | ||
| 231 | static inline double calc_offset(const ntp_message *m, const struct timeval *t) { | ||
| 232 | double client_tx, peer_rx, peer_tx, client_rx; | ||
| 233 | client_tx = NTP64asDOUBLE(m->origts); | ||
| 234 | peer_rx = NTP64asDOUBLE(m->rxts); | ||
| 235 | peer_tx = NTP64asDOUBLE(m->txts); | ||
| 236 | client_rx = TVasDOUBLE((*t)); | ||
| 237 | return (.5 * ((peer_tx - client_rx) + (peer_rx - client_tx))); | ||
| 238 | } | ||
| 239 | |||
| 240 | /* print out a ntp packet in human readable/debuggable format */ | ||
| 241 | void print_ntp_message(const ntp_message *p) { | ||
| 242 | struct timeval ref, orig, rx, tx; | ||
| 243 | |||
| 244 | NTP64toTV(p->refts, ref); | ||
| 245 | NTP64toTV(p->origts, orig); | ||
| 246 | NTP64toTV(p->rxts, rx); | ||
| 247 | NTP64toTV(p->txts, tx); | ||
| 248 | |||
| 249 | printf("packet contents:\n"); | ||
| 250 | printf("\tflags: 0x%.2x\n", p->flags); | ||
| 251 | printf("\t li=%d (0x%.2x)\n", LI(p->flags), p->flags & LI_MASK); | ||
| 252 | printf("\t vn=%d (0x%.2x)\n", VN(p->flags), p->flags & VN_MASK); | ||
| 253 | printf("\t mode=%d (0x%.2x)\n", MODE(p->flags), p->flags & MODE_MASK); | ||
| 254 | printf("\tstratum = %d\n", p->stratum); | ||
| 255 | printf("\tpoll = %g\n", pow(2, p->poll)); | ||
| 256 | printf("\tprecision = %g\n", pow(2, p->precision)); | ||
| 257 | printf("\trtdelay = %-.16g\n", NTP32asDOUBLE(p->rtdelay)); | ||
| 258 | printf("\trtdisp = %-.16g\n", NTP32asDOUBLE(p->rtdisp)); | ||
| 259 | printf("\trefid = %x\n", p->refid); | ||
| 260 | printf("\trefts = %-.16g\n", NTP64asDOUBLE(p->refts)); | ||
| 261 | printf("\torigts = %-.16g\n", NTP64asDOUBLE(p->origts)); | ||
| 262 | printf("\trxts = %-.16g\n", NTP64asDOUBLE(p->rxts)); | ||
| 263 | printf("\ttxts = %-.16g\n", NTP64asDOUBLE(p->txts)); | ||
| 264 | } | ||
| 265 | |||
| 266 | void print_ntp_control_message(const ntp_control_message *p) { | ||
| 267 | int i = 0, numpeers = 0; | ||
| 268 | const ntp_assoc_status_pair *peer = NULL; | ||
| 269 | |||
| 270 | printf("control packet contents:\n"); | ||
| 271 | printf("\tflags: 0x%.2x , 0x%.2x\n", p->flags, p->op); | ||
| 272 | printf("\t li=%d (0x%.2x)\n", LI(p->flags), p->flags & LI_MASK); | ||
| 273 | printf("\t vn=%d (0x%.2x)\n", VN(p->flags), p->flags & VN_MASK); | ||
| 274 | printf("\t mode=%d (0x%.2x)\n", MODE(p->flags), p->flags & MODE_MASK); | ||
| 275 | printf("\t response=%d (0x%.2x)\n", (p->op & REM_RESP) > 0, p->op & REM_RESP); | ||
| 276 | printf("\t more=%d (0x%.2x)\n", (p->op & REM_MORE) > 0, p->op & REM_MORE); | ||
| 277 | printf("\t error=%d (0x%.2x)\n", (p->op & REM_ERROR) > 0, p->op & REM_ERROR); | ||
| 278 | printf("\t op=%d (0x%.2x)\n", p->op & OP_MASK, p->op & OP_MASK); | ||
| 279 | printf("\tsequence: %d (0x%.2x)\n", ntohs(p->seq), ntohs(p->seq)); | ||
| 280 | printf("\tstatus: %d (0x%.2x)\n", ntohs(p->status), ntohs(p->status)); | ||
| 281 | printf("\tassoc: %d (0x%.2x)\n", ntohs(p->assoc), ntohs(p->assoc)); | ||
| 282 | printf("\toffset: %d (0x%.2x)\n", ntohs(p->offset), ntohs(p->offset)); | ||
| 283 | printf("\tcount: %d (0x%.2x)\n", ntohs(p->count), ntohs(p->count)); | ||
| 284 | numpeers = ntohs(p->count) / (sizeof(ntp_assoc_status_pair)); | ||
| 285 | if (p->op & REM_RESP && p->op & OP_READSTAT) { | ||
| 286 | peer = (ntp_assoc_status_pair *)p->data; | ||
| 287 | for (i = 0; i < numpeers; i++) { | ||
| 288 | printf("\tpeer id %.2x status %.2x", ntohs(peer[i].assoc), ntohs(peer[i].status)); | ||
| 289 | if (PEER_SEL(peer[i].status) >= PEER_INCLUDED) { | ||
| 290 | if (PEER_SEL(peer[i].status) >= PEER_SYNCSOURCE) { | ||
| 291 | printf(" <-- current sync source"); | ||
| 292 | } else { | ||
| 293 | printf(" <-- current sync candidate"); | ||
| 294 | } | ||
| 295 | } | ||
| 296 | printf("\n"); | ||
| 297 | } | ||
| 298 | } | ||
| 299 | } | ||
| 300 | |||
| 301 | void setup_request(ntp_message *p) { | ||
| 302 | struct timeval t; | ||
| 303 | |||
| 304 | memset(p, 0, sizeof(ntp_message)); | ||
| 305 | LI_SET(p->flags, LI_ALARM); | ||
| 306 | VN_SET(p->flags, 4); | ||
| 307 | MODE_SET(p->flags, MODE_CLIENT); | ||
| 308 | p->poll = 4; | ||
| 309 | p->precision = (int8_t)0xfa; | ||
| 310 | L16(p->rtdelay) = htons(1); | ||
| 311 | L16(p->rtdisp) = htons(1); | ||
| 312 | |||
| 313 | gettimeofday(&t, NULL); | ||
| 314 | TVtoNTP64(t, p->txts); | ||
| 315 | } | ||
| 316 | |||
| 317 | /* select the "best" server from a list of servers, and return its index. | ||
| 318 | * this is done by filtering servers based on stratum, dispersion, and | ||
| 319 | * finally round-trip delay. */ | ||
| 320 | int best_offset_server(const ntp_server_results *slist, int nservers) { | ||
| 321 | int cserver = 0, best_server = -1; | ||
| 322 | |||
| 323 | /* for each server */ | ||
| 324 | for (cserver = 0; cserver < nservers; cserver++) { | ||
| 325 | /* We don't want any servers that fails these tests */ | ||
| 326 | /* Sort out servers that didn't respond or responede with a 0 stratum; | ||
| 327 | * stratum 0 is for reference clocks so no NTP server should ever report | ||
| 328 | * a stratum 0 */ | ||
| 329 | if (slist[cserver].stratum == 0) { | ||
| 330 | if (verbose) { | ||
| 331 | printf("discarding peer %d: stratum=%d\n", cserver, slist[cserver].stratum); | ||
| 332 | } | ||
| 333 | continue; | ||
| 334 | } | ||
| 335 | /* Sort out servers with error flags */ | ||
| 336 | if (LI(slist[cserver].flags) == LI_ALARM) { | ||
| 337 | if (verbose) { | ||
| 338 | printf("discarding peer %d: flags=%d\n", cserver, LI(slist[cserver].flags)); | ||
| 339 | } | ||
| 340 | continue; | ||
| 341 | } | ||
| 342 | |||
| 343 | /* If we don't have a server yet, use the first one */ | ||
| 344 | if (best_server == -1) { | ||
| 345 | best_server = cserver; | ||
| 346 | DBG(printf("using peer %d as our first candidate\n", best_server)); | ||
| 347 | continue; | ||
| 348 | } | ||
| 349 | |||
| 350 | /* compare the server to the best one we've seen so far */ | ||
| 351 | /* does it have an equal or better stratum? */ | ||
| 352 | DBG(printf("comparing peer %d with peer %d\n", cserver, best_server)); | ||
| 353 | if (slist[cserver].stratum <= slist[best_server].stratum) { | ||
| 354 | DBG(printf("stratum for peer %d <= peer %d\n", cserver, best_server)); | ||
| 355 | /* does it have an equal or better dispersion? */ | ||
| 356 | if (slist[cserver].rtdisp <= slist[best_server].rtdisp) { | ||
| 357 | DBG(printf("dispersion for peer %d <= peer %d\n", cserver, best_server)); | ||
| 358 | /* does it have a better rtdelay? */ | ||
| 359 | if (slist[cserver].rtdelay < slist[best_server].rtdelay) { | ||
| 360 | DBG(printf("rtdelay for peer %d < peer %d\n", cserver, best_server)); | ||
| 361 | best_server = cserver; | ||
| 362 | DBG(printf("peer %d is now our best candidate\n", best_server)); | ||
| 363 | } | ||
| 364 | } | ||
| 365 | } | ||
| 366 | } | ||
| 367 | |||
| 368 | if (best_server >= 0) { | ||
| 369 | DBG(printf("best server selected: peer %d\n", best_server)); | ||
| 370 | return best_server; | ||
| 371 | } else { | ||
| 372 | DBG(printf("no peers meeting synchronization criteria :(\n")); | ||
| 373 | return -1; | ||
| 374 | } | ||
| 375 | } | ||
| 376 | |||
| 377 | /* do everything we need to get the total average offset | ||
| 378 | * - we use a certain amount of parallelization with poll() to ensure | ||
| 379 | * we don't waste time sitting around waiting for single packets. | ||
| 380 | * - we also "manually" handle resolving host names and connecting, because | ||
| 381 | * we have to do it in a way that our lazy macros don't handle currently :( */ | ||
| 382 | double offset_request(const char *host, int *status) { | ||
| 383 | int i = 0, ga_result = 0, num_hosts = 0, *socklist = NULL, respnum = 0; | ||
| 384 | int servers_completed = 0, one_read = 0, servers_readable = 0, best_index = -1; | ||
| 385 | time_t now_time = 0, start_ts = 0; | ||
| 386 | ntp_message *req = NULL; | ||
| 387 | double avg_offset = 0.; | ||
| 388 | struct timeval recv_time; | ||
| 389 | struct addrinfo *ai = NULL, *ai_tmp = NULL, hints; | ||
| 390 | struct pollfd *ufds = NULL; | ||
| 391 | ntp_server_results *servers = NULL; | ||
| 392 | |||
| 393 | /* setup hints to only return results from getaddrinfo that we'd like */ | ||
| 394 | memset(&hints, 0, sizeof(struct addrinfo)); | ||
| 395 | hints.ai_family = address_family; | ||
| 396 | hints.ai_protocol = IPPROTO_UDP; | ||
| 397 | hints.ai_socktype = SOCK_DGRAM; | ||
| 398 | |||
| 399 | /* fill in ai with the list of hosts resolved by the host name */ | ||
| 400 | ga_result = getaddrinfo(host, "123", &hints, &ai); | ||
| 401 | if (ga_result != 0) { | ||
| 402 | die(STATE_UNKNOWN, "error getting address for %s: %s\n", host, gai_strerror(ga_result)); | ||
| 403 | } | ||
| 404 | |||
| 405 | /* count the number of returned hosts, and allocate stuff accordingly */ | ||
| 406 | for (ai_tmp = ai; ai_tmp != NULL; ai_tmp = ai_tmp->ai_next) { | ||
| 407 | num_hosts++; | ||
| 408 | } | ||
| 409 | req = (ntp_message *)malloc(sizeof(ntp_message) * num_hosts); | ||
| 410 | if (req == NULL) { | ||
| 411 | die(STATE_UNKNOWN, "can not allocate ntp message array"); | ||
| 412 | } | ||
| 413 | socklist = (int *)malloc(sizeof(int) * num_hosts); | ||
| 414 | if (socklist == NULL) { | ||
| 415 | die(STATE_UNKNOWN, "can not allocate socket array"); | ||
| 416 | } | ||
| 417 | ufds = (struct pollfd *)malloc(sizeof(struct pollfd) * num_hosts); | ||
| 418 | if (ufds == NULL) { | ||
| 419 | die(STATE_UNKNOWN, "can not allocate socket array"); | ||
| 420 | } | ||
| 421 | servers = (ntp_server_results *)malloc(sizeof(ntp_server_results) * num_hosts); | ||
| 422 | if (servers == NULL) { | ||
| 423 | die(STATE_UNKNOWN, "can not allocate server array"); | ||
| 424 | } | ||
| 425 | memset(servers, 0, sizeof(ntp_server_results) * num_hosts); | ||
| 426 | DBG(printf("Found %d peers to check\n", num_hosts)); | ||
| 427 | |||
| 428 | /* setup each socket for writing, and the corresponding struct pollfd */ | ||
| 429 | ai_tmp = ai; | ||
| 430 | for (i = 0; ai_tmp; i++) { | ||
| 431 | socklist[i] = socket(ai_tmp->ai_family, SOCK_DGRAM, IPPROTO_UDP); | ||
| 432 | if (socklist[i] == -1) { | ||
| 433 | perror(NULL); | ||
| 434 | die(STATE_UNKNOWN, "can not create new socket"); | ||
| 435 | } | ||
| 436 | if (connect(socklist[i], ai_tmp->ai_addr, ai_tmp->ai_addrlen)) { | ||
| 437 | /* don't die here, because it is enough if there is one server | ||
| 438 | answering in time. This also would break for dual ipv4/6 stacked | ||
| 439 | ntp servers when the client only supports on of them. | ||
| 440 | */ | ||
| 441 | DBG(printf("can't create socket connection on peer %i: %s\n", i, strerror(errno))); | ||
| 442 | } else { | ||
| 443 | ufds[i].fd = socklist[i]; | ||
| 444 | ufds[i].events = POLLIN; | ||
| 445 | ufds[i].revents = 0; | ||
| 446 | } | ||
| 447 | ai_tmp = ai_tmp->ai_next; | ||
| 448 | } | ||
| 449 | |||
| 450 | /* now do AVG_NUM checks to each host. we stop before timeout/2 seconds | ||
| 451 | * have passed in order to ensure post-processing and jitter time. */ | ||
| 452 | now_time = start_ts = time(NULL); | ||
| 453 | while (servers_completed < num_hosts && now_time - start_ts <= socket_timeout / 2) { | ||
| 454 | /* loop through each server and find each one which hasn't | ||
| 455 | * been touched in the past second or so and is still lacking | ||
| 456 | * some responses. for each of these servers, send a new request, | ||
| 457 | * and update the "waiting" timestamp with the current time. */ | ||
| 458 | now_time = time(NULL); | ||
| 459 | |||
| 460 | for (i = 0; i < num_hosts; i++) { | ||
| 461 | if (servers[i].waiting < now_time && servers[i].num_responses < AVG_NUM) { | ||
| 462 | if (verbose && servers[i].waiting != 0) { | ||
| 463 | printf("re-"); | ||
| 464 | } | ||
| 465 | if (verbose) { | ||
| 466 | printf("sending request to peer %d\n", i); | ||
| 467 | } | ||
| 468 | setup_request(&req[i]); | ||
| 469 | write(socklist[i], &req[i], sizeof(ntp_message)); | ||
| 470 | servers[i].waiting = now_time; | ||
| 471 | break; | ||
| 472 | } | ||
| 473 | } | ||
| 474 | |||
| 475 | /* quickly poll for any sockets with pending data */ | ||
| 476 | servers_readable = poll(ufds, num_hosts, 100); | ||
| 477 | if (servers_readable == -1) { | ||
| 478 | perror("polling ntp sockets"); | ||
| 479 | die(STATE_UNKNOWN, "communication errors"); | ||
| 480 | } | ||
| 481 | |||
| 482 | /* read from any sockets with pending data */ | ||
| 483 | for (i = 0; servers_readable && i < num_hosts; i++) { | ||
| 484 | if (ufds[i].revents & POLLIN && servers[i].num_responses < AVG_NUM) { | ||
| 485 | if (verbose) { | ||
| 486 | printf("response from peer %d: ", i); | ||
| 487 | } | ||
| 488 | |||
| 489 | read(ufds[i].fd, &req[i], sizeof(ntp_message)); | ||
| 490 | gettimeofday(&recv_time, NULL); | ||
| 491 | DBG(print_ntp_message(&req[i])); | ||
| 492 | respnum = servers[i].num_responses++; | ||
| 493 | servers[i].offset[respnum] = calc_offset(&req[i], &recv_time); | ||
| 494 | if (verbose) { | ||
| 495 | printf("offset %.10g\n", servers[i].offset[respnum]); | ||
| 496 | } | ||
| 497 | servers[i].stratum = req[i].stratum; | ||
| 498 | servers[i].rtdisp = NTP32asDOUBLE(req[i].rtdisp); | ||
| 499 | servers[i].rtdelay = NTP32asDOUBLE(req[i].rtdelay); | ||
| 500 | servers[i].waiting = 0; | ||
| 501 | servers[i].flags = req[i].flags; | ||
| 502 | servers_readable--; | ||
| 503 | one_read = 1; | ||
| 504 | if (servers[i].num_responses == AVG_NUM) { | ||
| 505 | servers_completed++; | ||
| 506 | } | ||
| 507 | } | ||
| 508 | } | ||
| 509 | /* lather, rinse, repeat. */ | ||
| 510 | } | ||
| 511 | |||
| 512 | if (one_read == 0) { | ||
| 513 | die(STATE_CRITICAL, "NTP CRITICAL: No response from NTP server\n"); | ||
| 514 | } | ||
| 515 | |||
| 516 | /* now, pick the best server from the list */ | ||
| 517 | best_index = best_offset_server(servers, num_hosts); | ||
| 518 | if (best_index < 0) { | ||
| 519 | *status = STATE_UNKNOWN; | ||
| 520 | } else { | ||
| 521 | /* finally, calculate the average offset */ | ||
| 522 | for (i = 0; i < servers[best_index].num_responses; i++) { | ||
| 523 | avg_offset += servers[best_index].offset[i]; | ||
| 524 | } | ||
| 525 | avg_offset /= servers[best_index].num_responses; | ||
| 526 | } | ||
| 527 | |||
| 528 | /* cleanup */ | ||
| 529 | /* FIXME: Not closing the socket to avoid reuse of the local port | ||
| 530 | * which can cause old NTP packets to be read instead of NTP control | ||
| 531 | * packets in jitter_request(). THERE MUST BE ANOTHER WAY... | ||
| 532 | * for(j=0; j<num_hosts; j++){ close(socklist[j]); } */ | ||
| 533 | free(socklist); | ||
| 534 | free(ufds); | ||
| 535 | free(servers); | ||
| 536 | free(req); | ||
| 537 | freeaddrinfo(ai); | ||
| 538 | |||
| 539 | if (verbose) { | ||
| 540 | printf("overall average offset: %.10g\n", avg_offset); | ||
| 541 | } | ||
| 542 | return avg_offset; | ||
| 543 | } | ||
| 544 | |||
| 545 | void setup_control_request(ntp_control_message *p, uint8_t opcode, uint16_t seq) { | ||
| 546 | memset(p, 0, sizeof(ntp_control_message)); | ||
| 547 | LI_SET(p->flags, LI_NOWARNING); | ||
| 548 | VN_SET(p->flags, VN_RESERVED); | ||
| 549 | MODE_SET(p->flags, MODE_CONTROLMSG); | ||
| 550 | OP_SET(p->op, opcode); | ||
| 551 | p->seq = htons(seq); | ||
| 552 | /* Remaining fields are zero for requests */ | ||
| 553 | } | ||
| 554 | |||
| 555 | /* XXX handle responses with the error bit set */ | ||
| 556 | double jitter_request(int *status) { | ||
| 557 | int conn = -1, i, npeers = 0, num_candidates = 0; | ||
| 558 | bool syncsource_found = false; | ||
| 559 | int run = 0, min_peer_sel = PEER_INCLUDED, num_selected = 0, num_valid = 0; | ||
| 560 | int peers_size = 0, peer_offset = 0; | ||
| 561 | ntp_assoc_status_pair *peers = NULL; | ||
| 562 | ntp_control_message req; | ||
| 563 | const char *getvar = "jitter"; | ||
| 564 | double rval = 0.0, jitter = -1.0; | ||
| 565 | char *startofvalue = NULL, *nptr = NULL; | ||
| 566 | void *tmp; | ||
| 567 | |||
| 568 | /* Long-winded explanation: | ||
| 569 | * Getting the jitter requires a number of steps: | ||
| 570 | * 1) Send a READSTAT request. | ||
| 571 | * 2) Interpret the READSTAT reply | ||
| 572 | * a) The data section contains a list of peer identifiers (16 bits) | ||
| 573 | * and associated status words (16 bits) | ||
| 574 | * b) We want the value of 0x06 in the SEL (peer selection) value, | ||
| 575 | * which means "current synchronizatin source". If that's missing, | ||
| 576 | * we take anything better than 0x04 (see the rfc for details) but | ||
| 577 | * set a minimum of warning. | ||
| 578 | * 3) Send a READVAR request for information on each peer identified | ||
| 579 | * in 2b greater than the minimum selection value. | ||
| 580 | * 4) Extract the jitter value from the data[] (it's ASCII) | ||
| 581 | */ | ||
| 582 | my_udp_connect(server_address, 123, &conn); | ||
| 583 | |||
| 584 | /* keep sending requests until the server stops setting the | ||
| 585 | * REM_MORE bit, though usually this is only 1 packet. */ | ||
| 586 | do { | ||
| 587 | setup_control_request(&req, OP_READSTAT, 1); | ||
| 588 | DBG(printf("sending READSTAT request")); | ||
| 589 | write(conn, &req, SIZEOF_NTPCM(req)); | ||
| 590 | DBG(print_ntp_control_message(&req)); | ||
| 591 | /* Attempt to read the largest size packet possible */ | ||
| 592 | req.count = htons(MAX_CM_SIZE); | ||
| 593 | DBG(printf("receiving READSTAT response")) | ||
| 594 | read(conn, &req, SIZEOF_NTPCM(req)); | ||
| 595 | DBG(print_ntp_control_message(&req)); | ||
| 596 | /* Each peer identifier is 4 bytes in the data section, which | ||
| 597 | * we represent as a ntp_assoc_status_pair datatype. | ||
| 598 | */ | ||
| 599 | peers_size += ntohs(req.count); | ||
| 600 | if ((tmp = realloc(peers, peers_size)) == NULL) { | ||
| 601 | free(peers), die(STATE_UNKNOWN, "can not (re)allocate 'peers' buffer\n"); | ||
| 602 | } | ||
| 603 | peers = tmp; | ||
| 604 | memcpy((void *)((ptrdiff_t)peers + peer_offset), (void *)req.data, ntohs(req.count)); | ||
| 605 | npeers = peers_size / sizeof(ntp_assoc_status_pair); | ||
| 606 | peer_offset += ntohs(req.count); | ||
| 607 | } while (req.op & REM_MORE); | ||
| 608 | |||
| 609 | /* first, let's find out if we have a sync source, or if there are | ||
| 610 | * at least some candidates. in the case of the latter we'll issue | ||
| 611 | * a warning but go ahead with the check on them. */ | ||
| 612 | for (i = 0; i < npeers; i++) { | ||
| 613 | if (PEER_SEL(peers[i].status) >= PEER_INCLUDED) { | ||
| 614 | num_candidates++; | ||
| 615 | if (PEER_SEL(peers[i].status) >= PEER_SYNCSOURCE) { | ||
| 616 | syncsource_found = true; | ||
| 617 | min_peer_sel = PEER_SYNCSOURCE; | ||
| 618 | } | ||
| 619 | } | ||
| 620 | } | ||
| 621 | if (verbose) { | ||
| 622 | printf("%d candidate peers available\n", num_candidates); | ||
| 623 | } | ||
| 624 | if (verbose && syncsource_found) { | ||
| 625 | printf("synchronization source found\n"); | ||
| 626 | } | ||
| 627 | if (!syncsource_found) { | ||
| 628 | *status = STATE_UNKNOWN; | ||
| 629 | if (verbose) { | ||
| 630 | printf("warning: no synchronization source found\n"); | ||
| 631 | } | ||
| 632 | } | ||
| 633 | |||
| 634 | for (run = 0; run < AVG_NUM; run++) { | ||
| 635 | if (verbose) { | ||
| 636 | printf("jitter run %d of %d\n", run + 1, AVG_NUM); | ||
| 637 | } | ||
| 638 | for (i = 0; i < npeers; i++) { | ||
| 639 | /* Only query this server if it is the current sync source */ | ||
| 640 | if (PEER_SEL(peers[i].status) >= min_peer_sel) { | ||
| 641 | char jitter_data[MAX_CM_SIZE + 1]; | ||
| 642 | size_t jitter_data_count; | ||
| 643 | |||
| 644 | num_selected++; | ||
| 645 | setup_control_request(&req, OP_READVAR, 2); | ||
| 646 | req.assoc = peers[i].assoc; | ||
| 647 | /* By spec, putting the variable name "jitter" in the request | ||
| 648 | * should cause the server to provide _only_ the jitter value. | ||
| 649 | * thus reducing net traffic, guaranteeing us only a single | ||
| 650 | * datagram in reply, and making interpretation much simpler | ||
| 651 | */ | ||
| 652 | /* Older servers doesn't know what jitter is, so if we get an | ||
| 653 | * error on the first pass we redo it with "dispersion" */ | ||
| 654 | strncpy(req.data, getvar, MAX_CM_SIZE - 1); | ||
| 655 | req.count = htons(strlen(getvar)); | ||
| 656 | DBG(printf("sending READVAR request...\n")); | ||
| 657 | write(conn, &req, SIZEOF_NTPCM(req)); | ||
| 658 | DBG(print_ntp_control_message(&req)); | ||
| 659 | |||
| 660 | req.count = htons(MAX_CM_SIZE); | ||
| 661 | DBG(printf("receiving READVAR response...\n")); | ||
| 662 | read(conn, &req, SIZEOF_NTPCM(req)); | ||
| 663 | DBG(print_ntp_control_message(&req)); | ||
| 664 | |||
| 665 | if (req.op & REM_ERROR && strstr(getvar, "jitter")) { | ||
| 666 | if (verbose) { | ||
| 667 | printf("The 'jitter' command failed (old ntp server?)\nRestarting with " | ||
| 668 | "'dispersion'...\n"); | ||
| 669 | } | ||
| 670 | getvar = "dispersion"; | ||
| 671 | num_selected--; | ||
| 672 | i--; | ||
| 673 | continue; | ||
| 674 | } | ||
| 675 | |||
| 676 | /* get to the float value */ | ||
| 677 | if (verbose) { | ||
| 678 | printf("parsing jitter from peer %.2x: ", ntohs(peers[i].assoc)); | ||
| 679 | } | ||
| 680 | if ((jitter_data_count = ntohs(req.count)) >= sizeof(jitter_data)) { | ||
| 681 | die(STATE_UNKNOWN, _("jitter response too large (%lu bytes)\n"), | ||
| 682 | (unsigned long)jitter_data_count); | ||
| 683 | } | ||
| 684 | memcpy(jitter_data, req.data, jitter_data_count); | ||
| 685 | jitter_data[jitter_data_count] = '\0'; | ||
| 686 | startofvalue = strchr(jitter_data, '='); | ||
| 687 | if (startofvalue != NULL) { | ||
| 688 | startofvalue++; | ||
| 689 | jitter = strtod(startofvalue, &nptr); | ||
| 690 | } | ||
| 691 | if (startofvalue == NULL || startofvalue == nptr) { | ||
| 692 | printf("warning: unable to read server jitter response.\n"); | ||
| 693 | *status = STATE_UNKNOWN; | ||
| 694 | } else { | ||
| 695 | if (verbose) { | ||
| 696 | printf("%g\n", jitter); | ||
| 697 | } | ||
| 698 | num_valid++; | ||
| 699 | rval += jitter; | ||
| 700 | } | ||
| 701 | } | ||
| 702 | } | ||
| 703 | if (verbose) { | ||
| 704 | printf("jitter parsed from %d/%d peers\n", num_valid, num_selected); | ||
| 705 | } | ||
| 706 | } | ||
| 707 | |||
| 708 | rval = num_valid ? rval / num_valid : -1.0; | ||
| 709 | |||
| 710 | close(conn); | ||
| 711 | if (peers != NULL) { | ||
| 712 | free(peers); | ||
| 713 | } | ||
| 714 | /* If we return -1.0, it means no synchronization source was found */ | ||
| 715 | return rval; | ||
| 716 | } | ||
| 717 | |||
| 718 | int process_arguments(int argc, char **argv) { | ||
| 719 | int c; | ||
| 720 | int option = 0; | ||
| 721 | static struct option longopts[] = { | ||
| 722 | {"version", no_argument, 0, 'V'}, {"help", no_argument, 0, 'h'}, | ||
| 723 | {"verbose", no_argument, 0, 'v'}, {"use-ipv4", no_argument, 0, '4'}, | ||
| 724 | {"use-ipv6", no_argument, 0, '6'}, {"warning", required_argument, 0, 'w'}, | ||
| 725 | {"critical", required_argument, 0, 'c'}, {"jwarn", required_argument, 0, 'j'}, | ||
| 726 | {"jcrit", required_argument, 0, 'k'}, {"timeout", required_argument, 0, 't'}, | ||
| 727 | {"hostname", required_argument, 0, 'H'}, {0, 0, 0, 0}}; | ||
| 728 | |||
| 729 | if (argc < 2) { | ||
| 730 | usage("\n"); | ||
| 731 | } | ||
| 732 | |||
| 733 | while (1) { | ||
| 734 | c = getopt_long(argc, argv, "Vhv46w:c:j:k:t:H:", longopts, &option); | ||
| 735 | if (c == -1 || c == EOF || c == 1) { | ||
| 736 | break; | ||
| 737 | } | ||
| 738 | |||
| 739 | switch (c) { | ||
| 740 | case 'h': | ||
| 741 | print_help(); | ||
| 742 | exit(STATE_UNKNOWN); | ||
| 743 | break; | ||
| 744 | case 'V': | ||
| 745 | print_revision(progname, NP_VERSION); | ||
| 746 | exit(STATE_UNKNOWN); | ||
| 747 | break; | ||
| 748 | case 'v': | ||
| 749 | verbose++; | ||
| 750 | break; | ||
| 751 | case 'w': | ||
| 752 | do_offset = true; | ||
| 753 | owarn = optarg; | ||
| 754 | break; | ||
| 755 | case 'c': | ||
| 756 | do_offset = true; | ||
| 757 | ocrit = optarg; | ||
| 758 | break; | ||
| 759 | case 'j': | ||
| 760 | do_jitter = true; | ||
| 761 | jwarn = optarg; | ||
| 762 | break; | ||
| 763 | case 'k': | ||
| 764 | do_jitter = true; | ||
| 765 | jcrit = optarg; | ||
| 766 | break; | ||
| 767 | case 'H': | ||
| 768 | if (!is_host(optarg)) { | ||
| 769 | usage2(_("Invalid hostname/address"), optarg); | ||
| 770 | } | ||
| 771 | server_address = strdup(optarg); | ||
| 772 | break; | ||
| 773 | case 't': | ||
| 774 | socket_timeout = atoi(optarg); | ||
| 775 | break; | ||
| 776 | case '4': | ||
| 777 | address_family = AF_INET; | ||
| 778 | break; | ||
| 779 | case '6': | ||
| 780 | #ifdef USE_IPV6 | ||
| 781 | address_family = AF_INET6; | ||
| 782 | #else | ||
| 783 | usage4(_("IPv6 support not available")); | ||
| 784 | #endif | ||
| 785 | break; | ||
| 786 | case '?': | ||
| 787 | /* print short usage statement if args not parsable */ | ||
| 788 | usage5(); | ||
| 789 | break; | ||
| 790 | } | ||
| 791 | } | ||
| 792 | |||
| 793 | if (server_address == NULL) { | ||
| 794 | usage4(_("Hostname was not supplied")); | ||
| 795 | } | ||
| 796 | |||
| 797 | return 0; | ||
| 798 | } | ||
| 799 | |||
| 800 | char *perfd_offset(double offset) { | ||
| 801 | return fperfdata("offset", offset, "s", true, offset_thresholds->warning->end, true, | ||
| 802 | offset_thresholds->critical->end, false, 0, false, 0); | ||
| 803 | } | ||
| 804 | |||
| 805 | char *perfd_jitter(double jitter) { | ||
| 806 | return fperfdata("jitter", jitter, "s", do_jitter, jitter_thresholds->warning->end, do_jitter, | ||
| 807 | jitter_thresholds->critical->end, true, 0, false, 0); | ||
| 808 | } | ||
| 809 | |||
| 810 | int main(int argc, char *argv[]) { | ||
| 811 | int result, offset_result, jitter_result; | ||
| 812 | double offset = 0, jitter = 0; | ||
| 813 | char *result_line, *perfdata_line; | ||
| 814 | |||
| 815 | setlocale(LC_ALL, ""); | ||
| 816 | bindtextdomain(PACKAGE, LOCALEDIR); | ||
| 817 | textdomain(PACKAGE); | ||
| 818 | |||
| 819 | result = offset_result = jitter_result = STATE_OK; | ||
| 820 | |||
| 821 | /* Parse extra opts if any */ | ||
| 822 | argv = np_extra_opts(&argc, argv, progname); | ||
| 823 | |||
| 824 | if (process_arguments(argc, argv) == ERROR) { | ||
| 825 | usage4(_("Could not parse arguments")); | ||
| 826 | } | ||
| 827 | |||
| 828 | set_thresholds(&offset_thresholds, owarn, ocrit); | ||
| 829 | set_thresholds(&jitter_thresholds, jwarn, jcrit); | ||
| 830 | |||
| 831 | /* initialize alarm signal handling */ | ||
| 832 | signal(SIGALRM, socket_timeout_alarm_handler); | ||
| 833 | |||
| 834 | /* set socket timeout */ | ||
| 835 | alarm(socket_timeout); | ||
| 836 | |||
| 837 | offset = offset_request(server_address, &offset_result); | ||
| 838 | /* check_ntp used to always return CRITICAL if offset_result == STATE_UNKNOWN. | ||
| 839 | * Now we'll only do that is the offset thresholds were set */ | ||
| 840 | if (do_offset && offset_result == STATE_UNKNOWN) { | ||
| 841 | result = STATE_CRITICAL; | ||
| 842 | } else { | ||
| 843 | result = get_status(fabs(offset), offset_thresholds); | ||
| 844 | } | ||
| 845 | |||
| 846 | /* If not told to check the jitter, we don't even send packets. | ||
| 847 | * jitter is checked using NTP control packets, which not all | ||
| 848 | * servers recognize. Trying to check the jitter on OpenNTPD | ||
| 849 | * (for example) will result in an error | ||
| 850 | */ | ||
| 851 | if (do_jitter) { | ||
| 852 | jitter = jitter_request(&jitter_result); | ||
| 853 | result = max_state_alt(result, get_status(jitter, jitter_thresholds)); | ||
| 854 | /* -1 indicates that we couldn't calculate the jitter | ||
| 855 | * Only overrides STATE_OK from the offset */ | ||
| 856 | if (jitter == -1.0 && result == STATE_OK) { | ||
| 857 | result = STATE_UNKNOWN; | ||
| 858 | } | ||
| 859 | } | ||
| 860 | result = max_state_alt(result, jitter_result); | ||
| 861 | |||
| 862 | switch (result) { | ||
| 863 | case STATE_CRITICAL: | ||
| 864 | xasprintf(&result_line, _("NTP CRITICAL:")); | ||
| 865 | break; | ||
| 866 | case STATE_WARNING: | ||
| 867 | xasprintf(&result_line, _("NTP WARNING:")); | ||
| 868 | break; | ||
| 869 | case STATE_OK: | ||
| 870 | xasprintf(&result_line, _("NTP OK:")); | ||
| 871 | break; | ||
| 872 | default: | ||
| 873 | xasprintf(&result_line, _("NTP UNKNOWN:")); | ||
| 874 | break; | ||
| 875 | } | ||
| 876 | if (offset_result == STATE_UNKNOWN) { | ||
| 877 | xasprintf(&result_line, "%s %s", result_line, _("Offset unknown")); | ||
| 878 | xasprintf(&perfdata_line, ""); | ||
| 879 | } else { | ||
| 880 | xasprintf(&result_line, "%s %s %.10g secs", result_line, _("Offset"), offset); | ||
| 881 | xasprintf(&perfdata_line, "%s", perfd_offset(offset)); | ||
| 882 | } | ||
| 883 | if (do_jitter) { | ||
| 884 | xasprintf(&result_line, "%s, jitter=%f", result_line, jitter); | ||
| 885 | xasprintf(&perfdata_line, "%s %s", perfdata_line, perfd_jitter(jitter)); | ||
| 886 | } | ||
| 887 | printf("%s|%s\n", result_line, perfdata_line); | ||
| 888 | |||
| 889 | if (server_address != NULL) { | ||
| 890 | free(server_address); | ||
| 891 | } | ||
| 892 | return result; | ||
| 893 | } | ||
| 894 | |||
| 895 | void print_help(void) { | ||
| 896 | print_revision(progname, NP_VERSION); | ||
| 897 | |||
| 898 | printf("Copyright (c) 2006 Sean Finney\n"); | ||
| 899 | printf(COPYRIGHT, copyright, email); | ||
| 900 | |||
| 901 | printf("%s\n", _("This plugin checks the selected ntp server")); | ||
| 902 | |||
| 903 | printf("\n\n"); | ||
| 904 | |||
| 905 | print_usage(); | ||
| 906 | printf(UT_HELP_VRSN); | ||
| 907 | printf(UT_EXTRA_OPTS); | ||
| 908 | printf(UT_HOST_PORT, 'p', "123"); | ||
| 909 | printf(UT_IPv46); | ||
| 910 | printf(" %s\n", "-w, --warning=THRESHOLD"); | ||
| 911 | printf(" %s\n", _("Offset to result in warning status (seconds)")); | ||
| 912 | printf(" %s\n", "-c, --critical=THRESHOLD"); | ||
| 913 | printf(" %s\n", _("Offset to result in critical status (seconds)")); | ||
| 914 | printf(" %s\n", "-j, --jwarn=THRESHOLD"); | ||
| 915 | printf(" %s\n", _("Warning threshold for jitter")); | ||
| 916 | printf(" %s\n", "-k, --jcrit=THRESHOLD"); | ||
| 917 | printf(" %s\n", _("Critical threshold for jitter")); | ||
| 918 | printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); | ||
| 919 | printf(UT_VERBOSE); | ||
| 920 | |||
| 921 | printf("\n"); | ||
| 922 | printf("%s\n", _("Notes:")); | ||
| 923 | printf(UT_THRESHOLDS_NOTES); | ||
| 924 | |||
| 925 | printf("\n"); | ||
| 926 | printf("%s\n", _("Examples:")); | ||
| 927 | printf(" %s\n", _("Normal offset check:")); | ||
| 928 | printf(" %s\n", ("./check_ntp -H ntpserv -w 0.5 -c 1")); | ||
| 929 | printf("\n"); | ||
| 930 | printf(" %s\n", | ||
| 931 | _("Check jitter too, avoiding critical notifications if jitter isn't available")); | ||
| 932 | printf(" %s\n", _("(See Notes above for more details on thresholds formats):")); | ||
| 933 | printf(" %s\n", ("./check_ntp -H ntpserv -w 0.5 -c 1 -j -1:100 -k -1:200")); | ||
| 934 | |||
| 935 | printf(UT_SUPPORT); | ||
| 936 | |||
| 937 | printf("%s\n", _("WARNING: check_ntp is deprecated. Please use check_ntp_peer or")); | ||
| 938 | printf("%s\n\n", _("check_ntp_time instead.")); | ||
| 939 | } | ||
| 940 | |||
| 941 | void print_usage(void) { | ||
| 942 | printf("%s\n", _("WARNING: check_ntp is deprecated. Please use check_ntp_peer or")); | ||
| 943 | printf("%s\n\n", _("check_ntp_time instead.")); | ||
| 944 | printf("%s\n", _("Usage:")); | ||
| 945 | printf(" %s -H <host> [-w <warn>] [-c <crit>] [-j <warn>] [-k <crit>] [-4|-6] [-v verbose]\n", | ||
| 946 | progname); | ||
| 947 | } | ||
diff --git a/plugins/check_ntp_peer.c b/plugins/check_ntp_peer.c index f7cad630..26f74286 100644 --- a/plugins/check_ntp_peer.c +++ b/plugins/check_ntp_peer.c | |||
| @@ -625,7 +625,7 @@ check_ntp_peer_config_wrapper process_arguments(int argc, char **argv) { | |||
| 625 | mp_thresholds_set_crit(result.config.truechimer_thresholds, tmp.range); | 625 | mp_thresholds_set_crit(result.config.truechimer_thresholds, tmp.range); |
| 626 | } break; | 626 | } break; |
| 627 | case 'H': | 627 | case 'H': |
| 628 | if (!is_host(optarg)) { | 628 | if (!is_host(optarg) && (optarg[0] != '/')) { |
| 629 | usage2(_("Invalid hostname/address"), optarg); | 629 | usage2(_("Invalid hostname/address"), optarg); |
| 630 | } | 630 | } |
| 631 | result.config.server_address = strdup(optarg); | 631 | result.config.server_address = strdup(optarg); |
diff --git a/plugins/check_ntp_time.c b/plugins/check_ntp_time.c index 602b6010..9e0beb9c 100644 --- a/plugins/check_ntp_time.c +++ b/plugins/check_ntp_time.c | |||
| @@ -42,6 +42,8 @@ | |||
| 42 | #include "states.h" | 42 | #include "states.h" |
| 43 | #include "thresholds.h" | 43 | #include "thresholds.h" |
| 44 | #include "check_ntp_time.d/config.h" | 44 | #include "check_ntp_time.d/config.h" |
| 45 | #include <netinet/in.h> | ||
| 46 | #include <sys/socket.h> | ||
| 45 | 47 | ||
| 46 | static int verbose = 0; | 48 | static int verbose = 0; |
| 47 | 49 | ||
| @@ -336,17 +338,25 @@ static offset_request_wrapper offset_request(const char *host, const char *port, | |||
| 336 | hints.ai_protocol = IPPROTO_UDP; | 338 | hints.ai_protocol = IPPROTO_UDP; |
| 337 | hints.ai_socktype = SOCK_DGRAM; | 339 | hints.ai_socktype = SOCK_DGRAM; |
| 338 | 340 | ||
| 339 | /* fill in ai with the list of hosts resolved by the host name */ | 341 | bool is_socket; |
| 340 | struct addrinfo *addresses = NULL; | 342 | struct addrinfo *addresses = NULL; |
| 341 | int ga_result = getaddrinfo(host, port, &hints, &addresses); | ||
| 342 | if (ga_result != 0) { | ||
| 343 | die(STATE_UNKNOWN, "error getting address for %s: %s\n", host, gai_strerror(ga_result)); | ||
| 344 | } | ||
| 345 | |||
| 346 | /* count the number of returned hosts, and allocate stuff accordingly */ | ||
| 347 | size_t num_hosts = 0; | 343 | size_t num_hosts = 0; |
| 348 | for (struct addrinfo *ai_tmp = addresses; ai_tmp != NULL; ai_tmp = ai_tmp->ai_next) { | 344 | if (host[0] == '/') { |
| 349 | num_hosts++; | 345 | num_hosts = 1; |
| 346 | is_socket = true; | ||
| 347 | } else { | ||
| 348 | is_socket = false; | ||
| 349 | |||
| 350 | /* fill in ai with the list of hosts resolved by the host name */ | ||
| 351 | int ga_result = getaddrinfo(host, port, &hints, &addresses); | ||
| 352 | if (ga_result != 0) { | ||
| 353 | die(STATE_UNKNOWN, "error getting address for %s: %s\n", host, gai_strerror(ga_result)); | ||
| 354 | } | ||
| 355 | |||
| 356 | /* count the number of returned hosts, and allocate stuff accordingly */ | ||
| 357 | for (struct addrinfo *ai_tmp = addresses; ai_tmp != NULL; ai_tmp = ai_tmp->ai_next) { | ||
| 358 | num_hosts++; | ||
| 359 | } | ||
| 350 | } | 360 | } |
| 351 | 361 | ||
| 352 | ntp_message *req = (ntp_message *)malloc(sizeof(ntp_message) * num_hosts); | 362 | ntp_message *req = (ntp_message *)malloc(sizeof(ntp_message) * num_hosts); |
| @@ -374,25 +384,51 @@ static offset_request_wrapper offset_request(const char *host, const char *port, | |||
| 374 | DBG(printf("Found %zu peers to check\n", num_hosts)); | 384 | DBG(printf("Found %zu peers to check\n", num_hosts)); |
| 375 | 385 | ||
| 376 | /* setup each socket for writing, and the corresponding struct pollfd */ | 386 | /* setup each socket for writing, and the corresponding struct pollfd */ |
| 377 | struct addrinfo *ai_tmp = addresses; | 387 | if (is_socket) { |
| 378 | for (int i = 0; ai_tmp; i++) { | 388 | socklist[0] = socket(AF_UNIX, SOCK_STREAM, 0); |
| 379 | socklist[i] = socket(ai_tmp->ai_family, SOCK_DGRAM, IPPROTO_UDP); | 389 | if (socklist[0] == -1) { |
| 380 | if (socklist[i] == -1) { | 390 | DBG(printf("can't create socket: %s\n", strerror(errno))); |
| 381 | perror(NULL); | 391 | die(STATE_UNKNOWN, "can not create new socket\n"); |
| 382 | die(STATE_UNKNOWN, "can not create new socket"); | ||
| 383 | } | 392 | } |
| 384 | if (connect(socklist[i], ai_tmp->ai_addr, ai_tmp->ai_addrlen)) { | 393 | |
| 394 | struct sockaddr_un unix_socket = { | ||
| 395 | .sun_family = AF_UNIX, | ||
| 396 | }; | ||
| 397 | |||
| 398 | strncpy(unix_socket.sun_path, host, strlen(host)); | ||
| 399 | |||
| 400 | if (connect(socklist[0], &unix_socket, sizeof(unix_socket))) { | ||
| 385 | /* don't die here, because it is enough if there is one server | 401 | /* don't die here, because it is enough if there is one server |
| 386 | answering in time. This also would break for dual ipv4/6 stacked | 402 | answering in time. This also would break for dual ipv4/6 stacked |
| 387 | ntp servers when the client only supports on of them. | 403 | ntp servers when the client only supports on of them. |
| 388 | */ | 404 | */ |
| 389 | DBG(printf("can't create socket connection on peer %i: %s\n", i, strerror(errno))); | 405 | DBG(printf("can't create socket connection on peer %i: %s\n", 0, strerror(errno))); |
| 390 | } else { | 406 | } else { |
| 391 | ufds[i].fd = socklist[i]; | 407 | ufds[0].fd = socklist[0]; |
| 392 | ufds[i].events = POLLIN; | 408 | ufds[0].events = POLLIN; |
| 393 | ufds[i].revents = 0; | 409 | ufds[0].revents = 0; |
| 410 | } | ||
| 411 | } else { | ||
| 412 | struct addrinfo *ai_tmp = addresses; | ||
| 413 | for (int i = 0; ai_tmp; i++) { | ||
| 414 | socklist[i] = socket(ai_tmp->ai_family, SOCK_DGRAM, IPPROTO_UDP); | ||
| 415 | if (socklist[i] == -1) { | ||
| 416 | perror(NULL); | ||
| 417 | die(STATE_UNKNOWN, "can not create new socket"); | ||
| 418 | } | ||
| 419 | if (connect(socklist[i], ai_tmp->ai_addr, ai_tmp->ai_addrlen)) { | ||
| 420 | /* don't die here, because it is enough if there is one server | ||
| 421 | answering in time. This also would break for dual ipv4/6 stacked | ||
| 422 | ntp servers when the client only supports on of them. | ||
| 423 | */ | ||
| 424 | DBG(printf("can't create socket connection on peer %i: %s\n", i, strerror(errno))); | ||
| 425 | } else { | ||
| 426 | ufds[i].fd = socklist[i]; | ||
| 427 | ufds[i].events = POLLIN; | ||
| 428 | ufds[i].revents = 0; | ||
| 429 | } | ||
| 430 | ai_tmp = ai_tmp->ai_next; | ||
| 394 | } | 431 | } |
| 395 | ai_tmp = ai_tmp->ai_next; | ||
| 396 | } | 432 | } |
| 397 | 433 | ||
| 398 | /* now do AVG_NUM checks to each host. We stop before timeout/2 seconds | 434 | /* now do AVG_NUM checks to each host. We stop before timeout/2 seconds |
| @@ -586,7 +622,7 @@ static check_ntp_time_config_wrapper process_arguments(int argc, char **argv) { | |||
| 586 | mp_thresholds_set_crit(result.config.offset_thresholds, tmp.range); | 622 | mp_thresholds_set_crit(result.config.offset_thresholds, tmp.range); |
| 587 | } break; | 623 | } break; |
| 588 | case 'H': | 624 | case 'H': |
| 589 | if (!is_host(optarg)) { | 625 | if (!is_host(optarg) && (optarg[0] != '/')) { |
| 590 | usage2(_("Invalid hostname/address"), optarg); | 626 | usage2(_("Invalid hostname/address"), optarg); |
| 591 | } | 627 | } |
| 592 | result.config.server_address = strdup(optarg); | 628 | result.config.server_address = strdup(optarg); |
diff --git a/plugins/check_radius.c b/plugins/check_radius.c index d26f7cf3..93352bcc 100644 --- a/plugins/check_radius.c +++ b/plugins/check_radius.c | |||
| @@ -28,6 +28,7 @@ | |||
| 28 | * | 28 | * |
| 29 | *****************************************************************************/ | 29 | *****************************************************************************/ |
| 30 | 30 | ||
| 31 | #include "output.h" | ||
| 31 | const char *progname = "check_radius"; | 32 | const char *progname = "check_radius"; |
| 32 | const char *copyright = "2000-2024"; | 33 | const char *copyright = "2000-2024"; |
| 33 | const char *email = "devel@monitoring-plugins.org"; | 34 | const char *email = "devel@monitoring-plugins.org"; |
| @@ -158,49 +159,80 @@ int main(int argc, char **argv) { | |||
| 158 | 159 | ||
| 159 | check_radius_config config = tmp_config.config; | 160 | check_radius_config config = tmp_config.config; |
| 160 | 161 | ||
| 162 | if (config.output_format_is_set) { | ||
| 163 | mp_set_format(config.output_format); | ||
| 164 | } | ||
| 165 | |||
| 161 | #if defined(HAVE_LIBFREERADIUS_CLIENT) || defined(HAVE_LIBRADIUSCLIENT_NG) || \ | 166 | #if defined(HAVE_LIBFREERADIUS_CLIENT) || defined(HAVE_LIBRADIUSCLIENT_NG) || \ |
| 162 | defined(HAVE_LIBRADCLI) | 167 | defined(HAVE_LIBRADCLI) |
| 163 | rc_handle *rch = NULL; | 168 | rc_handle *rch = NULL; |
| 164 | #endif | 169 | #endif |
| 165 | 170 | ||
| 171 | mp_check overall = mp_check_init(); | ||
| 172 | mp_subcheck sc_read_config = mp_subcheck_init(); | ||
| 173 | |||
| 166 | char *str = strdup("dictionary"); | 174 | char *str = strdup("dictionary"); |
| 167 | if ((config.config_file && my_rc_read_config(config.config_file, &rch)) || | 175 | if ((config.config_file && my_rc_read_config(config.config_file, &rch)) || |
| 168 | my_rc_read_dictionary(my_rc_conf_str(str))) { | 176 | my_rc_read_dictionary(my_rc_conf_str(str))) { |
| 169 | die(STATE_UNKNOWN, _("Config file error\n")); | 177 | sc_read_config = mp_set_subcheck_state(sc_read_config, STATE_UNKNOWN); |
| 178 | xasprintf(&sc_read_config.output, "failed to read config file"); | ||
| 179 | mp_add_subcheck_to_check(&overall, sc_read_config); | ||
| 180 | mp_exit(overall); | ||
| 170 | } | 181 | } |
| 171 | 182 | ||
| 183 | sc_read_config = mp_set_subcheck_state(sc_read_config, STATE_OK); | ||
| 184 | xasprintf(&sc_read_config.output, "read config file successfully"); | ||
| 185 | mp_add_subcheck_to_check(&overall, sc_read_config); | ||
| 186 | |||
| 172 | uint32_t service = PW_AUTHENTICATE_ONLY; | 187 | uint32_t service = PW_AUTHENTICATE_ONLY; |
| 173 | 188 | ||
| 189 | mp_subcheck sc_configuring = mp_subcheck_init(); | ||
| 174 | SEND_DATA data; | 190 | SEND_DATA data; |
| 175 | memset(&data, 0, sizeof(data)); | 191 | memset(&data, 0, sizeof(data)); |
| 176 | if (!(my_rc_avpair_add(&data.send_pairs, PW_SERVICE_TYPE, &service, 0) && | 192 | if (!(my_rc_avpair_add(&data.send_pairs, PW_SERVICE_TYPE, &service, 0) && |
| 177 | my_rc_avpair_add(&data.send_pairs, PW_USER_NAME, config.username, 0) && | 193 | my_rc_avpair_add(&data.send_pairs, PW_USER_NAME, config.username, 0) && |
| 178 | my_rc_avpair_add(&data.send_pairs, PW_USER_PASSWORD, config.password, 0))) { | 194 | my_rc_avpair_add(&data.send_pairs, PW_USER_PASSWORD, config.password, 0))) { |
| 179 | die(STATE_UNKNOWN, _("Out of Memory?\n")); | 195 | xasprintf(&sc_configuring.output, "Failed to the radius options: Out of Memory?"); |
| 196 | sc_configuring = mp_set_subcheck_state(sc_configuring, STATE_UNKNOWN); | ||
| 197 | mp_add_subcheck_to_check(&overall, sc_configuring); | ||
| 198 | mp_exit(overall); | ||
| 180 | } | 199 | } |
| 181 | 200 | ||
| 182 | if (config.nas_id != NULL) { | 201 | if (config.nas_id != NULL) { |
| 183 | if (!(my_rc_avpair_add(&data.send_pairs, PW_NAS_IDENTIFIER, config.nas_id, 0))) { | 202 | if (!(my_rc_avpair_add(&data.send_pairs, PW_NAS_IDENTIFIER, config.nas_id, 0))) { |
| 184 | die(STATE_UNKNOWN, _("Invalid NAS-Identifier\n")); | 203 | xasprintf(&sc_configuring.output, |
| 204 | "Failed to the radius options: invalid NAS identifier?"); | ||
| 205 | sc_configuring = mp_set_subcheck_state(sc_configuring, STATE_UNKNOWN); | ||
| 206 | mp_add_subcheck_to_check(&overall, sc_configuring); | ||
| 207 | mp_exit(overall); | ||
| 185 | } | 208 | } |
| 186 | } | 209 | } |
| 187 | 210 | ||
| 188 | char name[HOST_NAME_MAX]; | 211 | char name[HOST_NAME_MAX]; |
| 189 | if (config.nas_ip_address == NULL) { | 212 | if (config.nas_ip_address == NULL) { |
| 190 | if (gethostname(name, sizeof(name)) != 0) { | 213 | if (gethostname(name, sizeof(name)) != 0) { |
| 191 | die(STATE_UNKNOWN, _("gethostname() failed!\n")); | 214 | xasprintf(&sc_configuring.output, "gethostname() failed"); |
| 215 | sc_configuring = mp_set_subcheck_state(sc_configuring, STATE_UNKNOWN); | ||
| 216 | mp_add_subcheck_to_check(&overall, sc_configuring); | ||
| 217 | mp_exit(overall); | ||
| 192 | } | 218 | } |
| 193 | config.nas_ip_address = name; | 219 | config.nas_ip_address = name; |
| 194 | } | 220 | } |
| 195 | 221 | ||
| 196 | struct sockaddr_storage radius_server_socket; | 222 | struct sockaddr_storage radius_server_socket; |
| 197 | if (!dns_lookup(config.nas_ip_address, &radius_server_socket, AF_UNSPEC)) { | 223 | if (!dns_lookup(config.nas_ip_address, &radius_server_socket, AF_UNSPEC)) { |
| 198 | die(STATE_UNKNOWN, _("Invalid NAS-IP-Address\n")); | 224 | xasprintf(&sc_configuring.output, "invalid NAS IP address. Lookup failed"); |
| 225 | sc_configuring = mp_set_subcheck_state(sc_configuring, STATE_UNKNOWN); | ||
| 226 | mp_add_subcheck_to_check(&overall, sc_configuring); | ||
| 227 | mp_exit(overall); | ||
| 199 | } | 228 | } |
| 200 | 229 | ||
| 201 | uint32_t client_id = ntohl(((struct sockaddr_in *)&radius_server_socket)->sin_addr.s_addr); | 230 | uint32_t client_id = ntohl(((struct sockaddr_in *)&radius_server_socket)->sin_addr.s_addr); |
| 202 | if (my_rc_avpair_add(&(data.send_pairs), PW_NAS_IP_ADDRESS, &client_id, 0) == NULL) { | 231 | if (my_rc_avpair_add(&(data.send_pairs), PW_NAS_IP_ADDRESS, &client_id, 0) == NULL) { |
| 203 | die(STATE_UNKNOWN, _("Invalid NAS-IP-Address\n")); | 232 | xasprintf(&sc_configuring.output, "invalid NAS IP address. Setting option failed"); |
| 233 | sc_configuring = mp_set_subcheck_state(sc_configuring, STATE_UNKNOWN); | ||
| 234 | mp_add_subcheck_to_check(&overall, sc_configuring); | ||
| 235 | mp_exit(overall); | ||
| 204 | } | 236 | } |
| 205 | 237 | ||
| 206 | my_rc_buildreq(&data, PW_ACCESS_REQUEST, config.server, config.port, (int)timeout_interval, | 238 | my_rc_buildreq(&data, PW_ACCESS_REQUEST, config.server, config.port, (int)timeout_interval, |
| @@ -218,51 +250,78 @@ int main(int argc, char **argv) { | |||
| 218 | rc_avpair_free(data.receive_pairs); | 250 | rc_avpair_free(data.receive_pairs); |
| 219 | } | 251 | } |
| 220 | 252 | ||
| 253 | mp_subcheck sc_eval = mp_subcheck_init(); | ||
| 254 | |||
| 221 | if (result == TIMEOUT_RC) { | 255 | if (result == TIMEOUT_RC) { |
| 222 | printf("Timeout\n"); | 256 | xasprintf(&sc_eval.output, "timeout"); |
| 223 | exit(STATE_CRITICAL); | 257 | sc_eval = mp_set_subcheck_state(sc_eval, STATE_CRITICAL); |
| 258 | mp_add_subcheck_to_check(&overall, sc_eval); | ||
| 259 | mp_exit(overall); | ||
| 224 | } | 260 | } |
| 225 | 261 | ||
| 226 | if (result == ERROR_RC) { | 262 | if (result == ERROR_RC) { |
| 227 | printf(_("Auth Error\n")); | 263 | xasprintf(&sc_eval.output, "auth error"); |
| 228 | exit(STATE_CRITICAL); | 264 | sc_eval = mp_set_subcheck_state(sc_eval, STATE_CRITICAL); |
| 265 | mp_add_subcheck_to_check(&overall, sc_eval); | ||
| 266 | mp_exit(overall); | ||
| 229 | } | 267 | } |
| 230 | 268 | ||
| 231 | if (result == REJECT_RC) { | 269 | if (result == REJECT_RC) { |
| 232 | printf(_("Auth Failed\n")); | 270 | xasprintf(&sc_eval.output, "auth failed"); |
| 233 | exit(STATE_WARNING); | 271 | sc_eval = mp_set_subcheck_state(sc_eval, STATE_WARNING); |
| 272 | mp_add_subcheck_to_check(&overall, sc_eval); | ||
| 273 | mp_exit(overall); | ||
| 234 | } | 274 | } |
| 235 | 275 | ||
| 236 | if (result == BADRESP_RC) { | 276 | if (result == BADRESP_RC) { |
| 237 | printf(_("Bad Response\n")); | 277 | xasprintf(&sc_eval.output, "bad response"); |
| 238 | exit(STATE_WARNING); | 278 | sc_eval = mp_set_subcheck_state(sc_eval, STATE_WARNING); |
| 279 | mp_add_subcheck_to_check(&overall, sc_eval); | ||
| 280 | mp_exit(overall); | ||
| 239 | } | 281 | } |
| 240 | 282 | ||
| 241 | if (config.expect && !strstr(msg, config.expect)) { | 283 | if (config.expect && !strstr(msg, config.expect)) { |
| 242 | printf("%s\n", msg); | 284 | xasprintf(&sc_eval.output, "%s", msg); |
| 243 | exit(STATE_WARNING); | 285 | sc_eval = mp_set_subcheck_state(sc_eval, STATE_WARNING); |
| 286 | mp_add_subcheck_to_check(&overall, sc_eval); | ||
| 287 | mp_exit(overall); | ||
| 244 | } | 288 | } |
| 245 | 289 | ||
| 246 | if (result == OK_RC) { | 290 | if (result == OK_RC) { |
| 247 | printf(_("Auth OK\n")); | 291 | xasprintf(&sc_eval.output, "auth OK"); |
| 248 | exit(STATE_OK); | 292 | sc_eval = mp_set_subcheck_state(sc_eval, STATE_OK); |
| 293 | mp_add_subcheck_to_check(&overall, sc_eval); | ||
| 294 | mp_exit(overall); | ||
| 249 | } | 295 | } |
| 250 | 296 | ||
| 251 | (void)snprintf(msg, sizeof(msg), _("Unexpected result code %d"), result); | 297 | xasprintf(&sc_eval.output, "unexpected result code: %d", result); |
| 252 | printf("%s\n", msg); | 298 | sc_eval = mp_set_subcheck_state(sc_eval, STATE_UNKNOWN); |
| 253 | exit(STATE_UNKNOWN); | 299 | mp_add_subcheck_to_check(&overall, sc_eval); |
| 300 | |||
| 301 | mp_exit(overall); | ||
| 254 | } | 302 | } |
| 255 | 303 | ||
| 256 | /* process command-line arguments */ | 304 | /* process command-line arguments */ |
| 257 | check_radius_config_wrapper process_arguments(int argc, char **argv) { | 305 | check_radius_config_wrapper process_arguments(int argc, char **argv) { |
| 258 | static struct option longopts[] = { | 306 | enum { |
| 259 | {"hostname", required_argument, 0, 'H'}, {"port", required_argument, 0, 'P'}, | 307 | output_format_index |
| 260 | {"username", required_argument, 0, 'u'}, {"password", required_argument, 0, 'p'}, | 308 | }; |
| 261 | {"nas-id", required_argument, 0, 'n'}, {"nas-ip-address", required_argument, 0, 'N'}, | 309 | |
| 262 | {"filename", required_argument, 0, 'F'}, {"expect", required_argument, 0, 'e'}, | 310 | static struct option longopts[] = {{"hostname", required_argument, 0, 'H'}, |
| 263 | {"retries", required_argument, 0, 'r'}, {"timeout", required_argument, 0, 't'}, | 311 | {"port", required_argument, 0, 'P'}, |
| 264 | {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, | 312 | {"username", required_argument, 0, 'u'}, |
| 265 | {"help", no_argument, 0, 'h'}, {0, 0, 0, 0}}; | 313 | {"password", required_argument, 0, 'p'}, |
| 314 | {"nas-id", required_argument, 0, 'n'}, | ||
| 315 | {"nas-ip-address", required_argument, 0, 'N'}, | ||
| 316 | {"filename", required_argument, 0, 'F'}, | ||
| 317 | {"expect", required_argument, 0, 'e'}, | ||
| 318 | {"retries", required_argument, 0, 'r'}, | ||
| 319 | {"timeout", required_argument, 0, 't'}, | ||
| 320 | {"verbose", no_argument, 0, 'v'}, | ||
| 321 | {"version", no_argument, 0, 'V'}, | ||
| 322 | {"help", no_argument, 0, 'h'}, | ||
| 323 | {"output-format", required_argument, 0, output_format_index}, | ||
| 324 | {0, 0, 0, 0}}; | ||
| 266 | 325 | ||
| 267 | check_radius_config_wrapper result = { | 326 | check_radius_config_wrapper result = { |
| 268 | .errorcode = OK, | 327 | .errorcode = OK, |
| @@ -340,6 +399,18 @@ check_radius_config_wrapper process_arguments(int argc, char **argv) { | |||
| 340 | usage2(_("Timeout interval must be a positive integer"), optarg); | 399 | usage2(_("Timeout interval must be a positive integer"), optarg); |
| 341 | } | 400 | } |
| 342 | break; | 401 | break; |
| 402 | case output_format_index: { | ||
| 403 | parsed_output_format parser = mp_parse_output_format(optarg); | ||
| 404 | if (!parser.parsing_success) { | ||
| 405 | // TODO List all available formats here, maybe add anothoer usage function | ||
| 406 | printf("Invalid output format: %s\n", optarg); | ||
| 407 | exit(STATE_UNKNOWN); | ||
| 408 | } | ||
| 409 | |||
| 410 | result.config.output_format_is_set = true; | ||
| 411 | result.config.output_format = parser.output_format; | ||
| 412 | break; | ||
| 413 | } | ||
| 343 | } | 414 | } |
| 344 | } | 415 | } |
| 345 | 416 | ||
| @@ -393,6 +464,7 @@ void print_help(void) { | |||
| 393 | printf(" %s\n", _("Response string to expect from the server")); | 464 | printf(" %s\n", _("Response string to expect from the server")); |
| 394 | printf(" %s\n", "-r, --retries=INTEGER"); | 465 | printf(" %s\n", "-r, --retries=INTEGER"); |
| 395 | printf(" %s\n", _("Number of times to retry a failed connection")); | 466 | printf(" %s\n", _("Number of times to retry a failed connection")); |
| 467 | printf(UT_OUTPUT_FORMAT); | ||
| 396 | 468 | ||
| 397 | printf(UT_CONN_TIMEOUT, timeout_interval); | 469 | printf(UT_CONN_TIMEOUT, timeout_interval); |
| 398 | 470 | ||
diff --git a/plugins/check_radius.d/config.h b/plugins/check_radius.d/config.h index b27d31e7..656bf98e 100644 --- a/plugins/check_radius.d/config.h +++ b/plugins/check_radius.d/config.h | |||
| @@ -1,6 +1,7 @@ | |||
| 1 | #pragma once | 1 | #pragma once |
| 2 | 2 | ||
| 3 | #include "../../config.h" | 3 | #include "../../config.h" |
| 4 | #include "output.h" | ||
| 4 | #include <stddef.h> | 5 | #include <stddef.h> |
| 5 | #if defined(HAVE_LIBRADCLI) | 6 | #if defined(HAVE_LIBRADCLI) |
| 6 | # include <radcli/radcli.h> | 7 | # include <radcli/radcli.h> |
| @@ -23,6 +24,9 @@ typedef struct { | |||
| 23 | unsigned short port; | 24 | unsigned short port; |
| 24 | 25 | ||
| 25 | char *expect; | 26 | char *expect; |
| 27 | |||
| 28 | bool output_format_is_set; | ||
| 29 | mp_output_format output_format; | ||
| 26 | } check_radius_config; | 30 | } check_radius_config; |
| 27 | 31 | ||
| 28 | check_radius_config check_radius_config_init() { | 32 | check_radius_config check_radius_config_init() { |
| @@ -37,6 +41,8 @@ check_radius_config check_radius_config_init() { | |||
| 37 | .port = PW_AUTH_UDP_PORT, | 41 | .port = PW_AUTH_UDP_PORT, |
| 38 | 42 | ||
| 39 | .expect = NULL, | 43 | .expect = NULL, |
| 44 | |||
| 45 | .output_format_is_set = false, | ||
| 40 | }; | 46 | }; |
| 41 | return tmp; | 47 | return tmp; |
| 42 | } | 48 | } |
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 @@ | |||
| 28 | * | 28 | * |
| 29 | *****************************************************************************/ | 29 | *****************************************************************************/ |
| 30 | 30 | ||
| 31 | #include "output.h" | ||
| 32 | #include "perfdata.h" | ||
| 31 | #include "states.h" | 33 | #include "states.h" |
| 32 | #include <stdio.h> | 34 | #include <stdio.h> |
| 33 | const char *progname = "check_real"; | ||
| 34 | const char *copyright = "2000-2024"; | ||
| 35 | const char *email = "devel@monitoring-plugins.org"; | ||
| 36 | |||
| 37 | #include "common.h" | 35 | #include "common.h" |
| 38 | #include "netutils.h" | 36 | #include "netutils.h" |
| 37 | #include "thresholds.h" | ||
| 39 | #include "utils.h" | 38 | #include "utils.h" |
| 40 | #include "check_real.d/config.h" | 39 | #include "check_real.d/config.h" |
| 41 | 40 | ||
| 42 | #define EXPECT "RTSP/1." | 41 | const char *progname = "check_real"; |
| 43 | #define URL "" | 42 | const char *copyright = "2000-2024"; |
| 43 | const char *email = "devel@monitoring-plugins.org"; | ||
| 44 | |||
| 45 | #define URL "" | ||
| 44 | 46 | ||
| 45 | typedef struct { | 47 | typedef struct { |
| 46 | int errorcode; | 48 | int errorcode; |
| @@ -68,42 +70,68 @@ int main(int argc, char **argv) { | |||
| 68 | 70 | ||
| 69 | const check_real_config config = tmp_config.config; | 71 | const check_real_config config = tmp_config.config; |
| 70 | 72 | ||
| 73 | if (config.output_format_is_set) { | ||
| 74 | mp_set_format(config.output_format); | ||
| 75 | } | ||
| 76 | |||
| 71 | /* initialize alarm signal handling */ | 77 | /* initialize alarm signal handling */ |
| 72 | signal(SIGALRM, socket_timeout_alarm_handler); | 78 | signal(SIGALRM, socket_timeout_alarm_handler); |
| 73 | 79 | ||
| 74 | /* set socket timeout */ | 80 | /* set socket timeout */ |
| 75 | alarm(socket_timeout); | 81 | alarm(socket_timeout); |
| 82 | time_t start_time; | ||
| 76 | time(&start_time); | 83 | time(&start_time); |
| 77 | 84 | ||
| 85 | mp_check overall = mp_check_init(); | ||
| 86 | mp_subcheck sc_connect = mp_subcheck_init(); | ||
| 87 | |||
| 78 | /* try to connect to the host at the given port number */ | 88 | /* try to connect to the host at the given port number */ |
| 79 | int socket; | 89 | int socket; |
| 80 | if (my_tcp_connect(config.server_address, config.server_port, &socket) != STATE_OK) { | 90 | if (my_tcp_connect(config.server_address, config.server_port, &socket) != STATE_OK) { |
| 81 | die(STATE_CRITICAL, _("Unable to connect to %s on port %d\n"), config.server_address, | 91 | xasprintf(&sc_connect.output, _("unable to connect to %s on port %d"), |
| 82 | config.server_port); | 92 | config.server_address, config.server_port); |
| 93 | sc_connect = mp_set_subcheck_state(sc_connect, STATE_CRITICAL); | ||
| 94 | mp_add_subcheck_to_check(&overall, sc_connect); | ||
| 95 | mp_exit(overall); | ||
| 83 | } | 96 | } |
| 84 | 97 | ||
| 98 | xasprintf(&sc_connect.output, _("connected to %s on port %d"), config.server_address, | ||
| 99 | config.server_port); | ||
| 100 | sc_connect = mp_set_subcheck_state(sc_connect, STATE_OK); | ||
| 101 | mp_add_subcheck_to_check(&overall, sc_connect); | ||
| 102 | |||
| 85 | /* Part I - Server Check */ | 103 | /* Part I - Server Check */ |
| 104 | mp_subcheck sc_send = mp_subcheck_init(); | ||
| 86 | 105 | ||
| 87 | /* send the OPTIONS request */ | 106 | /* send the OPTIONS request */ |
| 88 | char buffer[MAX_INPUT_BUFFER]; | 107 | char buffer[MAX_INPUT_BUFFER]; |
| 89 | sprintf(buffer, "OPTIONS rtsp://%s:%d RTSP/1.0\r\n", config.host_name, config.server_port); | 108 | sprintf(buffer, "OPTIONS rtsp://%s:%d RTSP/1.0\r\n", config.host_name, config.server_port); |
| 90 | ssize_t sent_bytes = send(socket, buffer, strlen(buffer), 0); | 109 | ssize_t sent_bytes = send(socket, buffer, strlen(buffer), 0); |
| 91 | if (sent_bytes == -1) { | 110 | if (sent_bytes == -1) { |
| 92 | die(STATE_CRITICAL, _("Sending options to %s failed\n"), config.host_name); | 111 | xasprintf(&sc_send.output, _("Sending options to %s failed"), config.host_name); |
| 112 | sc_send = mp_set_subcheck_state(sc_send, STATE_CRITICAL); | ||
| 113 | mp_add_subcheck_to_check(&overall, sc_send); | ||
| 114 | mp_exit(overall); | ||
| 93 | } | 115 | } |
| 94 | 116 | ||
| 95 | /* send the header sync */ | 117 | /* send the header sync */ |
| 96 | sprintf(buffer, "CSeq: 1\r\n"); | 118 | sprintf(buffer, "CSeq: 1\r\n"); |
| 97 | sent_bytes = send(socket, buffer, strlen(buffer), 0); | 119 | sent_bytes = send(socket, buffer, strlen(buffer), 0); |
| 98 | if (sent_bytes == -1) { | 120 | if (sent_bytes == -1) { |
| 99 | die(STATE_CRITICAL, _("Sending header sync to %s failed\n"), config.host_name); | 121 | xasprintf(&sc_send.output, _("Sending header sync to %s failed"), config.host_name); |
| 122 | sc_send = mp_set_subcheck_state(sc_send, STATE_CRITICAL); | ||
| 123 | mp_add_subcheck_to_check(&overall, sc_send); | ||
| 124 | mp_exit(overall); | ||
| 100 | } | 125 | } |
| 101 | 126 | ||
| 102 | /* send a newline so the server knows we're done with the request */ | 127 | /* send a newline so the server knows we're done with the request */ |
| 103 | sprintf(buffer, "\r\n"); | 128 | sprintf(buffer, "\r\n"); |
| 104 | sent_bytes = send(socket, buffer, strlen(buffer), 0); | 129 | sent_bytes = send(socket, buffer, strlen(buffer), 0); |
| 105 | if (sent_bytes == -1) { | 130 | if (sent_bytes == -1) { |
| 106 | die(STATE_CRITICAL, _("Sending newline to %s failed\n"), config.host_name); | 131 | xasprintf(&sc_send.output, _("Sending newline to %s failed"), config.host_name); |
| 132 | sc_send = mp_set_subcheck_state(sc_send, STATE_CRITICAL); | ||
| 133 | mp_add_subcheck_to_check(&overall, sc_send); | ||
| 134 | mp_exit(overall); | ||
| 107 | } | 135 | } |
| 108 | 136 | ||
| 109 | /* watch for the REAL connection string */ | 137 | /* watch for the REAL connection string */ |
| @@ -111,60 +139,75 @@ int main(int argc, char **argv) { | |||
| 111 | 139 | ||
| 112 | /* return a CRITICAL status if we couldn't read any data */ | 140 | /* return a CRITICAL status if we couldn't read any data */ |
| 113 | if (received_bytes == -1) { | 141 | if (received_bytes == -1) { |
| 114 | die(STATE_CRITICAL, _("No data received from %s\n"), config.host_name); | 142 | xasprintf(&sc_send.output, _("No data received from %s"), config.host_name); |
| 143 | sc_send = mp_set_subcheck_state(sc_send, STATE_CRITICAL); | ||
| 144 | mp_add_subcheck_to_check(&overall, sc_send); | ||
| 145 | mp_exit(overall); | ||
| 115 | } | 146 | } |
| 116 | 147 | ||
| 117 | mp_state_enum result = STATE_OK; | 148 | time_t end_time; |
| 118 | char *status_line = NULL; | 149 | { |
| 119 | /* make sure we find the response we are looking for */ | 150 | mp_subcheck sc_options_request = mp_subcheck_init(); |
| 120 | if (!strstr(buffer, config.server_expect)) { | 151 | mp_state_enum options_result = STATE_OK; |
| 121 | if (config.server_port == PORT) { | 152 | /* make sure we find the response we are looking for */ |
| 122 | printf("%s\n", _("Invalid REAL response received from host")); | 153 | if (!strstr(buffer, config.server_expect)) { |
| 154 | if (config.server_port == PORT) { | ||
| 155 | xasprintf(&sc_options_request.output, "invalid REAL response received from host"); | ||
| 156 | } else { | ||
| 157 | xasprintf(&sc_options_request.output, | ||
| 158 | "invalid REAL response received from host on port %d", | ||
| 159 | config.server_port); | ||
| 160 | } | ||
| 123 | } else { | 161 | } else { |
| 124 | printf(_("Invalid REAL response received from host on port %d\n"), config.server_port); | 162 | /* else we got the REAL string, so check the return code */ |
| 125 | } | 163 | time(&end_time); |
| 126 | } else { | ||
| 127 | /* else we got the REAL string, so check the return code */ | ||
| 128 | 164 | ||
| 129 | time(&end_time); | 165 | options_result = STATE_OK; |
| 130 | 166 | ||
| 131 | result = STATE_OK; | 167 | char *status_line = strtok(buffer, "\n"); |
| 168 | xasprintf(&sc_options_request.output, "status line: %s", status_line); | ||
| 132 | 169 | ||
| 133 | status_line = strtok(buffer, "\n"); | 170 | if (strstr(status_line, "200")) { |
| 134 | 171 | options_result = STATE_OK; | |
| 135 | if (strstr(status_line, "200")) { | 172 | } |
| 136 | result = STATE_OK; | 173 | /* client errors options_result in a warning state */ |
| 174 | else if (strstr(status_line, "400")) { | ||
| 175 | options_result = STATE_WARNING; | ||
| 176 | } else if (strstr(status_line, "401")) { | ||
| 177 | options_result = STATE_WARNING; | ||
| 178 | } else if (strstr(status_line, "402")) { | ||
| 179 | options_result = STATE_WARNING; | ||
| 180 | } else if (strstr(status_line, "403")) { | ||
| 181 | options_result = STATE_WARNING; | ||
| 182 | } else if (strstr(status_line, "404")) { | ||
| 183 | options_result = STATE_WARNING; | ||
| 184 | } else if (strstr(status_line, "500")) { | ||
| 185 | /* server errors options_result in a critical state */ | ||
| 186 | options_result = STATE_CRITICAL; | ||
| 187 | } else if (strstr(status_line, "501")) { | ||
| 188 | options_result = STATE_CRITICAL; | ||
| 189 | } else if (strstr(status_line, "502")) { | ||
| 190 | options_result = STATE_CRITICAL; | ||
| 191 | } else if (strstr(status_line, "503")) { | ||
| 192 | options_result = STATE_CRITICAL; | ||
| 193 | } else { | ||
| 194 | options_result = STATE_UNKNOWN; | ||
| 195 | } | ||
| 137 | } | 196 | } |
| 138 | 197 | ||
| 139 | /* client errors result in a warning state */ | 198 | sc_options_request = mp_set_subcheck_state(sc_options_request, options_result); |
| 140 | else if (strstr(status_line, "400")) { | 199 | mp_add_subcheck_to_check(&overall, sc_options_request); |
| 141 | result = STATE_WARNING; | 200 | |
| 142 | } else if (strstr(status_line, "401")) { | 201 | if (options_result != STATE_OK) { |
| 143 | result = STATE_WARNING; | 202 | // exit here if Setting options already failed |
| 144 | } else if (strstr(status_line, "402")) { | 203 | mp_exit(overall); |
| 145 | result = STATE_WARNING; | ||
| 146 | } else if (strstr(status_line, "403")) { | ||
| 147 | result = STATE_WARNING; | ||
| 148 | } else if (strstr(status_line, "404")) { | ||
| 149 | result = STATE_WARNING; | ||
| 150 | } else if (strstr(status_line, "500")) { | ||
| 151 | /* server errors result in a critical state */ | ||
| 152 | result = STATE_CRITICAL; | ||
| 153 | } else if (strstr(status_line, "501")) { | ||
| 154 | result = STATE_CRITICAL; | ||
| 155 | } else if (strstr(status_line, "502")) { | ||
| 156 | result = STATE_CRITICAL; | ||
| 157 | } else if (strstr(status_line, "503")) { | ||
| 158 | result = STATE_CRITICAL; | ||
| 159 | } else { | ||
| 160 | result = STATE_UNKNOWN; | ||
| 161 | } | 204 | } |
| 162 | } | 205 | } |
| 163 | 206 | ||
| 164 | /* Part II - Check stream exists and is ok */ | 207 | /* Part II - Check stream exists and is ok */ |
| 165 | if ((result == STATE_OK) && (config.server_url != NULL)) { | 208 | if (config.server_url != NULL) { |
| 166 | |||
| 167 | /* Part I - Server Check */ | 209 | /* Part I - Server Check */ |
| 210 | mp_subcheck sc_describe = mp_subcheck_init(); | ||
| 168 | 211 | ||
| 169 | /* send the DESCRIBE request */ | 212 | /* send the DESCRIBE request */ |
| 170 | sprintf(buffer, "DESCRIBE rtsp://%s:%d%s RTSP/1.0\r\n", config.host_name, | 213 | 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) { | |||
| 172 | 215 | ||
| 173 | ssize_t sent_bytes = send(socket, buffer, strlen(buffer), 0); | 216 | ssize_t sent_bytes = send(socket, buffer, strlen(buffer), 0); |
| 174 | if (sent_bytes == -1) { | 217 | if (sent_bytes == -1) { |
| 175 | die(STATE_CRITICAL, _("Sending DESCRIBE request to %s failed\n"), config.host_name); | 218 | sc_describe = mp_set_subcheck_state(sc_describe, STATE_CRITICAL); |
| 219 | xasprintf(&sc_describe.output, "sending DESCRIBE request to %s failed", | ||
| 220 | config.host_name); | ||
| 221 | mp_add_subcheck_to_check(&overall, sc_describe); | ||
| 222 | mp_exit(overall); | ||
| 176 | } | 223 | } |
| 177 | 224 | ||
| 178 | /* send the header sync */ | 225 | /* send the header sync */ |
| 179 | sprintf(buffer, "CSeq: 2\r\n"); | 226 | sprintf(buffer, "CSeq: 2\r\n"); |
| 180 | sent_bytes = send(socket, buffer, strlen(buffer), 0); | 227 | sent_bytes = send(socket, buffer, strlen(buffer), 0); |
| 181 | if (sent_bytes == -1) { | 228 | if (sent_bytes == -1) { |
| 182 | die(STATE_CRITICAL, _("Sending DESCRIBE request to %s failed\n"), config.host_name); | 229 | sc_describe = mp_set_subcheck_state(sc_describe, STATE_CRITICAL); |
| 230 | xasprintf(&sc_describe.output, "sending DESCRIBE request to %s failed", | ||
| 231 | config.host_name); | ||
| 232 | mp_add_subcheck_to_check(&overall, sc_describe); | ||
| 233 | mp_exit(overall); | ||
| 183 | } | 234 | } |
| 184 | 235 | ||
| 185 | /* send a newline so the server knows we're done with the request */ | 236 | /* send a newline so the server knows we're done with the request */ |
| 186 | sprintf(buffer, "\r\n"); | 237 | sprintf(buffer, "\r\n"); |
| 187 | sent_bytes = send(socket, buffer, strlen(buffer), 0); | 238 | sent_bytes = send(socket, buffer, strlen(buffer), 0); |
| 188 | if (sent_bytes == -1) { | 239 | if (sent_bytes == -1) { |
| 189 | die(STATE_CRITICAL, _("Sending DESCRIBE request to %s failed\n"), config.host_name); | 240 | sc_describe = mp_set_subcheck_state(sc_describe, STATE_CRITICAL); |
| 241 | xasprintf(&sc_describe.output, "sending DESCRIBE request to %s failed", | ||
| 242 | config.host_name); | ||
| 243 | mp_add_subcheck_to_check(&overall, sc_describe); | ||
| 244 | mp_exit(overall); | ||
| 190 | } | 245 | } |
| 191 | 246 | ||
| 192 | /* watch for the REAL connection string */ | 247 | /* watch for the REAL connection string */ |
| 193 | ssize_t recv_bytes = recv(socket, buffer, MAX_INPUT_BUFFER - 1, 0); | 248 | ssize_t recv_bytes = recv(socket, buffer, MAX_INPUT_BUFFER - 1, 0); |
| 194 | if (recv_bytes == -1) { | 249 | if (recv_bytes == -1) { |
| 195 | /* return a CRITICAL status if we couldn't read any data */ | 250 | /* return a CRITICAL status if we couldn't read any data */ |
| 196 | printf(_("No data received from host\n")); | 251 | sc_describe = mp_set_subcheck_state(sc_describe, STATE_CRITICAL); |
| 197 | result = STATE_CRITICAL; | 252 | xasprintf(&sc_describe.output, "No data received from host on DESCRIBE request"); |
| 253 | mp_add_subcheck_to_check(&overall, sc_describe); | ||
| 254 | mp_exit(overall); | ||
| 198 | } else { | 255 | } else { |
| 199 | buffer[result] = '\0'; /* null terminate received buffer */ | 256 | buffer[recv_bytes] = '\0'; /* null terminate received buffer */ |
| 200 | /* make sure we find the response we are looking for */ | 257 | /* make sure we find the response we are looking for */ |
| 201 | if (!strstr(buffer, config.server_expect)) { | 258 | if (!strstr(buffer, config.server_expect)) { |
| 202 | if (config.server_port == PORT) { | 259 | if (config.server_port == PORT) { |
| 203 | printf("%s\n", _("Invalid REAL response received from host")); | 260 | xasprintf(&sc_describe.output, "invalid REAL response received from host"); |
| 204 | } else { | 261 | } else { |
| 205 | printf(_("Invalid REAL response received from host on port %d\n"), | 262 | xasprintf(&sc_describe.output, |
| 206 | config.server_port); | 263 | "invalid REAL response received from host on port %d", |
| 264 | config.server_port); | ||
| 207 | } | 265 | } |
| 208 | } else { | ||
| 209 | 266 | ||
| 267 | sc_describe = mp_set_subcheck_state(sc_describe, STATE_UNKNOWN); | ||
| 268 | mp_add_subcheck_to_check(&overall, sc_describe); | ||
| 269 | mp_exit(overall); | ||
| 270 | } else { | ||
| 210 | /* else we got the REAL string, so check the return code */ | 271 | /* else we got the REAL string, so check the return code */ |
| 211 | 272 | ||
| 212 | time(&end_time); | 273 | time(&end_time); |
| 213 | 274 | ||
| 214 | result = STATE_OK; | 275 | char *status_line = strtok(buffer, "\n"); |
| 215 | 276 | xasprintf(&sc_describe.output, "status line: %s", status_line); | |
| 216 | status_line = strtok(buffer, "\n"); | ||
| 217 | 277 | ||
| 278 | mp_state_enum describe_result; | ||
| 218 | if (strstr(status_line, "200")) { | 279 | if (strstr(status_line, "200")) { |
| 219 | result = STATE_OK; | 280 | describe_result = STATE_OK; |
| 220 | } | 281 | } |
| 221 | 282 | /* client errors describe_result in a warning state */ | |
| 222 | /* client errors result in a warning state */ | ||
| 223 | else if (strstr(status_line, "400")) { | 283 | else if (strstr(status_line, "400")) { |
| 224 | result = STATE_WARNING; | 284 | describe_result = STATE_WARNING; |
| 225 | } else if (strstr(status_line, "401")) { | 285 | } else if (strstr(status_line, "401")) { |
| 226 | result = STATE_WARNING; | 286 | describe_result = STATE_WARNING; |
| 227 | } else if (strstr(status_line, "402")) { | 287 | } else if (strstr(status_line, "402")) { |
| 228 | result = STATE_WARNING; | 288 | describe_result = STATE_WARNING; |
| 229 | } else if (strstr(status_line, "403")) { | 289 | } else if (strstr(status_line, "403")) { |
| 230 | result = STATE_WARNING; | 290 | describe_result = STATE_WARNING; |
| 231 | } else if (strstr(status_line, "404")) { | 291 | } else if (strstr(status_line, "404")) { |
| 232 | result = STATE_WARNING; | 292 | describe_result = STATE_WARNING; |
| 233 | } | 293 | } |
| 234 | 294 | /* server errors describe_result in a critical state */ | |
| 235 | /* server errors result in a critical state */ | ||
| 236 | else if (strstr(status_line, "500")) { | 295 | else if (strstr(status_line, "500")) { |
| 237 | result = STATE_CRITICAL; | 296 | describe_result = STATE_CRITICAL; |
| 238 | } else if (strstr(status_line, "501")) { | 297 | } else if (strstr(status_line, "501")) { |
| 239 | result = STATE_CRITICAL; | 298 | describe_result = STATE_CRITICAL; |
| 240 | } else if (strstr(status_line, "502")) { | 299 | } else if (strstr(status_line, "502")) { |
| 241 | result = STATE_CRITICAL; | 300 | describe_result = STATE_CRITICAL; |
| 242 | } else if (strstr(status_line, "503")) { | 301 | } else if (strstr(status_line, "503")) { |
| 243 | result = STATE_CRITICAL; | 302 | describe_result = STATE_CRITICAL; |
| 303 | } else { | ||
| 304 | describe_result = STATE_UNKNOWN; | ||
| 244 | } | 305 | } |
| 245 | 306 | ||
| 246 | else { | 307 | sc_describe = mp_set_subcheck_state(sc_describe, describe_result); |
| 247 | result = STATE_UNKNOWN; | 308 | mp_add_subcheck_to_check(&overall, sc_describe); |
| 248 | } | ||
| 249 | } | 309 | } |
| 250 | } | 310 | } |
| 251 | } | 311 | } |
| 252 | 312 | ||
| 253 | /* Return results */ | 313 | /* Return results */ |
| 254 | if (result == STATE_OK) { | 314 | mp_subcheck sc_timing = mp_subcheck_init(); |
| 255 | if (config.check_critical_time && (end_time - start_time) > config.critical_time) { | 315 | xasprintf(&sc_timing.output, "response time: %lds", end_time - start_time); |
| 256 | result = STATE_CRITICAL; | 316 | sc_timing = mp_set_subcheck_default_state(sc_timing, STATE_OK); |
| 257 | } else if (config.check_warning_time && (end_time - start_time) > config.warning_time) { | ||
| 258 | result = STATE_WARNING; | ||
| 259 | } | ||
| 260 | 317 | ||
| 261 | /* Put some HTML in here to create a dynamic link */ | 318 | mp_perfdata pd_response_time = perfdata_init(); |
| 262 | printf(_("REAL %s - %d second response time\n"), state_text(result), | 319 | pd_response_time = mp_set_pd_value(pd_response_time, (end_time - start_time)); |
| 263 | (int)(end_time - start_time)); | 320 | pd_response_time.label = "response_time"; |
| 264 | } else { | 321 | pd_response_time.uom = "s"; |
| 265 | printf("%s\n", status_line); | 322 | pd_response_time = mp_pd_set_thresholds(pd_response_time, config.time_thresholds); |
| 266 | } | 323 | mp_add_perfdata_to_subcheck(&sc_connect, pd_response_time); |
| 324 | sc_timing = mp_set_subcheck_state(sc_timing, mp_get_pd_status(pd_response_time)); | ||
| 325 | |||
| 326 | mp_add_subcheck_to_check(&overall, sc_timing); | ||
| 267 | 327 | ||
| 268 | /* close the connection */ | 328 | /* close the connection */ |
| 269 | close(socket); | 329 | close(socket); |
| @@ -271,18 +331,28 @@ int main(int argc, char **argv) { | |||
| 271 | /* reset the alarm */ | 331 | /* reset the alarm */ |
| 272 | alarm(0); | 332 | alarm(0); |
| 273 | 333 | ||
| 274 | exit(result); | 334 | mp_exit(overall); |
| 275 | } | 335 | } |
| 276 | 336 | ||
| 277 | /* process command-line arguments */ | 337 | /* process command-line arguments */ |
| 278 | check_real_config_wrapper process_arguments(int argc, char **argv) { | 338 | check_real_config_wrapper process_arguments(int argc, char **argv) { |
| 279 | static struct option longopts[] = { | 339 | enum { |
| 280 | {"hostname", required_argument, 0, 'H'}, {"IPaddress", required_argument, 0, 'I'}, | 340 | output_format_index = CHAR_MAX + 1, |
| 281 | {"expect", required_argument, 0, 'e'}, {"url", required_argument, 0, 'u'}, | 341 | }; |
| 282 | {"port", required_argument, 0, 'p'}, {"critical", required_argument, 0, 'c'}, | 342 | |
| 283 | {"warning", required_argument, 0, 'w'}, {"timeout", required_argument, 0, 't'}, | 343 | static struct option longopts[] = {{"hostname", required_argument, 0, 'H'}, |
| 284 | {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, | 344 | {"IPaddress", required_argument, 0, 'I'}, |
| 285 | {"help", no_argument, 0, 'h'}, {0, 0, 0, 0}}; | 345 | {"expect", required_argument, 0, 'e'}, |
| 346 | {"url", required_argument, 0, 'u'}, | ||
| 347 | {"port", required_argument, 0, 'p'}, | ||
| 348 | {"critical", required_argument, 0, 'c'}, | ||
| 349 | {"warning", required_argument, 0, 'w'}, | ||
| 350 | {"timeout", required_argument, 0, 't'}, | ||
| 351 | {"verbose", no_argument, 0, 'v'}, | ||
| 352 | {"version", no_argument, 0, 'V'}, | ||
| 353 | {"help", no_argument, 0, 'h'}, | ||
| 354 | {"output-format", required_argument, 0, output_format_index}, | ||
| 355 | {0, 0, 0, 0}}; | ||
| 286 | 356 | ||
| 287 | check_real_config_wrapper result = { | 357 | check_real_config_wrapper result = { |
| 288 | .errorcode = OK, | 358 | .errorcode = OK, |
| @@ -337,21 +407,23 @@ check_real_config_wrapper process_arguments(int argc, char **argv) { | |||
| 337 | } | 407 | } |
| 338 | break; | 408 | break; |
| 339 | case 'w': /* warning time threshold */ | 409 | case 'w': /* warning time threshold */ |
| 340 | if (is_intnonneg(optarg)) { | 410 | { |
| 341 | result.config.warning_time = atoi(optarg); | 411 | mp_range_parsed critical_range = mp_parse_range_string(optarg); |
| 342 | result.config.check_warning_time = true; | 412 | if (critical_range.error != MP_PARSING_SUCCES) { |
| 343 | } else { | 413 | die(STATE_UNKNOWN, "failed to parse warning threshold: %s", optarg); |
| 344 | usage4(_("Warning time must be a positive integer")); | ||
| 345 | } | 414 | } |
| 346 | break; | 415 | result.config.time_thresholds = |
| 416 | mp_thresholds_set_warn(result.config.time_thresholds, critical_range.range); | ||
| 417 | } break; | ||
| 347 | case 'c': /* critical time threshold */ | 418 | case 'c': /* critical time threshold */ |
| 348 | if (is_intnonneg(optarg)) { | 419 | { |
| 349 | result.config.critical_time = atoi(optarg); | 420 | mp_range_parsed critical_range = mp_parse_range_string(optarg); |
| 350 | result.config.check_critical_time = true; | 421 | if (critical_range.error != MP_PARSING_SUCCES) { |
| 351 | } else { | 422 | die(STATE_UNKNOWN, "failed to parse critical threshold: %s", optarg); |
| 352 | usage4(_("Critical time must be a positive integer")); | ||
| 353 | } | 423 | } |
| 354 | break; | 424 | result.config.time_thresholds = |
| 425 | mp_thresholds_set_crit(result.config.time_thresholds, critical_range.range); | ||
| 426 | } break; | ||
| 355 | case 'v': /* verbose */ | 427 | case 'v': /* verbose */ |
| 356 | verbose = true; | 428 | verbose = true; |
| 357 | break; | 429 | break; |
| @@ -368,6 +440,18 @@ check_real_config_wrapper process_arguments(int argc, char **argv) { | |||
| 368 | case 'h': /* help */ | 440 | case 'h': /* help */ |
| 369 | print_help(); | 441 | print_help(); |
| 370 | exit(STATE_UNKNOWN); | 442 | exit(STATE_UNKNOWN); |
| 443 | case output_format_index: { | ||
| 444 | parsed_output_format parser = mp_parse_output_format(optarg); | ||
| 445 | if (!parser.parsing_success) { | ||
| 446 | // TODO List all available formats here, maybe add anothoer usage function | ||
| 447 | printf("Invalid output format: %s\n", optarg); | ||
| 448 | exit(STATE_UNKNOWN); | ||
| 449 | } | ||
| 450 | |||
| 451 | result.config.output_format_is_set = true; | ||
| 452 | result.config.output_format = parser.output_format; | ||
| 453 | break; | ||
| 454 | } | ||
| 371 | case '?': /* usage */ | 455 | case '?': /* usage */ |
| 372 | usage5(); | 456 | usage5(); |
| 373 | } | 457 | } |
| @@ -390,10 +474,6 @@ check_real_config_wrapper process_arguments(int argc, char **argv) { | |||
| 390 | result.config.host_name = strdup(result.config.server_address); | 474 | result.config.host_name = strdup(result.config.server_address); |
| 391 | } | 475 | } |
| 392 | 476 | ||
| 393 | if (result.config.server_expect == NULL) { | ||
| 394 | result.config.server_expect = strdup(EXPECT); | ||
| 395 | } | ||
| 396 | |||
| 397 | return result; | 477 | return result; |
| 398 | } | 478 | } |
| 399 | 479 | ||
| @@ -420,7 +500,7 @@ void print_help(void) { | |||
| 420 | printf(" %s\n", "-u, --url=STRING"); | 500 | printf(" %s\n", "-u, --url=STRING"); |
| 421 | printf(" %s\n", _("Connect to this url")); | 501 | printf(" %s\n", _("Connect to this url")); |
| 422 | printf(" %s\n", "-e, --expect=STRING"); | 502 | printf(" %s\n", "-e, --expect=STRING"); |
| 423 | printf(_("String to expect in first line of server response (default: %s)\n"), EXPECT); | 503 | printf(_("String to expect in first line of server response (default: %s)\n"), default_expect); |
| 424 | 504 | ||
| 425 | printf(UT_WARN_CRIT); | 505 | printf(UT_WARN_CRIT); |
| 426 | 506 | ||
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 @@ | |||
| 1 | #pragma once | 1 | #pragma once |
| 2 | 2 | ||
| 3 | #include "../../config.h" | 3 | #include "../../config.h" |
| 4 | #include "output.h" | ||
| 5 | #include "thresholds.h" | ||
| 4 | #include <stddef.h> | 6 | #include <stddef.h> |
| 5 | 7 | ||
| 6 | enum { | 8 | enum { |
| 7 | PORT = 554 | 9 | PORT = 554 |
| 8 | }; | 10 | }; |
| 9 | 11 | ||
| 12 | const char *default_expect = "RTSP/1."; | ||
| 13 | |||
| 10 | typedef struct { | 14 | typedef struct { |
| 11 | char *server_address; | 15 | char *server_address; |
| 12 | char *host_name; | 16 | char *host_name; |
| @@ -14,10 +18,11 @@ typedef struct { | |||
| 14 | char *server_url; | 18 | char *server_url; |
| 15 | 19 | ||
| 16 | char *server_expect; | 20 | char *server_expect; |
| 17 | int warning_time; | 21 | |
| 18 | bool check_warning_time; | 22 | mp_thresholds time_thresholds; |
| 19 | int critical_time; | 23 | |
| 20 | bool check_critical_time; | 24 | bool output_format_is_set; |
| 25 | mp_output_format output_format; | ||
| 21 | } check_real_config; | 26 | } check_real_config; |
| 22 | 27 | ||
| 23 | check_real_config check_real_config_init() { | 28 | check_real_config check_real_config_init() { |
| @@ -27,11 +32,11 @@ check_real_config check_real_config_init() { | |||
| 27 | .server_port = PORT, | 32 | .server_port = PORT, |
| 28 | .server_url = NULL, | 33 | .server_url = NULL, |
| 29 | 34 | ||
| 30 | .server_expect = NULL, | 35 | .server_expect = default_expect, |
| 31 | .warning_time = 0, | 36 | |
| 32 | .check_warning_time = false, | 37 | .time_thresholds = mp_thresholds_init(), |
| 33 | .critical_time = 0, | 38 | |
| 34 | .check_critical_time = false, | 39 | .output_format_is_set = false, |
| 35 | }; | 40 | }; |
| 36 | return tmp; | 41 | return tmp; |
| 37 | } | 42 | } |
diff --git a/plugins/check_smtp.c b/plugins/check_smtp.c index e806ad29..e8c35f58 100644 --- a/plugins/check_smtp.c +++ b/plugins/check_smtp.c | |||
| @@ -37,7 +37,6 @@ | |||
| 37 | #include "base64.h" | 37 | #include "base64.h" |
| 38 | #include "regex.h" | 38 | #include "regex.h" |
| 39 | 39 | ||
| 40 | #include <bits/getopt_ext.h> | ||
| 41 | #include <ctype.h> | 40 | #include <ctype.h> |
| 42 | #include <string.h> | 41 | #include <string.h> |
| 43 | #include "check_smtp.d/config.h" | 42 | #include "check_smtp.d/config.h" |
diff --git a/plugins/check_snmp.d/check_snmp_helpers.c b/plugins/check_snmp.d/check_snmp_helpers.c index ecbfc5dd..2dfc88b5 100644 --- a/plugins/check_snmp.d/check_snmp_helpers.c +++ b/plugins/check_snmp.d/check_snmp_helpers.c | |||
| @@ -36,7 +36,8 @@ int check_snmp_set_thresholds(const char *threshold_string, check_snmp_test_unit | |||
| 36 | threshold_string++; | 36 | threshold_string++; |
| 37 | } | 37 | } |
| 38 | 38 | ||
| 39 | for (char *ptr = strtok(threshold_string, ", "); ptr != NULL; | 39 | char *thr_string_copy = strdup(threshold_string); |
| 40 | for (char *ptr = strtok(thr_string_copy, ", "); ptr != NULL; | ||
| 40 | ptr = strtok(NULL, ", "), tu_index++) { | 41 | ptr = strtok(NULL, ", "), tu_index++) { |
| 41 | 42 | ||
| 42 | if (tu_index > max_test_units) { | 43 | if (tu_index > max_test_units) { |
| @@ -64,6 +65,7 @@ int check_snmp_set_thresholds(const char *threshold_string, check_snmp_test_unit | |||
| 64 | } | 65 | } |
| 65 | } | 66 | } |
| 66 | 67 | ||
| 68 | free(thr_string_copy); | ||
| 67 | } else { | 69 | } else { |
| 68 | // Single value | 70 | // Single value |
| 69 | // only valid for the first test unit | 71 | // only valid for the first test unit |
| @@ -446,7 +448,8 @@ check_snmp_evaluation evaluate_single_unit(response_value response, | |||
| 446 | long long treated_value = (long long)response.value.uIntVal; | 448 | long long treated_value = (long long)response.value.uIntVal; |
| 447 | 449 | ||
| 448 | if (eval_params.multiplier_set || eval_params.offset_set) { | 450 | if (eval_params.multiplier_set || eval_params.offset_set) { |
| 449 | double processed = 0; | 451 | double processed = (double)response.value.uIntVal; |
| 452 | |||
| 450 | if (eval_params.offset_set) { | 453 | if (eval_params.offset_set) { |
| 451 | processed += eval_params.offset; | 454 | processed += eval_params.offset; |
| 452 | } | 455 | } |
| @@ -480,15 +483,16 @@ check_snmp_evaluation evaluate_single_unit(response_value response, | |||
| 480 | } break; | 483 | } break; |
| 481 | case ASN_INTEGER: { | 484 | case ASN_INTEGER: { |
| 482 | if (eval_params.multiplier_set || eval_params.offset_set) { | 485 | if (eval_params.multiplier_set || eval_params.offset_set) { |
| 483 | double processed = 0; | 486 | double processed = (double)response.value.intVal; |
| 484 | if (eval_params.multiplier_set) { | ||
| 485 | processed = (double)response.value.intVal * eval_params.multiplier; | ||
| 486 | } | ||
| 487 | 487 | ||
| 488 | if (eval_params.offset_set) { | 488 | if (eval_params.offset_set) { |
| 489 | processed += eval_params.offset; | 489 | processed += eval_params.offset; |
| 490 | } | 490 | } |
| 491 | 491 | ||
| 492 | if (eval_params.multiplier_set) { | ||
| 493 | processed *= eval_params.multiplier; | ||
| 494 | } | ||
| 495 | |||
| 492 | result_state.value.doubleVal = processed; | 496 | result_state.value.doubleVal = processed; |
| 493 | 497 | ||
| 494 | if (eval_params.calculate_rate && have_previous_state) { | 498 | if (eval_params.calculate_rate && have_previous_state) { |
| @@ -841,8 +845,8 @@ char *_np_state_calculate_location_prefix(void) { | |||
| 841 | * Sets variables. Generates filename. Returns np_state_key. die with | 845 | * Sets variables. Generates filename. Returns np_state_key. die with |
| 842 | * UNKNOWN if exception | 846 | * UNKNOWN if exception |
| 843 | */ | 847 | */ |
| 844 | state_key np_enable_state(char *keyname, int expected_data_version, char *plugin_name, int argc, | 848 | state_key np_enable_state(char *keyname, int expected_data_version, const char *plugin_name, |
| 845 | char **argv) { | 849 | int argc, char **argv) { |
| 846 | state_key *this_state = (state_key *)calloc(1, sizeof(state_key)); | 850 | state_key *this_state = (state_key *)calloc(1, sizeof(state_key)); |
| 847 | if (this_state == NULL) { | 851 | if (this_state == NULL) { |
| 848 | die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno)); | 852 | die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno)); |
| @@ -867,7 +871,7 @@ state_key np_enable_state(char *keyname, int expected_data_version, char *plugin | |||
| 867 | tmp_char++; | 871 | tmp_char++; |
| 868 | } | 872 | } |
| 869 | this_state->name = temp_keyname; | 873 | this_state->name = temp_keyname; |
| 870 | this_state->plugin_name = plugin_name; | 874 | this_state->plugin_name = (char *)plugin_name; |
| 871 | this_state->data_version = expected_data_version; | 875 | this_state->data_version = expected_data_version; |
| 872 | this_state->state_data = NULL; | 876 | this_state->state_data = NULL; |
| 873 | 877 | ||
diff --git a/plugins/check_snmp.d/check_snmp_helpers.h b/plugins/check_snmp.d/check_snmp_helpers.h index 0f7780b1..95b361ac 100644 --- a/plugins/check_snmp.d/check_snmp_helpers.h +++ b/plugins/check_snmp.d/check_snmp_helpers.h | |||
| @@ -66,6 +66,6 @@ typedef struct state_key_struct { | |||
| 66 | } state_key; | 66 | } state_key; |
| 67 | 67 | ||
| 68 | state_data *np_state_read(state_key stateKey); | 68 | state_data *np_state_read(state_key stateKey); |
| 69 | state_key np_enable_state(char *keyname, int expected_data_version, char *plugin_name, int argc, | 69 | state_key np_enable_state(char *keyname, int expected_data_version, const char *plugin_name, |
| 70 | char **argv); | 70 | int argc, char **argv); |
| 71 | void np_state_write_string(state_key stateKey, time_t timestamp, char *stringToStore); | 71 | void np_state_write_string(state_key stateKey, time_t timestamp, char *stringToStore); |
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) { | |||
| 68 | 68 | ||
| 69 | /* set socket timeout */ | 69 | /* set socket timeout */ |
| 70 | alarm(socket_timeout); | 70 | alarm(socket_timeout); |
| 71 | time_t start_time; | ||
| 71 | time(&start_time); | 72 | time(&start_time); |
| 72 | 73 | ||
| 73 | int socket; | 74 | int socket; |
| @@ -113,6 +114,7 @@ int main(int argc, char **argv) { | |||
| 113 | close(socket); | 114 | close(socket); |
| 114 | 115 | ||
| 115 | /* reset the alarm */ | 116 | /* reset the alarm */ |
| 117 | time_t end_time; | ||
| 116 | time(&end_time); | 118 | time(&end_time); |
| 117 | alarm(0); | 119 | alarm(0); |
| 118 | 120 | ||
diff --git a/plugins/t/check_disk.t b/plugins/t/check_disk.t index 0f62fb2b..72a83ea4 100644 --- a/plugins/t/check_disk.t +++ b/plugins/t/check_disk.t | |||
| @@ -80,14 +80,25 @@ if($free_percent_on_mp1 == $avg_free_percent || $free_percent_on_mp2 == $avg_fre | |||
| 80 | die "One mountpoints has average space free - cannot do rest of test"; | 80 | die "One mountpoints has average space free - cannot do rest of test"; |
| 81 | } | 81 | } |
| 82 | 82 | ||
| 83 | my $free_inodes_on_mp1 = $result->{'mp_test_result'}->{'checks'}->[1]->{'checks'}[2]->{'perfdata'}->[0]->{'value'}->{'value'}; | 83 | my $used_inodes_on_mp1 = $result->{'mp_test_result'}->{'checks'}->[1]->{'checks'}[2]->{'perfdata'}->[0]->{'value'}->{'value'}; |
| 84 | my $total_inodes_on_mp1 = $result->{'mp_test_result'}->{'checks'}->[1]->{'checks'}[2]->{'perfdata'}->[0]->{'max'}->{'value'}; | 84 | my $total_inodes_on_mp1 = $result->{'mp_test_result'}->{'checks'}->[1]->{'checks'}[2]->{'perfdata'}->[0]->{'max'}->{'value'}; |
| 85 | |||
| 86 | my $free_inodes_on_mp1 = $total_inodes_on_mp1 - $used_inodes_on_mp1; | ||
| 85 | my $free_inode_percentage_on_mp1 = $free_inodes_on_mp1 / ($total_inodes_on_mp1 / 100); | 87 | my $free_inode_percentage_on_mp1 = $free_inodes_on_mp1 / ($total_inodes_on_mp1 / 100); |
| 86 | 88 | ||
| 87 | my $free_inodes_on_mp2 = $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}[2]->{'perfdata'}->[0]->{'value'}->{'value'}; | 89 | # print("free inodes on mp1: " . $free_inodes_on_mp1 . "\n"); |
| 90 | # print("total inodes on mp1: " . $total_inodes_on_mp1 . "\n"); | ||
| 91 | # print("free inode percentage on mp1: " . $free_inode_percentage_on_mp1 . "\n"); | ||
| 92 | |||
| 93 | my $used_inodes_on_mp2 = $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}[2]->{'perfdata'}->[0]->{'value'}->{'value'}; | ||
| 88 | my $total_inodes_on_mp2 = $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}[2]->{'perfdata'}->[0]->{'max'}->{'value'}; | 94 | my $total_inodes_on_mp2 = $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}[2]->{'perfdata'}->[0]->{'max'}->{'value'}; |
| 95 | my $free_inodes_on_mp2 = $total_inodes_on_mp2 - $used_inodes_on_mp2; | ||
| 89 | my $free_inode_percentage_on_mp2 = $free_inodes_on_mp2 / ($total_inodes_on_mp2 / 100); | 96 | my $free_inode_percentage_on_mp2 = $free_inodes_on_mp2 / ($total_inodes_on_mp2 / 100); |
| 90 | 97 | ||
| 98 | # print("free inodes on mp2: " . $free_inodes_on_mp2 . "\n"); | ||
| 99 | # print("total inodes on mp2: " . $total_inodes_on_mp2 . "\n"); | ||
| 100 | # print("free inode percentage on mp2: " . $free_inode_percentage_on_mp2 . "\n"); | ||
| 101 | |||
| 91 | my $avg_inode_free_percentage = ceil(($free_inode_percentage_on_mp1 + $free_inode_percentage_on_mp2)/2); | 102 | my $avg_inode_free_percentage = ceil(($free_inode_percentage_on_mp1 + $free_inode_percentage_on_mp2)/2); |
| 92 | my ($more_inode_free, $less_inode_free); | 103 | my ($more_inode_free, $less_inode_free); |
| 93 | if ($free_inode_percentage_on_mp1 > $free_inode_percentage_on_mp2) { | 104 | if ($free_inode_percentage_on_mp1 > $free_inode_percentage_on_mp2) { |
diff --git a/plugins/t/check_ldap.t b/plugins/t/check_ldap.t index fcba0393..f3162ebb 100644 --- a/plugins/t/check_ldap.t +++ b/plugins/t/check_ldap.t | |||
| @@ -32,7 +32,7 @@ SKIP: { | |||
| 32 | 32 | ||
| 33 | $result = NPTest->testCmd("$command -H $hostname_invalid -b ou=blah -t 5"); | 33 | $result = NPTest->testCmd("$command -H $hostname_invalid -b ou=blah -t 5"); |
| 34 | is( $result->return_code, 2, "$command -H $hostname_invalid -b ou=blah -t 5" ); | 34 | is( $result->return_code, 2, "$command -H $hostname_invalid -b ou=blah -t 5" ); |
| 35 | is( $result->output, 'Could not bind to the LDAP server', "output ok" ); | 35 | like( $result->output, '/could not bind to the LDAP server/', "output ok" ); |
| 36 | }; | 36 | }; |
| 37 | 37 | ||
| 38 | SKIP: { | 38 | SKIP: { |
| @@ -42,30 +42,30 @@ SKIP: { | |||
| 42 | $cmd = "$command -H $host_tcp_ldap -b $ldap_base_dn -t 5 -w 2 -c 3 -3"; | 42 | $cmd = "$command -H $host_tcp_ldap -b $ldap_base_dn -t 5 -w 2 -c 3 -3"; |
| 43 | $result = NPTest->testCmd($cmd); | 43 | $result = NPTest->testCmd($cmd); |
| 44 | is( $result->return_code, 0, $cmd ); | 44 | is( $result->return_code, 0, $cmd ); |
| 45 | like( $result->output, '/^LDAP OK - \d+.\d+ seconds response time\|time=\d+\.\d+s;2\.0+;3\.0+;0\.0+$/', "output ok" ); | 45 | like( $result->output, '/connection time \d+.\d+s/', "output ok" ); |
| 46 | 46 | ||
| 47 | $cmd = "$command -H $host_tcp_ldap -b $ldap_base_dn -t 5 -w 2 -c 3 -3 -W 10000000 -C 10000001"; | 47 | $cmd = "$command -H $host_tcp_ldap -b $ldap_base_dn -t 5 -w 2 -c 3 -3 -W 10000000 -C 10000001"; |
| 48 | $result = NPTest->testCmd($cmd); | 48 | $result = NPTest->testCmd($cmd); |
| 49 | is( $result->return_code, 0, $cmd ); | 49 | is( $result->return_code, 0, $cmd ); |
| 50 | like( $result->output, '/^LDAP OK - found \d+ entries in \d+\.\d+ seconds\|time=\d\.\d+s;2\.0+;3\.0+;0\.0+ entries=\d+\.0+;10000000;10000001;0\.0+$/', "output ok" ); | 50 | like( $result->output, '/found \d+ entries/', "output ok" ); |
| 51 | 51 | ||
| 52 | $cmd = "$command -H $host_tcp_ldap -b $ldap_base_dn -t 5 -w 2 -c 3 -3 -W 10000000: -C 10000001:"; | 52 | $cmd = "$command -H $host_tcp_ldap -b $ldap_base_dn -t 5 -w 2 -c 3 -3 -W 10000000: -C 10000001:"; |
| 53 | $result = NPTest->testCmd($cmd); | 53 | $result = NPTest->testCmd($cmd); |
| 54 | is( $result->return_code, 2, $cmd ); | 54 | is( $result->return_code, 2, $cmd ); |
| 55 | like( $result->output, '/^LDAP CRITICAL - found \d+ entries in \d+\.\d+ seconds\|time=\d\.\d+s;2\.0+;3\.0+;0\.0+ entries=\d+\.0+;10000000:;10000001:;0\.0+$/', "output ok" ); | 55 | like( $result->output, '/found \d+ entries/', "output ok" ); |
| 56 | 56 | ||
| 57 | $cmd = "$command -H $host_tcp_ldap -b $ldap_base_dn -t 5 -w 2 -c 3 -3 -W 0 -C 0"; | 57 | $cmd = "$command -H $host_tcp_ldap -b $ldap_base_dn -t 5 -w 2 -c 3 -3 -W 0 -C 0"; |
| 58 | $result = NPTest->testCmd($cmd); | 58 | $result = NPTest->testCmd($cmd); |
| 59 | is( $result->return_code, 2, $cmd ); | 59 | is( $result->return_code, 2, $cmd ); |
| 60 | like( $result->output, '/^LDAP CRITICAL - found \d+ entries in \d+\.\d+ seconds\|time=\d\.\d+s;2\.0+;3\.0+;0\.0+ entries=\d+\.0+;0;0;0\.0+$/', "output ok" ); | 60 | like( $result->output, '/found \d+ entries/', "output ok" ); |
| 61 | 61 | ||
| 62 | $cmd = "$command -H $host_tcp_ldap -b $ldap_base_dn -t 5 -w 2 -c 3 -3 -W 10000000: -C 10000001"; | 62 | $cmd = "$command -H $host_tcp_ldap -b $ldap_base_dn -t 5 -w 2 -c 3 -3 -W 10000000: -C 10000001"; |
| 63 | $result = NPTest->testCmd($cmd); | 63 | $result = NPTest->testCmd($cmd); |
| 64 | is( $result->return_code, 1, $cmd ); | 64 | is( $result->return_code, 1, $cmd ); |
| 65 | like( $result->output, '/^LDAP WARNING - found \d+ entries in \d+\.\d+ seconds\|time=\d\.\d+s;2\.0+;3\.0+;0\.0+ entries=\d+\.0+;10000000:;10000001;0\.0+$/', "output ok" ); | 65 | like( $result->output, '/found \d+ entries/', "output ok" ); |
| 66 | 66 | ||
| 67 | $cmd = "$command -H $host_tcp_ldap -b $ldap_base_dn -t 5 -w 2 -c 3 -3 -C 10000001"; | 67 | $cmd = "$command -H $host_tcp_ldap -b $ldap_base_dn -t 5 -w 2 -c 3 -3 -C 10000001"; |
| 68 | $result = NPTest->testCmd($cmd); | 68 | $result = NPTest->testCmd($cmd); |
| 69 | is( $result->return_code, 0, $cmd ); | 69 | is( $result->return_code, 0, $cmd ); |
| 70 | like( $result->output, '/^LDAP OK - found \d+ entries in \d+\.\d+ seconds\|time=\d\.\d+s;2\.0+;3\.0+;0\.0+ entries=\d+\.0+;;10000001;0\.0+$/', "output ok" ); | 70 | like( $result->output, '/found \d+ entries/', "output ok" ); |
| 71 | }; | 71 | }; |
diff --git a/plugins/t/check_ntp.t b/plugins/t/check_ntp.t index a8ac7bb8..7703bc3b 100644 --- a/plugins/t/check_ntp.t +++ b/plugins/t/check_ntp.t | |||
| @@ -8,7 +8,7 @@ use strict; | |||
| 8 | use Test::More; | 8 | use Test::More; |
| 9 | use NPTest; | 9 | use NPTest; |
| 10 | 10 | ||
| 11 | my @PLUGINS1 = ('check_ntp', 'check_ntp_peer', 'check_ntp_time'); | 11 | my @PLUGINS1 = ('check_ntp_peer', 'check_ntp_time'); |
| 12 | my @PLUGINS2 = ('check_ntp_peer'); | 12 | my @PLUGINS2 = ('check_ntp_peer'); |
| 13 | 13 | ||
| 14 | plan tests => (12 * scalar(@PLUGINS1)) + (6 * scalar(@PLUGINS2)); | 14 | plan tests => (12 * scalar(@PLUGINS1)) + (6 * scalar(@PLUGINS2)); |
diff --git a/plugins/tests/check_curl.t b/plugins/tests/check_curl.t index 52c5ad1c..248eb4c5 100755 --- a/plugins/tests/check_curl.t +++ b/plugins/tests/check_curl.t | |||
| @@ -20,9 +20,14 @@ use Test::More; | |||
| 20 | use NPTest; | 20 | use NPTest; |
| 21 | use FindBin qw($Bin); | 21 | use FindBin qw($Bin); |
| 22 | 22 | ||
| 23 | use URI; | ||
| 24 | use URI::QueryParam; | ||
| 25 | use HTTP::Daemon; | ||
| 26 | use HTTP::Daemon::SSL; | ||
| 27 | |||
| 23 | $ENV{'LC_TIME'} = "C"; | 28 | $ENV{'LC_TIME'} = "C"; |
| 24 | 29 | ||
| 25 | my $common_tests = 75; | 30 | my $common_tests = 95; |
| 26 | my $ssl_only_tests = 8; | 31 | my $ssl_only_tests = 8; |
| 27 | # Check that all dependent modules are available | 32 | # Check that all dependent modules are available |
| 28 | eval "use HTTP::Daemon 6.01;"; | 33 | eval "use HTTP::Daemon 6.01;"; |
| @@ -186,6 +191,123 @@ sub run_server { | |||
| 186 | $c->send_response('moved to /redirect2'); | 191 | $c->send_response('moved to /redirect2'); |
| 187 | } elsif ($r->url->path eq "/redir_timeout") { | 192 | } elsif ($r->url->path eq "/redir_timeout") { |
| 188 | $c->send_redirect( "/timeout" ); | 193 | $c->send_redirect( "/timeout" ); |
| 194 | } elsif ($r->url->path =~ m{^/redirect_with_increment}) { | ||
| 195 | # <scheme>://<username>:<password>@<host>:<port>/<path>;<parameters>?<query>#<fragment> | ||
| 196 | # Find every parameter, query , and fragment keys and increment them | ||
| 197 | |||
| 198 | my $content = ""; | ||
| 199 | |||
| 200 | # Use URI to help with query/fragment; parse path params manually. | ||
| 201 | my $original_url = $r->url->as_string; | ||
| 202 | $content .= " original_url: ${original_url}\n"; | ||
| 203 | my $uri = URI->new($original_url); | ||
| 204 | $content .= " uri: ${uri}\n"; | ||
| 205 | |||
| 206 | my $path = $uri->path // ''; | ||
| 207 | my $query = $uri->query // ''; | ||
| 208 | my $fragment = $uri->fragment // ''; | ||
| 209 | |||
| 210 | $content .= " path: ${path}\n"; | ||
| 211 | $content .= " query: ${query}\n"; | ||
| 212 | $content .= " fragment: ${fragment}\n"; | ||
| 213 | |||
| 214 | # split the URI part and parameters. URI package cannot do this | ||
| 215 | # group 1 is captured: anything without a semicolon: ([^;]*) | ||
| 216 | # group 2 is uncaptured: (?:;(.*))? | ||
| 217 | # (?: ... )? prevents capturing the parameter section | ||
| 218 | # inside group 2, ';' matches the first ever semicolon | ||
| 219 | # group3 is captured: any character string : (.*) | ||
| 220 | # \? matches an actual ? mark, which starts the query parameters | ||
| 221 | my ($before_params, $params) = $uri =~ m{^([^;]*)(?:;(.*))?\?}; | ||
| 222 | $before_params //= ''; | ||
| 223 | $params //= ''; | ||
| 224 | $content .= " before_params: ${before_params}\n"; | ||
| 225 | $content .= " params: ${params}\n"; | ||
| 226 | my @parameter_pairs; | ||
| 227 | if (defined $params && length $params) { | ||
| 228 | for my $p (split /;/, $params) { | ||
| 229 | my ($key,$value) = split /=/, $p, 2; | ||
| 230 | $value //= ''; | ||
| 231 | push @parameter_pairs, [ $key, $value ]; | ||
| 232 | $content .= " parameter: ${key} -> ${value}\n"; | ||
| 233 | } | ||
| 234 | } | ||
| 235 | |||
| 236 | # query parameters are offered directly from the library | ||
| 237 | my @query_form = $uri->query_form; | ||
| 238 | my @query_parameter_pairs; | ||
| 239 | while (@query_form) { | ||
| 240 | my $key = shift @query_form; | ||
| 241 | my $value = shift @query_form; | ||
| 242 | $value //= ''; # there can be valueless keys | ||
| 243 | push @query_parameter_pairs, [ $key, $value ]; | ||
| 244 | $content .= " query: ${key} -> ${value}\n"; | ||
| 245 | } | ||
| 246 | |||
| 247 | # helper to increment value | ||
| 248 | my $increment = sub { | ||
| 249 | my ($v) = @_; | ||
| 250 | return $v if !defined $v || $v eq ''; | ||
| 251 | # numeric integer | ||
| 252 | if ($v =~ /^-?\d+$/) { | ||
| 253 | return $v + 1; | ||
| 254 | } | ||
| 255 | # otherwise -> increment as if its an ascii character | ||
| 256 | # sed replacement syntax, but the $& holds the matched character | ||
| 257 | if (length($v)) { | ||
| 258 | (my $new_v = $v) =~ s/./chr(ord($&) + 1)/ge; | ||
| 259 | return $new_v; | ||
| 260 | } | ||
| 261 | }; | ||
| 262 | |||
| 263 | # increment values in pairs | ||
| 264 | for my $pair (@parameter_pairs) { | ||
| 265 | $pair->[1] = $increment->($pair->[1]); | ||
| 266 | $content .= " parameter new: " . $pair->[0] . " -> " . $pair->[1] . "\n"; | ||
| 267 | } | ||
| 268 | for my $pair (@query_parameter_pairs) { | ||
| 269 | $pair->[1] = $increment->($pair->[1]); | ||
| 270 | $content .= " query parameter new: " . $pair->[0] . " -> " . $pair->[1] . "\n"; | ||
| 271 | } | ||
| 272 | |||
| 273 | # rebuild strings | ||
| 274 | my $new_parameter_str = join(';', map { $_->[0] . '=' . $_->[1] } @parameter_pairs); | ||
| 275 | $content .= " new_parameter_str: ${new_parameter_str}\n"; | ||
| 276 | |||
| 277 | # library can rebuild from an array | ||
| 278 | my @new_query_form; | ||
| 279 | for my $p (@query_parameter_pairs) { push @new_query_form, $p->[0], $p->[1] } | ||
| 280 | |||
| 281 | my $new_fragment_str = ''; | ||
| 282 | for my $pair (@parameter_pairs) { | ||
| 283 | my $key = $pair->[0]; | ||
| 284 | my $value = $pair->[1]; | ||
| 285 | if ($key eq "fragment") { | ||
| 286 | $new_fragment_str = $value | ||
| 287 | } | ||
| 288 | } | ||
| 289 | $content .= " new_fragment_str: ${new_fragment_str}\n"; | ||
| 290 | |||
| 291 | # construct new URI using the library | ||
| 292 | my $new_uri = URI->new(''); | ||
| 293 | $new_uri->path( $before_params . ($new_parameter_str ? ';' . $new_parameter_str : '') ); | ||
| 294 | $new_uri->query_form( \@new_query_form ) if @new_query_form; | ||
| 295 | $new_uri->fragment( $new_fragment_str ) if $new_fragment_str ne ''; | ||
| 296 | $content .= " new_uri: ${new_uri}\n"; | ||
| 297 | |||
| 298 | # Redirect until fail_count or redirect_count reaches 3 | ||
| 299 | if ($new_uri =~ /fail_count=3/){ | ||
| 300 | $c->send_error(HTTP::Status->RC_FORBIDDEN, "fail count reached 3, url path:" . $r->url->path ); | ||
| 301 | } elsif ($new_uri =~ /redirect_count=3/){ | ||
| 302 | $c->send_response(HTTP::Response->new( 200, 'OK', undef , $content )); | ||
| 303 | } elsif ($new_uri =~ /location_redirect_count=3/){ | ||
| 304 | $c->send_basic_header(302); | ||
| 305 | $c->send_header("Location", "$new_uri" ); | ||
| 306 | $c->send_crlf; | ||
| 307 | $c->send_response("$content \n moved to $new_uri"); | ||
| 308 | } else { | ||
| 309 | $c->send_redirect( $new_uri->as_string, 301, $content ); | ||
| 310 | } | ||
| 189 | } elsif ($r->url->path eq "/timeout") { | 311 | } elsif ($r->url->path eq "/timeout") { |
| 190 | # Keep $c from being destroyed, but prevent severe leaks | 312 | # Keep $c from being destroyed, but prevent severe leaks |
| 191 | unshift @persist, $c; | 313 | unshift @persist, $c; |
| @@ -215,7 +337,7 @@ sub run_server { | |||
| 215 | return($chunk); | 337 | return($chunk); |
| 216 | })); | 338 | })); |
| 217 | } else { | 339 | } else { |
| 218 | $c->send_error(HTTP::Status->RC_FORBIDDEN); | 340 | $c->send_error(HTTP::Status->RC_FORBIDDEN, "unknown url path:" . $r->url->path ); |
| 219 | } | 341 | } |
| 220 | $c->close; | 342 | $c->close; |
| 221 | } | 343 | } |
| @@ -482,6 +604,64 @@ sub run_common_tests { | |||
| 482 | is( $result->return_code, 0, $cmd); | 604 | is( $result->return_code, 0, $cmd); |
| 483 | like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output ); | 605 | like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct: ".$result->output ); |
| 484 | 606 | ||
| 607 | # Redirect with increment tests. These are for checking if the url parameters, query parameters and fragment are parsed. | ||
| 608 | # The server at this point has dynamic redirection. It tries to increment values that it sees in these fields, then redirects. | ||
| 609 | # It also appends some debug log and writes it into HTTP content, pass the -vvv parameter to see them. | ||
| 610 | |||
| 611 | $cmd = "$command -u '/redirect_with_increment/path1/path2/path3/path4' --onredirect=follow -vvv"; | ||
| 612 | $result = NPTest->testCmd( "$cmd" ); | ||
| 613 | is( $result->return_code, 1, $cmd); | ||
| 614 | like( $result->output, '/.*HTTP/1.1 403 Forbidden - \d+ bytes in [\d\.]+ second.*/', "Output correct, redirect_count was not present, got redirected to / : ".$result->output ); | ||
| 615 | |||
| 616 | # redirect_count=0 is parsed as a parameter and incremented. When it goes up to 3, the redirection returns HTTP OK | ||
| 617 | $cmd = "$command -u '/redirect_with_increment/path1/path2;redirect_count=0;p1=1;p2=ab?qp1=10&qp2=kl#f1=test' --onredirect=follow -vvv"; | ||
| 618 | $result = NPTest->testCmd( "$cmd" ); | ||
| 619 | is( $result->return_code, 0, $cmd); | ||
| 620 | like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct, redirect_count went up to 3, and returned OK: ".$result->output ); | ||
| 621 | |||
| 622 | # location_redirect_count=0 goes up to 3, which uses the HTTP 302 style of redirection with 'Location' header | ||
| 623 | $cmd = "$command -u '/redirect_with_increment/path1/path2;location_redirect_count=0;p1=1;p2=ab?qp1=10&qp2=kl#f1=test' --onredirect=follow -vvv"; | ||
| 624 | $result = NPTest->testCmd( "$cmd" ); | ||
| 625 | is( $result->return_code, 0, $cmd); | ||
| 626 | like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct, location_redirect_count went up to 3: ".$result->output ); | ||
| 627 | |||
| 628 | # fail_count parameter may also go up to 3, which returns a HTTP 403 | ||
| 629 | $cmd = "$command -u '/redirect_with_increment/path1/path2;redirect_count=0;fail_count=2' --onredirect=follow -vvv"; | ||
| 630 | $result = NPTest->testCmd( "$cmd" ); | ||
| 631 | is( $result->return_code, 1, $cmd); | ||
| 632 | like( $result->output, '/.*HTTP/1.1 403 Forbidden - \d+ bytes in [\d\.]+ second.*/', "Output correct, early due to fail_count reaching 3: ".$result->output ); | ||
| 633 | |||
| 634 | # redirect_count=0, p1=1 , p2=ab => redirect_count=1, p1=2 , p2=bc => redirect_count=2, p1=3 , p2=cd => redirect_count=3 , p1=4 , p2=de | ||
| 635 | # Last visited URI returns HTTP OK instead of redirect, and the one before that contains the new_uri in its content | ||
| 636 | $cmd = "$command -u '/redirect_with_increment/path1/path2;redirect_count=0;p1=1;p2=ab?qp1=10&qp2=kl#f1=test' --onredirect=follow -vvv"; | ||
| 637 | $result = NPTest->testCmd( "$cmd" ); | ||
| 638 | is( $result->return_code, 0, $cmd); | ||
| 639 | like( $result->output, '/.*redirect_count=3;p1=4;p2=de\?*/', "Output correct, parsed and incremented both parameters p1 and p2 : ".$result->output ); | ||
| 640 | like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct, location_redirect_count went up to 3: ".$result->output ); | ||
| 641 | |||
| 642 | # Same incrementation as before, uses the query parameters that come after the first '?' : qp1 and qp2 | ||
| 643 | $cmd = "$command -u '/redirect_with_increment/path1/path2;redirect_count=0;p1=1;p2=ab?qp1=10&qp2=kl#f1=test' --onredirect=follow -vvv"; | ||
| 644 | $result = NPTest->testCmd( "$cmd" ); | ||
| 645 | is( $result->return_code, 0, $cmd); | ||
| 646 | like( $result->output, '/.*\?qp1=13&qp2=no*/', "Output correct, parsed and incremented both query parameters qp1 and qp2 : ".$result->output ); | ||
| 647 | like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct, location_redirect_count went up to 3: ".$result->output ); | ||
| 648 | |||
| 649 | # Check if the query parameter order is kept intact | ||
| 650 | $cmd = "$command -u '/redirect_with_increment;redirect_count=0;?qp0=0&qp1=1&qp2=2&qp3=3&qp4=4&qp5=5' --onredirect=follow -vvv"; | ||
| 651 | $result = NPTest->testCmd( "$cmd" ); | ||
| 652 | is( $result->return_code, 0, $cmd); | ||
| 653 | like( $result->output, '/.*\?qp0=3&qp1=4&qp2=5&qp3=6&qp4=7&qp5=8*/', "Output correct, parsed and incremented query parameters qp1,qp2,qp3,qp4,qp5 in order : ".$result->output ); | ||
| 654 | like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct, location_redirect_count went up to 3: ".$result->output ); | ||
| 655 | |||
| 656 | # The fragment is passed as another parameter. | ||
| 657 | # During the server redirects the fragment will be set to its value, if such a key is present. | ||
| 658 | # 'ebiil' => 'fcjjm' => 'gdkkn' => 'hello' | ||
| 659 | $cmd = "$command -u '/redirect_with_increment/path1/path2;redirect_count=0;fragment=ebiil?qp1=0' --onredirect=follow -vvv"; | ||
| 660 | $result = NPTest->testCmd( "$cmd" ); | ||
| 661 | is( $result->return_code, 0, $cmd); | ||
| 662 | like( $result->output, '/.*redirect_count=3;fragment=hello\?qp1=3#hello*/', "Output correct, fragments are specified by server and followed by check_curl: ".$result->output ); | ||
| 663 | like( $result->output, '/.*HTTP/1.1 200 OK - \d+ bytes in [\d\.]+ second.*/', "Output correct, location_redirect_count went up to 3: ".$result->output ); | ||
| 664 | |||
| 485 | # These tests may block | 665 | # These tests may block |
| 486 | # stickyport - on full urlS port is set back to 80 otherwise | 666 | # stickyport - on full urlS port is set back to 80 otherwise |
| 487 | $cmd = "$command -f stickyport -u /redir_external -t 5 -s redirected"; | 667 | $cmd = "$command -f stickyport -u /redir_external -t 5 -s redirected"; |
diff --git a/plugins/tests/check_nt.t b/plugins/tests/check_nt.t deleted file mode 100755 index 223d4933..00000000 --- a/plugins/tests/check_nt.t +++ /dev/null | |||
| @@ -1,80 +0,0 @@ | |||
| 1 | #! /usr/bin/perl -w -I .. | ||
| 2 | # | ||
| 3 | # Test check_nt by having a stub check_nt daemon | ||
| 4 | # | ||
| 5 | |||
| 6 | use strict; | ||
| 7 | use Test::More; | ||
| 8 | use NPTest; | ||
| 9 | use FindBin qw($Bin); | ||
| 10 | |||
| 11 | use IO::Socket; | ||
| 12 | use IO::Select; | ||
| 13 | use POSIX; | ||
| 14 | |||
| 15 | my $port = 50000 + int(rand(1000)); | ||
| 16 | |||
| 17 | my $pid = fork(); | ||
| 18 | if ($pid) { | ||
| 19 | # Parent | ||
| 20 | #print "parent\n"; | ||
| 21 | # give our webserver some time to startup | ||
| 22 | sleep(1); | ||
| 23 | } else { | ||
| 24 | # Child | ||
| 25 | #print "child\n"; | ||
| 26 | |||
| 27 | my $server = IO::Socket::INET->new( | ||
| 28 | LocalPort => $port, | ||
| 29 | Type => SOCK_STREAM, | ||
| 30 | Reuse => 1, | ||
| 31 | Proto => "tcp", | ||
| 32 | Listen => 10, | ||
| 33 | ) or die "Cannot be a tcp server on port $port: $@"; | ||
| 34 | |||
| 35 | $server->autoflush(1); | ||
| 36 | |||
| 37 | print "Please contact me at port $port\n"; | ||
| 38 | while (my $client = $server->accept ) { | ||
| 39 | my $data = ""; | ||
| 40 | my $rv = $client->recv($data, POSIX::BUFSIZ, 0); | ||
| 41 | |||
| 42 | my ($password, $command, $arg) = split('&', $data); | ||
| 43 | |||
| 44 | if ($command eq "4") { | ||
| 45 | if ($arg eq "c") { | ||
| 46 | print $client "930000000&1000000000"; | ||
| 47 | } elsif ($arg eq "d") { | ||
| 48 | print $client "UNKNOWN: Drive is not a fixed drive"; | ||
| 49 | } | ||
| 50 | } | ||
| 51 | } | ||
| 52 | exit; | ||
| 53 | } | ||
| 54 | |||
| 55 | END { if ($pid) { print "Killing $pid\n"; kill "INT", $pid } }; | ||
| 56 | |||
| 57 | if ($ARGV[0] && $ARGV[0] eq "-d") { | ||
| 58 | sleep 1000; | ||
| 59 | } | ||
| 60 | |||
| 61 | if (-x "./check_nt") { | ||
| 62 | plan tests => 5; | ||
| 63 | } else { | ||
| 64 | plan skip_all => "No check_nt compiled"; | ||
| 65 | } | ||
| 66 | |||
| 67 | my $result; | ||
| 68 | my $command = "./check_nt -H 127.0.0.1 -p $port"; | ||
| 69 | |||
| 70 | $result = NPTest->testCmd( "$command -v USEDDISKSPACE -l c" ); | ||
| 71 | is( $result->return_code, 0, "USEDDISKSPACE c"); | ||
| 72 | is( $result->output, q{c:\ - total: 0.93 Gb - used: 0.07 Gb (7%) - free 0.87 Gb (93%) | 'c:\ Used Space'=0.07Gb;0.00;0.00;0.00;0.93}, "Output right" ); | ||
| 73 | |||
| 74 | $result = NPTest->testCmd( "$command -v USEDDISKSPACE -l d" ); | ||
| 75 | is( $result->return_code, 3, "USEDDISKSPACE d - invalid"); | ||
| 76 | is( $result->output, "Free disk space : Invalid drive", "Output right" ); | ||
| 77 | |||
| 78 | $result = NPTest->testCmd( "./check_nt -v USEDDISKSPACE -l d" ); | ||
| 79 | is( $result->return_code, 3, "Fail if -H missing"); | ||
| 80 | |||
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; | |||
| 40 | #define STRLEN 64 | 40 | #define STRLEN 64 |
| 41 | #define TXTBLK 128 | 41 | #define TXTBLK 128 |
| 42 | 42 | ||
| 43 | time_t start_time, end_time; | ||
| 44 | 43 | ||
| 45 | void usage(const char *msg) { | 44 | void usage(const char *msg) { |
| 46 | printf("%s\n", msg); | 45 | 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. */ | |||
| 32 | void support(void); | 32 | void support(void); |
| 33 | void print_revision(const char *, const char *); | 33 | void print_revision(const char *, const char *); |
| 34 | 34 | ||
| 35 | extern time_t start_time, end_time; | ||
| 36 | |||
| 37 | /* Test input types */ | 35 | /* Test input types */ |
| 38 | 36 | ||
| 39 | bool is_integer(char *); | 37 | bool is_integer(char *); |
