Code

mark for translation
[nagiosplug.git] / plugins / check_pgsql.c
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  *****************************************************************************/
26 const char *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"
33 #define DEFAULT_DB "template1"
34 #define DEFAULT_HOST "127.0.0.1"
36 enum {
37         DEFAULT_PORT = 5432,
38         DEFAULT_WARN = 2,
39         DEFAULT_CRIT = 8,
40         DEFAULT_TIMEOUT = 30
41 };
43 #include "config.h"
44 #include "common.h"
45 #include "utils.h"
46 #include <libpq-fe.h>
48 int process_arguments (int, char **);
49 int validate_arguments (void);
50 void print_usage (void);
51 void print_help (void);
52 int is_pg_dbname (char *);
53 int is_pg_logname (char *);
55 char *pghost = NULL;                                            /* host name of the backend server */
56 char *pgport = NULL;                                            /* port of the backend server */
57 int default_port = DEFAULT_PORT;
58 char *pgoptions = NULL;
59 char *pgtty = NULL;
60 char dbName[NAMEDATALEN] = DEFAULT_DB;
61 char *pguser = NULL;
62 char *pgpasswd = NULL;
63 int twarn = DEFAULT_WARN;
64 int tcrit = DEFAULT_CRIT;
66 PGconn *conn;
67 /*PGresult   *res;*/
68 \f
70 /******************************************************************************
72 The (psuedo?)literate programming XML is contained within \@\@\- <XML> \-\@\@
73 tags in the comments. With in the tags, the XML is assembled sequentially.
74 You can define entities in tags. You also have all the #defines available as
75 entities.
77 Please note that all tags must be lowercase to use the DocBook XML DTD.
79 @@-<article>
81 <sect1>
82 <title>Quick Reference</title>
83 <!-- The refentry forms a manpage -->
84 <refentry>
85 <refmeta>
86 <manvolnum>5<manvolnum>
87 </refmeta>
88 <refnamdiv>
89 <refname>&progname;</refname>
90 <refpurpose>&SUMMARY;</refpurpose>
91 </refnamdiv>
92 </refentry>
93 </sect1>
95 <sect1>
96 <title>FAQ</title>
97 </sect1>
99 <sect1>
100 <title>Theory, Installation, and Operation</title>
102 <sect2>
103 <title>General Description</title>
104 <para>
105 &DESCRIPTION;
106 </para>
107 </sect2>
109 <sect2>
110 <title>Future Enhancements</title>
111 <para>ToDo List</para>
112 <itemizedlist>
113 <listitem>Add option to get password from a secured file rather than the command line</listitem>
114 <listitem>Add option to specify the query to execute</listitem>
115 </itemizedlist>
116 </sect2>
119 <sect2>
120 <title>Functions</title>
121 -@@
122 ******************************************************************************/
123 \f
127 void
128 print_help (void)
130         print_revision (progname, REVISION);
131         printf
132                 ("Copyright (c) %s %s <%s>\n\n%s\n",
133                  COPYRIGHT, AUTHOR, EMAIL, SUMMARY);
134         print_usage ();
135         printf (_("\
136 \nOptions:\n\
137  -H, --hostname=ADDRESS\n\
138     Host name argument for servers using host headers (use numeric\n\
139     address if possible to bypass DNS lookup).\n\
140  -P, --port=INTEGER\n\
141     Port number (default: %d)\n\
142  -4, --use-ipv4\n\
143     Use IPv4 connection\n\
144  -6, --use-ipv6\n\
145     Use IPv6 connection\n"), DEFAULT_PORT);
146         printf (S_("\
147   -d, --database=STRING\n\
148     Database to check (default: %s)\n\
149   -l, --logname = STRING\n\
150     Login name of user\n\
151   -p, --password = STRING\n\
152     Password (BIG SECURITY ISSUE)\n\n"), DEFAULT_DB);
153         printf (S_("\nOptions:\n\
154   -c, --critical=INTEGER\n\
155     Exit STATE_CRITICAL if connection time exceeds threshold (default: %d)\n\
156   -w, --warning=INTEGER\n\
157     Exit STATE_WARNING if connection time exceeds threshold (default: %d)\n\
158   -t, --timeout=INTEGER\n\
159     Terminate test if timeout limit is exceeded (default: %d)\n"),
160                 DEFAULT_WARN, DEFAULT_CRIT, DEFAULT_TIMEOUT);
161         printf (_("\
162  -v, --verbose\n\
163     Show details for command-line debugging (Nagios may truncate output)\n\
164  -h, --help\n\
165     Print detailed help screen\n\
166  -V, --version\n\
167     Print version information\n\n"));
168         printf (S_("All parameters are optional.\n\
169 \n\
170 This plugin tests a PostgreSQL DBMS to determine whether it is active and\n\
171 accepting queries. In its current operation, it simply connects to the\n\
172 specified database, and then disconnects. If no database is specified, it\n\
173 connects to the template1 database, which is present in every functioning \n\
174 PostgreSQL DBMS.\n"));
175         printf (S_("\n\
176 The plugin will connect to a local postmaster if no host is specified. To\n\
177 connect to a remote host, be sure that the remote postmaster accepts TCP/IP\n\
178 connections (start the postmaster with the -i option).\n"));
179         printf (S_("\n\
180 Typically, the nagios user (unless the --logname option is used) should be\n\
181 able to connect to the database without a password. The plugin can also send\n\
182 a password, but no effort is made to obsure or encrypt the password.\n"));
184         support ();
187 void
188 print_usage (void)
190         printf (S_("\
191 Usage:\n %s [-H <host>] [-P <port>] [-c <critical time>] [-w <warning time>]\n\
192             [-t <timeout>]"), progname);
193         printf (S_("[-d <database>] [-l <logname>] [-p <password>]\n"));
194         printf (S_("\
195          %s (-h | --help) for detailed help\n\
196          %s (-V | --version) for version information\n"),
197                                         progname, progname);
200 int
201 main (int argc, char **argv)
203         int elapsed_time;
205         /* begin, by setting the parameters for a backend connection if the
206          * parameters are null, then the system will try to use reasonable
207          * defaults by looking up environment variables or, failing that,
208          * using hardwired constants */
210         pgoptions = NULL;  /* special options to start up the backend server */
211         pgtty = NULL;      /* debugging tty for the backend server */
213         if (process_arguments (argc, argv) == ERROR)
214                 usage ("Could not parse arguments");
216         /* Set signal handling and alarm */
217         if (signal (SIGALRM, timeout_alarm_handler) == SIG_ERR) {
218                 printf (_("Cannot catch SIGALRM"));
219                 return STATE_UNKNOWN;
220         }
221         alarm (timeout_interval);
223         /* make a connection to the database */
224         time (&start_time);
225         conn =
226                 PQsetdbLogin (pghost, pgport, pgoptions, pgtty, dbName, pguser, pgpasswd);
227         time (&end_time);
228         elapsed_time = (int) (end_time - start_time);
230         /* check to see that the backend connection was successfully made */
231         if (PQstatus (conn) == CONNECTION_BAD) {
232                 printf (_("PGSQL: CRITICAL - no connection to '%s' (%s).\n"), dbName,
233                                                 PQerrorMessage (conn));
234                 PQfinish (conn);
235                 return STATE_CRITICAL;
236         }
237         else if (elapsed_time > tcrit) {
238                 PQfinish (conn);
239                 printf (_("PGSQL: CRITICAL - database %s (%d sec.)\n"), dbName,
240                                                 elapsed_time);
241                 return STATE_CRITICAL;
242         }
243         else if (elapsed_time > twarn) {
244                 PQfinish (conn);
245                 printf (_("PGSQL: WARNING - database %s (%d sec.)\n"), dbName, elapsed_time);
246                 return STATE_WARNING;
247         }
248         else {
249                 PQfinish (conn);
250                 printf (_("PGSQL: ok - database %s (%d sec.)\n"), dbName, elapsed_time);
251                 return STATE_OK;
252         }
254 \f
257 /* process command-line arguments */
258 int
259 process_arguments (int argc, char **argv)
261         int c;
263         int option_index = 0;
264         static struct option long_options[] = {
265                 {"help", no_argument, 0, 'h'},
266                 {"version", no_argument, 0, 'V'},
267                 {"timeout", required_argument, 0, 't'},
268                 {"critical", required_argument, 0, 'c'},
269                 {"warning", required_argument, 0, 'w'},
270                 {"hostname", required_argument, 0, 'H'},
271                 {"logname", required_argument, 0, 'l'},
272                 {"password", required_argument, 0, 'p'},
273                 {"authorization", required_argument, 0, 'a'},
274                 {"port", required_argument, 0, 'P'},
275                 {"database", required_argument, 0, 'd'},
276                 {0, 0, 0, 0}
277         };
279         while (1) {
280                 c = getopt_long (argc, argv, "hVt:c:w:H:P:d:l:p:a:",
281                                  long_options, &option_index);
283                 if (c == EOF)
284                         break;
286                 switch (c) {
287                 case '?':     /* usage */
288                         usage3 (_("Unknown argument"), optopt);
289                 case 'h':     /* help */
290                         print_help ();
291                         exit (STATE_OK);
292                 case 'V':     /* version */
293                         print_revision (progname, REVISION);
294                         exit (STATE_OK);
295                 case 't':     /* timeout period */
296                         if (!is_integer (optarg))
297                                 usage2 (_("Timeout Interval must be an integer"), optarg);
298                         timeout_interval = atoi (optarg);
299                         break;
300                 case 'c':     /* critical time threshold */
301                         if (!is_integer (optarg))
302                                 usage2 (_("Invalid critical threshold"), optarg);
303                         tcrit = atoi (optarg);
304                         break;
305                 case 'w':     /* warning time threshold */
306                         if (!is_integer (optarg))
307                                 usage2 (_("Invalid critical threshold"), optarg);
308                         twarn = atoi (optarg);
309                         break;
310                 case 'H':     /* host */
311                         if (!is_host (optarg))
312                                 usage2 (_("You gave an invalid host name"), optarg);
313                         pghost = optarg;
314                         break;
315                 case 'P':     /* port */
316                         if (!is_integer (optarg))
317                                 usage2 (_("Port must be an integer"), optarg);
318                         pgport = optarg;
319                         break;
320                 case 'd':     /* database name */
321                         if (!is_pg_dbname (optarg))
322                                 usage2 (_("Database name is not valid"), optarg);
323                         strncpy (dbName, optarg, NAMEDATALEN - 1);
324                         dbName[NAMEDATALEN - 1] = 0;
325                         break;
326                 case 'l':     /* login name */
327                         if (!is_pg_logname (optarg))
328                                 usage2 (_("user name is not valid"), optarg);
329                         pguser = optarg;
330                         break;
331                 case 'p':     /* authentication password */
332                 case 'a':
333                         pgpasswd = optarg;
334                         break;
335                 }
336         }
338         return validate_arguments ();
342 /******************************************************************************
344 @@-
345 <sect3>
346 <title>validate_arguments</title>
348 <para>&PROTO_validate_arguments;</para>
350 <para>Given a database name, this function returns TRUE if the string
351 is a valid PostgreSQL database name, and returns false if it is
352 not.</para>
354 <para>Valid PostgreSQL database names are less than &NAMEDATALEN;
355 characters long and consist of letters, numbers, and underscores. The
356 first character cannot be a number, however.</para>
358 </sect3>
359 -@@
360 ******************************************************************************/
362 int
363 validate_arguments ()
365         return OK;
367 \f
370 /******************************************************************************
372 @@-
373 <sect3>
374 <title>is_pg_dbname</title>
376 <para>&PROTO_is_pg_dbname;</para>
378 <para>Given a database name, this function returns TRUE if the string
379 is a valid PostgreSQL database name, and returns false if it is
380 not.</para>
382 <para>Valid PostgreSQL database names are less than &NAMEDATALEN;
383 characters long and consist of letters, numbers, and underscores. The
384 first character cannot be a number, however.</para>
386 </sect3>
387 -@@
388 ******************************************************************************/
390 int
391 is_pg_dbname (char *dbname)
393         char txt[NAMEDATALEN];
394         char tmp[NAMEDATALEN];
395         if (strlen (dbname) > NAMEDATALEN - 1)
396                 return (FALSE);
397         strncpy (txt, dbname, NAMEDATALEN - 1);
398         txt[NAMEDATALEN - 1] = 0;
399         if (sscanf (txt, "%[_a-zA-Z]%[^_a-zA-Z0-9]", tmp, tmp) == 1)
400                 return (TRUE);
401         if (sscanf (txt, "%[_a-zA-Z]%[_a-zA-Z0-9]%[^_a-zA-Z0-9]", tmp, tmp, tmp) ==
402                         2) return (TRUE);
403         return (FALSE);
406 /**
408 the tango program should eventually create an entity here based on the 
409 function prototype
411 @@-
412 <sect3>
413 <title>is_pg_logname</title>
415 <para>&PROTO_is_pg_logname;</para>
417 <para>Given a username, this function returns TRUE if the string is a
418 valid PostgreSQL username, and returns false if it is not. Valid PostgreSQL
419 usernames are less than &NAMEDATALEN; characters long and consist of
420 letters, numbers, dashes, and underscores, plus possibly some other
421 characters.</para>
423 <para>Currently this function only checks string length. Additional checks
424 should be added.</para>
426 </sect3>
427 -@@
428 ******************************************************************************/
430 int
431 is_pg_logname (char *username)
433         if (strlen (username) > NAMEDATALEN - 1)
434                 return (FALSE);
435         return (TRUE);
438 /******************************************************************************
439 @@-
440 </sect2> 
441 </sect1>
442 </article>
443 -@@
444 ******************************************************************************/