6e52dab75e0759c501910d30ba3a16452acad595
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) {
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 }
97 }
99 char *
100 my_basename (char *path)
101 {
102 if (!strstr (path, "/"))
103 return path;
104 else
105 return 1 + strrchr (path, '/');
106 }
109 void
110 support (void)
111 {
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");
116 }
119 char *
120 clean_revstring (const char *revstring)
121 {
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");
127 }
129 void
130 print_revision (char *command_name, const char *revision_string)
131 {
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");
143 }
146 void
147 terminate (int result, const char *fmt, ...)
148 {
149 va_list ap;
150 va_start (ap, fmt);
151 vprintf (fmt, ap);
152 va_end (ap);
153 exit (result);
154 }
156 void
157 timeout_alarm_handler (int signo)
158 {
159 if (signo == SIGALRM) {
160 printf ("CRITICAL - Plugin timed out after %d seconds\n",
161 timeout_interval);
162 exit (STATE_CRITICAL);
163 }
164 }
166 int
167 is_host (char *address)
168 {
169 if (is_dotted_quad (address) || is_hostname (address))
170 return (TRUE);
171 return (FALSE);
172 }
174 int
175 is_dotted_quad (char *address)
176 {
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;
188 }
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)
199 {
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;
216 }
218 int
219 is_numeric (char *number)
220 {
221 char tmp[1];
222 float x;
223 if (sscanf (number, "%f%c", &x, tmp) == 1)
224 return (TRUE);
225 return (FALSE);
226 }
228 int
229 is_positive (char *number)
230 {
231 if (is_numeric (number) && atof (number) > 0.0)
232 return (TRUE);
233 return (FALSE);
234 }
236 int
237 is_negative (char *number)
238 {
239 if (is_numeric (number) && atof (number) < 0.0)
240 return (TRUE);
241 return (FALSE);
242 }
244 int
245 is_nonnegative (char *number)
246 {
247 if (is_numeric (number) && atof (number) >= 0.0)
248 return (TRUE);
249 return (FALSE);
250 }
252 int
253 is_percentage (char *number)
254 {
255 int x;
256 if (is_numeric (number) && (x = atof (number)) >= 0 && x <= 100)
257 return (TRUE);
258 return (FALSE);
259 }
261 int
262 is_integer (char *number)
263 {
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);
273 }
275 int
276 is_intpos (char *number)
277 {
278 if (is_integer (number) && atoi (number) > 0)
279 return (TRUE);
280 return (FALSE);
281 }
283 int
284 is_intneg (char *number)
285 {
286 if (is_integer (number) && atoi (number) < 0)
287 return (TRUE);
288 return (FALSE);
289 }
291 int
292 is_intnonneg (char *number)
293 {
294 if (is_integer (number) && atoi (number) >= 0)
295 return (TRUE);
296 return (FALSE);
297 }
299 int
300 is_intpercent (char *number)
301 {
302 int i;
303 if (is_integer (number) && (i = atoi (number)) >= 0 && i <= 100)
304 return (TRUE);
305 return (FALSE);
306 }
308 int
309 is_option (char *str)
310 {
311 if (strspn (str, "-") == 1 || strspn (str, "-") == 2)
312 return TRUE;
313 return FALSE;
314 }
319 double
320 delta_time (struct timeval *tv)
321 {
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);
328 }
333 void
334 strip (char *buffer)
335 {
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;
348 }
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)
374 {
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;
391 }
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)
417 {
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;
440 }
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)
498 {
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;
512 }
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, ...)
536 {
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 }
578 }
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)
602 {
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;
619 }
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)
640 {
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;
663 }