Code

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