Code

fixes for using POSIX return codes
[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 char *
62 my_basename (char *path)
63 {
64         if (!strstr (path, "/"))
65                 return path;
66         else
67                 return 1 + strrchr (path, '/');
68 }
71 void
72 support (void)
73 {
74         printf
75                 ("Send email to nagios-users@lists.sourceforge.net if you have questions\n"
76                  "regarding use of this software. To submit patches or suggest improvements,\n"
77                  "send email to nagiosplug-devel@lists.sourceforge.net\n");
78 }
81 char *
82 clean_revstring (const char *revstring)
83 {
84         char plugin_revision[STRLEN];
85         if (sscanf (revstring,"$Revision: %[0-9.]",plugin_revision) == 1)
86                 return strscpy (NULL, plugin_revision);
87         else
88           return strscpy (NULL, "N/A");
89 }
91 void
92 print_revision (char *command_name, const char *revision_string)
93 {
94         char plugin_revision[STRLEN];
96         if (sscanf (revision_string, "$Revision: %[0-9.]", plugin_revision) != 1)
97                 strncpy (plugin_revision, "N/A", STRLEN);
98         printf ("%s (nagios-plugins %s) %s\n",
99                                         my_basename (command_name), VERSION, plugin_revision);
100         printf
101                 ("The nagios plugins come with ABSOLUTELY NO WARRANTY. You may redistribute\n"
102                  "copies of the plugins under the terms of the GNU General Public License.\n"
103                  "For more information about these matters, see the file named COPYING.\n");
108 void
109 terminate (int result, const char *fmt, ...)
111         va_list ap;
112         va_start (ap, fmt);
113         vprintf (fmt, ap);
114         va_end (ap);
115         exit (result);
118 void
119 timeout_alarm_handler (int signo)
121         if (signo == SIGALRM) {
122                 printf ("CRITICAL - Plugin timed out after %d seconds\n",
123                                                 timeout_interval);
124                 exit (STATE_CRITICAL);
125         }
128 int
129 is_host (char *address)
131         if (is_dotted_quad (address) || is_hostname (address))
132                 return (TRUE);
133         return (FALSE);
136 int
137 is_dotted_quad (char *address)
139         int o1, o2, o3, o4;
140         char c[1];
142         if (sscanf (address, "%d.%d.%d.%d%c", &o1, &o2, &o3, &o4, c) != 4)
143                 return FALSE;
144         else if (o1 > 255 || o2 > 255 || o3 > 255 || o4 > 255)
145                 return FALSE;
146         else if (o1 < 0 || o2 < 0 || o3 < 0 || o4 < 0)
147                 return FALSE;
148         else
149                 return TRUE;
152 /* from RFC-1035
153  * 
154  * The labels must follow the rules for ARPANET host names.  They must
155  * start with a letter, end with a letter or digit, and have as interior
156  * characters only letters, digits, and hyphen.  There are also some
157  * restrictions on the length.  Labels must be 63 characters or less. */
159 int
160 is_hostname (char *s1)
162         if (strlen (s1) > 63)
163                 return FALSE;
164         if (strcspn
165                         (s1,
166                          "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUWVXYZ0123456789-.") !=
167                         0) return FALSE;
168         if (strspn (s1, "0123456789-.") == 1)
169                 return FALSE;
170         while ((s1 = index (s1, '.'))) {
171                 s1++;
172                 if (strspn (s1, "0123456789-.") == 1) {
173                         printf ("%s\n", s1);
174                         return FALSE;
175                 }
176         }
177         return TRUE;
180 int
181 is_numeric (char *number)
183         char tmp[1];
184         float x;
185         if (sscanf (number, "%f%c", &x, tmp) == 1)
186                 return (TRUE);
187         return (FALSE);
190 int
191 is_positive (char *number)
193         if (is_numeric (number) && atof (number) > 0.0)
194                 return (TRUE);
195         return (FALSE);
198 int
199 is_negative (char *number)
201         if (is_numeric (number) && atof (number) < 0.0)
202                 return (TRUE);
203         return (FALSE);
206 int
207 is_nonnegative (char *number)
209         if (is_numeric (number) && atof (number) >= 0.0)
210                 return (TRUE);
211         return (FALSE);
214 int
215 is_percentage (char *number)
217         int x;
218         if (is_numeric (number) && (x = atof (number)) >= 0 && x <= 100)
219                 return (TRUE);
220         return (FALSE);
223 int
224 is_integer (char *number)
226         long int n;
228         if (strspn (number, "-0123456789 ") != strlen (number))
229                 return (FALSE);
231         n = strtol (number, NULL, 10);
232         if (errno != ERANGE && n >= INT_MIN && n <= INT_MAX)
233                 return (TRUE);
234         return (FALSE);
237 int
238 is_intpos (char *number)
240         if (is_integer (number) && atoi (number) > 0)
241                 return (TRUE);
242         return (FALSE);
245 int
246 is_intneg (char *number)
248         if (is_integer (number) && atoi (number) < 0)
249                 return (TRUE);
250         return (FALSE);
253 int
254 is_intnonneg (char *number)
256         if (is_integer (number) && atoi (number) >= 0)
257                 return (TRUE);
258         return (FALSE);
261 int
262 is_intpercent (char *number)
264         int i;
265         if (is_integer (number) && (i = atoi (number)) >= 0 && i <= 100)
266                 return (TRUE);
267         return (FALSE);
270 int
271 is_option (char *str)
273         if (strspn (str, "-") == 1 || strspn (str, "-") == 2)
274                 return TRUE;
275         return FALSE;
282 void
283 strip (char *buffer)
285         size_t x;
286         int i;
288         for (x = strlen (buffer); x >= 1; x--) {
289                 i = x - 1;
290                 if (buffer[i] == ' ' ||
291                                 buffer[i] == '\r' || buffer[i] == '\n' || buffer[i] == '\t')
292                         buffer[i] = '\0';
293                 else
294                         break;
295         }
296         return;
303 /******************************************************************************
304  *
305  * Copies one string to another
306  *
307  * Given a pointer destination string, which may or may not already
308  * hold some text, and a source string with additional text (possibly
309  * NULL or empty), returns a pointer to a a copy of the source
310  * string. Uses realloc to free memory held by the dest argument if
311  * new storage space is required, and any previously existing data in
312  * the destination string is lost.
313  *
314  * Example:
315  *
316  * char *str=NULL;
317  * str = strscpy("This is a line of text with no trailing newline");
318  *
319  *****************************************************************************/
321 char *
322 strscpy (char *dest, const char *src)
324         size_t len;
326         if (src == NULL)
327                 return dest;
329         len = strlen (src) + 1;
330         if (dest == NULL)
331                 dest = malloc (len);
332         else if (strlen (dest) < len)
333                 dest = realloc (dest, len);
334         if (dest == NULL)
335                 terminate (STATE_UNKNOWN, "failed realloc in strscpy\n");
337         strncpy (dest, src, len);
339         return dest;
346 /******************************************************************************
347  *
348  * Concatenates one string to the end of another
349  *
350  * Given a pointer destination string, which may or may not already
351  * hold some text, and a source string with additional text (possibly
352  * NULL or empty), returns a pointer to a string that is the first
353  * string with the second concatenated to it. Uses realloc to free 
354  * memory held by the dest argument if new storage space is required.
355  *
356  * Example:
357  *
358  * char *str=NULL;
359  * str = strscpy("This is a line of text with no trailing newline");
360  * str = strscat(str,"\n");
361  *
362  *****************************************************************************/
364 char *
365 strscat (char *dest, const char *src)
367         size_t len, l2;
369         if (src)
370                 l2 = strlen (src);
371         else
372                 return dest;
374         if (dest)
375                 len = strlen (dest);
376         else
377                 len = 0;
379         dest = realloc (dest, len + l2 + 1);
380         if (dest == NULL)
381                 terminate (STATE_UNKNOWN, "failed malloc in strscat\n");
383         strncpy (dest + len, src, l2);
384         dest[len + l2] = '\0';
386         return dest;
393 /******************************************************************************
394  *
395  * Returns a pointer to the next line of a multiline string buffer
396  *
397  * Given a pointer string, find the text following the next sequence
398  * of \r and \n characters. This has the effect of skipping blank
399  * lines as well
400  *
401  * Example:
402  *
403  * Given text as follows:
404  *
405  * ==============================
406  * This
407  * is
408  * a
409  * 
410  * multiline string buffer
411  * ==============================
412  *
413  * int i=0;
414  * char *str=NULL;
415  * char *ptr=NULL;
416  * str = strscpy(str,"This\nis\r\na\n\nmultiline string buffer\n");
417  * ptr = str;
418  * while (ptr) {
419  *   printf("%d %s",i++,firstword(ptr));
420  *   ptr = strnl(ptr);
421  * }
422  * 
423  * Produces the following:
424  *
425  * 1 This
426  * 2 is
427  * 3 a
428  * 4 multiline
429  *
430  * NOTE: The 'firstword()' function is conceptual only and does not
431  *       exist in this package.
432  *
433  * NOTE: Although the second 'ptr' variable is not strictly needed in
434  *       this example, it is good practice with these utilities. Once
435  *       the * pointer is advance in this manner, it may no longer be
436  *       handled with * realloc(). So at the end of the code fragment
437  *       above, * strscpy(str,"foo") work perfectly fine, but
438  *       strscpy(ptr,"foo") will * cause the the program to crash with
439  *       a segmentation fault.
440  *
441  *****************************************************************************/
443 char *
444 strnl (char *str)
446         size_t len;
447         if (str == NULL)
448                 return NULL;
449         str = strpbrk (str, "\r\n");
450         if (str == NULL)
451                 return NULL;
452         len = strspn (str, "\r\n");
453         if (str[len] == '\0')
454                 return NULL;
455         str += len;
456         if (strlen (str) == 0)
457                 return NULL;
458         return str;
465 /******************************************************************************
466  *
467  * Does a formatted print to a string variable
468  *
469  * Given a pointer destination string, which may or may not already
470  * hold some text, and a source string with additional text (possibly
471  * NULL or empty), returns a pointer to a string that cntains the
472  * results of the specified formatted print
473  *
474  * Example:
475  *
476  * char *str=NULL;
477  * str = ssprintf(str,"%d %s",1,"string");
478  *
479  *****************************************************************************/
481 char *
482 ssprintf (char *ptr, const char *fmt, ...)
484         va_list ap;
485         int nchars;
486         size_t size;
487         char *str = NULL;
489         if (str == NULL) {
490                 str = malloc (TXTBLK);
491                 if (str == NULL)
492                         terminate (STATE_UNKNOWN, "malloc failed in ssprintf");
493                 size = TXTBLK;
494         }
495         else
496                 size = max (strlen (str), TXTBLK);
498         va_start (ap, fmt);
500         while (1) {
502                 nchars = vsnprintf (str, size, fmt, ap);
504                 if (nchars > -1)
505                         if (nchars < (int) size) {
506                                 va_end (ap);
507                                 str[nchars] = '\0';
508                                 if (ptr)
509                                         free (ptr);
510                                 return str;
511                         }
512                         else {
513                                 size = (size_t) (nchars + 1);
514                         }
516                 else
517                         size *= 2;
519                 str = realloc (str, size);
521                 if (str == NULL)
522                         terminate (STATE_UNKNOWN, "realloc failed in ssprintf");
523         }
531 /******************************************************************************
532  *
533  * Like strscpy, except only the portion of the source string up to
534  * the provided delimiter is copied.
535  *
536  * Example:
537  *
538  * str = strpcpy(str,"This is a line of text with no trailing newline","x");
539  * printf("%s\n",str);
540  *
541  * Produces:
542  *
543  *This is a line of te
544  *
545  *****************************************************************************/
547 char *
548 strpcpy (char *dest, const char *src, const char *str)
550         size_t len;
552         if (src)
553                 len = strcspn (src, str);
554         else
555                 return NULL;
557         if (dest == NULL || strlen (dest) < len)
558                 dest = realloc (dest, len + 1);
559         if (dest == NULL)
560                 terminate (STATE_UNKNOWN, "failed realloc in strpcpy\n");
562         strncpy (dest, src, len);
563         dest[len] = '\0';
565         return dest;
572 /******************************************************************************
573  *
574  * Like strscat, except only the portion of the source string up to
575  * the provided delimiter is copied.
576  *
577  * str = strpcpy(str,"This is a line of text with no trailing newline","x");
578  * str = strpcat(str,"This is a line of text with no trailing newline","x");
579  * printf("%s\n",str);
580  * 
581  *This is a line of texThis is a line of tex
582  *
583  *****************************************************************************/
585 char *
586 strpcat (char *dest, const char *src, const char *str)
588         size_t len, l2;
590         if (dest)
591                 len = strlen (dest);
592         else
593                 len = 0;
595         if (src) {
596                 l2 = strcspn (src, str);
597         }
598         else {
599                 return dest;
600         }
602         dest = realloc (dest, len + l2 + 1);
603         if (dest == NULL)
604                 terminate (STATE_UNKNOWN, "failed malloc in strscat\n");
606         strncpy (dest + len, src, l2);
607         dest[len + l2] = '\0';
609         return dest;