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