Code

Remove getopt_long checks
[nagiosplug.git] / plugins / check_ping.c
1 /*****************************************************************************
2 *
3 * CHECK_PING.C
4 *
5 * Program: Ping plugin for Nagios
6 * License: GPL
7 * Copyright (c) 1999 Ethan Galstad (nagios@nagios.org)
8 *
9 * $Id$
10 *
11 *****************************************************************************/
13 const char *progname = "check_ping";
14 #define REVISION "$Revision$"
15 #define COPYRIGHT "1999-2001"
16 #define AUTHOR "Ethan Galstad/Karl DeBisschop"
17 #define EMAIL "kdebisschop@users.sourceforge.net"
18 #define SUMMARY "Use ping to check connection statistics for a remote host.\n"
20 #define OPTIONS "\
21 -H <host_address> -w <wrta>,<wpl>%% -c <crta>,<cpl>%%\n\
22        [-p packets] [-t timeout] [-L]\n"
24 #define LONGOPTIONS "\
25 -H, --hostname=HOST\n\
26    host to ping\n\
27 -w, --warning=THRESHOLD\n\
28    warning threshold pair\n\
29 -c, --critical=THRESHOLD\n\
30    critical threshold pair\n\
31 -p, --packets=INTEGER\n\
32    number of ICMP ECHO packets to send (Default: %d)\n\
33 -t, --timeout=INTEGER\n\
34    optional specified timeout in second (Default: %d)\n\
35 -L, --link\n\
36    show HTML in the plugin output (obsoleted by urlize)\n\
37 THRESHOLD is <rta>,<pl>%% where <rta> is the round trip average travel\n\
38 time (ms) which triggers a WARNING or CRITICAL state, and <pl> is the\n\
39 percentage of packet loss to trigger an alarm state.\n"
41 #define DESCRIPTION "\
42 This plugin uses the ping command to probe the specified host for packet loss\n\
43 (percentage) and round trip average (milliseconds). It can produce HTML output\n\
44 linking to a traceroute CGI contributed by Ian Cass. The CGI can be found in\n\
45 the contrib area of the downloads section at http://www.nagios.org\n\n"
47 #include "config.h"
48 #include "common.h"
49 #include "popen.h"
50 #include "utils.h"
52 #define UNKNOWN_PACKET_LOSS 200 /* 200% */
53 #define UNKNOWN_TRIP_TIME -1.0  /* -1 seconds */
54 #define DEFAULT_MAX_PACKETS 5           /* default no. of ICMP ECHO packets */
56 #define WARN_DUPLICATES "DUPLICATES FOUND! "
58 int process_arguments (int, char **);
59 int get_threshold (char *, float *, int *);
60 int validate_arguments (void);
61 int run_ping (char *, char *);
62 void print_usage (void);
63 void print_help (void);
65 int display_html = FALSE;
66 int wpl = UNKNOWN_PACKET_LOSS;
67 int cpl = UNKNOWN_PACKET_LOSS;
68 float wrta = UNKNOWN_TRIP_TIME;
69 float crta = UNKNOWN_TRIP_TIME;
70 char **addresses = NULL;
71 int n_addresses;
72 int max_addr = 1;
73 int max_packets = -1;
74 int verbose = FALSE;
76 float rta = UNKNOWN_TRIP_TIME;
77 int pl = UNKNOWN_PACKET_LOSS;
79 char *warn_text = NULL;
81 int
82 main (int argc, char **argv)
83 {
84         char *command_line = NULL;
85         int result = STATE_UNKNOWN;
86         int this_result = STATE_UNKNOWN;
87         int i;
89         addresses = malloc (max_addr);
91         if (process_arguments (argc, argv) == ERROR)
92                 usage ("Could not parse arguments");
93         exit;
95         /* Set signal handling and alarm */
96         if (signal (SIGALRM, popen_timeout_alarm_handler) == SIG_ERR) {
97                 printf ("Cannot catch SIGALRM");
98                 return STATE_UNKNOWN;
99         }
101         /* handle timeouts gracefully */
102         alarm (timeout_interval);
104         for (i = 0 ; i < n_addresses ; i++) {
106                 /* does the host address of number of packets argument come first? */
107 #ifdef PING_PACKETS_FIRST
108                 asprintf (&command_line, PING_COMMAND, max_packets, addresses[i]);
109 #else
110                 asprintf (&command_line, PING_COMMAND, addresses[i], max_packets);
111 #endif
113                 if (verbose)
114                         printf ("%s ==> ", command_line);
116                 /* run the command */
117                 this_result = run_ping (command_line, addresses[i]);
119                 if (pl == UNKNOWN_PACKET_LOSS || rta == UNKNOWN_TRIP_TIME) {
120                         printf ("%s\n", command_line);
121                         terminate (STATE_UNKNOWN,
122                                                                  "Error: Could not interpret output from ping command\n");
123                 }
125                 if (pl >= cpl || rta >= crta || rta < 0)
126                         this_result = STATE_CRITICAL;
127                 else if (pl >= wpl || rta >= wrta)
128                         this_result = STATE_WARNING;
129                 else if (pl >= 0 && rta >= 0)
130                         this_result = max_state (STATE_OK, this_result);        
131         
132                 if (n_addresses > 1 && this_result != STATE_UNKNOWN)
133                         terminate (STATE_OK, "%s is alive\n", addresses[i]);
135                 if (display_html == TRUE)
136                         printf ("<A HREF='%s/traceroute.cgi?%s'>", CGIURL, addresses[i]);
137                 if (pl == 100)
138                         printf ("PING %s - %sPacket loss = %d%%", state_text (this_result), warn_text,
139                                                         pl);
140                 else
141                         printf ("PING %s - %sPacket loss = %d%%, RTA = %2.2f ms",
142                                                         state_text (this_result), warn_text, pl, rta);
143                 if (display_html == TRUE)
144                         printf ("</A>");
145                 printf ("\n");
147                 if (verbose)
148                         printf ("%f:%d%% %f:%d%%\n", wrta, wpl, crta, cpl);
150                 result = max_state (result, this_result);
152         }
154         return result;
156 \f
158 /* process command-line arguments */
159 int
160 process_arguments (int argc, char **argv)
162         int c = 1;
163         char *ptr;
165         int option_index = 0;
166         static struct option long_options[] = {
167                 STD_LONG_OPTS,
168                 {"packets", required_argument, 0, 'p'},
169                 {"nohtml", no_argument, 0, 'n'},
170                 {"link", no_argument, 0, 'L'},
171                 {0, 0, 0, 0}
172         };
174         if (argc < 2)
175                 return ERROR;
177         for (c = 1; c < argc; c++) {
178                 if (strcmp ("-to", argv[c]) == 0)
179                         strcpy (argv[c], "-t");
180                 if (strcmp ("-nohtml", argv[c]) == 0)
181                         strcpy (argv[c], "-n");
182         }
184         while (1) {
185                 c = getopt_long (argc, argv, "VvhnLt:c:w:H:p:", long_options, &option_index);
187                 if (c == -1 || c == EOF)
188                         break;
190                 switch (c) {
191                 case '?':       /* usage */
192                         usage3 ("Unknown argument", optopt);
193                 case 'h':       /* help */
194                         print_help ();
195                         exit (STATE_OK);
196                 case 'V':       /* version */
197                         print_revision (progname, REVISION);
198                         exit (STATE_OK);
199                 case 't':       /* timeout period */
200                         timeout_interval = atoi (optarg);
201                         break;
202                 case 'v':       /* verbose mode */
203                         verbose = TRUE;
204                         break;
205                 case 'H':       /* hostname */
206                         ptr=optarg;
207                         while (1) {
208                                 n_addresses++;
209                                 if (n_addresses > max_addr) {
210                                         max_addr *= 2;
211                                         addresses = realloc (addresses, max_addr);
212                                         if (addresses == NULL)
213                                                 terminate (STATE_UNKNOWN, "Could not realloc() addresses\n");
214                                 }
215                                 addresses[n_addresses-1] = ptr;
216                                 if (ptr = index (ptr, ',')) {
217                                         strcpy (ptr, "");
218                                         ptr += sizeof(char);
219                                 } else {
220                                         break;
221                                 }
222                         }
223                         break;
224                 case 'p':       /* number of packets to send */
225                         if (is_intnonneg (optarg))
226                                 max_packets = atoi (optarg);
227                         else
228                                 usage2 ("<max_packets> (%s) must be a non-negative number\n", optarg);
229                         break;
230                 case 'n':       /* no HTML */
231                         display_html = FALSE;
232                         break;
233                 case 'L':       /* show HTML */
234                         display_html = TRUE;
235                         break;
236                 case 'c':
237                         get_threshold (optarg, &crta, &cpl);
238                         break;
239                 case 'w':
240                         get_threshold (optarg, &wrta, &wpl);
241                         break;
242                 }
243         }
245         c = optind;
246         if (c == argc)
247                 return validate_arguments ();
249         if (addresses[0] == NULL) {
250                 if (is_host (argv[c]) == FALSE) {
251                         printf ("Invalid host name/address: %s\n\n", argv[c]);
252                         return ERROR;
253                 } else {
254                         addresses[0] = argv[c++];
255                         if (c == argc)
256                                 return validate_arguments ();
257                 }
258         }
260         if (wpl == UNKNOWN_PACKET_LOSS) {
261                 if (is_intpercent (argv[c]) == FALSE) {
262                         printf ("<wpl> (%s) must be an integer percentage\n", argv[c]);
263                         return ERROR;
264                 } else {
265                         wpl = atoi (argv[c++]);
266                         if (c == argc)
267                                 return validate_arguments ();
268                 }
269         }
271         if (cpl == UNKNOWN_PACKET_LOSS) {
272                 if (is_intpercent (argv[c]) == FALSE) {
273                         printf ("<cpl> (%s) must be an integer percentage\n", argv[c]);
274                         return ERROR;
275                 } else {
276                         cpl = atoi (argv[c++]);
277                         if (c == argc)
278                                 return validate_arguments ();
279                 }
280         }
282         if (wrta == UNKNOWN_TRIP_TIME) {
283                 if (is_negative (argv[c])) {
284                         printf ("<wrta> (%s) must be a non-negative number\n", argv[c]);
285                         return ERROR;
286                 } else {
287                         wrta = atof (argv[c++]);
288                         if (c == argc)
289                                 return validate_arguments ();
290                 }
291         }
293         if (crta == UNKNOWN_TRIP_TIME) {
294                 if (is_negative (argv[c])) {
295                         printf ("<crta> (%s) must be a non-negative number\n", argv[c]);
296                         return ERROR;
297                 } else {
298                         crta = atof (argv[c++]);
299                         if (c == argc)
300                                 return validate_arguments ();
301                 }
302         }
304         if (max_packets == -1) {
305                 if (is_intnonneg (argv[c])) {
306                         max_packets = atoi (argv[c++]);
307                 }       else {
308                         printf ("<max_packets> (%s) must be a non-negative number\n", argv[c]);
309                         return ERROR;
310                 }
311         }
313         return validate_arguments ();
316 int
317 get_threshold (char *arg, float *trta, int *tpl)
319         if (is_intnonneg (arg) && sscanf (arg, "%f", trta) == 1)
320                 return OK;
321         else if (strpbrk (arg, ",:") && strstr (arg, "%") && sscanf (arg, "%f%*[:,]%d%%", trta, tpl) == 2)
322                 return OK;
323         else if (strstr (arg, "%") && sscanf (arg, "%d%%", tpl) == 1) 
324                 return OK;
325         else
326                 usage2 ("%s: Warning threshold must be integer or percentage!\n\n", arg);
329 int
330 validate_arguments ()
332         float max_seconds;
333         int i;
335         if (wrta == UNKNOWN_TRIP_TIME) {
336                 printf ("<wrta> was not set\n");
337                 return ERROR;
338         }
339         else if (crta == UNKNOWN_TRIP_TIME) {
340                 printf ("<crta> was not set\n");
341                 return ERROR;
342         }
343         else if (wpl == UNKNOWN_PACKET_LOSS) {
344                 printf ("<wpl> was not set\n");
345                 return ERROR;
346         }
347         else if (cpl == UNKNOWN_PACKET_LOSS) {
348                 printf ("<cpl> was not set\n");
349                 return ERROR;
350         }
351         else if (wrta > crta) {
352                 printf ("<wrta> (%f) cannot be larger than <crta> (%f)\n", wrta, crta);
353                 return ERROR;
354         }
355         else if (wpl > cpl) {
356                 printf ("<wpl> (%d) cannot be larger than <cpl> (%d)\n", wpl, cpl);
357                 return ERROR;
358         }
360         if (max_packets == -1)
361                 max_packets = DEFAULT_MAX_PACKETS;
363         max_seconds = crta / 1000.0 * max_packets + max_packets;
364         if (max_seconds > timeout_interval)
365                 timeout_interval = (int)max_seconds;
367         for (i=0; i<n_addresses; i++) {
368                 if (is_host(addresses[i]) == FALSE)
369                         usage2 ("Invalid host name/address", addresses[i]);
370         }
372         return OK;
374 \f
376 int
377 run_ping (char *command_line, char *server_address)
379         char input_buffer[MAX_INPUT_BUFFER];
380         int result = STATE_UNKNOWN;
382         warn_text = malloc (1);
383         if (warn_text == NULL)
384                 terminate (STATE_UNKNOWN, "unable to malloc warn_text");
385         warn_text[0] = 0;
387         if ((child_process = spopen (command_line)) == NULL) {
388                 printf ("Cannot open pipe: ");
389                 terminate (STATE_UNKNOWN, command_line);
390         }
391         child_stderr = fdopen (child_stderr_array[fileno (child_process)], "r");
392         if (child_stderr == NULL)
393                 printf ("Cannot open stderr for %s\n", command_line);
395         while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process)) {
397                 if (strstr (input_buffer, "(DUP!)")) {
398                         /* cannot use the max function since STATE_UNKNOWN is max
399                         result = max (result, STATE_WARNING); */
400                         if( !(result == STATE_CRITICAL) ){
401                                 result = STATE_WARNING;
402                         }
403                         
404                         warn_text = realloc (warn_text, strlen (WARN_DUPLICATES) + 1);
405                         if (warn_text == NULL)
406                                 terminate (STATE_UNKNOWN, "unable to realloc warn_text");
407                         strcpy (warn_text, WARN_DUPLICATES);
408                 }
410                 /* get the percent loss statistics */
411                 if (sscanf
412                                         (input_buffer, "%*d packets transmitted, %*d packets received, +%*d errors, %d%% packet loss",
413                                                  &pl) == 1
414                                 || sscanf 
415                                         (input_buffer, "%*d packets transmitted, %*d packets received, %d%% packet loss",
416                                                 &pl) == 1
417                                 || sscanf 
418                                         (input_buffer, "%*d packets transmitted, %*d packets received, %d%% loss, time", &pl) == 1
419                                 || sscanf
420                                         (input_buffer, "%*d packets transmitted, %*d received, %d%% loss, time", &pl) == 1
421                                         /* Suse 8.0 as reported by Richard * Brodie */
422                                 )
423                         continue;
425                 /* get the round trip average */
426                 else
427                         if (sscanf (input_buffer, "round-trip min/avg/max = %*f/%f/%*f", &rta)
428                                         == 1
429                                         || sscanf (input_buffer,
430                                                                                  "round-trip min/avg/max/mdev = %*f/%f/%*f/%*f",
431                                                                                  &rta) == 1
432                                         || sscanf (input_buffer,
433                                                                                  "round-trip min/avg/max/sdev = %*f/%f/%*f/%*f",
434                                                                                  &rta) == 1
435                                         || sscanf (input_buffer,
436                                                                                  "round-trip min/avg/max/stddev = %*f/%f/%*f/%*f",
437                                                                                  &rta) == 1
438                                         || sscanf (input_buffer,
439                                                                                  "round-trip min/avg/max/std-dev = %*f/%f/%*f/%*f",
440                                                                                  &rta) == 1
441                                         || sscanf (input_buffer, "round-trip (ms) min/avg/max = %*f/%f/%*f",
442                                                                                  &rta) == 1
443                                         || sscanf (input_buffer, "rtt min/avg/max/mdev = %*f/%f/%*f/%*f ms",
444                                                                                  &rta) == 1
445                                                                                 )
446                         continue;
447         }
449         /* this is needed because there is no rta if all packets are lost */
450         if (pl == 100)
451                 rta = crta;
454         /* check stderr */
455         while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_stderr)) {
456                 if (strstr
457                                 (input_buffer,
458                                  "Warning: no SO_TIMESTAMP support, falling back to SIOCGSTAMP"))
459                                 continue;
461                 if (strstr (input_buffer, "Network is unreachable"))
462                         terminate (STATE_CRITICAL, "PING CRITICAL - Network unreachable (%s)",
463                                                                  server_address);
464                 else if (strstr (input_buffer, "Destination Host Unreachable"))
465                         terminate (STATE_CRITICAL, "PING CRITICAL - Host Unreachable (%s)",
466                                                                  server_address);
467                 else if (strstr (input_buffer, "unknown host" ) )
468                         terminate (STATE_CRITICAL, "PING CRITICAL - Host not found (%s)",
469                                                                 server_address);
471                 warn_text =
472                         realloc (warn_text, strlen (warn_text) + strlen (input_buffer) + 2);
473                 if (warn_text == NULL)
474                         terminate (STATE_UNKNOWN, "unable to realloc warn_text");
475                 if (strlen (warn_text) == 0)
476                         strcpy (warn_text, input_buffer);
477                 else
478                         sprintf (warn_text, "%s %s", warn_text, input_buffer);
480                 if (strstr (input_buffer, "DUPLICATES FOUND")) {
481                         if( !(result == STATE_CRITICAL) ){
482                                 result = STATE_WARNING;
483                         }
484                 }
485                 else
486                         result = STATE_CRITICAL ;
487         }
488         (void) fclose (child_stderr);
491         /* close the pipe - WARNING if status is set */
492         if (spclose (child_process))
493                 result = max_state (result, STATE_WARNING);
495         return result;
499 void
500 print_usage (void)
502         printf ("Usage:\n" " %s %s\n"
503                                         " %s (-h | --help) for detailed help\n"
504                                         " %s (-V | --version) for version information\n",
505                                         progname, OPTIONS, progname, progname);
508 void
509 print_help (void)
511         print_revision (progname, REVISION);
512         printf
513                 ("Copyright (c) %s %s <%s>\n\n%s\n",
514                  COPYRIGHT, AUTHOR, EMAIL, SUMMARY);
515         print_usage ();
516         printf
517                 ("\nOptions:\n" LONGOPTIONS "\n" DESCRIPTION "\n", 
518                  DEFAULT_MAX_PACKETS, DEFAULT_SOCKET_TIMEOUT);
519         support ();