diff options
Diffstat (limited to 'plugins/check_dbi.c')
-rw-r--r-- | plugins/check_dbi.c | 1080 |
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 | ||
32 | const char *progname = "check_dbi"; | 32 | const char *progname = "check_dbi"; |
33 | const char *copyright = "2011"; | 33 | const char *copyright = "2011-2024"; |
34 | const char *email = "devel@monitoring-plugins.org"; | 34 | const 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 | ||
56 | typedef enum { | 58 | static 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 | |||
63 | typedef enum { | ||
64 | TYPE_NUMERIC, | ||
65 | TYPE_STRING, | ||
66 | } np_dbi_type_t; | ||
67 | 59 | ||
68 | typedef struct { | 60 | typedef 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 | |||
73 | char *host = NULL; | ||
74 | int verbose = 0; | ||
75 | |||
76 | char *warning_range = NULL; | ||
77 | char *critical_range = NULL; | ||
78 | thresholds *dbi_thresholds = NULL; | ||
79 | |||
80 | char *expect = NULL; | ||
81 | |||
82 | regex_t expect_re; | ||
83 | char *expect_re_str = NULL; | ||
84 | int expect_re_cflags = 0; | ||
85 | |||
86 | np_dbi_metric_t metric = METRIC_QUERY_RESULT; | ||
87 | np_dbi_type_t type = TYPE_NUMERIC; | ||
88 | 64 | ||
89 | char *np_dbi_driver = NULL; | 65 | static check_dbi_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/); |
90 | driver_option_t *np_dbi_options = NULL; | 66 | static check_dbi_config_wrapper validate_arguments(check_dbi_config_wrapper /*config_wrapper*/); |
91 | int np_dbi_options_num = 0; | 67 | void print_usage(void); |
92 | char *np_dbi_database = NULL; | 68 | static void print_help(void); |
93 | char *np_dbi_query = NULL; | ||
94 | 69 | ||
95 | int process_arguments (int, char **); | 70 | static double timediff(struct timeval /*start*/, struct timeval /*end*/); |
96 | int validate_arguments (void); | ||
97 | void print_usage (void); | ||
98 | void print_help (void); | ||
99 | 71 | ||
100 | double timediff (struct timeval, struct timeval); | 72 | static void np_dbi_print_error(dbi_conn /*conn*/, char * /*fmt*/, ...); |
101 | 73 | ||
102 | void np_dbi_print_error (dbi_conn, char *, ...); | 74 | static 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 | ||
104 | int do_query (dbi_conn, const char **, double *, double *); | 78 | int main(int argc, char **argv) { |
105 | |||
106 | int | ||
107 | main (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 */ |
347 | int | 350 | check_dbi_config_wrapper process_arguments(int argc, char **argv) { |
348 | process_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 | ||
494 | int | 499 | check_dbi_config_wrapper validate_arguments(check_dbi_config_wrapper config_wrapper) { |
495 | validate_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 | ||
525 | void | 542 | void print_help(void) { |
526 | print_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 | ||
621 | void | 638 | void print_usage(void) { |
622 | print_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) \ | 645 | const 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 | |||
636 | const char * | ||
637 | get_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 | ||
658 | double | 669 | double get_field(dbi_conn conn, dbi_result res, unsigned short *field_type, mp_dbi_metric metric, |
659 | get_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 | ||
707 | double | 719 | mp_state_enum get_query_result(dbi_conn conn, dbi_result res, const char **res_val_str, |
708 | get_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 | 788 | mp_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) { | |
766 | int | ||
767 | do_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 | ||
798 | double | 822 | double timediff(struct timeval start, struct timeval end) { |
799 | timediff (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 | ||
812 | void | 833 | void np_dbi_print_error(dbi_conn conn, char *fmt, ...) { |
813 | np_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 | |||