f9d66110328cbbd0f39c4c9634e045ed504288c8
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$
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)
120 {
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) != TRUE)
136 usage4 (_("Could not parse arguments"));
138 /* Set signal handling and alarm */
139 if (signal (SIGALRM, timeout_alarm_handler) == SIG_ERR) {
140 usage4 (_("Cannot catch SIGALRM"));
141 }
142 alarm (timeout_interval);
144 /* make a connection to the database */
145 time (&start_time);
146 conn =
147 PQsetdbLogin (pghost, pgport, pgoptions, pgtty, dbName, pguser, pgpasswd);
148 time (&end_time);
149 elapsed_time = (int) (end_time - start_time);
151 /* check to see that the backend connection was successfully made */
152 if (PQstatus (conn) == CONNECTION_BAD) {
153 printf (_("CRITICAL - no connection to '%s' (%s).\n"),
154 dbName, PQerrorMessage (conn));
155 PQfinish (conn);
156 return STATE_CRITICAL;
157 }
158 else if (elapsed_time > tcrit) {
159 status = STATE_CRITICAL;
160 }
161 else if (elapsed_time > twarn) {
162 status = STATE_WARNING;
163 }
164 else {
165 status = STATE_OK;
166 }
167 PQfinish (conn);
168 printf (_(" %s - database %s (%d sec.)|%s\n"),
169 state_text(status), dbName, elapsed_time,
170 fperfdata("time", elapsed_time, "s",
171 (int)twarn, twarn, (int)tcrit, tcrit, TRUE, 0, FALSE,0));
172 return status;
173 }
177 /* process command-line arguments */
178 int
179 process_arguments (int argc, char **argv)
180 {
181 int c;
183 int option = 0;
184 static struct option longopts[] = {
185 {"help", no_argument, 0, 'h'},
186 {"version", no_argument, 0, 'V'},
187 {"timeout", required_argument, 0, 't'},
188 {"critical", required_argument, 0, 'c'},
189 {"warning", required_argument, 0, 'w'},
190 {"hostname", required_argument, 0, 'H'},
191 {"logname", required_argument, 0, 'l'},
192 {"password", required_argument, 0, 'p'},
193 {"authorization", required_argument, 0, 'a'},
194 {"port", required_argument, 0, 'P'},
195 {"database", required_argument, 0, 'd'},
196 {0, 0, 0, 0}
197 };
199 while (1) {
200 c = getopt_long (argc, argv, "hVt:c:w:H:P:d:l:p:a:",
201 longopts, &option);
203 if (c == EOF)
204 break;
206 switch (c) {
207 case '?': /* usage */
208 printf (_("%s: Unknown argument: %s\n\n"), progname, optarg);
209 print_usage ();
210 exit (STATE_UNKNOWN);
211 case 'h': /* help */
212 print_help ();
213 exit (STATE_OK);
214 case 'V': /* version */
215 print_revision (progname, revision);
216 exit (STATE_OK);
217 case 't': /* timeout period */
218 if (!is_integer (optarg))
219 usage2 (_("Timeout interval must be a positive integer"), optarg);
220 else
221 timeout_interval = atoi (optarg);
222 break;
223 case 'c': /* critical time threshold */
224 if (!is_nonnegative (optarg))
225 usage2 (_("Critical threshold must be a positive integer"), optarg);
226 else
227 tcrit = strtod (optarg, NULL);
228 break;
229 case 'w': /* warning time threshold */
230 if (!is_nonnegative (optarg))
231 usage2 (_("Critical threshold must be a positive integer"), optarg);
232 else
233 twarn = strtod (optarg, NULL);
234 break;
235 case 'H': /* host */
236 if (!is_host (optarg))
237 usage2 (_("Invalid hostname/address"), optarg);
238 else
239 pghost = optarg;
240 break;
241 case 'P': /* port */
242 if (!is_integer (optarg))
243 usage2 (_("Port must be a positive integer"), optarg);
244 else
245 pgport = optarg;
246 break;
247 case 'd': /* database name */
248 if (!is_pg_dbname (optarg)) /* checks length and valid chars */
249 usage2 (_("Database name is not valid"), optarg);
250 else /* we know length, and know optarg is terminated, so us strcpy */
251 strcpy (dbName, optarg);
252 break;
253 case 'l': /* login name */
254 if (!is_pg_logname (optarg))
255 usage2 (_("user name is not valid"), optarg);
256 else
257 pguser = optarg;
258 break;
259 case 'p': /* authentication password */
260 case 'a':
261 pgpasswd = optarg;
262 break;
263 }
264 }
266 return validate_arguments ();
267 }
270 /******************************************************************************
272 @@-
273 <sect3>
274 <title>validate_arguments</title>
276 <para>&PROTO_validate_arguments;</para>
278 <para>Given a database name, this function returns TRUE if the string
279 is a valid PostgreSQL database name, and returns false if it is
280 not.</para>
282 <para>Valid PostgreSQL database names are less than &NAMEDATALEN;
283 characters long and consist of letters, numbers, and underscores. The
284 first character cannot be a number, however.</para>
286 </sect3>
287 -@@
288 ******************************************************************************/
292 int
293 validate_arguments ()
294 {
295 return OK;
296 }
299 /******************************************************************************
301 @@-
302 <sect3>
303 <title>is_pg_dbname</title>
305 <para>&PROTO_is_pg_dbname;</para>
307 <para>Given a database name, this function returns TRUE if the string
308 is a valid PostgreSQL database name, and returns false if it is
309 not.</para>
311 <para>Valid PostgreSQL database names are less than &NAMEDATALEN;
312 characters long and consist of letters, numbers, and underscores. The
313 first character cannot be a number, however.</para>
315 </sect3>
316 -@@
317 ******************************************************************************/
321 int
322 is_pg_dbname (char *dbname)
323 {
324 char txt[NAMEDATALEN];
325 char tmp[NAMEDATALEN];
326 if (strlen (dbname) > NAMEDATALEN - 1)
327 return (FALSE);
328 strncpy (txt, dbname, NAMEDATALEN - 1);
329 txt[NAMEDATALEN - 1] = 0;
330 if (sscanf (txt, "%[_a-zA-Z]%[^_a-zA-Z0-9]", tmp, tmp) == 1)
331 return (TRUE);
332 if (sscanf (txt, "%[_a-zA-Z]%[_a-zA-Z0-9]%[^_a-zA-Z0-9]", tmp, tmp, tmp) ==
333 2) return (TRUE);
334 return (FALSE);
335 }
337 /**
339 the tango program should eventually create an entity here based on the
340 function prototype
342 @@-
343 <sect3>
344 <title>is_pg_logname</title>
346 <para>&PROTO_is_pg_logname;</para>
348 <para>Given a username, this function returns TRUE if the string is a
349 valid PostgreSQL username, and returns false if it is not. Valid PostgreSQL
350 usernames are less than &NAMEDATALEN; characters long and consist of
351 letters, numbers, dashes, and underscores, plus possibly some other
352 characters.</para>
354 <para>Currently this function only checks string length. Additional checks
355 should be added.</para>
357 </sect3>
358 -@@
359 ******************************************************************************/
363 int
364 is_pg_logname (char *username)
365 {
366 if (strlen (username) > NAMEDATALEN - 1)
367 return (FALSE);
368 return (TRUE);
369 }
371 /******************************************************************************
372 @@-
373 </sect2>
374 </sect1>
375 </article>
376 -@@
377 ******************************************************************************/
381 void
382 print_help (void)
383 {
384 char *myport;
386 asprintf (&myport, "%d", DEFAULT_PORT);
388 print_revision (progname, revision);
390 printf (_(COPYRIGHT), copyright, email);
392 printf (_("Test whether a PostgreSQL Database is accepting connections.\n\n"));
394 print_usage ();
396 printf (_(UT_HELP_VRSN));
398 printf (_(UT_HOST_PORT), 'P', myport);
400 printf (_(UT_IPv46));
402 printf (S_("\
403 -d, --database=STRING\n\
404 Database to check (default: %s)\n\
405 -l, --logname = STRING\n\
406 Login name of user\n\
407 -p, --password = STRING\n\
408 Password (BIG SECURITY ISSUE)\n"), DEFAULT_DB);
410 printf (_(UT_WARN_CRIT));
412 printf (_(UT_TIMEOUT), DEFAULT_SOCKET_TIMEOUT);
414 printf (_(UT_VERBOSE));
416 printf (S_("\nAll parameters are optional.\n\
417 \n\
418 This plugin tests a PostgreSQL DBMS to determine whether it is active and\n\
419 accepting queries. In its current operation, it simply connects to the\n\
420 specified database, and then disconnects. If no database is specified, it\n\
421 connects to the template1 database, which is present in every functioning \n\
422 PostgreSQL DBMS.\n"));
423 printf (S_("\n\
424 The plugin will connect to a local postmaster if no host is specified. To\n\
425 connect to a remote host, be sure that the remote postmaster accepts TCP/IP\n\
426 connections (start the postmaster with the -i option).\n"));
427 printf (S_("\n\
428 Typically, the nagios user (unless the --logname option is used) should be\n\
429 able to connect to the database without a password. The plugin can also send\n\
430 a password, but no effort is made to obsure or encrypt the password.\n"));
432 printf (_(UT_SUPPORT));
433 }
437 void
438 print_usage (void)
439 {
440 printf (S_("\
441 Usage:\n %s [-H <host>] [-P <port>] [-c <critical time>] [-w <warning time>]\n\
442 [-t <timeout>]"), progname);
443 printf (S_("[-d <database>] [-l <logname>] [-p <password>]\n"));
444 printf (S_("\
445 %s (-h | --help) for detailed help\n\
446 %s (-V | --version) for version information\n"),
447 progname, progname);
448 }