summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/utils_tcp.h1
-rw-r--r--plugins/Makefile.am5
-rw-r--r--plugins/check_real.c245
-rw-r--r--plugins/check_real.d/config.h37
-rw-r--r--plugins/check_tcp.c777
-rw-r--r--plugins/check_tcp.d/config.h84
-rw-r--r--plugins/check_time.c191
-rw-r--r--plugins/check_time.d/config.h42
-rw-r--r--plugins/check_ups.c274
-rw-r--r--plugins/check_ups.d/config.h55
-rw-r--r--plugins/negate.c96
-rw-r--r--plugins/negate.d/config.h24
-rw-r--r--plugins/t/check_ftp.t2
-rw-r--r--plugins/t/check_jabber.t4
-rw-r--r--plugins/t/check_tcp.t12
-rw-r--r--plugins/t/check_udp.t4
16 files changed, 1135 insertions, 718 deletions
diff --git a/lib/utils_tcp.h b/lib/utils_tcp.h
index d5999e9b..a7d83c59 100644
--- a/lib/utils_tcp.h
+++ b/lib/utils_tcp.h
@@ -11,6 +11,7 @@
11 * server. 11 * server.
12 */ 12 */
13enum np_match_result { 13enum np_match_result {
14 NP_MATCH_NONE,
14 NP_MATCH_FAILURE, 15 NP_MATCH_FAILURE,
15 NP_MATCH_SUCCESS, 16 NP_MATCH_SUCCESS,
16 NP_MATCH_RETRY 17 NP_MATCH_RETRY
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
index a1a8103d..30ca63d1 100644
--- a/plugins/Makefile.am
+++ b/plugins/Makefile.am
@@ -49,13 +49,17 @@ np_test_scripts = tests/test_check_swap.t
49EXTRA_DIST = t \ 49EXTRA_DIST = t \
50 tests \ 50 tests \
51 $(np_test_scripts) \ 51 $(np_test_scripts) \
52 negate.d \
52 check_swap.d \ 53 check_swap.d \
53 check_ldap.d \ 54 check_ldap.d \
54 check_hpjd.d \ 55 check_hpjd.d \
55 check_game.d \ 56 check_game.d \
56 check_radius.d \ 57 check_radius.d \
58 check_time.d \
57 check_nagios.d \ 59 check_nagios.d \
58 check_dbi.d \ 60 check_dbi.d \
61 check_tcp.d \
62 check_real.d \
59 check_ssh.d \ 63 check_ssh.d \
60 check_nt.d \ 64 check_nt.d \
61 check_dns.d \ 65 check_dns.d \
@@ -72,6 +76,7 @@ EXTRA_DIST = t \
72 check_ntp_time.d \ 76 check_ntp_time.d \
73 check_dig.d \ 77 check_dig.d \
74 check_cluster.d \ 78 check_cluster.d \
79 check_ups.d \
75 check_fping.d 80 check_fping.d
76 81
77PLUGINHDRS = common.h 82PLUGINHDRS = common.h
diff --git a/plugins/check_real.c b/plugins/check_real.c
index 369a88b1..ec0928ed 100644
--- a/plugins/check_real.c
+++ b/plugins/check_real.c
@@ -28,6 +28,8 @@
28 * 28 *
29 *****************************************************************************/ 29 *****************************************************************************/
30 30
31#include "states.h"
32#include <stdio.h>
31const char *progname = "check_real"; 33const char *progname = "check_real";
32const char *copyright = "2000-2024"; 34const char *copyright = "2000-2024";
33const char *email = "devel@monitoring-plugins.org"; 35const char *email = "devel@monitoring-plugins.org";
@@ -35,27 +37,20 @@ const char *email = "devel@monitoring-plugins.org";
35#include "common.h" 37#include "common.h"
36#include "netutils.h" 38#include "netutils.h"
37#include "utils.h" 39#include "utils.h"
38 40#include "check_real.d/config.h"
39enum {
40 PORT = 554
41};
42 41
43#define EXPECT "RTSP/1." 42#define EXPECT "RTSP/1."
44#define URL "" 43#define URL ""
45 44
46static int process_arguments(int, char **); 45typedef struct {
46 int errorcode;
47 check_real_config config;
48} check_real_config_wrapper;
49static check_real_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
50
47static void print_help(void); 51static void print_help(void);
48void print_usage(void); 52void print_usage(void);
49 53
50static int server_port = PORT;
51static char *server_address;
52static char *host_name;
53static char *server_url = NULL;
54static char *server_expect;
55static int warning_time = 0;
56static bool check_warning_time = false;
57static int critical_time = 0;
58static bool check_critical_time = false;
59static bool verbose = false; 54static bool verbose = false;
60 55
61int main(int argc, char **argv) { 56int main(int argc, char **argv) {
@@ -66,8 +61,12 @@ int main(int argc, char **argv) {
66 /* Parse extra opts if any */ 61 /* Parse extra opts if any */
67 argv = np_extra_opts(&argc, argv, progname); 62 argv = np_extra_opts(&argc, argv, progname);
68 63
69 if (process_arguments(argc, argv) == ERROR) 64 check_real_config_wrapper tmp_config = process_arguments(argc, argv);
65 if (tmp_config.errorcode == ERROR) {
70 usage4(_("Could not parse arguments")); 66 usage4(_("Could not parse arguments"));
67 }
68
69 const check_real_config config = tmp_config.config;
71 70
72 /* initialize alarm signal handling */ 71 /* initialize alarm signal handling */
73 signal(SIGALRM, socket_timeout_alarm_handler); 72 signal(SIGALRM, socket_timeout_alarm_handler);
@@ -78,38 +77,51 @@ int main(int argc, char **argv) {
78 77
79 /* try to connect to the host at the given port number */ 78 /* try to connect to the host at the given port number */
80 int socket; 79 int socket;
81 if (my_tcp_connect(server_address, server_port, &socket) != STATE_OK) 80 if (my_tcp_connect(config.server_address, config.server_port, &socket) != STATE_OK) {
82 die(STATE_CRITICAL, _("Unable to connect to %s on port %d\n"), server_address, server_port); 81 die(STATE_CRITICAL, _("Unable to connect to %s on port %d\n"), config.server_address, config.server_port);
82 }
83 83
84 /* Part I - Server Check */ 84 /* Part I - Server Check */
85 85
86 /* send the OPTIONS request */ 86 /* send the OPTIONS request */
87 char buffer[MAX_INPUT_BUFFER]; 87 char buffer[MAX_INPUT_BUFFER];
88 sprintf(buffer, "OPTIONS rtsp://%s:%d RTSP/1.0\r\n", host_name, server_port); 88 sprintf(buffer, "OPTIONS rtsp://%s:%d RTSP/1.0\r\n", config.host_name, config.server_port);
89 int result = send(socket, buffer, strlen(buffer), 0); 89 ssize_t sent_bytes = send(socket, buffer, strlen(buffer), 0);
90 if (sent_bytes == -1) {
91 die(STATE_CRITICAL, _("Sending options to %s failed\n"), config.host_name);
92 }
90 93
91 /* send the header sync */ 94 /* send the header sync */
92 sprintf(buffer, "CSeq: 1\r\n"); 95 sprintf(buffer, "CSeq: 1\r\n");
93 result = send(socket, buffer, strlen(buffer), 0); 96 sent_bytes = send(socket, buffer, strlen(buffer), 0);
97 if (sent_bytes == -1) {
98 die(STATE_CRITICAL, _("Sending header sync to %s failed\n"), config.host_name);
99 }
94 100
95 /* send a newline so the server knows we're done with the request */ 101 /* send a newline so the server knows we're done with the request */
96 sprintf(buffer, "\r\n"); 102 sprintf(buffer, "\r\n");
97 result = send(socket, buffer, strlen(buffer), 0); 103 sent_bytes = send(socket, buffer, strlen(buffer), 0);
104 if (sent_bytes == -1) {
105 die(STATE_CRITICAL, _("Sending newline to %s failed\n"), config.host_name);
106 }
98 107
99 /* watch for the REAL connection string */ 108 /* watch for the REAL connection string */
100 result = recv(socket, buffer, MAX_INPUT_BUFFER - 1, 0); 109 ssize_t received_bytes = recv(socket, buffer, MAX_INPUT_BUFFER - 1, 0);
101 110
102 /* return a CRITICAL status if we couldn't read any data */ 111 /* return a CRITICAL status if we couldn't read any data */
103 if (result == -1) 112 if (received_bytes == -1) {
104 die(STATE_CRITICAL, _("No data received from %s\n"), host_name); 113 die(STATE_CRITICAL, _("No data received from %s\n"), config.host_name);
114 }
105 115
116 mp_state_enum result = STATE_OK;
106 char *status_line = NULL; 117 char *status_line = NULL;
107 /* make sure we find the response we are looking for */ 118 /* make sure we find the response we are looking for */
108 if (!strstr(buffer, server_expect)) { 119 if (!strstr(buffer, config.server_expect)) {
109 if (server_port == PORT) 120 if (config.server_port == PORT) {
110 printf("%s\n", _("Invalid REAL response received from host")); 121 printf("%s\n", _("Invalid REAL response received from host"));
111 else 122 } else {
112 printf(_("Invalid REAL response received from host on port %d\n"), server_port); 123 printf(_("Invalid REAL response received from host on port %d\n"), config.server_port);
124 }
113 } else { 125 } else {
114 /* else we got the REAL string, so check the return code */ 126 /* else we got the REAL string, so check the return code */
115 127
@@ -117,69 +129,79 @@ int main(int argc, char **argv) {
117 129
118 result = STATE_OK; 130 result = STATE_OK;
119 131
120 status_line = (char *)strtok(buffer, "\n"); 132 status_line = strtok(buffer, "\n");
121 133
122 if (strstr(status_line, "200")) 134 if (strstr(status_line, "200")) {
123 result = STATE_OK; 135 result = STATE_OK;
136 }
124 137
125 /* client errors result in a warning state */ 138 /* client errors result in a warning state */
126 else if (strstr(status_line, "400")) 139 else if (strstr(status_line, "400")) {
127 result = STATE_WARNING; 140 result = STATE_WARNING;
128 else if (strstr(status_line, "401")) 141 } else if (strstr(status_line, "401")) {
129 result = STATE_WARNING; 142 result = STATE_WARNING;
130 else if (strstr(status_line, "402")) 143 } else if (strstr(status_line, "402")) {
131 result = STATE_WARNING; 144 result = STATE_WARNING;
132 else if (strstr(status_line, "403")) 145 } else if (strstr(status_line, "403")) {
133 result = STATE_WARNING; 146 result = STATE_WARNING;
134 else if (strstr(status_line, "404")) 147 } else if (strstr(status_line, "404")) {
135 result = STATE_WARNING; 148 result = STATE_WARNING;
136 149 } else if (strstr(status_line, "500")) {
137 /* server errors result in a critical state */ 150 /* server errors result in a critical state */
138 else if (strstr(status_line, "500"))
139 result = STATE_CRITICAL; 151 result = STATE_CRITICAL;
140 else if (strstr(status_line, "501")) 152 } else if (strstr(status_line, "501")) {
141 result = STATE_CRITICAL; 153 result = STATE_CRITICAL;
142 else if (strstr(status_line, "502")) 154 } else if (strstr(status_line, "502")) {
143 result = STATE_CRITICAL; 155 result = STATE_CRITICAL;
144 else if (strstr(status_line, "503")) 156 } else if (strstr(status_line, "503")) {
145 result = STATE_CRITICAL; 157 result = STATE_CRITICAL;
146 158 } else {
147 else
148 result = STATE_UNKNOWN; 159 result = STATE_UNKNOWN;
160 }
149 } 161 }
150 162
151 /* Part II - Check stream exists and is ok */ 163 /* Part II - Check stream exists and is ok */
152 if ((result == STATE_OK) && (server_url != NULL)) { 164 if ((result == STATE_OK) && (config.server_url != NULL)) {
153 165
154 /* Part I - Server Check */ 166 /* Part I - Server Check */
155 167
156 /* send the DESCRIBE request */ 168 /* send the DESCRIBE request */
157 sprintf(buffer, "DESCRIBE rtsp://%s:%d%s RTSP/1.0\r\n", host_name, server_port, server_url); 169 sprintf(buffer, "DESCRIBE rtsp://%s:%d%s RTSP/1.0\r\n", config.host_name, config.server_port, config.server_url);
158 result = send(socket, buffer, strlen(buffer), 0); 170
171 ssize_t sent_bytes = send(socket, buffer, strlen(buffer), 0);
172 if (sent_bytes == -1) {
173 die(STATE_CRITICAL, _("Sending DESCRIBE request to %s failed\n"), config.host_name);
174 }
159 175
160 /* send the header sync */ 176 /* send the header sync */
161 sprintf(buffer, "CSeq: 2\r\n"); 177 sprintf(buffer, "CSeq: 2\r\n");
162 result = send(socket, buffer, strlen(buffer), 0); 178 sent_bytes = send(socket, buffer, strlen(buffer), 0);
179 if (sent_bytes == -1) {
180 die(STATE_CRITICAL, _("Sending DESCRIBE request to %s failed\n"), config.host_name);
181 }
163 182
164 /* send a newline so the server knows we're done with the request */ 183 /* send a newline so the server knows we're done with the request */
165 sprintf(buffer, "\r\n"); 184 sprintf(buffer, "\r\n");
166 result = send(socket, buffer, strlen(buffer), 0); 185 sent_bytes = send(socket, buffer, strlen(buffer), 0);
186 if (sent_bytes == -1) {
187 die(STATE_CRITICAL, _("Sending DESCRIBE request to %s failed\n"), config.host_name);
188 }
167 189
168 /* watch for the REAL connection string */ 190 /* watch for the REAL connection string */
169 result = recv(socket, buffer, MAX_INPUT_BUFFER - 1, 0); 191 ssize_t recv_bytes = recv(socket, buffer, MAX_INPUT_BUFFER - 1, 0);
170 buffer[result] = '\0'; /* null terminate received buffer */ 192 if (recv_bytes == -1) {
171 193 /* return a CRITICAL status if we couldn't read any data */
172 /* return a CRITICAL status if we couldn't read any data */
173 if (result == -1) {
174 printf(_("No data received from host\n")); 194 printf(_("No data received from host\n"));
175 result = STATE_CRITICAL; 195 result = STATE_CRITICAL;
176 } else { 196 } else {
197 buffer[result] = '\0'; /* null terminate received buffer */
177 /* make sure we find the response we are looking for */ 198 /* make sure we find the response we are looking for */
178 if (!strstr(buffer, server_expect)) { 199 if (!strstr(buffer, config.server_expect)) {
179 if (server_port == PORT) 200 if (config.server_port == PORT) {
180 printf("%s\n", _("Invalid REAL response received from host")); 201 printf("%s\n", _("Invalid REAL response received from host"));
181 else 202 } else {
182 printf(_("Invalid REAL response received from host on port %d\n"), server_port); 203 printf(_("Invalid REAL response received from host on port %d\n"), config.server_port);
204 }
183 } else { 205 } else {
184 206
185 /* else we got the REAL string, so check the return code */ 207 /* else we got the REAL string, so check the return code */
@@ -188,51 +210,56 @@ int main(int argc, char **argv) {
188 210
189 result = STATE_OK; 211 result = STATE_OK;
190 212
191 status_line = (char *)strtok(buffer, "\n"); 213 status_line = strtok(buffer, "\n");
192 214
193 if (strstr(status_line, "200")) 215 if (strstr(status_line, "200")) {
194 result = STATE_OK; 216 result = STATE_OK;
217 }
195 218
196 /* client errors result in a warning state */ 219 /* client errors result in a warning state */
197 else if (strstr(status_line, "400")) 220 else if (strstr(status_line, "400")) {
198 result = STATE_WARNING; 221 result = STATE_WARNING;
199 else if (strstr(status_line, "401")) 222 } else if (strstr(status_line, "401")) {
200 result = STATE_WARNING; 223 result = STATE_WARNING;
201 else if (strstr(status_line, "402")) 224 } else if (strstr(status_line, "402")) {
202 result = STATE_WARNING; 225 result = STATE_WARNING;
203 else if (strstr(status_line, "403")) 226 } else if (strstr(status_line, "403")) {
204 result = STATE_WARNING; 227 result = STATE_WARNING;
205 else if (strstr(status_line, "404")) 228 } else if (strstr(status_line, "404")) {
206 result = STATE_WARNING; 229 result = STATE_WARNING;
230 }
207 231
208 /* server errors result in a critical state */ 232 /* server errors result in a critical state */
209 else if (strstr(status_line, "500")) 233 else if (strstr(status_line, "500")) {
210 result = STATE_CRITICAL; 234 result = STATE_CRITICAL;
211 else if (strstr(status_line, "501")) 235 } else if (strstr(status_line, "501")) {
212 result = STATE_CRITICAL; 236 result = STATE_CRITICAL;
213 else if (strstr(status_line, "502")) 237 } else if (strstr(status_line, "502")) {
214 result = STATE_CRITICAL; 238 result = STATE_CRITICAL;
215 else if (strstr(status_line, "503")) 239 } else if (strstr(status_line, "503")) {
216 result = STATE_CRITICAL; 240 result = STATE_CRITICAL;
241 }
217 242
218 else 243 else {
219 result = STATE_UNKNOWN; 244 result = STATE_UNKNOWN;
245 }
220 } 246 }
221 } 247 }
222 } 248 }
223 249
224 /* Return results */ 250 /* Return results */
225 if (result == STATE_OK) { 251 if (result == STATE_OK) {
226 252 if (config.check_critical_time && (end_time - start_time) > config.critical_time) {
227 if (check_critical_time && (end_time - start_time) > critical_time)
228 result = STATE_CRITICAL; 253 result = STATE_CRITICAL;
229 else if (check_warning_time && (end_time - start_time) > warning_time) 254 } else if (config.check_warning_time && (end_time - start_time) > config.warning_time) {
230 result = STATE_WARNING; 255 result = STATE_WARNING;
256 }
231 257
232 /* Put some HTML in here to create a dynamic link */ 258 /* Put some HTML in here to create a dynamic link */
233 printf(_("REAL %s - %d second response time\n"), state_text(result), (int)(end_time - start_time)); 259 printf(_("REAL %s - %d second response time\n"), state_text(result), (int)(end_time - start_time));
234 } else 260 } else {
235 printf("%s\n", status_line); 261 printf("%s\n", status_line);
262 }
236 263
237 /* close the connection */ 264 /* close the connection */
238 close(socket); 265 close(socket);
@@ -240,11 +267,11 @@ int main(int argc, char **argv) {
240 /* reset the alarm */ 267 /* reset the alarm */
241 alarm(0); 268 alarm(0);
242 269
243 return result; 270 exit(result);
244} 271}
245 272
246/* process command-line arguments */ 273/* process command-line arguments */
247int process_arguments(int argc, char **argv) { 274check_real_config_wrapper process_arguments(int argc, char **argv) {
248 static struct option longopts[] = {{"hostname", required_argument, 0, 'H'}, {"IPaddress", required_argument, 0, 'I'}, 275 static struct option longopts[] = {{"hostname", required_argument, 0, 'H'}, {"IPaddress", required_argument, 0, 'I'},
249 {"expect", required_argument, 0, 'e'}, {"url", required_argument, 0, 'u'}, 276 {"expect", required_argument, 0, 'e'}, {"url", required_argument, 0, 'u'},
250 {"port", required_argument, 0, 'p'}, {"critical", required_argument, 0, 'c'}, 277 {"port", required_argument, 0, 'p'}, {"critical", required_argument, 0, 'c'},
@@ -252,61 +279,70 @@ int process_arguments(int argc, char **argv) {
252 {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, 279 {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'},
253 {"help", no_argument, 0, 'h'}, {0, 0, 0, 0}}; 280 {"help", no_argument, 0, 'h'}, {0, 0, 0, 0}};
254 281
255 if (argc < 2) 282 check_real_config_wrapper result = {
256 return ERROR; 283 .errorcode = OK,
284 .config = check_real_config_init(),
285 };
286
287 if (argc < 2) {
288 result.errorcode = ERROR;
289 return result;
290 }
257 291
258 for (int i = 1; i < argc; i++) { 292 for (int i = 1; i < argc; i++) {
259 if (strcmp("-to", argv[i]) == 0) 293 if (strcmp("-to", argv[i]) == 0) {
260 strcpy(argv[i], "-t"); 294 strcpy(argv[i], "-t");
261 else if (strcmp("-wt", argv[i]) == 0) 295 } else if (strcmp("-wt", argv[i]) == 0) {
262 strcpy(argv[i], "-w"); 296 strcpy(argv[i], "-w");
263 else if (strcmp("-ct", argv[i]) == 0) 297 } else if (strcmp("-ct", argv[i]) == 0) {
264 strcpy(argv[i], "-c"); 298 strcpy(argv[i], "-c");
299 }
265 } 300 }
266 301
267 int option_char;
268 while (true) { 302 while (true) {
269 int option = 0; 303 int option = 0;
270 option_char = getopt_long(argc, argv, "+hvVI:H:e:u:p:w:c:t:", longopts, &option); 304 int option_char = getopt_long(argc, argv, "+hvVI:H:e:u:p:w:c:t:", longopts, &option);
271 305
272 if (option_char == -1 || option_char == EOF) 306 if (option_char == -1 || option_char == EOF) {
273 break; 307 break;
308 }
274 309
275 switch (option_char) { 310 switch (option_char) {
276 case 'I': /* hostname */ 311 case 'I': /* hostname */
277 case 'H': /* hostname */ 312 case 'H': /* hostname */
278 if (server_address) 313 if (result.config.server_address) {
279 break; 314 break;
280 else if (is_host(optarg)) 315 } else if (is_host(optarg)) {
281 server_address = optarg; 316 result.config.server_address = optarg;
282 else 317 } else {
283 usage2(_("Invalid hostname/address"), optarg); 318 usage2(_("Invalid hostname/address"), optarg);
319 }
284 break; 320 break;
285 case 'e': /* string to expect in response header */ 321 case 'e': /* string to expect in response header */
286 server_expect = optarg; 322 result.config.server_expect = optarg;
287 break; 323 break;
288 case 'u': /* server URL */ 324 case 'u': /* server URL */
289 server_url = optarg; 325 result.config.server_url = optarg;
290 break; 326 break;
291 case 'p': /* port */ 327 case 'p': /* port */
292 if (is_intpos(optarg)) { 328 if (is_intpos(optarg)) {
293 server_port = atoi(optarg); 329 result.config.server_port = atoi(optarg);
294 } else { 330 } else {
295 usage4(_("Port must be a positive integer")); 331 usage4(_("Port must be a positive integer"));
296 } 332 }
297 break; 333 break;
298 case 'w': /* warning time threshold */ 334 case 'w': /* warning time threshold */
299 if (is_intnonneg(optarg)) { 335 if (is_intnonneg(optarg)) {
300 warning_time = atoi(optarg); 336 result.config.warning_time = atoi(optarg);
301 check_warning_time = true; 337 result.config.check_warning_time = true;
302 } else { 338 } else {
303 usage4(_("Warning time must be a positive integer")); 339 usage4(_("Warning time must be a positive integer"));
304 } 340 }
305 break; 341 break;
306 case 'c': /* critical time threshold */ 342 case 'c': /* critical time threshold */
307 if (is_intnonneg(optarg)) { 343 if (is_intnonneg(optarg)) {
308 critical_time = atoi(optarg); 344 result.config.critical_time = atoi(optarg);
309 check_critical_time = true; 345 result.config.check_critical_time = true;
310 } else { 346 } else {
311 usage4(_("Critical time must be a positive integer")); 347 usage4(_("Critical time must be a positive integer"));
312 } 348 }
@@ -332,25 +368,28 @@ int process_arguments(int argc, char **argv) {
332 } 368 }
333 } 369 }
334 370
335 option_char = optind; 371 int option_char = optind;
336 if (server_address == NULL && argc > option_char) { 372 if (result.config.server_address == NULL && argc > option_char) {
337 if (is_host(argv[option_char])) { 373 if (is_host(argv[option_char])) {
338 server_address = argv[option_char++]; 374 result.config.server_address = argv[option_char++];
339 } else { 375 } else {
340 usage2(_("Invalid hostname/address"), argv[option_char]); 376 usage2(_("Invalid hostname/address"), argv[option_char]);
341 } 377 }
342 } 378 }
343 379
344 if (server_address == NULL) 380 if (result.config.server_address == NULL) {
345 usage4(_("You must provide a server to check")); 381 usage4(_("You must provide a server to check"));
382 }
346 383
347 if (host_name == NULL) 384 if (result.config.host_name == NULL) {
348 host_name = strdup(server_address); 385 result.config.host_name = strdup(result.config.server_address);
386 }
349 387
350 if (server_expect == NULL) 388 if (result.config.server_expect == NULL) {
351 server_expect = strdup(EXPECT); 389 result.config.server_expect = strdup(EXPECT);
390 }
352 391
353 return OK; 392 return result;
354} 393}
355 394
356void print_help(void) { 395void print_help(void) {
diff --git a/plugins/check_real.d/config.h b/plugins/check_real.d/config.h
new file mode 100644
index 00000000..c4663cf9
--- /dev/null
+++ b/plugins/check_real.d/config.h
@@ -0,0 +1,37 @@
1#pragma once
2
3#include "../../config.h"
4#include <stddef.h>
5
6enum {
7 PORT = 554
8};
9
10typedef struct {
11 char *server_address;
12 char *host_name;
13 int server_port;
14 char *server_url;
15
16 char *server_expect;
17 int warning_time;
18 bool check_warning_time;
19 int critical_time;
20 bool check_critical_time;
21} check_real_config;
22
23check_real_config check_real_config_init() {
24 check_real_config tmp = {
25 .server_address = NULL,
26 .host_name = NULL,
27 .server_port = PORT,
28 .server_url = NULL,
29
30 .server_expect = NULL,
31 .warning_time = 0,
32 .check_warning_time = false,
33 .critical_time = 0,
34 .check_critical_time = false,
35 };
36 return tmp;
37}
diff --git a/plugins/check_tcp.c b/plugins/check_tcp.c
index 49ad096c..22dcc74e 100644
--- a/plugins/check_tcp.c
+++ b/plugins/check_tcp.c
@@ -3,7 +3,7 @@
3 * Monitoring check_tcp plugin 3 * Monitoring check_tcp plugin
4 * 4 *
5 * License: GPL 5 * License: GPL
6 * Copyright (c) 1999-2024 Monitoring Plugins Development Team 6 * Copyright (c) 1999-2025 Monitoring Plugins Development Team
7 * 7 *
8 * Description: 8 * Description:
9 * 9 *
@@ -29,74 +29,63 @@
29 29
30/* progname "check_tcp" changes depending on symlink called */ 30/* progname "check_tcp" changes depending on symlink called */
31char *progname; 31char *progname;
32const char *copyright = "1999-2024"; 32const char *copyright = "1999-2025";
33const char *email = "devel@monitoring-plugins.org"; 33const char *email = "devel@monitoring-plugins.org";
34 34
35#include "common.h" 35#include "./common.h"
36#include "netutils.h" 36#include "./netutils.h"
37#include "utils.h" 37#include "./utils.h"
38#include "utils_tcp.h" 38#include "./check_tcp.d/config.h"
39#include "output.h"
40#include "states.h"
39 41
42#include <sys/types.h>
40#include <ctype.h> 43#include <ctype.h>
41#include <sys/select.h> 44#include <sys/select.h>
42 45
46ssize_t my_recv(int socket_descriptor, char *buf, size_t len, bool use_tls) {
43#ifdef HAVE_SSL 47#ifdef HAVE_SSL
44static bool check_cert = false; 48 if (use_tls) {
45static int days_till_exp_warn, days_till_exp_crit; 49 return np_net_ssl_read(buf, (int)len);
46# define my_recv(buf, len) ((flags & FLAG_SSL) ? np_net_ssl_read(buf, len) : read(sd, buf, len)) 50 }
47# define my_send(buf, len) ((flags & FLAG_SSL) ? np_net_ssl_write(buf, len) : send(sd, buf, len, 0))
48#else
49# define my_recv(buf, len) read(sd, buf, len)
50# define my_send(buf, len) send(sd, buf, len, 0)
51#endif 51#endif
52 return read(socket_descriptor, buf, len);
53}
52 54
53/* int my_recv(char *, size_t); */ 55ssize_t my_send(int socket_descriptor, char *buf, size_t len, bool use_tls) {
54static int process_arguments(int /*argc*/, char ** /*argv*/); 56#ifdef HAVE_SSL
55static void print_help(void); 57 if (use_tls) {
58 return np_net_ssl_write(buf, (int)len);
59 }
60#endif
61 return write(socket_descriptor, buf, len);
62}
63
64typedef struct {
65 int errorcode;
66 check_tcp_config config;
67} check_tcp_config_wrapper;
68static check_tcp_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/, check_tcp_config /*config*/);
69void print_help(const char *service);
56void print_usage(void); 70void print_usage(void);
57 71
58#define EXPECT server_expect[0] 72int verbosity = 0;
59static char *SERVICE = "TCP";
60static char *SEND = NULL;
61static char *QUIT = NULL;
62static int PROTOCOL = IPPROTO_TCP; /* most common is default */
63static int PORT = 0;
64static int READ_TIMEOUT = 2;
65
66static int server_port = 0;
67static char *server_address = NULL;
68static bool host_specified = false;
69static char *server_send = NULL;
70static char *server_quit = NULL;
71static char **server_expect;
72static size_t server_expect_count = 0;
73static ssize_t maxbytes = 0;
74static char **warn_codes = NULL;
75static size_t warn_codes_count = 0;
76static char **crit_codes = NULL;
77static size_t crit_codes_count = 0;
78static unsigned int delay = 0;
79static double warning_time = 0;
80static double critical_time = 0;
81static double elapsed_time = 0;
82static long microsec;
83static int sd = 0;
84#define MAXBUF 1024
85static char buffer[MAXBUF];
86static int expect_mismatch_state = STATE_WARNING;
87static int match_flags = NP_MATCH_EXACT;
88 73
89#ifdef HAVE_SSL 74static const int READ_TIMEOUT = 2;
90static char *sni = NULL;
91static bool sni_specified = false;
92#endif
93 75
94#define FLAG_SSL 0x01 76const int MAXBUF = 1024;
95#define FLAG_VERBOSE 0x02 77
96#define FLAG_TIME_WARN 0x04 78const int DEFAULT_FTP_PORT = 21;
97#define FLAG_TIME_CRIT 0x08 79const int DEFAULT_POP_PORT = 110;
98#define FLAG_HIDE_OUTPUT 0x10 80const int DEFAULT_SPOP_PORT = 995;
99static size_t flags; 81const int DEFAULT_SMTP_PORT = 25;
82const int DEFAULT_SSMTP_PORT = 465;
83const int DEFAULT_IMAP_PORT = 143;
84const int DEFAULT_SIMAP_PORT = 993;
85const int DEFAULT_XMPP_C2S_PORT = 5222;
86const int DEFAULT_NNTP_PORT = 119;
87const int DEFAULT_NNTPS_PORT = 563;
88const int DEFAULT_CLAMD_PORT = 3310;
100 89
101int main(int argc, char **argv) { 90int main(int argc, char **argv) {
102 setlocale(LC_ALL, ""); 91 setlocale(LC_ALL, "");
@@ -105,277 +94,377 @@ int main(int argc, char **argv) {
105 94
106 /* determine program- and service-name quickly */ 95 /* determine program- and service-name quickly */
107 progname = strrchr(argv[0], '/'); 96 progname = strrchr(argv[0], '/');
108 if (progname != NULL) 97 if (progname != NULL) {
109 progname++; 98 progname++;
110 else 99 } else {
111 progname = argv[0]; 100 progname = argv[0];
101 }
102
103 // Initialize config here with values from above,
104 // might be changed by on disk config or cli commands
105 check_tcp_config config = check_tcp_config_init();
112 106
113 size_t prog_name_len = strlen(progname); 107 size_t prog_name_len = strlen(progname);
114 if (prog_name_len > 6 && !memcmp(progname, "check_", 6)) { 108 const size_t prefix_length = strlen("check_");
115 SERVICE = strdup(progname + 6); 109
116 for (size_t i = 0; i < prog_name_len - 6; i++) 110 if (prog_name_len <= prefix_length) {
117 SERVICE[i] = toupper(SERVICE[i]); 111 die(STATE_UNKNOWN, _("Weird progname"));
112 }
113
114 if (!memcmp(progname, "check_", prefix_length)) {
115 config.service = strdup(progname + prefix_length);
116 if (config.service == NULL) {
117 die(STATE_UNKNOWN, _("Allocation failed"));
118 }
119
120 for (size_t i = 0; i < prog_name_len - prefix_length; i++) {
121 config.service[i] = toupper(config.service[i]);
122 }
118 } 123 }
119 124
120 /* set up a reasonable buffer at first (will be realloc()'ed if 125 /* set up a reasonable buffer at first (will be realloc()'ed if
121 * user specifies other options) */ 126 * user specifies other options) */
122 server_expect = calloc(2, sizeof(char *)); 127 config.server_expect = calloc(2, sizeof(char *));
128
129 if (config.server_expect == NULL) {
130 die(STATE_UNKNOWN, _("Allocation failed"));
131 }
123 132
124 /* determine defaults for this service's protocol */ 133 /* determine defaults for this service's protocol */
125 if (!strncmp(SERVICE, "UDP", 3)) { 134 if (!strncmp(config.service, "UDP", strlen("UDP"))) {
126 PROTOCOL = IPPROTO_UDP; 135 config.protocol = IPPROTO_UDP;
127 } else if (!strncmp(SERVICE, "FTP", 3)) { 136 } else if (!strncmp(config.service, "FTP", strlen("FTP"))) {
128 EXPECT = "220"; 137 config.server_expect[0] = "220";
129 QUIT = "QUIT\r\n"; 138 config.quit = "QUIT\r\n";
130 PORT = 21; 139 config.server_port = DEFAULT_FTP_PORT;
131 } else if (!strncmp(SERVICE, "POP", 3) || !strncmp(SERVICE, "POP3", 4)) { 140 } else if (!strncmp(config.service, "POP", strlen("POP")) || !strncmp(config.service, "POP3", strlen("POP3"))) {
132 EXPECT = "+OK"; 141 config.server_expect[0] = "+OK";
133 QUIT = "QUIT\r\n"; 142 config.quit = "QUIT\r\n";
134 PORT = 110; 143 config.server_port = DEFAULT_POP_PORT;
135 } else if (!strncmp(SERVICE, "SMTP", 4)) { 144 } else if (!strncmp(config.service, "SMTP", strlen("SMTP"))) {
136 EXPECT = "220"; 145 config.server_expect[0] = "220";
137 QUIT = "QUIT\r\n"; 146 config.quit = "QUIT\r\n";
138 PORT = 25; 147 config.server_port = DEFAULT_SMTP_PORT;
139 } else if (!strncmp(SERVICE, "IMAP", 4)) { 148 } else if (!strncmp(config.service, "IMAP", strlen("IMAP"))) {
140 EXPECT = "* OK"; 149 config.server_expect[0] = "* OK";
141 QUIT = "a1 LOGOUT\r\n"; 150 config.quit = "a1 LOGOUT\r\n";
142 PORT = 143; 151 config.server_port = DEFAULT_IMAP_PORT;
143 } 152 }
144#ifdef HAVE_SSL 153#ifdef HAVE_SSL
145 else if (!strncmp(SERVICE, "SIMAP", 5)) { 154 else if (!strncmp(config.service, "SIMAP", strlen("SIMAP"))) {
146 EXPECT = "* OK"; 155 config.server_expect[0] = "* OK";
147 QUIT = "a1 LOGOUT\r\n"; 156 config.quit = "a1 LOGOUT\r\n";
148 flags |= FLAG_SSL; 157 config.use_tls = true;
149 PORT = 993; 158 config.server_port = DEFAULT_SIMAP_PORT;
150 } else if (!strncmp(SERVICE, "SPOP", 4)) { 159 } else if (!strncmp(config.service, "SPOP", strlen("SPOP"))) {
151 EXPECT = "+OK"; 160 config.server_expect[0] = "+OK";
152 QUIT = "QUIT\r\n"; 161 config.quit = "QUIT\r\n";
153 flags |= FLAG_SSL; 162 config.use_tls = true;
154 PORT = 995; 163 config.server_port = DEFAULT_SPOP_PORT;
155 } else if (!strncmp(SERVICE, "SSMTP", 5)) { 164 } else if (!strncmp(config.service, "SSMTP", strlen("SSMTP"))) {
156 EXPECT = "220"; 165 config.server_expect[0] = "220";
157 QUIT = "QUIT\r\n"; 166 config.quit = "QUIT\r\n";
158 flags |= FLAG_SSL; 167 config.use_tls = true;
159 PORT = 465; 168 config.server_port = DEFAULT_SSMTP_PORT;
160 } else if (!strncmp(SERVICE, "JABBER", 6)) { 169 } else if (!strncmp(config.service, "JABBER", strlen("JABBER"))) {
161 SEND = "<stream:stream to=\'host\' xmlns=\'jabber:client\' xmlns:stream=\'http://etherx.jabber.org/streams\'>\n"; 170 config.send = "<stream:stream to=\'host\' xmlns=\'jabber:client\' xmlns:stream=\'http://etherx.jabber.org/streams\'>\n";
162 EXPECT = "<?xml version=\'1.0\'"; 171 config.server_expect[0] = "<?xml version=\'1.0\'";
163 QUIT = "</stream:stream>\n"; 172 config.quit = "</stream:stream>\n";
164 flags |= FLAG_HIDE_OUTPUT; 173 config.hide_output = true;
165 PORT = 5222; 174 config.server_port = DEFAULT_XMPP_C2S_PORT;
166 } else if (!strncmp(SERVICE, "NNTPS", 5)) { 175 } else if (!strncmp(config.service, "NNTPS", strlen("NNTPS"))) {
167 server_expect_count = 2; 176 config.server_expect_count = 2;
168 server_expect[0] = "200"; 177 config.server_expect[0] = "200";
169 server_expect[1] = "201"; 178 config.server_expect[1] = "201";
170 QUIT = "QUIT\r\n"; 179 config.quit = "QUIT\r\n";
171 flags |= FLAG_SSL; 180 config.use_tls = true;
172 PORT = 563; 181 config.server_port = DEFAULT_NNTPS_PORT;
173 } 182 }
174#endif 183#endif
175 else if (!strncmp(SERVICE, "NNTP", 4)) { 184 else if (!strncmp(config.service, "NNTP", strlen("NNTP"))) {
176 server_expect_count = 2; 185 config.server_expect_count = 2;
177 server_expect = malloc(sizeof(char *) * server_expect_count); 186 char **tmp = realloc(config.server_expect, config.server_expect_count * sizeof(char *));
178 server_expect[0] = strdup("200"); 187 if (tmp == NULL) {
179 server_expect[1] = strdup("201"); 188 free(config.server_expect);
180 QUIT = "QUIT\r\n"; 189 die(STATE_UNKNOWN, _("Allocation failed"));
181 PORT = 119; 190 }
182 } else if (!strncmp(SERVICE, "CLAMD", 5)) { 191 config.server_expect = tmp;
183 SEND = "PING"; 192
184 EXPECT = "PONG"; 193 config.server_expect[0] = strdup("200");
185 QUIT = NULL; 194 config.server_expect[1] = strdup("201");
186 PORT = 3310; 195 config.quit = "QUIT\r\n";
196 config.server_port = DEFAULT_NNTP_PORT;
197 } else if (!strncmp(config.service, "CLAMD", strlen("CLAMD"))) {
198 config.send = "PING";
199 config.server_expect[0] = "PONG";
200 config.quit = NULL;
201 config.server_port = DEFAULT_CLAMD_PORT;
187 } 202 }
188 /* fallthrough check, so it's supposed to use reverse matching */ 203 /* fallthrough check, so it's supposed to use reverse matching */
189 else if (strcmp(SERVICE, "TCP")) 204 else if (strcmp(config.service, "TCP")) {
190 usage(_("CRITICAL - Generic check_tcp called with unknown service\n")); 205 usage(_("CRITICAL - Generic check_tcp called with unknown service\n"));
191 206 }
192 server_address = "127.0.0.1";
193 server_port = PORT;
194 server_send = SEND;
195 server_quit = QUIT;
196 char *status = NULL;
197 207
198 /* Parse extra opts if any */ 208 /* Parse extra opts if any */
199 argv = np_extra_opts(&argc, argv, progname); 209 argv = np_extra_opts(&argc, argv, progname);
200 210
201 if (process_arguments(argc, argv) == ERROR) 211 check_tcp_config_wrapper paw = process_arguments(argc, argv, config);
212 if (paw.errorcode == ERROR) {
202 usage4(_("Could not parse arguments")); 213 usage4(_("Could not parse arguments"));
214 }
203 215
204 if (flags & FLAG_VERBOSE) { 216 config = paw.config;
205 printf("Using service %s\n", SERVICE); 217
206 printf("Port: %d\n", server_port); 218 if (verbosity > 0) {
207 printf("flags: 0x%x\n", (int)flags); 219 printf("Using service %s\n", config.service);
220 printf("Port: %d\n", config.server_port);
208 } 221 }
209 222
210 if (EXPECT && !server_expect_count) 223 if ((config.server_expect_count == 0) && config.server_expect[0]) {
211 server_expect_count++; 224 config.server_expect_count++;
225 }
212 226
213 if (PROTOCOL == IPPROTO_UDP && !(server_expect_count && server_send)) { 227 if (config.protocol == IPPROTO_UDP && !(config.server_expect_count && config.send)) {
214 usage(_("With UDP checks, a send/expect string must be specified.")); 228 usage(_("With UDP checks, a send/expect string must be specified."));
215 } 229 }
216 230
231 // Initialize check stuff before setting timers
232 mp_check overall = mp_check_init();
233 if (config.output_format_set) {
234 mp_set_format(config.output_format);
235 }
236
217 /* set up the timer */ 237 /* set up the timer */
218 signal(SIGALRM, socket_timeout_alarm_handler); 238 signal(SIGALRM, socket_timeout_alarm_handler);
219 alarm(socket_timeout); 239 alarm(socket_timeout);
220 240
221 /* try to connect to the host at the given port number */ 241 /* try to connect to the host at the given port number */
222 struct timeval tv; 242 struct timeval start_time;
223 gettimeofday(&tv, NULL); 243 gettimeofday(&start_time, NULL);
224 244
225 int result = STATE_UNKNOWN; 245 int socket_descriptor = 0;
226 result = np_net_connect(server_address, server_port, &sd, PROTOCOL); 246 mp_subcheck inital_connect_result = mp_subcheck_init();
227 if (result == STATE_CRITICAL) 247
228 return econn_refuse_state; 248 // Try initial connection
249 if (np_net_connect(config.server_address, config.server_port, &socket_descriptor, config.protocol) == STATE_CRITICAL) {
250 // Early exit here, we got connection refused
251 inital_connect_result = mp_set_subcheck_state(inital_connect_result, config.econn_refuse_state);
252 xasprintf(&inital_connect_result.output, "Connection to %s on port %i was REFUSED", config.server_address, config.server_port);
253 mp_add_subcheck_to_check(&overall, inital_connect_result);
254 mp_exit(overall);
255 } else {
256 inital_connect_result = mp_set_subcheck_state(inital_connect_result, STATE_OK);
257 xasprintf(&inital_connect_result.output, "Connection to %s on port %i was a SUCCESS", config.server_address, config.server_port);
258 mp_add_subcheck_to_check(&overall, inital_connect_result);
259 }
229 260
230#ifdef HAVE_SSL 261#ifdef HAVE_SSL
231 if (flags & FLAG_SSL) { 262 if (config.use_tls) {
232 result = np_net_ssl_init_with_hostname(sd, (sni_specified ? sni : NULL)); 263 mp_subcheck tls_connection_result = mp_subcheck_init();
233 if (result == STATE_OK && check_cert) { 264 mp_state_enum result = np_net_ssl_init_with_hostname(socket_descriptor, (config.sni_specified ? config.sni : NULL));
234 result = np_net_ssl_check_cert(days_till_exp_warn, days_till_exp_crit); 265 tls_connection_result = mp_set_subcheck_default_state(tls_connection_result, result);
266
267 if (result == STATE_OK) {
268 xasprintf(&tls_connection_result.output, "TLS connection succeeded");
269
270 if (config.check_cert) {
271 result = np_net_ssl_check_cert(config.days_till_exp_warn, config.days_till_exp_crit);
272
273 mp_subcheck tls_certificate_lifetime_result = mp_subcheck_init();
274 tls_certificate_lifetime_result = mp_set_subcheck_state(tls_certificate_lifetime_result, result);
275
276 if (result == STATE_OK) {
277 xasprintf(&tls_certificate_lifetime_result.output, "Certificate lifetime is within thresholds");
278 } else if (result == STATE_WARNING) {
279 xasprintf(&tls_certificate_lifetime_result.output, "Certificate lifetime is violating warning threshold (%i)",
280 config.days_till_exp_warn);
281 } else if (result == STATE_CRITICAL) {
282 xasprintf(&tls_certificate_lifetime_result.output, "Certificate lifetime is violating critical threshold (%i)",
283 config.days_till_exp_crit);
284 } else {
285 xasprintf(&tls_certificate_lifetime_result.output, "Certificate lifetime is somehow unknown");
286 }
287
288 mp_add_subcheck_to_subcheck(&tls_connection_result, tls_certificate_lifetime_result);
289 }
290
291 mp_add_subcheck_to_check(&overall, tls_connection_result);
292 } else {
293 xasprintf(&tls_connection_result.output, "TLS connection failed");
294 mp_add_subcheck_to_check(&overall, tls_connection_result);
295
296 if (socket_descriptor) {
297 close(socket_descriptor);
298 }
299 np_net_ssl_cleanup();
300
301 mp_exit(overall);
235 } 302 }
236 } 303 }
237 if (result != STATE_OK) {
238 if (sd)
239 close(sd);
240 np_net_ssl_cleanup();
241 return result;
242 }
243#endif /* HAVE_SSL */ 304#endif /* HAVE_SSL */
244 305
245 if (server_send != NULL) { /* Something to send? */ 306 if (config.send != NULL) { /* Something to send? */
246 my_send(server_send, strlen(server_send)); 307 my_send(socket_descriptor, config.send, strlen(config.send), config.use_tls);
247 } 308 }
248 309
249 if (delay > 0) { 310 if (config.delay > 0) {
250 tv.tv_sec += delay; 311 start_time.tv_sec += config.delay;
251 sleep(delay); 312 sleep(config.delay);
252 } 313 }
253 314
254 if (flags & FLAG_VERBOSE) { 315 if (verbosity > 0) {
255 if (server_send) { 316 if (config.send) {
256 printf("Send string: %s\n", server_send); 317 printf("Send string: %s\n", config.send);
318 }
319 if (config.quit) {
320 printf("Quit string: %s\n", config.quit);
257 } 321 }
258 if (server_quit) { 322 printf("server_expect_count: %d\n", (int)config.server_expect_count);
259 printf("Quit string: %s\n", server_quit); 323 for (size_t i = 0; i < config.server_expect_count; i++) {
324 printf("\t%zd: %s\n", i, config.server_expect[i]);
260 } 325 }
261 printf("server_expect_count: %d\n", (int)server_expect_count);
262 for (size_t i = 0; i < server_expect_count; i++)
263 printf("\t%zd: %s\n", i, server_expect[i]);
264 } 326 }
265 327
266 /* if(len) later on, we know we have a non-NULL response */ 328 /* if(len) later on, we know we have a non-NULL response */
267 ssize_t len = 0; 329 ssize_t len = 0;
330 char *received_buffer = NULL;
331 enum np_match_result match = NP_MATCH_NONE;
332 mp_subcheck expected_data_result = mp_subcheck_init();
268 333
269 int match = -1; 334 if (config.server_expect_count) {
270 struct timeval timeout;
271 fd_set rfds;
272 FD_ZERO(&rfds);
273 if (server_expect_count) {
274 ssize_t received = 0; 335 ssize_t received = 0;
336 char buffer[MAXBUF];
275 337
276 /* watch for the expect string */ 338 /* watch for the expect string */
277 while ((received = my_recv(buffer, sizeof(buffer))) > 0) { 339 while ((received = my_recv(socket_descriptor, buffer, sizeof(buffer), config.use_tls)) > 0) {
278 status = realloc(status, len + received + 1); 340 received_buffer = realloc(received_buffer, len + received + 1);
279 memcpy(&status[len], buffer, received); 341
342 if (received_buffer == NULL) {
343 die(STATE_UNKNOWN, _("Allocation failed"));
344 }
345
346 memcpy(&received_buffer[len], buffer, received);
280 len += received; 347 len += received;
281 status[len] = '\0'; 348 received_buffer[len] = '\0';
282 349
283 /* stop reading if user-forced */ 350 /* stop reading if user-forced */
284 if (maxbytes && len >= maxbytes) 351 if (config.maxbytes && len >= config.maxbytes) {
285 break; 352 break;
353 }
286 354
287 if ((match = np_expect_match(status, server_expect, server_expect_count, match_flags)) != NP_MATCH_RETRY) 355 if ((match = np_expect_match(received_buffer, config.server_expect, config.server_expect_count, config.match_flags)) !=
356 NP_MATCH_RETRY) {
288 break; 357 break;
358 }
359
360 fd_set rfds;
361 FD_ZERO(&rfds);
362 FD_SET(socket_descriptor, &rfds);
289 363
290 /* some protocols wait for further input, so make sure we don't wait forever */ 364 /* some protocols wait for further input, so make sure we don't wait forever */
291 FD_SET(sd, &rfds); 365 struct timeval timeout;
292 timeout.tv_sec = READ_TIMEOUT; 366 timeout.tv_sec = READ_TIMEOUT;
293 timeout.tv_usec = 0; 367 timeout.tv_usec = 0;
294 if (select(sd + 1, &rfds, NULL, NULL, &timeout) <= 0) 368
369 if (select(socket_descriptor + 1, &rfds, NULL, NULL, &timeout) <= 0) {
295 break; 370 break;
371 }
296 } 372 }
297 373
298 if (match == NP_MATCH_RETRY) 374 if (match == NP_MATCH_RETRY) {
299 match = NP_MATCH_FAILURE; 375 match = NP_MATCH_FAILURE;
376 }
300 377
301 /* no data when expected, so return critical */ 378 /* no data when expected, so return critical */
302 if (len == 0) 379 if (len == 0) {
303 die(STATE_CRITICAL, _("No data received from host\n")); 380 xasprintf(&expected_data_result.output, "Received no data when some was expected");
381 expected_data_result = mp_set_subcheck_state(expected_data_result, STATE_CRITICAL);
382 mp_add_subcheck_to_check(&overall, expected_data_result);
383 mp_exit(overall);
384 }
304 385
305 /* print raw output if we're debugging */ 386 /* print raw output if we're debugging */
306 if (flags & FLAG_VERBOSE) 387 if (verbosity > 0) {
307 printf("received %d bytes from host\n#-raw-recv-------#\n%s\n#-raw-recv-------#\n", (int)len + 1, status); 388 printf("received %d bytes from host\n#-raw-recv-------#\n%s\n#-raw-recv-------#\n", (int)len + 1, received_buffer);
389 }
308 /* strip whitespace from end of output */ 390 /* strip whitespace from end of output */
309 while (--len > 0 && isspace(status[len])) 391 while (--len > 0 && isspace(received_buffer[len])) {
310 status[len] = '\0'; 392 received_buffer[len] = '\0';
393 }
311 } 394 }
312 395
313 if (server_quit != NULL) { 396 if (config.quit != NULL) {
314 my_send(server_quit, strlen(server_quit)); 397 my_send(socket_descriptor, config.quit, strlen(config.quit), config.use_tls);
398 }
399
400 if (socket_descriptor) {
401 close(socket_descriptor);
315 } 402 }
316 if (sd)
317 close(sd);
318#ifdef HAVE_SSL 403#ifdef HAVE_SSL
319 np_net_ssl_cleanup(); 404 np_net_ssl_cleanup();
320#endif 405#endif
321 406
322 microsec = deltime(tv); 407 long microsec = deltime(start_time);
323 elapsed_time = (double)microsec / 1.0e6; 408 double elapsed_time = (double)microsec / 1.0e6;
324 409
325 if (flags & FLAG_TIME_CRIT && elapsed_time > critical_time) 410 mp_subcheck elapsed_time_result = mp_subcheck_init();
326 result = STATE_CRITICAL;
327 else if (flags & FLAG_TIME_WARN && elapsed_time > warning_time)
328 result = STATE_WARNING;
329 411
330 /* did we get the response we hoped? */ 412 mp_perfdata time_pd = perfdata_init();
331 if (match == NP_MATCH_FAILURE && result != STATE_CRITICAL) 413 time_pd = mp_set_pd_value(time_pd, elapsed_time);
332 result = expect_mismatch_state; 414 time_pd.label = "time";
415 time_pd.uom = "s";
333 416
334 /* reset the alarm */ 417 if (config.critical_time_set && elapsed_time > config.critical_time) {
335 alarm(0); 418 xasprintf(&elapsed_time_result.output, "Connection time %fs exceeded critical threshold (%f)", elapsed_time, config.critical_time);
419
420 elapsed_time_result = mp_set_subcheck_state(elapsed_time_result, STATE_CRITICAL);
421 time_pd.crit_present = true;
422 mp_range crit_val = mp_range_init();
423
424 crit_val.end = mp_create_pd_value(config.critical_time);
425 crit_val.end_infinity = false;
336 426
337 /* this is a bit stupid, because we don't want to print the 427 time_pd.crit = crit_val;
338 * response time (which can look ok to the user) if we didn't get 428 } else if (config.warning_time_set && elapsed_time > config.warning_time) {
339 * the response we were looking for. if-else */ 429 xasprintf(&elapsed_time_result.output, "Connection time %fs exceeded warning threshold (%f)", elapsed_time, config.critical_time);
340 printf("%s %s - ", SERVICE, state_text(result)); 430
341 431 elapsed_time_result = mp_set_subcheck_state(elapsed_time_result, STATE_WARNING);
342 if (match == NP_MATCH_FAILURE && len && !(flags & FLAG_HIDE_OUTPUT)) 432 time_pd.warn_present = true;
343 printf("Unexpected response from host/socket: %s", status); 433 mp_range warn_val = mp_range_init();
344 else { 434 warn_val.end = mp_create_pd_value(config.critical_time);
345 if (match == NP_MATCH_FAILURE) 435 warn_val.end_infinity = false;
346 printf("Unexpected response from host/socket on "); 436
347 else 437 time_pd.warn = warn_val;
348 printf("%.3f second response time on ", elapsed_time); 438 } else {
349 if (server_address[0] != '/') { 439 elapsed_time_result = mp_set_subcheck_state(elapsed_time_result, STATE_OK);
350 if (host_specified) 440 xasprintf(&elapsed_time_result.output, "Connection time %fs is within thresholds", elapsed_time);
351 printf("%s port %d", server_address, server_port);
352 else
353 printf("port %d", server_port);
354 } else
355 printf("socket %s", server_address);
356 } 441 }
357 442
358 if (match != NP_MATCH_FAILURE && !(flags & FLAG_HIDE_OUTPUT) && len) 443 mp_add_perfdata_to_subcheck(&elapsed_time_result, time_pd);
359 printf(" [%s]", status); 444 mp_add_subcheck_to_check(&overall, elapsed_time_result);
360 445
361 /* perf-data doesn't apply when server doesn't talk properly, 446 /* did we get the response we hoped? */
362 * so print all zeroes on warn and crit. Use fperfdata since 447 if (match == NP_MATCH_FAILURE) {
363 * localisation settings can make different outputs */ 448 expected_data_result = mp_set_subcheck_state(expected_data_result, config.expect_mismatch_state);
364 if (match == NP_MATCH_FAILURE) 449 xasprintf(&expected_data_result.output, "Answer failed to match expectation");
365 printf("|%s", fperfdata("time", elapsed_time, "s", (flags & FLAG_TIME_WARN ? true : false), 0, 450 mp_add_subcheck_to_check(&overall, expected_data_result);
366 (flags & FLAG_TIME_CRIT ? true : false), 0, true, 0, true, socket_timeout)); 451 } else if (match == NP_MATCH_SUCCESS) {
367 else 452 expected_data_result = mp_set_subcheck_state(expected_data_result, STATE_OK);
368 printf("|%s", fperfdata("time", elapsed_time, "s", (flags & FLAG_TIME_WARN ? true : false), warning_time, 453 xasprintf(&expected_data_result.output, "The answer of the server matched the expectation");
369 (flags & FLAG_TIME_CRIT ? true : false), critical_time, true, 0, true, socket_timeout)); 454 mp_add_subcheck_to_check(&overall, expected_data_result);
455 }
370 456
371 putchar('\n'); 457 /* reset the alarm */
372 return result; 458 alarm(0);
459
460 mp_exit(overall);
373} 461}
374 462
375/* process command-line arguments */ 463/* process command-line arguments */
376static int process_arguments(int argc, char **argv) { 464static check_tcp_config_wrapper process_arguments(int argc, char **argv, check_tcp_config config) {
377 enum { 465 enum {
378 SNI_OPTION = CHAR_MAX + 1 466 SNI_OPTION = CHAR_MAX + 1,
467 output_format_index,
379 }; 468 };
380 469
381 static struct option longopts[] = {{"hostname", required_argument, 0, 'H'}, 470 static struct option longopts[] = {{"hostname", required_argument, 0, 'H'},
@@ -404,54 +493,58 @@ static int process_arguments(int argc, char **argv) {
404 {"ssl", no_argument, 0, 'S'}, 493 {"ssl", no_argument, 0, 'S'},
405 {"sni", required_argument, 0, SNI_OPTION}, 494 {"sni", required_argument, 0, SNI_OPTION},
406 {"certificate", required_argument, 0, 'D'}, 495 {"certificate", required_argument, 0, 'D'},
496 {"output-format", required_argument, 0, output_format_index},
407 {0, 0, 0, 0}}; 497 {0, 0, 0, 0}};
408 498
409 if (argc < 2) 499 if (argc < 2) {
410 usage4(_("No arguments found")); 500 usage4(_("No arguments found"));
501 }
411 502
412 /* backwards compatibility */ 503 /* backwards compatibility */
413 for (int i = 1; i < argc; i++) { 504 for (int i = 1; i < argc; i++) {
414 if (strcmp("-to", argv[i]) == 0) 505 if (strcmp("-to", argv[i]) == 0) {
415 strcpy(argv[i], "-t"); 506 strcpy(argv[i], "-t");
416 else if (strcmp("-wt", argv[i]) == 0) 507 } else if (strcmp("-wt", argv[i]) == 0) {
417 strcpy(argv[i], "-w"); 508 strcpy(argv[i], "-w");
418 else if (strcmp("-ct", argv[i]) == 0) 509 } else if (strcmp("-ct", argv[i]) == 0) {
419 strcpy(argv[i], "-c"); 510 strcpy(argv[i], "-c");
511 }
420 } 512 }
421 513
422 if (!is_option(argv[1])) { 514 if (!is_option(argv[1])) {
423 server_address = argv[1]; 515 config.server_address = argv[1];
424 argv[1] = argv[0]; 516 argv[1] = argv[0];
425 argv = &argv[1]; 517 argv = &argv[1];
426 argc--; 518 argc--;
427 } 519 }
428 520
429 int option_char;
430 bool escape = false; 521 bool escape = false;
522
431 while (true) { 523 while (true) {
432 int option = 0; 524 int option = 0;
433 option_char = getopt_long(argc, argv, "+hVv46EAH:s:e:q:m:c:w:t:p:C:W:d:Sr:jD:M:", longopts, &option); 525 int option_index = getopt_long(argc, argv, "+hVv46EAH:s:e:q:m:c:w:t:p:C:W:d:Sr:jD:M:", longopts, &option);
434 526
435 if (option_char == -1 || option_char == EOF || option_char == 1) 527 if (option_index == -1 || option_index == EOF || option_index == 1) {
436 break; 528 break;
529 }
437 530
438 switch (option_char) { 531 switch (option_index) {
439 case '?': /* print short usage statement if args not parsable */ 532 case '?': /* print short usage statement if args not parsable */
440 usage5(); 533 usage5();
441 case 'h': /* help */ 534 case 'h': /* help */
442 print_help(); 535 print_help(config.service);
443 exit(STATE_UNKNOWN); 536 exit(STATE_UNKNOWN);
444 case 'V': /* version */ 537 case 'V': /* version */
445 print_revision(progname, NP_VERSION); 538 print_revision(progname, NP_VERSION);
446 exit(STATE_UNKNOWN); 539 exit(STATE_UNKNOWN);
447 case 'v': /* verbose mode */ 540 case 'v': /* verbose mode */
448 flags |= FLAG_VERBOSE; 541 verbosity++;
449 match_flags |= NP_MATCH_VERBOSE; 542 config.match_flags |= NP_MATCH_VERBOSE;
450 break; 543 break;
451 case '4': 544 case '4': // Apparently unused TODO
452 address_family = AF_INET; 545 address_family = AF_INET;
453 break; 546 break;
454 case '6': 547 case '6': // Apparently unused TODO
455#ifdef USE_IPV6 548#ifdef USE_IPV6
456 address_family = AF_INET6; 549 address_family = AF_INET6;
457#else 550#else
@@ -459,163 +552,190 @@ static int process_arguments(int argc, char **argv) {
459#endif 552#endif
460 break; 553 break;
461 case 'H': /* hostname */ 554 case 'H': /* hostname */
462 host_specified = true; 555 config.host_specified = true;
463 server_address = optarg; 556 config.server_address = optarg;
464 break; 557 break;
465 case 'c': /* critical */ 558 case 'c': /* critical */
466 critical_time = strtod(optarg, NULL); 559 config.critical_time = strtod(optarg, NULL);
467 flags |= FLAG_TIME_CRIT; 560 config.critical_time_set = true;
468 break; 561 break;
469 case 'j': /* hide output */ 562 case 'j': /* hide output */
470 flags |= FLAG_HIDE_OUTPUT; 563 config.hide_output = true;
471 break; 564 break;
472 case 'w': /* warning */ 565 case 'w': /* warning */
473 warning_time = strtod(optarg, NULL); 566 config.warning_time = strtod(optarg, NULL);
474 flags |= FLAG_TIME_WARN; 567 config.warning_time_set = true;
475 break;
476 case 'C':
477 crit_codes = realloc(crit_codes, ++crit_codes_count);
478 crit_codes[crit_codes_count - 1] = optarg;
479 break;
480 case 'W':
481 warn_codes = realloc(warn_codes, ++warn_codes_count);
482 warn_codes[warn_codes_count - 1] = optarg;
483 break; 568 break;
484 case 't': /* timeout */ 569 case 't': /* timeout */
485 if (!is_intpos(optarg)) 570 if (!is_intpos(optarg)) {
486 usage4(_("Timeout interval must be a positive integer")); 571 usage4(_("Timeout interval must be a positive integer"));
487 else 572 } else {
488 socket_timeout = atoi(optarg); 573 socket_timeout = atoi(optarg);
574 }
489 break; 575 break;
490 case 'p': /* port */ 576 case 'p': /* port */
491 if (!is_intpos(optarg)) 577 if (!is_intpos(optarg)) {
492 usage4(_("Port must be a positive integer")); 578 usage4(_("Port must be a positive integer"));
493 else 579 } else {
494 server_port = atoi(optarg); 580 config.server_port = atoi(optarg);
581 }
495 break; 582 break;
496 case 'E': 583 case 'E':
497 escape = true; 584 escape = true;
498 break; 585 break;
499 case 's': 586 case 's':
500 if (escape) 587 if (escape) {
501 server_send = np_escaped_string(optarg); 588 config.send = np_escaped_string(optarg);
502 else 589 } else {
503 xasprintf(&server_send, "%s", optarg); 590 xasprintf(&config.send, "%s", optarg);
591 }
504 break; 592 break;
505 case 'e': /* expect string (may be repeated) */ 593 case 'e': /* expect string (may be repeated) */
506 match_flags &= ~NP_MATCH_EXACT; 594 config.match_flags &= ~NP_MATCH_EXACT;
507 if (server_expect_count == 0) 595 if (config.server_expect_count == 0) {
508 server_expect = malloc(sizeof(char *) * (++server_expect_count)); 596 config.server_expect = malloc(sizeof(char *) * (++config.server_expect_count));
509 else 597 } else {
510 server_expect = realloc(server_expect, sizeof(char *) * (++server_expect_count)); 598 config.server_expect = realloc(config.server_expect, sizeof(char *) * (++config.server_expect_count));
511 server_expect[server_expect_count - 1] = optarg; 599 }
600
601 if (config.server_expect == NULL) {
602 die(STATE_UNKNOWN, _("Allocation failed"));
603 }
604 config.server_expect[config.server_expect_count - 1] = optarg;
512 break; 605 break;
513 case 'm': 606 case 'm':
514 if (!is_intpos(optarg)) 607 if (!is_intpos(optarg)) {
515 usage4(_("Maxbytes must be a positive integer")); 608 usage4(_("Maxbytes must be a positive integer"));
516 else 609 } else {
517 maxbytes = strtol(optarg, NULL, 0); 610 config.maxbytes = strtol(optarg, NULL, 0);
611 }
518 break; 612 break;
519 case 'q': 613 case 'q':
520 if (escape) 614 if (escape) {
521 server_quit = np_escaped_string(optarg); 615 config.quit = np_escaped_string(optarg);
522 else 616 } else {
523 xasprintf(&server_quit, "%s\r\n", optarg); 617 xasprintf(&config.quit, "%s\r\n", optarg);
618 }
524 break; 619 break;
525 case 'r': 620 case 'r':
526 if (!strncmp(optarg, "ok", 2)) 621 if (!strncmp(optarg, "ok", 2)) {
527 econn_refuse_state = STATE_OK; 622 config.econn_refuse_state = STATE_OK;
528 else if (!strncmp(optarg, "warn", 4)) 623 } else if (!strncmp(optarg, "warn", 4)) {
529 econn_refuse_state = STATE_WARNING; 624 config.econn_refuse_state = STATE_WARNING;
530 else if (!strncmp(optarg, "crit", 4)) 625 } else if (!strncmp(optarg, "crit", 4)) {
531 econn_refuse_state = STATE_CRITICAL; 626 config.econn_refuse_state = STATE_CRITICAL;
532 else 627 } else {
533 usage4(_("Refuse must be one of ok, warn, crit")); 628 usage4(_("Refuse must be one of ok, warn, crit"));
629 }
534 break; 630 break;
535 case 'M': 631 case 'M':
536 if (!strncmp(optarg, "ok", 2)) 632 if (!strncmp(optarg, "ok", 2)) {
537 expect_mismatch_state = STATE_OK; 633 config.expect_mismatch_state = STATE_OK;
538 else if (!strncmp(optarg, "warn", 4)) 634 } else if (!strncmp(optarg, "warn", 4)) {
539 expect_mismatch_state = STATE_WARNING; 635 config.expect_mismatch_state = STATE_WARNING;
540 else if (!strncmp(optarg, "crit", 4)) 636 } else if (!strncmp(optarg, "crit", 4)) {
541 expect_mismatch_state = STATE_CRITICAL; 637 config.expect_mismatch_state = STATE_CRITICAL;
542 else 638 } else {
543 usage4(_("Mismatch must be one of ok, warn, crit")); 639 usage4(_("Mismatch must be one of ok, warn, crit"));
640 }
544 break; 641 break;
545 case 'd': 642 case 'd':
546 if (is_intpos(optarg)) 643 if (is_intpos(optarg)) {
547 delay = atoi(optarg); 644 config.delay = atoi(optarg);
548 else 645 } else {
549 usage4(_("Delay must be a positive integer")); 646 usage4(_("Delay must be a positive integer"));
647 }
550 break; 648 break;
551 case 'D': { /* Check SSL cert validity - days 'til certificate expiration */ 649 case 'D': /* Check SSL cert validity - days 'til certificate expiration */
552#ifdef HAVE_SSL 650#ifdef HAVE_SSL
553# ifdef USE_OPENSSL /* XXX */ 651# ifdef USE_OPENSSL /* XXX */
652 {
554 char *temp; 653 char *temp;
555 if ((temp = strchr(optarg, ',')) != NULL) { 654 if ((temp = strchr(optarg, ',')) != NULL) {
556 *temp = '\0'; 655 *temp = '\0';
557 if (!is_intnonneg(optarg)) 656 if (!is_intnonneg(optarg)) {
558 usage2(_("Invalid certificate expiration period"), optarg); 657 usage2(_("Invalid certificate expiration period"), optarg);
559 days_till_exp_warn = atoi(optarg); 658 }
659 config.days_till_exp_warn = atoi(optarg);
560 *temp = ','; 660 *temp = ',';
561 temp++; 661 temp++;
562 if (!is_intnonneg(temp)) 662 if (!is_intnonneg(temp)) {
563 usage2(_("Invalid certificate expiration period"), temp); 663 usage2(_("Invalid certificate expiration period"), temp);
564 days_till_exp_crit = atoi(temp); 664 }
665 config.days_till_exp_crit = atoi(temp);
565 } else { 666 } else {
566 days_till_exp_crit = 0; 667 config.days_till_exp_crit = 0;
567 if (!is_intnonneg(optarg)) 668 if (!is_intnonneg(optarg)) {
568 usage2(_("Invalid certificate expiration period"), optarg); 669 usage2(_("Invalid certificate expiration period"), optarg);
569 days_till_exp_warn = atoi(optarg); 670 }
671 config.days_till_exp_warn = atoi(optarg);
570 } 672 }
571 check_cert = true; 673 config.check_cert = true;
572 flags |= FLAG_SSL; 674 config.use_tls = true;
573 } break; 675 } break;
574# endif /* USE_OPENSSL */ 676# endif /* USE_OPENSSL */
575#endif 677#endif
576 /* fallthrough if we don't have ssl */ 678 /* fallthrough if we don't have ssl */
577 case 'S': 679 case 'S':
578#ifdef HAVE_SSL 680#ifdef HAVE_SSL
579 flags |= FLAG_SSL; 681 config.use_tls = true;
580#else 682#else
581 die(STATE_UNKNOWN, _("Invalid option - SSL is not available")); 683 die(STATE_UNKNOWN, _("Invalid option - SSL is not available"));
582#endif 684#endif
583 break; 685 break;
584 case SNI_OPTION: 686 case SNI_OPTION:
585#ifdef HAVE_SSL 687#ifdef HAVE_SSL
586 flags |= FLAG_SSL; 688 config.use_tls = true;
587 sni_specified = true; 689 config.sni_specified = true;
588 sni = optarg; 690 config.sni = optarg;
589#else 691#else
590 die(STATE_UNKNOWN, _("Invalid option - SSL is not available")); 692 die(STATE_UNKNOWN, _("Invalid option - SSL is not available"));
591#endif 693#endif
592 break; 694 break;
593 case 'A': 695 case 'A':
594 match_flags |= NP_MATCH_ALL; 696 config.match_flags |= NP_MATCH_ALL;
697 break;
698 case output_format_index: {
699 parsed_output_format parser = mp_parse_output_format(optarg);
700 if (!parser.parsing_success) {
701 // TODO List all available formats here, maybe add anothoer usage function
702 printf("Invalid output format: %s\n", optarg);
703 exit(STATE_UNKNOWN);
704 }
705
706 config.output_format_set = true;
707 config.output_format = parser.output_format;
595 break; 708 break;
596 } 709 }
710 }
597 } 711 }
598 712
599 option_char = optind; 713 int index = optind;
600 if (!host_specified && option_char < argc) 714 if (!config.host_specified && index < argc) {
601 server_address = strdup(argv[option_char++]); 715 config.server_address = strdup(argv[index++]);
716 }
602 717
603 if (server_address == NULL) 718 if (config.server_address == NULL) {
604 usage4(_("You must provide a server address")); 719 usage4(_("You must provide a server address"));
605 else if (server_address[0] != '/' && !is_host(server_address)) 720 } else if (config.server_address[0] != '/' && !is_host(config.server_address)) {
606 die(STATE_CRITICAL, "%s %s - %s: %s\n", SERVICE, state_text(STATE_CRITICAL), _("Invalid hostname, address or socket"), 721 die(STATE_CRITICAL, "%s %s - %s: %s\n", config.service, state_text(STATE_CRITICAL), _("Invalid hostname, address or socket"),
607 server_address); 722 config.server_address);
723 }
608 724
609 return OK; 725 check_tcp_config_wrapper result = {
726 .config = config,
727 .errorcode = OK,
728 };
729 return result;
610} 730}
611 731
612void print_help(void) { 732void print_help(const char *service) {
613 print_revision(progname, NP_VERSION); 733 print_revision(progname, NP_VERSION);
614 734
615 printf("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n"); 735 printf("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
616 printf(COPYRIGHT, copyright, email); 736 printf(COPYRIGHT, copyright, email);
617 737
618 printf(_("This plugin tests %s connections with the specified host (or unix socket).\n\n"), SERVICE); 738 printf(_("This plugin tests %s connections with the specified host (or unix socket).\n\n"), service);
619 739
620 print_usage(); 740 print_usage();
621 741
@@ -662,6 +782,7 @@ void print_help(void) {
662 782
663 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 783 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
664 784
785 printf(UT_OUTPUT_FORMAT);
665 printf(UT_VERBOSE); 786 printf(UT_VERBOSE);
666 787
667 printf(UT_SUPPORT); 788 printf(UT_SUPPORT);
diff --git a/plugins/check_tcp.d/config.h b/plugins/check_tcp.d/config.h
new file mode 100644
index 00000000..dc25d79e
--- /dev/null
+++ b/plugins/check_tcp.d/config.h
@@ -0,0 +1,84 @@
1#pragma once
2
3#include "../../lib/utils_tcp.h"
4#include "output.h"
5#include "states.h"
6#include <netinet/in.h>
7
8typedef struct {
9 char *server_address;
10 bool host_specified;
11 int server_port; // TODO can this be a uint16?
12
13 int protocol; /* most common is default */
14 char *service;
15 char *send;
16 char *quit;
17 char **server_expect;
18 size_t server_expect_count;
19 bool use_tls;
20#ifdef HAVE_SSL
21 char *sni;
22 bool sni_specified;
23 bool check_cert;
24 int days_till_exp_warn;
25 int days_till_exp_crit;
26#endif // HAVE_SSL
27 int match_flags;
28 mp_state_enum expect_mismatch_state;
29 unsigned int delay;
30
31 bool warning_time_set;
32 double warning_time;
33 bool critical_time_set;
34 double critical_time;
35
36 mp_state_enum econn_refuse_state;
37
38 ssize_t maxbytes;
39
40 bool hide_output;
41
42 bool output_format_set;
43 mp_output_format output_format;
44} check_tcp_config;
45
46check_tcp_config check_tcp_config_init() {
47 check_tcp_config result = {
48 .server_address = "127.0.0.1",
49 .host_specified = false,
50 .server_port = 0,
51
52 .protocol = IPPROTO_TCP,
53 .service = "TCP",
54 .send = NULL,
55 .quit = NULL,
56 .server_expect = NULL,
57 .server_expect_count = 0,
58 .use_tls = false,
59#ifdef HAVE_SSL
60 .sni = NULL,
61 .sni_specified = false,
62 .check_cert = false,
63 .days_till_exp_warn = 0,
64 .days_till_exp_crit = 0,
65#endif // HAVE_SSL
66 .match_flags = NP_MATCH_EXACT,
67 .expect_mismatch_state = STATE_WARNING,
68 .delay = 0,
69
70 .warning_time_set = false,
71 .warning_time = 0,
72 .critical_time_set = false,
73 .critical_time = 0,
74
75 .econn_refuse_state = STATE_CRITICAL,
76
77 .maxbytes = 0,
78
79 .hide_output = false,
80
81 .output_format_set = false,
82 };
83 return result;
84}
diff --git a/plugins/check_time.c b/plugins/check_time.c
index d1f50683..debf59f3 100644
--- a/plugins/check_time.c
+++ b/plugins/check_time.c
@@ -28,6 +28,7 @@
28 * 28 *
29 *****************************************************************************/ 29 *****************************************************************************/
30 30
31#include "states.h"
31const char *progname = "check_time"; 32const char *progname = "check_time";
32const char *copyright = "1999-2024"; 33const char *copyright = "1999-2024";
33const char *email = "devel@monitoring-plugins.org"; 34const char *email = "devel@monitoring-plugins.org";
@@ -35,28 +36,15 @@ const char *email = "devel@monitoring-plugins.org";
35#include "common.h" 36#include "common.h"
36#include "netutils.h" 37#include "netutils.h"
37#include "utils.h" 38#include "utils.h"
38 39#include "check_time.d/config.h"
39enum {
40 TIME_PORT = 37
41};
42 40
43#define UNIX_EPOCH 2208988800UL 41#define UNIX_EPOCH 2208988800UL
44 42
45static uint32_t raw_server_time; 43typedef struct {
46static unsigned long server_time, diff_time; 44 int errorcode;
47static int warning_time = 0; 45 check_time_config config;
48static bool check_warning_time = false; 46} check_time_config_wrapper;
49static int critical_time = 0; 47static check_time_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
50static bool check_critical_time = false;
51static unsigned long warning_diff = 0;
52static bool check_warning_diff = false;
53static unsigned long critical_diff = 0;
54static bool check_critical_diff = false;
55static int server_port = TIME_PORT;
56static char *server_address = NULL;
57static bool use_udp = false;
58
59static int process_arguments(int, char **);
60static void print_help(void); 48static void print_help(void);
61void print_usage(void); 49void print_usage(void);
62 50
@@ -68,8 +56,12 @@ int main(int argc, char **argv) {
68 /* Parse extra opts if any */ 56 /* Parse extra opts if any */
69 argv = np_extra_opts(&argc, argv, progname); 57 argv = np_extra_opts(&argc, argv, progname);
70 58
71 if (process_arguments(argc, argv) == ERROR) 59 check_time_config_wrapper tmp_config = process_arguments(argc, argv);
60 if (tmp_config.errorcode == ERROR) {
72 usage4(_("Could not parse arguments")); 61 usage4(_("Could not parse arguments"));
62 }
63
64 const check_time_config config = tmp_config.config;
73 65
74 /* initialize alarm signal handling */ 66 /* initialize alarm signal handling */
75 signal(SIGALRM, socket_timeout_alarm_handler); 67 signal(SIGALRM, socket_timeout_alarm_handler);
@@ -79,37 +71,40 @@ int main(int argc, char **argv) {
79 time(&start_time); 71 time(&start_time);
80 72
81 int socket; 73 int socket;
82 int result = STATE_UNKNOWN; 74 mp_state_enum result = STATE_UNKNOWN;
83 /* try to connect to the host at the given port number */ 75 /* try to connect to the host at the given port number */
84 if (use_udp) { 76 if (config.use_udp) {
85 result = my_udp_connect(server_address, server_port, &socket); 77 result = my_udp_connect(config.server_address, config.server_port, &socket);
86 } else { 78 } else {
87 result = my_tcp_connect(server_address, server_port, &socket); 79 result = my_tcp_connect(config.server_address, config.server_port, &socket);
88 } 80 }
89 81
90 if (result != STATE_OK) { 82 if (result != STATE_OK) {
91 if (check_critical_time) 83 if (config.check_critical_time) {
92 result = STATE_CRITICAL; 84 result = STATE_CRITICAL;
93 else if (check_warning_time) 85 } else if (config.check_warning_time) {
94 result = STATE_WARNING; 86 result = STATE_WARNING;
95 else 87 } else {
96 result = STATE_UNKNOWN; 88 result = STATE_UNKNOWN;
97 die(result, _("TIME UNKNOWN - could not connect to server %s, port %d\n"), server_address, server_port); 89 }
90 die(result, _("TIME UNKNOWN - could not connect to server %s, port %d\n"), config.server_address, config.server_port);
98 } 91 }
99 92
100 if (use_udp) { 93 if (config.use_udp) {
101 if (send(socket, "", 0, 0) < 0) { 94 if (send(socket, "", 0, 0) < 0) {
102 if (check_critical_time) 95 if (config.check_critical_time) {
103 result = STATE_CRITICAL; 96 result = STATE_CRITICAL;
104 else if (check_warning_time) 97 } else if (config.check_warning_time) {
105 result = STATE_WARNING; 98 result = STATE_WARNING;
106 else 99 } else {
107 result = STATE_UNKNOWN; 100 result = STATE_UNKNOWN;
108 die(result, _("TIME UNKNOWN - could not send UDP request to server %s, port %d\n"), server_address, server_port); 101 }
102 die(result, _("TIME UNKNOWN - could not send UDP request to server %s, port %d\n"), config.server_address, config.server_port);
109 } 103 }
110 } 104 }
111 105
112 /* watch for the connection string */ 106 /* watch for the connection string */
107 uint32_t raw_server_time;
113 result = recv(socket, (void *)&raw_server_time, sizeof(raw_server_time), 0); 108 result = recv(socket, (void *)&raw_server_time, sizeof(raw_server_time), 0);
114 109
115 /* close the connection */ 110 /* close the connection */
@@ -121,48 +116,56 @@ int main(int argc, char **argv) {
121 116
122 /* return a WARNING status if we couldn't read any data */ 117 /* return a WARNING status if we couldn't read any data */
123 if (result <= 0) { 118 if (result <= 0) {
124 if (check_critical_time) 119 if (config.check_critical_time) {
125 result = STATE_CRITICAL; 120 result = STATE_CRITICAL;
126 else if (check_warning_time) 121 } else if (config.check_warning_time) {
127 result = STATE_WARNING; 122 result = STATE_WARNING;
128 else 123 } else {
129 result = STATE_UNKNOWN; 124 result = STATE_UNKNOWN;
130 die(result, _("TIME UNKNOWN - no data received from server %s, port %d\n"), server_address, server_port); 125 }
126 die(result, _("TIME UNKNOWN - no data received from server %s, port %d\n"), config.server_address, config.server_port);
131 } 127 }
132 128
133 result = STATE_OK; 129 result = STATE_OK;
134 130
135 time_t conntime = (end_time - start_time); 131 time_t conntime = (end_time - start_time);
136 if (check_critical_time && conntime > critical_time) 132 if (config.check_critical_time && conntime > config.critical_time) {
137 result = STATE_CRITICAL; 133 result = STATE_CRITICAL;
138 else if (check_warning_time && conntime > warning_time) 134 } else if (config.check_warning_time && conntime > config.warning_time) {
139 result = STATE_WARNING; 135 result = STATE_WARNING;
136 }
140 137
141 if (result != STATE_OK) 138 if (result != STATE_OK) {
142 die(result, _("TIME %s - %d second response time|%s\n"), state_text(result), (int)conntime, 139 die(result, _("TIME %s - %d second response time|%s\n"), state_text(result), (int)conntime,
143 perfdata("time", (long)conntime, "s", check_warning_time, (long)warning_time, check_critical_time, (long)critical_time, true, 0, 140 perfdata("time", (long)conntime, "s", config.check_warning_time, (long)config.warning_time, config.check_critical_time,
144 false, 0)); 141 (long)config.critical_time, true, 0, false, 0));
142 }
145 143
144 unsigned long server_time;
145 unsigned long diff_time;
146 server_time = ntohl(raw_server_time) - UNIX_EPOCH; 146 server_time = ntohl(raw_server_time) - UNIX_EPOCH;
147 if (server_time > (unsigned long)end_time) 147 if (server_time > (unsigned long)end_time) {
148 diff_time = server_time - (unsigned long)end_time; 148 diff_time = server_time - (unsigned long)end_time;
149 else 149 } else {
150 diff_time = (unsigned long)end_time - server_time; 150 diff_time = (unsigned long)end_time - server_time;
151 }
151 152
152 if (check_critical_diff && diff_time > critical_diff) 153 if (config.check_critical_diff && diff_time > config.critical_diff) {
153 result = STATE_CRITICAL; 154 result = STATE_CRITICAL;
154 else if (check_warning_diff && diff_time > warning_diff) 155 } else if (config.check_warning_diff && diff_time > config.warning_diff) {
155 result = STATE_WARNING; 156 result = STATE_WARNING;
157 }
156 158
157 printf(_("TIME %s - %lu second time difference|%s %s\n"), state_text(result), diff_time, 159 printf(_("TIME %s - %lu second time difference|%s %s\n"), state_text(result), diff_time,
158 perfdata("time", (long)conntime, "s", check_warning_time, (long)warning_time, check_critical_time, (long)critical_time, true, 0, 160 perfdata("time", (long)conntime, "s", config.check_warning_time, (long)config.warning_time, config.check_critical_time,
159 false, 0), 161 (long)config.critical_time, true, 0, false, 0),
160 perfdata("offset", diff_time, "s", check_warning_diff, warning_diff, check_critical_diff, critical_diff, true, 0, false, 0)); 162 perfdata("offset", diff_time, "s", config.check_warning_diff, config.warning_diff, config.check_critical_diff,
163 config.critical_diff, true, 0, false, 0));
161 return result; 164 return result;
162} 165}
163 166
164/* process command-line arguments */ 167/* process command-line arguments */
165int process_arguments(int argc, char **argv) { 168check_time_config_wrapper process_arguments(int argc, char **argv) {
166 static struct option longopts[] = {{"hostname", required_argument, 0, 'H'}, 169 static struct option longopts[] = {{"hostname", required_argument, 0, 'H'},
167 {"warning-variance", required_argument, 0, 'w'}, 170 {"warning-variance", required_argument, 0, 'w'},
168 {"critical-variance", required_argument, 0, 'c'}, 171 {"critical-variance", required_argument, 0, 'c'},
@@ -175,29 +178,37 @@ int process_arguments(int argc, char **argv) {
175 {"help", no_argument, 0, 'h'}, 178 {"help", no_argument, 0, 'h'},
176 {0, 0, 0, 0}}; 179 {0, 0, 0, 0}};
177 180
178 if (argc < 2) 181 if (argc < 2) {
179 usage("\n"); 182 usage("\n");
183 }
180 184
181 for (int i = 1; i < argc; i++) { 185 for (int i = 1; i < argc; i++) {
182 if (strcmp("-to", argv[i]) == 0) 186 if (strcmp("-to", argv[i]) == 0) {
183 strcpy(argv[i], "-t"); 187 strcpy(argv[i], "-t");
184 else if (strcmp("-wd", argv[i]) == 0) 188 } else if (strcmp("-wd", argv[i]) == 0) {
185 strcpy(argv[i], "-w"); 189 strcpy(argv[i], "-w");
186 else if (strcmp("-cd", argv[i]) == 0) 190 } else if (strcmp("-cd", argv[i]) == 0) {
187 strcpy(argv[i], "-c"); 191 strcpy(argv[i], "-c");
188 else if (strcmp("-wt", argv[i]) == 0) 192 } else if (strcmp("-wt", argv[i]) == 0) {
189 strcpy(argv[i], "-W"); 193 strcpy(argv[i], "-W");
190 else if (strcmp("-ct", argv[i]) == 0) 194 } else if (strcmp("-ct", argv[i]) == 0) {
191 strcpy(argv[i], "-C"); 195 strcpy(argv[i], "-C");
196 }
192 } 197 }
193 198
199 check_time_config_wrapper result = {
200 .errorcode = OK,
201 .config = check_time_config_init(),
202 };
203
194 int option_char; 204 int option_char;
195 while (true) { 205 while (true) {
196 int option = 0; 206 int option = 0;
197 option_char = getopt_long(argc, argv, "hVH:w:c:W:C:p:t:u", longopts, &option); 207 option_char = getopt_long(argc, argv, "hVH:w:c:W:C:p:t:u", longopts, &option);
198 208
199 if (option_char == -1 || option_char == EOF) 209 if (option_char == -1 || option_char == EOF) {
200 break; 210 break;
211 }
201 212
202 switch (option_char) { 213 switch (option_char) {
203 case '?': /* print short usage statement if args not parsable */ 214 case '?': /* print short usage statement if args not parsable */
@@ -209,18 +220,19 @@ int process_arguments(int argc, char **argv) {
209 print_revision(progname, NP_VERSION); 220 print_revision(progname, NP_VERSION);
210 exit(STATE_UNKNOWN); 221 exit(STATE_UNKNOWN);
211 case 'H': /* hostname */ 222 case 'H': /* hostname */
212 if (!is_host(optarg)) 223 if (!is_host(optarg)) {
213 usage2(_("Invalid hostname/address"), optarg); 224 usage2(_("Invalid hostname/address"), optarg);
214 server_address = optarg; 225 }
226 result.config.server_address = optarg;
215 break; 227 break;
216 case 'w': /* warning-variance */ 228 case 'w': /* warning-variance */
217 if (is_intnonneg(optarg)) { 229 if (is_intnonneg(optarg)) {
218 warning_diff = strtoul(optarg, NULL, 10); 230 result.config.warning_diff = strtoul(optarg, NULL, 10);
219 check_warning_diff = true; 231 result.config.check_warning_diff = true;
220 } else if (strspn(optarg, "0123456789:,") > 0) { 232 } else if (strspn(optarg, "0123456789:,") > 0) {
221 if (sscanf(optarg, "%lu%*[:,]%d", &warning_diff, &warning_time) == 2) { 233 if (sscanf(optarg, "%lu%*[:,]%d", &result.config.warning_diff, &result.config.warning_time) == 2) {
222 check_warning_diff = true; 234 result.config.check_warning_diff = true;
223 check_warning_time = true; 235 result.config.check_warning_time = true;
224 } else { 236 } else {
225 usage4(_("Warning thresholds must be a positive integer")); 237 usage4(_("Warning thresholds must be a positive integer"));
226 } 238 }
@@ -230,12 +242,12 @@ int process_arguments(int argc, char **argv) {
230 break; 242 break;
231 case 'c': /* critical-variance */ 243 case 'c': /* critical-variance */
232 if (is_intnonneg(optarg)) { 244 if (is_intnonneg(optarg)) {
233 critical_diff = strtoul(optarg, NULL, 10); 245 result.config.critical_diff = strtoul(optarg, NULL, 10);
234 check_critical_diff = true; 246 result.config.check_critical_diff = true;
235 } else if (strspn(optarg, "0123456789:,") > 0) { 247 } else if (strspn(optarg, "0123456789:,") > 0) {
236 if (sscanf(optarg, "%lu%*[:,]%d", &critical_diff, &critical_time) == 2) { 248 if (sscanf(optarg, "%lu%*[:,]%d", &result.config.critical_diff, &result.config.critical_time) == 2) {
237 check_critical_diff = true; 249 result.config.check_critical_diff = true;
238 check_critical_time = true; 250 result.config.check_critical_time = true;
239 } else { 251 } else {
240 usage4(_("Critical thresholds must be a positive integer")); 252 usage4(_("Critical thresholds must be a positive integer"));
241 } 253 }
@@ -244,48 +256,53 @@ int process_arguments(int argc, char **argv) {
244 } 256 }
245 break; 257 break;
246 case 'W': /* warning-connect */ 258 case 'W': /* warning-connect */
247 if (!is_intnonneg(optarg)) 259 if (!is_intnonneg(optarg)) {
248 usage4(_("Warning threshold must be a positive integer")); 260 usage4(_("Warning threshold must be a positive integer"));
249 else 261 } else {
250 warning_time = atoi(optarg); 262 result.config.warning_time = atoi(optarg);
251 check_warning_time = true; 263 }
264 result.config.check_warning_time = true;
252 break; 265 break;
253 case 'C': /* critical-connect */ 266 case 'C': /* critical-connect */
254 if (!is_intnonneg(optarg)) 267 if (!is_intnonneg(optarg)) {
255 usage4(_("Critical threshold must be a positive integer")); 268 usage4(_("Critical threshold must be a positive integer"));
256 else 269 } else {
257 critical_time = atoi(optarg); 270 result.config.critical_time = atoi(optarg);
258 check_critical_time = true; 271 }
272 result.config.check_critical_time = true;
259 break; 273 break;
260 case 'p': /* port */ 274 case 'p': /* port */
261 if (!is_intnonneg(optarg)) 275 if (!is_intnonneg(optarg)) {
262 usage4(_("Port must be a positive integer")); 276 usage4(_("Port must be a positive integer"));
263 else 277 } else {
264 server_port = atoi(optarg); 278 result.config.server_port = atoi(optarg);
279 }
265 break; 280 break;
266 case 't': /* timeout */ 281 case 't': /* timeout */
267 if (!is_intnonneg(optarg)) 282 if (!is_intnonneg(optarg)) {
268 usage2(_("Timeout interval must be a positive integer"), optarg); 283 usage2(_("Timeout interval must be a positive integer"), optarg);
269 else 284 } else {
270 socket_timeout = atoi(optarg); 285 socket_timeout = atoi(optarg);
286 }
271 break; 287 break;
272 case 'u': /* udp */ 288 case 'u': /* udp */
273 use_udp = true; 289 result.config.use_udp = true;
274 } 290 }
275 } 291 }
276 292
277 option_char = optind; 293 option_char = optind;
278 if (server_address == NULL) { 294 if (result.config.server_address == NULL) {
279 if (argc > option_char) { 295 if (argc > option_char) {
280 if (!is_host(argv[option_char])) 296 if (!is_host(argv[option_char])) {
281 usage2(_("Invalid hostname/address"), optarg); 297 usage2(_("Invalid hostname/address"), optarg);
282 server_address = argv[option_char]; 298 }
299 result.config.server_address = argv[option_char];
283 } else { 300 } else {
284 usage4(_("Hostname was not supplied")); 301 usage4(_("Hostname was not supplied"));
285 } 302 }
286 } 303 }
287 304
288 return OK; 305 return result;
289} 306}
290 307
291void print_help(void) { 308void print_help(void) {
diff --git a/plugins/check_time.d/config.h b/plugins/check_time.d/config.h
new file mode 100644
index 00000000..09bd7c45
--- /dev/null
+++ b/plugins/check_time.d/config.h
@@ -0,0 +1,42 @@
1#pragma once
2
3#include "../../config.h"
4#include <stddef.h>
5
6enum {
7 TIME_PORT = 37
8};
9
10typedef struct {
11 char *server_address;
12 int server_port;
13 bool use_udp;
14
15 int warning_time;
16 bool check_warning_time;
17 int critical_time;
18 bool check_critical_time;
19 unsigned long warning_diff;
20 bool check_warning_diff;
21 unsigned long critical_diff;
22 bool check_critical_diff;
23} check_time_config;
24
25check_time_config check_time_config_init() {
26 check_time_config tmp = {
27 .server_address = NULL,
28 .server_port = TIME_PORT,
29 .use_udp = false,
30
31 .warning_time = 0,
32 .check_warning_time = false,
33 .critical_time = 0,
34 .check_critical_time = false,
35
36 .warning_diff = 0,
37 .check_warning_diff = false,
38 .critical_diff = 0,
39 .check_critical_diff = false,
40 };
41 return tmp;
42}
diff --git a/plugins/check_ups.c b/plugins/check_ups.c
index 526a29df..ecc0760f 100644
--- a/plugins/check_ups.c
+++ b/plugins/check_ups.c
@@ -39,69 +39,29 @@ const char *email = "devel@monitoring-plugins.org";
39#include "common.h" 39#include "common.h"
40#include "netutils.h" 40#include "netutils.h"
41#include "utils.h" 41#include "utils.h"
42 42#include "check_ups.d/config.h"
43enum { 43#include "states.h"
44 PORT = 3493
45};
46
47#define UPS_NONE 0 /* no supported options */
48#define UPS_UTILITY 1 /* supports utility line */
49#define UPS_BATTPCT 2 /* supports percent battery remaining */
50#define UPS_STATUS 4 /* supports UPS status */
51#define UPS_TEMP 8 /* supports UPS temperature */
52#define UPS_LOADPCT 16 /* supports load percent */
53#define UPS_REALPOWER 32 /* supports real power */
54
55#define UPSSTATUS_NONE 0
56#define UPSSTATUS_OFF 1
57#define UPSSTATUS_OL 2
58#define UPSSTATUS_OB 4
59#define UPSSTATUS_LB 8
60#define UPSSTATUS_CAL 16
61#define UPSSTATUS_RB 32 /*Replace Battery */
62#define UPSSTATUS_BYPASS 64
63#define UPSSTATUS_OVER 128
64#define UPSSTATUS_TRIM 256
65#define UPSSTATUS_BOOST 512
66#define UPSSTATUS_CHRG 1024
67#define UPSSTATUS_DISCHRG 2048
68#define UPSSTATUS_UNKNOWN 4096
69#define UPSSTATUS_ALARM 8192
70 44
71enum { 45enum {
72 NOSUCHVAR = ERROR - 1 46 NOSUCHVAR = ERROR - 1
73}; 47};
74 48
75typedef struct ups_config {
76 unsigned int server_port;
77 char *server_address;
78 char *ups_name;
79 double warning_value;
80 double critical_value;
81 bool check_warn;
82 bool check_crit;
83 int check_variable;
84 int status;
85 bool temp_output_c;
86} ups_config;
87
88ups_config ups_config_init(void) {
89 ups_config tmp = {0};
90 tmp.server_port = PORT;
91 tmp.server_address = NULL;
92 tmp.ups_name = NULL;
93 tmp.check_variable = UPS_NONE;
94 tmp.status = UPSSTATUS_NONE;
95
96 return tmp;
97}
98
99// Forward declarations 49// Forward declarations
100static int determine_status(ups_config * /*config*/, int *supported_options); 50typedef struct {
101static int get_ups_variable(const char * /*varname*/, char * /*buf*/, ups_config config); 51 int errorcode;
52 int ups_status;
53 int supported_options;
54} determine_status_result;
55static determine_status_result determine_status(check_ups_config /*config*/);
56static int get_ups_variable(const char * /*varname*/, char * /*buf*/, check_ups_config config);
57
58typedef struct {
59 int errorcode;
60 check_ups_config config;
61} check_ups_config_wrapper;
62static check_ups_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
63static check_ups_config_wrapper validate_arguments(check_ups_config_wrapper /*config_wrapper*/);
102 64
103static int process_arguments(int /*argc*/, char ** /*argv*/, ups_config * /*config*/);
104static int validate_arguments(ups_config /*config*/);
105static void print_help(void); 65static void print_help(void);
106void print_usage(void); 66void print_usage(void);
107 67
@@ -109,28 +69,16 @@ int main(int argc, char **argv) {
109 setlocale(LC_ALL, ""); 69 setlocale(LC_ALL, "");
110 bindtextdomain(PACKAGE, LOCALEDIR); 70 bindtextdomain(PACKAGE, LOCALEDIR);
111 textdomain(PACKAGE); 71 textdomain(PACKAGE);
112
113 char *ups_status;
114 ups_status = strdup("N/A");
115
116 char *data;
117 data = strdup("");
118
119 char *message;
120 message = strdup("");
121
122 // Exit result
123 int result = STATE_UNKNOWN;
124
125 /* Parse extra opts if any */ 72 /* Parse extra opts if any */
126 argv = np_extra_opts(&argc, argv, progname); 73 argv = np_extra_opts(&argc, argv, progname);
127 74
128 // Config from commandline 75 check_ups_config_wrapper tmp_config = process_arguments(argc, argv);
129 ups_config config = ups_config_init();
130 76
131 if (process_arguments(argc, argv, &config) == ERROR) { 77 if (tmp_config.errorcode == ERROR) {
132 usage4(_("Could not parse arguments")); 78 usage4(_("Could not parse arguments"));
133 } 79 }
80 // Config from commandline
81 check_ups_config config = tmp_config.config;
134 82
135 /* initialize alarm signal handling */ 83 /* initialize alarm signal handling */
136 signal(SIGALRM, socket_timeout_alarm_handler); 84 signal(SIGALRM, socket_timeout_alarm_handler);
@@ -138,71 +86,75 @@ int main(int argc, char **argv) {
138 /* set socket timeout */ 86 /* set socket timeout */
139 alarm(socket_timeout); 87 alarm(socket_timeout);
140 88
141 int supported_options = UPS_NONE;
142
143 /* get the ups status if possible */ 89 /* get the ups status if possible */
144 if (determine_status(&config, &supported_options) != OK) { 90 determine_status_result query_result = determine_status(config);
91 if (query_result.errorcode != OK) {
145 return STATE_CRITICAL; 92 return STATE_CRITICAL;
146 } 93 }
147 94
148 if (supported_options & UPS_STATUS) { 95 int ups_status_flags = query_result.ups_status;
96 int supported_options = query_result.supported_options;
149 97
150 ups_status = strdup(""); 98 // Exit result
99 mp_state_enum result = STATE_UNKNOWN;
100 char *message = NULL;
151 101
102 if (supported_options & UPS_STATUS) {
103 char *ups_status = strdup("");
152 result = STATE_OK; 104 result = STATE_OK;
153 105
154 if (config.status & UPSSTATUS_OFF) { 106 if (ups_status_flags & UPSSTATUS_OFF) {
155 xasprintf(&ups_status, "Off"); 107 xasprintf(&ups_status, "Off");
156 result = STATE_CRITICAL; 108 result = STATE_CRITICAL;
157 } else if ((config.status & (UPSSTATUS_OB | UPSSTATUS_LB)) == (UPSSTATUS_OB | UPSSTATUS_LB)) { 109 } else if ((ups_status_flags & (UPSSTATUS_OB | UPSSTATUS_LB)) == (UPSSTATUS_OB | UPSSTATUS_LB)) {
158 xasprintf(&ups_status, _("On Battery, Low Battery")); 110 xasprintf(&ups_status, _("On Battery, Low Battery"));
159 result = STATE_CRITICAL; 111 result = STATE_CRITICAL;
160 } else { 112 } else {
161 if (config.status & UPSSTATUS_OL) { 113 if (ups_status_flags & UPSSTATUS_OL) {
162 xasprintf(&ups_status, "%s%s", ups_status, _("Online")); 114 xasprintf(&ups_status, "%s%s", ups_status, _("Online"));
163 } 115 }
164 if (config.status & UPSSTATUS_OB) { 116 if (ups_status_flags & UPSSTATUS_OB) {
165 xasprintf(&ups_status, "%s%s", ups_status, _("On Battery")); 117 xasprintf(&ups_status, "%s%s", ups_status, _("On Battery"));
166 result = max_state(result, STATE_WARNING); 118 result = max_state(result, STATE_WARNING);
167 } 119 }
168 if (config.status & UPSSTATUS_LB) { 120 if (ups_status_flags & UPSSTATUS_LB) {
169 xasprintf(&ups_status, "%s%s", ups_status, _(", Low Battery")); 121 xasprintf(&ups_status, "%s%s", ups_status, _(", Low Battery"));
170 result = max_state(result, STATE_WARNING); 122 result = max_state(result, STATE_WARNING);
171 } 123 }
172 if (config.status & UPSSTATUS_CAL) { 124 if (ups_status_flags & UPSSTATUS_CAL) {
173 xasprintf(&ups_status, "%s%s", ups_status, _(", Calibrating")); 125 xasprintf(&ups_status, "%s%s", ups_status, _(", Calibrating"));
174 } 126 }
175 if (config.status & UPSSTATUS_RB) { 127 if (ups_status_flags & UPSSTATUS_RB) {
176 xasprintf(&ups_status, "%s%s", ups_status, _(", Replace Battery")); 128 xasprintf(&ups_status, "%s%s", ups_status, _(", Replace Battery"));
177 result = max_state(result, STATE_WARNING); 129 result = max_state(result, STATE_WARNING);
178 } 130 }
179 if (config.status & UPSSTATUS_BYPASS) { 131 if (ups_status_flags & UPSSTATUS_BYPASS) {
180 xasprintf(&ups_status, "%s%s", ups_status, _(", On Bypass")); 132 xasprintf(&ups_status, "%s%s", ups_status, _(", On Bypass"));
181 // Bypassing the battery is likely a bad thing 133 // Bypassing the battery is likely a bad thing
182 result = STATE_CRITICAL; 134 result = STATE_CRITICAL;
183 } 135 }
184 if (config.status & UPSSTATUS_OVER) { 136 if (ups_status_flags & UPSSTATUS_OVER) {
185 xasprintf(&ups_status, "%s%s", ups_status, _(", Overload")); 137 xasprintf(&ups_status, "%s%s", ups_status, _(", Overload"));
186 result = max_state(result, STATE_WARNING); 138 result = max_state(result, STATE_WARNING);
187 } 139 }
188 if (config.status & UPSSTATUS_TRIM) { 140 if (ups_status_flags & UPSSTATUS_TRIM) {
189 xasprintf(&ups_status, "%s%s", ups_status, _(", Trimming")); 141 xasprintf(&ups_status, "%s%s", ups_status, _(", Trimming"));
190 } 142 }
191 if (config.status & UPSSTATUS_BOOST) { 143 if (ups_status_flags & UPSSTATUS_BOOST) {
192 xasprintf(&ups_status, "%s%s", ups_status, _(", Boosting")); 144 xasprintf(&ups_status, "%s%s", ups_status, _(", Boosting"));
193 } 145 }
194 if (config.status & UPSSTATUS_CHRG) { 146 if (ups_status_flags & UPSSTATUS_CHRG) {
195 xasprintf(&ups_status, "%s%s", ups_status, _(", Charging")); 147 xasprintf(&ups_status, "%s%s", ups_status, _(", Charging"));
196 } 148 }
197 if (config.status & UPSSTATUS_DISCHRG) { 149 if (ups_status_flags & UPSSTATUS_DISCHRG) {
198 xasprintf(&ups_status, "%s%s", ups_status, _(", Discharging")); 150 xasprintf(&ups_status, "%s%s", ups_status, _(", Discharging"));
199 result = max_state(result, STATE_WARNING); 151 result = max_state(result, STATE_WARNING);
200 } 152 }
201 if (config.status & UPSSTATUS_ALARM) { 153 if (ups_status_flags & UPSSTATUS_ALARM) {
202 xasprintf(&ups_status, "%s%s", ups_status, _(", ALARM")); 154 xasprintf(&ups_status, "%s%s", ups_status, _(", ALARM"));
203 result = STATE_CRITICAL; 155 result = STATE_CRITICAL;
204 } 156 }
205 if (config.status & UPSSTATUS_UNKNOWN) { 157 if (ups_status_flags & UPSSTATUS_UNKNOWN) {
206 xasprintf(&ups_status, "%s%s", ups_status, _(", Unknown")); 158 xasprintf(&ups_status, "%s%s", ups_status, _(", Unknown"));
207 } 159 }
208 } 160 }
@@ -211,7 +163,7 @@ int main(int argc, char **argv) {
211 163
212 int res; 164 int res;
213 char temp_buffer[MAX_INPUT_BUFFER]; 165 char temp_buffer[MAX_INPUT_BUFFER];
214 166 char *performance_data = strdup("");
215 /* get the ups utility voltage if possible */ 167 /* get the ups utility voltage if possible */
216 res = get_ups_variable("input.voltage", temp_buffer, config); 168 res = get_ups_variable("input.voltage", temp_buffer, config);
217 if (res == NOSUCHVAR) { 169 if (res == NOSUCHVAR) {
@@ -239,11 +191,12 @@ int main(int argc, char **argv) {
239 } else if (config.check_warn && ups_utility_deviation >= config.warning_value) { 191 } else if (config.check_warn && ups_utility_deviation >= config.warning_value) {
240 result = max_state(result, STATE_WARNING); 192 result = max_state(result, STATE_WARNING);
241 } 193 }
242 xasprintf(&data, "%s", 194 xasprintf(&performance_data, "%s",
243 perfdata("voltage", (long)(1000 * ups_utility_voltage), "mV", config.check_warn, (long)(1000 * config.warning_value), 195 perfdata("voltage", (long)(1000 * ups_utility_voltage), "mV", config.check_warn, (long)(1000 * config.warning_value),
244 config.check_crit, (long)(1000 * config.critical_value), true, 0, false, 0)); 196 config.check_crit, (long)(1000 * config.critical_value), true, 0, false, 0));
245 } else { 197 } else {
246 xasprintf(&data, "%s", perfdata("voltage", (long)(1000 * ups_utility_voltage), "mV", false, 0, false, 0, true, 0, false, 0)); 198 xasprintf(&performance_data, "%s",
199 perfdata("voltage", (long)(1000 * ups_utility_voltage), "mV", false, 0, false, 0, true, 0, false, 0));
247 } 200 }
248 } 201 }
249 202
@@ -266,11 +219,12 @@ int main(int argc, char **argv) {
266 } else if (config.check_warn && ups_battery_percent <= config.warning_value) { 219 } else if (config.check_warn && ups_battery_percent <= config.warning_value) {
267 result = max_state(result, STATE_WARNING); 220 result = max_state(result, STATE_WARNING);
268 } 221 }
269 xasprintf(&data, "%s %s", data, 222 xasprintf(&performance_data, "%s %s", performance_data,
270 perfdata("battery", (long)ups_battery_percent, "%", config.check_warn, (long)(config.warning_value), 223 perfdata("battery", (long)ups_battery_percent, "%", config.check_warn, (long)(config.warning_value),
271 config.check_crit, (long)(config.critical_value), true, 0, true, 100)); 224 config.check_crit, (long)(config.critical_value), true, 0, true, 100));
272 } else { 225 } else {
273 xasprintf(&data, "%s %s", data, perfdata("battery", (long)ups_battery_percent, "%", false, 0, false, 0, true, 0, true, 100)); 226 xasprintf(&performance_data, "%s %s", performance_data,
227 perfdata("battery", (long)ups_battery_percent, "%", false, 0, false, 0, true, 0, true, 100));
274 } 228 }
275 } 229 }
276 230
@@ -293,11 +247,12 @@ int main(int argc, char **argv) {
293 } else if (config.check_warn && ups_load_percent >= config.warning_value) { 247 } else if (config.check_warn && ups_load_percent >= config.warning_value) {
294 result = max_state(result, STATE_WARNING); 248 result = max_state(result, STATE_WARNING);
295 } 249 }
296 xasprintf(&data, "%s %s", data, 250 xasprintf(&performance_data, "%s %s", performance_data,
297 perfdata("load", (long)ups_load_percent, "%", config.check_warn, (long)(config.warning_value), config.check_crit, 251 perfdata("load", (long)ups_load_percent, "%", config.check_warn, (long)(config.warning_value), config.check_crit,
298 (long)(config.critical_value), true, 0, true, 100)); 252 (long)(config.critical_value), true, 0, true, 100));
299 } else { 253 } else {
300 xasprintf(&data, "%s %s", data, perfdata("load", (long)ups_load_percent, "%", false, 0, false, 0, true, 0, true, 100)); 254 xasprintf(&performance_data, "%s %s", performance_data,
255 perfdata("load", (long)ups_load_percent, "%", false, 0, false, 0, true, 0, true, 100));
301 } 256 }
302 } 257 }
303 258
@@ -329,11 +284,12 @@ int main(int argc, char **argv) {
329 } else if (config.check_warn && ups_temperature >= config.warning_value) { 284 } else if (config.check_warn && ups_temperature >= config.warning_value) {
330 result = max_state(result, STATE_WARNING); 285 result = max_state(result, STATE_WARNING);
331 } 286 }
332 xasprintf(&data, "%s %s", data, 287 xasprintf(&performance_data, "%s %s", performance_data,
333 perfdata("temp", (long)ups_temperature, tunits, config.check_warn, (long)(config.warning_value), config.check_crit, 288 perfdata("temp", (long)ups_temperature, tunits, config.check_warn, (long)(config.warning_value), config.check_crit,
334 (long)(config.critical_value), true, 0, false, 0)); 289 (long)(config.critical_value), true, 0, false, 0));
335 } else { 290 } else {
336 xasprintf(&data, "%s %s", data, perfdata("temp", (long)ups_temperature, tunits, false, 0, false, 0, true, 0, false, 0)); 291 xasprintf(&performance_data, "%s %s", performance_data,
292 perfdata("temp", (long)ups_temperature, tunits, false, 0, false, 0, true, 0, false, 0));
337 } 293 }
338 } 294 }
339 295
@@ -355,11 +311,12 @@ int main(int argc, char **argv) {
355 } else if (config.check_warn && ups_realpower >= config.warning_value) { 311 } else if (config.check_warn && ups_realpower >= config.warning_value) {
356 result = max_state(result, STATE_WARNING); 312 result = max_state(result, STATE_WARNING);
357 } 313 }
358 xasprintf(&data, "%s %s", data, 314 xasprintf(&performance_data, "%s %s", performance_data,
359 perfdata("realpower", (long)ups_realpower, "W", config.check_warn, (long)(config.warning_value), config.check_crit, 315 perfdata("realpower", (long)ups_realpower, "W", config.check_warn, (long)(config.warning_value), config.check_crit,
360 (long)(config.critical_value), true, 0, false, 0)); 316 (long)(config.critical_value), true, 0, false, 0));
361 } else { 317 } else {
362 xasprintf(&data, "%s %s", data, perfdata("realpower", (long)ups_realpower, "W", false, 0, false, 0, true, 0, false, 0)); 318 xasprintf(&performance_data, "%s %s", performance_data,
319 perfdata("realpower", (long)ups_realpower, "W", false, 0, false, 0, true, 0, false, 0));
363 } 320 }
364 } 321 }
365 322
@@ -373,66 +330,73 @@ int main(int argc, char **argv) {
373 /* reset timeout */ 330 /* reset timeout */
374 alarm(0); 331 alarm(0);
375 332
376 printf("UPS %s - %s|%s\n", state_text(result), message, data); 333 printf("UPS %s - %s|%s\n", state_text(result), message, performance_data);
377 return result; 334 exit(result);
378} 335}
379 336
380/* determines what options are supported by the UPS */ 337/* determines what options are supported by the UPS */
381int determine_status(ups_config *config, int *supported_options) { 338determine_status_result determine_status(const check_ups_config config) {
382 char recv_buffer[MAX_INPUT_BUFFER];
383 339
384 int res = get_ups_variable("ups.status", recv_buffer, *config); 340 determine_status_result result = {
341 .errorcode = OK,
342 .ups_status = UPSSTATUS_NONE,
343 .supported_options = 0,
344 };
345
346 char recv_buffer[MAX_INPUT_BUFFER];
347 int res = get_ups_variable("ups.status", recv_buffer, config);
385 if (res == NOSUCHVAR) { 348 if (res == NOSUCHVAR) {
386 return OK; 349 return result;
387 } 350 }
388 351
389 if (res != STATE_OK) { 352 if (res != STATE_OK) {
390 printf("%s\n", _("Invalid response received from host")); 353 printf("%s\n", _("Invalid response received from host"));
391 return ERROR; 354 result.errorcode = ERROR;
355 return result;
392 } 356 }
393 357
394 *supported_options |= UPS_STATUS; 358 result.supported_options |= UPS_STATUS;
395 359
396 char temp_buffer[MAX_INPUT_BUFFER]; 360 char temp_buffer[MAX_INPUT_BUFFER];
397 361
398 strcpy(temp_buffer, recv_buffer); 362 strcpy(temp_buffer, recv_buffer);
399 for (char *ptr = (char *)strtok(temp_buffer, " "); ptr != NULL; ptr = (char *)strtok(NULL, " ")) { 363 for (char *ptr = strtok(temp_buffer, " "); ptr != NULL; ptr = strtok(NULL, " ")) {
400 if (!strcmp(ptr, "OFF")) { 364 if (!strcmp(ptr, "OFF")) {
401 config->status |= UPSSTATUS_OFF; 365 result.ups_status |= UPSSTATUS_OFF;
402 } else if (!strcmp(ptr, "OL")) { 366 } else if (!strcmp(ptr, "OL")) {
403 config->status |= UPSSTATUS_OL; 367 result.ups_status |= UPSSTATUS_OL;
404 } else if (!strcmp(ptr, "OB")) { 368 } else if (!strcmp(ptr, "OB")) {
405 config->status |= UPSSTATUS_OB; 369 result.ups_status |= UPSSTATUS_OB;
406 } else if (!strcmp(ptr, "LB")) { 370 } else if (!strcmp(ptr, "LB")) {
407 config->status |= UPSSTATUS_LB; 371 result.ups_status |= UPSSTATUS_LB;
408 } else if (!strcmp(ptr, "CAL")) { 372 } else if (!strcmp(ptr, "CAL")) {
409 config->status |= UPSSTATUS_CAL; 373 result.ups_status |= UPSSTATUS_CAL;
410 } else if (!strcmp(ptr, "RB")) { 374 } else if (!strcmp(ptr, "RB")) {
411 config->status |= UPSSTATUS_RB; 375 result.ups_status |= UPSSTATUS_RB;
412 } else if (!strcmp(ptr, "BYPASS")) { 376 } else if (!strcmp(ptr, "BYPASS")) {
413 config->status |= UPSSTATUS_BYPASS; 377 result.ups_status |= UPSSTATUS_BYPASS;
414 } else if (!strcmp(ptr, "OVER")) { 378 } else if (!strcmp(ptr, "OVER")) {
415 config->status |= UPSSTATUS_OVER; 379 result.ups_status |= UPSSTATUS_OVER;
416 } else if (!strcmp(ptr, "TRIM")) { 380 } else if (!strcmp(ptr, "TRIM")) {
417 config->status |= UPSSTATUS_TRIM; 381 result.ups_status |= UPSSTATUS_TRIM;
418 } else if (!strcmp(ptr, "BOOST")) { 382 } else if (!strcmp(ptr, "BOOST")) {
419 config->status |= UPSSTATUS_BOOST; 383 result.ups_status |= UPSSTATUS_BOOST;
420 } else if (!strcmp(ptr, "CHRG")) { 384 } else if (!strcmp(ptr, "CHRG")) {
421 config->status |= UPSSTATUS_CHRG; 385 result.ups_status |= UPSSTATUS_CHRG;
422 } else if (!strcmp(ptr, "DISCHRG")) { 386 } else if (!strcmp(ptr, "DISCHRG")) {
423 config->status |= UPSSTATUS_DISCHRG; 387 result.ups_status |= UPSSTATUS_DISCHRG;
424 } else if (!strcmp(ptr, "ALARM")) { 388 } else if (!strcmp(ptr, "ALARM")) {
425 config->status |= UPSSTATUS_ALARM; 389 result.ups_status |= UPSSTATUS_ALARM;
426 } else { 390 } else {
427 config->status |= UPSSTATUS_UNKNOWN; 391 result.ups_status |= UPSSTATUS_UNKNOWN;
428 } 392 }
429 } 393 }
430 394
431 return OK; 395 return result;
432} 396}
433 397
434/* gets a variable value for a specific UPS */ 398/* gets a variable value for a specific UPS */
435int get_ups_variable(const char *varname, char *buf, const ups_config config) { 399int get_ups_variable(const char *varname, char *buf, const check_ups_config config) {
436 char send_buffer[MAX_INPUT_BUFFER]; 400 char send_buffer[MAX_INPUT_BUFFER];
437 401
438 /* create the command string to send to the UPS daemon */ 402 /* create the command string to send to the UPS daemon */
@@ -500,7 +464,7 @@ int get_ups_variable(const char *varname, char *buf, const ups_config config) {
500 [-wv warn_value] [-cv crit_value] [-to to_sec] */ 464 [-wv warn_value] [-cv crit_value] [-to to_sec] */
501 465
502/* process command-line arguments */ 466/* process command-line arguments */
503int process_arguments(int argc, char **argv, ups_config *config) { 467check_ups_config_wrapper process_arguments(int argc, char **argv) {
504 468
505 static struct option longopts[] = {{"hostname", required_argument, 0, 'H'}, 469 static struct option longopts[] = {{"hostname", required_argument, 0, 'H'},
506 {"ups", required_argument, 0, 'u'}, 470 {"ups", required_argument, 0, 'u'},
@@ -514,8 +478,14 @@ int process_arguments(int argc, char **argv, ups_config *config) {
514 {"help", no_argument, 0, 'h'}, 478 {"help", no_argument, 0, 'h'},
515 {0, 0, 0, 0}}; 479 {0, 0, 0, 0}};
516 480
481 check_ups_config_wrapper result = {
482 .errorcode = OK,
483 .config = check_ups_config_init(),
484 };
485
517 if (argc < 2) { 486 if (argc < 2) {
518 return ERROR; 487 result.errorcode = ERROR;
488 return result;
519 } 489 }
520 490
521 int c; 491 int c;
@@ -542,52 +512,52 @@ int process_arguments(int argc, char **argv, ups_config *config) {
542 usage5(); 512 usage5();
543 case 'H': /* hostname */ 513 case 'H': /* hostname */
544 if (is_host(optarg)) { 514 if (is_host(optarg)) {
545 config->server_address = optarg; 515 result.config.server_address = optarg;
546 } else { 516 } else {
547 usage2(_("Invalid hostname/address"), optarg); 517 usage2(_("Invalid hostname/address"), optarg);
548 } 518 }
549 break; 519 break;
550 case 'T': /* FIXME: to be improved (ie "-T C" for Celsius or "-T F" for 520 case 'T': /* FIXME: to be improved (ie "-T C" for Celsius or "-T F" for
551 Fahrenheit) */ 521 Fahrenheit) */
552 config->temp_output_c = true; 522 result.config.temp_output_c = true;
553 break; 523 break;
554 case 'u': /* ups name */ 524 case 'u': /* ups name */
555 config->ups_name = optarg; 525 result.config.ups_name = optarg;
556 break; 526 break;
557 case 'p': /* port */ 527 case 'p': /* port */
558 if (is_intpos(optarg)) { 528 if (is_intpos(optarg)) {
559 config->server_port = atoi(optarg); 529 result.config.server_port = atoi(optarg);
560 } else { 530 } else {
561 usage2(_("Port must be a positive integer"), optarg); 531 usage2(_("Port must be a positive integer"), optarg);
562 } 532 }
563 break; 533 break;
564 case 'c': /* critical time threshold */ 534 case 'c': /* critical time threshold */
565 if (is_intnonneg(optarg)) { 535 if (is_intnonneg(optarg)) {
566 config->critical_value = atoi(optarg); 536 result.config.critical_value = atoi(optarg);
567 config->check_crit = true; 537 result.config.check_crit = true;
568 } else { 538 } else {
569 usage2(_("Critical time must be a positive integer"), optarg); 539 usage2(_("Critical time must be a positive integer"), optarg);
570 } 540 }
571 break; 541 break;
572 case 'w': /* warning time threshold */ 542 case 'w': /* warning time threshold */
573 if (is_intnonneg(optarg)) { 543 if (is_intnonneg(optarg)) {
574 config->warning_value = atoi(optarg); 544 result.config.warning_value = atoi(optarg);
575 config->check_warn = true; 545 result.config.check_warn = true;
576 } else { 546 } else {
577 usage2(_("Warning time must be a positive integer"), optarg); 547 usage2(_("Warning time must be a positive integer"), optarg);
578 } 548 }
579 break; 549 break;
580 case 'v': /* variable */ 550 case 'v': /* variable */
581 if (!strcmp(optarg, "LINE")) { 551 if (!strcmp(optarg, "LINE")) {
582 config->check_variable = UPS_UTILITY; 552 result.config.check_variable = UPS_UTILITY;
583 } else if (!strcmp(optarg, "TEMP")) { 553 } else if (!strcmp(optarg, "TEMP")) {
584 config->check_variable = UPS_TEMP; 554 result.config.check_variable = UPS_TEMP;
585 } else if (!strcmp(optarg, "BATTPCT")) { 555 } else if (!strcmp(optarg, "BATTPCT")) {
586 config->check_variable = UPS_BATTPCT; 556 result.config.check_variable = UPS_BATTPCT;
587 } else if (!strcmp(optarg, "LOADPCT")) { 557 } else if (!strcmp(optarg, "LOADPCT")) {
588 config->check_variable = UPS_LOADPCT; 558 result.config.check_variable = UPS_LOADPCT;
589 } else if (!strcmp(optarg, "REALPOWER")) { 559 } else if (!strcmp(optarg, "REALPOWER")) {
590 config->check_variable = UPS_REALPOWER; 560 result.config.check_variable = UPS_REALPOWER;
591 } else { 561 } else {
592 usage2(_("Unrecognized UPS variable"), optarg); 562 usage2(_("Unrecognized UPS variable"), optarg);
593 } 563 }
@@ -608,27 +578,27 @@ int process_arguments(int argc, char **argv, ups_config *config) {
608 } 578 }
609 } 579 }
610 580
611 if (config->server_address == NULL && argc > optind) { 581 if (result.config.server_address == NULL && argc > optind) {
612 if (is_host(argv[optind])) { 582 if (is_host(argv[optind])) {
613 config->server_address = argv[optind++]; 583 result.config.server_address = argv[optind++];
614 } else { 584 } else {
615 usage2(_("Invalid hostname/address"), optarg); 585 usage2(_("Invalid hostname/address"), optarg);
616 } 586 }
617 } 587 }
618 588
619 if (config->server_address == NULL) { 589 if (result.config.server_address == NULL) {
620 config->server_address = strdup("127.0.0.1"); 590 result.config.server_address = strdup("127.0.0.1");
621 } 591 }
622 592
623 return validate_arguments(*config); 593 return validate_arguments(result);
624} 594}
625 595
626int validate_arguments(ups_config config) { 596check_ups_config_wrapper validate_arguments(check_ups_config_wrapper config_wrapper) {
627 if (!config.ups_name) { 597 if (config_wrapper.config.ups_name) {
628 printf("%s\n", _("Error : no UPS indicated")); 598 printf("%s\n", _("Error : no UPS indicated"));
629 return ERROR; 599 config_wrapper.errorcode = ERROR;
630 } 600 }
631 return OK; 601 return config_wrapper;
632} 602}
633 603
634void print_help(void) { 604void print_help(void) {
diff --git a/plugins/check_ups.d/config.h b/plugins/check_ups.d/config.h
new file mode 100644
index 00000000..353104f2
--- /dev/null
+++ b/plugins/check_ups.d/config.h
@@ -0,0 +1,55 @@
1#pragma once
2
3#include "../../config.h"
4#include <stddef.h>
5
6#define UPS_NONE 0 /* no supported options */
7#define UPS_UTILITY 1 /* supports utility line */
8#define UPS_BATTPCT 2 /* supports percent battery remaining */
9#define UPS_STATUS 4 /* supports UPS status */
10#define UPS_TEMP 8 /* supports UPS temperature */
11#define UPS_LOADPCT 16 /* supports load percent */
12#define UPS_REALPOWER 32 /* supports real power */
13
14#define UPSSTATUS_NONE 0
15#define UPSSTATUS_OFF 1
16#define UPSSTATUS_OL 2
17#define UPSSTATUS_OB 4
18#define UPSSTATUS_LB 8
19#define UPSSTATUS_CAL 16
20#define UPSSTATUS_RB 32 /*Replace Battery */
21#define UPSSTATUS_BYPASS 64
22#define UPSSTATUS_OVER 128
23#define UPSSTATUS_TRIM 256
24#define UPSSTATUS_BOOST 512
25#define UPSSTATUS_CHRG 1024
26#define UPSSTATUS_DISCHRG 2048
27#define UPSSTATUS_UNKNOWN 4096
28#define UPSSTATUS_ALARM 8192
29
30enum {
31 PORT = 3493
32};
33
34typedef struct ups_config {
35 unsigned int server_port;
36 char *server_address;
37 char *ups_name;
38 double warning_value;
39 double critical_value;
40 bool check_warn;
41 bool check_crit;
42 int check_variable;
43 bool temp_output_c;
44} check_ups_config;
45
46check_ups_config check_ups_config_init(void) {
47 check_ups_config tmp = {0};
48 tmp.server_port = PORT;
49 tmp.server_address = NULL;
50 tmp.ups_name = NULL;
51 tmp.check_variable = UPS_NONE;
52
53 return tmp;
54}
55
diff --git a/plugins/negate.c b/plugins/negate.c
index 750c0bfb..0520d298 100644
--- a/plugins/negate.c
+++ b/plugins/negate.c
@@ -38,21 +38,18 @@ const char *email = "devel@monitoring-plugins.org";
38#include "common.h" 38#include "common.h"
39#include "utils.h" 39#include "utils.h"
40#include "utils_cmd.h" 40#include "utils_cmd.h"
41#include "negate.d/config.h"
42#include "../lib/states.h"
41 43
42#include <ctype.h> 44typedef struct {
45 int errorcode;
46 negate_config config;
47} negate_config_wrapper;
48static negate_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
49static negate_config_wrapper validate_arguments(negate_config_wrapper /*config_wrapper*/);
43 50
44static const char **process_arguments(int /*argc*/, char ** /*argv*/);
45static void validate_arguments(char ** /*command_line*/);
46static void print_help(void); 51static void print_help(void);
47void print_usage(void); 52void print_usage(void);
48static bool subst_text = false;
49
50static int state[4] = {
51 STATE_OK,
52 STATE_WARNING,
53 STATE_CRITICAL,
54 STATE_UNKNOWN,
55};
56 53
57int main(int argc, char **argv) { 54int main(int argc, char **argv) {
58 setlocale(LC_ALL, ""); 55 setlocale(LC_ALL, "");
@@ -61,15 +58,24 @@ int main(int argc, char **argv) {
61 58
62 timeout_interval = DEFAULT_TIMEOUT; 59 timeout_interval = DEFAULT_TIMEOUT;
63 60
64 char **command_line = (char **)process_arguments(argc, argv); 61 negate_config_wrapper tmp_config = process_arguments(argc, argv);
62
63 if (tmp_config.errorcode == ERROR) {
64 die(STATE_UNKNOWN, _("negate: Failed to parse input"));
65 }
66
67 negate_config config = tmp_config.config;
68
69 char **command_line = config.command_line;
65 70
66 /* Set signal handling and alarm */ 71 /* Set signal handling and alarm */
67 if (signal(SIGALRM, timeout_alarm_handler) == SIG_ERR) 72 if (signal(SIGALRM, timeout_alarm_handler) == SIG_ERR) {
68 die(STATE_UNKNOWN, _("Cannot catch SIGALRM")); 73 die(STATE_UNKNOWN, _("Cannot catch SIGALRM"));
74 }
69 75
70 (void)alarm((unsigned)timeout_interval); 76 (void)alarm(timeout_interval);
71 77
72 int result = STATE_UNKNOWN; 78 mp_state_enum result = STATE_UNKNOWN;
73 output chld_out; 79 output chld_out;
74 output chld_err; 80 output chld_err;
75 81
@@ -86,46 +92,52 @@ int main(int argc, char **argv) {
86 } 92 }
87 93
88 /* Return UNKNOWN or worse if no output is returned */ 94 /* Return UNKNOWN or worse if no output is returned */
89 if (chld_out.lines == 0) 95 if (chld_out.lines == 0) {
90 die(max_state_alt(result, STATE_UNKNOWN), _("No data returned from command\n")); 96 die(max_state_alt(result, STATE_UNKNOWN), _("No data returned from command\n"));
97 }
91 98
92 char *sub; 99 char *sub;
93 for (size_t i = 0; i < chld_out.lines; i++) { 100 for (size_t i = 0; i < chld_out.lines; i++) {
94 if (subst_text && result >= 0 && result <= 4 && result != state[result]) { 101 if (config.subst_text && result >= 0 && result <= 4 && result != config.state[result]) {
95 /* Loop over each match found */ 102 /* Loop over each match found */
96 while ((sub = strstr(chld_out.line[i], state_text(result)))) { 103 while ((sub = strstr(chld_out.line[i], state_text(result)))) {
97 /* Terminate the first part and skip over the string we'll substitute */ 104 /* Terminate the first part and skip over the string we'll substitute */
98 *sub = '\0'; 105 *sub = '\0';
99 sub += strlen(state_text(result)); 106 sub += strlen(state_text(result));
100 /* then put everything back together */ 107 /* then put everything back together */
101 xasprintf(&chld_out.line[i], "%s%s%s", chld_out.line[i], state_text(state[result]), sub); 108 xasprintf(&chld_out.line[i], "%s%s%s", chld_out.line[i], state_text(config.state[result]), sub);
102 } 109 }
103 } 110 }
104 printf("%s\n", chld_out.line[i]); 111 printf("%s\n", chld_out.line[i]);
105 } 112 }
106 113
107 if (result >= 0 && result <= 4) { 114 if (result >= 0 && result <= 4) {
108 exit(state[result]); 115 exit(config.state[result]);
109 } else { 116 } else {
110 exit(result); 117 exit(result);
111 } 118 }
112} 119}
113 120
114/* process command-line arguments */ 121/* process command-line arguments */
115static const char **process_arguments(int argc, char **argv) { 122static negate_config_wrapper process_arguments(int argc, char **argv) {
116 static struct option longopts[] = {{"help", no_argument, 0, 'h'}, {"version", no_argument, 0, 'V'}, 123 static struct option longopts[] = {{"help", no_argument, 0, 'h'}, {"version", no_argument, 0, 'V'},
117 {"timeout", required_argument, 0, 't'}, {"timeout-result", required_argument, 0, 'T'}, 124 {"timeout", required_argument, 0, 't'}, {"timeout-result", required_argument, 0, 'T'},
118 {"ok", required_argument, 0, 'o'}, {"warning", required_argument, 0, 'w'}, 125 {"ok", required_argument, 0, 'o'}, {"warning", required_argument, 0, 'w'},
119 {"critical", required_argument, 0, 'c'}, {"unknown", required_argument, 0, 'u'}, 126 {"critical", required_argument, 0, 'c'}, {"unknown", required_argument, 0, 'u'},
120 {"substitute", no_argument, 0, 's'}, {0, 0, 0, 0}}; 127 {"substitute", no_argument, 0, 's'}, {0, 0, 0, 0}};
121 128
129 negate_config_wrapper result = {
130 .errorcode = OK,
131 .config = negate_config_init(),
132 };
122 bool permute = true; 133 bool permute = true;
123 while (true) { 134 while (true) {
124 int option = 0; 135 int option = 0;
125 int option_char = getopt_long(argc, argv, "+hVt:T:o:w:c:u:s", longopts, &option); 136 int option_char = getopt_long(argc, argv, "+hVt:T:o:w:c:u:s", longopts, &option);
126 137
127 if (option_char == -1 || option_char == EOF) 138 if (option_char == -1 || option_char == EOF) {
128 break; 139 break;
140 }
129 141
130 switch (option_char) { 142 switch (option_char) {
131 case '?': /* help */ 143 case '?': /* help */
@@ -139,58 +151,68 @@ static const char **process_arguments(int argc, char **argv) {
139 print_revision(progname, NP_VERSION); 151 print_revision(progname, NP_VERSION);
140 exit(STATE_UNKNOWN); 152 exit(STATE_UNKNOWN);
141 case 't': /* timeout period */ 153 case 't': /* timeout period */
142 if (!is_integer(optarg)) 154 if (!is_integer(optarg)) {
143 usage2(_("Timeout interval must be a positive integer"), optarg); 155 usage2(_("Timeout interval must be a positive integer"), optarg);
144 else 156 } else {
145 timeout_interval = atoi(optarg); 157 timeout_interval = atoi(optarg);
158 }
146 break; 159 break;
147 case 'T': /* Result to return on timeouts */ 160 case 'T': /* Result to return on timeouts */
148 if ((timeout_state = mp_translate_state(optarg)) == ERROR) 161 if ((timeout_state = mp_translate_state(optarg)) == ERROR) {
149 usage4(_("Timeout result must be a valid state name (OK, WARNING, CRITICAL, UNKNOWN) or integer (0-3).")); 162 usage4(_("Timeout result must be a valid state name (OK, WARNING, CRITICAL, UNKNOWN) or integer (0-3)."));
163 }
150 break; 164 break;
151 case 'o': /* replacement for OK */ 165 case 'o': /* replacement for OK */
152 if ((state[STATE_OK] = mp_translate_state(optarg)) == ERROR) 166 if ((result.config.state[STATE_OK] = mp_translate_state(optarg)) == ERROR) {
153 usage4(_("Ok must be a valid state name (OK, WARNING, CRITICAL, UNKNOWN) or integer (0-3).")); 167 usage4(_("Ok must be a valid state name (OK, WARNING, CRITICAL, UNKNOWN) or integer (0-3)."));
168 }
154 permute = false; 169 permute = false;
155 break; 170 break;
156 171
157 case 'w': /* replacement for WARNING */ 172 case 'w': /* replacement for WARNING */
158 if ((state[STATE_WARNING] = mp_translate_state(optarg)) == ERROR) 173 if ((result.config.state[STATE_WARNING] = mp_translate_state(optarg)) == ERROR) {
159 usage4(_("Warning must be a valid state name (OK, WARNING, CRITICAL, UNKNOWN) or integer (0-3).")); 174 usage4(_("Warning must be a valid state name (OK, WARNING, CRITICAL, UNKNOWN) or integer (0-3)."));
175 }
160 permute = false; 176 permute = false;
161 break; 177 break;
162 case 'c': /* replacement for CRITICAL */ 178 case 'c': /* replacement for CRITICAL */
163 if ((state[STATE_CRITICAL] = mp_translate_state(optarg)) == ERROR) 179 if ((result.config.state[STATE_CRITICAL] = mp_translate_state(optarg)) == ERROR) {
164 usage4(_("Critical must be a valid state name (OK, WARNING, CRITICAL, UNKNOWN) or integer (0-3).")); 180 usage4(_("Critical must be a valid state name (OK, WARNING, CRITICAL, UNKNOWN) or integer (0-3)."));
181 }
165 permute = false; 182 permute = false;
166 break; 183 break;
167 case 'u': /* replacement for UNKNOWN */ 184 case 'u': /* replacement for UNKNOWN */
168 if ((state[STATE_UNKNOWN] = mp_translate_state(optarg)) == ERROR) 185 if ((result.config.state[STATE_UNKNOWN] = mp_translate_state(optarg)) == ERROR) {
169 usage4(_("Unknown must be a valid state name (OK, WARNING, CRITICAL, UNKNOWN) or integer (0-3).")); 186 usage4(_("Unknown must be a valid state name (OK, WARNING, CRITICAL, UNKNOWN) or integer (0-3)."));
187 }
170 permute = false; 188 permute = false;
171 break; 189 break;
172 case 's': /* Substitute status text */ 190 case 's': /* Substitute status text */
173 subst_text = true; 191 result.config.subst_text = true;
174 break; 192 break;
175 } 193 }
176 } 194 }
177 195
178 validate_arguments(&argv[optind]);
179
180 if (permute) { /* No [owcu] switch specified, default to this */ 196 if (permute) { /* No [owcu] switch specified, default to this */
181 state[STATE_OK] = STATE_CRITICAL; 197 result.config.state[STATE_OK] = STATE_CRITICAL;
182 state[STATE_CRITICAL] = STATE_OK; 198 result.config.state[STATE_CRITICAL] = STATE_OK;
183 } 199 }
184 200
185 return (const char **)&argv[optind]; 201 result.config.command_line = &argv[optind];
202
203 return validate_arguments(result);
186} 204}
187 205
188void validate_arguments(char **command_line) { 206negate_config_wrapper validate_arguments(negate_config_wrapper config_wrapper) {
189 if (command_line[0] == NULL) 207 if (config_wrapper.config.command_line[0] == NULL) {
190 usage4(_("Could not parse arguments")); 208 usage4(_("Could not parse arguments"));
209 }
191 210
192 if (strncmp(command_line[0], "/", 1) != 0 && strncmp(command_line[0], "./", 2) != 0) 211 if (strncmp(config_wrapper.config.command_line[0], "/", 1) != 0 && strncmp(config_wrapper.config.command_line[0], "./", 2) != 0) {
193 usage4(_("Require path to command")); 212 usage4(_("Require path to command"));
213 }
214
215 return config_wrapper;
194} 216}
195 217
196void print_help(void) { 218void print_help(void) {
diff --git a/plugins/negate.d/config.h b/plugins/negate.d/config.h
new file mode 100644
index 00000000..0cf30cd4
--- /dev/null
+++ b/plugins/negate.d/config.h
@@ -0,0 +1,24 @@
1#pragma once
2
3#include "states.h"
4
5typedef struct {
6 mp_state_enum state[4];
7 bool subst_text;
8 char **command_line;
9} negate_config;
10
11negate_config negate_config_init() {
12 negate_config tmp = {
13 .state =
14 {
15 STATE_OK,
16 STATE_WARNING,
17 STATE_CRITICAL,
18 STATE_UNKNOWN,
19 },
20 .subst_text = false,
21 .command_line = NULL,
22 };
23 return tmp;
24}
diff --git a/plugins/t/check_ftp.t b/plugins/t/check_ftp.t
index 93a7d7c3..a2f79dca 100644
--- a/plugins/t/check_ftp.t
+++ b/plugins/t/check_ftp.t
@@ -15,7 +15,7 @@ my $host_tcp_ftp = getTestParameter("NP_HOST_TCP_FTP", "A host providing t
15my $host_nonresponsive = getTestParameter("NP_HOST_NONRESPONSIVE", "The hostname of system not responsive to network requests", "10.0.0.1"); 15my $host_nonresponsive = getTestParameter("NP_HOST_NONRESPONSIVE", "The hostname of system not responsive to network requests", "10.0.0.1");
16my $hostname_invalid = getTestParameter("NP_HOSTNAME_INVALID", "An invalid (not known to DNS) hostname", "nosuchhost"); 16my $hostname_invalid = getTestParameter("NP_HOSTNAME_INVALID", "An invalid (not known to DNS) hostname", "nosuchhost");
17 17
18my $successOutput = '/FTP OK -\s+[0-9]?\.?[0-9]+ second response time/'; 18my $successOutput = '/Connection time\s+[0-9]?\.?[0-9]+/';
19 19
20my $t; 20my $t;
21 21
diff --git a/plugins/t/check_jabber.t b/plugins/t/check_jabber.t
index 08cadcbd..dc46f4c3 100644
--- a/plugins/t/check_jabber.t
+++ b/plugins/t/check_jabber.t
@@ -15,11 +15,11 @@ my $host_nonresponsive = getTestParameter("NP_HOST_NONRESPONSIVE", "The hostname
15my $hostname_invalid = getTestParameter("NP_HOSTNAME_INVALID", "An invalid (not known to DNS) hostname", "nosuchhost"); 15my $hostname_invalid = getTestParameter("NP_HOSTNAME_INVALID", "An invalid (not known to DNS) hostname", "nosuchhost");
16 16
17 17
18my $jabberOK = '/JABBER OK\s-\s\d+\.\d+\ssecond response time on '.$host_tcp_jabber.' port 5222/'; 18my $jabberOK = '/Connection to '.$host_tcp_jabber.' on port 5222/';
19 19
20my $jabberUnresponsive = '/Socket timeout after\s\d+\sseconds/'; 20my $jabberUnresponsive = '/Socket timeout after\s\d+\sseconds/';
21 21
22my $jabberInvalid = '/JABBER CRITICAL - Invalid hostname, address or socket:\s.+/'; 22my $jabberInvalid = '/Invalid hostname, address or socket:\s.+/';
23 23
24my $r; 24my $r;
25 25
diff --git a/plugins/t/check_tcp.t b/plugins/t/check_tcp.t
index cb4de53d..5c8fd0be 100644
--- a/plugins/t/check_tcp.t
+++ b/plugins/t/check_tcp.t
@@ -21,19 +21,19 @@ my $host_nonresponsive = getTestParameter("NP_HOST_NONRESPONSIVE", "The hostname
21my $hostname_invalid = getTestParameter("NP_HOSTNAME_INVALID", "An invalid (not known to DNS) hostname", "nosuchhost"); 21my $hostname_invalid = getTestParameter("NP_HOSTNAME_INVALID", "An invalid (not known to DNS) hostname", "nosuchhost");
22my $internet_access = getTestParameter("NP_INTERNET_ACCESS", "Is this system directly connected to the internet?", "yes"); 22my $internet_access = getTestParameter("NP_INTERNET_ACCESS", "Is this system directly connected to the internet?", "yes");
23 23
24my $successOutput = '/^TCP OK\s-\s+[0-9]?\.?[0-9]+ second response time on port [0-9]+/'; 24my $successOutput = '/Connection time\s+[0-9]?\.?[0-9]+s is within thresholds+/';
25 25
26my $failedExpect = '/^TCP WARNING\s-\sUnexpected response from host/socket on port [0-9]+/'; 26my $failedExpect = '/Answer failed to match/';
27 27
28my $t; 28my $t;
29 29
30$tests = $tests - 4 if $internet_access eq "no"; 30$tests = $tests - 4 if $internet_access eq "no";
31plan tests => $tests; 31plan tests => $tests;
32 32
33$t += checkCmd( "./check_tcp $host_tcp_http -p 80 -wt 300 -ct 600", 0, $successOutput ); 33$t += checkCmd( "./check_tcp $host_tcp_http -p 80 -w 300 -c 600", 0, $successOutput );
34$t += checkCmd( "./check_tcp $host_tcp_http -p 81 -wt 0 -ct 0 -to 1", 2 ); # use invalid port for this test 34$t += checkCmd( "./check_tcp $host_tcp_http -p 81 -w 0 -c 0 -t 1", 2 ); # use invalid port for this test
35$t += checkCmd( "./check_tcp $host_nonresponsive -p 80 -wt 0 -ct 0 -to 1", 2 ); 35$t += checkCmd( "./check_tcp $host_nonresponsive -p 80 -w 0 -c 0 -t 1", 2 );
36$t += checkCmd( "./check_tcp $hostname_invalid -p 80 -wt 0 -ct 0 -to 1", 2 ); 36$t += checkCmd( "./check_tcp $hostname_invalid -p 80 -w 0 -c 0 -t 1", 2 );
37if($internet_access ne "no") { 37if($internet_access ne "no") {
38 $t += checkCmd( "./check_tcp -S -D 1 -H $host_tls_http -p 443", 0 ); 38 $t += checkCmd( "./check_tcp -S -D 1 -H $host_tls_http -p 443", 0 );
39 $t += checkCmd( "./check_tcp -S -D 9000,1 -H $host_tls_http -p 443", 1 ); 39 $t += checkCmd( "./check_tcp -S -D 9000,1 -H $host_tls_http -p 443", 1 );
diff --git a/plugins/t/check_udp.t b/plugins/t/check_udp.t
index 6c47d095..5cb9e6dc 100644
--- a/plugins/t/check_udp.t
+++ b/plugins/t/check_udp.t
@@ -28,7 +28,7 @@ like ( $res->output, '/With UDP checks, a send/expect string must be specified.
28 28
29$res = NPTest->testCmd( "./check_udp -H localhost -p 3333 -s foo -e bar" ); 29$res = NPTest->testCmd( "./check_udp -H localhost -p 3333 -s foo -e bar" );
30cmp_ok( $res->return_code, '==', 2, "Errors correctly because no udp service running" ); 30cmp_ok( $res->return_code, '==', 2, "Errors correctly because no udp service running" );
31like ( $res->output, '/No data received from host/', "Output OK"); 31like ( $res->output, '/Received no data /', "Output OK");
32 32
33my $nc; 33my $nc;
34if(system("which nc.traditional >/dev/null 2>&1") == 0) { 34if(system("which nc.traditional >/dev/null 2>&1") == 0) {
@@ -48,7 +48,7 @@ SKIP: {
48 sleep 1; 48 sleep 1;
49 $res = NPTest->testCmd( "./check_udp -H localhost -p 3333 -s '' -e barbar -4" ); 49 $res = NPTest->testCmd( "./check_udp -H localhost -p 3333 -s '' -e barbar -4" );
50 cmp_ok( $res->return_code, '==', 0, "Got barbar response back" ); 50 cmp_ok( $res->return_code, '==', 0, "Got barbar response back" );
51 like ( $res->output, '/\[barbar\]/', "Output OK"); 51 like ( $res->output, '/answer of the server matched/', "Output OK");
52 close NC; 52 close NC;
53 53
54 # Start up a udp server listening on port 3333, quit after 3 seconds 54 # Start up a udp server listening on port 3333, quit after 3 seconds