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 }
320 void
321 strip (char *buffer)
322 {
323 size_t x;
324 int i;
326 for (x = strlen (buffer); x >= 1; x--) {
327 i = x - 1;
328 if (buffer[i] == ' ' ||
329 buffer[i] == '\r' || buffer[i] == '\n' || buffer[i] == '\t')
330 buffer[i] = '\0';
331 else
332 break;
333 }
334 return;
335 }
341 /******************************************************************************
342 *
343 * Copies one string to another
344 *
345 * Given a pointer destination string, which may or may not already
346 * hold some text, and a source string with additional text (possibly
347 * NULL or empty), returns a pointer to a a copy of the source
348 * string. Uses realloc to free memory held by the dest argument if
349 * new storage space is required, and any previously existing data in
350 * the destination string is lost.
351 *
352 * Example:
353 *
354 * char *str=NULL;
355 * str = strscpy("This is a line of text with no trailing newline");
356 *
357 *****************************************************************************/
359 char *
360 strscpy (char *dest, const char *src)
361 {
362 size_t len;
364 if (src == NULL)
365 return dest;
367 len = strlen (src) + 1;
368 if (dest == NULL)
369 dest = malloc (len);
370 else if (strlen (dest) < len)
371 dest = realloc (dest, len);
372 if (dest == NULL)
373 terminate (STATE_UNKNOWN, "failed realloc in strscpy\n");
375 strncpy (dest, src, len);
377 return dest;
378 }
384 /******************************************************************************
385 *
386 * Concatenates one string to the end of another
387 *
388 * Given a pointer destination string, which may or may not already
389 * hold some text, and a source string with additional text (possibly
390 * NULL or empty), returns a pointer to a string that is the first
391 * string with the second concatenated to it. Uses realloc to free
392 * memory held by the dest argument if new storage space is required.
393 *
394 * Example:
395 *
396 * char *str=NULL;
397 * str = strscpy("This is a line of text with no trailing newline");
398 * str = strscat(str,"\n");
399 *
400 *****************************************************************************/
402 char *
403 strscat (char *dest, const char *src)
404 {
405 size_t len, l2;
407 if (src == NULL)
408 return dest;
409 else
410 l2 = strlen (src);
412 if (dest == NULL) {
413 len = 0;
414 dest = malloc (l2 + 1);
415 } else {
416 len = strlen (dest);
417 dest = realloc (dest, len + l2 + 1);
418 }
420 if (dest == NULL)
421 terminate (STATE_UNKNOWN, "failed malloc in strscat\n");
423 strncpy (dest + len, src, l2);
424 dest[len + l2] = '\0';
426 return dest;
427 }
433 /******************************************************************************
434 *
435 * Returns a pointer to the next line of a multiline string buffer
436 *
437 * Given a pointer string, find the text following the next sequence
438 * of \r and \n characters. This has the effect of skipping blank
439 * lines as well
440 *
441 * Example:
442 *
443 * Given text as follows:
444 *
445 * ==============================
446 * This
447 * is
448 * a
449 *
450 * multiline string buffer
451 * ==============================
452 *
453 * int i=0;
454 * char *str=NULL;
455 * char *ptr=NULL;
456 * str = strscpy(str,"This\nis\r\na\n\nmultiline string buffer\n");
457 * ptr = str;
458 * while (ptr) {
459 * printf("%d %s",i++,firstword(ptr));
460 * ptr = strnl(ptr);
461 * }
462 *
463 * Produces the following:
464 *
465 * 1 This
466 * 2 is
467 * 3 a
468 * 4 multiline
469 *
470 * NOTE: The 'firstword()' function is conceptual only and does not
471 * exist in this package.
472 *
473 * NOTE: Although the second 'ptr' variable is not strictly needed in
474 * this example, it is good practice with these utilities. Once
475 * the * pointer is advance in this manner, it may no longer be
476 * handled with * realloc(). So at the end of the code fragment
477 * above, * strscpy(str,"foo") work perfectly fine, but
478 * strscpy(ptr,"foo") will * cause the the program to crash with
479 * a segmentation fault.
480 *
481 *****************************************************************************/
483 char *
484 strnl (char *str)
485 {
486 size_t len;
487 if (str == NULL)
488 return NULL;
489 str = strpbrk (str, "\r\n");
490 if (str == NULL)
491 return NULL;
492 len = strspn (str, "\r\n");
493 if (str[len] == '\0')
494 return NULL;
495 str += len;
496 if (strlen (str) == 0)
497 return NULL;
498 return str;
499 }
505 /******************************************************************************
506 *
507 * Does a formatted print to a string variable
508 *
509 * Given a pointer destination string, which may or may not already
510 * hold some text, and a source string with additional text (possibly
511 * NULL or empty), returns a pointer to a string that cntains the
512 * results of the specified formatted print
513 *
514 * Example:
515 *
516 * char *str=NULL;
517 * str = ssprintf(str,"%d %s",1,"string");
518 *
519 *****************************************************************************/
521 char *
522 ssprintf (char *ptr, const char *fmt, ...)
523 {
524 va_list ap;
525 int nchars;
526 size_t size;
527 char *str = NULL;
529 if (str == NULL) {
530 str = malloc (TXTBLK);
531 if (str == NULL)
532 terminate (STATE_UNKNOWN, "malloc failed in ssprintf");
533 size = TXTBLK;
534 }
535 else
536 size = max (strlen (str), TXTBLK);
538 va_start (ap, fmt);
540 while (1) {
542 nchars = vsnprintf (str, size, fmt, ap);
544 if (nchars > -1)
545 if (nchars < (int) size) {
546 va_end (ap);
547 str[nchars] = '\0';
548 if (ptr)
549 free (ptr);
550 return str;
551 }
552 else {
553 size = (size_t) (nchars + 1);
554 }
556 else
557 size *= 2;
559 str = realloc (str, size);
561 if (str == NULL)
562 terminate (STATE_UNKNOWN, "realloc failed in ssprintf");
563 }
565 }
571 /******************************************************************************
572 *
573 * Like strscpy, except only the portion of the source string up to
574 * the provided delimiter is copied.
575 *
576 * Example:
577 *
578 * str = strpcpy(str,"This is a line of text with no trailing newline","x");
579 * printf("%s\n",str);
580 *
581 * Produces:
582 *
583 *This is a line of te
584 *
585 *****************************************************************************/
587 char *
588 strpcpy (char *dest, const char *src, const char *str)
589 {
590 size_t len;
592 if (src)
593 len = strcspn (src, str);
594 else
595 return NULL;
597 if (dest == NULL || strlen (dest) < len)
598 dest = realloc (dest, len + 1);
599 if (dest == NULL)
600 terminate (STATE_UNKNOWN, "failed realloc in strpcpy\n");
602 strncpy (dest, src, len);
603 dest[len] = '\0';
605 return dest;
606 }
612 /******************************************************************************
613 *
614 * Like strscat, except only the portion of the source string up to
615 * the provided delimiter is copied.
616 *
617 * str = strpcpy(str,"This is a line of text with no trailing newline","x");
618 * str = strpcat(str,"This is a line of text with no trailing newline","x");
619 * printf("%s\n",str);
620 *
621 *This is a line of texThis is a line of tex
622 *
623 *****************************************************************************/
625 char *
626 strpcat (char *dest, const char *src, const char *str)
627 {
628 size_t len, l2;
630 if (dest)
631 len = strlen (dest);
632 else
633 len = 0;
635 if (src) {
636 l2 = strcspn (src, str);
637 }
638 else {
639 return dest;
640 }
642 dest = realloc (dest, len + l2 + 1);
643 if (dest == NULL)
644 terminate (STATE_UNKNOWN, "failed malloc in strscat\n");
646 strncpy (dest + len, src, l2);
647 dest[len + l2] = '\0';
649 return dest;
650 }