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