Code

plugin to check spread messaging toolkit
[nagiosplug.git] / contrib / check_fping_in.c
1 /******************************************************************************
2 *
3 * CHECK_INET_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 * 09-29-2000 Matthew Grant (matthewg@plain.co.nz)
23 *            changes for monitoring multiple hosts for checking Internet
24 *            reachibility
25 *
26 * Description:
27 *
28 * This plugin will use the /bin/fping command (from nagios) to ping
29 * the specified host for a fast check if the host is alive. Note that
30 * it is necessary to set the suid flag on fping.
31 ******************************************************************************/
33 #include "config.h"
34 #include "common.h"
35 #include "popen.h"
36 #include "utils.h"
38 #define PROGNAME "check_fping"
39 #define PACKET_COUNT 15
40 #define PACKET_SIZE 56
41 #define CRITICAL_COUNT 2
42 #define WARNING_COUNT 1
43 #define UNKNOWN_PACKET_LOSS 200 /* 200% */
44 #define UNKNOWN_TRIP_TIME -1.0 /* -1 seconds */
46 #define STRSZ 100
48 int textscan(char *buf);
49 int process_arguments(int, char **);
50 int get_threshold (char *arg, char *rv[2]);
51 void print_usage(void);
52 void print_help(void);
54 char *server_names=NULL;
55 char *name="INTERNET";
56 int cthresh=CRITICAL_COUNT;
57 int wthresh=WARNING_COUNT;
58 int nnames=0;
59 int tpl=UNKNOWN_PACKET_LOSS;
60 double trta=UNKNOWN_TRIP_TIME;
61 int packet_size=PACKET_SIZE;
62 int packet_count=PACKET_COUNT;
63 int verbose=FALSE;
64 int fail = 0;
65 int not_found = 0;
66 int rta_fail = 0;
67 int pl_fail = 0;
68 int unreachable = 0;
70 int main(int argc, char **argv){
71         int result;
72         int status=STATE_UNKNOWN;
73         char *servers=NULL;
74         char *command_line=NULL;
75         char *input_buffer=NULL;
76         char *pl_buffer=NULL; 
77         char *rta_buffer=NULL; 
78         input_buffer=malloc(MAX_INPUT_BUFFER);
79         rta_buffer = malloc(80);
80         pl_buffer = malloc(80);
81         memset(rta_buffer, 0, 80);
82         memset(pl_buffer, 0, 80);
83         
84         if(process_arguments(argc,argv)==ERROR)
85                 usage("Could not parse arguments\n");
87         servers=strscpy(servers,server_names);
89         /* compose the command */
90         command_line=ssprintf
91                 (command_line,"%s -b %d -c %d %s",
92                  PATH_TO_FPING,
93                  packet_size,
94                  packet_count,
95                  servers);
97         if (verbose) printf("%s\n",command_line);
99         /* run the command */
100         child_process=spopen(command_line);
101         if(child_process==NULL){
102                 printf("Unable to open pipe: %s\n",command_line);
103                 return STATE_UNKNOWN;
104         }
106         child_stderr=fdopen(child_stderr_array[fileno(child_process)],"r");
107         if(child_stderr==NULL){
108                 printf("Could not open stderr for %s\n",command_line);
109         }
111         while (fgets(input_buffer,MAX_INPUT_BUFFER-1,child_process)) {
112                 if (verbose) printf("%s",input_buffer);
113                 result = textscan(input_buffer);
114                 status = max(status,result);
115         }
117         while(fgets(input_buffer,MAX_INPUT_BUFFER-1,child_stderr)) {
118                 if (verbose) printf("%s",input_buffer);
119                 result = textscan(input_buffer);
120                 status = max(status,result);
121         }
122         
123         (void)fclose(child_stderr);
125         /* close the pipe */
126         if(spclose(child_process))
127                 status=max(status,STATE_WARNING);
129         /* Analyse fail count and produce results */
130         if (fail >= wthresh) {
131                 status = max(status, STATE_WARNING);
132         }
134         if (fail >= cthresh) {
135                 status = max(status, STATE_CRITICAL);
136         }
137         
138         if( tpl != UNKNOWN_PACKET_LOSS ) {
139                 snprintf(pl_buffer, 80, ", %d PL", pl_fail);
140         }
142         if( trta != UNKNOWN_TRIP_TIME ) {
143                 snprintf(rta_buffer, 80, ", %d RTA", rta_fail);
145         }
146         
147         printf("FPING %s - %s, %d of %d fail, %d NF, %d UR%s%s\n",
148                         state_text(status),
149                         (name != NULL ? name : server_names),
150                         fail,
151                         nnames,
152                         not_found,
153                         unreachable,
154                         pl_buffer,
155                         rta_buffer);
156         
157         return status;
162 /* analyse fping output - each event resulting in an increment of fail
163  * must be mutually exclusive. packet loss and round trip time analysed 
164  * together, both at once just results in one increment of fail
165  */
166 int textscan(char *buf)
168         char *rtastr=NULL;
169         char *losstr=NULL;
170         double loss;
171         double rta;
172         int status=STATE_OK;
173         
174         if (strstr(buf,"not found")) {
175                 fail++;
176                 not_found++;
177         } else if(strstr(buf,"xmt/rcv/%loss") 
178                 && strstr(buf,"min/avg/max")) {
179                 losstr = strstr(buf,"=");
180                 losstr = 1+strstr(losstr,"/");
181                 losstr = 1+strstr(losstr,"/");
182                 rtastr = strstr(buf,"min/avg/max");
183                 rtastr = strstr(rtastr,"=");
184                 rtastr = 1+index(rtastr,'/');
185                 loss = strtod(losstr,NULL);
186                 rta = strtod(rtastr,NULL);
187                 /* Increment fail counter
188                  */
189                 if (tpl!=UNKNOWN_PACKET_LOSS && loss>tpl) {
190                         fail++;
191                 }
192                 else if (trta!=UNKNOWN_TRIP_TIME && rta>trta) {
193                         fail++;
194                 }
195                 else if (loss >= 100) {
196                         fail++;
197                 }
198                 /* Increment other counters 
199                  */
200                 if (trta!=UNKNOWN_TRIP_TIME && rta>trta) 
201                         rta_fail++;
202                 if (tpl!=UNKNOWN_PACKET_LOSS && loss>tpl) 
203                         pl_fail++;
204                 if (loss >= 100) 
205                         unreachable++;
206         } else if(strstr(buf,"xmt/rcv/%loss") ) {
207                 losstr = strstr(buf,"=");
208                 losstr = 1+strstr(losstr,"/");
209                 losstr = 1+strstr(losstr,"/");
210                 loss = strtod(losstr,NULL);
211                 /* Increment fail counter
212                  */
213                 if (tpl!=UNKNOWN_PACKET_LOSS && loss>tpl) {
214                         fail++;
215                 }
216                 else if (loss >= 100) {
217                         fail++;
218                 }
219                 /* Increment other counters 
220                  */
221                 if (tpl!=UNKNOWN_PACKET_LOSS && loss>tpl)
222                         pl_fail++;
223                 if (loss >= 100) 
224                         unreachable++;
225         }
226         
227         return status;
233 /* process command-line arguments */
234 int process_arguments(int argc, char **argv)
236         int c;
238 #ifdef HAVE_GETOPT_H
239         int option_index = 0;
240         static struct option long_options[] =
241         { 
242                 {"hostname"           ,required_argument,0,'H'},
243                 {"critical"           ,required_argument,0,'c'},
244                 {"warning"            ,required_argument,0,'w'},
245                 {"bytes"              ,required_argument,0,'b'},
246                 {"number"             ,required_argument,0,'n'},
247                 {"pl-threshold"       ,required_argument,0,'p'},
248                 {"rta-threshold"      ,required_argument,0,'r'},
249                 {"name"               ,required_argument,0,'N'},
250                 {"verbose"            ,no_argument,      0,'v'},
251                 {"version"            ,no_argument,      0,'V'},
252                 {"help"               ,no_argument,      0,'h'},
253                 {0,0,0,0}
254         };
255 #else
257         if(argc<2) return ERROR;
258         
259         if (!is_option(argv[1])){
260                 server_names=argv[1];
261                 argv[1]=argv[0];
262                 argv=&argv[1];
263                 argc--;
264         }
265 #endif
266         
267         while (1){
268 #ifdef HAVE_GETOPT_H
269                 c = getopt_long(argc,argv,"+hVvH:c:w:b:n:N:p:r:",long_options,&option_index);
270 #else
271                 c = getopt(argc,argv,"+hVvH:c:w:b:n:N:p:r:");
272 #endif
274                 if (c==-1||c==EOF||c==1)
275                         break;
277                 switch (c)
278                         {
279                         case '?': /* print short usage statement if args not parsable */
280                                 printf("%s: Unknown argument: %s\n\n",my_basename(argv[0]),optarg);
281                                 print_usage();
282                                 exit(STATE_UNKNOWN);
283                         case 'h': /* help */
284                                 print_help();
285                                 exit(STATE_OK);
286                         case 'V': /* version */
287                                 print_revision(my_basename(argv[0]),"$Revision$");
288                                 exit(STATE_OK);
289                         case 'v': /* verbose mode */
290                                 verbose=TRUE;
291                                 break;
292                         case 'H': /* hostname */
293                                 if(is_host(optarg)==FALSE){
294                                         printf("Invalid host name/address\n\n");
295                                         print_usage();
296                                         exit(STATE_UNKNOWN);
297                                 }
298                                 if (server_names != NULL) 
299                                         server_names=strscat(server_names," ");
300                                 server_names=strscat(server_names,optarg);
301                                 nnames++;
302                                 break;
303                         case 'c':
304                                 if (is_intpos(optarg))
305                                         cthresh = atoi(optarg);
306                                 else
307                                         usage("Critical threshold must be a positive integer"); 
308                                 break;
309                         case 'w':
310                                 if (is_intpos(optarg))
311                                         wthresh = atoi(optarg);
312                                 else
313                                         usage("Warning threshold must be a postive integer");
314                                 break;
315                         case 'r':
316                                 if (is_intpos(optarg)) {
317                                         trta=strtod(optarg,NULL);
318                                 } 
319                                 else {
320                                         usage("RTA threshold must be a positive integer");
321                                 }
322                                 break;
323                         case 'p':
324                                 if (is_intpos(optarg)) {
325                                         tpl=strtod(optarg,NULL);
326                                 } 
327                                 else {
328                                         usage("RTA threshold must be a positive integer");
329                                 }
330                                 break;
331                         case 'b': /* bytes per packet */
332                                 if (is_intpos(optarg))
333                                         packet_size=atoi(optarg);
334                                 else
335                                         usage("Packet size must be a positive integer");
336                                 break;
337                         case 'N': /* Name of service */
338                                 name = optarg;
339                                 break;
340                         case 'n': /* number of packets */
341                                 if (is_intpos(optarg))
342                                         packet_count=atoi(optarg);
343                                 else
344                                         usage("Packet count must be a positive integer");
345                                 break;
346                         }
347         }
349         while (optind < argc) {
350                 if(is_host(argv[optind])==FALSE) {
351                         printf("Invalid host name/address\n\n");
352                         print_usage();
353                         exit(STATE_UNKNOWN);
354                 }
355                 if (server_names != NULL)
356                         server_names=strscat(server_names," ");
357                 server_names=strscat(server_names,argv[optind]);
358                 nnames++;
359                 optind++;
360         }
361         
362         if (server_names==NULL || nnames < 2)
363                 usage("At least 2 hostnames must be supplied\n\n");
364         
365         if (cthresh < 2) 
366                 usage("Critical threshold must be at least 2");
367         if (cthresh > nnames)
368                 usage("Critical threshold cannot be greater than number of hosts tested");
369         if (wthresh < 1)
370                 usage("Warning threshold must be at least 1");
371         if (wthresh > nnames)
372                 usage("Warning threshold cannot be greater than number of hosts tested");
373         if(wthresh >= cthresh)
374                 usage("Warning threshold must be less than the critical threshold"); 
375         
376         return OK;
380 void print_usage(void)
382         printf("Usage: %s <host_address> <host_address> [<host_address>] ...\n",PROGNAME);
389 void print_help(void)
392         print_revision(PROGNAME,"$Revision$");
394         printf
395                 ("Copyright (c) 1999 Didi Rieder (adrieder@sbox.tu-graz.ac.at)\n"
396                  "          (c) 2000 Matthew Grant (matthewg@plain.co.nz)\n"
397                  "This plugin will use the /bin/fping command (from saint) to ping the\n"
398                  "specified hosts for a fast check to see if the Internet is still \n"
399                  "reachable, and the results of the testing aggregated. Note that it\n"
400                  "is necessary to set the suid flag on fping.\n\n");
402         print_usage();
404   printf
405                 ("\nOptions:\n"
406                  "-b, --bytes=INTEGER\n"
407                  "   Size of ICMP packet (default: %d)\n"
408                  "-c, --critical=INTEGER (default: %d)\n"
409                  "   critical threshold failure count\n"
410                  "-n, --number=INTEGER\n"
411                  "   Number of ICMP packets to send (default: %d)\n"
412                  "-H, --hostname=HOST\n"
413                  "   Name or IP Address of host to ping (IP Address bypasses name lookup,\n"
414                  "   reducing system load)\n"
415                  "-h, --help\n"
416                  "   Print this help screen\n"
417                  "-N, --name\n"
418                  "   Service name to print in results, defaults to INTERNET\n"
419                  "-p, --pl-threshold\n"
420                  "   Packet loss threshold - specify to turn on packet loss testing\n"
421                  "-r, --rta-threshold\n"
422                  "   Round trip average threshold - specify to turn on RTA testing\n"
423                  "-V, --version\n"
424                  "   Print version information\n"
425                  "-v, --verbose\n"
426                  "   Show details for command-line debugging (do not use with nagios server)\n"
427                  "-w, --warning=INTEGER (default: %d)\n"
428                  "   warning threshold failure count\n",
429                  PACKET_SIZE, CRITICAL_COUNT, PACKET_COUNT, WARNING_COUNT);