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.c440
1 files changed, 440 insertions, 0 deletions
diff --git a/plugins/check_pgsql.c b/plugins/check_pgsql.c
new file mode 100644
index 0000000..03614ab
--- /dev/null
+++ b/plugins/check_pgsql.c
@@ -0,0 +1,440 @@
1/******************************************************************************
2 *
3 * Program: PostgreSQL plugin for Nagios
4 * License: GPL
5 *
6 * License Information:
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 *
22 * $Id$
23 *
24 *****************************************************************************/
25
26#define PROGNAME "check_pgsql"
27#define REVISION "$Revision$"
28#define COPYRIGHT "1999-2001"
29#define AUTHOR "Karl DeBisschop"
30#define EMAIL "kdebisschop@users.sourceforge.net"
31#define SUMMARY "Tests to see if a PostgreSQL DBMS is accepting connections.\n"
32
33#define OPTIONS "\
34\[-c critical_time] [-w warning_time] [-t timeout] [-H host]\n\
35 [-P port] [-d database] [-l logname] [-p password]"
36
37#define LONGOPTIONS "\
38 -c, --critical=INTEGER\n\
39 Exit STATE_CRITICAL if connection time exceeds threshold (default: %d)\n\
40 -w, --warning=INTEGER\n\
41 Exit STATE_WARNING if connection time exceeds threshold (default: %d)\n\
42 -t, --timeout=INTEGER\n\
43 Terminate test if timeout limit is exceeded (default: %d)\n\
44 -H, --hostname=STRING\n\
45 Name or numeric IP address of machine running backend\n\
46 -P, --port=INTEGER\n\
47 Port running backend (default: %s)\n\
48 -d, --database=STRING\n\
49 Database to check (default: %s)\n\
50 -l, --logname = STRING\n\
51 Login name of user\n\
52 -p, --password = STRING\n\
53 Password (BIG SECURITY ISSUE)\n"
54
55#define DESCRIPTION "All parameters are optional.\n\
56\n\
57This plugin tests a PostgreSQL DBMS to determine whether it is active and\n\
58accepting queries. In its current operation, it simply connects to the\n\
59specified database, and then disconnects. If no database is specified, it\n\
60connects to the template1 database, which is present in every functioning \n\
61PostgreSQL DBMS.\n\
62\n\
63The plugin will connect to a local postmaster if no host is specified. To\n\
64connect to a remote host, be sure that the remote postmaster accepts TCP/IP\n\
65connections (start the postmaster with the -i option).\n\
66\n\
67Typically, the nagios user (unless the --logname option is used) should be\n\
68able to connect to the database without a password. The plugin can also send\n\
69a password, but no effort is made to obsure or encrypt the password.\n"
70
71#define DEFAULT_DB "template1"
72#define DEFAULT_HOST "127.0.0.1"
73#define DEFAULT_PORT "5432"
74#define DEFAULT_WARN 2
75#define DEFAULT_CRIT 8
76#define DEFAULT_TIMEOUT 30
77
78#include "config.h"
79#include "common.h"
80#include "utils.h"
81#include <netdb.h>
82#include <libpq-fe.h>
83
84int process_arguments (int, char **);
85int validate_arguments (void);
86void print_usage (void);
87void print_help (void);
88int is_pg_dbname (char *);
89int is_pg_logname (char *);
90
91char *pghost = NULL; /* host name of the backend server */
92char *pgport = NULL; /* port of the backend server */
93char default_port[4] = DEFAULT_PORT;
94char *pgoptions = NULL;
95char *pgtty = NULL;
96char dbName[NAMEDATALEN] = DEFAULT_DB;
97char *pguser = NULL;
98char *pgpasswd = NULL;
99int twarn = DEFAULT_WARN;
100int tcrit = DEFAULT_CRIT;
101
102PGconn *conn;
103/*PGresult *res;*/
104
105
106/******************************************************************************
107
108The (psuedo?)literate programming XML is contained within \@\@\- <XML> \-\@\@
109tags in the comments. With in the tags, the XML is assembled sequentially.
110You can define entities in tags. You also have all the #defines available as
111entities.
112
113Please note that all tags must be lowercase to use the DocBook XML DTD.
114
115@@-<article>
116
117<sect1>
118<title>Quick Reference</title>
119<!-- The refentry forms a manpage -->
120<refentry>
121<refmeta>
122<manvolnum>5<manvolnum>
123</refmeta>
124<refnamdiv>
125<refname>&PROGNAME;</refname>
126<refpurpose>&SUMMARY;</refpurpose>
127</refnamdiv>
128</refentry>
129</sect1>
130
131<sect1>
132<title>FAQ</title>
133</sect1>
134
135<sect1>
136<title>Theory, Installation, and Operation</title>
137
138<sect2>
139<title>General Description</title>
140<para>
141&DESCRIPTION;
142</para>
143</sect2>
144
145<sect2>
146<title>Future Enhancements</title>
147<para>ToDo List</para>
148<itemizedlist>
149<listitem>Add option to get password from a secured file rather than the command line</listitem>
150<listitem>Add option to specify the query to execute</listitem>
151</itemizedlist>
152</sect2>
153
154
155<sect2>
156<title>Functions</title>
157-@@
158******************************************************************************/
159
160int
161main (int argc, char **argv)
162{
163 int elapsed_time;
164
165 /* begin, by setting the parameters for a backend connection if the
166 * parameters are null, then the system will try to use reasonable
167 * defaults by looking up environment variables or, failing that,
168 * using hardwired constants */
169
170 pgoptions = NULL; /* special options to start up the backend server */
171 pgtty = NULL; /* debugging tty for the backend server */
172
173 if (process_arguments (argc, argv) == ERROR)
174 usage ("Could not parse arguments");
175
176 /* Set signal handling and alarm */
177 if (signal (SIGALRM, timeout_alarm_handler) == SIG_ERR) {
178 printf ("Cannot catch SIGALRM");
179 return STATE_UNKNOWN;
180 }
181 alarm (timeout_interval);
182
183 /* make a connection to the database */
184 time (&start_time);
185 conn =
186 PQsetdbLogin (pghost, pgport, pgoptions, pgtty, dbName, pguser, pgpasswd);
187 time (&end_time);
188 elapsed_time = (int) (end_time - start_time);
189
190 /* check to see that the backend connection was successfully made */
191 if (PQstatus (conn) == CONNECTION_BAD) {
192 printf ("PGSQL: CRITICAL - no connection to '%s' (%s).\n", dbName,
193 PQerrorMessage (conn));
194 PQfinish (conn);
195 return STATE_CRITICAL;
196 }
197 else if (elapsed_time > tcrit) {
198 PQfinish (conn);
199 printf ("PGSQL: CRITICAL - database %s (%d sec.)\n", dbName,
200 elapsed_time);
201 return STATE_CRITICAL;
202 }
203 else if (elapsed_time > twarn) {
204 PQfinish (conn);
205 printf ("PGSQL: WARNING - database %s (%d sec.)\n", dbName, elapsed_time);
206 return STATE_WARNING;
207 }
208 else {
209 PQfinish (conn);
210 printf ("PGSQL: ok - database %s (%d sec.)\n", dbName, elapsed_time);
211 return STATE_OK;
212 }
213}
214
215
216
217
218void
219print_help (void)
220{
221 print_revision (PROGNAME, REVISION);
222 printf
223 ("Copyright (c) %s %s <%s>\n\n%s\n",
224 COPYRIGHT, AUTHOR, EMAIL, SUMMARY);
225 print_usage ();
226 printf
227 ("\nOptions:\n" LONGOPTIONS "\n" DESCRIPTION "\n",
228 DEFAULT_WARN, DEFAULT_CRIT, DEFAULT_TIMEOUT, DEFAULT_PORT, DEFAULT_DB);
229 support ();
230}
231
232void
233print_usage (void)
234{
235 printf ("Usage:\n" " %s %s\n"
236#ifdef HAVE_GETOPT_H
237 " %s (-h | --help) for detailed help\n"
238 " %s (-V | --version) for version information\n",
239#else
240 " %s -h for detailed help\n"
241 " %s -V for version information\n",
242#endif
243 PROGNAME, OPTIONS, PROGNAME, PROGNAME);
244}
245
246
247
248/* process command-line arguments */
249int
250process_arguments (int argc, char **argv)
251{
252 int c;
253
254#ifdef HAVE_GETOPT_H
255 int option_index = 0;
256 static struct option long_options[] = {
257 {"help", no_argument, 0, 'h'},
258 {"version", no_argument, 0, 'V'},
259 {"timeout", required_argument, 0, 't'},
260 {"critical", required_argument, 0, 'c'},
261 {"warning", required_argument, 0, 'w'},
262 {"hostname", required_argument, 0, 'H'},
263 {"logname", required_argument, 0, 'l'},
264 {"password", required_argument, 0, 'p'},
265 {"authorization", required_argument, 0, 'a'},
266 {"port", required_argument, 0, 'P'},
267 {"database", required_argument, 0, 'd'},
268 {0, 0, 0, 0}
269 };
270#endif
271
272 while (1) {
273#ifdef HAVE_GETOPT_H
274 c = getopt_long (argc, argv, "+?hVt:c:w:H:P:d:l:p:a:",
275 long_options, &option_index);
276#else
277 c = getopt (argc, argv, "+?hVt:c:w:H:P:d:l:p:a:");
278#endif
279 if (c == EOF)
280 break;
281
282 switch (c) {
283 case '?': /* help */
284 usage2 ("Unknown argument", optarg);
285 case 'h': /* help */
286 print_help ();
287 exit (STATE_OK);
288 case 'V': /* version */
289 print_revision (PROGNAME, REVISION);
290 exit (STATE_OK);
291 case 't': /* timeout period */
292 if (!is_integer (optarg))
293 usage2 ("Timeout Interval must be an integer", optarg);
294 timeout_interval = atoi (optarg);
295 break;
296 case 'c': /* critical time threshold */
297 if (!is_integer (optarg))
298 usage2 ("Invalid critical threshold", optarg);
299 tcrit = atoi (optarg);
300 break;
301 case 'w': /* warning time threshold */
302 if (!is_integer (optarg))
303 usage2 ("Invalid critical threshold", optarg);
304 twarn = atoi (optarg);
305 break;
306 case 'H': /* host */
307 if (!is_host (optarg))
308 usage2 ("You gave an invalid host name", optarg);
309 pghost = optarg;
310 break;
311 case 'P': /* port */
312 if (!is_integer (optarg))
313 usage2 ("Port must be an integer", optarg);
314 pgport = optarg;
315 break;
316 case 'd': /* database name */
317 if (!is_pg_dbname (optarg))
318 usage2 ("Database name is not valid", optarg);
319 strncpy (dbName, optarg, NAMEDATALEN - 1);
320 dbName[NAMEDATALEN - 1] = 0;
321 break;
322 case 'l': /* login name */
323 if (!is_pg_logname (optarg))
324 usage2 ("user name is not valid", optarg);
325 pguser = optarg;
326 break;
327 case 'p': /* authentication password */
328 case 'a':
329 pgpasswd = optarg;
330 break;
331 }
332 }
333
334 return validate_arguments ();
335}
336
337
338/******************************************************************************
339
340@@-
341<sect3>
342<title>validate_arguments</title>
343
344<para>&PROTO_validate_arguments;</para>
345
346<para>Given a database name, this function returns TRUE if the string
347is a valid PostgreSQL database name, and returns false if it is
348not.</para>
349
350<para>Valid PostgreSQL database names are less than &NAMEDATALEN;
351characters long and consist of letters, numbers, and underscores. The
352first character cannot be a number, however.</para>
353
354</sect3>
355-@@
356******************************************************************************/
357
358int
359validate_arguments ()
360{
361 return OK;
362}
363
364
365
366/******************************************************************************
367
368@@-
369<sect3>
370<title>is_pg_dbname</title>
371
372<para>&PROTO_is_pg_dbname;</para>
373
374<para>Given a database name, this function returns TRUE if the string
375is a valid PostgreSQL database name, and returns false if it is
376not.</para>
377
378<para>Valid PostgreSQL database names are less than &NAMEDATALEN;
379characters long and consist of letters, numbers, and underscores. The
380first character cannot be a number, however.</para>
381
382</sect3>
383-@@
384******************************************************************************/
385
386int
387is_pg_dbname (char *dbname)
388{
389 char txt[NAMEDATALEN];
390 char tmp[NAMEDATALEN];
391 if (strlen (dbname) > NAMEDATALEN - 1)
392 return (FALSE);
393 strncpy (txt, dbname, NAMEDATALEN - 1);
394 txt[NAMEDATALEN - 1] = 0;
395 if (sscanf (txt, "%[_a-zA-Z]%[^_a-zA-Z0-9]", tmp, tmp) == 1)
396 return (TRUE);
397 if (sscanf (txt, "%[_a-zA-Z]%[_a-zA-Z0-9]%[^_a-zA-Z0-9]", tmp, tmp, tmp) ==
398 2) return (TRUE);
399 return (FALSE);
400}
401
402/**
403
404the tango program should eventually create an entity here based on the
405function prototype
406
407@@-
408<sect3>
409<title>is_pg_logname</title>
410
411<para>&PROTO_is_pg_logname;</para>
412
413<para>Given a username, this function returns TRUE if the string is a
414valid PostgreSQL username, and returns false if it is not. Valid PostgreSQL
415usernames are less than &NAMEDATALEN; characters long and consist of
416letters, numbers, dashes, and underscores, plus possibly some other
417characters.</para>
418
419<para>Currently this function only checks string length. Additional checks
420should be added.</para>
421
422</sect3>
423-@@
424******************************************************************************/
425
426int
427is_pg_logname (char *username)
428{
429 if (strlen (username) > NAMEDATALEN - 1)
430 return (FALSE);
431 return (TRUE);
432}
433
434/******************************************************************************
435@@-
436</sect2>
437</sect1>
438</article>
439-@@
440******************************************************************************/