summaryrefslogtreecommitdiffstats
path: root/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'plugins')
-rw-r--r--plugins/Makefile.am3
-rw-r--r--plugins/check_by_ssh.c34
-rw-r--r--plugins/check_curl.c65
-rw-r--r--plugins/check_curl.d/check_curl_helpers.c32
-rw-r--r--plugins/check_curl.d/check_curl_helpers.h2
-rw-r--r--plugins/check_curl.d/config.h6
-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_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.c10
-rw-r--r--plugins/check_snmp.d/check_snmp_helpers.h4
-rw-r--r--plugins/check_time.c2
-rwxr-xr-xplugins/tests/check_curl.t184
-rw-r--r--plugins/utils.c1
-rw-r--r--plugins/utils.h2
18 files changed, 649 insertions, 314 deletions
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
index d098fa8a..a35f273e 100644
--- a/plugins/Makefile.am
+++ b/plugins/Makefile.am
@@ -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 \
@@ -164,7 +165,7 @@ check_radius_LDADD = $(NETLIBS) $(RADIUSLIBS)
164check_real_LDADD = $(NETLIBS) 165check_real_LDADD = $(NETLIBS)
165check_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
166check_snmp_LDADD = $(BASEOBJS) 167check_snmp_LDADD = $(BASEOBJS)
167check_snmp_LDFLAGS = $(AM_LDFLAGS) `net-snmp-config --libs` 168check_snmp_LDFLAGS = $(AM_LDFLAGS) -lm `net-snmp-config --libs`
168check_snmp_CFLAGS = $(AM_CFLAGS) `net-snmp-config --cflags` 169check_snmp_CFLAGS = $(AM_CFLAGS) `net-snmp-config --cflags`
169check_smtp_LDADD = $(SSLOBJS) 170check_smtp_LDADD = $(SSLOBJS)
170check_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 e3e514ff..1dec8a2a 100644
--- a/plugins/check_curl.c
+++ b/plugins/check_curl.c
@@ -92,16 +92,16 @@ typedef struct {
92static check_curl_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/); 92static check_curl_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
93 93
94static 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,
95 int redir_depth); 95 long redir_depth);
96 96
97typedef struct { 97typedef struct {
98 int redir_depth; 98 long redir_depth;
99 check_curl_working_state working_state; 99 check_curl_working_state working_state;
100 int error_code; 100 int error_code;
101 check_curl_global_state curl_state; 101 check_curl_global_state curl_state;
102} redir_wrapper; 102} redir_wrapper;
103static 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*/,
104 int redir_depth, check_curl_working_state working_state); 104 long redir_depth, check_curl_working_state working_state);
105 105
106static void print_help(void); 106static void print_help(void);
107void print_usage(void); 107void print_usage(void);
@@ -198,7 +198,7 @@ CURLcode sslctxfun(CURL *curl, SSL_CTX *sslctx, void *parm) {
198#endif /* HAVE_SSL */ 198#endif /* HAVE_SSL */
199 199
200mp_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,
201 int redir_depth) { 201 long redir_depth) {
202 202
203 // ======================= 203 // =======================
204 // Initialisation for curl 204 // Initialisation for curl
@@ -441,19 +441,19 @@ mp_subcheck check_http(const check_curl_config config, check_curl_working_state
441 "CURLINFO_REDIRECT_COUNT"); 441 "CURLINFO_REDIRECT_COUNT");
442 442
443 if (verbose >= 2) { 443 if (verbose >= 2) {
444 printf(_("* curl LIBINFO_REDIRECT_COUNT is %d\n"), redir_depth); 444 printf(_("* curl LIBINFO_REDIRECT_COUNT is %ld\n"), redir_depth);
445 } 445 }
446 446
447 mp_subcheck sc_redir_depth = mp_subcheck_init(); 447 mp_subcheck sc_redir_depth = mp_subcheck_init();
448 if (redir_depth > config.max_depth) { 448 if (redir_depth > config.max_depth) {
449 xasprintf(&sc_redir_depth.output, 449 xasprintf(&sc_redir_depth.output,
450 "maximum redirection depth %d exceeded in libcurl", 450 "maximum redirection depth %ld exceeded in libcurl",
451 config.max_depth); 451 config.max_depth);
452 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);
453 mp_add_subcheck_to_subcheck(&sc_result, sc_redir_depth); 453 mp_add_subcheck_to_subcheck(&sc_result, sc_redir_depth);
454 return sc_result; 454 return sc_result;
455 } 455 }
456 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)",
457 redir_depth, config.max_depth); 457 redir_depth, config.max_depth);
458 mp_add_subcheck_to_subcheck(&sc_result, sc_redir_depth); 458 mp_add_subcheck_to_subcheck(&sc_result, sc_redir_depth);
459 459
@@ -653,7 +653,7 @@ char *uri_string(const UriTextRangeA range, char *buf, size_t buflen) {
653} 653}
654 654
655redir_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,
656 int redir_depth, check_curl_working_state working_state) { 656 long redir_depth, check_curl_working_state working_state) {
657 curlhelp_statusline status_line; 657 curlhelp_statusline status_line;
658 struct phr_header headers[255]; 658 struct phr_header headers[255];
659 size_t msglen; 659 size_t msglen;
@@ -678,7 +678,7 @@ redir_wrapper redir(curlhelp_write_curlbuf *header_buf, const check_curl_config
678 } 678 }
679 679
680 if (++redir_depth > config.max_depth) { 680 if (++redir_depth > config.max_depth) {
681 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"),
682 config.max_depth, location); 682 config.max_depth, location);
683 } 683 }
684 684
@@ -761,7 +761,7 @@ redir_wrapper redir(curlhelp_write_curlbuf *header_buf, const check_curl_config
761 } 761 }
762 762
763 /* compose new path */ 763 /* compose new path */
764 /* TODO: handle fragments and query part of URL */ 764 /* TODO: handle fragments of URL */
765 char *new_url = (char *)calloc(1, DEFAULT_BUFFER_SIZE); 765 char *new_url = (char *)calloc(1, DEFAULT_BUFFER_SIZE);
766 if (uri.pathHead) { 766 if (uri.pathHead) {
767 for (UriPathSegmentA *pathSegment = uri.pathHead; pathSegment; 767 for (UriPathSegmentA *pathSegment = uri.pathHead; pathSegment;
@@ -772,6 +772,29 @@ redir_wrapper redir(curlhelp_write_curlbuf *header_buf, const check_curl_config
772 } 772 }
773 } 773 }
774 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
775 if (working_state.serverPort == new_port && 798 if (working_state.serverPort == new_port &&
776 !strncmp(working_state.server_address, new_host, MAX_IPV4_HOSTLENGTH) && 799 !strncmp(working_state.server_address, new_host, MAX_IPV4_HOSTLENGTH) &&
777 (working_state.host_name && 800 (working_state.host_name &&
@@ -1400,7 +1423,7 @@ check_curl_config_wrapper process_arguments(int argc, char **argv) {
1400 } 1423 }
1401#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 54, 0) */ 1424#endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 54, 0) */
1402 if (verbose >= 2) { 1425 if (verbose >= 2) {
1403 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);
1404 } 1427 }
1405 if (!specify_port) { 1428 if (!specify_port) {
1406 result.config.initial_config.serverPort = HTTPS_PORT; 1429 result.config.initial_config.serverPort = HTTPS_PORT;
@@ -1482,8 +1505,8 @@ void print_help(void) {
1482 printf(" %s\n", "-I, --IP-address=ADDRESS"); 1505 printf(" %s\n", "-I, --IP-address=ADDRESS");
1483 printf(" %s\n", 1506 printf(" %s\n",
1484 "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).");
1485 printf(" %s\n", 1508 printf(" %s\n", "This overwrites the network address of the target while leaving everything "
1486 "This overwrites the network address of the target while leaving everything else (HTTP headers) as they are"); 1509 "else (HTTP headers) as they are");
1487 printf(" %s\n", "-p, --port=INTEGER"); 1510 printf(" %s\n", "-p, --port=INTEGER");
1488 printf(" %s", _("Port number (default: ")); 1511 printf(" %s", _("Port number (default: "));
1489 printf("%d)\n", HTTP_PORT); 1512 printf("%d)\n", HTTP_PORT);
@@ -1547,7 +1570,8 @@ void print_help(void) {
1547 printf(" %s\n", _("String to expect in the content")); 1570 printf(" %s\n", _("String to expect in the content"));
1548 printf(" %s\n", "-u, --url=PATH"); 1571 printf(" %s\n", "-u, --url=PATH");
1549 printf(" %s\n", _("URL to GET or POST (default: /)")); 1572 printf(" %s\n", _("URL to GET or POST (default: /)"));
1550 printf(" %s\n", _("This is the part after the address in a URL, so for \"https://example.com/index.html\" it would be '-u /index.html'")); 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'"));
1551 printf(" %s\n", "-P, --post=STRING"); 1575 printf(" %s\n", "-P, --post=STRING");
1552 printf(" %s\n", _("URL decoded http POST data")); 1576 printf(" %s\n", _("URL decoded http POST data"));
1553 printf(" %s\n", 1577 printf(" %s\n",
@@ -1648,6 +1672,8 @@ void print_help(void) {
1648 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"));
1649 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."));
1650 printf("\n"); 1674 printf("\n");
1675 printf(" %s\n", _("To also verify certificates, please set --verify-cert."));
1676 printf("\n");
1651 printf("%s\n", _("Examples:")); 1677 printf("%s\n", _("Examples:"));
1652 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");
1653 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,"));
@@ -1657,16 +1683,18 @@ void print_help(void) {
1657 _("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,"));
1658 printf(" %s\n", _("a STATE_CRITICAL will be returned.")); 1684 printf(" %s\n", _("a STATE_CRITICAL will be returned."));
1659 printf("\n"); 1685 printf("\n");
1660 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");
1661 printf(" %s\n", 1687 printf(" %s\n",
1662 _("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,"));
1663 printf(" %s\n", 1689 printf(" %s\n",
1664 _("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"));
1665 printf(" %s\n", 1691 printf(" %s\n",
1666 _("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"));
1667 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."));
1668 printf("\n"); 1696 printf("\n");
1669 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");
1670 printf(" %s\n", 1698 printf(" %s\n",
1671 _("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,"));
1672 printf(" %s\n", 1700 printf(" %s\n",
@@ -1689,7 +1717,8 @@ void print_help(void) {
1689 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:"));
1690 printf(" %s\n", 1718 printf(" %s\n",
1691 _("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"));
1692 printf(" %s\n", _("legacy proxy requests in check_http style might still work, but are frowned upon, so DONT:")); 1720 printf(" %s\n", _("legacy proxy requests in check_http style might still work, but are frowned "
1721 "upon, so DONT:"));
1693 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 "
1694 "CONNECT -H www.verisign.com ")); 1723 "CONNECT -H www.verisign.com "));
1695 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 e4e7bef6..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
@@ -214,10 +214,10 @@ check_curl_configure_curl(const check_curl_static_curl_config config,
214 if (working_state.http_method) { 214 if (working_state.http_method) {
215 if (!strcmp(working_state.http_method, "POST")) { 215 if (!strcmp(working_state.http_method, "POST")) {
216 handle_curl_option_return_code( 216 handle_curl_option_return_code(
217 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");
218 } else if (!strcmp(working_state.http_method, "PUT")) { 218 } else if (!strcmp(working_state.http_method, "PUT")) {
219 handle_curl_option_return_code( 219 handle_curl_option_return_code(
220 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");
221 } else { 221 } else {
222 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,
223 CURLOPT_CUSTOMREQUEST, 223 CURLOPT_CUSTOMREQUEST,
@@ -300,10 +300,10 @@ check_curl_configure_curl(const check_curl_static_curl_config config,
300 /* 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
301 * hostname in the certificate, can be switched off later */ 301 * hostname in the certificate, can be switched off later */
302 handle_curl_option_return_code( 302 handle_curl_option_return_code(
303 curl_easy_setopt(result.curl_state.curl, CURLOPT_SSL_VERIFYPEER, 1), 303 curl_easy_setopt(result.curl_state.curl, CURLOPT_SSL_VERIFYPEER, 1L),
304 "CURLOPT_SSL_VERIFYPEER"); 304 "CURLOPT_SSL_VERIFYPEER");
305 handle_curl_option_return_code( 305 handle_curl_option_return_code(
306 curl_easy_setopt(result.curl_state.curl, CURLOPT_SSL_VERIFYHOST, 2), 306 curl_easy_setopt(result.curl_state.curl, CURLOPT_SSL_VERIFYHOST, 2L),
307 "CURLOPT_SSL_VERIFYHOST"); 307 "CURLOPT_SSL_VERIFYHOST");
308 } else { 308 } else {
309 /* backward-compatible behaviour, be tolerant in checks 309 /* backward-compatible behaviour, be tolerant in checks
@@ -311,10 +311,10 @@ check_curl_configure_curl(const check_curl_static_curl_config config,
311 * to be less tolerant about ssl verfications 311 * to be less tolerant about ssl verfications
312 */ 312 */
313 handle_curl_option_return_code( 313 handle_curl_option_return_code(
314 curl_easy_setopt(result.curl_state.curl, CURLOPT_SSL_VERIFYPEER, 0), 314 curl_easy_setopt(result.curl_state.curl, CURLOPT_SSL_VERIFYPEER, 0L),
315 "CURLOPT_SSL_VERIFYPEER"); 315 "CURLOPT_SSL_VERIFYPEER");
316 handle_curl_option_return_code( 316 handle_curl_option_return_code(
317 curl_easy_setopt(result.curl_state.curl, CURLOPT_SSL_VERIFYHOST, 0), 317 curl_easy_setopt(result.curl_state.curl, CURLOPT_SSL_VERIFYHOST, 0L),
318 "CURLOPT_SSL_VERIFYHOST"); 318 "CURLOPT_SSL_VERIFYHOST");
319 } 319 }
320 320
@@ -438,7 +438,7 @@ check_curl_configure_curl(const check_curl_static_curl_config config,
438 if (on_redirect_dependent) { 438 if (on_redirect_dependent) {
439 if (follow_method == FOLLOW_LIBCURL) { 439 if (follow_method == FOLLOW_LIBCURL) {
440 handle_curl_option_return_code( 440 handle_curl_option_return_code(
441 curl_easy_setopt(result.curl_state.curl, CURLOPT_FOLLOWLOCATION, 1), 441 curl_easy_setopt(result.curl_state.curl, CURLOPT_FOLLOWLOCATION, 1L),
442 "CURLOPT_FOLLOWLOCATION"); 442 "CURLOPT_FOLLOWLOCATION");
443 443
444 /* default -1 is infinite, not good, could lead to zombie plugins! 444 /* default -1 is infinite, not good, could lead to zombie plugins!
@@ -474,7 +474,7 @@ check_curl_configure_curl(const check_curl_static_curl_config config,
474 } 474 }
475 /* no-body */ 475 /* no-body */
476 if (working_state.no_body) { 476 if (working_state.no_body) {
477 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),
478 "CURLOPT_NOBODY"); 478 "CURLOPT_NOBODY");
479 } 479 }
480 480
@@ -796,15 +796,17 @@ mp_subcheck check_document_dates(const curlhelp_write_curlbuf *header_buf, const
796 ((float)last_modified) / (60 * 60 * 24)); 796 ((float)last_modified) / (60 * 60 * 24));
797 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);
798 } else { 798 } else {
799 xasprintf(&sc_document_dates.output, _("Last modified %ld:%02ld:%02ld ago"), 799 xasprintf(&sc_document_dates.output, _("Last modified %lld:%02d:%02d ago"),
800 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);
801 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);
802 } 803 }
803 } else { 804 } else {
804 // TODO is this the OK case? 805 // TODO is this the OK case?
805 time_t last_modified = (srv_data - doc_data); 806 time_t last_modified = (srv_data - doc_data);
806 xasprintf(&sc_document_dates.output, _("Last modified %ld:%02ld:%02ld ago"), 807 xasprintf(&sc_document_dates.output, _("Last modified %lld:%02d:%02d ago"),
807 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);
808 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);
809 } 811 }
810 } 812 }
@@ -1212,7 +1214,7 @@ mp_subcheck check_curl_certificate_checks(CURL *curl, X509 *cert, int warn_days_
1212 1214
1213 cert_ptr_union cert_ptr = {0}; 1215 cert_ptr_union cert_ptr = {0};
1214 cert_ptr.to_info = NULL; 1216 cert_ptr.to_info = NULL;
1215 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);
1216 if (!res && cert_ptr.to_info) { 1218 if (!res && cert_ptr.to_info) {
1217# ifdef USE_OPENSSL 1219# ifdef USE_OPENSSL
1218 /* 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 e7b80f7e..e77b763b 100644
--- a/plugins/check_curl.d/check_curl_helpers.h
+++ b/plugins/check_curl.d/check_curl_helpers.h
@@ -80,7 +80,7 @@ check_curl_configure_curl_wrapper check_curl_configure_curl(check_curl_static_cu
80 check_curl_working_state working_state, 80 check_curl_working_state working_state,
81 bool check_cert, 81 bool check_cert,
82 bool on_redirect_dependent, 82 bool on_redirect_dependent,
83 int follow_method, int max_depth); 83 int follow_method, long max_depth);
84 84
85void handle_curl_option_return_code(CURLcode res, const char *option); 85void handle_curl_option_return_code(CURLcode res, const char *option);
86 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_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_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 f506537a..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
@@ -843,8 +845,8 @@ char *_np_state_calculate_location_prefix(void) {
843 * Sets variables. Generates filename. Returns np_state_key. die with 845 * Sets variables. Generates filename. Returns np_state_key. die with
844 * UNKNOWN if exception 846 * UNKNOWN if exception
845 */ 847 */
846state_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,
847 char **argv) { 849 int argc, char **argv) {
848 state_key *this_state = (state_key *)calloc(1, sizeof(state_key)); 850 state_key *this_state = (state_key *)calloc(1, sizeof(state_key));
849 if (this_state == NULL) { 851 if (this_state == NULL) {
850 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno)); 852 die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno));
@@ -869,7 +871,7 @@ state_key np_enable_state(char *keyname, int expected_data_version, char *plugin
869 tmp_char++; 871 tmp_char++;
870 } 872 }
871 this_state->name = temp_keyname; 873 this_state->name = temp_keyname;
872 this_state->plugin_name = plugin_name; 874 this_state->plugin_name = (char *)plugin_name;
873 this_state->data_version = expected_data_version; 875 this_state->data_version = expected_data_version;
874 this_state->state_data = NULL; 876 this_state->state_data = NULL;
875 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/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/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 *);