6cd217e09cc2a5e6931a62363db8656b962abf04
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)
120 {
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 }
171 }
172 \f
175 /* process command-line arguments */
176 int
177 process_arguments (int argc, char **argv)
178 {
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 ();
264 }
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 ()
289 {
290 return OK;
291 }
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)
317 {
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);
329 }
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)
357 {
358 if (strlen (username) > NAMEDATALEN - 1)
359 return (FALSE);
360 return (TRUE);
361 }
363 /******************************************************************************
364 @@-
365 </sect2>
366 </sect1>
367 </article>
368 -@@
369 ******************************************************************************/
370 \f
375 void
376 print_help (void)
377 {
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));
427 }
432 void
433 print_usage (void)
434 {
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);
443 }