Code

protect against some null strings, make formats more uniform
[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 double delta_time (struct timeval tv);
49 void strip (char *);
50 char *strscpy (char *dest, const char *src);
51 char *strscat (char *dest, char *src);
52 char *strnl (char *str);
53 char *strpcpy (char *dest, const char *src, const char *str);
54 char *strpcat (char *dest, const char *src, const char *str);
56 #define LABELLEN 63
57 #define STRLEN 64
58 #define TXTBLK 128
60 #define max(a,b) ((a)>(b))?(a):(b)
62 /* **************************************************************************
63  * max_state(STATE_x, STATE_y)
64  * compares STATE_x to  STATE_y and returns result based on the following
65  * STATE_UNKNOWN < STATE_OK < STATE_WARNING < STATE_CRITICAL
66  *
67  * Note that numerically the above does not hold
68  ****************************************************************************/
70 int
71 max_state(int a, int b)
72 {
73         if (a == STATE_CRITICAL || b == STATE_CRITICAL)
74                 return STATE_CRITICAL;
75         else if (a == STATE_WARNING || b == STATE_WARNING)
76                 return STATE_WARNING;
77         else if (a == STATE_OK || b == STATE_OK)
78                 return STATE_OK;
79         else if (a == STATE_UNKNOWN || b == STATE_UNKNOWN)
80                 return STATE_UNKNOWN;
81         else if (a == STATE_DEPENDENT || b == STATE_DEPENDENT)
82                 return STATE_DEPENDENT;
83         else
84                 return max (a, b);
85 }
87 char *
88 my_basename (char *path)
89 {
90         if (!strstr (path, "/"))
91                 return path;
92         else
93                 return 1 + strrchr (path, '/');
94 }
97 void
98 support (void)
99 {
100         printf
101                 ("Send email to nagios-users@lists.sourceforge.net if you have questions\n"
102                  "regarding use of this software. To submit patches or suggest improvements,\n"
103                  "send email to nagiosplug-devel@lists.sourceforge.net\n");
107 char *
108 clean_revstring (const char *revstring)
110         char plugin_revision[STRLEN];
111         if (sscanf (revstring,"$Revision: %[0-9.]",plugin_revision) == 1)
112                 return strscpy (NULL, plugin_revision);
113         else
114           return strscpy (NULL, "N/A");
117 void
118 print_revision (char *command_name, const char *revision_string)
120         char plugin_revision[STRLEN];
122         if (sscanf (revision_string, "$Revision: %[0-9.]", plugin_revision) != 1)
123                 strncpy (plugin_revision, "N/A", STRLEN);
124         printf ("%s (nagios-plugins %s) %s\n",
125                                         my_basename (command_name), VERSION, plugin_revision);
126         printf
127                 ("The nagios plugins come with ABSOLUTELY NO WARRANTY. You may redistribute\n"
128                  "copies of the plugins under the terms of the GNU General Public License.\n"
129                  "For more information about these matters, see the file named COPYING.\n");
134 void
135 terminate (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_host (char *address)
157         if (is_dotted_quad (address) || is_hostname (address))
158                 return (TRUE);
159         return (FALSE);
162 int
163 is_dotted_quad (char *address)
165         int o1, o2, o3, o4;
166         char c[1];
168         if (!address)
169                 return FALSE;
171         if (sscanf (address, "%d.%d.%d.%d%c", &o1, &o2, &o3, &o4, c) != 4)
172                 return FALSE;
173         else if (o1 > 255 || o2 > 255 || o3 > 255 || o4 > 255)
174                 return FALSE;
175         else if (o1 < 0 || o2 < 0 || o3 < 0 || o4 < 0)
176                 return FALSE;
177         else
178                 return TRUE;
181 /* from RFC-1035
182  * 
183  * The labels must follow the rules for ARPANET host names.  They must
184  * start with a letter, end with a letter or digit, and have as interior
185  * characters only letters, digits, and hyphen.  There are also some
186  * restrictions on the length.  Labels must be 63 characters or less. */
188 int
189 is_hostname (char *s1)
191         if (!s1 || strlen (s1) > 63) {
192                 return FALSE;
193         }
194         if (strcspn (s1, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUWVXYZ0123456789-.") != 0) {
195                 return FALSE;
196         }
197         if (strspn (s1, "0123456789-.") == 1) {
198                 return FALSE;
199         }
200         while ((s1 = index (s1, '.'))) {
201                 s1++;
202                 if (strspn (s1, "0123456789-.") == 1) {
203                         return FALSE;
204                 }
205         }
206         return TRUE;
209 int
210 is_numeric (char *number)
212         char tmp[1];
213         float x;
215         if (!number)
216                 return FALSE;
217         else if (sscanf (number, "%f%c", &x, tmp) == 1)
218                 return TRUE;
219         else
220                 return FALSE;
223 int
224 is_positive (char *number)
226         if (is_numeric (number) && atof (number) > 0.0)
227                 return TRUE;
228         else
229                 return FALSE;
232 int
233 is_negative (char *number)
235         if (is_numeric (number) && atof (number) < 0.0)
236                 return TRUE;
237         else
238                 return FALSE;
241 int
242 is_nonnegative (char *number)
244         if (is_numeric (number) && atof (number) >= 0.0)
245                 return TRUE;
246         else
247                 return FALSE;
250 int
251 is_percentage (char *number)
253         int x;
254         if (is_numeric (number) && (x = atof (number)) >= 0 && x <= 100)
255                 return TRUE;
256         else
257                 return FALSE;
260 int
261 is_integer (char *number)
263         long int n;
265         if (!number || (strspn (number, "-0123456789 ") != strlen (number)))
266                 return FALSE;
268         n = strtol (number, NULL, 10);
270         if (errno != ERANGE && n >= INT_MIN && n <= INT_MAX)
271                 return TRUE;
272         else
273                 return FALSE;
276 int
277 is_intpos (char *number)
279         if (is_integer (number) && atoi (number) > 0)
280                 return TRUE;
281         else
282                 return FALSE;
285 int
286 is_intneg (char *number)
288         if (is_integer (number) && atoi (number) < 0)
289                 return TRUE;
290         else
291                 return FALSE;
294 int
295 is_intnonneg (char *number)
297         if (is_integer (number) && atoi (number) >= 0)
298                 return TRUE;
299         else
300                 return FALSE;
303 int
304 is_intpercent (char *number)
306         int i;
307         if (is_integer (number) && (i = atoi (number)) >= 0 && i <= 100)
308                 return TRUE;
309         else
310                 return FALSE;
313 int
314 is_option (char *str)
316         if (!str)
317                 return FALSE;
318         else if (strspn (str, "-") == 1 || strspn (str, "-") == 2)
319                 return TRUE;
320         else
321                 return FALSE;
326 #ifdef NEED_GETTIMEOFDAY
327 int
328 gettimeofday (struct timeval *tv, struct timezone *tz)
330         tv->tv_usec = 0;
331         tv->tv_sec = (long) time ((time_t) 0);
333 #endif
337 double
338 delta_time (struct timeval tv)
340         struct timeval now;
342         gettimeofday (&now, NULL);
343         return ((double)(now.tv_sec - tv.tv_sec) + (double)(now.tv_usec - tv.tv_usec) / (double)1000000);
349 void
350 strip (char *buffer)
352         size_t x;
353         int i;
355         for (x = strlen (buffer); x >= 1; x--) {
356                 i = x - 1;
357                 if (buffer[i] == ' ' ||
358                                 buffer[i] == '\r' || buffer[i] == '\n' || buffer[i] == '\t')
359                         buffer[i] = '\0';
360                 else
361                         break;
362         }
363         return;
370 /******************************************************************************
371  *
372  * Copies one string to another. Any previously existing data in
373  * the destination string is lost.
374  *
375  * Example:
376  *
377  * char *str=NULL;
378  * str = strscpy("This is a line of text with no trailing newline");
379  *
380  *****************************************************************************/
382 char *
383 strscpy (char *dest, const char *src)
385         if (src == NULL)
386                 return NULL;
388         asprintf (&dest, "%s", src);
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, char *src)
419         if (dest == NULL)
420                 return src;
421         if (src != NULL)
422                 asprintf (&dest, "%s%s", dest, src);
424         return dest;
431 /******************************************************************************
432  *
433  * Returns a pointer to the next line of a multiline string buffer
434  *
435  * Given a pointer string, find the text following the next sequence
436  * of \r and \n characters. This has the effect of skipping blank
437  * lines as well
438  *
439  * Example:
440  *
441  * Given text as follows:
442  *
443  * ==============================
444  * This
445  * is
446  * a
447  * 
448  * multiline string buffer
449  * ==============================
450  *
451  * int i=0;
452  * char *str=NULL;
453  * char *ptr=NULL;
454  * str = strscpy(str,"This\nis\r\na\n\nmultiline string buffer\n");
455  * ptr = str;
456  * while (ptr) {
457  *   printf("%d %s",i++,firstword(ptr));
458  *   ptr = strnl(ptr);
459  * }
460  * 
461  * Produces the following:
462  *
463  * 1 This
464  * 2 is
465  * 3 a
466  * 4 multiline
467  *
468  * NOTE: The 'firstword()' function is conceptual only and does not
469  *       exist in this package.
470  *
471  * NOTE: Although the second 'ptr' variable is not strictly needed in
472  *       this example, it is good practice with these utilities. Once
473  *       the * pointer is advance in this manner, it may no longer be
474  *       handled with * realloc(). So at the end of the code fragment
475  *       above, * strscpy(str,"foo") work perfectly fine, but
476  *       strscpy(ptr,"foo") will * cause the the program to crash with
477  *       a segmentation fault.
478  *
479  *****************************************************************************/
481 char *
482 strnl (char *str)
484         size_t len;
485         if (str == NULL)
486                 return NULL;
487         str = strpbrk (str, "\r\n");
488         if (str == NULL)
489                 return NULL;
490         len = strspn (str, "\r\n");
491         if (str[len] == '\0')
492                 return NULL;
493         str += len;
494         if (strlen (str) == 0)
495                 return NULL;
496         return str;
503 /******************************************************************************
504  *
505  * Like strscpy, except only the portion of the source string up to
506  * the provided delimiter is copied.
507  *
508  * Example:
509  *
510  * str = strpcpy(str,"This is a line of text with no trailing newline","x");
511  * printf("%s\n",str);
512  *
513  * Produces:
514  *
515  *This is a line of te
516  *
517  *****************************************************************************/
519 char *
520 strpcpy (char *dest, const char *src, const char *str)
522         size_t len;
524         if (src)
525                 len = strcspn (src, str);
526         else
527                 return NULL;
529         if (dest == NULL || strlen (dest) < len)
530                 dest = realloc (dest, len + 1);
531         if (dest == NULL)
532                 terminate (STATE_UNKNOWN, "failed realloc in strpcpy\n");
534         strncpy (dest, src, len);
535         dest[len] = '\0';
537         return dest;
544 /******************************************************************************
545  *
546  * Like strscat, except only the portion of the source string up to
547  * the provided delimiter is copied.
548  *
549  * str = strpcpy(str,"This is a line of text with no trailing newline","x");
550  * str = strpcat(str,"This is a line of text with no trailing newline","x");
551  * printf("%s\n",str);
552  * 
553  *This is a line of texThis is a line of tex
554  *
555  *****************************************************************************/
557 char *
558 strpcat (char *dest, const char *src, const char *str)
560         size_t len, l2;
562         if (dest)
563                 len = strlen (dest);
564         else
565                 len = 0;
567         if (src) {
568                 l2 = strcspn (src, str);
569         }
570         else {
571                 return dest;
572         }
574         dest = realloc (dest, len + l2 + 1);
575         if (dest == NULL)
576                 terminate (STATE_UNKNOWN, "failed malloc in strscat\n");
578         strncpy (dest + len, src, l2);
579         dest[len + l2] = '\0';
581         return dest;