8bec1cf12c2d811edfbbcbee42e67334956f535c
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)
408 l2 = strlen (src);
409 else
410 return dest;
412 if (dest)
413 len = strlen (dest);
414 else
415 len = 0;
417 dest = realloc (dest, len + l2 + 1);
418 if (dest == NULL)
419 terminate (STATE_UNKNOWN, "failed malloc in strscat\n");
421 strncpy (dest + len, src, l2);
422 dest[len + l2] = '\0';
424 return dest;
425 }
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)
483 {
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;
497 }
503 /******************************************************************************
504 *
505 * Does a formatted print to a string variable
506 *
507 * Given a pointer destination string, which may or may not already
508 * hold some text, and a source string with additional text (possibly
509 * NULL or empty), returns a pointer to a string that cntains the
510 * results of the specified formatted print
511 *
512 * Example:
513 *
514 * char *str=NULL;
515 * str = ssprintf(str,"%d %s",1,"string");
516 *
517 *****************************************************************************/
519 char *
520 ssprintf (char *ptr, const char *fmt, ...)
521 {
522 va_list ap;
523 int nchars;
524 size_t size;
525 char *str = NULL;
527 if (str == NULL) {
528 str = malloc (TXTBLK);
529 if (str == NULL)
530 terminate (STATE_UNKNOWN, "malloc failed in ssprintf");
531 size = TXTBLK;
532 }
533 else
534 size = max (strlen (str), TXTBLK);
536 va_start (ap, fmt);
538 while (1) {
540 nchars = vsnprintf (str, size, fmt, ap);
542 if (nchars > -1)
543 if (nchars < (int) size) {
544 va_end (ap);
545 str[nchars] = '\0';
546 if (ptr)
547 free (ptr);
548 return str;
549 }
550 else {
551 size = (size_t) (nchars + 1);
552 }
554 else
555 size *= 2;
557 str = realloc (str, size);
559 if (str == NULL)
560 terminate (STATE_UNKNOWN, "realloc failed in ssprintf");
561 }
563 }
569 /******************************************************************************
570 *
571 * Like strscpy, except only the portion of the source string up to
572 * the provided delimiter is copied.
573 *
574 * Example:
575 *
576 * str = strpcpy(str,"This is a line of text with no trailing newline","x");
577 * printf("%s\n",str);
578 *
579 * Produces:
580 *
581 *This is a line of te
582 *
583 *****************************************************************************/
585 char *
586 strpcpy (char *dest, const char *src, const char *str)
587 {
588 size_t len;
590 if (src)
591 len = strcspn (src, str);
592 else
593 return NULL;
595 if (dest == NULL || strlen (dest) < len)
596 dest = realloc (dest, len + 1);
597 if (dest == NULL)
598 terminate (STATE_UNKNOWN, "failed realloc in strpcpy\n");
600 strncpy (dest, src, len);
601 dest[len] = '\0';
603 return dest;
604 }
610 /******************************************************************************
611 *
612 * Like strscat, except only the portion of the source string up to
613 * the provided delimiter is copied.
614 *
615 * str = strpcpy(str,"This is a line of text with no trailing newline","x");
616 * str = strpcat(str,"This is a line of text with no trailing newline","x");
617 * printf("%s\n",str);
618 *
619 *This is a line of texThis is a line of tex
620 *
621 *****************************************************************************/
623 char *
624 strpcat (char *dest, const char *src, const char *str)
625 {
626 size_t len, l2;
628 if (dest)
629 len = strlen (dest);
630 else
631 len = 0;
633 if (src) {
634 l2 = strcspn (src, str);
635 }
636 else {
637 return dest;
638 }
640 dest = realloc (dest, len + l2 + 1);
641 if (dest == NULL)
642 terminate (STATE_UNKNOWN, "failed malloc in strscat\n");
644 strncpy (dest + len, src, l2);
645 dest[len + l2] = '\0';
647 return dest;
648 }