Code

6e52dab75e0759c501910d30ba3a16452acad595
[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 #include "config.h"
15 #include "common.h"
16 #include "version.h"
17 #include <stdarg.h>
18 #include <limits.h>
20 extern int timeout_interval;
22 char *my_basename (char *);
23 void support (void);
24 char *clean_revstring (const char *);
25 void print_revision (char *, const char *);
26 void terminate (int, const char *fmt, ...);
27 RETSIGTYPE timeout_alarm_handler (int);
29 int is_host (char *);
30 int is_dotted_quad (char *);
31 int is_hostname (char *);
33 int is_integer (char *);
34 int is_intpos (char *);
35 int is_intneg (char *);
36 int is_intnonneg (char *);
37 int is_intpercent (char *);
39 int is_numeric (char *);
40 int is_positive (char *);
41 int is_negative (char *);
42 int is_nonnegative (char *);
43 int is_percentage (char *);
45 int is_option (char *str);
47 void strip (char *);
48 char *strscpy (char *dest, const char *src);
49 char *strscat (char *dest, const char *src);
50 char *strnl (char *str);
51 char *ssprintf (char *str, const char *fmt, ...);
52 char *strpcpy (char *dest, const char *src, const char *str);
53 char *strpcat (char *dest, const char *src, const char *str);
55 #define LABELLEN 63
56 #define STRLEN 64
57 #define TXTBLK 128
59 #define max(a,b) ((a)>(b))?(a):(b)
61 /* **************************************************************************
62  * max_state(result, STATE_x)
63  * compares STATE_x to result and returns result if STATE_x is less than a based on the following
64  * STATE_UNKNOWN < STATE_OK < STATE_WARNING < STATE_CRITICAL
65  *
66  * Note that numerically the above does not hold
67  ****************************************************************************/
69 int
70 max_state(int a, int b)
71 {
72         if(a == STATE_CRITICAL){
73                 return a;
74         }
75         else if (a == STATE_WARNING) {
77                 if (b == STATE_CRITICAL){
78                         return b;
79                 }else {
80                         return a;
81                 }
82         } 
83         else if (a == STATE_OK) {
84                 
85                 if ( b== STATE_CRITICAL || b == STATE_WARNING) {
86                         return b;
87                 }else{
88                         return a;
89                 }
90         }
91         else {
92                 /* a == UNKNOWN */
93                 return b;
94         }
95                 
97 }
99 char *
100 my_basename (char *path)
102         if (!strstr (path, "/"))
103                 return path;
104         else
105                 return 1 + strrchr (path, '/');
109 void
110 support (void)
112         printf
113                 ("Send email to nagios-users@lists.sourceforge.net if you have questions\n"
114                  "regarding use of this software. To submit patches or suggest improvements,\n"
115                  "send email to nagiosplug-devel@lists.sourceforge.net\n");
119 char *
120 clean_revstring (const char *revstring)
122         char plugin_revision[STRLEN];
123         if (sscanf (revstring,"$Revision: %[0-9.]",plugin_revision) == 1)
124                 return strscpy (NULL, plugin_revision);
125         else
126           return strscpy (NULL, "N/A");
129 void
130 print_revision (char *command_name, const char *revision_string)
132         char plugin_revision[STRLEN];
134         if (sscanf (revision_string, "$Revision: %[0-9.]", plugin_revision) != 1)
135                 strncpy (plugin_revision, "N/A", STRLEN);
136         printf ("%s (nagios-plugins %s) %s\n",
137                                         my_basename (command_name), VERSION, plugin_revision);
138         printf
139                 ("The nagios plugins come with ABSOLUTELY NO WARRANTY. You may redistribute\n"
140                  "copies of the plugins under the terms of the GNU General Public License.\n"
141                  "For more information about these matters, see the file named COPYING.\n");
146 void
147 terminate (int result, const char *fmt, ...)
149         va_list ap;
150         va_start (ap, fmt);
151         vprintf (fmt, ap);
152         va_end (ap);
153         exit (result);
156 void
157 timeout_alarm_handler (int signo)
159         if (signo == SIGALRM) {
160                 printf ("CRITICAL - Plugin timed out after %d seconds\n",
161                                                 timeout_interval);
162                 exit (STATE_CRITICAL);
163         }
166 int
167 is_host (char *address)
169         if (is_dotted_quad (address) || is_hostname (address))
170                 return (TRUE);
171         return (FALSE);
174 int
175 is_dotted_quad (char *address)
177         int o1, o2, o3, o4;
178         char c[1];
180         if (sscanf (address, "%d.%d.%d.%d%c", &o1, &o2, &o3, &o4, c) != 4)
181                 return FALSE;
182         else if (o1 > 255 || o2 > 255 || o3 > 255 || o4 > 255)
183                 return FALSE;
184         else if (o1 < 0 || o2 < 0 || o3 < 0 || o4 < 0)
185                 return FALSE;
186         else
187                 return TRUE;
190 /* from RFC-1035
191  * 
192  * The labels must follow the rules for ARPANET host names.  They must
193  * start with a letter, end with a letter or digit, and have as interior
194  * characters only letters, digits, and hyphen.  There are also some
195  * restrictions on the length.  Labels must be 63 characters or less. */
197 int
198 is_hostname (char *s1)
200         if (strlen (s1) > 63)
201                 return FALSE;
202         if (strcspn
203                         (s1,
204                          "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUWVXYZ0123456789-.") !=
205                         0) return FALSE;
206         if (strspn (s1, "0123456789-.") == 1)
207                 return FALSE;
208         while ((s1 = index (s1, '.'))) {
209                 s1++;
210                 if (strspn (s1, "0123456789-.") == 1) {
211                         printf ("%s\n", s1);
212                         return FALSE;
213                 }
214         }
215         return TRUE;
218 int
219 is_numeric (char *number)
221         char tmp[1];
222         float x;
223         if (sscanf (number, "%f%c", &x, tmp) == 1)
224                 return (TRUE);
225         return (FALSE);
228 int
229 is_positive (char *number)
231         if (is_numeric (number) && atof (number) > 0.0)
232                 return (TRUE);
233         return (FALSE);
236 int
237 is_negative (char *number)
239         if (is_numeric (number) && atof (number) < 0.0)
240                 return (TRUE);
241         return (FALSE);
244 int
245 is_nonnegative (char *number)
247         if (is_numeric (number) && atof (number) >= 0.0)
248                 return (TRUE);
249         return (FALSE);
252 int
253 is_percentage (char *number)
255         int x;
256         if (is_numeric (number) && (x = atof (number)) >= 0 && x <= 100)
257                 return (TRUE);
258         return (FALSE);
261 int
262 is_integer (char *number)
264         long int n;
266         if (strspn (number, "-0123456789 ") != strlen (number))
267                 return (FALSE);
269         n = strtol (number, NULL, 10);
270         if (errno != ERANGE && n >= INT_MIN && n <= INT_MAX)
271                 return (TRUE);
272         return (FALSE);
275 int
276 is_intpos (char *number)
278         if (is_integer (number) && atoi (number) > 0)
279                 return (TRUE);
280         return (FALSE);
283 int
284 is_intneg (char *number)
286         if (is_integer (number) && atoi (number) < 0)
287                 return (TRUE);
288         return (FALSE);
291 int
292 is_intnonneg (char *number)
294         if (is_integer (number) && atoi (number) >= 0)
295                 return (TRUE);
296         return (FALSE);
299 int
300 is_intpercent (char *number)
302         int i;
303         if (is_integer (number) && (i = atoi (number)) >= 0 && i <= 100)
304                 return (TRUE);
305         return (FALSE);
308 int
309 is_option (char *str)
311         if (strspn (str, "-") == 1 || strspn (str, "-") == 2)
312                 return TRUE;
313         return FALSE;
319 double
320 delta_time (struct timeval *tv)
322         struct timeval *pt;
323         struct timezone *tz;
325         gettimeofday (pt, tz);
327         return (pt->tv_sec - tv->tv_sec + (pt->tv_usec - tv->tv_usec) / 1000000);
333 void
334 strip (char *buffer)
336         size_t x;
337         int i;
339         for (x = strlen (buffer); x >= 1; x--) {
340                 i = x - 1;
341                 if (buffer[i] == ' ' ||
342                                 buffer[i] == '\r' || buffer[i] == '\n' || buffer[i] == '\t')
343                         buffer[i] = '\0';
344                 else
345                         break;
346         }
347         return;
354 /******************************************************************************
355  *
356  * Copies one string to another
357  *
358  * Given a pointer destination string, which may or may not already
359  * hold some text, and a source string with additional text (possibly
360  * NULL or empty), returns a pointer to a a copy of the source
361  * string. Uses realloc to free memory held by the dest argument if
362  * new storage space is required, and any previously existing data in
363  * the destination string is lost.
364  *
365  * Example:
366  *
367  * char *str=NULL;
368  * str = strscpy("This is a line of text with no trailing newline");
369  *
370  *****************************************************************************/
372 char *
373 strscpy (char *dest, const char *src)
375         size_t len;
377         if (src == NULL)
378                 return dest;
380         len = strlen (src) + 1;
381         if (dest == NULL)
382                 dest = malloc (len);
383         else if (strlen (dest) < len)
384                 dest = realloc (dest, len);
385         if (dest == NULL)
386                 terminate (STATE_UNKNOWN, "failed realloc in strscpy\n");
388         strncpy (dest, src, len);
390         return dest;
397 /******************************************************************************
398  *
399  * Concatenates one string to the end of another
400  *
401  * Given a pointer destination string, which may or may not already
402  * hold some text, and a source string with additional text (possibly
403  * NULL or empty), returns a pointer to a string that is the first
404  * string with the second concatenated to it. Uses realloc to free 
405  * memory held by the dest argument if new storage space is required.
406  *
407  * Example:
408  *
409  * char *str=NULL;
410  * str = strscpy("This is a line of text with no trailing newline");
411  * str = strscat(str,"\n");
412  *
413  *****************************************************************************/
415 char *
416 strscat (char *dest, const char *src)
418         size_t len, l2;
420         if (src == NULL)
421                 return dest;
422         else
423                 l2 = strlen (src);
425         if (dest == NULL) {
426                 len = 0;
427                 dest = malloc (l2 + 1);
428         } else {
429                 len = strlen (dest);
430                 dest = realloc (dest, len + l2 + 1);
431         }
433         if (dest == NULL)
434                 terminate (STATE_UNKNOWN, "failed malloc in strscat\n");
436         strncpy (dest + len, src, l2);
437         dest[len + l2] = '\0';
439         return dest;
446 /******************************************************************************
447  *
448  * Returns a pointer to the next line of a multiline string buffer
449  *
450  * Given a pointer string, find the text following the next sequence
451  * of \r and \n characters. This has the effect of skipping blank
452  * lines as well
453  *
454  * Example:
455  *
456  * Given text as follows:
457  *
458  * ==============================
459  * This
460  * is
461  * a
462  * 
463  * multiline string buffer
464  * ==============================
465  *
466  * int i=0;
467  * char *str=NULL;
468  * char *ptr=NULL;
469  * str = strscpy(str,"This\nis\r\na\n\nmultiline string buffer\n");
470  * ptr = str;
471  * while (ptr) {
472  *   printf("%d %s",i++,firstword(ptr));
473  *   ptr = strnl(ptr);
474  * }
475  * 
476  * Produces the following:
477  *
478  * 1 This
479  * 2 is
480  * 3 a
481  * 4 multiline
482  *
483  * NOTE: The 'firstword()' function is conceptual only and does not
484  *       exist in this package.
485  *
486  * NOTE: Although the second 'ptr' variable is not strictly needed in
487  *       this example, it is good practice with these utilities. Once
488  *       the * pointer is advance in this manner, it may no longer be
489  *       handled with * realloc(). So at the end of the code fragment
490  *       above, * strscpy(str,"foo") work perfectly fine, but
491  *       strscpy(ptr,"foo") will * cause the the program to crash with
492  *       a segmentation fault.
493  *
494  *****************************************************************************/
496 char *
497 strnl (char *str)
499         size_t len;
500         if (str == NULL)
501                 return NULL;
502         str = strpbrk (str, "\r\n");
503         if (str == NULL)
504                 return NULL;
505         len = strspn (str, "\r\n");
506         if (str[len] == '\0')
507                 return NULL;
508         str += len;
509         if (strlen (str) == 0)
510                 return NULL;
511         return str;
518 /******************************************************************************
519  *
520  * Does a formatted print to a string variable
521  *
522  * Given a pointer destination string, which may or may not already
523  * hold some text, and a source string with additional text (possibly
524  * NULL or empty), returns a pointer to a string that cntains the
525  * results of the specified formatted print
526  *
527  * Example:
528  *
529  * char *str=NULL;
530  * str = ssprintf(str,"%d %s",1,"string");
531  *
532  *****************************************************************************/
534 char *
535 ssprintf (char *ptr, const char *fmt, ...)
537         va_list ap;
538         int nchars;
539         size_t size;
540         char *str = NULL;
542         if (str == NULL) {
543                 str = malloc (TXTBLK);
544                 if (str == NULL)
545                         terminate (STATE_UNKNOWN, "malloc failed in ssprintf");
546                 size = TXTBLK;
547         }
548         else
549                 size = max (strlen (str), TXTBLK);
551         va_start (ap, fmt);
553         while (1) {
555                 nchars = vsnprintf (str, size, fmt, ap);
557                 if (nchars > -1)
558                         if (nchars < (int) size) {
559                                 va_end (ap);
560                                 str[nchars] = '\0';
561                                 if (ptr)
562                                         free (ptr);
563                                 return str;
564                         }
565                         else {
566                                 size = (size_t) (nchars + 1);
567                         }
569                 else
570                         size *= 2;
572                 str = realloc (str, size);
574                 if (str == NULL)
575                         terminate (STATE_UNKNOWN, "realloc failed in ssprintf");
576         }
584 /******************************************************************************
585  *
586  * Like strscpy, except only the portion of the source string up to
587  * the provided delimiter is copied.
588  *
589  * Example:
590  *
591  * str = strpcpy(str,"This is a line of text with no trailing newline","x");
592  * printf("%s\n",str);
593  *
594  * Produces:
595  *
596  *This is a line of te
597  *
598  *****************************************************************************/
600 char *
601 strpcpy (char *dest, const char *src, const char *str)
603         size_t len;
605         if (src)
606                 len = strcspn (src, str);
607         else
608                 return NULL;
610         if (dest == NULL || strlen (dest) < len)
611                 dest = realloc (dest, len + 1);
612         if (dest == NULL)
613                 terminate (STATE_UNKNOWN, "failed realloc in strpcpy\n");
615         strncpy (dest, src, len);
616         dest[len] = '\0';
618         return dest;
625 /******************************************************************************
626  *
627  * Like strscat, except only the portion of the source string up to
628  * the provided delimiter is copied.
629  *
630  * str = strpcpy(str,"This is a line of text with no trailing newline","x");
631  * str = strpcat(str,"This is a line of text with no trailing newline","x");
632  * printf("%s\n",str);
633  * 
634  *This is a line of texThis is a line of tex
635  *
636  *****************************************************************************/
638 char *
639 strpcat (char *dest, const char *src, const char *str)
641         size_t len, l2;
643         if (dest)
644                 len = strlen (dest);
645         else
646                 len = 0;
648         if (src) {
649                 l2 = strcspn (src, str);
650         }
651         else {
652                 return dest;
653         }
655         dest = realloc (dest, len + l2 + 1);
656         if (dest == NULL)
657                 terminate (STATE_UNKNOWN, "failed malloc in strscat\n");
659         strncpy (dest + len, src, l2);
660         dest[len + l2] = '\0';
662         return dest;