summaryrefslogtreecommitdiffstats
path: root/plugins/check_dbi.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/check_dbi.c')
-rw-r--r--plugins/check_dbi.c445
1 files changed, 239 insertions, 206 deletions
diff --git a/plugins/check_dbi.c b/plugins/check_dbi.c
index 96575672..9efcd1cb 100644
--- a/plugins/check_dbi.c
+++ b/plugins/check_dbi.c
@@ -33,6 +33,8 @@ const char *progname = "check_dbi";
33const char *copyright = "2011-2024"; 33const char *copyright = "2011-2024";
34const char *email = "devel@monitoring-plugins.org"; 34const char *email = "devel@monitoring-plugins.org";
35 35
36#include "../lib/monitoringplug.h"
37#include "check_dbi.d/config.h"
36#include "common.h" 38#include "common.h"
37#include "utils.h" 39#include "utils.h"
38#include "utils_cmd.h" 40#include "utils_cmd.h"
@@ -53,55 +55,24 @@ const char *email = "devel@monitoring-plugins.org";
53 55
54#include <stdarg.h> 56#include <stdarg.h>
55 57
56typedef enum {
57 METRIC_CONN_TIME,
58 METRIC_SERVER_VERSION,
59 METRIC_QUERY_RESULT,
60 METRIC_QUERY_TIME,
61} np_dbi_metric_t;
62
63typedef enum {
64 TYPE_NUMERIC,
65 TYPE_STRING,
66} np_dbi_type_t;
67
68typedef struct {
69 char *key;
70 char *value;
71} driver_option_t;
72
73static char *host = NULL;
74static int verbose = 0; 58static int verbose = 0;
75 59
76static char *warning_range = NULL; 60typedef struct {
77static char *critical_range = NULL; 61 int errorcode;
78static thresholds *dbi_thresholds = NULL; 62 check_dbi_config config;
79 63} check_dbi_config_wrapper;
80static char *expect = NULL;
81
82static regex_t expect_re;
83static char *expect_re_str = NULL;
84static int expect_re_cflags = 0;
85
86static np_dbi_metric_t metric = METRIC_QUERY_RESULT;
87static np_dbi_type_t type = TYPE_NUMERIC;
88
89static char *np_dbi_driver = NULL;
90static driver_option_t *np_dbi_options = NULL;
91static int np_dbi_options_num = 0;
92static char *np_dbi_database = NULL;
93static char *np_dbi_query = NULL;
94 64
95static int process_arguments(int, char **); 65static check_dbi_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
96static int validate_arguments(void); 66static check_dbi_config_wrapper validate_arguments(check_dbi_config_wrapper /*config_wrapper*/);
97void print_usage(void); 67void print_usage(void);
98static void print_help(void); 68static void print_help(void);
99 69
100static double timediff(struct timeval, struct timeval); 70static double timediff(struct timeval /*start*/, struct timeval /*end*/);
101 71
102static void np_dbi_print_error(dbi_conn, char *, ...); 72static void np_dbi_print_error(dbi_conn /*conn*/, char * /*fmt*/, ...);
103 73
104static int do_query(dbi_conn, const char **, double *, double *); 74static mp_state_enum do_query(dbi_conn /*conn*/, const char ** /*res_val_str*/, double * /*res_val*/, double * /*res_time*/, mp_dbi_metric /*metric*/,
75 mp_dbi_type /*type*/, char * /*np_dbi_query*/);
105 76
106int main(int argc, char **argv) { 77int main(int argc, char **argv) {
107 int status = STATE_UNKNOWN; 78 int status = STATE_UNKNOWN;
@@ -119,8 +90,6 @@ int main(int argc, char **argv) {
119 const char *query_val_str = NULL; 90 const char *query_val_str = NULL;
120 double query_val = 0.0; 91 double query_val = 0.0;
121 92
122 int i;
123
124 setlocale(LC_ALL, ""); 93 setlocale(LC_ALL, "");
125 bindtextdomain(PACKAGE, LOCALEDIR); 94 bindtextdomain(PACKAGE, LOCALEDIR);
126 textdomain(PACKAGE); 95 textdomain(PACKAGE);
@@ -128,8 +97,13 @@ int main(int argc, char **argv) {
128 /* Parse extra opts if any */ 97 /* Parse extra opts if any */
129 argv = np_extra_opts(&argc, argv, progname); 98 argv = np_extra_opts(&argc, argv, progname);
130 99
131 if (process_arguments(argc, argv) == ERROR) 100 check_dbi_config_wrapper tmp = process_arguments(argc, argv);
101
102 if (tmp.errorcode == ERROR) {
132 usage4(_("Could not parse arguments")); 103 usage4(_("Could not parse arguments"));
104 }
105
106 const check_dbi_config config = tmp.config;
133 107
134 /* Set signal handling and alarm */ 108 /* Set signal handling and alarm */
135 if (signal(SIGALRM, timeout_alarm_handler) == SIG_ERR) { 109 if (signal(SIGALRM, timeout_alarm_handler) == SIG_ERR) {
@@ -137,8 +111,9 @@ int main(int argc, char **argv) {
137 } 111 }
138 alarm(timeout_interval); 112 alarm(timeout_interval);
139 113
140 if (verbose > 2) 114 if (verbose > 2) {
141 printf("Initializing DBI\n"); 115 printf("Initializing DBI\n");
116 }
142 117
143 dbi_inst *instance_p = {0}; 118 dbi_inst *instance_p = {0};
144 119
@@ -152,12 +127,13 @@ int main(int argc, char **argv) {
152 return STATE_UNKNOWN; 127 return STATE_UNKNOWN;
153 } 128 }
154 129
155 if (verbose) 130 if (verbose) {
156 printf("Opening DBI driver '%s'\n", np_dbi_driver); 131 printf("Opening DBI driver '%s'\n", config.dbi_driver);
132 }
157 133
158 driver = dbi_driver_open_r(np_dbi_driver, instance_p); 134 driver = dbi_driver_open_r(config.dbi_driver, instance_p);
159 if (!driver) { 135 if (!driver) {
160 printf("UNKNOWN - failed to open DBI driver '%s'; possibly it's not installed.\n", np_dbi_driver); 136 printf("UNKNOWN - failed to open DBI driver '%s'; possibly it's not installed.\n", config.dbi_driver);
161 137
162 printf("Known drivers:\n"); 138 printf("Known drivers:\n");
163 for (driver = dbi_driver_list_r(NULL, instance_p); driver; driver = dbi_driver_list_r(driver, instance_p)) { 139 for (driver = dbi_driver_list_r(NULL, instance_p); driver; driver = dbi_driver_list_r(driver, instance_p)) {
@@ -176,17 +152,19 @@ int main(int argc, char **argv) {
176 return STATE_UNKNOWN; 152 return STATE_UNKNOWN;
177 } 153 }
178 154
179 for (i = 0; i < np_dbi_options_num; ++i) { 155 for (size_t i = 0; i < config.dbi_options_num; ++i) {
180 const char *opt; 156 const char *opt;
181 157
182 if (verbose > 1) 158 if (verbose > 1) {
183 printf("Setting DBI driver option '%s' to '%s'\n", np_dbi_options[i].key, np_dbi_options[i].value); 159 printf("Setting DBI driver option '%s' to '%s'\n", config.dbi_options[i].key, config.dbi_options[i].value);
160 }
184 161
185 if (!dbi_conn_set_option(conn, np_dbi_options[i].key, np_dbi_options[i].value)) 162 if (!dbi_conn_set_option(conn, config.dbi_options[i].key, config.dbi_options[i].value)) {
186 continue; 163 continue;
164 }
187 /* else: status != 0 */ 165 /* else: status != 0 */
188 166
189 np_dbi_print_error(conn, "UNKNOWN - failed to set option '%s' to '%s'", np_dbi_options[i].key, np_dbi_options[i].value); 167 np_dbi_print_error(conn, "UNKNOWN - failed to set option '%s' to '%s'", config.dbi_options[i].key, config.dbi_options[i].value);
190 printf("Known driver options:\n"); 168 printf("Known driver options:\n");
191 169
192 for (opt = dbi_conn_get_option_list(conn, NULL); opt; opt = dbi_conn_get_option_list(conn, opt)) { 170 for (opt = dbi_conn_get_option_list(conn, NULL); opt; opt = dbi_conn_get_option_list(conn, opt)) {
@@ -196,10 +174,11 @@ int main(int argc, char **argv) {
196 return STATE_UNKNOWN; 174 return STATE_UNKNOWN;
197 } 175 }
198 176
199 if (host) { 177 if (config.host) {
200 if (verbose > 1) 178 if (verbose > 1) {
201 printf("Setting DBI driver option 'host' to '%s'\n", host); 179 printf("Setting DBI driver option 'host' to '%s'\n", config.host);
202 dbi_conn_set_option(conn, "host", host); 180 }
181 dbi_conn_set_option(conn, "host", config.host);
203 } 182 }
204 183
205 if (verbose) { 184 if (verbose) {
@@ -209,10 +188,12 @@ int main(int argc, char **argv) {
209 dbname = dbi_conn_get_option(conn, "dbname"); 188 dbname = dbi_conn_get_option(conn, "dbname");
210 host = dbi_conn_get_option(conn, "host"); 189 host = dbi_conn_get_option(conn, "host");
211 190
212 if (!dbname) 191 if (!dbname) {
213 dbname = "<unspecified>"; 192 dbname = "<unspecified>";
214 if (!host) 193 }
194 if (!host) {
215 host = "<unspecified>"; 195 host = "<unspecified>";
196 }
216 197
217 printf("Connecting to database '%s' at host '%s'\n", dbname, host); 198 printf("Connecting to database '%s' at host '%s'\n", dbname, host);
218 } 199 }
@@ -226,109 +207,122 @@ int main(int argc, char **argv) {
226 conn_time = timediff(start_timeval, end_timeval); 207 conn_time = timediff(start_timeval, end_timeval);
227 208
228 server_version = dbi_conn_get_engine_version(conn); 209 server_version = dbi_conn_get_engine_version(conn);
229 if (verbose) 210 if (verbose) {
230 printf("Connected to server version %u\n", server_version); 211 printf("Connected to server version %u\n", server_version);
212 }
231 213
232 if (metric == METRIC_SERVER_VERSION) 214 if (config.metric == METRIC_SERVER_VERSION) {
233 status = get_status(server_version, dbi_thresholds); 215 status = get_status(server_version, config.dbi_thresholds);
216 }
234 217
235 if (verbose) 218 if (verbose) {
236 printf("Time elapsed: %f\n", conn_time); 219 printf("Time elapsed: %f\n", conn_time);
220 }
237 221
238 if (metric == METRIC_CONN_TIME) 222 if (config.metric == METRIC_CONN_TIME) {
239 status = get_status(conn_time, dbi_thresholds); 223 status = get_status(conn_time, config.dbi_thresholds);
224 }
240 225
241 /* select a database */ 226 /* select a database */
242 if (np_dbi_database) { 227 if (config.dbi_database) {
243 if (verbose > 1) 228 if (verbose > 1) {
244 printf("Selecting database '%s'\n", np_dbi_database); 229 printf("Selecting database '%s'\n", config.dbi_database);
230 }
245 231
246 if (dbi_conn_select_db(conn, np_dbi_database)) { 232 if (dbi_conn_select_db(conn, config.dbi_database)) {
247 np_dbi_print_error(conn, "UNKNOWN - failed to select database '%s'", np_dbi_database); 233 np_dbi_print_error(conn, "UNKNOWN - failed to select database '%s'", config.dbi_database);
248 return STATE_UNKNOWN; 234 return STATE_UNKNOWN;
249 } 235 }
250 } 236 }
251 237
252 if (np_dbi_query) { 238 if (config.dbi_query) {
253 /* execute query */ 239 /* execute query */
254 status = do_query(conn, &query_val_str, &query_val, &query_time); 240 status = do_query(conn, &query_val_str, &query_val, &query_time, config.metric, config.type, config.dbi_query);
255 if (status != STATE_OK) 241 if (status != STATE_OK) {
256 /* do_query prints an error message in this case */ 242 /* do_query prints an error message in this case */
257 return status; 243 return status;
244 }
258 245
259 if (metric == METRIC_QUERY_RESULT) { 246 if (config.metric == METRIC_QUERY_RESULT) {
260 if (expect) { 247 if (config.expect) {
261 if ((!query_val_str) || strcmp(query_val_str, expect)) 248 if ((!query_val_str) || strcmp(query_val_str, config.expect)) {
262 status = STATE_CRITICAL; 249 status = STATE_CRITICAL;
263 else 250 } else {
264 status = STATE_OK; 251 status = STATE_OK;
265 } else if (expect_re_str) { 252 }
253 } else if (config.expect_re_str) {
266 int err; 254 int err;
267 255
256 regex_t expect_re = {};
268 err = regexec(&expect_re, query_val_str, 0, NULL, /* flags = */ 0); 257 err = regexec(&expect_re, query_val_str, 0, NULL, /* flags = */ 0);
269 if (!err) 258 if (!err) {
270 status = STATE_OK; 259 status = STATE_OK;
271 else if (err == REG_NOMATCH) 260 } else if (err == REG_NOMATCH) {
272 status = STATE_CRITICAL; 261 status = STATE_CRITICAL;
273 else { 262 } else {
274 char errmsg[1024]; 263 char errmsg[1024];
275 regerror(err, &expect_re, errmsg, sizeof(errmsg)); 264 regerror(err, &expect_re, errmsg, sizeof(errmsg));
276 printf("ERROR - failed to execute regular expression: %s\n", errmsg); 265 printf("ERROR - failed to execute regular expression: %s\n", errmsg);
277 status = STATE_CRITICAL; 266 status = STATE_CRITICAL;
278 } 267 }
279 } else 268 } else {
280 status = get_status(query_val, dbi_thresholds); 269 status = get_status(query_val, config.dbi_thresholds);
281 } else if (metric == METRIC_QUERY_TIME) 270 }
282 status = get_status(query_time, dbi_thresholds); 271 } else if (config.metric == METRIC_QUERY_TIME) {
272 status = get_status(query_time, config.dbi_thresholds);
273 }
283 } 274 }
284 275
285 if (verbose) 276 if (verbose) {
286 printf("Closing connection\n"); 277 printf("Closing connection\n");
278 }
287 dbi_conn_close(conn); 279 dbi_conn_close(conn);
288 280
289 /* In case of METRIC_QUERY_RESULT, isnan(query_val) indicates an error 281 /* In case of METRIC_QUERY_RESULT, isnan(query_val) indicates an error
290 * which should have been reported and handled (abort) before 282 * which should have been reported and handled (abort) before
291 * ... unless we expected a string to be returned */ 283 * ... unless we expected a string to be returned */
292 assert((metric != METRIC_QUERY_RESULT) || (!isnan(query_val)) || (type == TYPE_STRING)); 284 assert((config.metric != METRIC_QUERY_RESULT) || (!isnan(query_val)) || (config.type == TYPE_STRING));
293 285
294 assert((type != TYPE_STRING) || (expect || expect_re_str)); 286 assert((config.type != TYPE_STRING) || (config.expect || config.expect_re_str));
295 287
296 printf("%s - connection time: %fs", state_text(status), conn_time); 288 printf("%s - connection time: %fs", state_text(status), conn_time);
297 if (np_dbi_query) { 289 if (config.dbi_query) {
298 if (type == TYPE_STRING) { 290 if (config.type == TYPE_STRING) {
299 assert(expect || expect_re_str); 291 assert(config.expect || config.expect_re_str);
300 printf(", '%s' returned '%s' in %fs", np_dbi_query, query_val_str ? query_val_str : "<nothing>", query_time); 292 printf(", '%s' returned '%s' in %fs", config.dbi_query, query_val_str ? query_val_str : "<nothing>", query_time);
301 if (status != STATE_OK) { 293 if (status != STATE_OK) {
302 if (expect) 294 if (config.expect) {
303 printf(" (expected '%s')", expect); 295 printf(" (expected '%s')", config.expect);
304 else if (expect_re_str) 296 } else if (config.expect_re_str) {
305 printf(" (expected regex /%s/%s)", expect_re_str, ((expect_re_cflags & REG_ICASE) ? "i" : "")); 297 printf(" (expected regex /%s/%s)", config.expect_re_str, ((config.expect_re_cflags & REG_ICASE) ? "i" : ""));
298 }
306 } 299 }
307 } else if (isnan(query_val)) 300 } else if (isnan(query_val)) {
308 printf(", '%s' query execution time: %fs", np_dbi_query, query_time); 301 printf(", '%s' query execution time: %fs", config.dbi_query, query_time);
309 else 302 } else {
310 printf(", '%s' returned %f in %fs", np_dbi_query, query_val, query_time); 303 printf(", '%s' returned %f in %fs", config.dbi_query, query_val, query_time);
304 }
311 } 305 }
312 306
313 printf(" | conntime=%fs;%s;%s;0; server_version=%u;%s;%s;0;", conn_time, 307 printf(" | conntime=%fs;%s;%s;0; server_version=%u;%s;%s;0;", conn_time,
314 ((metric == METRIC_CONN_TIME) && warning_range) ? warning_range : "", 308 ((config.metric == METRIC_CONN_TIME) && config.warning_range) ? config.warning_range : "",
315 ((metric == METRIC_CONN_TIME) && critical_range) ? critical_range : "", server_version, 309 ((config.metric == METRIC_CONN_TIME) && config.critical_range) ? config.critical_range : "", server_version,
316 ((metric == METRIC_SERVER_VERSION) && warning_range) ? warning_range : "", 310 ((config.metric == METRIC_SERVER_VERSION) && config.warning_range) ? config.warning_range : "",
317 ((metric == METRIC_SERVER_VERSION) && critical_range) ? critical_range : ""); 311 ((config.metric == METRIC_SERVER_VERSION) && config.critical_range) ? config.critical_range : "");
318 if (np_dbi_query) { 312 if (config.dbi_query) {
319 if (!isnan(query_val)) /* this is also true when -e is used */ 313 if (!isnan(query_val)) { /* this is also true when -e is used */
320 printf(" query=%f;%s;%s;;", query_val, ((metric == METRIC_QUERY_RESULT) && warning_range) ? warning_range : "", 314 printf(" query=%f;%s;%s;;", query_val, ((config.metric == METRIC_QUERY_RESULT) && config.warning_range) ? config.warning_range : "",
321 ((metric == METRIC_QUERY_RESULT) && critical_range) ? critical_range : ""); 315 ((config.metric == METRIC_QUERY_RESULT) && config.critical_range) ? config.critical_range : "");
322 printf(" querytime=%fs;%s;%s;0;", query_time, ((metric == METRIC_QUERY_TIME) && warning_range) ? warning_range : "", 316 }
323 ((metric == METRIC_QUERY_TIME) && critical_range) ? critical_range : ""); 317 printf(" querytime=%fs;%s;%s;0;", query_time, ((config.metric == METRIC_QUERY_TIME) && config.warning_range) ? config.warning_range : "",
318 ((config.metric == METRIC_QUERY_TIME) && config.critical_range) ? config.critical_range : "");
324 } 319 }
325 printf("\n"); 320 printf("\n");
326 return status; 321 return status;
327} 322}
328 323
329/* process command-line arguments */ 324/* process command-line arguments */
330int process_arguments(int argc, char **argv) { 325check_dbi_config_wrapper process_arguments(int argc, char **argv) {
331 int c;
332 326
333 int option = 0; 327 int option = 0;
334 static struct option longopts[] = {STD_LONG_OPTS, 328 static struct option longopts[] = {STD_LONG_OPTS,
@@ -343,13 +337,19 @@ int process_arguments(int argc, char **argv) {
343 {"database", required_argument, 0, 'D'}, 337 {"database", required_argument, 0, 'D'},
344 {0, 0, 0, 0}}; 338 {0, 0, 0, 0}};
345 339
346 while (1) { 340 check_dbi_config_wrapper result = {
347 c = getopt_long(argc, argv, "Vvht:c:w:e:r:R:m:H:d:o:q:D:", longopts, &option); 341 .config = check_dbi_config_init(),
342 .errorcode = OK,
343 };
344 int option_char;
345 while (true) {
346 option_char = getopt_long(argc, argv, "Vvht:c:w:e:r:R:m:H:d:o:q:D:", longopts, &option);
348 347
349 if (c == EOF) 348 if (option_char == EOF) {
350 break; 349 break;
350 }
351 351
352 switch (c) { 352 switch (option_char) {
353 case '?': /* usage */ 353 case '?': /* usage */
354 usage5(); 354 usage5();
355 case 'h': /* help */ 355 case 'h': /* help */
@@ -360,135 +360,148 @@ int process_arguments(int argc, char **argv) {
360 exit(STATE_UNKNOWN); 360 exit(STATE_UNKNOWN);
361 361
362 case 'c': /* critical range */ 362 case 'c': /* critical range */
363 critical_range = optarg; 363 result.config.critical_range = optarg;
364 type = TYPE_NUMERIC; 364 result.config.type = TYPE_NUMERIC;
365 break; 365 break;
366 case 'w': /* warning range */ 366 case 'w': /* warning range */
367 warning_range = optarg; 367 result.config.warning_range = optarg;
368 type = TYPE_NUMERIC; 368 result.config.type = TYPE_NUMERIC;
369 break; 369 break;
370 case 'e': 370 case 'e':
371 expect = optarg; 371 result.config.expect = optarg;
372 type = TYPE_STRING; 372 result.config.type = TYPE_STRING;
373 break; 373 break;
374 case 'R': 374 case 'R':
375 expect_re_cflags = REG_ICASE; 375 result.config.expect_re_cflags = REG_ICASE;
376 /* fall through */ 376 /* fall through */
377 case 'r': { 377 case 'r': {
378 int err; 378 int err;
379 379
380 expect_re_cflags |= REG_EXTENDED | REG_NOSUB | REG_NEWLINE; 380 result.config.expect_re_cflags |= REG_EXTENDED | REG_NOSUB | REG_NEWLINE;
381 expect_re_str = optarg; 381 result.config.expect_re_str = optarg;
382 type = TYPE_STRING; 382 result.config.type = TYPE_STRING;
383 383
384 err = regcomp(&expect_re, expect_re_str, expect_re_cflags); 384 regex_t expect_re = {};
385 err = regcomp(&expect_re, result.config.expect_re_str, result.config.expect_re_cflags);
385 if (err) { 386 if (err) {
386 char errmsg[1024]; 387 char errmsg[1024];
387 regerror(err, &expect_re, errmsg, sizeof(errmsg)); 388 regerror(err, &expect_re, errmsg, sizeof(errmsg));
388 printf("ERROR - failed to compile regular expression: %s\n", errmsg); 389 printf("ERROR - failed to compile regular expression: %s\n", errmsg);
389 return ERROR; 390
391 result.errorcode = ERROR;
392 return result;
390 } 393 }
391 break; 394 break;
392 } 395 }
393 396
394 case 'm': 397 case 'm':
395 if (!strcasecmp(optarg, "CONN_TIME")) 398 if (!strcasecmp(optarg, "CONN_TIME")) {
396 metric = METRIC_CONN_TIME; 399 result.config.metric = METRIC_CONN_TIME;
397 else if (!strcasecmp(optarg, "SERVER_VERSION")) 400 } else if (!strcasecmp(optarg, "SERVER_VERSION")) {
398 metric = METRIC_SERVER_VERSION; 401 result.config.metric = METRIC_SERVER_VERSION;
399 else if (!strcasecmp(optarg, "QUERY_RESULT")) 402 } else if (!strcasecmp(optarg, "QUERY_RESULT")) {
400 metric = METRIC_QUERY_RESULT; 403 result.config.metric = METRIC_QUERY_RESULT;
401 else if (!strcasecmp(optarg, "QUERY_TIME")) 404 } else if (!strcasecmp(optarg, "QUERY_TIME")) {
402 metric = METRIC_QUERY_TIME; 405 result.config.metric = METRIC_QUERY_TIME;
403 else 406 } else {
404 usage2(_("Invalid metric"), optarg); 407 usage2(_("Invalid metric"), optarg);
408 }
405 break; 409 break;
406 case 't': /* timeout */ 410 case 't': /* timeout */
407 if (!is_intnonneg(optarg)) 411 if (!is_intnonneg(optarg)) {
408 usage2(_("Timeout interval must be a positive integer"), optarg); 412 usage2(_("Timeout interval must be a positive integer"), optarg);
409 else 413 } else {
410 timeout_interval = atoi(optarg); 414 timeout_interval = atoi(optarg);
415 }
411 416
412 break; 417 break;
413 case 'H': /* host */ 418 case 'H': /* host */
414 if (!is_host(optarg)) 419 if (!is_host(optarg)) {
415 usage2(_("Invalid hostname/address"), optarg); 420 usage2(_("Invalid hostname/address"), optarg);
416 else 421 } else {
417 host = optarg; 422 result.config.host = optarg;
423 }
418 break; 424 break;
419 case 'v': 425 case 'v':
420 verbose++; 426 verbose++;
421 break; 427 break;
422 428
423 case 'd': 429 case 'd':
424 np_dbi_driver = optarg; 430 result.config.dbi_driver = optarg;
425 break; 431 break;
426 case 'o': { 432 case 'o': {
427 driver_option_t *new; 433 driver_option_t *new = NULL;
428
429 char *k;
430 char *v;
431 434
432 k = optarg; 435 char *key = optarg;
433 v = strchr(k, (int)'='); 436 char *value = strchr(key, '=');
434 437
435 if (!v) 438 if (!value) {
436 usage2(_("Option must be '<key>=<value>'"), optarg); 439 usage2(_("Option must be '<key>=<value>'"), optarg);
440 }
437 441
438 *v = '\0'; 442 *value = '\0';
439 ++v; 443 ++value;
440 444
441 new = realloc(np_dbi_options, (np_dbi_options_num + 1) * sizeof(*new)); 445 new = realloc(result.config.dbi_options, (result.config.dbi_options_num + 1) * sizeof(*new));
442 if (!new) { 446 if (!new) {
443 printf("UNKNOWN - failed to reallocate memory\n"); 447 printf("UNKNOWN - failed to reallocate memory\n");
444 exit(STATE_UNKNOWN); 448 exit(STATE_UNKNOWN);
445 } 449 }
446 450
447 np_dbi_options = new; 451 result.config.dbi_options = new;
448 new = np_dbi_options + np_dbi_options_num; 452 new = result.config.dbi_options + result.config.dbi_options_num;
449 ++np_dbi_options_num; 453 result.config.dbi_options_num++;
450 454
451 new->key = k; 455 new->key = key;
452 new->value = v; 456 new->value = value;
453 } break; 457 } break;
454 case 'q': 458 case 'q':
455 np_dbi_query = optarg; 459 result.config.dbi_query = optarg;
456 break; 460 break;
457 case 'D': 461 case 'D':
458 np_dbi_database = optarg; 462 result.config.dbi_database = optarg;
459 break; 463 break;
460 } 464 }
461 } 465 }
462 466
463 set_thresholds(&dbi_thresholds, warning_range, critical_range); 467 set_thresholds(&result.config.dbi_thresholds, result.config.warning_range, result.config.critical_range);
464 468
465 return validate_arguments(); 469 return validate_arguments(result);
466} 470}
467 471
468int validate_arguments(void) { 472check_dbi_config_wrapper validate_arguments(check_dbi_config_wrapper config_wrapper) {
469 if (!np_dbi_driver) 473 if (!config_wrapper.config.dbi_driver) {
470 usage("Must specify a DBI driver"); 474 usage("Must specify a DBI driver");
475 }
471 476
472 if (((metric == METRIC_QUERY_RESULT) || (metric == METRIC_QUERY_TIME)) && (!np_dbi_query)) 477 if (((config_wrapper.config.metric == METRIC_QUERY_RESULT) || (config_wrapper.config.metric == METRIC_QUERY_TIME)) &&
478 (!config_wrapper.config.dbi_query)) {
473 usage("Must specify a query to execute (metric == QUERY_RESULT)"); 479 usage("Must specify a query to execute (metric == QUERY_RESULT)");
480 }
474 481
475 if ((metric != METRIC_CONN_TIME) && (metric != METRIC_SERVER_VERSION) && (metric != METRIC_QUERY_RESULT) && 482 if ((config_wrapper.config.metric != METRIC_CONN_TIME) && (config_wrapper.config.metric != METRIC_SERVER_VERSION) &&
476 (metric != METRIC_QUERY_TIME)) 483 (config_wrapper.config.metric != METRIC_QUERY_RESULT) && (config_wrapper.config.metric != METRIC_QUERY_TIME)) {
477 usage("Invalid metric specified"); 484 usage("Invalid metric specified");
485 }
478 486
479 if (expect && (warning_range || critical_range || expect_re_str)) 487 if (config_wrapper.config.expect && (config_wrapper.config.warning_range || config_wrapper.config.critical_range || config_wrapper.config.expect_re_str)) {
480 usage("Do not mix -e and -w/-c/-r/-R"); 488 usage("Do not mix -e and -w/-c/-r/-R");
489 }
481 490
482 if (expect_re_str && (warning_range || critical_range || expect)) 491 if (config_wrapper.config.expect_re_str && (config_wrapper.config.warning_range || config_wrapper.config.critical_range || config_wrapper.config.expect)) {
483 usage("Do not mix -r/-R and -w/-c/-e"); 492 usage("Do not mix -r/-R and -w/-c/-e");
493 }
484 494
485 if (expect && (metric != METRIC_QUERY_RESULT)) 495 if (config_wrapper.config.expect && (config_wrapper.config.metric != METRIC_QUERY_RESULT)) {
486 usage("Option -e requires metric QUERY_RESULT"); 496 usage("Option -e requires metric QUERY_RESULT");
497 }
487 498
488 if (expect_re_str && (metric != METRIC_QUERY_RESULT)) 499 if (config_wrapper.config.expect_re_str && (config_wrapper.config.metric != METRIC_QUERY_RESULT)) {
489 usage("Options -r/-R require metric QUERY_RESULT"); 500 usage("Options -r/-R require metric QUERY_RESULT");
501 }
490 502
491 return OK; 503 config_wrapper.errorcode = OK;
504 return config_wrapper;
492} 505}
493 506
494void print_help(void) { 507void print_help(void) {
@@ -518,6 +531,8 @@ void print_help(void) {
518 printf(" %s\n", _("DBI driver options")); 531 printf(" %s\n", _("DBI driver options"));
519 printf(" %s\n", "-q, --query=STRING"); 532 printf(" %s\n", "-q, --query=STRING");
520 printf(" %s\n", _("query to execute")); 533 printf(" %s\n", _("query to execute"));
534 printf(" %s\n", "-H STRING");
535 printf(" %s\n", _("target database host"));
521 printf("\n"); 536 printf("\n");
522 537
523 printf(UT_WARN_CRIT_RANGE); 538 printf(UT_WARN_CRIT_RANGE);
@@ -592,13 +607,7 @@ void print_usage(void) {
592 printf(" [-e <string>] [-r|-R <regex>]\n"); 607 printf(" [-e <string>] [-r|-R <regex>]\n");
593} 608}
594 609
595#define CHECK_IGNORE_ERROR(s) \ 610const char *get_field_str(dbi_conn conn, dbi_result res, unsigned short field_type, mp_dbi_metric metric, mp_dbi_type type) {
596 do { \
597 if (metric != METRIC_QUERY_RESULT) \
598 return (s); \
599 } while (0)
600
601const char *get_field_str(dbi_conn conn, dbi_result res, unsigned short field_type) {
602 const char *str; 611 const char *str;
603 612
604 if (field_type != DBI_TYPE_STRING) { 613 if (field_type != DBI_TYPE_STRING) {
@@ -608,17 +617,20 @@ const char *get_field_str(dbi_conn conn, dbi_result res, unsigned short field_ty
608 617
609 str = dbi_result_get_string_idx(res, 1); 618 str = dbi_result_get_string_idx(res, 1);
610 if ((!str) || (strcmp(str, "ERROR") == 0)) { 619 if ((!str) || (strcmp(str, "ERROR") == 0)) {
611 CHECK_IGNORE_ERROR(NULL); 620 if (metric != METRIC_QUERY_RESULT) {
621 return NULL;
622 }
612 np_dbi_print_error(conn, "CRITICAL - failed to fetch string value"); 623 np_dbi_print_error(conn, "CRITICAL - failed to fetch string value");
613 return NULL; 624 return NULL;
614 } 625 }
615 626
616 if ((verbose && (type == TYPE_STRING)) || (verbose > 2)) 627 if ((verbose && (type == TYPE_STRING)) || (verbose > 2)) {
617 printf("Query returned string '%s'\n", str); 628 printf("Query returned string '%s'\n", str);
629 }
618 return str; 630 return str;
619} 631}
620 632
621double get_field(dbi_conn conn, dbi_result res, unsigned short *field_type) { 633double get_field(dbi_conn conn, dbi_result res, unsigned short *field_type, mp_dbi_metric metric, mp_dbi_type type) {
622 double val = NAN; 634 double val = NAN;
623 635
624 if (*field_type == DBI_TYPE_INTEGER) { 636 if (*field_type == DBI_TYPE_INTEGER) {
@@ -629,26 +641,33 @@ double get_field(dbi_conn conn, dbi_result res, unsigned short *field_type) {
629 const char *val_str; 641 const char *val_str;
630 char *endptr = NULL; 642 char *endptr = NULL;
631 643
632 val_str = get_field_str(conn, res, *field_type); 644 val_str = get_field_str(conn, res, *field_type, metric, type);
633 if (!val_str) { 645 if (!val_str) {
634 CHECK_IGNORE_ERROR(NAN); 646 if (metric != METRIC_QUERY_RESULT) {
647 return NAN;
648 }
635 *field_type = DBI_TYPE_ERROR; 649 *field_type = DBI_TYPE_ERROR;
636 return NAN; 650 return NAN;
637 } 651 }
638 652
639 val = strtod(val_str, &endptr); 653 val = strtod(val_str, &endptr);
640 if (endptr == val_str) { 654 if (endptr == val_str) {
641 CHECK_IGNORE_ERROR(NAN); 655 if (metric != METRIC_QUERY_RESULT) {
656 return NAN;
657 }
642 printf("CRITICAL - result value is not a numeric: %s\n", val_str); 658 printf("CRITICAL - result value is not a numeric: %s\n", val_str);
643 *field_type = DBI_TYPE_ERROR; 659 *field_type = DBI_TYPE_ERROR;
644 return NAN; 660 return NAN;
645 } 661 }
646 if ((endptr != NULL) && (*endptr != '\0')) { 662 if ((endptr != NULL) && (*endptr != '\0')) {
647 if (verbose) 663 if (verbose) {
648 printf("Garbage after value: %s\n", endptr); 664 printf("Garbage after value: %s\n", endptr);
665 }
649 } 666 }
650 } else { 667 } else {
651 CHECK_IGNORE_ERROR(NAN); 668 if (metric != METRIC_QUERY_RESULT) {
669 return NAN;
670 }
652 printf("CRITICAL - cannot parse value of type %s (%i)\n", 671 printf("CRITICAL - cannot parse value of type %s (%i)\n",
653 (*field_type == DBI_TYPE_BINARY) ? "BINARY" 672 (*field_type == DBI_TYPE_BINARY) ? "BINARY"
654 : (*field_type == DBI_TYPE_DATETIME) ? "DATETIME" 673 : (*field_type == DBI_TYPE_DATETIME) ? "DATETIME"
@@ -660,53 +679,66 @@ double get_field(dbi_conn conn, dbi_result res, unsigned short *field_type) {
660 return val; 679 return val;
661} 680}
662 681
663double get_query_result(dbi_conn conn, dbi_result res, const char **res_val_str, double *res_val) { 682mp_state_enum get_query_result(dbi_conn conn, dbi_result res, const char **res_val_str, double *res_val, mp_dbi_metric metric, mp_dbi_type type) {
664 unsigned short field_type; 683 unsigned short field_type;
665 double val = NAN; 684 double val = NAN;
666 685
667 if (dbi_result_get_numrows(res) == DBI_ROW_ERROR) { 686 if (dbi_result_get_numrows(res) == DBI_ROW_ERROR) {
668 CHECK_IGNORE_ERROR(STATE_OK); 687 if (metric != METRIC_QUERY_RESULT) {
688 return STATE_OK;
689 }
669 np_dbi_print_error(conn, "CRITICAL - failed to fetch rows"); 690 np_dbi_print_error(conn, "CRITICAL - failed to fetch rows");
670 return STATE_CRITICAL; 691 return STATE_CRITICAL;
671 } 692 }
672 693
673 if (dbi_result_get_numrows(res) < 1) { 694 if (dbi_result_get_numrows(res) < 1) {
674 CHECK_IGNORE_ERROR(STATE_OK); 695 if (metric != METRIC_QUERY_RESULT) {
696 return STATE_OK;
697 }
675 printf("WARNING - no rows returned\n"); 698 printf("WARNING - no rows returned\n");
676 return STATE_WARNING; 699 return STATE_WARNING;
677 } 700 }
678 701
679 if (dbi_result_get_numfields(res) == DBI_FIELD_ERROR) { 702 if (dbi_result_get_numfields(res) == DBI_FIELD_ERROR) {
680 CHECK_IGNORE_ERROR(STATE_OK); 703 if (metric != METRIC_QUERY_RESULT) {
704 return STATE_OK;
705 }
681 np_dbi_print_error(conn, "CRITICAL - failed to fetch fields"); 706 np_dbi_print_error(conn, "CRITICAL - failed to fetch fields");
682 return STATE_CRITICAL; 707 return STATE_CRITICAL;
683 } 708 }
684 709
685 if (dbi_result_get_numfields(res) < 1) { 710 if (dbi_result_get_numfields(res) < 1) {
686 CHECK_IGNORE_ERROR(STATE_OK); 711 if (metric != METRIC_QUERY_RESULT) {
712 return STATE_OK;
713 }
687 printf("WARNING - no fields returned\n"); 714 printf("WARNING - no fields returned\n");
688 return STATE_WARNING; 715 return STATE_WARNING;
689 } 716 }
690 717
691 if (dbi_result_first_row(res) != 1) { 718 if (dbi_result_first_row(res) != 1) {
692 CHECK_IGNORE_ERROR(STATE_OK); 719 if (metric != METRIC_QUERY_RESULT) {
720 return STATE_OK;
721 }
693 np_dbi_print_error(conn, "CRITICAL - failed to fetch first row"); 722 np_dbi_print_error(conn, "CRITICAL - failed to fetch first row");
694 return STATE_CRITICAL; 723 return STATE_CRITICAL;
695 } 724 }
696 725
697 field_type = dbi_result_get_field_type_idx(res, 1); 726 field_type = dbi_result_get_field_type_idx(res, 1);
698 if (field_type != DBI_TYPE_ERROR) { 727 if (field_type != DBI_TYPE_ERROR) {
699 if (type == TYPE_STRING) 728 if (type == TYPE_STRING) {
700 /* the value will be freed in dbi_result_free */ 729 /* the value will be freed in dbi_result_free */
701 *res_val_str = strdup(get_field_str(conn, res, field_type)); 730 *res_val_str = strdup(get_field_str(conn, res, field_type, metric, type));
702 else 731 } else {
703 val = get_field(conn, res, &field_type); 732 val = get_field(conn, res, &field_type, metric, type);
733 }
704 } 734 }
705 735
706 *res_val = val; 736 *res_val = val;
707 737
708 if (field_type == DBI_TYPE_ERROR) { 738 if (field_type == DBI_TYPE_ERROR) {
709 CHECK_IGNORE_ERROR(STATE_OK); 739 if (metric != METRIC_QUERY_RESULT) {
740 return STATE_OK;
741 }
710 np_dbi_print_error(conn, "CRITICAL - failed to fetch data"); 742 np_dbi_print_error(conn, "CRITICAL - failed to fetch data");
711 return STATE_CRITICAL; 743 return STATE_CRITICAL;
712 } 744 }
@@ -715,19 +747,19 @@ double get_query_result(dbi_conn conn, dbi_result res, const char **res_val_str,
715 return STATE_OK; 747 return STATE_OK;
716} 748}
717 749
718#undef CHECK_IGNORE_ERROR 750mp_state_enum do_query(dbi_conn conn, const char **res_val_str, double *res_val, double *res_time, mp_dbi_metric metric, mp_dbi_type type,
719 751 char *np_dbi_query) {
720int do_query(dbi_conn conn, const char **res_val_str, double *res_val, double *res_time) {
721 dbi_result res; 752 dbi_result res;
722 753
723 struct timeval timeval_start; 754 struct timeval timeval_start;
724 struct timeval timeval_end; 755 struct timeval timeval_end;
725 int status = STATE_OK; 756 mp_state_enum status = STATE_OK;
726 757
727 assert(np_dbi_query); 758 assert(np_dbi_query);
728 759
729 if (verbose) 760 if (verbose) {
730 printf("Executing query '%s'\n", np_dbi_query); 761 printf("Executing query '%s'\n", np_dbi_query);
762 }
731 763
732 gettimeofday(&timeval_start, NULL); 764 gettimeofday(&timeval_start, NULL);
733 765
@@ -737,13 +769,14 @@ int do_query(dbi_conn conn, const char **res_val_str, double *res_val, double *r
737 return STATE_CRITICAL; 769 return STATE_CRITICAL;
738 } 770 }
739 771
740 status = get_query_result(conn, res, res_val_str, res_val); 772 status = get_query_result(conn, res, res_val_str, res_val, metric, type);
741 773
742 gettimeofday(&timeval_end, NULL); 774 gettimeofday(&timeval_end, NULL);
743 *res_time = timediff(timeval_start, timeval_end); 775 *res_time = timediff(timeval_start, timeval_end);
744 776
745 if (verbose) 777 if (verbose) {
746 printf("Time elapsed: %f\n", *res_time); 778 printf("Time elapsed: %f\n", *res_time);
779 }
747 780
748 return status; 781 return status;
749} 782}