diff options
Diffstat (limited to 'plugins/check_pgsql.c')
-rw-r--r-- | plugins/check_pgsql.c | 737 |
1 files changed, 331 insertions, 406 deletions
diff --git a/plugins/check_pgsql.c b/plugins/check_pgsql.c index 94d589e1..84305adb 100644 --- a/plugins/check_pgsql.c +++ b/plugins/check_pgsql.c | |||
@@ -1,95 +1,75 @@ | |||
1 | /***************************************************************************** | 1 | /***************************************************************************** |
2 | * | 2 | * |
3 | * Monitoring check_pgsql plugin | 3 | * Monitoring check_pgsql plugin |
4 | * | 4 | * |
5 | * License: GPL | 5 | * License: GPL |
6 | * Copyright (c) 1999-2011 Monitoring Plugins Development Team | 6 | * Copyright (c) 1999-2024 Monitoring Plugins Development Team |
7 | * | 7 | * |
8 | * Description: | 8 | * Description: |
9 | * | 9 | * |
10 | * This file contains the check_pgsql plugin | 10 | * This file contains the check_pgsql plugin |
11 | * | 11 | * |
12 | * Test whether a PostgreSQL Database is accepting connections. | 12 | * Test whether a PostgreSQL Database is accepting connections. |
13 | * | 13 | * |
14 | * | 14 | * |
15 | * This program is free software: you can redistribute it and/or modify | 15 | * This program is free software: you can redistribute it and/or modify |
16 | * it under the terms of the GNU General Public License as published by | 16 | * it under the terms of the GNU General Public License as published by |
17 | * the Free Software Foundation, either version 3 of the License, or | 17 | * the Free Software Foundation, either version 3 of the License, or |
18 | * (at your option) any later version. | 18 | * (at your option) any later version. |
19 | * | 19 | * |
20 | * This program is distributed in the hope that it will be useful, | 20 | * This program is distributed in the hope that it will be useful, |
21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
23 | * GNU General Public License for more details. | 23 | * GNU General Public License for more details. |
24 | * | 24 | * |
25 | * You should have received a copy of the GNU General Public License | 25 | * You should have received a copy of the GNU General Public License |
26 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | 26 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
27 | * | 27 | * |
28 | * | 28 | * |
29 | *****************************************************************************/ | 29 | *****************************************************************************/ |
30 | 30 | ||
31 | #include "states.h" | ||
31 | const char *progname = "check_pgsql"; | 32 | const char *progname = "check_pgsql"; |
32 | const char *copyright = "1999-2011"; | 33 | const char *copyright = "1999-2024"; |
33 | const char *email = "devel@monitoring-plugins.org"; | 34 | const char *email = "devel@monitoring-plugins.org"; |
34 | 35 | ||
35 | #include "common.h" | 36 | #include "common.h" |
36 | #include "utils.h" | 37 | #include "utils.h" |
37 | #include "utils_cmd.h" | 38 | #include "utils_cmd.h" |
39 | #include "check_pgsql.d/config.h" | ||
40 | #include "thresholds.h" | ||
38 | 41 | ||
39 | #include "netutils.h" | 42 | #include "netutils.h" |
40 | #include <libpq-fe.h> | 43 | #include <libpq-fe.h> |
41 | #include <pg_config_manual.h> | 44 | #include <pg_config_manual.h> |
42 | 45 | ||
43 | #define DEFAULT_DB "template1" | ||
44 | #define DEFAULT_HOST "127.0.0.1" | 46 | #define DEFAULT_HOST "127.0.0.1" |
45 | 47 | ||
46 | /* return the PSQL server version as a 3-tuple */ | 48 | /* return the PSQL server version as a 3-tuple */ |
47 | #define PSQL_SERVER_VERSION3(server_version) \ | 49 | #define PSQL_SERVER_VERSION3(server_version) \ |
48 | (server_version) / 10000, \ | 50 | (server_version) / 10000, (server_version) / 100 - (int)((server_version) / 10000) * 100, \ |
49 | (server_version) / 100 - (int)((server_version) / 10000) * 100, \ | 51 | (server_version) - (int)((server_version) / 100) * 100 |
50 | (server_version) - (int)((server_version) / 100) * 100 | ||
51 | /* return true if the given host is a UNIX domain socket */ | 52 | /* return true if the given host is a UNIX domain socket */ |
52 | #define PSQL_IS_UNIX_DOMAIN_SOCKET(host) \ | 53 | #define PSQL_IS_UNIX_DOMAIN_SOCKET(host) ((NULL == (host)) || ('\0' == *(host)) || ('/' == *(host))) |
53 | ((NULL == (host)) || ('\0' == *(host)) || ('/' == *(host))) | ||
54 | /* return a 3-tuple identifying a host/port independent of the socket type */ | 54 | /* return a 3-tuple identifying a host/port independent of the socket type */ |
55 | #define PSQL_SOCKET3(host, port) \ | 55 | #define PSQL_SOCKET3(host, port) \ |
56 | ((NULL == (host)) || ('\0' == *(host))) ? DEFAULT_PGSOCKET_DIR : host, \ | 56 | ((NULL == (host)) || ('\0' == *(host))) ? DEFAULT_PGSOCKET_DIR : host, PSQL_IS_UNIX_DOMAIN_SOCKET(host) ? "/.s.PGSQL." : ":", port |
57 | PSQL_IS_UNIX_DOMAIN_SOCKET (host) ? "/.s.PGSQL." : ":", \ | 57 | |
58 | port | 58 | typedef struct { |
59 | 59 | int errorcode; | |
60 | enum { | 60 | check_pgsql_config config; |
61 | DEFAULT_PORT = 5432, | 61 | } check_pgsql_config_wrapper; |
62 | DEFAULT_WARN = 2, | 62 | static check_pgsql_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/); |
63 | DEFAULT_CRIT = 8 | 63 | |
64 | }; | 64 | static void print_help(void); |
65 | 65 | static bool is_pg_logname(char * /*username*/); | |
66 | 66 | static mp_state_enum do_query(PGconn * /*conn*/, char * /*query*/, const char /*pgqueryname*/[], thresholds * /*qthresholds*/, | |
67 | 67 | char * /*query_warning*/, char * /*query_critical*/); | |
68 | int process_arguments (int, char **); | 68 | void print_usage(void); |
69 | int validate_arguments (void); | 69 | |
70 | void print_usage (void); | 70 | static int verbose = 0; |
71 | void print_help (void); | 71 | |
72 | bool is_pg_logname (char *); | ||
73 | int do_query (PGconn *, char *); | ||
74 | |||
75 | char *pghost = NULL; /* host name of the backend server */ | ||
76 | char *pgport = NULL; /* port of the backend server */ | ||
77 | int default_port = DEFAULT_PORT; | ||
78 | char *pgoptions = NULL; | ||
79 | char *pgtty = NULL; | ||
80 | char dbName[NAMEDATALEN] = DEFAULT_DB; | ||
81 | char *pguser = NULL; | ||
82 | char *pgpasswd = NULL; | ||
83 | char *pgparams = NULL; | ||
84 | double twarn = (double)DEFAULT_WARN; | ||
85 | double tcrit = (double)DEFAULT_CRIT; | ||
86 | char *pgquery = NULL; | ||
87 | #define OPTID_QUERYNAME -1000 | 72 | #define OPTID_QUERYNAME -1000 |
88 | char *pgqueryname = NULL; | ||
89 | char *query_warning = NULL; | ||
90 | char *query_critical = NULL; | ||
91 | thresholds *qthresholds = NULL; | ||
92 | int verbose = 0; | ||
93 | 73 | ||
94 | /****************************************************************************** | 74 | /****************************************************************************** |
95 | 75 | ||
@@ -141,237 +121,235 @@ Please note that all tags must be lowercase to use the DocBook XML DTD. | |||
141 | -@@ | 121 | -@@ |
142 | ******************************************************************************/ | 122 | ******************************************************************************/ |
143 | 123 | ||
124 | int main(int argc, char **argv) { | ||
125 | setlocale(LC_ALL, ""); | ||
126 | bindtextdomain(PACKAGE, LOCALEDIR); | ||
127 | textdomain(PACKAGE); | ||
144 | 128 | ||
129 | /* Parse extra opts if any */ | ||
130 | argv = np_extra_opts(&argc, argv, progname); | ||
145 | 131 | ||
146 | int | 132 | check_pgsql_config_wrapper tmp_config = process_arguments(argc, argv); |
147 | main (int argc, char **argv) | 133 | if (tmp_config.errorcode == ERROR) { |
148 | { | 134 | usage4(_("Could not parse arguments")); |
149 | PGconn *conn; | 135 | } |
150 | char *conninfo = NULL; | ||
151 | |||
152 | struct timeval start_timeval; | ||
153 | struct timeval end_timeval; | ||
154 | double elapsed_time; | ||
155 | int status = STATE_UNKNOWN; | ||
156 | int query_status = STATE_UNKNOWN; | ||
157 | |||
158 | /* begin, by setting the parameters for a backend connection if the | ||
159 | * parameters are null, then the system will try to use reasonable | ||
160 | * defaults by looking up environment variables or, failing that, | ||
161 | * using hardwired constants */ | ||
162 | |||
163 | pgoptions = NULL; /* special options to start up the backend server */ | ||
164 | pgtty = NULL; /* debugging tty for the backend server */ | ||
165 | |||
166 | setlocale (LC_ALL, ""); | ||
167 | bindtextdomain (PACKAGE, LOCALEDIR); | ||
168 | textdomain (PACKAGE); | ||
169 | 136 | ||
170 | /* Parse extra opts if any */ | 137 | const check_pgsql_config config = tmp_config.config; |
171 | argv=np_extra_opts (&argc, argv, progname); | ||
172 | 138 | ||
173 | if (process_arguments (argc, argv) == ERROR) | 139 | if (verbose > 2) { |
174 | usage4 (_("Could not parse arguments")); | ||
175 | if (verbose > 2) | ||
176 | printf("Arguments initialized\n"); | 140 | printf("Arguments initialized\n"); |
141 | } | ||
177 | 142 | ||
178 | /* Set signal handling and alarm */ | 143 | /* Set signal handling and alarm */ |
179 | if (signal (SIGALRM, timeout_alarm_handler) == SIG_ERR) { | 144 | if (signal(SIGALRM, timeout_alarm_handler) == SIG_ERR) { |
180 | usage4 (_("Cannot catch SIGALRM")); | 145 | usage4(_("Cannot catch SIGALRM")); |
146 | } | ||
147 | alarm(timeout_interval); | ||
148 | |||
149 | char *conninfo = NULL; | ||
150 | if (config.pgparams) { | ||
151 | asprintf(&conninfo, "%s ", config.pgparams); | ||
152 | } | ||
153 | |||
154 | asprintf(&conninfo, "%sdbname = '%s'", conninfo ? conninfo : "", config.dbName); | ||
155 | if (config.pghost) { | ||
156 | asprintf(&conninfo, "%s host = '%s'", conninfo, config.pghost); | ||
157 | } | ||
158 | if (config.pgport) { | ||
159 | asprintf(&conninfo, "%s port = '%s'", conninfo, config.pgport); | ||
160 | } | ||
161 | if (config.pgoptions) { | ||
162 | asprintf(&conninfo, "%s options = '%s'", conninfo, config.pgoptions); | ||
181 | } | 163 | } |
182 | alarm (timeout_interval); | ||
183 | |||
184 | if (pgparams) | ||
185 | asprintf (&conninfo, "%s ", pgparams); | ||
186 | |||
187 | asprintf (&conninfo, "%sdbname = '%s'", conninfo ? conninfo : "", dbName); | ||
188 | if (pghost) | ||
189 | asprintf (&conninfo, "%s host = '%s'", conninfo, pghost); | ||
190 | if (pgport) | ||
191 | asprintf (&conninfo, "%s port = '%s'", conninfo, pgport); | ||
192 | if (pgoptions) | ||
193 | asprintf (&conninfo, "%s options = '%s'", conninfo, pgoptions); | ||
194 | /* if (pgtty) -- ignored by PQconnectdb */ | 164 | /* if (pgtty) -- ignored by PQconnectdb */ |
195 | if (pguser) | 165 | if (config.pguser) { |
196 | asprintf (&conninfo, "%s user = '%s'", conninfo, pguser); | 166 | asprintf(&conninfo, "%s user = '%s'", conninfo, config.pguser); |
167 | } | ||
197 | 168 | ||
198 | if (verbose) /* do not include password (see right below) in output */ | 169 | if (verbose) { /* do not include password (see right below) in output */ |
199 | printf ("Connecting to PostgreSQL using conninfo: %s%s\n", conninfo, | 170 | printf("Connecting to PostgreSQL using conninfo: %s%s\n", conninfo, config.pgpasswd ? " password = <hidden>" : ""); |
200 | pgpasswd ? " password = <hidden>" : ""); | 171 | } |
201 | 172 | ||
202 | if (pgpasswd) | 173 | if (config.pgpasswd) { |
203 | asprintf (&conninfo, "%s password = '%s'", conninfo, pgpasswd); | 174 | asprintf(&conninfo, "%s password = '%s'", conninfo, config.pgpasswd); |
175 | } | ||
204 | 176 | ||
205 | /* make a connection to the database */ | 177 | /* make a connection to the database */ |
206 | gettimeofday (&start_timeval, NULL); | 178 | struct timeval start_timeval; |
207 | conn = PQconnectdb (conninfo); | 179 | gettimeofday(&start_timeval, NULL); |
208 | gettimeofday (&end_timeval, NULL); | 180 | PGconn *conn = PQconnectdb(conninfo); |
181 | struct timeval end_timeval; | ||
182 | gettimeofday(&end_timeval, NULL); | ||
209 | 183 | ||
210 | while (start_timeval.tv_usec > end_timeval.tv_usec) { | 184 | while (start_timeval.tv_usec > end_timeval.tv_usec) { |
211 | --end_timeval.tv_sec; | 185 | --end_timeval.tv_sec; |
212 | end_timeval.tv_usec += 1000000; | 186 | end_timeval.tv_usec += 1000000; |
213 | } | 187 | } |
214 | elapsed_time = (double)(end_timeval.tv_sec - start_timeval.tv_sec) | 188 | double elapsed_time = |
215 | + (double)(end_timeval.tv_usec - start_timeval.tv_usec) / 1000000.0; | 189 | (double)(end_timeval.tv_sec - start_timeval.tv_sec) + ((double)(end_timeval.tv_usec - start_timeval.tv_usec) / 1000000.0); |
216 | 190 | ||
217 | if (verbose) | 191 | if (verbose) { |
218 | printf("Time elapsed: %f\n", elapsed_time); | 192 | printf("Time elapsed: %f\n", elapsed_time); |
193 | } | ||
219 | 194 | ||
220 | /* check to see that the backend connection was successfully made */ | 195 | /* check to see that the backend connection was successfully made */ |
221 | if (verbose) | 196 | if (verbose) { |
222 | printf("Verifying connection\n"); | 197 | printf("Verifying connection\n"); |
223 | if (PQstatus (conn) == CONNECTION_BAD) { | 198 | } |
224 | printf (_("CRITICAL - no connection to '%s' (%s).\n"), | 199 | if (PQstatus(conn) == CONNECTION_BAD) { |
225 | dbName, PQerrorMessage (conn)); | 200 | printf(_("CRITICAL - no connection to '%s' (%s).\n"), config.dbName, PQerrorMessage(conn)); |
226 | PQfinish (conn); | 201 | PQfinish(conn); |
227 | return STATE_CRITICAL; | 202 | return STATE_CRITICAL; |
228 | } | 203 | } |
229 | else if (elapsed_time > tcrit) { | 204 | |
205 | mp_state_enum status = STATE_UNKNOWN; | ||
206 | if (elapsed_time > config.tcrit) { | ||
230 | status = STATE_CRITICAL; | 207 | status = STATE_CRITICAL; |
231 | } | 208 | } else if (elapsed_time > config.twarn) { |
232 | else if (elapsed_time > twarn) { | ||
233 | status = STATE_WARNING; | 209 | status = STATE_WARNING; |
234 | } | 210 | } else { |
235 | else { | ||
236 | status = STATE_OK; | 211 | status = STATE_OK; |
237 | } | 212 | } |
238 | 213 | ||
239 | if (verbose) { | 214 | if (verbose) { |
240 | char *server_host = PQhost (conn); | 215 | char *server_host = PQhost(conn); |
241 | int server_version = PQserverVersion (conn); | 216 | int server_version = PQserverVersion(conn); |
242 | 217 | ||
243 | printf ("Successfully connected to database %s (user %s) " | 218 | printf("Successfully connected to database %s (user %s) " |
244 | "at server %s%s%s (server version: %d.%d.%d, " | 219 | "at server %s%s%s (server version: %d.%d.%d, " |
245 | "protocol version: %d, pid: %d)\n", | 220 | "protocol version: %d, pid: %d)\n", |
246 | PQdb (conn), PQuser (conn), | 221 | PQdb(conn), PQuser(conn), PSQL_SOCKET3(server_host, PQport(conn)), PSQL_SERVER_VERSION3(server_version), |
247 | PSQL_SOCKET3 (server_host, PQport (conn)), | 222 | PQprotocolVersion(conn), PQbackendPID(conn)); |
248 | PSQL_SERVER_VERSION3 (server_version), | ||
249 | PQprotocolVersion (conn), PQbackendPID (conn)); | ||
250 | } | 223 | } |
251 | 224 | ||
252 | printf (_(" %s - database %s (%f sec.)|%s\n"), | 225 | printf(_(" %s - database %s (%f sec.)|%s\n"), state_text(status), config.dbName, elapsed_time, |
253 | state_text(status), dbName, elapsed_time, | 226 | fperfdata("time", elapsed_time, "s", (config.twarn > 0.0), config.twarn, (config.tcrit > 0.0), config.tcrit, true, 0, false, 0)); |
254 | fperfdata("time", elapsed_time, "s", | ||
255 | !!(twarn > 0.0), twarn, !!(tcrit > 0.0), tcrit, true, 0, false,0)); | ||
256 | 227 | ||
257 | if (pgquery) | 228 | mp_state_enum query_status = STATE_UNKNOWN; |
258 | query_status = do_query (conn, pgquery); | 229 | if (config.pgquery) { |
230 | query_status = do_query(conn, config.pgquery, config.pgqueryname, config.qthresholds, config.query_warning, config.query_critical); | ||
231 | } | ||
259 | 232 | ||
260 | if (verbose) | 233 | if (verbose) { |
261 | printf("Closing connection\n"); | 234 | printf("Closing connection\n"); |
262 | PQfinish (conn); | 235 | } |
263 | return (pgquery && query_status > status) ? query_status : status; | 236 | PQfinish(conn); |
237 | return (config.pgquery && query_status > status) ? query_status : status; | ||
264 | } | 238 | } |
265 | 239 | ||
266 | |||
267 | |||
268 | /* process command-line arguments */ | 240 | /* process command-line arguments */ |
269 | int | 241 | check_pgsql_config_wrapper process_arguments(int argc, char **argv) { |
270 | process_arguments (int argc, char **argv) | 242 | static struct option longopts[] = {{"help", no_argument, 0, 'h'}, |
271 | { | 243 | {"version", no_argument, 0, 'V'}, |
272 | int c; | 244 | {"timeout", required_argument, 0, 't'}, |
273 | 245 | {"critical", required_argument, 0, 'c'}, | |
274 | int option = 0; | 246 | {"warning", required_argument, 0, 'w'}, |
275 | static struct option longopts[] = { | 247 | {"hostname", required_argument, 0, 'H'}, |
276 | {"help", no_argument, 0, 'h'}, | 248 | {"logname", required_argument, 0, 'l'}, |
277 | {"version", no_argument, 0, 'V'}, | 249 | {"password", required_argument, 0, 'p'}, |
278 | {"timeout", required_argument, 0, 't'}, | 250 | {"authorization", required_argument, 0, 'a'}, |
279 | {"critical", required_argument, 0, 'c'}, | 251 | {"port", required_argument, 0, 'P'}, |
280 | {"warning", required_argument, 0, 'w'}, | 252 | {"database", required_argument, 0, 'd'}, |
281 | {"hostname", required_argument, 0, 'H'}, | 253 | {"option", required_argument, 0, 'o'}, |
282 | {"logname", required_argument, 0, 'l'}, | 254 | {"query", required_argument, 0, 'q'}, |
283 | {"password", required_argument, 0, 'p'}, | 255 | {"queryname", required_argument, 0, OPTID_QUERYNAME}, |
284 | {"authorization", required_argument, 0, 'a'}, | 256 | {"query_critical", required_argument, 0, 'C'}, |
285 | {"port", required_argument, 0, 'P'}, | 257 | {"query_warning", required_argument, 0, 'W'}, |
286 | {"database", required_argument, 0, 'd'}, | 258 | {"verbose", no_argument, 0, 'v'}, |
287 | {"option", required_argument, 0, 'o'}, | 259 | {0, 0, 0, 0}}; |
288 | {"query", required_argument, 0, 'q'}, | 260 | |
289 | {"queryname", required_argument, 0, OPTID_QUERYNAME}, | 261 | check_pgsql_config_wrapper result = { |
290 | {"query_critical", required_argument, 0, 'C'}, | 262 | .errorcode = OK, |
291 | {"query_warning", required_argument, 0, 'W'}, | 263 | .config = check_pgsql_config_init(), |
292 | {"verbose", no_argument, 0, 'v'}, | ||
293 | {0, 0, 0, 0} | ||
294 | }; | 264 | }; |
295 | 265 | ||
296 | while (1) { | 266 | while (true) { |
297 | c = getopt_long (argc, argv, "hVt:c:w:H:P:d:l:p:a:o:q:C:W:v", | 267 | int option = 0; |
298 | longopts, &option); | 268 | int option_char = getopt_long(argc, argv, "hVt:c:w:H:P:d:l:p:a:o:q:C:W:v", longopts, &option); |
299 | 269 | ||
300 | if (c == EOF) | 270 | if (option_char == EOF) { |
301 | break; | 271 | break; |
272 | } | ||
302 | 273 | ||
303 | switch (c) { | 274 | switch (option_char) { |
304 | case '?': /* usage */ | 275 | case '?': /* usage */ |
305 | usage5 (); | 276 | usage5(); |
306 | case 'h': /* help */ | 277 | case 'h': /* help */ |
307 | print_help (); | 278 | print_help(); |
308 | exit (STATE_UNKNOWN); | 279 | exit(STATE_UNKNOWN); |
309 | case 'V': /* version */ | 280 | case 'V': /* version */ |
310 | print_revision (progname, NP_VERSION); | 281 | print_revision(progname, NP_VERSION); |
311 | exit (STATE_UNKNOWN); | 282 | exit(STATE_UNKNOWN); |
312 | case 't': /* timeout period */ | 283 | case 't': /* timeout period */ |
313 | if (!is_integer (optarg)) | 284 | if (!is_integer(optarg)) { |
314 | usage2 (_("Timeout interval must be a positive integer"), optarg); | 285 | usage2(_("Timeout interval must be a positive integer"), optarg); |
315 | else | 286 | } else { |
316 | timeout_interval = atoi (optarg); | 287 | timeout_interval = atoi(optarg); |
288 | } | ||
317 | break; | 289 | break; |
318 | case 'c': /* critical time threshold */ | 290 | case 'c': /* critical time threshold */ |
319 | if (!is_nonnegative (optarg)) | 291 | if (!is_nonnegative(optarg)) { |
320 | usage2 (_("Critical threshold must be a positive integer"), optarg); | 292 | usage2(_("Critical threshold must be a positive integer"), optarg); |
321 | else | 293 | } else { |
322 | tcrit = strtod (optarg, NULL); | 294 | result.config.tcrit = strtod(optarg, NULL); |
295 | } | ||
323 | break; | 296 | break; |
324 | case 'w': /* warning time threshold */ | 297 | case 'w': /* warning time threshold */ |
325 | if (!is_nonnegative (optarg)) | 298 | if (!is_nonnegative(optarg)) { |
326 | usage2 (_("Warning threshold must be a positive integer"), optarg); | 299 | usage2(_("Warning threshold must be a positive integer"), optarg); |
327 | else | 300 | } else { |
328 | twarn = strtod (optarg, NULL); | 301 | result.config.twarn = strtod(optarg, NULL); |
302 | } | ||
329 | break; | 303 | break; |
330 | case 'C': /* critical query threshold */ | 304 | case 'C': /* critical query threshold */ |
331 | query_critical = optarg; | 305 | result.config.query_critical = optarg; |
332 | break; | 306 | break; |
333 | case 'W': /* warning query threshold */ | 307 | case 'W': /* warning query threshold */ |
334 | query_warning = optarg; | 308 | result.config.query_warning = optarg; |
335 | break; | 309 | break; |
336 | case 'H': /* host */ | 310 | case 'H': /* host */ |
337 | if ((*optarg != '/') && (!is_host (optarg))) | 311 | if ((*optarg != '/') && (!is_host(optarg))) { |
338 | usage2 (_("Invalid hostname/address"), optarg); | 312 | usage2(_("Invalid hostname/address"), optarg); |
339 | else | 313 | } else { |
340 | pghost = optarg; | 314 | result.config.pghost = optarg; |
315 | } | ||
341 | break; | 316 | break; |
342 | case 'P': /* port */ | 317 | case 'P': /* port */ |
343 | if (!is_integer (optarg)) | 318 | if (!is_integer(optarg)) { |
344 | usage2 (_("Port must be a positive integer"), optarg); | 319 | usage2(_("Port must be a positive integer"), optarg); |
345 | else | 320 | } else { |
346 | pgport = optarg; | 321 | result.config.pgport = optarg; |
322 | } | ||
347 | break; | 323 | break; |
348 | case 'd': /* database name */ | 324 | case 'd': /* database name */ |
349 | if (strlen(optarg) >= NAMEDATALEN) { | 325 | if (strlen(optarg) >= NAMEDATALEN) { |
350 | usage2 (_("Database name exceeds the maximum length"), optarg); | 326 | usage2(_("Database name exceeds the maximum length"), optarg); |
351 | } | 327 | } |
352 | snprintf(dbName, NAMEDATALEN, "%s", optarg); | 328 | snprintf(result.config.dbName, NAMEDATALEN, "%s", optarg); |
353 | break; | 329 | break; |
354 | case 'l': /* login name */ | 330 | case 'l': /* login name */ |
355 | if (!is_pg_logname (optarg)) | 331 | if (!is_pg_logname(optarg)) { |
356 | usage2 (_("User name is not valid"), optarg); | 332 | usage2(_("User name is not valid"), optarg); |
357 | else | 333 | } else { |
358 | pguser = optarg; | 334 | result.config.pguser = optarg; |
335 | } | ||
359 | break; | 336 | break; |
360 | case 'p': /* authentication password */ | 337 | case 'p': /* authentication password */ |
361 | case 'a': | 338 | case 'a': |
362 | pgpasswd = optarg; | 339 | result.config.pgpasswd = optarg; |
363 | break; | 340 | break; |
364 | case 'o': | 341 | case 'o': |
365 | if (pgparams) | 342 | if (result.config.pgparams) { |
366 | asprintf (&pgparams, "%s %s", pgparams, optarg); | 343 | asprintf(&result.config.pgparams, "%s %s", result.config.pgparams, optarg); |
367 | else | 344 | } else { |
368 | asprintf (&pgparams, "%s", optarg); | 345 | asprintf(&result.config.pgparams, "%s", optarg); |
346 | } | ||
369 | break; | 347 | break; |
370 | case 'q': | 348 | case 'q': |
371 | pgquery = optarg; | 349 | result.config.pgquery = optarg; |
372 | break; | 350 | break; |
373 | case OPTID_QUERYNAME: | 351 | case OPTID_QUERYNAME: |
374 | pgqueryname = optarg; | 352 | result.config.pgqueryname = optarg; |
375 | break; | 353 | break; |
376 | case 'v': | 354 | case 'v': |
377 | verbose++; | 355 | verbose++; |
@@ -379,38 +357,9 @@ process_arguments (int argc, char **argv) | |||
379 | } | 357 | } |
380 | } | 358 | } |
381 | 359 | ||
382 | set_thresholds (&qthresholds, query_warning, query_critical); | 360 | set_thresholds(&result.config.qthresholds, result.config.query_warning, result.config.query_critical); |
383 | |||
384 | return validate_arguments (); | ||
385 | } | ||
386 | |||
387 | |||
388 | /****************************************************************************** | ||
389 | |||
390 | @@- | ||
391 | <sect3> | ||
392 | <title>validate_arguments</title> | ||
393 | |||
394 | <para>&PROTO_validate_arguments;</para> | ||
395 | |||
396 | <para>Given a database name, this function returns true if the string | ||
397 | is a valid PostgreSQL database name, and returns false if it is | ||
398 | not.</para> | ||
399 | |||
400 | <para>Valid PostgreSQL database names are less than &NAMEDATALEN; | ||
401 | characters long and consist of letters, numbers, and underscores. The | ||
402 | first character cannot be a number, however.</para> | ||
403 | |||
404 | </sect3> | ||
405 | -@@ | ||
406 | ******************************************************************************/ | ||
407 | |||
408 | |||
409 | 361 | ||
410 | int | 362 | return result; |
411 | validate_arguments () | ||
412 | { | ||
413 | return OK; | ||
414 | } | 363 | } |
415 | 364 | ||
416 | /** | 365 | /** |
@@ -437,11 +386,10 @@ should be added.</para> | |||
437 | -@@ | 386 | -@@ |
438 | ******************************************************************************/ | 387 | ******************************************************************************/ |
439 | 388 | ||
440 | 389 | bool is_pg_logname(char *username) { | |
441 | 390 | if (strlen(username) > NAMEDATALEN - 1) { | |
442 | bool is_pg_logname (char *username) { | ||
443 | if (strlen (username) > NAMEDATALEN - 1) | ||
444 | return (false); | 391 | return (false); |
392 | } | ||
445 | return (true); | 393 | return (true); |
446 | } | 394 | } |
447 | 395 | ||
@@ -453,182 +401,159 @@ bool is_pg_logname (char *username) { | |||
453 | -@@ | 401 | -@@ |
454 | ******************************************************************************/ | 402 | ******************************************************************************/ |
455 | 403 | ||
456 | 404 | void print_help(void) { | |
457 | |||
458 | void | ||
459 | print_help (void) | ||
460 | { | ||
461 | char *myport; | 405 | char *myport; |
462 | 406 | ||
463 | xasprintf (&myport, "%d", DEFAULT_PORT); | 407 | xasprintf(&myport, "%d", 5432); |
464 | 408 | ||
465 | print_revision (progname, NP_VERSION); | 409 | print_revision(progname, NP_VERSION); |
466 | 410 | ||
467 | printf (COPYRIGHT, copyright, email); | 411 | printf(COPYRIGHT, copyright, email); |
468 | 412 | ||
469 | printf (_("Test whether a PostgreSQL Database is accepting connections.")); | 413 | printf(_("Test whether a PostgreSQL Database is accepting connections.")); |
470 | 414 | ||
471 | printf ("\n\n"); | 415 | printf("\n\n"); |
472 | 416 | ||
473 | print_usage (); | 417 | print_usage(); |
474 | 418 | ||
475 | printf (UT_HELP_VRSN); | 419 | printf(UT_HELP_VRSN); |
476 | printf (UT_EXTRA_OPTS); | 420 | printf(UT_EXTRA_OPTS); |
477 | 421 | ||
478 | printf (UT_HOST_PORT, 'P', myport); | 422 | printf(UT_HOST_PORT, 'P', myport); |
479 | 423 | ||
480 | printf (" %s\n", "-d, --database=STRING"); | 424 | printf(" %s\n", "-d, --database=STRING"); |
481 | printf (" %s", _("Database to check ")); | 425 | printf(" %s", _("Database to check ")); |
482 | printf (_("(default: %s)\n"), DEFAULT_DB); | 426 | printf(_("(default: %s)\n"), DEFAULT_DB); |
483 | printf (" %s\n", "-l, --logname = STRING"); | 427 | printf(" %s\n", "-l, --logname = STRING"); |
484 | printf (" %s\n", _("Login name of user")); | 428 | printf(" %s\n", _("Login name of user")); |
485 | printf (" %s\n", "-p, --password = STRING"); | 429 | printf(" %s\n", "-p, --password = STRING"); |
486 | printf (" %s\n", _("Password (BIG SECURITY ISSUE)")); | 430 | printf(" %s\n", _("Password (BIG SECURITY ISSUE)")); |
487 | printf (" %s\n", "-o, --option = STRING"); | 431 | printf(" %s\n", "-o, --option = STRING"); |
488 | printf (" %s\n", _("Connection parameters (keyword = value), see below")); | 432 | printf(" %s\n", _("Connection parameters (keyword = value), see below")); |
489 | 433 | ||
490 | printf (UT_WARN_CRIT); | 434 | printf(UT_WARN_CRIT); |
491 | 435 | ||
492 | printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); | 436 | printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); |
493 | 437 | ||
494 | printf (" %s\n", "-q, --query=STRING"); | 438 | printf(" %s\n", "-q, --query=STRING"); |
495 | printf (" %s\n", _("SQL query to run. Only first column in first row will be read")); | 439 | printf(" %s\n", _("SQL query to run. Only first column in first row will be read")); |
496 | printf (" %s\n", "--queryname=STRING"); | 440 | printf(" %s\n", "--queryname=STRING"); |
497 | printf (" %s\n", _("A name for the query, this string is used instead of the query")); | 441 | printf(" %s\n", _("A name for the query, this string is used instead of the query")); |
498 | printf (" %s\n", _("in the long output of the plugin")); | 442 | printf(" %s\n", _("in the long output of the plugin")); |
499 | printf (" %s\n", "-W, --query-warning=RANGE"); | 443 | printf(" %s\n", "-W, --query-warning=RANGE"); |
500 | printf (" %s\n", _("SQL query value to result in warning status (double)")); | 444 | printf(" %s\n", _("SQL query value to result in warning status (double)")); |
501 | printf (" %s\n", "-C, --query-critical=RANGE"); | 445 | printf(" %s\n", "-C, --query-critical=RANGE"); |
502 | printf (" %s\n", _("SQL query value to result in critical status (double)")); | 446 | printf(" %s\n", _("SQL query value to result in critical status (double)")); |
503 | 447 | ||
504 | printf (UT_VERBOSE); | 448 | printf(UT_VERBOSE); |
505 | 449 | ||
506 | printf ("\n"); | 450 | printf("\n"); |
507 | printf (" %s\n", _("All parameters are optional.")); | 451 | printf(" %s\n", _("All parameters are optional.")); |
508 | printf (" %s\n", _("This plugin tests a PostgreSQL DBMS to determine whether it is active and")); | 452 | printf(" %s\n", _("This plugin tests a PostgreSQL DBMS to determine whether it is active and")); |
509 | printf (" %s\n", _("accepting queries. In its current operation, it simply connects to the")); | 453 | printf(" %s\n", _("accepting queries. In its current operation, it simply connects to the")); |
510 | printf (" %s\n", _("specified database, and then disconnects. If no database is specified, it")); | 454 | printf(" %s\n", _("specified database, and then disconnects. If no database is specified, it")); |
511 | printf (" %s\n", _("connects to the template1 database, which is present in every functioning")); | 455 | printf(" %s\n", _("connects to the template1 database, which is present in every functioning")); |
512 | printf (" %s\n\n", _("PostgreSQL DBMS.")); | 456 | printf(" %s\n\n", _("PostgreSQL DBMS.")); |
513 | 457 | ||
514 | printf (" %s\n", _("If a query is specified using the -q option, it will be executed after")); | 458 | printf(" %s\n", _("If a query is specified using the -q option, it will be executed after")); |
515 | printf (" %s\n", _("connecting to the server. The result from the query has to be numeric.")); | 459 | printf(" %s\n", _("connecting to the server. The result from the query has to be numeric.")); |
516 | printf (" %s\n", _("Multiple SQL commands, separated by semicolon, are allowed but the result ")); | 460 | printf(" %s\n", _("Multiple SQL commands, separated by semicolon, are allowed but the result ")); |
517 | printf (" %s\n", _("of the last command is taken into account only. The value of the first")); | 461 | printf(" %s\n", _("of the last command is taken into account only. The value of the first")); |
518 | printf (" %s\n", _("column in the first row is used as the check result. If a second column is")); | 462 | printf(" %s\n", _("column in the first row is used as the check result. If a second column is")); |
519 | printf (" %s\n", _("present in the result set, this is added to the plugin output with a")); | 463 | printf(" %s\n", _("present in the result set, this is added to the plugin output with a")); |
520 | printf (" %s\n", _("prefix of \"Extra Info:\". This information can be displayed in the system")); | 464 | printf(" %s\n", _("prefix of \"Extra Info:\". This information can be displayed in the system")); |
521 | printf (" %s\n\n", _("executing the plugin.")); | 465 | printf(" %s\n\n", _("executing the plugin.")); |
522 | 466 | ||
523 | printf (" %s\n", _("See the chapter \"Monitoring Database Activity\" of the PostgreSQL manual")); | 467 | printf(" %s\n", _("See the chapter \"Monitoring Database Activity\" of the PostgreSQL manual")); |
524 | printf (" %s\n\n", _("for details about how to access internal statistics of the database server.")); | 468 | printf(" %s\n\n", _("for details about how to access internal statistics of the database server.")); |
525 | 469 | ||
526 | printf (" %s\n", _("For a list of available connection parameters which may be used with the -o")); | 470 | printf(" %s\n", _("For a list of available connection parameters which may be used with the -o")); |
527 | printf (" %s\n", _("command line option, see the documentation for PQconnectdb() in the chapter")); | 471 | printf(" %s\n", _("command line option, see the documentation for PQconnectdb() in the chapter")); |
528 | printf (" %s\n", _("\"libpq - C Library\" of the PostgreSQL manual. For example, this may be")); | 472 | printf(" %s\n", _("\"libpq - C Library\" of the PostgreSQL manual. For example, this may be")); |
529 | printf (" %s\n", _("used to specify a service name in pg_service.conf to be used for additional")); | 473 | printf(" %s\n", _("used to specify a service name in pg_service.conf to be used for additional")); |
530 | printf (" %s\n", _("connection parameters: -o 'service=<name>' or to specify the SSL mode:")); | 474 | printf(" %s\n", _("connection parameters: -o 'service=<name>' or to specify the SSL mode:")); |
531 | printf (" %s\n\n", _("-o 'sslmode=require'.")); | 475 | printf(" %s\n\n", _("-o 'sslmode=require'.")); |
532 | 476 | ||
533 | printf (" %s\n", _("The plugin will connect to a local postmaster if no host is specified. To")); | 477 | printf(" %s\n", _("The plugin will connect to a local postmaster if no host is specified. To")); |
534 | printf (" %s\n", _("connect to a remote host, be sure that the remote postmaster accepts TCP/IP")); | 478 | printf(" %s\n", _("connect to a remote host, be sure that the remote postmaster accepts TCP/IP")); |
535 | printf (" %s\n\n", _("connections (start the postmaster with the -i option).")); | 479 | printf(" %s\n\n", _("connections (start the postmaster with the -i option).")); |
536 | 480 | ||
537 | printf (" %s\n", _("Typically, the monitoring user (unless the --logname option is used) should be")); | 481 | printf(" %s\n", _("Typically, the monitoring user (unless the --logname option is used) should be")); |
538 | printf (" %s\n", _("able to connect to the database without a password. The plugin can also send")); | 482 | printf(" %s\n", _("able to connect to the database without a password. The plugin can also send")); |
539 | printf (" %s\n", _("a password, but no effort is made to obscure or encrypt the password.")); | 483 | printf(" %s\n", _("a password, but no effort is made to obscure or encrypt the password.")); |
540 | 484 | ||
541 | printf (UT_SUPPORT); | 485 | printf(UT_SUPPORT); |
542 | } | 486 | } |
543 | 487 | ||
544 | 488 | void print_usage(void) { | |
545 | 489 | printf("%s\n", _("Usage:")); | |
546 | void | 490 | printf("%s [-H <host>] [-P <port>] [-c <critical time>] [-w <warning time>]\n", progname); |
547 | print_usage (void) | 491 | printf(" [-t <timeout>] [-d <database>] [-l <logname>] [-p <password>]\n" |
548 | { | 492 | "[-q <query>] [-C <critical query range>] [-W <warning query range>]\n"); |
549 | printf ("%s\n", _("Usage:")); | ||
550 | printf ("%s [-H <host>] [-P <port>] [-c <critical time>] [-w <warning time>]\n", progname); | ||
551 | printf (" [-t <timeout>] [-d <database>] [-l <logname>] [-p <password>]\n" | ||
552 | "[-q <query>] [-C <critical query range>] [-W <warning query range>]\n"); | ||
553 | } | 493 | } |
554 | 494 | ||
555 | int | 495 | mp_state_enum do_query(PGconn *conn, char *query, const char pgqueryname[], thresholds *qthresholds, char *query_warning, |
556 | do_query (PGconn *conn, char *query) | 496 | char *query_critical) { |
557 | { | 497 | if (verbose) { |
558 | PGresult *res; | 498 | printf("Executing SQL query \"%s\".\n", query); |
559 | 499 | } | |
560 | char *val_str; | 500 | PGresult *res = PQexec(conn, query); |
561 | char *extra_info; | ||
562 | double value; | ||
563 | |||
564 | char *endptr = NULL; | ||
565 | |||
566 | int my_status = STATE_UNKNOWN; | ||
567 | |||
568 | if (verbose) | ||
569 | printf ("Executing SQL query \"%s\".\n", query); | ||
570 | res = PQexec (conn, query); | ||
571 | 501 | ||
572 | if (PGRES_TUPLES_OK != PQresultStatus (res)) { | 502 | if (PGRES_TUPLES_OK != PQresultStatus(res)) { |
573 | printf (_("QUERY %s - %s: %s.\n"), _("CRITICAL"), _("Error with query"), | 503 | printf(_("QUERY %s - %s: %s.\n"), _("CRITICAL"), _("Error with query"), PQerrorMessage(conn)); |
574 | PQerrorMessage (conn)); | ||
575 | return STATE_CRITICAL; | 504 | return STATE_CRITICAL; |
576 | } | 505 | } |
577 | 506 | ||
578 | if (PQntuples (res) < 1) { | 507 | if (PQntuples(res) < 1) { |
579 | printf ("QUERY %s - %s.\n", _("WARNING"), _("No rows returned")); | 508 | printf("QUERY %s - %s.\n", _("WARNING"), _("No rows returned")); |
580 | return STATE_WARNING; | 509 | return STATE_WARNING; |
581 | } | 510 | } |
582 | 511 | ||
583 | if (PQnfields (res) < 1) { | 512 | if (PQnfields(res) < 1) { |
584 | printf ("QUERY %s - %s.\n", _("WARNING"), _("No columns returned")); | 513 | printf("QUERY %s - %s.\n", _("WARNING"), _("No columns returned")); |
585 | return STATE_WARNING; | 514 | return STATE_WARNING; |
586 | } | 515 | } |
587 | 516 | ||
588 | val_str = PQgetvalue (res, 0, 0); | 517 | char *val_str = PQgetvalue(res, 0, 0); |
589 | if (! val_str) { | 518 | if (!val_str) { |
590 | printf ("QUERY %s - %s.\n", _("CRITICAL"), _("No data returned")); | 519 | printf("QUERY %s - %s.\n", _("CRITICAL"), _("No data returned")); |
591 | return STATE_CRITICAL; | 520 | return STATE_CRITICAL; |
592 | } | 521 | } |
593 | 522 | ||
594 | value = strtod (val_str, &endptr); | 523 | char *endptr = NULL; |
595 | if (verbose) | 524 | double value = strtod(val_str, &endptr); |
596 | printf ("Query result: %f\n", value); | 525 | if (verbose) { |
526 | printf("Query result: %f\n", value); | ||
527 | } | ||
597 | 528 | ||
598 | if (endptr == val_str) { | 529 | if (endptr == val_str) { |
599 | printf ("QUERY %s - %s: %s\n", _("CRITICAL"), _("Is not a numeric"), val_str); | 530 | printf("QUERY %s - %s: %s\n", _("CRITICAL"), _("Is not a numeric"), val_str); |
600 | return STATE_CRITICAL; | 531 | return STATE_CRITICAL; |
601 | } | 532 | } |
602 | else if ((endptr != NULL) && (*endptr != '\0')) { | ||
603 | if (verbose) | ||
604 | printf ("Garbage after value: %s.\n", endptr); | ||
605 | } | ||
606 | 533 | ||
607 | my_status = get_status (value, qthresholds); | 534 | if ((endptr != NULL) && (*endptr != '\0')) { |
608 | printf ("QUERY %s - ", | 535 | if (verbose) { |
609 | (my_status == STATE_OK) | 536 | printf("Garbage after value: %s.\n", endptr); |
610 | ? _("OK") | 537 | } |
611 | : (my_status == STATE_WARNING) | ||
612 | ? _("WARNING") | ||
613 | : (my_status == STATE_CRITICAL) | ||
614 | ? _("CRITICAL") | ||
615 | : _("UNKNOWN")); | ||
616 | if(pgqueryname) { | ||
617 | printf (_("%s returned %f"), pgqueryname, value); | ||
618 | } | 538 | } |
619 | else { | 539 | |
620 | printf (_("'%s' returned %f"), query, value); | 540 | mp_state_enum my_status = get_status(value, qthresholds); |
541 | printf("QUERY %s - ", (my_status == STATE_OK) ? _("OK") | ||
542 | : (my_status == STATE_WARNING) ? _("WARNING") | ||
543 | : (my_status == STATE_CRITICAL) ? _("CRITICAL") | ||
544 | : _("UNKNOWN")); | ||
545 | if (pgqueryname) { | ||
546 | printf(_("%s returned %f"), pgqueryname, value); | ||
547 | } else { | ||
548 | printf(_("'%s' returned %f"), query, value); | ||
621 | } | 549 | } |
622 | 550 | ||
623 | printf ("|query=%f;%s;%s;;\n", value, | 551 | printf("|query=%f;%s;%s;;\n", value, query_warning ? query_warning : "", query_critical ? query_critical : ""); |
624 | query_warning ? query_warning : "", | 552 | if (PQnfields(res) > 1) { |
625 | query_critical ? query_critical : ""); | 553 | char *extra_info = PQgetvalue(res, 0, 1); |
626 | if (PQnfields (res) > 1) { | ||
627 | extra_info = PQgetvalue (res, 0, 1); | ||
628 | if (extra_info != NULL) { | 554 | if (extra_info != NULL) { |
629 | printf ("Extra Info: %s\n", extra_info); | 555 | printf("Extra Info: %s\n", extra_info); |
630 | } | 556 | } |
631 | } | 557 | } |
632 | return my_status; | 558 | return my_status; |
633 | } | 559 | } |
634 | |||