Code

changed Error: by CRITICAL -
[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  $Id$
18  
19  *****************************************************************************/
21 #define DEFAULT_DB "template1"
22 #define DEFAULT_HOST "127.0.0.1"
24 enum {
25         DEFAULT_PORT = 5432,
26         DEFAULT_WARN = 2,
27         DEFAULT_CRIT = 8
28 };
30 #include "common.h"
31 #include "utils.h"
32 #include "netutils.h"
33 #include <libpq-fe.h>
35 int process_arguments (int, char **);
36 int validate_arguments (void);
37 void print_usage (void);
38 void print_help (void);
39 int is_pg_dbname (char *);
40 int is_pg_logname (char *);
42 char *pghost = NULL;                                            /* host name of the backend server */
43 char *pgport = NULL;                                            /* port of the backend server */
44 int default_port = DEFAULT_PORT;
45 char *pgoptions = NULL;
46 char *pgtty = NULL;
47 char dbName[NAMEDATALEN] = DEFAULT_DB;
48 char *pguser = NULL;
49 char *pgpasswd = NULL;
50 double twarn = (double)DEFAULT_WARN;
51 double tcrit = (double)DEFAULT_CRIT;
53 PGconn *conn;
54 /*PGresult   *res;*/
56 const char *progname = "check_pgsql";
57 const char *revision = "$Revision$";
58 const char *copyright = "1999-2003";
59 const char *email = "nagiosplug-devel@lists.sourceforge.net";
62 /******************************************************************************
64 The (psuedo?)literate programming XML is contained within \@\@\- <XML> \-\@\@
65 tags in the comments. With in the tags, the XML is assembled sequentially.
66 You can define entities in tags. You also have all the #defines available as
67 entities.
69 Please note that all tags must be lowercase to use the DocBook XML DTD.
71 @@-<article>
73 <sect1>
74 <title>Quick Reference</title>
75 <!-- The refentry forms a manpage -->
76 <refentry>
77 <refmeta>
78 <manvolnum>5<manvolnum>
79 </refmeta>
80 <refnamdiv>
81 <refname>&progname;</refname>
82 <refpurpose>&SUMMARY;</refpurpose>
83 </refnamdiv>
84 </refentry>
85 </sect1>
87 <sect1>
88 <title>FAQ</title>
89 </sect1>
91 <sect1>
92 <title>Theory, Installation, and Operation</title>
94 <sect2>
95 <title>General Description</title>
96 <para>
97 &DESCRIPTION;
98 </para>
99 </sect2>
101 <sect2>
102 <title>Future Enhancements</title>
103 <para>ToDo List</para>
104 <itemizedlist>
105 <listitem>Add option to get password from a secured file rather than the command line</listitem>
106 <listitem>Add option to specify the query to execute</listitem>
107 </itemizedlist>
108 </sect2>
111 <sect2>
112 <title>Functions</title>
113 -@@
114 ******************************************************************************/
118 int
119 main (int argc, char **argv)
121         int elapsed_time, status;
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         setlocale (LC_ALL, "");
132         bindtextdomain (PACKAGE, LOCALEDIR);
133         textdomain (PACKAGE);
135         if (process_arguments (argc, argv) != OK)
136                 usage (_("check_pgsql: could not parse arguments\n"));
138         /* Set signal handling and alarm */
139         if (signal (SIGALRM, timeout_alarm_handler) == SIG_ERR) {
140                 printf (_("Cannot catch SIGALRM"));
141                 return STATE_UNKNOWN;
142         }
143         alarm (timeout_interval);
145         /* make a connection to the database */
146         time (&start_time);
147         conn =
148                 PQsetdbLogin (pghost, pgport, pgoptions, pgtty, dbName, pguser, pgpasswd);
149         time (&end_time);
150         elapsed_time = (int) (end_time - start_time);
152         /* check to see that the backend connection was successfully made */
153         if (PQstatus (conn) == CONNECTION_BAD) {
154                 printf (_("CRITICAL - no connection to '%s' (%s).\n"),
155                         dbName, PQerrorMessage (conn));
156                 PQfinish (conn);
157                 return STATE_CRITICAL;
158         }
159         else if (elapsed_time > tcrit) {
160                 status = STATE_CRITICAL;
161         }
162         else if (elapsed_time > twarn) {
163                 status = STATE_WARNING;
164         }
165         else {
166                 status = STATE_OK;
167         }
168         PQfinish (conn);
169         printf (_(" %s - database %s (%d sec.)|%s\n"), 
170                 state_text(status), dbName, elapsed_time,
171                 fperfdata("time", elapsed_time, "s",
172                          (int)twarn, twarn, (int)tcrit, tcrit, TRUE, 0, FALSE,0));
173         return status;
178 /* process command-line arguments */
179 int
180 process_arguments (int argc, char **argv)
182         int c;
184         int option = 0;
185         static struct option longopts[] = {
186                 {"help", no_argument, 0, 'h'},
187                 {"version", no_argument, 0, 'V'},
188                 {"timeout", required_argument, 0, 't'},
189                 {"critical", required_argument, 0, 'c'},
190                 {"warning", required_argument, 0, 'w'},
191                 {"hostname", required_argument, 0, 'H'},
192                 {"logname", required_argument, 0, 'l'},
193                 {"password", required_argument, 0, 'p'},
194                 {"authorization", required_argument, 0, 'a'},
195                 {"port", required_argument, 0, 'P'},
196                 {"database", required_argument, 0, 'd'},
197                 {0, 0, 0, 0}
198         };
200         while (1) {
201                 c = getopt_long (argc, argv, "hVt:c:w:H:P:d:l:p:a:",
202                                  longopts, &option);
204                 if (c == EOF)
205                         break;
207                 switch (c) {
208                 case '?':     /* usage */
209                         printf (_("%s: Unknown argument: %s\n\n"), progname, optarg);
210                         print_usage ();
211                         exit (STATE_UNKNOWN);
212                 case 'h':     /* help */
213                         print_help ();
214                         exit (STATE_OK);
215                 case 'V':     /* version */
216                         print_revision (progname, revision);
217                         exit (STATE_OK);
218                 case 't':     /* timeout period */
219                         if (!is_integer (optarg))
220                                 usage2 (_("Timeout interval must be a positive integer"), optarg);
221                         else
222                                 timeout_interval = atoi (optarg);
223                         break;
224                 case 'c':     /* critical time threshold */
225                         if (!is_nonnegative (optarg))
226                                 usage2 (_("Critical threshold must be a positive integer"), optarg);
227                         else
228                                 tcrit = strtod (optarg, NULL);
229                         break;
230                 case 'w':     /* warning time threshold */
231                         if (!is_nonnegative (optarg))
232                                 usage2 (_("Critical threshold must be a positive integer"), optarg);
233                         else
234                                 twarn = strtod (optarg, NULL);
235                         break;
236                 case 'H':     /* host */
237                         if (!is_host (optarg))
238                                 usage2 (_("Invalid hostname/address"), optarg);
239                         else
240                                 pghost = optarg;
241                         break;
242                 case 'P':     /* port */
243                         if (!is_integer (optarg))
244                                 usage2 (_("Port must be a positive integer"), optarg);
245                         else
246                                 pgport = optarg;
247                         break;
248                 case 'd':     /* database name */
249                         if (!is_pg_dbname (optarg)) /* checks length and valid chars */
250                                 usage2 (_("Database name is not valid"), optarg);
251                         else /* we know length, and know optarg is terminated, so us strcpy */
252                                 strcpy (dbName, optarg);
253                         break;
254                 case 'l':     /* login name */
255                         if (!is_pg_logname (optarg))
256                                 usage2 (_("user name is not valid"), optarg);
257                         else
258                                 pguser = optarg;
259                         break;
260                 case 'p':     /* authentication password */
261                 case 'a':
262                         pgpasswd = optarg;
263                         break;
264                 }
265         }
267         return validate_arguments ();
271 /******************************************************************************
273 @@-
274 <sect3>
275 <title>validate_arguments</title>
277 <para>&PROTO_validate_arguments;</para>
279 <para>Given a database name, this function returns TRUE if the string
280 is a valid PostgreSQL database name, and returns false if it is
281 not.</para>
283 <para>Valid PostgreSQL database names are less than &NAMEDATALEN;
284 characters long and consist of letters, numbers, and underscores. The
285 first character cannot be a number, however.</para>
287 </sect3>
288 -@@
289 ******************************************************************************/
293 int
294 validate_arguments ()
296         return OK;
300 /******************************************************************************
302 @@-
303 <sect3>
304 <title>is_pg_dbname</title>
306 <para>&PROTO_is_pg_dbname;</para>
308 <para>Given a database name, this function returns TRUE if the string
309 is a valid PostgreSQL database name, and returns false if it is
310 not.</para>
312 <para>Valid PostgreSQL database names are less than &NAMEDATALEN;
313 characters long and consist of letters, numbers, and underscores. The
314 first character cannot be a number, however.</para>
316 </sect3>
317 -@@
318 ******************************************************************************/
322 int
323 is_pg_dbname (char *dbname)
325         char txt[NAMEDATALEN];
326         char tmp[NAMEDATALEN];
327         if (strlen (dbname) > NAMEDATALEN - 1)
328                 return (FALSE);
329         strncpy (txt, dbname, NAMEDATALEN - 1);
330         txt[NAMEDATALEN - 1] = 0;
331         if (sscanf (txt, "%[_a-zA-Z]%[^_a-zA-Z0-9]", tmp, tmp) == 1)
332                 return (TRUE);
333         if (sscanf (txt, "%[_a-zA-Z]%[_a-zA-Z0-9]%[^_a-zA-Z0-9]", tmp, tmp, tmp) ==
334                         2) return (TRUE);
335         return (FALSE);
338 /**
340 the tango program should eventually create an entity here based on the 
341 function prototype
343 @@-
344 <sect3>
345 <title>is_pg_logname</title>
347 <para>&PROTO_is_pg_logname;</para>
349 <para>Given a username, this function returns TRUE if the string is a
350 valid PostgreSQL username, and returns false if it is not. Valid PostgreSQL
351 usernames are less than &NAMEDATALEN; characters long and consist of
352 letters, numbers, dashes, and underscores, plus possibly some other
353 characters.</para>
355 <para>Currently this function only checks string length. Additional checks
356 should be added.</para>
358 </sect3>
359 -@@
360 ******************************************************************************/
364 int
365 is_pg_logname (char *username)
367         if (strlen (username) > NAMEDATALEN - 1)
368                 return (FALSE);
369         return (TRUE);
372 /******************************************************************************
373 @@-
374 </sect2> 
375 </sect1>
376 </article>
377 -@@
378 ******************************************************************************/
382 void
383 print_help (void)
385         char *myport;
387         asprintf (&myport, "%d", DEFAULT_PORT);
389         print_revision (progname, revision);
391         printf (_(COPYRIGHT), copyright, email);
393         printf (_("Test whether a PostgreSQL Database is accepting connections.\n\n"));
395         print_usage ();
397         printf (_(UT_HELP_VRSN));
399         printf (_(UT_HOST_PORT), 'P', myport);
401         printf (_(UT_IPv46));
403         printf (S_("\
404   -d, --database=STRING\n\
405     Database to check (default: %s)\n\
406   -l, --logname = STRING\n\
407     Login name of user\n\
408   -p, --password = STRING\n\
409     Password (BIG SECURITY ISSUE)\n"), DEFAULT_DB);
411         printf (_(UT_WARN_CRIT));
413         printf (_(UT_TIMEOUT), DEFAULT_SOCKET_TIMEOUT);
415         printf (_(UT_VERBOSE));
417         printf (S_("\nAll parameters are optional.\n\
418 \n\
419 This plugin tests a PostgreSQL DBMS to determine whether it is active and\n\
420 accepting queries. In its current operation, it simply connects to the\n\
421 specified database, and then disconnects. If no database is specified, it\n\
422 connects to the template1 database, which is present in every functioning \n\
423 PostgreSQL DBMS.\n"));
424         printf (S_("\n\
425 The plugin will connect to a local postmaster if no host is specified. To\n\
426 connect to a remote host, be sure that the remote postmaster accepts TCP/IP\n\
427 connections (start the postmaster with the -i option).\n"));
428         printf (S_("\n\
429 Typically, the nagios user (unless the --logname option is used) should be\n\
430 able to connect to the database without a password. The plugin can also send\n\
431 a password, but no effort is made to obsure or encrypt the password.\n"));
433         printf (_(UT_SUPPORT));
438 void
439 print_usage (void)
441         printf (S_("\
442 Usage:\n %s [-H <host>] [-P <port>] [-c <critical time>] [-w <warning time>]\n\
443             [-t <timeout>]"), progname);
444         printf (S_("[-d <database>] [-l <logname>] [-p <password>]\n"));
445         printf (S_("\
446          %s (-h | --help) for detailed help\n\
447          %s (-V | --version) for version information\n"),
448                                         progname, progname);