summaryrefslogtreecommitdiffstats
path: root/plugins/check_pgsql.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/check_pgsql.c')
-rw-r--r--plugins/check_pgsql.c499
1 files changed, 324 insertions, 175 deletions
diff --git a/plugins/check_pgsql.c b/plugins/check_pgsql.c
index 6613634d..9e6b0f41 100644
--- a/plugins/check_pgsql.c
+++ b/plugins/check_pgsql.c
@@ -28,62 +28,63 @@
28 * 28 *
29 *****************************************************************************/ 29 *****************************************************************************/
30 30
31const char *progname = "check_pgsql"; 31#include "output.h"
32const char *copyright = "1999-2024"; 32#include "perfdata.h"
33const char *email = "devel@monitoring-plugins.org"; 33#include "states.h"
34
35#include "common.h" 34#include "common.h"
36#include "utils.h" 35#include "utils.h"
37#include "utils_cmd.h" 36#include "utils_cmd.h"
38 37#include "check_pgsql.d/config.h"
38#include "thresholds.h"
39#include "netutils.h" 39#include "netutils.h"
40#include <libpq-fe.h> 40#include <libpq-fe.h>
41#include <pg_config_manual.h> 41#include <pg_config_manual.h>
42 42
43#define DEFAULT_DB "template1" 43const char *progname = "check_pgsql";
44const char *copyright = "1999-2024";
45const char *email = "devel@monitoring-plugins.org";
46
44#define DEFAULT_HOST "127.0.0.1" 47#define DEFAULT_HOST "127.0.0.1"
45 48
46/* return the PSQL server version as a 3-tuple */ 49/* return the PSQL server version as a 3-tuple */
47#define PSQL_SERVER_VERSION3(server_version) \ 50#define PSQL_SERVER_VERSION3(server_version) \
48 (server_version) / 10000, (server_version) / 100 - (int)((server_version) / 10000) * 100, \ 51 ((server_version) / 10000), \
49 (server_version) - (int)((server_version) / 100) * 100 52 (((server_version) / 100) - (int)(((server_version) / 10000) * 100)), \
53 (server_version) - (int)(((server_version) / 100) * 100)
50/* return true if the given host is a UNIX domain socket */ 54/* return true if the given host is a UNIX domain socket */
51#define PSQL_IS_UNIX_DOMAIN_SOCKET(host) ((NULL == (host)) || ('\0' == *(host)) || ('/' == *(host))) 55#define PSQL_IS_UNIX_DOMAIN_SOCKET(host) ((NULL == (host)) || ('\0' == *(host)) || ('/' == *(host)))
52/* return a 3-tuple identifying a host/port independent of the socket type */ 56/* return a 3-tuple identifying a host/port independent of the socket type */
53#define PSQL_SOCKET3(host, port) \ 57#define PSQL_SOCKET3(host, port) \
54 ((NULL == (host)) || ('\0' == *(host))) ? DEFAULT_PGSOCKET_DIR : host, PSQL_IS_UNIX_DOMAIN_SOCKET(host) ? "/.s.PGSQL." : ":", port 58 ((NULL == (host)) || ('\0' == *(host))) ? DEFAULT_PGSOCKET_DIR : host, \
59 PSQL_IS_UNIX_DOMAIN_SOCKET(host) ? "/.s.PGSQL." : ":", port
55 60
56enum { 61typedef struct {
57 DEFAULT_PORT = 5432, 62 int errorcode;
58 DEFAULT_WARN = 2, 63 check_pgsql_config config;
59 DEFAULT_CRIT = 8 64} check_pgsql_config_wrapper;
60}; 65static check_pgsql_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
61 66
62static int process_arguments(int /*argc*/, char ** /*argv*/);
63static void print_help(void); 67static void print_help(void);
64static bool is_pg_logname(char * /*username*/); 68static bool is_pg_logname(char * /*username*/);
65static int do_query(PGconn * /*conn*/, char * /*query*/); 69
70typedef enum {
71 QUERY_OK,
72 ERROR_WITH_QUERY, // critical
73 NO_ROWS_RETURNED, // warning
74 NO_COLUMNS_RETURNED, // warning
75 NO_DATA_RETURNED, // critica/
76 RESULT_IS_NOT_NUMERIC // critical
77} do_query_errorcode;
78
79typedef struct {
80 do_query_errorcode error_code;
81 double numerical_result;
82} do_query_wrapper;
83static do_query_wrapper do_query(PGconn * /*conn*/, char * /*query*/);
66void print_usage(void); 84void print_usage(void);
67 85
68static char *pghost = NULL; /* host name of the backend server */
69static char *pgport = NULL; /* port of the backend server */
70static char *pgoptions = NULL;
71static char *pgtty = NULL;
72static char dbName[NAMEDATALEN] = DEFAULT_DB;
73static char *pguser = NULL;
74static char *pgpasswd = NULL;
75static char *pgparams = NULL;
76static double twarn = (double)DEFAULT_WARN;
77static double tcrit = (double)DEFAULT_CRIT;
78static char *pgquery = NULL;
79static char *pgqueryname = NULL;
80static char *query_warning = NULL;
81static char *query_critical = NULL;
82static thresholds *qthresholds = NULL;
83static int verbose = 0; 86static int verbose = 0;
84 87
85#define OPTID_QUERYNAME -1000
86
87/****************************************************************************** 88/******************************************************************************
88 89
89The (pseudo?)literate programming XML is contained within \@\@\- <XML> \-\@\@ 90The (pseudo?)literate programming XML is contained within \@\@\- <XML> \-\@\@
@@ -139,21 +140,19 @@ int main(int argc, char **argv) {
139 bindtextdomain(PACKAGE, LOCALEDIR); 140 bindtextdomain(PACKAGE, LOCALEDIR);
140 textdomain(PACKAGE); 141 textdomain(PACKAGE);
141 142
142 /* begin, by setting the parameters for a backend connection if the
143 * parameters are null, then the system will try to use reasonable
144 * defaults by looking up environment variables or, failing that,
145 * using hardwired constants */
146
147 pgoptions = NULL; /* special options to start up the backend server */
148 pgtty = NULL; /* debugging tty for the backend server */
149
150 /* Parse extra opts if any */ 143 /* Parse extra opts if any */
151 argv = np_extra_opts(&argc, argv, progname); 144 argv = np_extra_opts(&argc, argv, progname);
152 145
153 if (process_arguments(argc, argv) == ERROR) 146 check_pgsql_config_wrapper tmp_config = process_arguments(argc, argv);
147 if (tmp_config.errorcode == ERROR) {
154 usage4(_("Could not parse arguments")); 148 usage4(_("Could not parse arguments"));
155 if (verbose > 2) 149 }
156 printf("Arguments initialized\n"); 150
151 const check_pgsql_config config = tmp_config.config;
152
153 if (config.output_format_is_set) {
154 mp_set_format(config.output_format);
155 }
157 156
158 /* Set signal handling and alarm */ 157 /* Set signal handling and alarm */
159 if (signal(SIGALRM, timeout_alarm_handler) == SIG_ERR) { 158 if (signal(SIGALRM, timeout_alarm_handler) == SIG_ERR) {
@@ -162,25 +161,33 @@ int main(int argc, char **argv) {
162 alarm(timeout_interval); 161 alarm(timeout_interval);
163 162
164 char *conninfo = NULL; 163 char *conninfo = NULL;
165 if (pgparams) 164 if (config.pgparams) {
166 asprintf(&conninfo, "%s ", pgparams); 165 asprintf(&conninfo, "%s ", config.pgparams);
167 166 }
168 asprintf(&conninfo, "%sdbname = '%s'", conninfo ? conninfo : "", dbName); 167
169 if (pghost) 168 asprintf(&conninfo, "%sdbname = '%s'", conninfo ? conninfo : "", config.dbName);
170 asprintf(&conninfo, "%s host = '%s'", conninfo, pghost); 169 if (config.pghost) {
171 if (pgport) 170 asprintf(&conninfo, "%s host = '%s'", conninfo, config.pghost);
172 asprintf(&conninfo, "%s port = '%s'", conninfo, pgport); 171 }
173 if (pgoptions) 172 if (config.pgport) {
174 asprintf(&conninfo, "%s options = '%s'", conninfo, pgoptions); 173 asprintf(&conninfo, "%s port = '%s'", conninfo, config.pgport);
174 }
175 if (config.pgoptions) {
176 asprintf(&conninfo, "%s options = '%s'", conninfo, config.pgoptions);
177 }
175 /* if (pgtty) -- ignored by PQconnectdb */ 178 /* if (pgtty) -- ignored by PQconnectdb */
176 if (pguser) 179 if (config.pguser) {
177 asprintf(&conninfo, "%s user = '%s'", conninfo, pguser); 180 asprintf(&conninfo, "%s user = '%s'", conninfo, config.pguser);
181 }
178 182
179 if (verbose) /* do not include password (see right below) in output */ 183 if (verbose) { /* do not include password (see right below) in output */
180 printf("Connecting to PostgreSQL using conninfo: %s%s\n", conninfo, pgpasswd ? " password = <hidden>" : ""); 184 printf("Connecting to PostgreSQL using conninfo: %s%s\n", conninfo,
185 config.pgpasswd ? " password = <hidden>" : "");
186 }
181 187
182 if (pgpasswd) 188 if (config.pgpasswd) {
183 asprintf(&conninfo, "%s password = '%s'", conninfo, pgpasswd); 189 asprintf(&conninfo, "%s password = '%s'", conninfo, config.pgpasswd);
190 }
184 191
185 /* make a connection to the database */ 192 /* make a connection to the database */
186 struct timeval start_timeval; 193 struct timeval start_timeval;
@@ -193,30 +200,54 @@ int main(int argc, char **argv) {
193 --end_timeval.tv_sec; 200 --end_timeval.tv_sec;
194 end_timeval.tv_usec += 1000000; 201 end_timeval.tv_usec += 1000000;
195 } 202 }
196 double elapsed_time = 203 double elapsed_time = (double)(end_timeval.tv_sec - start_timeval.tv_sec) +
197 (double)(end_timeval.tv_sec - start_timeval.tv_sec) + (double)(end_timeval.tv_usec - start_timeval.tv_usec) / 1000000.0; 204 ((double)(end_timeval.tv_usec - start_timeval.tv_usec) / 1000000.0);
198 205
199 if (verbose) 206 if (verbose) {
200 printf("Time elapsed: %f\n", elapsed_time); 207 printf("Time elapsed: %f\n", elapsed_time);
208 }
201 209
202 /* check to see that the backend connection was successfully made */ 210 /* check to see that the backend connection was successfully made */
203 if (verbose) 211 if (verbose) {
204 printf("Verifying connection\n"); 212 printf("Verifying connection\n");
205 if (PQstatus(conn) == CONNECTION_BAD) {
206 printf(_("CRITICAL - no connection to '%s' (%s).\n"), dbName, PQerrorMessage(conn));
207 PQfinish(conn);
208 return STATE_CRITICAL;
209 } 213 }
210 214
211 int status = STATE_UNKNOWN; 215 mp_check overall = mp_check_init();
212 if (elapsed_time > tcrit) { 216
213 status = STATE_CRITICAL; 217 mp_set_ok_summary(&overall, "Postgres check is OK");
214 } else if (elapsed_time > twarn) { 218
215 status = STATE_WARNING; 219 mp_subcheck sc_connection = mp_subcheck_init();
220
221 if (PQstatus(conn) == CONNECTION_BAD) {
222 sc_connection = mp_set_subcheck_state(sc_connection, STATE_CRITICAL);
223 xasprintf(&sc_connection.output, "no connection to '%s' (%s)", config.dbName,
224 PQerrorMessage(conn));
225 PQfinish(conn);
226 mp_add_subcheck_to_check(&overall, sc_connection);
227 mp_exit(overall);
216 } else { 228 } else {
217 status = STATE_OK; 229 sc_connection = mp_set_subcheck_state(sc_connection, STATE_OK);
230 xasprintf(&sc_connection.output, "connected to '%s'", config.dbName);
231 mp_add_subcheck_to_check(&overall, sc_connection);
218 } 232 }
219 233
234 mp_subcheck sc_connection_time = mp_subcheck_init();
235 sc_connection_time = mp_set_subcheck_default_state(sc_connection_time, STATE_UNKNOWN);
236
237 xasprintf(&sc_connection_time.output, "connection time: %.10g", elapsed_time);
238
239 mp_perfdata pd_connection_time = perfdata_init();
240 pd_connection_time.label = "time";
241 pd_connection_time.uom = "s";
242 pd_connection_time = mp_set_pd_value(pd_connection_time, elapsed_time);
243 pd_connection_time = mp_pd_set_thresholds(pd_connection_time, config.time_thresholds);
244
245 mp_add_perfdata_to_subcheck(&sc_connection_time, pd_connection_time);
246 sc_connection_time =
247 mp_set_subcheck_state(sc_connection_time, mp_get_pd_status(pd_connection_time));
248
249 mp_add_subcheck_to_check(&overall, sc_connection_time);
250
220 if (verbose) { 251 if (verbose) {
221 char *server_host = PQhost(conn); 252 char *server_host = PQhost(conn);
222 int server_version = PQserverVersion(conn); 253 int server_version = PQserverVersion(conn);
@@ -224,25 +255,91 @@ int main(int argc, char **argv) {
224 printf("Successfully connected to database %s (user %s) " 255 printf("Successfully connected to database %s (user %s) "
225 "at server %s%s%s (server version: %d.%d.%d, " 256 "at server %s%s%s (server version: %d.%d.%d, "
226 "protocol version: %d, pid: %d)\n", 257 "protocol version: %d, pid: %d)\n",
227 PQdb(conn), PQuser(conn), PSQL_SOCKET3(server_host, PQport(conn)), PSQL_SERVER_VERSION3(server_version), 258 PQdb(conn), PQuser(conn), PSQL_SOCKET3(server_host, PQport(conn)),
228 PQprotocolVersion(conn), PQbackendPID(conn)); 259 PSQL_SERVER_VERSION3(server_version), PQprotocolVersion(conn), PQbackendPID(conn));
229 } 260 }
230 261
231 printf(_(" %s - database %s (%f sec.)|%s\n"), state_text(status), dbName, elapsed_time, 262 if (config.pgquery) {
232 fperfdata("time", elapsed_time, "s", !!(twarn > 0.0), twarn, !!(tcrit > 0.0), tcrit, true, 0, false, 0)); 263 mp_subcheck sc_query = mp_subcheck_init();
264 sc_query = mp_set_subcheck_default_state(sc_query, STATE_UNKNOWN);
265 if (config.pgqueryname) {
266 xasprintf(&sc_query.output, "query '%s'", config.pgqueryname);
267 } else {
268 xasprintf(&sc_query.output, "query '%s'", config.pgquery);
269 }
270
271 do_query_wrapper query_result = do_query(conn, config.pgquery);
233 272
234 int query_status = STATE_UNKNOWN; 273 switch (query_result.error_code) {
235 if (pgquery) 274 case QUERY_OK: {
236 query_status = do_query(conn, pgquery); 275 // Query was successful and there is a numerical result
276 sc_query = mp_set_subcheck_state(sc_query, STATE_OK);
277 xasprintf(&sc_query.output, "%s succeeded", sc_query.output);
278
279 mp_perfdata pd_query = perfdata_init();
280 pd_query = mp_set_pd_value(pd_query, query_result.numerical_result);
281 pd_query = mp_pd_set_thresholds(pd_query, config.qthresholds);
282 pd_query.label = "query";
283
284 mp_subcheck sc_query_compare = mp_subcheck_init();
285 mp_state_enum query_compare_state = mp_get_pd_status(pd_query);
286
287 sc_query_compare = mp_set_subcheck_state(sc_query_compare, query_compare_state);
288 mp_add_perfdata_to_subcheck(&sc_query_compare, pd_query);
289
290 if (query_compare_state == STATE_OK) {
291 xasprintf(&sc_query_compare.output, "query result '%f' is within thresholds",
292 query_result.numerical_result);
293 } else {
294 xasprintf(&sc_query_compare.output, "query result '%f' is violating thresholds",
295 query_result.numerical_result);
296 }
297 mp_add_subcheck_to_check(&overall, sc_query_compare);
237 298
238 if (verbose) 299 } break;
300 case ERROR_WITH_QUERY:
301 xasprintf(&sc_query.output, "%s - Error with query: %s", sc_query.output,
302 PQerrorMessage(conn));
303 sc_query = mp_set_subcheck_state(sc_query, STATE_CRITICAL);
304 break;
305 case NO_ROWS_RETURNED:
306 xasprintf(&sc_query.output, "%s - no rows were returned by the query", sc_query.output);
307 sc_query = mp_set_subcheck_state(sc_query, STATE_WARNING);
308 break;
309 case NO_COLUMNS_RETURNED:
310 xasprintf(&sc_query.output, "%s - no columns were returned by the query",
311 sc_query.output);
312 sc_query = mp_set_subcheck_state(sc_query, STATE_WARNING);
313 break;
314 case NO_DATA_RETURNED:
315 xasprintf(&sc_query.output, "%s - no data was returned by the query", sc_query.output);
316 sc_query = mp_set_subcheck_state(sc_query, STATE_WARNING);
317 break;
318 case RESULT_IS_NOT_NUMERIC:
319 xasprintf(&sc_query.output, "%s - result of the query is not numeric", sc_query.output);
320 sc_query = mp_set_subcheck_state(sc_query, STATE_CRITICAL);
321 break;
322 };
323
324 mp_add_subcheck_to_check(&overall, sc_query);
325 }
326
327 if (verbose) {
239 printf("Closing connection\n"); 328 printf("Closing connection\n");
329 }
240 PQfinish(conn); 330 PQfinish(conn);
241 return (pgquery && query_status > status) ? query_status : status; 331
332 mp_exit(overall);
242} 333}
243 334
244/* process command-line arguments */ 335/* process command-line arguments */
245int process_arguments(int argc, char **argv) { 336static check_pgsql_config_wrapper process_arguments(int argc, char **argv) {
337
338 enum {
339 OPTID_QUERYNAME = CHAR_MAX + 1,
340 output_format_index,
341 };
342
246 static struct option longopts[] = {{"help", no_argument, 0, 'h'}, 343 static struct option longopts[] = {{"help", no_argument, 0, 'h'},
247 {"version", no_argument, 0, 'V'}, 344 {"version", no_argument, 0, 'V'},
248 {"timeout", required_argument, 0, 't'}, 345 {"timeout", required_argument, 0, 't'},
@@ -260,16 +357,35 @@ int process_arguments(int argc, char **argv) {
260 {"query_critical", required_argument, 0, 'C'}, 357 {"query_critical", required_argument, 0, 'C'},
261 {"query_warning", required_argument, 0, 'W'}, 358 {"query_warning", required_argument, 0, 'W'},
262 {"verbose", no_argument, 0, 'v'}, 359 {"verbose", no_argument, 0, 'v'},
360 {"output-format", required_argument, 0, output_format_index},
263 {0, 0, 0, 0}}; 361 {0, 0, 0, 0}};
264 362
363 check_pgsql_config_wrapper result = {
364 .errorcode = OK,
365 .config = check_pgsql_config_init(),
366 };
367
265 while (true) { 368 while (true) {
266 int option = 0; 369 int option = 0;
267 int option_char = getopt_long(argc, argv, "hVt:c:w:H:P:d:l:p:a:o:q:C:W:v", longopts, &option); 370 int option_char =
371 getopt_long(argc, argv, "hVt:c:w:H:P:d:l:p:a:o:q:C:W:v", longopts, &option);
268 372
269 if (option_char == EOF) 373 if (option_char == EOF) {
270 break; 374 break;
375 }
271 376
272 switch (option_char) { 377 switch (option_char) {
378 case output_format_index: {
379 parsed_output_format parser = mp_parse_output_format(optarg);
380 if (!parser.parsing_success) {
381 printf("Invalid output format: %s\n", optarg);
382 exit(STATE_UNKNOWN);
383 }
384
385 result.config.output_format_is_set = true;
386 result.config.output_format = parser.output_format;
387 break;
388 }
273 case '?': /* usage */ 389 case '?': /* usage */
274 usage5(); 390 usage5();
275 case 'h': /* help */ 391 case 'h': /* help */
@@ -279,68 +395,89 @@ int process_arguments(int argc, char **argv) {
279 print_revision(progname, NP_VERSION); 395 print_revision(progname, NP_VERSION);
280 exit(STATE_UNKNOWN); 396 exit(STATE_UNKNOWN);
281 case 't': /* timeout period */ 397 case 't': /* timeout period */
282 if (!is_integer(optarg)) 398 if (!is_integer(optarg)) {
283 usage2(_("Timeout interval must be a positive integer"), optarg); 399 usage2(_("Timeout interval must be a positive integer"), optarg);
284 else 400 } else {
285 timeout_interval = atoi(optarg); 401 timeout_interval = atoi(optarg);
402 }
286 break; 403 break;
287 case 'c': /* critical time threshold */ 404 case 'c': /* critical time threshold */ {
288 if (!is_nonnegative(optarg)) 405 mp_range_parsed tmp = mp_parse_range_string(optarg);
289 usage2(_("Critical threshold must be a positive integer"), optarg); 406 if (tmp.error != MP_PARSING_SUCCESS) {
290 else 407 die(STATE_UNKNOWN, "failed to parse critical time threshold");
291 tcrit = strtod(optarg, NULL); 408 }
292 break; 409 result.config.time_thresholds =
293 case 'w': /* warning time threshold */ 410 mp_thresholds_set_crit(result.config.time_thresholds, tmp.range);
294 if (!is_nonnegative(optarg)) 411 } break;
295 usage2(_("Warning threshold must be a positive integer"), optarg); 412 case 'w': /* warning time threshold */ {
296 else 413 mp_range_parsed tmp = mp_parse_range_string(optarg);
297 twarn = strtod(optarg, NULL); 414 if (tmp.error != MP_PARSING_SUCCESS) {
298 break; 415 die(STATE_UNKNOWN, "failed to parse warning time threshold");
299 case 'C': /* critical query threshold */ 416 }
300 query_critical = optarg; 417 result.config.time_thresholds =
301 break; 418 mp_thresholds_set_warn(result.config.time_thresholds, tmp.range);
302 case 'W': /* warning query threshold */ 419 } break;
303 query_warning = optarg; 420 case 'C': /* critical query threshold */ {
304 break; 421 mp_range_parsed tmp = mp_parse_range_string(optarg);
422 if (tmp.error != MP_PARSING_SUCCESS) {
423 die(STATE_UNKNOWN, "failed to parse critical query threshold");
424 }
425
426 result.config.qthresholds =
427 mp_thresholds_set_crit(result.config.qthresholds, tmp.range);
428
429 } break;
430 case 'W': /* warning query threshold */ {
431 mp_range_parsed tmp = mp_parse_range_string(optarg);
432 if (tmp.error != MP_PARSING_SUCCESS) {
433 die(STATE_UNKNOWN, "failed to parse warning query threshold");
434 }
435 result.config.qthresholds =
436 mp_thresholds_set_warn(result.config.qthresholds, tmp.range);
437 } break;
305 case 'H': /* host */ 438 case 'H': /* host */
306 if ((*optarg != '/') && (!is_host(optarg))) 439 if ((*optarg != '/') && (!is_host(optarg))) {
307 usage2(_("Invalid hostname/address"), optarg); 440 usage2(_("Invalid hostname/address"), optarg);
308 else 441 } else {
309 pghost = optarg; 442 result.config.pghost = optarg;
443 }
310 break; 444 break;
311 case 'P': /* port */ 445 case 'P': /* port */
312 if (!is_integer(optarg)) 446 if (!is_integer(optarg)) {
313 usage2(_("Port must be a positive integer"), optarg); 447 usage2(_("Port must be a positive integer"), optarg);
314 else 448 } else {
315 pgport = optarg; 449 result.config.pgport = optarg;
450 }
316 break; 451 break;
317 case 'd': /* database name */ 452 case 'd': /* database name */
318 if (strlen(optarg) >= NAMEDATALEN) { 453 if (strlen(optarg) >= NAMEDATALEN) {
319 usage2(_("Database name exceeds the maximum length"), optarg); 454 usage2(_("Database name exceeds the maximum length"), optarg);
320 } 455 }
321 snprintf(dbName, NAMEDATALEN, "%s", optarg); 456 snprintf(result.config.dbName, NAMEDATALEN, "%s", optarg);
322 break; 457 break;
323 case 'l': /* login name */ 458 case 'l': /* login name */
324 if (!is_pg_logname(optarg)) 459 if (!is_pg_logname(optarg)) {
325 usage2(_("User name is not valid"), optarg); 460 usage2(_("User name is not valid"), optarg);
326 else 461 } else {
327 pguser = optarg; 462 result.config.pguser = optarg;
463 }
328 break; 464 break;
329 case 'p': /* authentication password */ 465 case 'p': /* authentication password */
330 case 'a': 466 case 'a':
331 pgpasswd = optarg; 467 result.config.pgpasswd = optarg;
332 break; 468 break;
333 case 'o': 469 case 'o':
334 if (pgparams) 470 if (result.config.pgparams) {
335 asprintf(&pgparams, "%s %s", pgparams, optarg); 471 asprintf(&result.config.pgparams, "%s %s", result.config.pgparams, optarg);
336 else 472 } else {
337 asprintf(&pgparams, "%s", optarg); 473 asprintf(&result.config.pgparams, "%s", optarg);
474 }
338 break; 475 break;
339 case 'q': 476 case 'q':
340 pgquery = optarg; 477 result.config.pgquery = optarg;
341 break; 478 break;
342 case OPTID_QUERYNAME: 479 case OPTID_QUERYNAME:
343 pgqueryname = optarg; 480 result.config.pgqueryname = optarg;
344 break; 481 break;
345 case 'v': 482 case 'v':
346 verbose++; 483 verbose++;
@@ -348,9 +485,7 @@ int process_arguments(int argc, char **argv) {
348 } 485 }
349 } 486 }
350 487
351 set_thresholds(&qthresholds, query_warning, query_critical); 488 return result;
352
353 return OK;
354} 489}
355 490
356/** 491/**
@@ -377,9 +512,10 @@ should be added.</para>
377-@@ 512-@@
378******************************************************************************/ 513******************************************************************************/
379 514
380bool is_pg_logname(char *username) { 515static bool is_pg_logname(char *username) {
381 if (strlen(username) > NAMEDATALEN - 1) 516 if (strlen(username) > NAMEDATALEN - 1) {
382 return (false); 517 return (false);
518 }
383 return (true); 519 return (true);
384} 520}
385 521
@@ -394,7 +530,7 @@ bool is_pg_logname(char *username) {
394void print_help(void) { 530void print_help(void) {
395 char *myport; 531 char *myport;
396 532
397 xasprintf(&myport, "%d", DEFAULT_PORT); 533 xasprintf(&myport, "%d", 5432);
398 534
399 print_revision(progname, NP_VERSION); 535 print_revision(progname, NP_VERSION);
400 536
@@ -430,12 +566,13 @@ void print_help(void) {
430 printf(" %s\n", "--queryname=STRING"); 566 printf(" %s\n", "--queryname=STRING");
431 printf(" %s\n", _("A name for the query, this string is used instead of the query")); 567 printf(" %s\n", _("A name for the query, this string is used instead of the query"));
432 printf(" %s\n", _("in the long output of the plugin")); 568 printf(" %s\n", _("in the long output of the plugin"));
433 printf(" %s\n", "-W, --query-warning=RANGE"); 569 printf(" %s\n", "-W, --query_warning=RANGE");
434 printf(" %s\n", _("SQL query value to result in warning status (double)")); 570 printf(" %s\n", _("SQL query value to result in warning status (double)"));
435 printf(" %s\n", "-C, --query-critical=RANGE"); 571 printf(" %s\n", "-C, --query_critical=RANGE");
436 printf(" %s\n", _("SQL query value to result in critical status (double)")); 572 printf(" %s\n", _("SQL query value to result in critical status (double)"));
437 573
438 printf(UT_VERBOSE); 574 printf(UT_VERBOSE);
575 printf(UT_OUTPUT_FORMAT);
439 576
440 printf("\n"); 577 printf("\n");
441 printf(" %s\n", _("All parameters are optional.")); 578 printf(" %s\n", _("All parameters are optional."));
@@ -447,29 +584,39 @@ void print_help(void) {
447 584
448 printf(" %s\n", _("If a query is specified using the -q option, it will be executed after")); 585 printf(" %s\n", _("If a query is specified using the -q option, it will be executed after"));
449 printf(" %s\n", _("connecting to the server. The result from the query has to be numeric.")); 586 printf(" %s\n", _("connecting to the server. The result from the query has to be numeric."));
450 printf(" %s\n", _("Multiple SQL commands, separated by semicolon, are allowed but the result ")); 587 printf(" %s\n",
588 _("Multiple SQL commands, separated by semicolon, are allowed but the result "));
451 printf(" %s\n", _("of the last command is taken into account only. The value of the first")); 589 printf(" %s\n", _("of the last command is taken into account only. The value of the first"));
452 printf(" %s\n", _("column in the first row is used as the check result. If a second column is")); 590 printf(" %s\n",
591 _("column in the first row is used as the check result. If a second column is"));
453 printf(" %s\n", _("present in the result set, this is added to the plugin output with a")); 592 printf(" %s\n", _("present in the result set, this is added to the plugin output with a"));
454 printf(" %s\n", _("prefix of \"Extra Info:\". This information can be displayed in the system")); 593 printf(" %s\n",
594 _("prefix of \"Extra Info:\". This information can be displayed in the system"));
455 printf(" %s\n\n", _("executing the plugin.")); 595 printf(" %s\n\n", _("executing the plugin."));
456 596
457 printf(" %s\n", _("See the chapter \"Monitoring Database Activity\" of the PostgreSQL manual")); 597 printf(" %s\n", _("See the chapter \"Monitoring Database Activity\" of the PostgreSQL manual"));
458 printf(" %s\n\n", _("for details about how to access internal statistics of the database server.")); 598 printf(" %s\n\n",
599 _("for details about how to access internal statistics of the database server."));
459 600
460 printf(" %s\n", _("For a list of available connection parameters which may be used with the -o")); 601 printf(" %s\n",
461 printf(" %s\n", _("command line option, see the documentation for PQconnectdb() in the chapter")); 602 _("For a list of available connection parameters which may be used with the -o"));
603 printf(" %s\n",
604 _("command line option, see the documentation for PQconnectdb() in the chapter"));
462 printf(" %s\n", _("\"libpq - C Library\" of the PostgreSQL manual. For example, this may be")); 605 printf(" %s\n", _("\"libpq - C Library\" of the PostgreSQL manual. For example, this may be"));
463 printf(" %s\n", _("used to specify a service name in pg_service.conf to be used for additional")); 606 printf(" %s\n",
607 _("used to specify a service name in pg_service.conf to be used for additional"));
464 printf(" %s\n", _("connection parameters: -o 'service=<name>' or to specify the SSL mode:")); 608 printf(" %s\n", _("connection parameters: -o 'service=<name>' or to specify the SSL mode:"));
465 printf(" %s\n\n", _("-o 'sslmode=require'.")); 609 printf(" %s\n\n", _("-o 'sslmode=require'."));
466 610
467 printf(" %s\n", _("The plugin will connect to a local postmaster if no host is specified. To")); 611 printf(" %s\n", _("The plugin will connect to a local postmaster if no host is specified. To"));
468 printf(" %s\n", _("connect to a remote host, be sure that the remote postmaster accepts TCP/IP")); 612 printf(" %s\n",
613 _("connect to a remote host, be sure that the remote postmaster accepts TCP/IP"));
469 printf(" %s\n\n", _("connections (start the postmaster with the -i option).")); 614 printf(" %s\n\n", _("connections (start the postmaster with the -i option)."));
470 615
471 printf(" %s\n", _("Typically, the monitoring user (unless the --logname option is used) should be")); 616 printf(" %s\n",
472 printf(" %s\n", _("able to connect to the database without a password. The plugin can also send")); 617 _("Typically, the monitoring user (unless the --logname option is used) should be"));
618 printf(" %s\n",
619 _("able to connect to the database without a password. The plugin can also send"));
473 printf(" %s\n", _("a password, but no effort is made to obscure or encrypt the password.")); 620 printf(" %s\n", _("a password, but no effort is made to obscure or encrypt the password."));
474 621
475 printf(UT_SUPPORT); 622 printf(UT_SUPPORT);
@@ -482,64 +629,66 @@ void print_usage(void) {
482 "[-q <query>] [-C <critical query range>] [-W <warning query range>]\n"); 629 "[-q <query>] [-C <critical query range>] [-W <warning query range>]\n");
483} 630}
484 631
485int do_query(PGconn *conn, char *query) { 632static do_query_wrapper do_query(PGconn *conn, char *query) {
486 if (verbose) 633 if (verbose) {
487 printf("Executing SQL query \"%s\".\n", query); 634 printf("Executing SQL query \"%s\".\n", query);
635 }
488 PGresult *res = PQexec(conn, query); 636 PGresult *res = PQexec(conn, query);
489 637
638 do_query_wrapper result = {
639 .error_code = QUERY_OK,
640 };
641
490 if (PGRES_TUPLES_OK != PQresultStatus(res)) { 642 if (PGRES_TUPLES_OK != PQresultStatus(res)) {
491 printf(_("QUERY %s - %s: %s.\n"), _("CRITICAL"), _("Error with query"), PQerrorMessage(conn)); 643 // TODO
492 return STATE_CRITICAL; 644 // printf(_("QUERY %s - %s: %s.\n"), _("CRITICAL"), _("Error with query"),
645 // PQerrorMessage(conn));
646 result.error_code = ERROR_WITH_QUERY;
647 return result;
493 } 648 }
494 649
495 if (PQntuples(res) < 1) { 650 if (PQntuples(res) < 1) {
496 printf("QUERY %s - %s.\n", _("WARNING"), _("No rows returned")); 651 // TODO
497 return STATE_WARNING; 652 // printf("QUERY %s - %s.\n", _("WARNING"), _("No rows returned"));
653 result.error_code = NO_ROWS_RETURNED;
654 return result;
498 } 655 }
499 656
500 if (PQnfields(res) < 1) { 657 if (PQnfields(res) < 1) {
501 printf("QUERY %s - %s.\n", _("WARNING"), _("No columns returned")); 658 // TODO
502 return STATE_WARNING; 659 // printf("QUERY %s - %s.\n", _("WARNING"), _("No columns returned"));
660 result.error_code = NO_COLUMNS_RETURNED;
661 return result;
503 } 662 }
504 663
505 char *val_str = PQgetvalue(res, 0, 0); 664 char *val_str = PQgetvalue(res, 0, 0);
506 if (!val_str) { 665 if (!val_str) {
507 printf("QUERY %s - %s.\n", _("CRITICAL"), _("No data returned")); 666 // TODO
508 return STATE_CRITICAL; 667 // printf("QUERY %s - %s.\n", _("CRITICAL"), _("No data returned"));
668 result.error_code = NO_DATA_RETURNED;
669 return result;
509 } 670 }
510 671
511 char *endptr = NULL; 672 char *endptr = NULL;
512 double value = strtod(val_str, &endptr); 673 double value = strtod(val_str, &endptr);
513 if (verbose) 674 if (verbose) {
514 printf("Query result: %f\n", value); 675 printf("Query result: %f\n", value);
676 }
515 677
516 if (endptr == val_str) { 678 if (endptr == val_str) {
517 printf("QUERY %s - %s: %s\n", _("CRITICAL"), _("Is not a numeric"), val_str); 679 // TODO
518 return STATE_CRITICAL; 680 // printf("QUERY %s - %s: %s\n", _("CRITICAL"), _("Is not a numeric"), val_str);
681 result.error_code = RESULT_IS_NOT_NUMERIC;
682 return result;
519 } 683 }
520 684
521 if ((endptr != NULL) && (*endptr != '\0')) { 685 if ((endptr != NULL) && (*endptr != '\0')) {
522 if (verbose) 686 if (verbose) {
523 printf("Garbage after value: %s.\n", endptr); 687 printf("Garbage after value: %s.\n", endptr);
688 }
524 } 689 }
525 690
526 int my_status = get_status(value, qthresholds); 691 result.numerical_result = value;
527 printf("QUERY %s - ", (my_status == STATE_OK) ? _("OK")
528 : (my_status == STATE_WARNING) ? _("WARNING")
529 : (my_status == STATE_CRITICAL) ? _("CRITICAL")
530 : _("UNKNOWN"));
531 if (pgqueryname) {
532 printf(_("%s returned %f"), pgqueryname, value);
533 } else {
534 printf(_("'%s' returned %f"), query, value);
535 }
536 692
537 printf("|query=%f;%s;%s;;\n", value, query_warning ? query_warning : "", query_critical ? query_critical : ""); 693 return result;
538 if (PQnfields(res) > 1) {
539 char *extra_info = PQgetvalue(res, 0, 1);
540 if (extra_info != NULL) {
541 printf("Extra Info: %s\n", extra_info);
542 }
543 }
544 return my_status;
545} 694}