summaryrefslogtreecommitdiffstats
path: root/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'plugins')
-rw-r--r--plugins/Makefile.am10
-rw-r--r--plugins/check_by_ssh.c34
-rw-r--r--plugins/check_curl.c81
-rw-r--r--plugins/check_curl.d/check_curl_helpers.c46
-rw-r--r--plugins/check_curl.d/check_curl_helpers.h6
-rw-r--r--plugins/check_curl.d/config.h6
-rw-r--r--plugins/check_dbi.c2
-rw-r--r--plugins/check_dig.c268
-rw-r--r--plugins/check_dig.d/config.h10
-rw-r--r--plugins/check_disk.c6
-rw-r--r--plugins/check_http.c2
-rw-r--r--plugins/check_ide_smart.c259
-rw-r--r--plugins/check_ide_smart.d/config.h15
-rw-r--r--plugins/check_ldap.c333
-rw-r--r--plugins/check_ldap.d/config.h24
-rw-r--r--plugins/check_mrtg.c138
-rw-r--r--plugins/check_mrtg.d/config.h17
-rw-r--r--plugins/check_mrtgtraf.c219
-rw-r--r--plugins/check_mrtgtraf.d/config.h19
-rw-r--r--plugins/check_mysql.c67
-rw-r--r--plugins/check_mysql.d/config.h5
-rw-r--r--plugins/check_mysql_query.c22
-rw-r--r--plugins/check_mysql_query.d/config.h6
-rw-r--r--plugins/check_nt.c789
-rw-r--r--plugins/check_nt.d/config.h53
-rw-r--r--plugins/check_ntp.c947
-rw-r--r--plugins/check_ntp_peer.c2
-rw-r--r--plugins/check_ntp_time.c80
-rw-r--r--plugins/check_radius.c130
-rw-r--r--plugins/check_radius.d/config.h6
-rw-r--r--plugins/check_real.c318
-rw-r--r--plugins/check_real.d/config.h23
-rw-r--r--plugins/check_smtp.c1
-rw-r--r--plugins/check_snmp.d/check_snmp_helpers.c22
-rw-r--r--plugins/check_snmp.d/check_snmp_helpers.h4
-rw-r--r--plugins/check_time.c2
-rw-r--r--plugins/t/check_disk.t15
-rw-r--r--plugins/t/check_ldap.t14
-rw-r--r--plugins/t/check_ntp.t2
-rwxr-xr-xplugins/tests/check_curl.t184
-rwxr-xr-xplugins/tests/check_nt.t80
-rw-r--r--plugins/utils.c1
-rw-r--r--plugins/utils.h2
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
35libexec_PROGRAMS = check_apt check_cluster check_disk check_dummy check_http check_load \ 35libexec_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
45EXTRA_PROGRAMS = check_mysql check_radius check_pgsql check_hpjd \ 45EXTRA_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)
157check_mysql_query_CPPFLAGS = $(AM_CPPFLAGS) $(MYSQLINCLUDE) 157check_mysql_query_CPPFLAGS = $(AM_CPPFLAGS) $(MYSQLINCLUDE)
158check_mysql_query_LDADD = $(NETLIBS) $(MYSQLLIBS) 158check_mysql_query_LDADD = $(NETLIBS) $(MYSQLLIBS)
159check_nagios_LDADD = $(BASEOBJS) 159check_nagios_LDADD = $(BASEOBJS)
160check_nt_LDADD = $(NETLIBS)
161check_ntp_LDADD = $(NETLIBS) $(MATHLIBS)
162check_ntp_peer_LDADD = $(NETLIBS) $(MATHLIBS) 160check_ntp_peer_LDADD = $(NETLIBS) $(MATHLIBS)
163check_pgsql_LDADD = $(NETLIBS) $(PGLIBS) 161check_pgsql_LDADD = $(NETLIBS) $(PGLIBS)
164check_ping_LDADD = $(NETLIBS) 162check_ping_LDADD = $(NETLIBS)
@@ -167,7 +165,7 @@ check_radius_LDADD = $(NETLIBS) $(RADIUSLIBS)
167check_real_LDADD = $(NETLIBS) 165check_real_LDADD = $(NETLIBS)
168check_snmp_SOURCES = check_snmp.c check_snmp.d/check_snmp_helpers.c 166check_snmp_SOURCES = check_snmp.c check_snmp.d/check_snmp_helpers.c
169check_snmp_LDADD = $(BASEOBJS) 167check_snmp_LDADD = $(BASEOBJS)
170check_snmp_LDFLAGS = $(AM_LDFLAGS) `net-snmp-config --libs` 168check_snmp_LDFLAGS = $(AM_LDFLAGS) -lm `net-snmp-config --libs`
171check_snmp_CFLAGS = $(AM_CFLAGS) `net-snmp-config --cflags` 169check_snmp_CFLAGS = $(AM_CFLAGS) `net-snmp-config --cflags`
172check_smtp_LDADD = $(SSLOBJS) 170check_smtp_LDADD = $(SSLOBJS)
173check_ssh_LDADD = $(NETLIBS) 171check_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
71enum { 71enum {
72 MAX_IPV4_HOSTLENGTH = 255,
73};
74
75enum {
76 REGS = 2, 72 REGS = 2,
77}; 73};
78 74
@@ -96,16 +92,16 @@ typedef struct {
96static check_curl_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/); 92static check_curl_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
97 93
98static mp_subcheck check_http(check_curl_config /*config*/, check_curl_working_state workingState, 94static mp_subcheck check_http(check_curl_config /*config*/, check_curl_working_state workingState,
99 int redir_depth); 95 long redir_depth);
100 96
101typedef struct { 97typedef 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;
107static redir_wrapper redir(curlhelp_write_curlbuf * /*header_buf*/, check_curl_config /*config*/, 103static 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
110static void print_help(void); 106static void print_help(void);
111void print_usage(void); 107void 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
204mp_subcheck check_http(const check_curl_config config, check_curl_working_state workingState, 200mp_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
659redir_wrapper redir(curlhelp_write_curlbuf *header_buf, const check_curl_config config, 655redir_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;
19check_curl_configure_curl_wrapper 19check_curl_configure_curl_wrapper
20check_curl_configure_curl(const check_curl_static_curl_config config, 20check_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
10enum {
11 MAX_IPV4_HOSTLENGTH = 255,
12};
13
10/* for buffers for header and body */ 14/* for buffers for header and body */
11typedef struct { 15typedef 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
81void handle_curl_option_return_code(CURLcode res, const char *option); 85void 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
35const char *progname = "check_dig"; 35const char *progname = "check_dig";
36const char *copyright = "2002-2024"; 36const char *copyright = "2002-2025";
37const char *email = "devel@monitoring-plugins.org"; 37const 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
57static int verbose = 0; 58static int verbose = 0;
58 59
60/* helpers for flag parsing */
61static flag_list parse_flags_line(const char *line);
62static flag_list split_csv_trim(const char *csv);
63static bool flag_list_contains(const flag_list *list, const char *needle);
64static void free_flag_list(flag_list *list);
65
59int main(int argc, char **argv) { 66int 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 */
459static 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 */
534static 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 */
589static 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 */
611static 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
10typedef struct { 10typedef struct {
11 char **items;
12 size_t count;
13} flag_list;
14
15typedef 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
24check_dig_config check_dig_config_init() { 31check_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
43static void print_help(void); 45static void print_help(void);
44void print_usage(void); 46void 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
80typedef struct threshold_s { 83typedef 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
86typedef struct thresholds_s { 89typedef 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
94typedef struct value_s { 97typedef 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
101typedef struct values_s { 104typedef 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
115static struct { 118static 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
136static char *get_offline_text(int); 139static char *get_offline_text(int /*status*/);
137static int smart_read_values(int, values_t *); 140static int smart_read_values(int /*fd*/, smart_values * /*values*/);
138static int nagios(values_t *, thresholds_t *); 141static mp_state_enum compare_values_and_thresholds(smart_values * /*p*/, smart_thresholds * /*t*/);
139static void print_value(value_t *, threshold_t *); 142static void print_value(smart_value * /*p*/, smart_threshold * /*t*/);
140static void print_values(values_t *, thresholds_t *); 143static void print_values(smart_values * /*p*/, smart_thresholds * /*t*/);
141static int smart_cmd_simple(int, enum SmartCommand, uint8_t, bool); 144static mp_state_enum smart_cmd_simple(int /*fd*/, enum SmartCommand /*command*/, uint8_t /*val0*/, bool /*show_error*/);
142static int smart_read_thresholds(int, thresholds_t *); 145static int smart_read_thresholds(int /*fd*/, smart_thresholds * /*thresholds*/);
143static bool verbose = false; 146static int verbose = 0;
144 147
145int main(int argc, char *argv[]) { 148typedef 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; 152static 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
221int 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
244char *get_offline_text(int status) { 262char *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
254int smart_read_values(int fd, values_t *values) { 271int 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
301int nagios(values_t *p, thresholds_t *t) { 319mp_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
352void print_value(value_t *p, threshold_t *t) { 371void 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
357void print_values(values_t *p, thresholds_t *t) { 377void 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
374int smart_cmd_simple(int fd, enum SmartCommand command, uint8_t val0, bool show_error) { 393mp_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
431int smart_read_thresholds(int fd, thresholds_t *thresholds) { 453int 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
6typedef struct {
7 char *device;
8} check_ide_smart_config;
9
10check_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 */
30char *progname = "check_ldap"; 30#include "output.h"
31const char *copyright = "2000-2024";
32const 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
43char *progname = "check_ldap";
44const char *copyright = "2000-2024";
45const char *email = "devel@monitoring-plugins.org";
46
44enum { 47enum {
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 */
239check_ldap_config_wrapper process_arguments(int argc, char **argv) { 313check_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
37check_ldap_config check_ldap_config_init() { 36check_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
32const char *progname = "check_mrtg";
33const char *copyright = "1999-2024";
34const 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
40const char *progname = "check_mrtg";
41const char *copyright = "1999-2024";
42const char *email = "devel@monitoring-plugins.org";
43
40typedef struct { 44typedef 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(&current_time); 153 time(&current_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 */
162check_mrtg_config_wrapper process_arguments(int argc, char **argv) { 192check_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
21check_mrtg_config check_mrtg_config_init() { 23check_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
32const char *progname = "check_mrtgtraf";
33const char *copyright = "1999-2024";
34const 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
40const char *progname = "check_mrtgtraf";
41const char *copyright = "1999-2024";
42const char *email = "devel@monitoring-plugins.org";
43
40typedef struct { 44typedef 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(&current_time); 140 time(&current_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 */
209check_mrtgtraf_config_wrapper process_arguments(int argc, char **argv) { 238check_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
18check_mrtgtraf_config check_mrtgtraf_config_init() { 21check_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
31check_mysql_config check_mysql_config_init() { 34check_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 */
187check_mysql_query_config_wrapper process_arguments(int argc, char **argv) { 191check_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
21check_mysql_query_config check_mysql_query_config_init() { 25check_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
35const char *progname = "check_nt";
36const char *copyright = "2000-2024";
37const 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
44enum {
45 MAX_VALUE_LIST = 30,
46};
47
48static char recv_buffer[MAX_INPUT_BUFFER];
49
50static void fetch_data(const char *address, int port, const char *sendb);
51
52typedef struct {
53 int errorcode;
54 check_nt_config config;
55} check_nt_config_wrapper;
56static check_nt_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
57
58static void preparelist(char *string);
59static bool strtoularray(unsigned long *array, char *string, const char *delim);
60static void print_help(void);
61void print_usage(void);
62
63int 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 */
481check_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
628void 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
640bool 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
658void 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
667void 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
785void 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
6enum {
7 PORT = 1248,
8};
9
10enum 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
24typedef 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
37check_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
33const char *progname = "check_ntp";
34const char *copyright = "2006-2024";
35const char *email = "devel@monitoring-plugins.org";
36
37#include "common.h"
38#include "netutils.h"
39#include "utils.h"
40
41static char *server_address = NULL;
42static int verbose = 0;
43static bool do_offset = false;
44static char *owarn = "60";
45static char *ocrit = "120";
46static bool do_jitter = false;
47static char *jwarn = "5000";
48static char *jcrit = "10000";
49
50static int process_arguments(int /*argc*/, char ** /*argv*/);
51static thresholds *offset_thresholds = NULL;
52static thresholds *jitter_thresholds = NULL;
53static void print_help(void);
54void 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 */
65typedef 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 */
80typedef 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 */
91typedef 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 */
104typedef 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 */
231static 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 */
241void 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
266void 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
301void 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. */
320int 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 :( */
382double 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
545void 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 */
556double 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
718int 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
800char *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
805char *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
810int 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
895void 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
941void 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
46static int verbose = 0; 48static 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"
31const char *progname = "check_radius"; 32const char *progname = "check_radius";
32const char *copyright = "2000-2024"; 33const char *copyright = "2000-2024";
33const char *email = "devel@monitoring-plugins.org"; 34const 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 */
257check_radius_config_wrapper process_arguments(int argc, char **argv) { 305check_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
28check_radius_config check_radius_config_init() { 32check_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>
33const char *progname = "check_real";
34const char *copyright = "2000-2024";
35const 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." 41const char *progname = "check_real";
43#define URL "" 42const char *copyright = "2000-2024";
43const char *email = "devel@monitoring-plugins.org";
44
45#define URL ""
44 46
45typedef struct { 47typedef 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 */
278check_real_config_wrapper process_arguments(int argc, char **argv) { 338check_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
6enum { 8enum {
7 PORT = 554 9 PORT = 554
8}; 10};
9 11
12const char *default_expect = "RTSP/1.";
13
10typedef struct { 14typedef 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
23check_real_config check_real_config_init() { 28check_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 */
844state_key np_enable_state(char *keyname, int expected_data_version, char *plugin_name, int argc, 848state_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
68state_data *np_state_read(state_key stateKey); 68state_data *np_state_read(state_key stateKey);
69state_key np_enable_state(char *keyname, int expected_data_version, char *plugin_name, int argc, 69state_key np_enable_state(char *keyname, int expected_data_version, const char *plugin_name,
70 char **argv); 70 int argc, char **argv);
71void np_state_write_string(state_key stateKey, time_t timestamp, char *stringToStore); 71void 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
83my $free_inodes_on_mp1 = $result->{'mp_test_result'}->{'checks'}->[1]->{'checks'}[2]->{'perfdata'}->[0]->{'value'}->{'value'}; 83my $used_inodes_on_mp1 = $result->{'mp_test_result'}->{'checks'}->[1]->{'checks'}[2]->{'perfdata'}->[0]->{'value'}->{'value'};
84my $total_inodes_on_mp1 = $result->{'mp_test_result'}->{'checks'}->[1]->{'checks'}[2]->{'perfdata'}->[0]->{'max'}->{'value'}; 84my $total_inodes_on_mp1 = $result->{'mp_test_result'}->{'checks'}->[1]->{'checks'}[2]->{'perfdata'}->[0]->{'max'}->{'value'};
85
86my $free_inodes_on_mp1 = $total_inodes_on_mp1 - $used_inodes_on_mp1;
85my $free_inode_percentage_on_mp1 = $free_inodes_on_mp1 / ($total_inodes_on_mp1 / 100); 87my $free_inode_percentage_on_mp1 = $free_inodes_on_mp1 / ($total_inodes_on_mp1 / 100);
86 88
87my $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
93my $used_inodes_on_mp2 = $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}[2]->{'perfdata'}->[0]->{'value'}->{'value'};
88my $total_inodes_on_mp2 = $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}[2]->{'perfdata'}->[0]->{'max'}->{'value'}; 94my $total_inodes_on_mp2 = $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}[2]->{'perfdata'}->[0]->{'max'}->{'value'};
95my $free_inodes_on_mp2 = $total_inodes_on_mp2 - $used_inodes_on_mp2;
89my $free_inode_percentage_on_mp2 = $free_inodes_on_mp2 / ($total_inodes_on_mp2 / 100); 96my $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
91my $avg_inode_free_percentage = ceil(($free_inode_percentage_on_mp1 + $free_inode_percentage_on_mp2)/2); 102my $avg_inode_free_percentage = ceil(($free_inode_percentage_on_mp1 + $free_inode_percentage_on_mp2)/2);
92my ($more_inode_free, $less_inode_free); 103my ($more_inode_free, $less_inode_free);
93if ($free_inode_percentage_on_mp1 > $free_inode_percentage_on_mp2) { 104if ($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
38SKIP: { 38SKIP: {
@@ -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;
8use Test::More; 8use Test::More;
9use NPTest; 9use NPTest;
10 10
11my @PLUGINS1 = ('check_ntp', 'check_ntp_peer', 'check_ntp_time'); 11my @PLUGINS1 = ('check_ntp_peer', 'check_ntp_time');
12my @PLUGINS2 = ('check_ntp_peer'); 12my @PLUGINS2 = ('check_ntp_peer');
13 13
14plan tests => (12 * scalar(@PLUGINS1)) + (6 * scalar(@PLUGINS2)); 14plan 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;
20use NPTest; 20use NPTest;
21use FindBin qw($Bin); 21use FindBin qw($Bin);
22 22
23use URI;
24use URI::QueryParam;
25use HTTP::Daemon;
26use HTTP::Daemon::SSL;
27
23$ENV{'LC_TIME'} = "C"; 28$ENV{'LC_TIME'} = "C";
24 29
25my $common_tests = 75; 30my $common_tests = 95;
26my $ssl_only_tests = 8; 31my $ssl_only_tests = 8;
27# Check that all dependent modules are available 32# Check that all dependent modules are available
28eval "use HTTP::Daemon 6.01;"; 33eval "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
6use strict;
7use Test::More;
8use NPTest;
9use FindBin qw($Bin);
10
11use IO::Socket;
12use IO::Select;
13use POSIX;
14
15my $port = 50000 + int(rand(1000));
16
17my $pid = fork();
18if ($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
55END { if ($pid) { print "Killing $pid\n"; kill "INT", $pid } };
56
57if ($ARGV[0] && $ARGV[0] eq "-d") {
58 sleep 1000;
59}
60
61if (-x "./check_nt") {
62 plan tests => 5;
63} else {
64 plan skip_all => "No check_nt compiled";
65}
66
67my $result;
68my $command = "./check_nt -H 127.0.0.1 -p $port";
69
70$result = NPTest->testCmd( "$command -v USEDDISKSPACE -l c" );
71is( $result->return_code, 0, "USEDDISKSPACE c");
72is( $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" );
75is( $result->return_code, 3, "USEDDISKSPACE d - invalid");
76is( $result->output, "Free disk space : Invalid drive", "Output right" );
77
78$result = NPTest->testCmd( "./check_nt -v USEDDISKSPACE -l d" );
79is( $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
43time_t start_time, end_time;
44 43
45void usage(const char *msg) { 44void 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. */
32void support(void); 32void support(void);
33void print_revision(const char *, const char *); 33void print_revision(const char *, const char *);
34 34
35extern time_t start_time, end_time;
36
37/* Test input types */ 35/* Test input types */
38 36
39bool is_integer(char *); 37bool is_integer(char *);