cb013412c851087b8165ca3861e5bcf10eceff92
1 /*****************************************************************************
2 *
3 * utils.c
4 *
5 * Library of useful functions for plugins
6 *
7 * Copyright (c) 2000 Karl DeBisschop (karl@debisschop.net)
8 * Copyright (c) 2006 Nagios Plugin Development Team
9 * License: GPL
10 *
11 * $Revision$
12 * $Date$
13 ****************************************************************************/
15 #define LOCAL_TIMEOUT_ALARM_HANDLER
17 #include "common.h"
18 #include "utils.h"
19 #include <stdarg.h>
20 #include <limits.h>
22 #include <arpa/inet.h>
24 extern void print_usage (void);
25 extern const char *progname;
27 #define STRLEN 64
28 #define TXTBLK 128
30 /* **************************************************************************
31 * max_state(STATE_x, STATE_y)
32 * compares STATE_x to STATE_y and returns result based on the following
33 * STATE_UNKNOWN < STATE_OK < STATE_WARNING < STATE_CRITICAL
34 *
35 * Note that numerically the above does not hold
36 ****************************************************************************/
38 int
39 max_state (int a, int b)
40 {
41 if (a == STATE_CRITICAL || b == STATE_CRITICAL)
42 return STATE_CRITICAL;
43 else if (a == STATE_WARNING || b == STATE_WARNING)
44 return STATE_WARNING;
45 else if (a == STATE_OK || b == STATE_OK)
46 return STATE_OK;
47 else if (a == STATE_UNKNOWN || b == STATE_UNKNOWN)
48 return STATE_UNKNOWN;
49 else if (a == STATE_DEPENDENT || b == STATE_DEPENDENT)
50 return STATE_DEPENDENT;
51 else
52 return max (a, b);
53 }
55 void usage (const char *msg)
56 {
57 printf ("%s\n", msg);
58 print_usage ();
59 exit (STATE_UNKNOWN);
60 }
62 void usage_va (const char *fmt, ...)
63 {
64 va_list ap;
65 printf("%s: ", progname);
66 va_start(ap, fmt);
67 vprintf(fmt, ap);
68 va_end(ap);
69 printf("\n");
70 exit (STATE_UNKNOWN);
71 }
73 void usage2(const char *msg, const char *arg)
74 {
75 printf ("%s: %s - %s\n", progname, msg, arg?arg:"(null)" );
76 print_usage ();
77 exit (STATE_UNKNOWN);
78 }
80 void
81 usage3 (const char *msg, int arg)
82 {
83 printf ("%s: %s - %c\n", progname, msg, arg);
84 print_usage();
85 exit (STATE_UNKNOWN);
86 }
88 void
89 usage4 (const char *msg)
90 {
91 printf ("%s: %s\n", progname, msg);
92 print_usage();
93 exit (STATE_UNKNOWN);
94 }
96 char *
97 clean_revstring (const char *revstring)
98 {
99 char plugin_revision[STRLEN];
100 if (sscanf (revstring,"$Revision: %[0-9.]",plugin_revision) == 1)
101 return strscpy (NULL, plugin_revision);
102 else
103 return strscpy (NULL, "N/A");
104 }
106 void
107 print_revision (const char *command_name, const char *revision_string)
108 {
109 char plugin_revision[STRLEN];
111 if (sscanf (revision_string, "$Revision: %[0-9.]", plugin_revision) != 1)
112 strncpy (plugin_revision, "N/A", STRLEN);
113 printf ("%s (%s %s) %s\n",
114 command_name, PACKAGE, VERSION, plugin_revision);
115 }
117 const char *
118 state_text (int result)
119 {
120 switch (result) {
121 case STATE_OK:
122 return "OK";
123 case STATE_WARNING:
124 return "WARNING";
125 case STATE_CRITICAL:
126 return "CRITICAL";
127 case STATE_DEPENDENT:
128 return "DEPENDENT";
129 default:
130 return "UNKNOWN";
131 }
132 }
134 void
135 die (int result, const char *fmt, ...)
136 {
137 va_list ap;
138 va_start (ap, fmt);
139 vprintf (fmt, ap);
140 va_end (ap);
141 exit (result);
142 }
144 void
145 timeout_alarm_handler (int signo)
146 {
147 if (signo == SIGALRM) {
148 printf (_("CRITICAL - Plugin timed out after %d seconds\n"),
149 timeout_interval);
150 exit (STATE_CRITICAL);
151 }
152 }
154 int
155 is_numeric (char *number)
156 {
157 char tmp[1];
158 float x;
160 if (!number)
161 return FALSE;
162 else if (sscanf (number, "%f%c", &x, tmp) == 1)
163 return TRUE;
164 else
165 return FALSE;
166 }
168 int
169 is_positive (char *number)
170 {
171 if (is_numeric (number) && atof (number) > 0.0)
172 return TRUE;
173 else
174 return FALSE;
175 }
177 int
178 is_negative (char *number)
179 {
180 if (is_numeric (number) && atof (number) < 0.0)
181 return TRUE;
182 else
183 return FALSE;
184 }
186 int
187 is_nonnegative (char *number)
188 {
189 if (is_numeric (number) && atof (number) >= 0.0)
190 return TRUE;
191 else
192 return FALSE;
193 }
195 int
196 is_percentage (char *number)
197 {
198 int x;
199 if (is_numeric (number) && (x = atof (number)) >= 0 && x <= 100)
200 return TRUE;
201 else
202 return FALSE;
203 }
205 int
206 is_integer (char *number)
207 {
208 long int n;
210 if (!number || (strspn (number, "-0123456789 ") != strlen (number)))
211 return FALSE;
213 n = strtol (number, NULL, 10);
215 if (errno != ERANGE && n >= INT_MIN && n <= INT_MAX)
216 return TRUE;
217 else
218 return FALSE;
219 }
221 int
222 is_intpos (char *number)
223 {
224 if (is_integer (number) && atoi (number) > 0)
225 return TRUE;
226 else
227 return FALSE;
228 }
230 int
231 is_intneg (char *number)
232 {
233 if (is_integer (number) && atoi (number) < 0)
234 return TRUE;
235 else
236 return FALSE;
237 }
239 int
240 is_intnonneg (char *number)
241 {
242 if (is_integer (number) && atoi (number) >= 0)
243 return TRUE;
244 else
245 return FALSE;
246 }
248 int
249 is_intpercent (char *number)
250 {
251 int i;
252 if (is_integer (number) && (i = atoi (number)) >= 0 && i <= 100)
253 return TRUE;
254 else
255 return FALSE;
256 }
258 int
259 is_option (char *str)
260 {
261 if (!str)
262 return FALSE;
263 else if (strspn (str, "-") == 1 || strspn (str, "-") == 2)
264 return TRUE;
265 else
266 return FALSE;
267 }
269 void set_range_start (range *this, double value) {
270 this->start = value;
271 this->start_infinity = FALSE;
272 }
274 void set_range_end (range *this, double value) {
275 this->end = value;
276 this->end_infinity = FALSE;
277 }
279 range
280 *parse_range_string (char *str) {
281 range *temp_range;
282 double start;
283 double end;
284 char *end_str;
286 temp_range = (range *) malloc(sizeof(range));
288 /* Set defaults */
289 temp_range->start = 0;
290 temp_range->start_infinity = FALSE;
291 temp_range->end = 0;
292 temp_range->end_infinity = TRUE;
293 temp_range->alert_on = OUTSIDE;
295 if (str[0] == '@') {
296 temp_range->alert_on = INSIDE;
297 str++;
298 }
300 end_str = index(str, ':');
301 if (end_str != NULL) {
302 if (str[0] == '~') {
303 temp_range->start_infinity = TRUE;
304 } else {
305 start = strtod(str, NULL); /* Will stop at the ':' */
306 set_range_start(temp_range, start);
307 }
308 end_str++; /* Move past the ':' */
309 } else {
310 end_str = str;
311 }
312 end = strtod(end_str, NULL);
313 if (strcmp(end_str, "") != 0) {
314 set_range_end(temp_range, end);
315 }
317 if (temp_range->start_infinity == TRUE ||
318 temp_range->end_infinity == TRUE ||
319 temp_range->start <= temp_range->end) {
320 return temp_range;
321 }
322 free(temp_range);
323 return NULL;
324 }
326 /* returns 0 if okay, otherwise 1 */
327 int
328 _set_thresholds(thresholds **my_thresholds, char *warn_string, char *critical_string)
329 {
330 thresholds *temp_thresholds = NULL;
332 temp_thresholds = malloc(sizeof(temp_thresholds));
334 temp_thresholds->warning = NULL;
335 temp_thresholds->critical = NULL;
337 if (warn_string != NULL) {
338 if ((temp_thresholds->warning = parse_range_string(warn_string)) == NULL) {
339 return 1;
340 }
341 }
342 if (critical_string != NULL) {
343 if ((temp_thresholds->critical = parse_range_string(critical_string)) == NULL) {
344 return 1;
345 }
346 }
348 if (*my_thresholds != 0) {
349 /* printf("Freeing here: %d\n", *my_thresholds); */
350 free(*my_thresholds);
351 }
352 *my_thresholds = temp_thresholds;
354 return 0;
355 }
357 void
358 set_thresholds(thresholds **my_thresholds, char *warn_string, char *critical_string)
359 {
360 if (_set_thresholds(my_thresholds, warn_string, critical_string) == 0) {
361 return;
362 } else {
363 usage(_("Range format incorrect"));
364 }
365 }
367 /* Returns TRUE if alert should be raised based on the range */
368 int
369 check_range(double value, range *my_range)
370 {
371 int false = FALSE;
372 int true = TRUE;
374 if (my_range->alert_on == INSIDE) {
375 false = TRUE;
376 true = FALSE;
377 }
379 if (my_range->end_infinity == FALSE && my_range->start_infinity == FALSE) {
380 if ((my_range->start <= value) && (value <= my_range->end)) {
381 return false;
382 } else {
383 return true;
384 }
385 } else if (my_range->start_infinity == FALSE && my_range->end_infinity == TRUE) {
386 if (my_range->start <= value) {
387 return false;
388 } else {
389 return true;
390 }
391 } else if (my_range->start_infinity == TRUE && my_range->end_infinity == FALSE) {
392 if (value <= my_range->end) {
393 return false;
394 } else {
395 return true;
396 }
397 } else {
398 return false;
399 }
400 }
402 /* Returns status */
403 int
404 get_status(double value, thresholds *my_thresholds)
405 {
406 if (my_thresholds->critical != NULL) {
407 if (check_range(value, my_thresholds->critical) == TRUE) {
408 return STATE_CRITICAL;
409 }
410 }
411 if (my_thresholds->warning != NULL) {
412 if (check_range(value, my_thresholds->warning) == TRUE) {
413 return STATE_WARNING;
414 }
415 }
416 return STATE_OK;
417 }
419 #ifdef NEED_GETTIMEOFDAY
420 int
421 gettimeofday (struct timeval *tv, struct timezone *tz)
422 {
423 tv->tv_usec = 0;
424 tv->tv_sec = (long) time ((time_t) 0);
425 }
426 #endif
430 double
431 delta_time (struct timeval tv)
432 {
433 struct timeval now;
435 gettimeofday (&now, NULL);
436 return ((double)(now.tv_sec - tv.tv_sec) + (double)(now.tv_usec - tv.tv_usec) / (double)1000000);
437 }
441 long
442 deltime (struct timeval tv)
443 {
444 struct timeval now;
445 gettimeofday (&now, NULL);
446 return (now.tv_sec - tv.tv_sec)*1000000 + now.tv_usec - tv.tv_usec;
447 }
452 void
453 strip (char *buffer)
454 {
455 size_t x;
456 int i;
458 for (x = strlen (buffer); x >= 1; x--) {
459 i = x - 1;
460 if (buffer[i] == ' ' ||
461 buffer[i] == '\r' || buffer[i] == '\n' || buffer[i] == '\t')
462 buffer[i] = '\0';
463 else
464 break;
465 }
466 return;
467 }
470 /******************************************************************************
471 *
472 * Copies one string to another. Any previously existing data in
473 * the destination string is lost.
474 *
475 * Example:
476 *
477 * char *str=NULL;
478 * str = strscpy("This is a line of text with no trailing newline");
479 *
480 *****************************************************************************/
482 char *
483 strscpy (char *dest, const char *src)
484 {
485 if (src == NULL)
486 return NULL;
488 asprintf (&dest, "%s", src);
490 return dest;
491 }
495 /******************************************************************************
496 *
497 * Returns a pointer to the next line of a multiline string buffer
498 *
499 * Given a pointer string, find the text following the next sequence
500 * of \r and \n characters. This has the effect of skipping blank
501 * lines as well
502 *
503 * Example:
504 *
505 * Given text as follows:
506 *
507 * ==============================
508 * This
509 * is
510 * a
511 *
512 * multiline string buffer
513 * ==============================
514 *
515 * int i=0;
516 * char *str=NULL;
517 * char *ptr=NULL;
518 * str = strscpy(str,"This\nis\r\na\n\nmultiline string buffer\n");
519 * ptr = str;
520 * while (ptr) {
521 * printf("%d %s",i++,firstword(ptr));
522 * ptr = strnl(ptr);
523 * }
524 *
525 * Produces the following:
526 *
527 * 1 This
528 * 2 is
529 * 3 a
530 * 4 multiline
531 *
532 * NOTE: The 'firstword()' function is conceptual only and does not
533 * exist in this package.
534 *
535 * NOTE: Although the second 'ptr' variable is not strictly needed in
536 * this example, it is good practice with these utilities. Once
537 * the * pointer is advance in this manner, it may no longer be
538 * handled with * realloc(). So at the end of the code fragment
539 * above, * strscpy(str,"foo") work perfectly fine, but
540 * strscpy(ptr,"foo") will * cause the the program to crash with
541 * a segmentation fault.
542 *
543 *****************************************************************************/
545 char *
546 strnl (char *str)
547 {
548 size_t len;
549 if (str == NULL)
550 return NULL;
551 str = strpbrk (str, "\r\n");
552 if (str == NULL)
553 return NULL;
554 len = strspn (str, "\r\n");
555 if (str[len] == '\0')
556 return NULL;
557 str += len;
558 if (strlen (str) == 0)
559 return NULL;
560 return str;
561 }
564 /******************************************************************************
565 *
566 * Like strscpy, except only the portion of the source string up to
567 * the provided delimiter is copied.
568 *
569 * Example:
570 *
571 * str = strpcpy(str,"This is a line of text with no trailing newline","x");
572 * printf("%s\n",str);
573 *
574 * Produces:
575 *
576 *This is a line of te
577 *
578 *****************************************************************************/
580 char *
581 strpcpy (char *dest, const char *src, const char *str)
582 {
583 size_t len;
585 if (src)
586 len = strcspn (src, str);
587 else
588 return NULL;
590 if (dest == NULL || strlen (dest) < len)
591 dest = realloc (dest, len + 1);
592 if (dest == NULL)
593 die (STATE_UNKNOWN, _("failed realloc in strpcpy\n"));
595 strncpy (dest, src, len);
596 dest[len] = '\0';
598 return dest;
599 }
603 /******************************************************************************
604 *
605 * Like strscat, except only the portion of the source string up to
606 * the provided delimiter is copied.
607 *
608 * str = strpcpy(str,"This is a line of text with no trailing newline","x");
609 * str = strpcat(str,"This is a line of text with no trailing newline","x");
610 * printf("%s\n",str);
611 *
612 *This is a line of texThis is a line of tex
613 *
614 *****************************************************************************/
616 char *
617 strpcat (char *dest, const char *src, const char *str)
618 {
619 size_t len, l2;
621 if (dest)
622 len = strlen (dest);
623 else
624 len = 0;
626 if (src) {
627 l2 = strcspn (src, str);
628 }
629 else {
630 return dest;
631 }
633 dest = realloc (dest, len + l2 + 1);
634 if (dest == NULL)
635 die (STATE_UNKNOWN, _("failed malloc in strscat\n"));
637 strncpy (dest + len, src, l2);
638 dest[len + l2] = '\0';
640 return dest;
641 }
643 /******************************************************************************
644 *
645 * Print perfdata in a standard format
646 *
647 ******************************************************************************/
649 char *perfdata (const char *label,
650 long int val,
651 const char *uom,
652 int warnp,
653 long int warn,
654 int critp,
655 long int crit,
656 int minp,
657 long int minv,
658 int maxp,
659 long int maxv)
660 {
661 char *data = NULL;
663 if (strpbrk (label, "'= "))
664 asprintf (&data, "'%s'=%ld%s;", label, val, uom);
665 else
666 asprintf (&data, "%s=%ld%s;", label, val, uom);
668 if (warnp)
669 asprintf (&data, "%s%ld;", data, warn);
670 else
671 asprintf (&data, "%s;", data);
673 if (critp)
674 asprintf (&data, "%s%ld;", data, crit);
675 else
676 asprintf (&data, "%s;", data);
678 if (minp)
679 asprintf (&data, "%s%ld", data, minv);
681 if (maxp)
682 asprintf (&data, "%s;%ld", data, maxv);
684 return data;
685 }
688 char *fperfdata (const char *label,
689 double val,
690 const char *uom,
691 int warnp,
692 double warn,
693 int critp,
694 double crit,
695 int minp,
696 double minv,
697 int maxp,
698 double maxv)
699 {
700 char *data = NULL;
702 if (strpbrk (label, "'= "))
703 asprintf (&data, "'%s'=", label);
704 else
705 asprintf (&data, "%s=", label);
707 asprintf (&data, "%s%f", data, val);
708 asprintf (&data, "%s%s;", data, uom);
710 if (warnp)
711 asprintf (&data, "%s%f", data, warn);
713 asprintf (&data, "%s;", data);
715 if (critp)
716 asprintf (&data, "%s%f", data, crit);
718 asprintf (&data, "%s;", data);
720 if (minp)
721 asprintf (&data, "%s%f", data, minv);
723 if (maxp) {
724 asprintf (&data, "%s;", data);
725 asprintf (&data, "%s%f", data, maxv);
726 }
728 return data;
729 }
731 char *np_escaped_string (const char *string) {
732 char *data;
733 int i, j=0;
734 data = strdup(string);
735 for (i=0; data[i]; i++) {
736 if (data[i] == '\\') {
737 switch(data[++i]) {
738 case 'n':
739 data[j++] = '\n';
740 break;
741 case 'r':
742 data[j++] = '\r';
743 break;
744 case 't':
745 data[j++] = '\t';
746 break;
747 case '\\':
748 data[j++] = '\\';
749 break;
750 default:
751 data[j++] = data[i];
752 }
753 } else {
754 data[j++] = data[i];
755 }
756 }
757 data[j] = '\0';
758 return data;
759 }