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.c1040
1 files changed, 510 insertions, 530 deletions
diff --git a/plugins/check_dbi.c b/plugins/check_dbi.c
index 29c85206..9efcd1cb 100644
--- a/plugins/check_dbi.c
+++ b/plugins/check_dbi.c
@@ -1,38 +1,40 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_dbi plugin 3 * Monitoring check_dbi plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 2011 Monitoring Plugins Development Team 6 * Copyright (c) 2011-2024 Monitoring Plugins Development Team
7* Author: Sebastian 'tokkee' Harl <sh@teamix.net> 7 * Original Author: Sebastian 'tokkee' Harl <sh@teamix.net>
8* 8 *
9* Description: 9 * Description:
10* 10 *
11* This file contains the check_dbi plugin 11 * This file contains the check_dbi plugin
12* 12 *
13* Runs an arbitrary (SQL) command and checks the result. 13 * Runs an arbitrary (SQL) command and checks the result.
14* 14 *
15* 15 *
16* This program is free software: you can redistribute it and/or modify 16 * This program is free software: you can redistribute it and/or modify
17* it under the terms of the GNU General Public License as published by 17 * it under the terms of the GNU General Public License as published by
18* the Free Software Foundation, either version 3 of the License, or 18 * the Free Software Foundation, either version 3 of the License, or
19* (at your option) any later version. 19 * (at your option) any later version.
20* 20 *
21* This program is distributed in the hope that it will be useful, 21 * This program is distributed in the hope that it will be useful,
22* but WITHOUT ANY WARRANTY; without even the implied warranty of 22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24* GNU General Public License for more details. 24 * GNU General Public License for more details.
25* 25 *
26* You should have received a copy of the GNU General Public License 26 * You should have received a copy of the GNU General Public License
27* along with this program. If not, see <http://www.gnu.org/licenses/>. 27 * along with this program. If not, see <http://www.gnu.org/licenses/>.
28* 28 *
29* 29 *
30*****************************************************************************/ 30 *****************************************************************************/
31 31
32const char *progname = "check_dbi"; 32const char *progname = "check_dbi";
33const char *copyright = "2011"; 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"
@@ -43,7 +45,7 @@ const char *email = "devel@monitoring-plugins.org";
43 45
44/* required for NAN */ 46/* required for NAN */
45#ifndef _ISOC99_SOURCE 47#ifndef _ISOC99_SOURCE
46#define _ISOC99_SOURCE 48# define _ISOC99_SOURCE
47#endif 49#endif
48 50
49#include <assert.h> 51#include <assert.h>
@@ -53,59 +55,26 @@ const char *email = "devel@monitoring-plugins.org";
53 55
54#include <stdarg.h> 56#include <stdarg.h>
55 57
56typedef enum { 58static int verbose = 0;
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 59
68typedef struct { 60typedef struct {
69 char *key; 61 int errorcode;
70 char *value; 62 check_dbi_config config;
71} driver_option_t; 63} check_dbi_config_wrapper;
72
73char *host = NULL;
74int verbose = 0;
75
76char *warning_range = NULL;
77char *critical_range = NULL;
78thresholds *dbi_thresholds = NULL;
79
80char *expect = NULL;
81
82regex_t expect_re;
83char *expect_re_str = NULL;
84int expect_re_cflags = 0;
85
86np_dbi_metric_t metric = METRIC_QUERY_RESULT;
87np_dbi_type_t type = TYPE_NUMERIC;
88 64
89char *np_dbi_driver = NULL; 65static check_dbi_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
90driver_option_t *np_dbi_options = NULL; 66static check_dbi_config_wrapper validate_arguments(check_dbi_config_wrapper /*config_wrapper*/);
91int np_dbi_options_num = 0; 67void print_usage(void);
92char *np_dbi_database = NULL; 68static void print_help(void);
93char *np_dbi_query = NULL;
94 69
95int process_arguments (int, char **); 70static double timediff(struct timeval /*start*/, struct timeval /*end*/);
96int validate_arguments (void);
97void print_usage (void);
98void print_help (void);
99 71
100double timediff (struct timeval, struct timeval); 72static void np_dbi_print_error(dbi_conn /*conn*/, char * /*fmt*/, ...);
101 73
102void np_dbi_print_error (dbi_conn, char *, ...); 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*/);
103 76
104int do_query (dbi_conn, const char **, double *, double *); 77int main(int argc, char **argv) {
105
106int
107main (int argc, char **argv)
108{
109 int status = STATE_UNKNOWN; 78 int status = STATE_UNKNOWN;
110 79
111 dbi_driver driver; 80 dbi_driver driver;
@@ -113,714 +82,725 @@ main (int argc, char **argv)
113 82
114 unsigned int server_version; 83 unsigned int server_version;
115 84
116 struct timeval start_timeval, end_timeval; 85 struct timeval start_timeval;
86 struct timeval end_timeval;
117 double conn_time = 0.0; 87 double conn_time = 0.0;
118 double query_time = 0.0; 88 double query_time = 0.0;
119 89
120 const char *query_val_str = NULL; 90 const char *query_val_str = NULL;
121 double query_val = 0.0; 91 double query_val = 0.0;
122 92
123 int i; 93 setlocale(LC_ALL, "");
124 94 bindtextdomain(PACKAGE, LOCALEDIR);
125 setlocale (LC_ALL, ""); 95 textdomain(PACKAGE);
126 bindtextdomain (PACKAGE, LOCALEDIR);
127 textdomain (PACKAGE);
128 96
129 /* Parse extra opts if any */ 97 /* Parse extra opts if any */
130 argv = np_extra_opts (&argc, argv, progname); 98 argv = np_extra_opts(&argc, argv, progname);
99
100 check_dbi_config_wrapper tmp = process_arguments(argc, argv);
101
102 if (tmp.errorcode == ERROR) {
103 usage4(_("Could not parse arguments"));
104 }
131 105
132 if (process_arguments (argc, argv) == ERROR) 106 const check_dbi_config config = tmp.config;
133 usage4 (_("Could not parse arguments"));
134 107
135 /* Set signal handling and alarm */ 108 /* Set signal handling and alarm */
136 if (signal (SIGALRM, timeout_alarm_handler) == SIG_ERR) { 109 if (signal(SIGALRM, timeout_alarm_handler) == SIG_ERR) {
137 usage4 (_("Cannot catch SIGALRM")); 110 usage4(_("Cannot catch SIGALRM"));
138 } 111 }
139 alarm (timeout_interval); 112 alarm(timeout_interval);
140 113
141 if (verbose > 2) 114 if (verbose > 2) {
142 printf ("Initializing DBI\n"); 115 printf("Initializing DBI\n");
116 }
143 117
144 dbi_inst *instance_p = { 0 }; 118 dbi_inst *instance_p = {0};
145 119
146 if (dbi_initialize_r(NULL, instance_p) < 0) { 120 if (dbi_initialize_r(NULL, instance_p) < 0) {
147 printf ("UNKNOWN - failed to initialize DBI; possibly you don't have any drivers installed.\n"); 121 printf("UNKNOWN - failed to initialize DBI; possibly you don't have any drivers installed.\n");
148 return STATE_UNKNOWN; 122 return STATE_UNKNOWN;
149 } 123 }
150 124
151 if (instance_p == NULL) { 125 if (instance_p == NULL) {
152 printf ("UNKNOWN - failed to initialize DBI.\n"); 126 printf("UNKNOWN - failed to initialize DBI.\n");
153 return STATE_UNKNOWN; 127 return STATE_UNKNOWN;
154 } 128 }
155 129
156 if (verbose) 130 if (verbose) {
157 printf ("Opening DBI driver '%s'\n", np_dbi_driver); 131 printf("Opening DBI driver '%s'\n", config.dbi_driver);
132 }
158 133
159 driver = dbi_driver_open_r(np_dbi_driver, instance_p); 134 driver = dbi_driver_open_r(config.dbi_driver, instance_p);
160 if (! driver) { 135 if (!driver) {
161 printf ("UNKNOWN - failed to open DBI driver '%s'; possibly it's not installed.\n", 136 printf("UNKNOWN - failed to open DBI driver '%s'; possibly it's not installed.\n", config.dbi_driver);
162 np_dbi_driver);
163 137
164 printf ("Known drivers:\n"); 138 printf("Known drivers:\n");
165 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)) {
166 printf (" - %s\n", dbi_driver_get_name (driver)); 140 printf(" - %s\n", dbi_driver_get_name(driver));
167 } 141 }
168 return STATE_UNKNOWN; 142 return STATE_UNKNOWN;
169 } 143 }
170 144
171 /* make a connection to the database */ 145 /* make a connection to the database */
172 gettimeofday (&start_timeval, NULL); 146 gettimeofday(&start_timeval, NULL);
173 147
174 conn = dbi_conn_open (driver); 148 conn = dbi_conn_open(driver);
175 if (! conn) { 149 if (!conn) {
176 printf ("UNKNOWN - failed top open connection object.\n"); 150 printf("UNKNOWN - failed top open connection object.\n");
177 dbi_conn_close (conn); 151 dbi_conn_close(conn);
178 return STATE_UNKNOWN; 152 return STATE_UNKNOWN;
179 } 153 }
180 154
181 for (i = 0; i < np_dbi_options_num; ++i) { 155 for (size_t i = 0; i < config.dbi_options_num; ++i) {
182 const char *opt; 156 const char *opt;
183 157
184 if (verbose > 1) 158 if (verbose > 1) {
185 printf ("Setting DBI driver option '%s' to '%s'\n", 159 printf("Setting DBI driver option '%s' to '%s'\n", config.dbi_options[i].key, config.dbi_options[i].value);
186 np_dbi_options[i].key, np_dbi_options[i].value); 160 }
187 161
188 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)) {
189 continue; 163 continue;
164 }
190 /* else: status != 0 */ 165 /* else: status != 0 */
191 166
192 np_dbi_print_error (conn, "UNKNOWN - failed to set option '%s' to '%s'", 167 np_dbi_print_error(conn, "UNKNOWN - failed to set option '%s' to '%s'", config.dbi_options[i].key, config.dbi_options[i].value);
193 np_dbi_options[i].key, np_dbi_options[i].value); 168 printf("Known driver options:\n");
194 printf ("Known driver options:\n");
195 169
196 for (opt = dbi_conn_get_option_list (conn, NULL); opt; 170 for (opt = dbi_conn_get_option_list(conn, NULL); opt; opt = dbi_conn_get_option_list(conn, opt)) {
197 opt = dbi_conn_get_option_list (conn, opt)) { 171 printf(" - %s\n", opt);
198 printf (" - %s\n", opt);
199 } 172 }
200 dbi_conn_close (conn); 173 dbi_conn_close(conn);
201 return STATE_UNKNOWN; 174 return STATE_UNKNOWN;
202 } 175 }
203 176
204 if (host) { 177 if (config.host) {
205 if (verbose > 1) 178 if (verbose > 1) {
206 printf ("Setting DBI driver option 'host' to '%s'\n", host); 179 printf("Setting DBI driver option 'host' to '%s'\n", config.host);
207 dbi_conn_set_option (conn, "host", host); 180 }
181 dbi_conn_set_option(conn, "host", config.host);
208 } 182 }
209 183
210 if (verbose) { 184 if (verbose) {
211 const char *dbname, *host; 185 const char *dbname;
186 const char *host;
212 187
213 dbname = dbi_conn_get_option (conn, "dbname"); 188 dbname = dbi_conn_get_option(conn, "dbname");
214 host = dbi_conn_get_option (conn, "host"); 189 host = dbi_conn_get_option(conn, "host");
215 190
216 if (! dbname) 191 if (!dbname) {
217 dbname = "<unspecified>"; 192 dbname = "<unspecified>";
218 if (! host) 193 }
194 if (!host) {
219 host = "<unspecified>"; 195 host = "<unspecified>";
196 }
220 197
221 printf ("Connecting to database '%s' at host '%s'\n", 198 printf("Connecting to database '%s' at host '%s'\n", dbname, host);
222 dbname, host);
223 } 199 }
224 200
225 if (dbi_conn_connect (conn) < 0) { 201 if (dbi_conn_connect(conn) < 0) {
226 np_dbi_print_error (conn, "UNKNOWN - failed to connect to database"); 202 np_dbi_print_error(conn, "UNKNOWN - failed to connect to database");
227 return STATE_UNKNOWN; 203 return STATE_UNKNOWN;
228 } 204 }
229 205
230 gettimeofday (&end_timeval, NULL); 206 gettimeofday(&end_timeval, NULL);
231 conn_time = timediff (start_timeval, end_timeval); 207 conn_time = timediff(start_timeval, end_timeval);
232 208
233 server_version = dbi_conn_get_engine_version (conn); 209 server_version = dbi_conn_get_engine_version(conn);
234 if (verbose) 210 if (verbose) {
235 printf ("Connected to server version %u\n", server_version); 211 printf("Connected to server version %u\n", server_version);
212 }
236 213
237 if (metric == METRIC_SERVER_VERSION) 214 if (config.metric == METRIC_SERVER_VERSION) {
238 status = get_status (server_version, dbi_thresholds); 215 status = get_status(server_version, config.dbi_thresholds);
216 }
239 217
240 if (verbose) 218 if (verbose) {
241 printf ("Time elapsed: %f\n", conn_time); 219 printf("Time elapsed: %f\n", conn_time);
220 }
242 221
243 if (metric == METRIC_CONN_TIME) 222 if (config.metric == METRIC_CONN_TIME) {
244 status = get_status (conn_time, dbi_thresholds); 223 status = get_status(conn_time, config.dbi_thresholds);
224 }
245 225
246 /* select a database */ 226 /* select a database */
247 if (np_dbi_database) { 227 if (config.dbi_database) {
248 if (verbose > 1) 228 if (verbose > 1) {
249 printf ("Selecting database '%s'\n", np_dbi_database); 229 printf("Selecting database '%s'\n", config.dbi_database);
230 }
250 231
251 if (dbi_conn_select_db (conn, np_dbi_database)) { 232 if (dbi_conn_select_db(conn, config.dbi_database)) {
252 np_dbi_print_error (conn, "UNKNOWN - failed to select database '%s'", 233 np_dbi_print_error(conn, "UNKNOWN - failed to select database '%s'", config.dbi_database);
253 np_dbi_database);
254 return STATE_UNKNOWN; 234 return STATE_UNKNOWN;
255 } 235 }
256 } 236 }
257 237
258 if (np_dbi_query) { 238 if (config.dbi_query) {
259 /* execute query */ 239 /* execute query */
260 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);
261 if (status != STATE_OK) 241 if (status != STATE_OK) {
262 /* do_query prints an error message in this case */ 242 /* do_query prints an error message in this case */
263 return status; 243 return status;
244 }
264 245
265 if (metric == METRIC_QUERY_RESULT) { 246 if (config.metric == METRIC_QUERY_RESULT) {
266 if (expect) { 247 if (config.expect) {
267 if ((! query_val_str) || strcmp (query_val_str, expect)) 248 if ((!query_val_str) || strcmp(query_val_str, config.expect)) {
268 status = STATE_CRITICAL; 249 status = STATE_CRITICAL;
269 else 250 } else {
270 status = STATE_OK; 251 status = STATE_OK;
271 } 252 }
272 else if (expect_re_str) { 253 } else if (config.expect_re_str) {
273 int err; 254 int err;
274 255
275 err = regexec (&expect_re, query_val_str, 0, NULL, /* flags = */ 0); 256 regex_t expect_re = {};
276 if (! err) 257 err = regexec(&expect_re, query_val_str, 0, NULL, /* flags = */ 0);
258 if (!err) {
277 status = STATE_OK; 259 status = STATE_OK;
278 else if (err == REG_NOMATCH) 260 } else if (err == REG_NOMATCH) {
279 status = STATE_CRITICAL; 261 status = STATE_CRITICAL;
280 else { 262 } else {
281 char errmsg[1024]; 263 char errmsg[1024];
282 regerror (err, &expect_re, errmsg, sizeof (errmsg)); 264 regerror(err, &expect_re, errmsg, sizeof(errmsg));
283 printf ("ERROR - failed to execute regular expression: %s\n", 265 printf("ERROR - failed to execute regular expression: %s\n", errmsg);
284 errmsg);
285 status = STATE_CRITICAL; 266 status = STATE_CRITICAL;
286 } 267 }
268 } else {
269 status = get_status(query_val, config.dbi_thresholds);
287 } 270 }
288 else 271 } else if (config.metric == METRIC_QUERY_TIME) {
289 status = get_status (query_val, dbi_thresholds); 272 status = get_status(query_time, config.dbi_thresholds);
290 } 273 }
291 else if (metric == METRIC_QUERY_TIME)
292 status = get_status (query_time, dbi_thresholds);
293 } 274 }
294 275
295 if (verbose) 276 if (verbose) {
296 printf("Closing connection\n"); 277 printf("Closing connection\n");
297 dbi_conn_close (conn); 278 }
279 dbi_conn_close(conn);
298 280
299 /* 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
300 * which should have been reported and handled (abort) before 282 * which should have been reported and handled (abort) before
301 * ... unless we expected a string to be returned */ 283 * ... unless we expected a string to be returned */
302 assert ((metric != METRIC_QUERY_RESULT) || (! isnan (query_val)) 284 assert((config.metric != METRIC_QUERY_RESULT) || (!isnan(query_val)) || (config.type == TYPE_STRING));
303 || (type == TYPE_STRING));
304 285
305 assert ((type != TYPE_STRING) || (expect || expect_re_str)); 286 assert((config.type != TYPE_STRING) || (config.expect || config.expect_re_str));
306 287
307 printf ("%s - connection time: %fs", state_text (status), conn_time); 288 printf("%s - connection time: %fs", state_text(status), conn_time);
308 if (np_dbi_query) { 289 if (config.dbi_query) {
309 if (type == TYPE_STRING) { 290 if (config.type == TYPE_STRING) {
310 assert (expect || expect_re_str); 291 assert(config.expect || config.expect_re_str);
311 printf (", '%s' returned '%s' in %fs", np_dbi_query, 292 printf(", '%s' returned '%s' in %fs", config.dbi_query, query_val_str ? query_val_str : "<nothing>", query_time);
312 query_val_str ? query_val_str : "<nothing>", query_time);
313 if (status != STATE_OK) { 293 if (status != STATE_OK) {
314 if (expect) 294 if (config.expect) {
315 printf (" (expected '%s')", expect); 295 printf(" (expected '%s')", config.expect);
316 else if (expect_re_str) 296 } else if (config.expect_re_str) {
317 printf (" (expected regex /%s/%s)", expect_re_str, 297 printf(" (expected regex /%s/%s)", config.expect_re_str, ((config.expect_re_cflags & REG_ICASE) ? "i" : ""));
318 ((expect_re_cflags & REG_ICASE) ? "i" : "")); 298 }
319 } 299 }
300 } else if (isnan(query_val)) {
301 printf(", '%s' query execution time: %fs", config.dbi_query, query_time);
302 } else {
303 printf(", '%s' returned %f in %fs", config.dbi_query, query_val, query_time);
320 } 304 }
321 else if (isnan (query_val)) 305 }
322 printf (", '%s' query execution time: %fs", np_dbi_query, query_time); 306
323 else 307 printf(" | conntime=%fs;%s;%s;0; server_version=%u;%s;%s;0;", conn_time,
324 printf (", '%s' returned %f in %fs", np_dbi_query, query_val, query_time); 308 ((config.metric == METRIC_CONN_TIME) && config.warning_range) ? config.warning_range : "",
325 } 309 ((config.metric == METRIC_CONN_TIME) && config.critical_range) ? config.critical_range : "", server_version,
326 310 ((config.metric == METRIC_SERVER_VERSION) && config.warning_range) ? config.warning_range : "",
327 printf (" | conntime=%fs;%s;%s;0; server_version=%u;%s;%s;0;", conn_time, 311 ((config.metric == METRIC_SERVER_VERSION) && config.critical_range) ? config.critical_range : "");
328 ((metric == METRIC_CONN_TIME) && warning_range) ? warning_range : "", 312 if (config.dbi_query) {
329 ((metric == METRIC_CONN_TIME) && critical_range) ? critical_range : "", 313 if (!isnan(query_val)) { /* this is also true when -e is used */
330 server_version, 314 printf(" query=%f;%s;%s;;", query_val, ((config.metric == METRIC_QUERY_RESULT) && config.warning_range) ? config.warning_range : "",
331 ((metric == METRIC_SERVER_VERSION) && warning_range) ? warning_range : "", 315 ((config.metric == METRIC_QUERY_RESULT) && config.critical_range) ? config.critical_range : "");
332 ((metric == METRIC_SERVER_VERSION) && critical_range) ? critical_range : ""); 316 }
333 if (np_dbi_query) { 317 printf(" querytime=%fs;%s;%s;0;", query_time, ((config.metric == METRIC_QUERY_TIME) && config.warning_range) ? config.warning_range : "",
334 if (! isnan (query_val)) /* this is also true when -e is used */ 318 ((config.metric == METRIC_QUERY_TIME) && config.critical_range) ? config.critical_range : "");
335 printf (" query=%f;%s;%s;;", query_val, 319 }
336 ((metric == METRIC_QUERY_RESULT) && warning_range) ? warning_range : "", 320 printf("\n");
337 ((metric == METRIC_QUERY_RESULT) && critical_range) ? critical_range : "");
338 printf (" querytime=%fs;%s;%s;0;", query_time,
339 ((metric == METRIC_QUERY_TIME) && warning_range) ? warning_range : "",
340 ((metric == METRIC_QUERY_TIME) && critical_range) ? critical_range : "");
341 }
342 printf ("\n");
343 return status; 321 return status;
344} 322}
345 323
346/* process command-line arguments */ 324/* process command-line arguments */
347int 325check_dbi_config_wrapper process_arguments(int argc, char **argv) {
348process_arguments (int argc, char **argv)
349{
350 int c;
351 326
352 int option = 0; 327 int option = 0;
353 static struct option longopts[] = { 328 static struct option longopts[] = {STD_LONG_OPTS,
354 STD_LONG_OPTS, 329
355 330 {"expect", required_argument, 0, 'e'},
356 {"expect", required_argument, 0, 'e'}, 331 {"regex", required_argument, 0, 'r'},
357 {"regex", required_argument, 0, 'r'}, 332 {"regexi", required_argument, 0, 'R'},
358 {"regexi", required_argument, 0, 'R'}, 333 {"metric", required_argument, 0, 'm'},
359 {"metric", required_argument, 0, 'm'}, 334 {"driver", required_argument, 0, 'd'},
360 {"driver", required_argument, 0, 'd'}, 335 {"option", required_argument, 0, 'o'},
361 {"option", required_argument, 0, 'o'}, 336 {"query", required_argument, 0, 'q'},
362 {"query", required_argument, 0, 'q'}, 337 {"database", required_argument, 0, 'D'},
363 {"database", required_argument, 0, 'D'}, 338 {0, 0, 0, 0}};
364 {0, 0, 0, 0} 339
340 check_dbi_config_wrapper result = {
341 .config = check_dbi_config_init(),
342 .errorcode = OK,
365 }; 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);
366 347
367 while (1) { 348 if (option_char == EOF) {
368 c = getopt_long (argc, argv, "Vvht:c:w:e:r:R:m:H:d:o:q:D:",
369 longopts, &option);
370
371 if (c == EOF)
372 break; 349 break;
350 }
373 351
374 switch (c) { 352 switch (option_char) {
375 case '?': /* usage */ 353 case '?': /* usage */
376 usage5 (); 354 usage5();
377 case 'h': /* help */ 355 case 'h': /* help */
378 print_help (); 356 print_help();
379 exit (STATE_UNKNOWN); 357 exit(STATE_UNKNOWN);
380 case 'V': /* version */ 358 case 'V': /* version */
381 print_revision (progname, NP_VERSION); 359 print_revision(progname, NP_VERSION);
382 exit (STATE_UNKNOWN); 360 exit(STATE_UNKNOWN);
383 361
384 case 'c': /* critical range */ 362 case 'c': /* critical range */
385 critical_range = optarg; 363 result.config.critical_range = optarg;
386 type = TYPE_NUMERIC; 364 result.config.type = TYPE_NUMERIC;
387 break; 365 break;
388 case 'w': /* warning range */ 366 case 'w': /* warning range */
389 warning_range = optarg; 367 result.config.warning_range = optarg;
390 type = TYPE_NUMERIC; 368 result.config.type = TYPE_NUMERIC;
391 break; 369 break;
392 case 'e': 370 case 'e':
393 expect = optarg; 371 result.config.expect = optarg;
394 type = TYPE_STRING; 372 result.config.type = TYPE_STRING;
395 break; 373 break;
396 case 'R': 374 case 'R':
397 expect_re_cflags = REG_ICASE; 375 result.config.expect_re_cflags = REG_ICASE;
398 /* fall through */ 376 /* fall through */
399 case 'r': 377 case 'r': {
400 { 378 int err;
401 int err; 379
402 380 result.config.expect_re_cflags |= REG_EXTENDED | REG_NOSUB | REG_NEWLINE;
403 expect_re_cflags |= REG_EXTENDED | REG_NOSUB | REG_NEWLINE; 381 result.config.expect_re_str = optarg;
404 expect_re_str = optarg; 382 result.config.type = TYPE_STRING;
405 type = TYPE_STRING; 383
406 384 regex_t expect_re = {};
407 err = regcomp (&expect_re, expect_re_str, expect_re_cflags); 385 err = regcomp(&expect_re, result.config.expect_re_str, result.config.expect_re_cflags);
408 if (err) { 386 if (err) {
409 char errmsg[1024]; 387 char errmsg[1024];
410 regerror (err, &expect_re, errmsg, sizeof (errmsg)); 388 regerror(err, &expect_re, errmsg, sizeof(errmsg));
411 printf ("ERROR - failed to compile regular expression: %s\n", 389 printf("ERROR - failed to compile regular expression: %s\n", errmsg);
412 errmsg); 390
413 return ERROR; 391 result.errorcode = ERROR;
414 } 392 return result;
415 break;
416 } 393 }
394 break;
395 }
417 396
418 case 'm': 397 case 'm':
419 if (! strcasecmp (optarg, "CONN_TIME")) 398 if (!strcasecmp(optarg, "CONN_TIME")) {
420 metric = METRIC_CONN_TIME; 399 result.config.metric = METRIC_CONN_TIME;
421 else if (! strcasecmp (optarg, "SERVER_VERSION")) 400 } else if (!strcasecmp(optarg, "SERVER_VERSION")) {
422 metric = METRIC_SERVER_VERSION; 401 result.config.metric = METRIC_SERVER_VERSION;
423 else if (! strcasecmp (optarg, "QUERY_RESULT")) 402 } else if (!strcasecmp(optarg, "QUERY_RESULT")) {
424 metric = METRIC_QUERY_RESULT; 403 result.config.metric = METRIC_QUERY_RESULT;
425 else if (! strcasecmp (optarg, "QUERY_TIME")) 404 } else if (!strcasecmp(optarg, "QUERY_TIME")) {
426 metric = METRIC_QUERY_TIME; 405 result.config.metric = METRIC_QUERY_TIME;
427 else 406 } else {
428 usage2 (_("Invalid metric"), optarg); 407 usage2(_("Invalid metric"), optarg);
408 }
429 break; 409 break;
430 case 't': /* timeout */ 410 case 't': /* timeout */
431 if (!is_intnonneg (optarg)) 411 if (!is_intnonneg(optarg)) {
432 usage2 (_("Timeout interval must be a positive integer"), optarg); 412 usage2(_("Timeout interval must be a positive integer"), optarg);
433 else 413 } else {
434 timeout_interval = atoi (optarg); 414 timeout_interval = atoi(optarg);
415 }
435 416
436 break; 417 break;
437 case 'H': /* host */ 418 case 'H': /* host */
438 if (!is_host (optarg)) 419 if (!is_host(optarg)) {
439 usage2 (_("Invalid hostname/address"), optarg); 420 usage2(_("Invalid hostname/address"), optarg);
440 else 421 } else {
441 host = optarg; 422 result.config.host = optarg;
423 }
442 break; 424 break;
443 case 'v': 425 case 'v':
444 verbose++; 426 verbose++;
445 break; 427 break;
446 428
447 case 'd': 429 case 'd':
448 np_dbi_driver = optarg; 430 result.config.dbi_driver = optarg;
449 break; 431 break;
450 case 'o': 432 case 'o': {
451 { 433 driver_option_t *new = NULL;
452 driver_option_t *new;
453
454 char *k, *v;
455 434
456 k = optarg; 435 char *key = optarg;
457 v = strchr (k, (int)'='); 436 char *value = strchr(key, '=');
458 437
459 if (! v) 438 if (!value) {
460 usage2 (_("Option must be '<key>=<value>'"), optarg); 439 usage2(_("Option must be '<key>=<value>'"), optarg);
440 }
461 441
462 *v = '\0'; 442 *value = '\0';
463 ++v; 443 ++value;
464 444
465 new = realloc (np_dbi_options, 445 new = realloc(result.config.dbi_options, (result.config.dbi_options_num + 1) * sizeof(*new));
466 (np_dbi_options_num + 1) * sizeof (*new)); 446 if (!new) {
467 if (! new) { 447 printf("UNKNOWN - failed to reallocate memory\n");
468 printf ("UNKNOWN - failed to reallocate memory\n"); 448 exit(STATE_UNKNOWN);
469 exit (STATE_UNKNOWN); 449 }
470 }
471 450
472 np_dbi_options = new; 451 result.config.dbi_options = new;
473 new = np_dbi_options + np_dbi_options_num; 452 new = result.config.dbi_options + result.config.dbi_options_num;
474 ++np_dbi_options_num; 453 result.config.dbi_options_num++;
475 454
476 new->key = k; 455 new->key = key;
477 new->value = v; 456 new->value = value;
478 } 457 } break;
479 break;
480 case 'q': 458 case 'q':
481 np_dbi_query = optarg; 459 result.config.dbi_query = optarg;
482 break; 460 break;
483 case 'D': 461 case 'D':
484 np_dbi_database = optarg; 462 result.config.dbi_database = optarg;
485 break; 463 break;
486 } 464 }
487 } 465 }
488 466
489 set_thresholds (&dbi_thresholds, warning_range, critical_range); 467 set_thresholds(&result.config.dbi_thresholds, result.config.warning_range, result.config.critical_range);
490 468
491 return validate_arguments (); 469 return validate_arguments(result);
492} 470}
493 471
494int 472check_dbi_config_wrapper validate_arguments(check_dbi_config_wrapper config_wrapper) {
495validate_arguments () 473 if (!config_wrapper.config.dbi_driver) {
496{ 474 usage("Must specify a DBI driver");
497 if (! np_dbi_driver) 475 }
498 usage ("Must specify a DBI driver");
499 476
500 if (((metric == METRIC_QUERY_RESULT) || (metric == METRIC_QUERY_TIME)) 477 if (((config_wrapper.config.metric == METRIC_QUERY_RESULT) || (config_wrapper.config.metric == METRIC_QUERY_TIME)) &&
501 && (! np_dbi_query)) 478 (!config_wrapper.config.dbi_query)) {
502 usage ("Must specify a query to execute (metric == QUERY_RESULT)"); 479 usage("Must specify a query to execute (metric == QUERY_RESULT)");
480 }
503 481
504 if ((metric != METRIC_CONN_TIME) 482 if ((config_wrapper.config.metric != METRIC_CONN_TIME) && (config_wrapper.config.metric != METRIC_SERVER_VERSION) &&
505 && (metric != METRIC_SERVER_VERSION) 483 (config_wrapper.config.metric != METRIC_QUERY_RESULT) && (config_wrapper.config.metric != METRIC_QUERY_TIME)) {
506 && (metric != METRIC_QUERY_RESULT) 484 usage("Invalid metric specified");
507 && (metric != METRIC_QUERY_TIME)) 485 }
508 usage ("Invalid metric specified");
509 486
510 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)) {
511 usage ("Do not mix -e and -w/-c/-r/-R"); 488 usage("Do not mix -e and -w/-c/-r/-R");
489 }
512 490
513 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)) {
514 usage ("Do not mix -r/-R and -w/-c/-e"); 492 usage("Do not mix -r/-R and -w/-c/-e");
493 }
515 494
516 if (expect && (metric != METRIC_QUERY_RESULT)) 495 if (config_wrapper.config.expect && (config_wrapper.config.metric != METRIC_QUERY_RESULT)) {
517 usage ("Option -e requires metric QUERY_RESULT"); 496 usage("Option -e requires metric QUERY_RESULT");
497 }
518 498
519 if (expect_re_str && (metric != METRIC_QUERY_RESULT)) 499 if (config_wrapper.config.expect_re_str && (config_wrapper.config.metric != METRIC_QUERY_RESULT)) {
520 usage ("Options -r/-R require metric QUERY_RESULT"); 500 usage("Options -r/-R require metric QUERY_RESULT");
501 }
521 502
522 return OK; 503 config_wrapper.errorcode = OK;
504 return config_wrapper;
523} 505}
524 506
525void 507void print_help(void) {
526print_help (void) 508 print_revision(progname, NP_VERSION);
527{
528 print_revision (progname, NP_VERSION);
529 509
530 printf (COPYRIGHT, copyright, email); 510 printf(COPYRIGHT, copyright, email);
531 511
532 printf (_("This program connects to an (SQL) database using DBI and checks the\n" 512 printf(_("This program connects to an (SQL) database using DBI and checks the\n"
533 "specified metric against threshold levels. The default metric is\n" 513 "specified metric against threshold levels. The default metric is\n"
534 "the result of the specified query.\n")); 514 "the result of the specified query.\n"));
535 515
536 printf ("\n\n"); 516 printf("\n\n");
537 517
538 print_usage (); 518 print_usage();
539 519
540 printf (UT_HELP_VRSN); 520 printf(UT_HELP_VRSN);
541/* include this conditionally to avoid 'zero-length printf format string' 521/* include this conditionally to avoid 'zero-length printf format string'
542 * compiler warnings */ 522 * compiler warnings */
543#ifdef NP_EXTRA_OPTS 523#ifdef NP_EXTRA_OPTS
544 printf (UT_EXTRA_OPTS); 524 printf(UT_EXTRA_OPTS);
545#endif 525#endif
546 printf ("\n"); 526 printf("\n");
547 527
548 printf (" %s\n", "-d, --driver=STRING"); 528 printf(" %s\n", "-d, --driver=STRING");
549 printf (" %s\n", _("DBI driver to use")); 529 printf(" %s\n", _("DBI driver to use"));
550 printf (" %s\n", "-o, --option=STRING"); 530 printf(" %s\n", "-o, --option=STRING");
551 printf (" %s\n", _("DBI driver options")); 531 printf(" %s\n", _("DBI driver options"));
552 printf (" %s\n", "-q, --query=STRING"); 532 printf(" %s\n", "-q, --query=STRING");
553 printf (" %s\n", _("query to execute")); 533 printf(" %s\n", _("query to execute"));
554 printf ("\n"); 534 printf(" %s\n", "-H STRING");
555 535 printf(" %s\n", _("target database host"));
556 printf (UT_WARN_CRIT_RANGE); 536 printf("\n");
557 printf (" %s\n", "-e, --expect=STRING"); 537
558 printf (" %s\n", _("String to expect as query result")); 538 printf(UT_WARN_CRIT_RANGE);
559 printf (" %s\n", _("Do not mix with -w, -c, -r, or -R!")); 539 printf(" %s\n", "-e, --expect=STRING");
560 printf (" %s\n", "-r, --regex=REGEX"); 540 printf(" %s\n", _("String to expect as query result"));
561 printf (" %s\n", _("Extended POSIX regular expression to check query result against")); 541 printf(" %s\n", _("Do not mix with -w, -c, -r, or -R!"));
562 printf (" %s\n", _("Do not mix with -w, -c, -e, or -R!")); 542 printf(" %s\n", "-r, --regex=REGEX");
563 printf (" %s\n", "-R, --regexi=REGEX"); 543 printf(" %s\n", _("Extended POSIX regular expression to check query result against"));
564 printf (" %s\n", _("Case-insensitive extended POSIX regex to check query result against")); 544 printf(" %s\n", _("Do not mix with -w, -c, -e, or -R!"));
565 printf (" %s\n", _("Do not mix with -w, -c, -e, or -r!")); 545 printf(" %s\n", "-R, --regexi=REGEX");
566 printf (" %s\n", "-m, --metric=METRIC"); 546 printf(" %s\n", _("Case-insensitive extended POSIX regex to check query result against"));
567 printf (" %s\n", _("Metric to check thresholds against. Available metrics:")); 547 printf(" %s\n", _("Do not mix with -w, -c, -e, or -r!"));
568 printf (" CONN_TIME - %s\n", _("time used for setting up the database connection")); 548 printf(" %s\n", "-m, --metric=METRIC");
569 printf (" QUERY_RESULT - %s\n", _("result (first column of first row) of the query")); 549 printf(" %s\n", _("Metric to check thresholds against. Available metrics:"));
570 printf (" QUERY_TIME - %s\n", _("time used to execute the query")); 550 printf(" CONN_TIME - %s\n", _("time used for setting up the database connection"));
571 printf (" %s\n", _("(ignore the query result)")); 551 printf(" QUERY_RESULT - %s\n", _("result (first column of first row) of the query"));
572 printf ("\n"); 552 printf(" QUERY_TIME - %s\n", _("time used to execute the query"));
573 553 printf(" %s\n", _("(ignore the query result)"));
574 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 554 printf("\n");
575 555
576 printf (UT_VERBOSE); 556 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
577 557
578 printf ("\n"); 558 printf(UT_VERBOSE);
579 printf (" %s\n", _("A DBI driver (-d option) is required. If the specified metric operates")); 559
580 printf (" %s\n\n", _("on a query, one has to be specified (-q option).")); 560 printf("\n");
581 561 printf(" %s\n", _("A DBI driver (-d option) is required. If the specified metric operates"));
582 printf (" %s\n", _("This plugin connects to an (SQL) database using libdbi and, optionally,")); 562 printf(" %s\n\n", _("on a query, one has to be specified (-q option)."));
583 printf (" %s\n", _("executes the specified query. The first column of the first row of the")); 563
584 printf (" %s\n", _("result will be parsed and, in QUERY_RESULT mode, compared with the")); 564 printf(" %s\n", _("This plugin connects to an (SQL) database using libdbi and, optionally,"));
585 printf (" %s\n", _("warning and critical ranges. The result from the query has to be numeric")); 565 printf(" %s\n", _("executes the specified query. The first column of the first row of the"));
586 printf (" %s\n\n", _("(strings representing numbers are fine).")); 566 printf(" %s\n", _("result will be parsed and, in QUERY_RESULT mode, compared with the"));
587 567 printf(" %s\n", _("warning and critical ranges. The result from the query has to be numeric"));
588 printf (" %s\n", _("The number and type of required DBI driver options depends on the actual")); 568 printf(" %s\n\n", _("(strings representing numbers are fine)."));
589 printf (" %s\n", _("driver. See its documentation at http://libdbi-drivers.sourceforge.net/")); 569
590 printf (" %s\n\n", _("for details.")); 570 printf(" %s\n", _("The number and type of required DBI driver options depends on the actual"));
591 571 printf(" %s\n", _("driver. See its documentation at http://libdbi-drivers.sourceforge.net/"));
592 printf (" %s\n", _("Examples:")); 572 printf(" %s\n\n", _("for details."));
593 printf (" check_dbi -d pgsql -o username=postgres -m QUERY_RESULT \\\n"); 573
594 printf (" -q 'SELECT COUNT(*) FROM pg_stat_activity' -w 5 -c 10\n"); 574 printf(" %s\n", _("Examples:"));
595 printf (" Warning if more than five connections; critical if more than ten.\n\n"); 575 printf(" check_dbi -d pgsql -o username=postgres -m QUERY_RESULT \\\n");
596 576 printf(" -q 'SELECT COUNT(*) FROM pg_stat_activity' -w 5 -c 10\n");
597 printf (" check_dbi -d mysql -H localhost -o username=user -o password=secret \\\n"); 577 printf(" Warning if more than five connections; critical if more than ten.\n\n");
598 printf (" -q 'SELECT COUNT(*) FROM logged_in_users -w 5:20 -c 0:50\n"); 578
599 printf (" Warning if less than 5 or more than 20 users are logged in; critical\n"); 579 printf(" check_dbi -d mysql -H localhost -o username=user -o password=secret \\\n");
600 printf (" if more than 50 users.\n\n"); 580 printf(" -q 'SELECT COUNT(*) FROM logged_in_users -w 5:20 -c 0:50\n");
601 581 printf(" Warning if less than 5 or more than 20 users are logged in; critical\n");
602 printf (" check_dbi -d firebird -o username=user -o password=secret -o dbname=foo \\\n"); 582 printf(" if more than 50 users.\n\n");
603 printf (" -m CONN_TIME -w 0.5 -c 2\n"); 583
604 printf (" Warning if connecting to the database takes more than half of a second;\n"); 584 printf(" check_dbi -d firebird -o username=user -o password=secret -o dbname=foo \\\n");
605 printf (" critical if it takes more than 2 seconds.\n\n"); 585 printf(" -m CONN_TIME -w 0.5 -c 2\n");
606 586 printf(" Warning if connecting to the database takes more than half of a second;\n");
607 printf (" check_dbi -d mysql -H localhost -o username=user \\\n"); 587 printf(" critical if it takes more than 2 seconds.\n\n");
608 printf (" -q 'SELECT concat(@@version, \" \", @@version_comment)' \\\n"); 588
609 printf (" -r '^5\\.[01].*MySQL Enterprise Server'\n"); 589 printf(" check_dbi -d mysql -H localhost -o username=user \\\n");
610 printf (" Critical if the database server is not a MySQL enterprise server in either\n"); 590 printf(" -q 'SELECT concat(@@version, \" \", @@version_comment)' \\\n");
611 printf (" version 5.0.x or 5.1.x.\n\n"); 591 printf(" -r '^5\\.[01].*MySQL Enterprise Server'\n");
612 592 printf(" Critical if the database server is not a MySQL enterprise server in either\n");
613 printf (" check_dbi -d pgsql -u username=user -m SERVER_VERSION \\\n"); 593 printf(" version 5.0.x or 5.1.x.\n\n");
614 printf (" -w 090000:090099 -c 090000:090199\n"); 594
615 printf (" Warn if the PostgreSQL server version is not 9.0.x; critical if the version\n"); 595 printf(" check_dbi -d pgsql -u username=user -m SERVER_VERSION \\\n");
616 printf (" is less than 9.x or higher than 9.1.x.\n"); 596 printf(" -w 090000:090099 -c 090000:090199\n");
617 597 printf(" Warn if the PostgreSQL server version is not 9.0.x; critical if the version\n");
618 printf (UT_SUPPORT); 598 printf(" is less than 9.x or higher than 9.1.x.\n");
599
600 printf(UT_SUPPORT);
619} 601}
620 602
621void 603void print_usage(void) {
622print_usage (void) 604 printf("%s\n", _("Usage:"));
623{ 605 printf("%s -d <DBI driver> [-o <DBI driver option> [...]] [-q <query>]\n", progname);
624 printf ("%s\n", _("Usage:")); 606 printf(" [-H <host>] [-c <critical range>] [-w <warning range>] [-m <metric>]\n");
625 printf ("%s -d <DBI driver> [-o <DBI driver option> [...]] [-q <query>]\n", progname); 607 printf(" [-e <string>] [-r|-R <regex>]\n");
626 printf (" [-H <host>] [-c <critical range>] [-w <warning range>] [-m <metric>]\n");
627 printf (" [-e <string>] [-r|-R <regex>]\n");
628} 608}
629 609
630#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) {
631 do { \
632 if (metric != METRIC_QUERY_RESULT) \
633 return (s); \
634 } while (0)
635
636const char *
637get_field_str (dbi_conn conn, dbi_result res, unsigned short field_type)
638{
639 const char *str; 611 const char *str;
640 612
641 if (field_type != DBI_TYPE_STRING) { 613 if (field_type != DBI_TYPE_STRING) {
642 printf ("CRITICAL - result value is not a string\n"); 614 printf("CRITICAL - result value is not a string\n");
643 return NULL; 615 return NULL;
644 } 616 }
645 617
646 str = dbi_result_get_string_idx (res, 1); 618 str = dbi_result_get_string_idx(res, 1);
647 if ((! str) || (strcmp (str, "ERROR") == 0)) { 619 if ((!str) || (strcmp(str, "ERROR") == 0)) {
648 CHECK_IGNORE_ERROR (NULL); 620 if (metric != METRIC_QUERY_RESULT) {
649 np_dbi_print_error (conn, "CRITICAL - failed to fetch string value"); 621 return NULL;
622 }
623 np_dbi_print_error(conn, "CRITICAL - failed to fetch string value");
650 return NULL; 624 return NULL;
651 } 625 }
652 626
653 if ((verbose && (type == TYPE_STRING)) || (verbose > 2)) 627 if ((verbose && (type == TYPE_STRING)) || (verbose > 2)) {
654 printf ("Query returned string '%s'\n", str); 628 printf("Query returned string '%s'\n", str);
629 }
655 return str; 630 return str;
656} 631}
657 632
658double 633double get_field(dbi_conn conn, dbi_result res, unsigned short *field_type, mp_dbi_metric metric, mp_dbi_type type) {
659get_field (dbi_conn conn, dbi_result res, unsigned short *field_type)
660{
661 double val = NAN; 634 double val = NAN;
662 635
663 if (*field_type == DBI_TYPE_INTEGER) { 636 if (*field_type == DBI_TYPE_INTEGER) {
664 val = (double)dbi_result_get_longlong_idx (res, 1); 637 val = (double)dbi_result_get_longlong_idx(res, 1);
665 } 638 } else if (*field_type == DBI_TYPE_DECIMAL) {
666 else if (*field_type == DBI_TYPE_DECIMAL) { 639 val = dbi_result_get_double_idx(res, 1);
667 val = dbi_result_get_double_idx (res, 1); 640 } else if (*field_type == DBI_TYPE_STRING) {
668 }
669 else if (*field_type == DBI_TYPE_STRING) {
670 const char *val_str; 641 const char *val_str;
671 char *endptr = NULL; 642 char *endptr = NULL;
672 643
673 val_str = get_field_str (conn, res, *field_type); 644 val_str = get_field_str(conn, res, *field_type, metric, type);
674 if (! val_str) { 645 if (!val_str) {
675 CHECK_IGNORE_ERROR (NAN); 646 if (metric != METRIC_QUERY_RESULT) {
647 return NAN;
648 }
676 *field_type = DBI_TYPE_ERROR; 649 *field_type = DBI_TYPE_ERROR;
677 return NAN; 650 return NAN;
678 } 651 }
679 652
680 val = strtod (val_str, &endptr); 653 val = strtod(val_str, &endptr);
681 if (endptr == val_str) { 654 if (endptr == val_str) {
682 CHECK_IGNORE_ERROR (NAN); 655 if (metric != METRIC_QUERY_RESULT) {
683 printf ("CRITICAL - result value is not a numeric: %s\n", val_str); 656 return NAN;
657 }
658 printf("CRITICAL - result value is not a numeric: %s\n", val_str);
684 *field_type = DBI_TYPE_ERROR; 659 *field_type = DBI_TYPE_ERROR;
685 return NAN; 660 return NAN;
686 } 661 }
687 else if ((endptr != NULL) && (*endptr != '\0')) { 662 if ((endptr != NULL) && (*endptr != '\0')) {
688 if (verbose) 663 if (verbose) {
689 printf ("Garbage after value: %s\n", endptr); 664 printf("Garbage after value: %s\n", endptr);
665 }
690 } 666 }
691 } 667 } else {
692 else { 668 if (metric != METRIC_QUERY_RESULT) {
693 CHECK_IGNORE_ERROR (NAN); 669 return NAN;
694 printf ("CRITICAL - cannot parse value of type %s (%i)\n", 670 }
695 (*field_type == DBI_TYPE_BINARY) 671 printf("CRITICAL - cannot parse value of type %s (%i)\n",
696 ? "BINARY" 672 (*field_type == DBI_TYPE_BINARY) ? "BINARY"
697 : (*field_type == DBI_TYPE_DATETIME) 673 : (*field_type == DBI_TYPE_DATETIME) ? "DATETIME"
698 ? "DATETIME" 674 : "<unknown>",
699 : "<unknown>", 675 *field_type);
700 *field_type);
701 *field_type = DBI_TYPE_ERROR; 676 *field_type = DBI_TYPE_ERROR;
702 return NAN; 677 return NAN;
703 } 678 }
704 return val; 679 return val;
705} 680}
706 681
707double 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) {
708get_query_result (dbi_conn conn, dbi_result res, const char **res_val_str, double *res_val)
709{
710 unsigned short field_type; 683 unsigned short field_type;
711 double val = NAN; 684 double val = NAN;
712 685
713 if (dbi_result_get_numrows (res) == DBI_ROW_ERROR) { 686 if (dbi_result_get_numrows(res) == DBI_ROW_ERROR) {
714 CHECK_IGNORE_ERROR (STATE_OK); 687 if (metric != METRIC_QUERY_RESULT) {
715 np_dbi_print_error (conn, "CRITICAL - failed to fetch rows"); 688 return STATE_OK;
689 }
690 np_dbi_print_error(conn, "CRITICAL - failed to fetch rows");
716 return STATE_CRITICAL; 691 return STATE_CRITICAL;
717 } 692 }
718 693
719 if (dbi_result_get_numrows (res) < 1) { 694 if (dbi_result_get_numrows(res) < 1) {
720 CHECK_IGNORE_ERROR (STATE_OK); 695 if (metric != METRIC_QUERY_RESULT) {
721 printf ("WARNING - no rows returned\n"); 696 return STATE_OK;
697 }
698 printf("WARNING - no rows returned\n");
722 return STATE_WARNING; 699 return STATE_WARNING;
723 } 700 }
724 701
725 if (dbi_result_get_numfields (res) == DBI_FIELD_ERROR) { 702 if (dbi_result_get_numfields(res) == DBI_FIELD_ERROR) {
726 CHECK_IGNORE_ERROR (STATE_OK); 703 if (metric != METRIC_QUERY_RESULT) {
727 np_dbi_print_error (conn, "CRITICAL - failed to fetch fields"); 704 return STATE_OK;
705 }
706 np_dbi_print_error(conn, "CRITICAL - failed to fetch fields");
728 return STATE_CRITICAL; 707 return STATE_CRITICAL;
729 } 708 }
730 709
731 if (dbi_result_get_numfields (res) < 1) { 710 if (dbi_result_get_numfields(res) < 1) {
732 CHECK_IGNORE_ERROR (STATE_OK); 711 if (metric != METRIC_QUERY_RESULT) {
733 printf ("WARNING - no fields returned\n"); 712 return STATE_OK;
713 }
714 printf("WARNING - no fields returned\n");
734 return STATE_WARNING; 715 return STATE_WARNING;
735 } 716 }
736 717
737 if (dbi_result_first_row (res) != 1) { 718 if (dbi_result_first_row(res) != 1) {
738 CHECK_IGNORE_ERROR (STATE_OK); 719 if (metric != METRIC_QUERY_RESULT) {
739 np_dbi_print_error (conn, "CRITICAL - failed to fetch first row"); 720 return STATE_OK;
721 }
722 np_dbi_print_error(conn, "CRITICAL - failed to fetch first row");
740 return STATE_CRITICAL; 723 return STATE_CRITICAL;
741 } 724 }
742 725
743 field_type = dbi_result_get_field_type_idx (res, 1); 726 field_type = dbi_result_get_field_type_idx(res, 1);
744 if (field_type != DBI_TYPE_ERROR) { 727 if (field_type != DBI_TYPE_ERROR) {
745 if (type == TYPE_STRING) 728 if (type == TYPE_STRING) {
746 /* the value will be freed in dbi_result_free */ 729 /* the value will be freed in dbi_result_free */
747 *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));
748 else 731 } else {
749 val = get_field (conn, res, &field_type); 732 val = get_field(conn, res, &field_type, metric, type);
733 }
750 } 734 }
751 735
752 *res_val = val; 736 *res_val = val;
753 737
754 if (field_type == DBI_TYPE_ERROR) { 738 if (field_type == DBI_TYPE_ERROR) {
755 CHECK_IGNORE_ERROR (STATE_OK); 739 if (metric != METRIC_QUERY_RESULT) {
756 np_dbi_print_error (conn, "CRITICAL - failed to fetch data"); 740 return STATE_OK;
741 }
742 np_dbi_print_error(conn, "CRITICAL - failed to fetch data");
757 return STATE_CRITICAL; 743 return STATE_CRITICAL;
758 } 744 }
759 745
760 dbi_result_free (res); 746 dbi_result_free(res);
761 return STATE_OK; 747 return STATE_OK;
762} 748}
763 749
764#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,
765 751 char *np_dbi_query) {
766int
767do_query (dbi_conn conn, const char **res_val_str, double *res_val, double *res_time)
768{
769 dbi_result res; 752 dbi_result res;
770 753
771 struct timeval timeval_start, timeval_end; 754 struct timeval timeval_start;
772 int status = STATE_OK; 755 struct timeval timeval_end;
756 mp_state_enum status = STATE_OK;
773 757
774 assert (np_dbi_query); 758 assert(np_dbi_query);
775 759
776 if (verbose) 760 if (verbose) {
777 printf ("Executing query '%s'\n", np_dbi_query); 761 printf("Executing query '%s'\n", np_dbi_query);
762 }
778 763
779 gettimeofday (&timeval_start, NULL); 764 gettimeofday(&timeval_start, NULL);
780 765
781 res = dbi_conn_query (conn, np_dbi_query); 766 res = dbi_conn_query(conn, np_dbi_query);
782 if (! res) { 767 if (!res) {
783 np_dbi_print_error (conn, "CRITICAL - failed to execute query '%s'", np_dbi_query); 768 np_dbi_print_error(conn, "CRITICAL - failed to execute query '%s'", np_dbi_query);
784 return STATE_CRITICAL; 769 return STATE_CRITICAL;
785 } 770 }
786 771
787 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);
788 773
789 gettimeofday (&timeval_end, NULL); 774 gettimeofday(&timeval_end, NULL);
790 *res_time = timediff (timeval_start, timeval_end); 775 *res_time = timediff(timeval_start, timeval_end);
791 776
792 if (verbose) 777 if (verbose) {
793 printf ("Time elapsed: %f\n", *res_time); 778 printf("Time elapsed: %f\n", *res_time);
779 }
794 780
795 return status; 781 return status;
796} 782}
797 783
798double 784double timediff(struct timeval start, struct timeval end) {
799timediff (struct timeval start, struct timeval end)
800{
801 double diff; 785 double diff;
802 786
803 while (start.tv_usec > end.tv_usec) { 787 while (start.tv_usec > end.tv_usec) {
804 --end.tv_sec; 788 --end.tv_sec;
805 end.tv_usec += 1000000; 789 end.tv_usec += 1000000;
806 } 790 }
807 diff = (double)(end.tv_sec - start.tv_sec) 791 diff = (double)(end.tv_sec - start.tv_sec) + (double)(end.tv_usec - start.tv_usec) / 1000000.0;
808 + (double)(end.tv_usec - start.tv_usec) / 1000000.0;
809 return diff; 792 return diff;
810} 793}
811 794
812void 795void np_dbi_print_error(dbi_conn conn, char *fmt, ...) {
813np_dbi_print_error (dbi_conn conn, char *fmt, ...)
814{
815 const char *errmsg = NULL; 796 const char *errmsg = NULL;
816 va_list ap; 797 va_list ap;
817 798
818 va_start (ap, fmt); 799 va_start(ap, fmt);
819 800
820 dbi_conn_error (conn, &errmsg); 801 dbi_conn_error(conn, &errmsg);
821 vprintf (fmt, ap); 802 vprintf(fmt, ap);
822 printf (": %s\n", errmsg); 803 printf(": %s\n", errmsg);
823 804
824 va_end (ap); 805 va_end(ap);
825} 806}
826