1 /******************************************************************************
2 *
3 * Nagios check_fping plugin
4 *
5 * License: GPL
6 * Copyright (c) 1999-2006 nagios-plugins team
7 *
8 * Last Modified: $Date$
9 *
10 * Description:
11 *
12 * This file contains the check_disk plugin
13 *
14 * This plugin will use the fping command to ping the specified host for a fast check
15 *
16 *
17 * License Information:
18 *
19 * This program is free software; you can redistribute it and/or modify
20 * it under the terms of the GNU General Public License as published by
21 * the Free Software Foundation; either version 2 of the License, or
22 * (at your option) any later version.
23 *
24 * This program is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 * GNU General Public License for more details.
28 *
29 * You should have received a copy of the GNU General Public License
30 * along with this program; if not, write to the Free Software
31 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
33 $Id$
35 ******************************************************************************/
37 const char *progname = "check_fping";
38 const char *revision = "$Revision$";
39 const char *copyright = "2000-2006";
40 const char *email = "nagiosplug-devel@lists.sourceforge.net";
42 #include "common.h"
43 #include "popen.h"
44 #include "netutils.h"
45 #include "utils.h"
47 enum {
48 PACKET_COUNT = 1,
49 PACKET_SIZE = 56,
50 PL = 0,
51 RTA = 1
52 };
54 int textscan (char *buf);
55 int process_arguments (int, char **);
56 int get_threshold (char *arg, char *rv[2]);
57 void print_help (void);
58 void print_usage (void);
60 char *server_name = NULL;
61 int packet_size = PACKET_SIZE;
62 int packet_count = PACKET_COUNT;
63 int verbose = FALSE;
64 int cpl;
65 int wpl;
66 double crta;
67 double wrta;
68 int cpl_p = FALSE;
69 int wpl_p = FALSE;
70 int crta_p = FALSE;
71 int wrta_p = FALSE;
73 int
74 main (int argc, char **argv)
75 {
76 /* normaly should be int result = STATE_UNKNOWN; */
78 int status = STATE_UNKNOWN;
79 char *server = NULL;
80 char *command_line = NULL;
81 char *input_buffer = NULL;
82 input_buffer = malloc (MAX_INPUT_BUFFER);
84 setlocale (LC_ALL, "");
85 bindtextdomain (PACKAGE, LOCALEDIR);
86 textdomain (PACKAGE);
88 if (process_arguments (argc, argv) == ERROR)
89 usage4 (_("Could not parse arguments"));
91 server = strscpy (server, server_name);
93 /* compose the command */
94 asprintf (&command_line, "%s -b %d -c %d %s", PATH_TO_FPING,
95 packet_size, packet_count, server);
97 if (verbose)
98 printf ("%s\n", command_line);
100 /* run the command */
101 child_process = spopen (command_line);
102 if (child_process == NULL) {
103 printf (_("Could not open pipe: %s\n"), command_line);
104 return STATE_UNKNOWN;
105 }
107 child_stderr = fdopen (child_stderr_array[fileno (child_process)], "r");
108 if (child_stderr == NULL) {
109 printf (_("Could not open stderr for %s\n"), command_line);
110 }
112 while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process)) {
113 if (verbose)
114 printf ("%s", input_buffer);
115 status = max_state (status, textscan (input_buffer));
116 }
118 /* If we get anything on STDERR, at least set warning */
119 while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_stderr)) {
120 status = max_state (status, STATE_WARNING);
121 if (verbose)
122 printf ("%s", input_buffer);
123 status = max_state (status, textscan (input_buffer));
124 }
125 (void) fclose (child_stderr);
127 /* close the pipe */
128 if (spclose (child_process))
129 /* need to use max_state not max */
130 status = max_state (status, STATE_WARNING);
132 printf ("FPING %s - %s\n", state_text (status), server_name);
134 return status;
135 }
139 int
140 textscan (char *buf)
141 {
142 char *rtastr = NULL;
143 char *losstr = NULL;
144 double loss;
145 double rta;
146 int status = STATE_UNKNOWN;
148 if (strstr (buf, "not found")) {
149 die (STATE_CRITICAL, _("FPING UNKNOW - %s not found\n"), server_name);
151 }
152 else if (strstr (buf, "is unreachable") || strstr (buf, "Unreachable")) {
153 die (STATE_CRITICAL, _("FPING CRITICAL - %s is unreachable\n"),
154 "host");
156 }
157 else if (strstr (buf, "is down")) {
158 die (STATE_CRITICAL, _("FPING CRITICAL - %s is down\n"), server_name);
160 }
161 else if (strstr (buf, "is alive")) {
162 status = STATE_OK;
164 }
165 else if (strstr (buf, "xmt/rcv/%loss") && strstr (buf, "min/avg/max")) {
166 losstr = strstr (buf, "=");
167 losstr = 1 + strstr (losstr, "/");
168 losstr = 1 + strstr (losstr, "/");
169 rtastr = strstr (buf, "min/avg/max");
170 rtastr = strstr (rtastr, "=");
171 rtastr = 1 + index (rtastr, '/');
172 loss = strtod (losstr, NULL);
173 rta = strtod (rtastr, NULL);
174 if (cpl_p == TRUE && loss > cpl)
175 status = STATE_CRITICAL;
176 else if (crta_p == TRUE && rta > crta)
177 status = STATE_CRITICAL;
178 else if (wpl_p == TRUE && loss > wpl)
179 status = STATE_WARNING;
180 else if (wrta_p == TRUE && rta > wrta)
181 status = STATE_WARNING;
182 else
183 status = STATE_OK;
184 die (status,
185 _("FPING %s - %s (loss=%.0f%%, rta=%f ms)|%s %s\n"),
186 state_text (status), server_name, loss, rta,
187 perfdata ("loss", (long int)loss, "%", wpl_p, wpl, cpl_p, cpl, TRUE, 0, TRUE, 100),
188 fperfdata ("rta", rta/1.0e3, "s", wrta_p, wrta/1.0e3, crta_p, crta/1.0e3, TRUE, 0, FALSE, 0));
190 }
191 else if(strstr (buf, "xmt/rcv/%loss") ) {
192 /* no min/max/avg if host was unreachable in fping v2.2.b1 */
193 losstr = strstr (buf, "=");
194 losstr = 1 + strstr (losstr, "/");
195 losstr = 1 + strstr (losstr, "/");
196 loss = strtod (losstr, NULL);
197 if (atoi(losstr) == 100)
198 status = STATE_CRITICAL;
199 else if (cpl_p == TRUE && loss > cpl)
200 status = STATE_CRITICAL;
201 else if (wpl_p == TRUE && loss > wpl)
202 status = STATE_WARNING;
203 else
204 status = STATE_OK;
205 /* loss=%.0f%%;%d;%d;0;100 */
206 die (status, _("FPING %s - %s (loss=%.0f%% )|%s\n"),
207 state_text (status), server_name, loss ,
208 perfdata ("loss", (long int)loss, "%", wpl_p, wpl, cpl_p, cpl, TRUE, 0, TRUE, 100));
210 }
211 else {
212 status = max_state (status, STATE_WARNING);
213 }
215 return status;
216 }
220 /* process command-line arguments */
221 int
222 process_arguments (int argc, char **argv)
223 {
224 int c;
225 char *rv[2];
227 int option = 0;
228 static struct option longopts[] = {
229 {"hostname", required_argument, 0, 'H'},
230 {"critical", required_argument, 0, 'c'},
231 {"warning", required_argument, 0, 'w'},
232 {"bytes", required_argument, 0, 'b'},
233 {"number", required_argument, 0, 'n'},
234 {"verbose", no_argument, 0, 'v'},
235 {"version", no_argument, 0, 'V'},
236 {"help", no_argument, 0, 'h'},
237 {0, 0, 0, 0}
238 };
240 rv[PL] = NULL;
241 rv[RTA] = NULL;
243 if (argc < 2)
244 return ERROR;
246 if (!is_option (argv[1])) {
247 server_name = argv[1];
248 argv[1] = argv[0];
249 argv = &argv[1];
250 argc--;
251 }
253 while (1) {
254 c = getopt_long (argc, argv, "+hVvH:c:w:b:n:", longopts, &option);
256 if (c == -1 || c == EOF || c == 1)
257 break;
259 switch (c) {
260 case '?': /* print short usage statement if args not parsable */
261 usage5 ();
262 case 'h': /* help */
263 print_help ();
264 exit (STATE_OK);
265 case 'V': /* version */
266 print_revision (progname, revision);
267 exit (STATE_OK);
268 case 'v': /* verbose mode */
269 verbose = TRUE;
270 break;
271 case 'H': /* hostname */
272 if (is_host (optarg) == FALSE) {
273 usage2 (_("Invalid hostname/address"), optarg);
274 }
275 server_name = strscpy (server_name, optarg);
276 break;
277 case 'c':
278 get_threshold (optarg, rv);
279 if (rv[RTA]) {
280 crta = strtod (rv[RTA], NULL);
281 crta_p = TRUE;
282 rv[RTA] = NULL;
283 }
284 if (rv[PL]) {
285 cpl = atoi (rv[PL]);
286 cpl_p = TRUE;
287 rv[PL] = NULL;
288 }
289 break;
290 case 'w':
291 get_threshold (optarg, rv);
292 if (rv[RTA]) {
293 wrta = strtod (rv[RTA], NULL);
294 wrta_p = TRUE;
295 rv[RTA] = NULL;
296 }
297 if (rv[PL]) {
298 wpl = atoi (rv[PL]);
299 wpl_p = TRUE;
300 rv[PL] = NULL;
301 }
302 break;
303 case 'b': /* bytes per packet */
304 if (is_intpos (optarg))
305 packet_size = atoi (optarg);
306 else
307 usage (_("Packet size must be a positive integer"));
308 break;
309 case 'n': /* number of packets */
310 if (is_intpos (optarg))
311 packet_count = atoi (optarg);
312 else
313 usage (_("Packet count must be a positive integer"));
314 break;
315 }
316 }
318 if (server_name == NULL)
319 usage4 (_("Hostname was not supplied"));
321 return OK;
322 }
325 int
326 get_threshold (char *arg, char *rv[2])
327 {
328 char *arg1 = NULL;
329 char *arg2 = NULL;
331 arg1 = strscpy (arg1, arg);
332 if (strpbrk (arg1, ",:"))
333 arg2 = 1 + strpbrk (arg1, ",:");
335 if (arg2) {
336 arg1[strcspn (arg1, ",:")] = 0;
337 if (strstr (arg1, "%") && strstr (arg2, "%"))
338 die (STATE_UNKNOWN,
339 _("%s: Only one threshold may be packet loss (%s)\n"), progname,
340 arg);
341 if (!strstr (arg1, "%") && !strstr (arg2, "%"))
342 die (STATE_UNKNOWN,
343 _("%s: Only one threshold must be packet loss (%s)\n"),
344 progname, arg);
345 }
347 if (arg2 && strstr (arg2, "%")) {
348 rv[PL] = arg2;
349 rv[RTA] = arg1;
350 }
351 else if (arg2) {
352 rv[PL] = arg1;
353 rv[RTA] = arg2;
354 }
355 else if (strstr (arg1, "%")) {
356 rv[PL] = arg1;
357 }
358 else {
359 rv[RTA] = arg1;
360 }
362 return OK;
363 }
366 void
367 print_help (void)
368 {
370 print_revision (progname, revision);
372 printf ("Copyright (c) 1999 Didi Rieder <adrieder@sbox.tu-graz.ac.at>\n");
373 printf (COPYRIGHT, copyright, email);
375 printf ("%s\n", _("This plugin will use the fping command to ping the specified host for a fast check"));
377 printf ("%s\n", _("Note that it is necessary to set the suid flag on fping."));
379 printf ("\n\n");
381 print_usage ();
383 printf (_(UT_HELP_VRSN));
385 printf (" %s\n", "-H, --hostname=HOST");
386 printf (" %s\n", _("name or IP Address of host to ping (IP Address bypasses name lookup, reducing system load)"));
387 printf (" %s\n", "-w, --warning=THRESHOLD");
388 printf (" %s\n", _("warning threshold pair"));
389 printf (" %s\n", "-c, --critical=THRESHOLD");
390 printf (" %s\n", _("critical threshold pair"));
391 printf (" %s\n", "-b, --bytes=INTEGER");
392 printf (" %s\n", _("size of ICMP packet (default: %d)"),PACKET_SIZE);
393 printf (" %s\n", "-n, --number=INTEGER");
394 printf (" %s\n", _("number of ICMP packets to send (default: %d)"),PACKET_COUNT);
395 printf (_(UT_VERBOSE));
396 printf ("\n");
397 printf (" %s\n", _("THRESHOLD is <rta>,<pl>%% where <rta> is the round trip average travel time (ms)"));
398 printf (" %s\n", _("which triggers a WARNING or CRITICAL state, and <pl> is the percentage of"));
399 printf (" %s\n", _("packet loss to trigger an alarm state."));
400 printf (_(UT_SUPPORT));
401 }
404 void
405 print_usage (void)
406 {
407 printf (_("Usage:"));
408 printf (" %s <host_address> -w limit -c limit [-b size] [-n number]\n", progname);
409 }