Code

Clearly defined thresholds & ranges in docs. Added get_status routine. Added
[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  * License: GPL
9  *
10  * $Revision$
11  * $Date$
12  ****************************************************************************/
14 #define LOCAL_TIMEOUT_ALARM_HANDLER
16 #include "common.h"
17 #include "utils.h"
18 #include <stdarg.h>
19 #include <limits.h>
21 #include <arpa/inet.h>
23 extern void print_usage (void);
24 extern const char *progname;
26 #define STRLEN 64
27 #define TXTBLK 128
29 /* **************************************************************************
30  * max_state(STATE_x, STATE_y)
31  * compares STATE_x to  STATE_y and returns result based on the following
32  * STATE_UNKNOWN < STATE_OK < STATE_WARNING < STATE_CRITICAL
33  *
34  * Note that numerically the above does not hold
35  ****************************************************************************/
37 int
38 max_state (int a, int b)
39 {
40         if (a == STATE_CRITICAL || b == STATE_CRITICAL)
41                 return STATE_CRITICAL;
42         else if (a == STATE_WARNING || b == STATE_WARNING)
43                 return STATE_WARNING;
44         else if (a == STATE_OK || b == STATE_OK)
45                 return STATE_OK;
46         else if (a == STATE_UNKNOWN || b == STATE_UNKNOWN)
47                 return STATE_UNKNOWN;
48         else if (a == STATE_DEPENDENT || b == STATE_DEPENDENT)
49                 return STATE_DEPENDENT;
50         else
51                 return max (a, b);
52 }
54 void usage (const char *msg)
55 {
56         printf ("%s\n", msg);
57         print_usage ();
58         exit (STATE_UNKNOWN);
59 }
61 void usage_va (const char *fmt, ...)
62 {
63         va_list ap;
64         printf("%s: ", progname);
65         va_start(ap, fmt);
66         vprintf(fmt, ap);
67         va_end(ap);
68         printf("\n");
69         exit (STATE_UNKNOWN);
70 }
72 void usage2(const char *msg, const char *arg)
73 {
74         printf ("%s: %s - %s\n",progname,msg,arg);
75         print_usage ();
76         exit (STATE_UNKNOWN);
77 }
79 void
80 usage3 (const char *msg, int arg)
81 {
82         printf ("%s: %s - %c\n", progname, msg, arg);
83         print_usage();
84         exit (STATE_UNKNOWN);
85 }
87 void
88 usage4 (const char *msg)
89 {
90         printf ("%s: %s\n", progname, msg);
91         print_usage();
92         exit (STATE_UNKNOWN);
93 }
95 char *
96 clean_revstring (const char *revstring)
97 {
98         char plugin_revision[STRLEN];
99         if (sscanf (revstring,"$Revision: %[0-9.]",plugin_revision) == 1)
100                 return strscpy (NULL, plugin_revision);
101         else
102           return strscpy (NULL, "N/A");
105 void
106 print_revision (const char *command_name, const char *revision_string)
108         char plugin_revision[STRLEN];
110         if (sscanf (revision_string, "$Revision: %[0-9.]", plugin_revision) != 1)
111                 strncpy (plugin_revision, "N/A", STRLEN);
112         printf ("%s (%s %s) %s\n",
113                                         command_name, PACKAGE, VERSION, plugin_revision);
116 const char *
117 state_text (int result)
119         switch (result) {
120         case STATE_OK:
121                 return "OK";
122         case STATE_WARNING:
123                 return "WARNING";
124         case STATE_CRITICAL:
125                 return "CRITICAL";
126         case STATE_DEPENDENT:
127                 return "DEPENDENT";
128         default:
129                 return "UNKNOWN";
130         }
133 void
134 die (int result, const char *fmt, ...)
136         va_list ap;
137         va_start (ap, fmt);
138         vprintf (fmt, ap);
139         va_end (ap);
140         exit (result);
143 void
144 timeout_alarm_handler (int signo)
146         if (signo == SIGALRM) {
147                 printf (_("CRITICAL - Plugin timed out after %d seconds\n"),
148                                                 timeout_interval);
149                 exit (STATE_CRITICAL);
150         }
153 int
154 is_numeric (char *number)
156         char tmp[1];
157         float x;
159         if (!number)
160                 return FALSE;
161         else if (sscanf (number, "%f%c", &x, tmp) == 1)
162                 return TRUE;
163         else
164                 return FALSE;
167 int
168 is_positive (char *number)
170         if (is_numeric (number) && atof (number) > 0.0)
171                 return TRUE;
172         else
173                 return FALSE;
176 int
177 is_negative (char *number)
179         if (is_numeric (number) && atof (number) < 0.0)
180                 return TRUE;
181         else
182                 return FALSE;
185 int
186 is_nonnegative (char *number)
188         if (is_numeric (number) && atof (number) >= 0.0)
189                 return TRUE;
190         else
191                 return FALSE;
194 int
195 is_percentage (char *number)
197         int x;
198         if (is_numeric (number) && (x = atof (number)) >= 0 && x <= 100)
199                 return TRUE;
200         else
201                 return FALSE;
204 int
205 is_integer (char *number)
207         long int n;
209         if (!number || (strspn (number, "-0123456789 ") != strlen (number)))
210                 return FALSE;
212         n = strtol (number, NULL, 10);
214         if (errno != ERANGE && n >= INT_MIN && n <= INT_MAX)
215                 return TRUE;
216         else
217                 return FALSE;
220 int
221 is_intpos (char *number)
223         if (is_integer (number) && atoi (number) > 0)
224                 return TRUE;
225         else
226                 return FALSE;
229 int
230 is_intneg (char *number)
232         if (is_integer (number) && atoi (number) < 0)
233                 return TRUE;
234         else
235                 return FALSE;
238 int
239 is_intnonneg (char *number)
241         if (is_integer (number) && atoi (number) >= 0)
242                 return TRUE;
243         else
244                 return FALSE;
247 int
248 is_intpercent (char *number)
250         int i;
251         if (is_integer (number) && (i = atoi (number)) >= 0 && i <= 100)
252                 return TRUE;
253         else
254                 return FALSE;
257 int
258 is_option (char *str)
260         if (!str)
261                 return FALSE;
262         else if (strspn (str, "-") == 1 || strspn (str, "-") == 2)
263                 return TRUE;
264         else
265                 return FALSE;
268 void set_range_start (range *this, double value) {
269         this->start = value;
270         this->start_infinity = FALSE;
273 void set_range_end (range *this, double value) {
274         this->end = value;
275         this->end_infinity = FALSE;
278 range
279 *parse_range_string (char *str) {
280         range *temp_range;
281         double start;
282         double end;
283         char *end_str;
285         temp_range = (range *) malloc(sizeof(range));
287         /* Set defaults */
288         temp_range->start = 0;
289         temp_range->start_infinity = FALSE;
290         temp_range->end = 0;
291         temp_range->end_infinity = TRUE;
292         temp_range->alert_on = OUTSIDE;
294         if (str[0] == '@') {
295                 temp_range->alert_on = INSIDE;
296                 str++;
297         }
299         end_str = index(str, ':');
300         if (end_str != NULL) {
301                 if (str[0] == '~') {
302                         temp_range->start_infinity = TRUE;
303                 } else {
304                         start = strtod(str, NULL);      /* Will stop at the ':' */
305                         set_range_start(temp_range, start);
306                 }
307                 end_str++;              /* Move past the ':' */
308         } else {
309                 end_str = str;
310         }
311         end = strtod(end_str, NULL);
312         if (strcmp(end_str, "") != 0) {
313                 set_range_end(temp_range, end);
314         }
316         if (temp_range->start_infinity == TRUE || 
317                 temp_range->end_infinity == TRUE ||
318                 temp_range->start <= temp_range->end) {
319                 return temp_range;
320         }
321         free(temp_range);
322         return NULL;
325 /* returns 0 if okay, otherwise 1 */
326 int
327 _set_thresholds(thresholds **my_thresholds, char *warn_string, char *critical_string)
329         thresholds *temp_thresholds = NULL;
331         temp_thresholds = malloc(sizeof(temp_thresholds));
333         temp_thresholds->warning = NULL;
334         temp_thresholds->critical = NULL;
336         if (warn_string != NULL) {
337                 if ((temp_thresholds->warning = parse_range_string(warn_string)) == NULL) {
338                         return 1;
339                 }
340         }
341         if (critical_string != NULL) {
342                 if ((temp_thresholds->critical = parse_range_string(critical_string)) == NULL) {
343                         return 1;
344                 }
345         }
347         if (*my_thresholds != 0) {
348                 /* printf("Freeing here: %d\n", *my_thresholds); */
349                 free(*my_thresholds);
350         }
351         *my_thresholds = temp_thresholds;
353         return 0;
356 void
357 set_thresholds(thresholds **my_thresholds, char *warn_string, char *critical_string)
359         if (_set_thresholds(my_thresholds, warn_string, critical_string) == 0) {
360                 return;
361         } else {
362                 usage("Range format incorrect");
363         }
366 /* Returns TRUE if alert should be raised based on the range */
367 int
368 check_range(double value, range *my_range)
370         int false = FALSE;
371         int true = TRUE;
372         
373         if (my_range->alert_on == INSIDE) {
374                 false = TRUE;
375                 true = FALSE;
376         }
378         if (my_range->end_infinity == FALSE && my_range->start_infinity == FALSE) {
379                 if ((my_range->start <= value) && (value <= my_range->end)) {
380                         return false;
381                 } else {
382                         return true;
383                 }
384         } else if (my_range->start_infinity == FALSE && my_range->end_infinity == TRUE) {
385                 if (my_range->start <= value) {
386                         return false;
387                 } else {
388                         return true;
389                 }
390         } else if (my_range->start_infinity == TRUE && my_range->end_infinity == FALSE) {
391                 if (value <= my_range->end) {
392                         return false;
393                 } else {
394                         return true;
395                 }
396         } else {
397                 return false;
398         }
401 /* Returns status */
402 int
403 get_status(double value, thresholds *my_thresholds)
405         if (my_thresholds->critical != NULL) {
406                 if (check_range(value, my_thresholds->critical) == TRUE) {
407                         return STATE_CRITICAL;
408                 }
409         }
410         if (my_thresholds->warning != NULL) {
411                 if (check_range(value, my_thresholds->warning) == TRUE) {
412                         return STATE_WARNING;
413                 }
414         }
415         return STATE_OK;
418 #ifdef NEED_GETTIMEOFDAY
419 int
420 gettimeofday (struct timeval *tv, struct timezone *tz)
422         tv->tv_usec = 0;
423         tv->tv_sec = (long) time ((time_t) 0);
425 #endif
429 double
430 delta_time (struct timeval tv)
432         struct timeval now;
434         gettimeofday (&now, NULL);
435         return ((double)(now.tv_sec - tv.tv_sec) + (double)(now.tv_usec - tv.tv_usec) / (double)1000000);
440 long
441 deltime (struct timeval tv)
443         struct timeval now;
444         gettimeofday (&now, NULL);
445         return (now.tv_sec - tv.tv_sec)*1000000 + now.tv_usec - tv.tv_usec;
451 void
452 strip (char *buffer)
454         size_t x;
455         int i;
457         for (x = strlen (buffer); x >= 1; x--) {
458                 i = x - 1;
459                 if (buffer[i] == ' ' ||
460                                 buffer[i] == '\r' || buffer[i] == '\n' || buffer[i] == '\t')
461                         buffer[i] = '\0';
462                 else
463                         break;
464         }
465         return;
469 /******************************************************************************
470  *
471  * Copies one string to another. Any previously existing data in
472  * the destination string is lost.
473  *
474  * Example:
475  *
476  * char *str=NULL;
477  * str = strscpy("This is a line of text with no trailing newline");
478  *
479  *****************************************************************************/
481 char *
482 strscpy (char *dest, const char *src)
484         if (src == NULL)
485                 return NULL;
487         asprintf (&dest, "%s", src);
489         return dest;
494 /******************************************************************************
495  *
496  * Returns a pointer to the next line of a multiline string buffer
497  *
498  * Given a pointer string, find the text following the next sequence
499  * of \r and \n characters. This has the effect of skipping blank
500  * lines as well
501  *
502  * Example:
503  *
504  * Given text as follows:
505  *
506  * ==============================
507  * This
508  * is
509  * a
510  * 
511  * multiline string buffer
512  * ==============================
513  *
514  * int i=0;
515  * char *str=NULL;
516  * char *ptr=NULL;
517  * str = strscpy(str,"This\nis\r\na\n\nmultiline string buffer\n");
518  * ptr = str;
519  * while (ptr) {
520  *   printf("%d %s",i++,firstword(ptr));
521  *   ptr = strnl(ptr);
522  * }
523  * 
524  * Produces the following:
525  *
526  * 1 This
527  * 2 is
528  * 3 a
529  * 4 multiline
530  *
531  * NOTE: The 'firstword()' function is conceptual only and does not
532  *       exist in this package.
533  *
534  * NOTE: Although the second 'ptr' variable is not strictly needed in
535  *       this example, it is good practice with these utilities. Once
536  *       the * pointer is advance in this manner, it may no longer be
537  *       handled with * realloc(). So at the end of the code fragment
538  *       above, * strscpy(str,"foo") work perfectly fine, but
539  *       strscpy(ptr,"foo") will * cause the the program to crash with
540  *       a segmentation fault.
541  *
542  *****************************************************************************/
544 char *
545 strnl (char *str)
547         size_t len;
548         if (str == NULL)
549                 return NULL;
550         str = strpbrk (str, "\r\n");
551         if (str == NULL)
552                 return NULL;
553         len = strspn (str, "\r\n");
554         if (str[len] == '\0')
555                 return NULL;
556         str += len;
557         if (strlen (str) == 0)
558                 return NULL;
559         return str;
563 /******************************************************************************
564  *
565  * Like strscpy, except only the portion of the source string up to
566  * the provided delimiter is copied.
567  *
568  * Example:
569  *
570  * str = strpcpy(str,"This is a line of text with no trailing newline","x");
571  * printf("%s\n",str);
572  *
573  * Produces:
574  *
575  *This is a line of te
576  *
577  *****************************************************************************/
579 char *
580 strpcpy (char *dest, const char *src, const char *str)
582         size_t len;
584         if (src)
585                 len = strcspn (src, str);
586         else
587                 return NULL;
589         if (dest == NULL || strlen (dest) < len)
590                 dest = realloc (dest, len + 1);
591         if (dest == NULL)
592                 die (STATE_UNKNOWN, _("failed realloc in strpcpy\n"));
594         strncpy (dest, src, len);
595         dest[len] = '\0';
597         return dest;
602 /******************************************************************************
603  *
604  * Like strscat, except only the portion of the source string up to
605  * the provided delimiter is copied.
606  *
607  * str = strpcpy(str,"This is a line of text with no trailing newline","x");
608  * str = strpcat(str,"This is a line of text with no trailing newline","x");
609  * printf("%s\n",str);
610  * 
611  *This is a line of texThis is a line of tex
612  *
613  *****************************************************************************/
615 char *
616 strpcat (char *dest, const char *src, const char *str)
618         size_t len, l2;
620         if (dest)
621                 len = strlen (dest);
622         else
623                 len = 0;
625         if (src) {
626                 l2 = strcspn (src, str);
627         }
628         else {
629                 return dest;
630         }
632         dest = realloc (dest, len + l2 + 1);
633         if (dest == NULL)
634                 die (STATE_UNKNOWN, _("failed malloc in strscat\n"));
636         strncpy (dest + len, src, l2);
637         dest[len + l2] = '\0';
639         return dest;
643 /******************************************************************************
644  *
645  * Print perfdata in a standard format
646  *
647  ******************************************************************************/
649 char *perfdata (const char *label,
650  long int val,
651  const char *uom,
652  int warnp,
653  long int warn,
654  int critp,
655  long int crit,
656  int minp,
657  long int minv,
658  int maxp,
659  long int maxv)
661         char *data = NULL;
663         if (strpbrk (label, "'= "))
664                 asprintf (&data, "'%s'=%ld%s;", label, val, uom);
665         else
666                 asprintf (&data, "%s=%ld%s;", label, val, uom);
668         if (warnp)
669                 asprintf (&data, "%s%ld;", data, warn);
670         else
671                 asprintf (&data, "%s;", data);
673         if (critp)
674                 asprintf (&data, "%s%ld;", data, crit);
675         else
676                 asprintf (&data, "%s;", data);
678         if (minp)
679                 asprintf (&data, "%s%ld", data, minv);
681         if (maxp)
682                 asprintf (&data, "%s;%ld", data, maxv);
684         return data;
688 char *fperfdata (const char *label,
689  double val,
690  const char *uom,
691  int warnp,
692  double warn,
693  int critp,
694  double crit,
695  int minp,
696  double minv,
697  int maxp,
698  double maxv)
700         char *data = NULL;
702         if (strpbrk (label, "'= "))
703                 asprintf (&data, "'%s'=", label);
704         else
705                 asprintf (&data, "%s=", label);
707         asprintf (&data, "%s%f", data, val);
708         asprintf (&data, "%s%s;", data, uom);
710         if (warnp)
711                 asprintf (&data, "%s%f", data, warn);
713         asprintf (&data, "%s;", data);
715         if (critp)
716                 asprintf (&data, "%s%f", data, crit);
718         asprintf (&data, "%s;", data);
720         if (minp)
721                 asprintf (&data, "%s%f", data, minv);
723         if (maxp) {
724                 asprintf (&data, "%s;", data);
725                 asprintf (&data, "%s%f", data, maxv);
726         }
728         return data;