0d1729e0d7cba768414d5b4564be4504f6ceddc2
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 now;
323 struct timezone tz;
324 double et;
326 gettimeofday (&now, NULL);
327 return ((double)(now.tv_sec - tv.tv_sec) + (double)(now.tv_usec - tv.tv_usec) / (double)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 {
419 if (src != NULL)
420 asprintf (&dest, "%s%s", dest, src);
422 return dest;
423 }
429 /******************************************************************************
430 *
431 * Returns a pointer to the next line of a multiline string buffer
432 *
433 * Given a pointer string, find the text following the next sequence
434 * of \r and \n characters. This has the effect of skipping blank
435 * lines as well
436 *
437 * Example:
438 *
439 * Given text as follows:
440 *
441 * ==============================
442 * This
443 * is
444 * a
445 *
446 * multiline string buffer
447 * ==============================
448 *
449 * int i=0;
450 * char *str=NULL;
451 * char *ptr=NULL;
452 * str = strscpy(str,"This\nis\r\na\n\nmultiline string buffer\n");
453 * ptr = str;
454 * while (ptr) {
455 * printf("%d %s",i++,firstword(ptr));
456 * ptr = strnl(ptr);
457 * }
458 *
459 * Produces the following:
460 *
461 * 1 This
462 * 2 is
463 * 3 a
464 * 4 multiline
465 *
466 * NOTE: The 'firstword()' function is conceptual only and does not
467 * exist in this package.
468 *
469 * NOTE: Although the second 'ptr' variable is not strictly needed in
470 * this example, it is good practice with these utilities. Once
471 * the * pointer is advance in this manner, it may no longer be
472 * handled with * realloc(). So at the end of the code fragment
473 * above, * strscpy(str,"foo") work perfectly fine, but
474 * strscpy(ptr,"foo") will * cause the the program to crash with
475 * a segmentation fault.
476 *
477 *****************************************************************************/
479 char *
480 strnl (char *str)
481 {
482 size_t len;
483 if (str == NULL)
484 return NULL;
485 str = strpbrk (str, "\r\n");
486 if (str == NULL)
487 return NULL;
488 len = strspn (str, "\r\n");
489 if (str[len] == '\0')
490 return NULL;
491 str += len;
492 if (strlen (str) == 0)
493 return NULL;
494 return str;
495 }
501 /******************************************************************************
502 *
503 * Does a formatted print to a string variable
504 *
505 * Given a pointer destination string, which may or may not already
506 * hold some text, and a source string with additional text (possibly
507 * NULL or empty), returns a pointer to a string that cntains the
508 * results of the specified formatted print
509 *
510 * Example:
511 *
512 * char *str=NULL;
513 * str = ssprintf(str,"%d %s",1,"string");
514 *
515 *****************************************************************************/
517 char *
518 ssprintf (char *ptr, const char *fmt, ...)
519 {
520 va_list ap;
521 int nchars;
522 size_t size;
523 char *str = NULL;
525 if (str == NULL) {
526 str = malloc (TXTBLK);
527 if (str == NULL)
528 terminate (STATE_UNKNOWN, "malloc failed in ssprintf");
529 size = TXTBLK;
530 }
531 else
532 size = max (strlen (str), TXTBLK);
534 va_start (ap, fmt);
536 while (1) {
538 nchars = vsnprintf (str, size, fmt, ap);
540 if (nchars > -1)
541 if (nchars < (int) size) {
542 va_end (ap);
543 str[nchars] = '\0';
544 if (ptr)
545 free (ptr);
546 return str;
547 }
548 else {
549 size = (size_t) (nchars + 1);
550 }
552 else
553 size *= 2;
555 str = realloc (str, size);
557 if (str == NULL)
558 terminate (STATE_UNKNOWN, "realloc failed in ssprintf");
559 }
561 }
567 /******************************************************************************
568 *
569 * Like strscpy, except only the portion of the source string up to
570 * the provided delimiter is copied.
571 *
572 * Example:
573 *
574 * str = strpcpy(str,"This is a line of text with no trailing newline","x");
575 * printf("%s\n",str);
576 *
577 * Produces:
578 *
579 *This is a line of te
580 *
581 *****************************************************************************/
583 char *
584 strpcpy (char *dest, const char *src, const char *str)
585 {
586 size_t len;
588 if (src)
589 len = strcspn (src, str);
590 else
591 return NULL;
593 if (dest == NULL || strlen (dest) < len)
594 dest = realloc (dest, len + 1);
595 if (dest == NULL)
596 terminate (STATE_UNKNOWN, "failed realloc in strpcpy\n");
598 strncpy (dest, src, len);
599 dest[len] = '\0';
601 return dest;
602 }
608 /******************************************************************************
609 *
610 * Like strscat, except only the portion of the source string up to
611 * the provided delimiter is copied.
612 *
613 * str = strpcpy(str,"This is a line of text with no trailing newline","x");
614 * str = strpcat(str,"This is a line of text with no trailing newline","x");
615 * printf("%s\n",str);
616 *
617 *This is a line of texThis is a line of tex
618 *
619 *****************************************************************************/
621 char *
622 strpcat (char *dest, const char *src, const char *str)
623 {
624 size_t len, l2;
626 if (dest)
627 len = strlen (dest);
628 else
629 len = 0;
631 if (src) {
632 l2 = strcspn (src, str);
633 }
634 else {
635 return dest;
636 }
638 dest = realloc (dest, len + l2 + 1);
639 if (dest == NULL)
640 terminate (STATE_UNKNOWN, "failed malloc in strscat\n");
642 strncpy (dest + len, src, l2);
643 dest[len + l2] = '\0';
645 return dest;
646 }