Code

print_help and print_usage() cleanup
[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 const char *progname = "check_pgsql";
22 const char *revision = "$Revision$";
23 const char *copyright = "1999-2004";
24 const char *email = "nagiosplug-devel@lists.sourceforge.net";
26 #include "common.h"
27 #include "utils.h"
29 #include "netutils.h"
30 #include <libpq-fe.h>
32 #define DEFAULT_DB "template1"
33 #define DEFAULT_HOST "127.0.0.1"
35 enum {
36         DEFAULT_PORT = 5432,
37         DEFAULT_WARN = 2,
38         DEFAULT_CRIT = 8
39 };
43 int process_arguments (int, char **);
44 int validate_arguments (void);
45 void print_usage (void);
46 void print_help (void);
47 int is_pg_dbname (char *);
48 int is_pg_logname (char *);
50 char *pghost = NULL;                                            /* host name of the backend server */
51 char *pgport = NULL;                                            /* port of the backend server */
52 int default_port = DEFAULT_PORT;
53 char *pgoptions = NULL;
54 char *pgtty = NULL;
55 char dbName[NAMEDATALEN] = DEFAULT_DB;
56 char *pguser = NULL;
57 char *pgpasswd = NULL;
58 double twarn = (double)DEFAULT_WARN;
59 double tcrit = (double)DEFAULT_CRIT;
61 PGconn *conn;
62 /*PGresult   *res;*/
65 /******************************************************************************
67 The (psuedo?)literate programming XML is contained within \@\@\- <XML> \-\@\@
68 tags in the comments. With in the tags, the XML is assembled sequentially.
69 You can define entities in tags. You also have all the #defines available as
70 entities.
72 Please note that all tags must be lowercase to use the DocBook XML DTD.
74 @@-<article>
76 <sect1>
77 <title>Quick Reference</title>
78 <!-- The refentry forms a manpage -->
79 <refentry>
80 <refmeta>
81 <manvolnum>5<manvolnum>
82 </refmeta>
83 <refnamdiv>
84 <refname>&progname;</refname>
85 <refpurpose>&SUMMARY;</refpurpose>
86 </refnamdiv>
87 </refentry>
88 </sect1>
90 <sect1>
91 <title>FAQ</title>
92 </sect1>
94 <sect1>
95 <title>Theory, Installation, and Operation</title>
97 <sect2>
98 <title>General Description</title>
99 <para>
100 &DESCRIPTION;
101 </para>
102 </sect2>
104 <sect2>
105 <title>Future Enhancements</title>
106 <para>ToDo List</para>
107 <itemizedlist>
108 <listitem>Add option to get password from a secured file rather than the command line</listitem>
109 <listitem>Add option to specify the query to execute</listitem>
110 </itemizedlist>
111 </sect2>
114 <sect2>
115 <title>Functions</title>
116 -@@
117 ******************************************************************************/
121 int
122 main (int argc, char **argv)
124         int elapsed_time;
125         int status = STATE_UNKNOWN;
127         /* begin, by setting the parameters for a backend connection if the
128          * parameters are null, then the system will try to use reasonable
129          * defaults by looking up environment variables or, failing that,
130          * using hardwired constants */
132         pgoptions = NULL;  /* special options to start up the backend server */
133         pgtty = NULL;      /* debugging tty for the backend server */
135         setlocale (LC_ALL, "");
136         bindtextdomain (PACKAGE, LOCALEDIR);
137         textdomain (PACKAGE);
139         if (process_arguments (argc, argv) != TRUE)
140                 usage4 (_("Could not parse arguments"));
142         /* Set signal handling and alarm */
143         if (signal (SIGALRM, timeout_alarm_handler) == SIG_ERR) {
144                 usage4 (_("Cannot catch SIGALRM"));
145         }
146         alarm (timeout_interval);
148         /* make a connection to the database */
149         time (&start_time);
150         conn =
151                 PQsetdbLogin (pghost, pgport, pgoptions, pgtty, dbName, pguser, pgpasswd);
152         time (&end_time);
153         elapsed_time = (int) (end_time - start_time);
155         /* check to see that the backend connection was successfully made */
156         if (PQstatus (conn) == CONNECTION_BAD) {
157                 printf (_("CRITICAL - no connection to '%s' (%s).\n"),
158                         dbName, PQerrorMessage (conn));
159                 PQfinish (conn);
160                 return STATE_CRITICAL;
161         }
162         else if (elapsed_time > tcrit) {
163                 status = STATE_CRITICAL;
164         }
165         else if (elapsed_time > twarn) {
166                 status = STATE_WARNING;
167         }
168         else {
169                 status = STATE_OK;
170         }
171         PQfinish (conn);
172         printf (_(" %s - database %s (%d sec.)|%s\n"), 
173                 state_text(status), dbName, elapsed_time,
174                 fperfdata("time", elapsed_time, "s",
175                          (int)twarn, twarn, (int)tcrit, tcrit, TRUE, 0, FALSE,0));
176         return status;
181 /* process command-line arguments */
182 int
183 process_arguments (int argc, char **argv)
185         int c;
187         int option = 0;
188         static struct option longopts[] = {
189                 {"help", no_argument, 0, 'h'},
190                 {"version", no_argument, 0, 'V'},
191                 {"timeout", required_argument, 0, 't'},
192                 {"critical", required_argument, 0, 'c'},
193                 {"warning", required_argument, 0, 'w'},
194                 {"hostname", required_argument, 0, 'H'},
195                 {"logname", required_argument, 0, 'l'},
196                 {"password", required_argument, 0, 'p'},
197                 {"authorization", required_argument, 0, 'a'},
198                 {"port", required_argument, 0, 'P'},
199                 {"database", required_argument, 0, 'd'},
200                 {0, 0, 0, 0}
201         };
203         while (1) {
204                 c = getopt_long (argc, argv, "hVt:c:w:H:P:d:l:p:a:",
205                                  longopts, &option);
207                 if (c == EOF)
208                         break;
210                 switch (c) {
211                 case '?':     /* usage */
212                         printf (_("%s: Unknown argument: %s\n\n"), progname, optarg);
213                         print_usage ();
214                         exit (STATE_UNKNOWN);
215                 case 'h':     /* help */
216                         print_help ();
217                         exit (STATE_OK);
218                 case 'V':     /* version */
219                         print_revision (progname, revision);
220                         exit (STATE_OK);
221                 case 't':     /* timeout period */
222                         if (!is_integer (optarg))
223                                 usage2 (_("Timeout interval must be a positive integer"), optarg);
224                         else
225                                 timeout_interval = atoi (optarg);
226                         break;
227                 case 'c':     /* critical time threshold */
228                         if (!is_nonnegative (optarg))
229                                 usage2 (_("Critical threshold must be a positive integer"), optarg);
230                         else
231                                 tcrit = strtod (optarg, NULL);
232                         break;
233                 case 'w':     /* warning time threshold */
234                         if (!is_nonnegative (optarg))
235                                 usage2 (_("Critical threshold must be a positive integer"), optarg);
236                         else
237                                 twarn = strtod (optarg, NULL);
238                         break;
239                 case 'H':     /* host */
240                         if (!is_host (optarg))
241                                 usage2 (_("Invalid hostname/address"), optarg);
242                         else
243                                 pghost = optarg;
244                         break;
245                 case 'P':     /* port */
246                         if (!is_integer (optarg))
247                                 usage2 (_("Port must be a positive integer"), optarg);
248                         else
249                                 pgport = optarg;
250                         break;
251                 case 'd':     /* database name */
252                         if (!is_pg_dbname (optarg)) /* checks length and valid chars */
253                                 usage2 (_("Database name is not valid"), optarg);
254                         else /* we know length, and know optarg is terminated, so us strcpy */
255                                 strcpy (dbName, optarg);
256                         break;
257                 case 'l':     /* login name */
258                         if (!is_pg_logname (optarg))
259                                 usage2 (_("User name is not valid"), optarg);
260                         else
261                                 pguser = optarg;
262                         break;
263                 case 'p':     /* authentication password */
264                 case 'a':
265                         pgpasswd = optarg;
266                         break;
267                 }
268         }
270         return validate_arguments ();
274 /******************************************************************************
276 @@-
277 <sect3>
278 <title>validate_arguments</title>
280 <para>&PROTO_validate_arguments;</para>
282 <para>Given a database name, this function returns TRUE if the string
283 is a valid PostgreSQL database name, and returns false if it is
284 not.</para>
286 <para>Valid PostgreSQL database names are less than &NAMEDATALEN;
287 characters long and consist of letters, numbers, and underscores. The
288 first character cannot be a number, however.</para>
290 </sect3>
291 -@@
292 ******************************************************************************/
296 int
297 validate_arguments ()
299         return OK;
303 /******************************************************************************
305 @@-
306 <sect3>
307 <title>is_pg_dbname</title>
309 <para>&PROTO_is_pg_dbname;</para>
311 <para>Given a database name, this function returns TRUE if the string
312 is a valid PostgreSQL database name, and returns false if it is
313 not.</para>
315 <para>Valid PostgreSQL database names are less than &NAMEDATALEN;
316 characters long and consist of letters, numbers, and underscores. The
317 first character cannot be a number, however.</para>
319 </sect3>
320 -@@
321 ******************************************************************************/
325 int
326 is_pg_dbname (char *dbname)
328         char txt[NAMEDATALEN];
329         char tmp[NAMEDATALEN];
330         if (strlen (dbname) > NAMEDATALEN - 1)
331                 return (FALSE);
332         strncpy (txt, dbname, NAMEDATALEN - 1);
333         txt[NAMEDATALEN - 1] = 0;
334         if (sscanf (txt, "%[_a-zA-Z]%[^_a-zA-Z0-9]", tmp, tmp) == 1)
335                 return (TRUE);
336         if (sscanf (txt, "%[_a-zA-Z]%[_a-zA-Z0-9]%[^_a-zA-Z0-9]", tmp, tmp, tmp) ==
337                         2) return (TRUE);
338         return (FALSE);
341 /**
343 the tango program should eventually create an entity here based on the 
344 function prototype
346 @@-
347 <sect3>
348 <title>is_pg_logname</title>
350 <para>&PROTO_is_pg_logname;</para>
352 <para>Given a username, this function returns TRUE if the string is a
353 valid PostgreSQL username, and returns false if it is not. Valid PostgreSQL
354 usernames are less than &NAMEDATALEN; characters long and consist of
355 letters, numbers, dashes, and underscores, plus possibly some other
356 characters.</para>
358 <para>Currently this function only checks string length. Additional checks
359 should be added.</para>
361 </sect3>
362 -@@
363 ******************************************************************************/
367 int
368 is_pg_logname (char *username)
370         if (strlen (username) > NAMEDATALEN - 1)
371                 return (FALSE);
372         return (TRUE);
375 /******************************************************************************
376 @@-
377 </sect2> 
378 </sect1>
379 </article>
380 -@@
381 ******************************************************************************/
385 void
386 print_help (void)
388         char *myport;
390         asprintf (&myport, "%d", DEFAULT_PORT);
392         print_revision (progname, revision);
394         printf (COPYRIGHT, copyright, email);
396         printf (_("Test whether a PostgreSQL Database is accepting connections.\n\n"));
398         print_usage ();
400         printf (_(UT_HELP_VRSN));
402         printf (_(UT_HOST_PORT), 'P', myport);
404         printf (_(UT_IPv46));
406         printf (S_("\
407   -d, --database=STRING\n\
408     Database to check (default: %s)\n\
409   -l, --logname = STRING\n\
410     Login name of user\n\
411   -p, --password = STRING\n\
412     Password (BIG SECURITY ISSUE)\n"), DEFAULT_DB);
414         printf (_(UT_WARN_CRIT));
416         printf (_(UT_TIMEOUT), DEFAULT_SOCKET_TIMEOUT);
418         printf (_(UT_VERBOSE));
420         printf (S_("\nAll parameters are optional.\n\
421 \n\
422 This plugin tests a PostgreSQL DBMS to determine whether it is active and\n\
423 accepting queries. In its current operation, it simply connects to the\n\
424 specified database, and then disconnects. If no database is specified, it\n\
425 connects to the template1 database, which is present in every functioning \n\
426 PostgreSQL DBMS.\n"));
427         printf (S_("\n\
428 The plugin will connect to a local postmaster if no host is specified. To\n\
429 connect to a remote host, be sure that the remote postmaster accepts TCP/IP\n\
430 connections (start the postmaster with the -i option).\n"));
431         printf (S_("\n\
432 Typically, the nagios user (unless the --logname option is used) should be\n\
433 able to connect to the database without a password. The plugin can also send\n\
434 a password, but no effort is made to obsure or encrypt the password.\n"));
436         printf (_(UT_SUPPORT));
441 void
442 print_usage (void)
444         printf ("\
445 Usage: %s [-H <host>] [-P <port>] [-c <critical time>] [-w <warning time>]\n\
446                   [-t <timeout>] [-d <database>] [-l <logname>] [-p <password>]\n", progname);