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 #define LOCAL_TIMEOUT_ALARM_HANDLER
16 #include "common.h"
17 #include "utils.h"
18 #include <stdarg.h>
19 #include <limits.h>
21 #include <arpa/inet.h>
23 extern void print_usage (void);
24 extern const char *progname;
26 #define STRLEN 64
27 #define TXTBLK 128
29 /* **************************************************************************
30 * max_state(STATE_x, STATE_y)
31 * compares STATE_x to STATE_y and returns result based on the following
32 * STATE_UNKNOWN < STATE_OK < STATE_WARNING < STATE_CRITICAL
33 *
34 * Note that numerically the above does not hold
35 ****************************************************************************/
37 int
38 max_state (int a, int b)
39 {
40 if (a == STATE_CRITICAL || b == STATE_CRITICAL)
41 return STATE_CRITICAL;
42 else if (a == STATE_WARNING || b == STATE_WARNING)
43 return STATE_WARNING;
44 else if (a == STATE_OK || b == STATE_OK)
45 return STATE_OK;
46 else if (a == STATE_UNKNOWN || b == STATE_UNKNOWN)
47 return STATE_UNKNOWN;
48 else if (a == STATE_DEPENDENT || b == STATE_DEPENDENT)
49 return STATE_DEPENDENT;
50 else
51 return max (a, b);
52 }
54 void usage (const char *msg)
55 {
56 printf ("%s\n", msg);
57 print_usage ();
58 exit (STATE_UNKNOWN);
59 }
61 void usage_va (const char *fmt, ...)
62 {
63 va_list ap;
64 printf("%s: ", progname);
65 va_start(ap, fmt);
66 vprintf(fmt, ap);
67 va_end(ap);
68 printf("\n");
69 exit (STATE_UNKNOWN);
70 }
72 void usage2(const char *msg, const char *arg)
73 {
74 printf ("%s: %s - %s\n",progname,msg,arg);
75 print_usage ();
76 exit (STATE_UNKNOWN);
77 }
79 void
80 usage3 (const char *msg, int arg)
81 {
82 printf ("%s: %s - %c\n", progname, msg, arg);
83 print_usage();
84 exit (STATE_UNKNOWN);
85 }
87 void
88 usage4 (const char *msg)
89 {
90 printf ("%s: %s\n", progname, msg);
91 print_usage();
92 exit (STATE_UNKNOWN);
93 }
95 char *
96 clean_revstring (const char *revstring)
97 {
98 char plugin_revision[STRLEN];
99 if (sscanf (revstring,"$Revision: %[0-9.]",plugin_revision) == 1)
100 return strscpy (NULL, plugin_revision);
101 else
102 return strscpy (NULL, "N/A");
103 }
105 void
106 print_revision (const char *command_name, const char *revision_string)
107 {
108 char plugin_revision[STRLEN];
110 if (sscanf (revision_string, "$Revision: %[0-9.]", plugin_revision) != 1)
111 strncpy (plugin_revision, "N/A", STRLEN);
112 printf ("%s (%s %s) %s\n",
113 command_name, PACKAGE, VERSION, plugin_revision);
114 }
116 const char *
117 state_text (int result)
118 {
119 switch (result) {
120 case STATE_OK:
121 return "OK";
122 case STATE_WARNING:
123 return "WARNING";
124 case STATE_CRITICAL:
125 return "CRITICAL";
126 case STATE_DEPENDENT:
127 return "DEPENDENT";
128 default:
129 return "UNKNOWN";
130 }
131 }
133 void
134 die (int result, const char *fmt, ...)
135 {
136 va_list ap;
137 va_start (ap, fmt);
138 vprintf (fmt, ap);
139 va_end (ap);
140 exit (result);
141 }
143 void
144 timeout_alarm_handler (int signo)
145 {
146 if (signo == SIGALRM) {
147 printf (_("CRITICAL - Plugin timed out after %d seconds\n"),
148 timeout_interval);
149 exit (STATE_CRITICAL);
150 }
151 }
153 int
154 is_numeric (char *number)
155 {
156 char tmp[1];
157 float x;
159 if (!number)
160 return FALSE;
161 else if (sscanf (number, "%f%c", &x, tmp) == 1)
162 return TRUE;
163 else
164 return FALSE;
165 }
167 int
168 is_positive (char *number)
169 {
170 if (is_numeric (number) && atof (number) > 0.0)
171 return TRUE;
172 else
173 return FALSE;
174 }
176 int
177 is_negative (char *number)
178 {
179 if (is_numeric (number) && atof (number) < 0.0)
180 return TRUE;
181 else
182 return FALSE;
183 }
185 int
186 is_nonnegative (char *number)
187 {
188 if (is_numeric (number) && atof (number) >= 0.0)
189 return TRUE;
190 else
191 return FALSE;
192 }
194 int
195 is_percentage (char *number)
196 {
197 int x;
198 if (is_numeric (number) && (x = atof (number)) >= 0 && x <= 100)
199 return TRUE;
200 else
201 return FALSE;
202 }
204 int
205 is_integer (char *number)
206 {
207 long int n;
209 if (!number || (strspn (number, "-0123456789 ") != strlen (number)))
210 return FALSE;
212 n = strtol (number, NULL, 10);
214 if (errno != ERANGE && n >= INT_MIN && n <= INT_MAX)
215 return TRUE;
216 else
217 return FALSE;
218 }
220 int
221 is_intpos (char *number)
222 {
223 if (is_integer (number) && atoi (number) > 0)
224 return TRUE;
225 else
226 return FALSE;
227 }
229 int
230 is_intneg (char *number)
231 {
232 if (is_integer (number) && atoi (number) < 0)
233 return TRUE;
234 else
235 return FALSE;
236 }
238 int
239 is_intnonneg (char *number)
240 {
241 if (is_integer (number) && atoi (number) >= 0)
242 return TRUE;
243 else
244 return FALSE;
245 }
247 int
248 is_intpercent (char *number)
249 {
250 int i;
251 if (is_integer (number) && (i = atoi (number)) >= 0 && i <= 100)
252 return TRUE;
253 else
254 return FALSE;
255 }
257 int
258 is_option (char *str)
259 {
260 if (!str)
261 return FALSE;
262 else if (strspn (str, "-") == 1 || strspn (str, "-") == 2)
263 return TRUE;
264 else
265 return FALSE;
266 }
268 void set_range_start (range *this, double value) {
269 this->start = value;
270 this->start_infinity = FALSE;
271 }
273 void set_range_end (range *this, double value) {
274 this->end = value;
275 this->end_infinity = FALSE;
276 }
278 range
279 *parse_range_string (char *str) {
280 range *temp_range;
281 double start;
282 double end;
283 char *end_str;
285 temp_range = (range *) malloc(sizeof(range));
287 /* Set defaults */
288 temp_range->start = 0;
289 temp_range->start_infinity = FALSE;
290 temp_range->end = 0;
291 temp_range->end_infinity = TRUE;
292 temp_range->alert_on = OUTSIDE;
294 if (str[0] == '@') {
295 temp_range->alert_on = INSIDE;
296 str++;
297 }
299 end_str = index(str, ':');
300 if (end_str != NULL) {
301 if (str[0] == '~') {
302 temp_range->start_infinity = TRUE;
303 } else {
304 start = strtod(str, NULL); /* Will stop at the ':' */
305 set_range_start(temp_range, start);
306 }
307 end_str++; /* Move past the ':' */
308 } else {
309 end_str = str;
310 }
311 end = strtod(end_str, NULL);
312 if (strcmp(end_str, "") != 0) {
313 set_range_end(temp_range, end);
314 }
316 if (temp_range->start_infinity == TRUE ||
317 temp_range->end_infinity == TRUE ||
318 temp_range->start <= temp_range->end) {
319 return temp_range;
320 }
321 free(temp_range);
322 return NULL;
323 }
325 /* returns 0 if okay, otherwise 1 */
326 int
327 _set_thresholds(thresholds **my_thresholds, char *warn_string, char *critical_string)
328 {
329 thresholds *temp_thresholds = NULL;
331 temp_thresholds = malloc(sizeof(temp_thresholds));
333 temp_thresholds->warning = NULL;
334 temp_thresholds->critical = NULL;
336 if (warn_string != NULL) {
337 if ((temp_thresholds->warning = parse_range_string(warn_string)) == NULL) {
338 return 1;
339 }
340 }
341 if (critical_string != NULL) {
342 if ((temp_thresholds->critical = parse_range_string(critical_string)) == NULL) {
343 return 1;
344 }
345 }
347 if (*my_thresholds != 0) {
348 /* printf("Freeing here: %d\n", *my_thresholds); */
349 free(*my_thresholds);
350 }
351 *my_thresholds = temp_thresholds;
353 return 0;
354 }
356 void
357 set_thresholds(thresholds **my_thresholds, char *warn_string, char *critical_string)
358 {
359 if (_set_thresholds(my_thresholds, warn_string, critical_string) == 0) {
360 return;
361 } else {
362 usage("Range format incorrect");
363 }
364 }
366 /* Returns TRUE if alert should be raised based on the range */
367 int
368 check_range(double value, range *my_range)
369 {
370 int false = FALSE;
371 int true = TRUE;
373 if (my_range->alert_on == INSIDE) {
374 false = TRUE;
375 true = FALSE;
376 }
378 if (my_range->end_infinity == FALSE && my_range->start_infinity == FALSE) {
379 if ((my_range->start <= value) && (value <= my_range->end)) {
380 return false;
381 } else {
382 return true;
383 }
384 } else if (my_range->start_infinity == FALSE && my_range->end_infinity == TRUE) {
385 if (my_range->start <= value) {
386 return false;
387 } else {
388 return true;
389 }
390 } else if (my_range->start_infinity == TRUE && my_range->end_infinity == FALSE) {
391 if (value <= my_range->end) {
392 return false;
393 } else {
394 return true;
395 }
396 } else {
397 return false;
398 }
399 }
401 /* Returns status */
402 int
403 get_status(double value, thresholds *my_thresholds)
404 {
405 if (my_thresholds->critical != NULL) {
406 if (check_range(value, my_thresholds->critical) == TRUE) {
407 return STATE_CRITICAL;
408 }
409 }
410 if (my_thresholds->warning != NULL) {
411 if (check_range(value, my_thresholds->warning) == TRUE) {
412 return STATE_WARNING;
413 }
414 }
415 return STATE_OK;
416 }
418 #ifdef NEED_GETTIMEOFDAY
419 int
420 gettimeofday (struct timeval *tv, struct timezone *tz)
421 {
422 tv->tv_usec = 0;
423 tv->tv_sec = (long) time ((time_t) 0);
424 }
425 #endif
429 double
430 delta_time (struct timeval tv)
431 {
432 struct timeval now;
434 gettimeofday (&now, NULL);
435 return ((double)(now.tv_sec - tv.tv_sec) + (double)(now.tv_usec - tv.tv_usec) / (double)1000000);
436 }
440 long
441 deltime (struct timeval tv)
442 {
443 struct timeval now;
444 gettimeofday (&now, NULL);
445 return (now.tv_sec - tv.tv_sec)*1000000 + now.tv_usec - tv.tv_usec;
446 }
451 void
452 strip (char *buffer)
453 {
454 size_t x;
455 int i;
457 for (x = strlen (buffer); x >= 1; x--) {
458 i = x - 1;
459 if (buffer[i] == ' ' ||
460 buffer[i] == '\r' || buffer[i] == '\n' || buffer[i] == '\t')
461 buffer[i] = '\0';
462 else
463 break;
464 }
465 return;
466 }
469 /******************************************************************************
470 *
471 * Copies one string to another. Any previously existing data in
472 * the destination string is lost.
473 *
474 * Example:
475 *
476 * char *str=NULL;
477 * str = strscpy("This is a line of text with no trailing newline");
478 *
479 *****************************************************************************/
481 char *
482 strscpy (char *dest, const char *src)
483 {
484 if (src == NULL)
485 return NULL;
487 asprintf (&dest, "%s", src);
489 return dest;
490 }
494 /******************************************************************************
495 *
496 * Returns a pointer to the next line of a multiline string buffer
497 *
498 * Given a pointer string, find the text following the next sequence
499 * of \r and \n characters. This has the effect of skipping blank
500 * lines as well
501 *
502 * Example:
503 *
504 * Given text as follows:
505 *
506 * ==============================
507 * This
508 * is
509 * a
510 *
511 * multiline string buffer
512 * ==============================
513 *
514 * int i=0;
515 * char *str=NULL;
516 * char *ptr=NULL;
517 * str = strscpy(str,"This\nis\r\na\n\nmultiline string buffer\n");
518 * ptr = str;
519 * while (ptr) {
520 * printf("%d %s",i++,firstword(ptr));
521 * ptr = strnl(ptr);
522 * }
523 *
524 * Produces the following:
525 *
526 * 1 This
527 * 2 is
528 * 3 a
529 * 4 multiline
530 *
531 * NOTE: The 'firstword()' function is conceptual only and does not
532 * exist in this package.
533 *
534 * NOTE: Although the second 'ptr' variable is not strictly needed in
535 * this example, it is good practice with these utilities. Once
536 * the * pointer is advance in this manner, it may no longer be
537 * handled with * realloc(). So at the end of the code fragment
538 * above, * strscpy(str,"foo") work perfectly fine, but
539 * strscpy(ptr,"foo") will * cause the the program to crash with
540 * a segmentation fault.
541 *
542 *****************************************************************************/
544 char *
545 strnl (char *str)
546 {
547 size_t len;
548 if (str == NULL)
549 return NULL;
550 str = strpbrk (str, "\r\n");
551 if (str == NULL)
552 return NULL;
553 len = strspn (str, "\r\n");
554 if (str[len] == '\0')
555 return NULL;
556 str += len;
557 if (strlen (str) == 0)
558 return NULL;
559 return str;
560 }
563 /******************************************************************************
564 *
565 * Like strscpy, except only the portion of the source string up to
566 * the provided delimiter is copied.
567 *
568 * Example:
569 *
570 * str = strpcpy(str,"This is a line of text with no trailing newline","x");
571 * printf("%s\n",str);
572 *
573 * Produces:
574 *
575 *This is a line of te
576 *
577 *****************************************************************************/
579 char *
580 strpcpy (char *dest, const char *src, const char *str)
581 {
582 size_t len;
584 if (src)
585 len = strcspn (src, str);
586 else
587 return NULL;
589 if (dest == NULL || strlen (dest) < len)
590 dest = realloc (dest, len + 1);
591 if (dest == NULL)
592 die (STATE_UNKNOWN, _("failed realloc in strpcpy\n"));
594 strncpy (dest, src, len);
595 dest[len] = '\0';
597 return dest;
598 }
602 /******************************************************************************
603 *
604 * Like strscat, except only the portion of the source string up to
605 * the provided delimiter is copied.
606 *
607 * str = strpcpy(str,"This is a line of text with no trailing newline","x");
608 * str = strpcat(str,"This is a line of text with no trailing newline","x");
609 * printf("%s\n",str);
610 *
611 *This is a line of texThis is a line of tex
612 *
613 *****************************************************************************/
615 char *
616 strpcat (char *dest, const char *src, const char *str)
617 {
618 size_t len, l2;
620 if (dest)
621 len = strlen (dest);
622 else
623 len = 0;
625 if (src) {
626 l2 = strcspn (src, str);
627 }
628 else {
629 return dest;
630 }
632 dest = realloc (dest, len + l2 + 1);
633 if (dest == NULL)
634 die (STATE_UNKNOWN, _("failed malloc in strscat\n"));
636 strncpy (dest + len, src, l2);
637 dest[len + l2] = '\0';
639 return dest;
640 }
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 }