Code

updating help and usage and license
[nagiosplug.git] / plugins / utils.c
1 /*****************************************************************************
2  *
3  * utils.c
4  *
5  * Library of useful functions for plugins
6  *
7  * Copyright (c) 2000 Karl DeBisschop (karl@debisschop.net)
8  * Copyright (c) 2006 Nagios Plugin Development Team
9  * License: GPL
10  *
11  * $Revision$
12  * $Date$
13  ****************************************************************************/
15 #define LOCAL_TIMEOUT_ALARM_HANDLER
17 #include "common.h"
18 #include "utils.h"
19 #include <stdarg.h>
20 #include <limits.h>
22 #include <arpa/inet.h>
24 extern void print_usage (void);
25 extern const char *progname;
27 #define STRLEN 64
28 #define TXTBLK 128
30 /* **************************************************************************
31  * max_state(STATE_x, STATE_y)
32  * compares STATE_x to  STATE_y and returns result based on the following
33  * STATE_UNKNOWN < STATE_OK < STATE_WARNING < STATE_CRITICAL
34  *
35  * Note that numerically the above does not hold
36  ****************************************************************************/
38 int
39 max_state (int a, int b)
40 {
41         if (a == STATE_CRITICAL || b == STATE_CRITICAL)
42                 return STATE_CRITICAL;
43         else if (a == STATE_WARNING || b == STATE_WARNING)
44                 return STATE_WARNING;
45         else if (a == STATE_OK || b == STATE_OK)
46                 return STATE_OK;
47         else if (a == STATE_UNKNOWN || b == STATE_UNKNOWN)
48                 return STATE_UNKNOWN;
49         else if (a == STATE_DEPENDENT || b == STATE_DEPENDENT)
50                 return STATE_DEPENDENT;
51         else
52                 return max (a, b);
53 }
55 void usage (const char *msg)
56 {
57         printf ("%s\n", msg);
58         print_usage ();
59         exit (STATE_UNKNOWN);
60 }
62 void usage_va (const char *fmt, ...)
63 {
64         va_list ap;
65         printf("%s: ", progname);
66         va_start(ap, fmt);
67         vprintf(fmt, ap);
68         va_end(ap);
69         printf("\n");
70         exit (STATE_UNKNOWN);
71 }
73 void usage2(const char *msg, const char *arg)
74 {
75         printf ("%s: %s - %s\n", progname, msg, arg?arg:"(null)" );
76         print_usage ();
77         exit (STATE_UNKNOWN);
78 }
80 void
81 usage3 (const char *msg, int arg)
82 {
83         printf ("%s: %s - %c\n", progname, msg, arg);
84         print_usage();
85         exit (STATE_UNKNOWN);
86 }
88 void
89 usage4 (const char *msg)
90 {
91         printf ("%s: %s\n", progname, msg);
92         print_usage();
93         exit (STATE_UNKNOWN);
94 }
96 char *
97 clean_revstring (const char *revstring)
98 {
99         char plugin_revision[STRLEN];
100         if (sscanf (revstring,"$Revision: %[0-9.]",plugin_revision) == 1)
101                 return strscpy (NULL, plugin_revision);
102         else
103           return strscpy (NULL, "N/A");
106 void
107 print_revision (const char *command_name, const char *revision_string)
109         char plugin_revision[STRLEN];
111         if (sscanf (revision_string, "$Revision: %[0-9.]", plugin_revision) != 1)
112                 strncpy (plugin_revision, "N/A", STRLEN);
113         printf ("%s (%s %s) %s\n",
114                                         command_name, PACKAGE, VERSION, plugin_revision);
117 const char *
118 state_text (int result)
120         switch (result) {
121         case STATE_OK:
122                 return "OK";
123         case STATE_WARNING:
124                 return "WARNING";
125         case STATE_CRITICAL:
126                 return "CRITICAL";
127         case STATE_DEPENDENT:
128                 return "DEPENDENT";
129         default:
130                 return "UNKNOWN";
131         }
134 void
135 die (int result, const char *fmt, ...)
137         va_list ap;
138         va_start (ap, fmt);
139         vprintf (fmt, ap);
140         va_end (ap);
141         exit (result);
144 void
145 timeout_alarm_handler (int signo)
147         if (signo == SIGALRM) {
148                 printf (_("CRITICAL - Plugin timed out after %d seconds\n"),
149                                                 timeout_interval);
150                 exit (STATE_CRITICAL);
151         }
154 int
155 is_numeric (char *number)
157         char tmp[1];
158         float x;
160         if (!number)
161                 return FALSE;
162         else if (sscanf (number, "%f%c", &x, tmp) == 1)
163                 return TRUE;
164         else
165                 return FALSE;
168 int
169 is_positive (char *number)
171         if (is_numeric (number) && atof (number) > 0.0)
172                 return TRUE;
173         else
174                 return FALSE;
177 int
178 is_negative (char *number)
180         if (is_numeric (number) && atof (number) < 0.0)
181                 return TRUE;
182         else
183                 return FALSE;
186 int
187 is_nonnegative (char *number)
189         if (is_numeric (number) && atof (number) >= 0.0)
190                 return TRUE;
191         else
192                 return FALSE;
195 int
196 is_percentage (char *number)
198         int x;
199         if (is_numeric (number) && (x = atof (number)) >= 0 && x <= 100)
200                 return TRUE;
201         else
202                 return FALSE;
205 int
206 is_integer (char *number)
208         long int n;
210         if (!number || (strspn (number, "-0123456789 ") != strlen (number)))
211                 return FALSE;
213         n = strtol (number, NULL, 10);
215         if (errno != ERANGE && n >= INT_MIN && n <= INT_MAX)
216                 return TRUE;
217         else
218                 return FALSE;
221 int
222 is_intpos (char *number)
224         if (is_integer (number) && atoi (number) > 0)
225                 return TRUE;
226         else
227                 return FALSE;
230 int
231 is_intneg (char *number)
233         if (is_integer (number) && atoi (number) < 0)
234                 return TRUE;
235         else
236                 return FALSE;
239 int
240 is_intnonneg (char *number)
242         if (is_integer (number) && atoi (number) >= 0)
243                 return TRUE;
244         else
245                 return FALSE;
248 int
249 is_intpercent (char *number)
251         int i;
252         if (is_integer (number) && (i = atoi (number)) >= 0 && i <= 100)
253                 return TRUE;
254         else
255                 return FALSE;
258 int
259 is_option (char *str)
261         if (!str)
262                 return FALSE;
263         else if (strspn (str, "-") == 1 || strspn (str, "-") == 2)
264                 return TRUE;
265         else
266                 return FALSE;
269 void set_range_start (range *this, double value) {
270         this->start = value;
271         this->start_infinity = FALSE;
274 void set_range_end (range *this, double value) {
275         this->end = value;
276         this->end_infinity = FALSE;
279 range
280 *parse_range_string (char *str) {
281         range *temp_range;
282         double start;
283         double end;
284         char *end_str;
286         temp_range = (range *) malloc(sizeof(range));
288         /* Set defaults */
289         temp_range->start = 0;
290         temp_range->start_infinity = FALSE;
291         temp_range->end = 0;
292         temp_range->end_infinity = TRUE;
293         temp_range->alert_on = OUTSIDE;
295         if (str[0] == '@') {
296                 temp_range->alert_on = INSIDE;
297                 str++;
298         }
300         end_str = index(str, ':');
301         if (end_str != NULL) {
302                 if (str[0] == '~') {
303                         temp_range->start_infinity = TRUE;
304                 } else {
305                         start = strtod(str, NULL);      /* Will stop at the ':' */
306                         set_range_start(temp_range, start);
307                 }
308                 end_str++;              /* Move past the ':' */
309         } else {
310                 end_str = str;
311         }
312         end = strtod(end_str, NULL);
313         if (strcmp(end_str, "") != 0) {
314                 set_range_end(temp_range, end);
315         }
317         if (temp_range->start_infinity == TRUE || 
318                 temp_range->end_infinity == TRUE ||
319                 temp_range->start <= temp_range->end) {
320                 return temp_range;
321         }
322         free(temp_range);
323         return NULL;
326 /* returns 0 if okay, otherwise 1 */
327 int
328 _set_thresholds(thresholds **my_thresholds, char *warn_string, char *critical_string)
330         thresholds *temp_thresholds = NULL;
332         temp_thresholds = malloc(sizeof(temp_thresholds));
334         temp_thresholds->warning = NULL;
335         temp_thresholds->critical = NULL;
337         if (warn_string != NULL) {
338                 if ((temp_thresholds->warning = parse_range_string(warn_string)) == NULL) {
339                         return 1;
340                 }
341         }
342         if (critical_string != NULL) {
343                 if ((temp_thresholds->critical = parse_range_string(critical_string)) == NULL) {
344                         return 1;
345                 }
346         }
348         if (*my_thresholds != 0) {
349                 /* printf("Freeing here: %d\n", *my_thresholds); */
350                 free(*my_thresholds);
351         }
352         *my_thresholds = temp_thresholds;
354         return 0;
357 void
358 set_thresholds(thresholds **my_thresholds, char *warn_string, char *critical_string)
360         if (_set_thresholds(my_thresholds, warn_string, critical_string) == 0) {
361                 return;
362         } else {
363                 usage(_("Range format incorrect"));
364         }
367 /* Returns TRUE if alert should be raised based on the range */
368 int
369 check_range(double value, range *my_range)
371         int false = FALSE;
372         int true = TRUE;
373         
374         if (my_range->alert_on == INSIDE) {
375                 false = TRUE;
376                 true = FALSE;
377         }
379         if (my_range->end_infinity == FALSE && my_range->start_infinity == FALSE) {
380                 if ((my_range->start <= value) && (value <= my_range->end)) {
381                         return false;
382                 } else {
383                         return true;
384                 }
385         } else if (my_range->start_infinity == FALSE && my_range->end_infinity == TRUE) {
386                 if (my_range->start <= value) {
387                         return false;
388                 } else {
389                         return true;
390                 }
391         } else if (my_range->start_infinity == TRUE && my_range->end_infinity == FALSE) {
392                 if (value <= my_range->end) {
393                         return false;
394                 } else {
395                         return true;
396                 }
397         } else {
398                 return false;
399         }
402 /* Returns status */
403 int
404 get_status(double value, thresholds *my_thresholds)
406         if (my_thresholds->critical != NULL) {
407                 if (check_range(value, my_thresholds->critical) == TRUE) {
408                         return STATE_CRITICAL;
409                 }
410         }
411         if (my_thresholds->warning != NULL) {
412                 if (check_range(value, my_thresholds->warning) == TRUE) {
413                         return STATE_WARNING;
414                 }
415         }
416         return STATE_OK;
419 #ifdef NEED_GETTIMEOFDAY
420 int
421 gettimeofday (struct timeval *tv, struct timezone *tz)
423         tv->tv_usec = 0;
424         tv->tv_sec = (long) time ((time_t) 0);
426 #endif
430 double
431 delta_time (struct timeval tv)
433         struct timeval now;
435         gettimeofday (&now, NULL);
436         return ((double)(now.tv_sec - tv.tv_sec) + (double)(now.tv_usec - tv.tv_usec) / (double)1000000);
441 long
442 deltime (struct timeval tv)
444         struct timeval now;
445         gettimeofday (&now, NULL);
446         return (now.tv_sec - tv.tv_sec)*1000000 + now.tv_usec - tv.tv_usec;
452 void
453 strip (char *buffer)
455         size_t x;
456         int i;
458         for (x = strlen (buffer); x >= 1; x--) {
459                 i = x - 1;
460                 if (buffer[i] == ' ' ||
461                                 buffer[i] == '\r' || buffer[i] == '\n' || buffer[i] == '\t')
462                         buffer[i] = '\0';
463                 else
464                         break;
465         }
466         return;
470 /******************************************************************************
471  *
472  * Copies one string to another. Any previously existing data in
473  * the destination string is lost.
474  *
475  * Example:
476  *
477  * char *str=NULL;
478  * str = strscpy("This is a line of text with no trailing newline");
479  *
480  *****************************************************************************/
482 char *
483 strscpy (char *dest, const char *src)
485         if (src == NULL)
486                 return NULL;
488         asprintf (&dest, "%s", src);
490         return dest;
495 /******************************************************************************
496  *
497  * Returns a pointer to the next line of a multiline string buffer
498  *
499  * Given a pointer string, find the text following the next sequence
500  * of \r and \n characters. This has the effect of skipping blank
501  * lines as well
502  *
503  * Example:
504  *
505  * Given text as follows:
506  *
507  * ==============================
508  * This
509  * is
510  * a
511  * 
512  * multiline string buffer
513  * ==============================
514  *
515  * int i=0;
516  * char *str=NULL;
517  * char *ptr=NULL;
518  * str = strscpy(str,"This\nis\r\na\n\nmultiline string buffer\n");
519  * ptr = str;
520  * while (ptr) {
521  *   printf("%d %s",i++,firstword(ptr));
522  *   ptr = strnl(ptr);
523  * }
524  * 
525  * Produces the following:
526  *
527  * 1 This
528  * 2 is
529  * 3 a
530  * 4 multiline
531  *
532  * NOTE: The 'firstword()' function is conceptual only and does not
533  *       exist in this package.
534  *
535  * NOTE: Although the second 'ptr' variable is not strictly needed in
536  *       this example, it is good practice with these utilities. Once
537  *       the * pointer is advance in this manner, it may no longer be
538  *       handled with * realloc(). So at the end of the code fragment
539  *       above, * strscpy(str,"foo") work perfectly fine, but
540  *       strscpy(ptr,"foo") will * cause the the program to crash with
541  *       a segmentation fault.
542  *
543  *****************************************************************************/
545 char *
546 strnl (char *str)
548         size_t len;
549         if (str == NULL)
550                 return NULL;
551         str = strpbrk (str, "\r\n");
552         if (str == NULL)
553                 return NULL;
554         len = strspn (str, "\r\n");
555         if (str[len] == '\0')
556                 return NULL;
557         str += len;
558         if (strlen (str) == 0)
559                 return NULL;
560         return str;
564 /******************************************************************************
565  *
566  * Like strscpy, except only the portion of the source string up to
567  * the provided delimiter is copied.
568  *
569  * Example:
570  *
571  * str = strpcpy(str,"This is a line of text with no trailing newline","x");
572  * printf("%s\n",str);
573  *
574  * Produces:
575  *
576  *This is a line of te
577  *
578  *****************************************************************************/
580 char *
581 strpcpy (char *dest, const char *src, const char *str)
583         size_t len;
585         if (src)
586                 len = strcspn (src, str);
587         else
588                 return NULL;
590         if (dest == NULL || strlen (dest) < len)
591                 dest = realloc (dest, len + 1);
592         if (dest == NULL)
593                 die (STATE_UNKNOWN, _("failed realloc in strpcpy\n"));
595         strncpy (dest, src, len);
596         dest[len] = '\0';
598         return dest;
603 /******************************************************************************
604  *
605  * Like strscat, except only the portion of the source string up to
606  * the provided delimiter is copied.
607  *
608  * str = strpcpy(str,"This is a line of text with no trailing newline","x");
609  * str = strpcat(str,"This is a line of text with no trailing newline","x");
610  * printf("%s\n",str);
611  * 
612  *This is a line of texThis is a line of tex
613  *
614  *****************************************************************************/
616 char *
617 strpcat (char *dest, const char *src, const char *str)
619         size_t len, l2;
621         if (dest)
622                 len = strlen (dest);
623         else
624                 len = 0;
626         if (src) {
627                 l2 = strcspn (src, str);
628         }
629         else {
630                 return dest;
631         }
633         dest = realloc (dest, len + l2 + 1);
634         if (dest == NULL)
635                 die (STATE_UNKNOWN, _("failed malloc in strscat\n"));
637         strncpy (dest + len, src, l2);
638         dest[len + l2] = '\0';
640         return dest;
643 #ifndef HAVE_BASENAME
644 /* function modified from coreutils base_name function - see ACKNOWLEDGEMENTS */
645 char *basename(const char *path) {
646         char const *base = path;
647         char const *p;
648         for (p = base; *p; p++) {
649                 if (*p == '/') {
650                         /* Treat multiple adjacent slashes like single slash */
651                         do p++;
652                         while (*p == '/');
654                         /* If filename ends in slash, use trailing slash
655                            as basename if no non-slashes found */
656                         if (! *p) {
657                                 if (*base == '/')
658                                         base = p - 1;
659                                 break;
660                         }
662                         /* *p is non-slash preceded by slash */
663                         base = p;
664                 }
665         }
666         return (char *) base;
668 #endif
670 /******************************************************************************
671  *
672  * Print perfdata in a standard format
673  *
674  ******************************************************************************/
676 char *perfdata (const char *label,
677  long int val,
678  const char *uom,
679  int warnp,
680  long int warn,
681  int critp,
682  long int crit,
683  int minp,
684  long int minv,
685  int maxp,
686  long int maxv)
688         char *data = NULL;
690         if (strpbrk (label, "'= "))
691                 asprintf (&data, "'%s'=%ld%s;", label, val, uom);
692         else
693                 asprintf (&data, "%s=%ld%s;", label, val, uom);
695         if (warnp)
696                 asprintf (&data, "%s%ld;", data, warn);
697         else
698                 asprintf (&data, "%s;", data);
700         if (critp)
701                 asprintf (&data, "%s%ld;", data, crit);
702         else
703                 asprintf (&data, "%s;", data);
705         if (minp)
706                 asprintf (&data, "%s%ld", data, minv);
708         if (maxp)
709                 asprintf (&data, "%s;%ld", data, maxv);
711         return data;
715 char *fperfdata (const char *label,
716  double val,
717  const char *uom,
718  int warnp,
719  double warn,
720  int critp,
721  double crit,
722  int minp,
723  double minv,
724  int maxp,
725  double maxv)
727         char *data = NULL;
729         if (strpbrk (label, "'= "))
730                 asprintf (&data, "'%s'=", label);
731         else
732                 asprintf (&data, "%s=", label);
734         asprintf (&data, "%s%f", data, val);
735         asprintf (&data, "%s%s;", data, uom);
737         if (warnp)
738                 asprintf (&data, "%s%f", data, warn);
740         asprintf (&data, "%s;", data);
742         if (critp)
743                 asprintf (&data, "%s%f", data, crit);
745         asprintf (&data, "%s;", data);
747         if (minp)
748                 asprintf (&data, "%s%f", data, minv);
750         if (maxp) {
751                 asprintf (&data, "%s;", data);
752                 asprintf (&data, "%s%f", data, maxv);
753         }
755         return data;
758 char *np_escaped_string (const char *string) {
759         char *data;
760         int i, j=0;
761         data = strdup(string);
762         for (i=0; data[i]; i++) {
763                 if (data[i] == '\\') {
764                         switch(data[++i]) {
765                                 case 'n':
766                                         data[j++] = '\n';
767                                         break;
768                                 case 'r':
769                                         data[j++] = '\r';
770                                         break;
771                                 case 't':
772                                         data[j++] = '\t';
773                                         break;
774                                 case '\\':
775                                         data[j++] = '\\';
776                                         break;
777                                 default:
778                                         data[j++] = data[i];
779                         }
780                 } else {
781                         data[j++] = data[i];
782                 }
783         }
784         data[j] = '\0';
785         return data;