1 /******************************************************************************
2 *
3 * CHECK_FPING.C
4 *
5 * Program: Fping plugin for Nagios
6 * License: GPL
7 * Copyright (c) 1999 Didi Rieder (adrieder@sbox.tu-graz.ac.at)
8 * $Id$
9 *
10 * Modifications:
11 *
12 * 08-24-1999 Didi Rieder (adrieder@sbox.tu-graz.ac.at)
13 * Intial Coding
14 * 09-11-1999 Karl DeBisschop (kdebiss@alum.mit.edu)
15 * Change to spopen
16 * Fix so that state unknown is returned by default
17 * (formerly would give state ok if no fping specified)
18 * Add server_name to output
19 * Reformat to 80-character standard screen
20 * 11-18-1999 Karl DeBisschop (kdebiss@alum.mit.edu)
21 * set STATE_WARNING of stderr written or nonzero status returned
22 *
23 * Description:
24 *
25 * This plugin will use the /bin/fping command (from saint) to ping
26 * the specified host for a fast check if the host is alive. Note that
27 * it is necessary to set the suid flag on fping.
28 ******************************************************************************/
30 const char *progname = "check_fping";
31 const char *revision = "$Revision$";
32 const char *copyright = "1999-2003";
33 const char *email = "nagiosplug-devel@lists.sourceforge.net";
35 #include "common.h"
36 #include "popen.h"
37 #include "utils.h"
39 #define PACKET_COUNT 1
40 #define PACKET_SIZE 56
41 #define UNKNOWN_PACKET_LOSS 200 /* 200% */
42 #define UNKNOWN_TRIP_TIME -1.0 /* -1 seconds */
44 #define PL 0
45 #define RTA 1
47 void
48 print_usage (void)
49 {
50 printf (_("Usage: %s <host_address>\n"), progname);
51 }
53 void
54 print_help (void)
55 {
57 print_revision (progname, "$Revision$");
59 printf (_("\
60 Copyright (c) 1999 Didi Rieder (adrieder@sbox.tu-graz.ac.at)\n\n\
61 This plugin will use the /bin/fping command (from saint) to ping the\n\
62 specified host for a fast check if the host is alive. Note that it is\n\
63 necessary to set the suid flag on fping.\n\n"));
65 print_usage ();
67 printf (_(UT_HELP_VRSN));
69 printf (_("\
70 -H, --hostname=HOST\n\
71 Name or IP Address of host to ping (IP Address bypasses name lookup,\n\
72 reducing system load)\n\
73 -w, --warning=THRESHOLD\n\
74 warning threshold pair\n\
75 -c, --critical=THRESHOLD\n\
76 critical threshold pair\n\
77 -b, --bytes=INTEGER\n\
78 Size of ICMP packet (default: %d)\n\
79 -n, --number=INTEGER\n\
80 Number of ICMP packets to send (default: %d)\n"),
81 PACKET_SIZE, PACKET_COUNT);
83 printf (_(UT_VERBOSE));
85 printf (_("\n\
86 THRESHOLD is <rta>,<pl>%% where <rta> is the round trip average travel\n\
87 time (ms) which triggers a WARNING or CRITICAL state, and <pl> is the\n\
88 percentage of packet loss to trigger an alarm state.\n"));
90 }
91 \f
92 int textscan (char *buf);
93 int process_arguments (int, char **);
94 int get_threshold (char *arg, char *rv[2]);
96 char *server_name = NULL;
97 int cpl = UNKNOWN_PACKET_LOSS;
98 int wpl = UNKNOWN_PACKET_LOSS;
99 double crta = UNKNOWN_TRIP_TIME;
100 double wrta = UNKNOWN_TRIP_TIME;
101 int packet_size = PACKET_SIZE;
102 int packet_count = PACKET_COUNT;
103 int verbose = FALSE;
105 int
106 main (int argc, char **argv)
107 {
108 int status = STATE_UNKNOWN;
109 char *server = NULL;
110 char *command_line = NULL;
111 char *input_buffer = NULL;
112 input_buffer = malloc (MAX_INPUT_BUFFER);
114 if (process_arguments (argc, argv) == ERROR)
115 usage (_("Could not parse arguments\n"));
117 server = strscpy (server, server_name);
119 /* compose the command */
120 asprintf (&command_line, "%s -b %d -c %d %s", PATH_TO_FPING,
121 packet_size, packet_count, server);
123 if (verbose)
124 printf ("%s\n", command_line);
126 /* run the command */
127 child_process = spopen (command_line);
128 if (child_process == NULL) {
129 printf (_("Unable to open pipe: %s\n"), command_line);
130 return STATE_UNKNOWN;
131 }
133 child_stderr = fdopen (child_stderr_array[fileno (child_process)], "r");
134 if (child_stderr == NULL) {
135 printf (_("Could not open stderr for %s\n"), command_line);
136 }
138 while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process)) {
139 if (verbose)
140 printf ("%s", input_buffer);
141 status = max_state (status, textscan (input_buffer));
142 }
144 /* If we get anything on STDERR, at least set warning */
145 while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_stderr)) {
146 status = max_state (status, STATE_WARNING);
147 if (verbose)
148 printf ("%s", input_buffer);
149 status = max_state (status, textscan (input_buffer));
150 }
151 (void) fclose (child_stderr);
153 /* close the pipe */
154 if (spclose (child_process))
155 /* need to use max_state not max */
156 status = max_state (status, STATE_WARNING);
158 printf ("FPING %s - %s\n", state_text (status), server_name);
160 return status;
161 }
166 int
167 textscan (char *buf)
168 {
169 char *rtastr = NULL;
170 char *losstr = NULL;
171 double loss;
172 double rta;
173 int status = STATE_UNKNOWN;
175 if (strstr (buf, "not found")) {
176 die (STATE_CRITICAL, _("FPING unknown - %s not found\n"), server_name);
178 }
179 else if (strstr (buf, "is unreachable") || strstr (buf, "Unreachable")) {
180 die (STATE_CRITICAL, _("FPING critical - %s is unreachable\n"),
181 "host");
183 }
184 else if (strstr (buf, "is down")) {
185 die (STATE_CRITICAL, _("FPING critical - %s is down\n"), server_name);
187 }
188 else if (strstr (buf, "is alive")) {
189 status = STATE_OK;
191 }
192 else if (strstr (buf, "xmt/rcv/%loss") && strstr (buf, "min/avg/max")) {
193 losstr = strstr (buf, "=");
194 losstr = 1 + strstr (losstr, "/");
195 losstr = 1 + strstr (losstr, "/");
196 rtastr = strstr (buf, "min/avg/max");
197 rtastr = strstr (rtastr, "=");
198 rtastr = 1 + index (rtastr, '/');
199 loss = strtod (losstr, NULL);
200 rta = strtod (rtastr, NULL);
201 if (cpl != UNKNOWN_PACKET_LOSS && loss > cpl)
202 status = STATE_CRITICAL;
203 else if (crta != UNKNOWN_TRIP_TIME && rta > crta)
204 status = STATE_CRITICAL;
205 else if (wpl != UNKNOWN_PACKET_LOSS && loss > wpl)
206 status = STATE_WARNING;
207 else if (wrta != UNKNOWN_TRIP_TIME && rta > wrta)
208 status = STATE_WARNING;
209 else
210 status = STATE_OK;
211 die (status, _("FPING %s - %s (loss=%f%%, rta=%f ms)\n"),
212 state_text (status), server_name, loss, rta);
214 }
215 else if(strstr (buf, "xmt/rcv/%loss") ) {
216 /* no min/max/avg if host was unreachable in fping v2.2.b1 */
217 losstr = strstr (buf, "=");
218 losstr = 1 + strstr (losstr, "/");
219 losstr = 1 + strstr (losstr, "/");
220 loss = strtod (losstr, NULL);
221 if (loss == 100)
222 status = STATE_CRITICAL;
223 else if (cpl != UNKNOWN_PACKET_LOSS && loss > cpl)
224 status = STATE_CRITICAL;
225 else if (wpl != UNKNOWN_PACKET_LOSS && loss > wpl)
226 status = STATE_WARNING;
227 else
228 status = STATE_OK;
230 die (status, _("FPING %s - %s (loss=%f%% )\n"),
231 state_text (status), server_name, loss );
233 }
234 else {
235 status = max_state (status, STATE_WARNING);
236 }
238 return status;
239 }
240 \f
244 /* process command-line arguments */
245 int
246 process_arguments (int argc, char **argv)
247 {
248 int c;
249 char *rv[2];
251 int option_index = 0;
252 static struct option long_options[] = {
253 {"hostname", required_argument, 0, 'H'},
254 {"critical", required_argument, 0, 'c'},
255 {"warning", required_argument, 0, 'w'},
256 {"bytes", required_argument, 0, 'b'},
257 {"number", required_argument, 0, 'n'},
258 {"verbose", no_argument, 0, 'v'},
259 {"version", no_argument, 0, 'V'},
260 {"help", no_argument, 0, 'h'},
261 {0, 0, 0, 0}
262 };
264 rv[PL] = NULL;
265 rv[RTA] = NULL;
267 if (argc < 2)
268 return ERROR;
270 if (!is_option (argv[1])) {
271 server_name = argv[1];
272 argv[1] = argv[0];
273 argv = &argv[1];
274 argc--;
275 }
277 while (1) {
278 c = getopt_long (argc, argv, "+hVvH:c:w:b:n:", long_options, &option_index);
280 if (c == -1 || c == EOF || c == 1)
281 break;
283 switch (c) {
284 case '?': /* print short usage statement if args not parsable */
285 printf (_("%s: Unknown argument: %s\n\n"), progname, optarg);
286 print_usage ();
287 exit (STATE_UNKNOWN);
288 case 'h': /* help */
289 print_help ();
290 exit (STATE_OK);
291 case 'V': /* version */
292 print_revision (progname, revision);
293 exit (STATE_OK);
294 case 'v': /* verbose mode */
295 verbose = TRUE;
296 break;
297 case 'H': /* hostname */
298 if (is_host (optarg) == FALSE) {
299 printf (_("Invalid host name/address\n\n"));
300 print_usage ();
301 exit (STATE_UNKNOWN);
302 }
303 server_name = strscpy (server_name, optarg);
304 break;
305 case 'c':
306 get_threshold (optarg, rv);
307 if (rv[RTA]) {
308 crta = strtod (rv[RTA], NULL);
309 rv[RTA] = NULL;
310 }
311 if (rv[PL]) {
312 cpl = atoi (rv[PL]);
313 rv[PL] = NULL;
314 }
315 break;
316 case 'w':
317 get_threshold (optarg, rv);
318 if (rv[RTA]) {
319 wrta = strtod (rv[RTA], NULL);
320 rv[RTA] = NULL;
321 }
322 if (rv[PL]) {
323 wpl = atoi (rv[PL]);
324 rv[PL] = NULL;
325 }
326 break;
327 case 'b': /* bytes per packet */
328 if (is_intpos (optarg))
329 packet_size = atoi (optarg);
330 else
331 usage (_("Packet size must be a positive integer"));
332 break;
333 case 'n': /* number of packets */
334 if (is_intpos (optarg))
335 packet_count = atoi (optarg);
336 else
337 usage (_("Packet count must be a positive integer"));
338 break;
339 }
340 }
343 if (server_name == NULL)
344 usage (_("Host name was not supplied\n\n"));
346 return OK;
347 }
353 int
354 get_threshold (char *arg, char *rv[2])
355 {
356 char *arg1 = NULL;
357 char *arg2 = NULL;
359 arg1 = strscpy (arg1, arg);
360 if (strpbrk (arg1, ",:"))
361 arg2 = 1 + strpbrk (arg1, ",:");
363 if (arg2) {
364 arg1[strcspn (arg1, ",:")] = 0;
365 if (strstr (arg1, "%") && strstr (arg2, "%"))
366 die (STATE_UNKNOWN,
367 _("%s: Only one threshold may be packet loss (%s)\n"), progname,
368 arg);
369 if (!strstr (arg1, "%") && !strstr (arg2, "%"))
370 die (STATE_UNKNOWN,
371 _("%s: Only one threshold must be packet loss (%s)\n"),
372 progname, arg);
373 }
375 if (arg2 && strstr (arg2, "%")) {
376 rv[PL] = arg2;
377 rv[RTA] = arg1;
378 }
379 else if (arg2) {
380 rv[PL] = arg1;
381 rv[RTA] = arg2;
382 }
383 else if (strstr (arg1, "%")) {
384 rv[PL] = arg1;
385 }
386 else {
387 rv[RTA] = arg1;
388 }
390 return OK;
391 }