1 /*****************************************************************************
3 * Library of useful functions for plugins
6 * Copyright (c) 2000 Karl DeBisschop (karl@debisschop.net)
7 * Copyright (c) 2002-2024 Monitoring Plugins Development Team
9 * This program is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation, either version 3 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <http://www.gnu.org/licenses/>.
23 *****************************************************************************/
27 #include "utils_base.h"
35 #include <arpa/inet.h>
37 extern void print_usage(void);
38 extern const char *progname
;
43 time_t start_time
, end_time
;
45 /* **************************************************************************
46 * max_state(STATE_x, STATE_y)
47 * compares STATE_x to STATE_y and returns result based on the following
48 * STATE_UNKNOWN < STATE_OK < STATE_WARNING < STATE_CRITICAL
50 * Note that numerically the above does not hold
51 ****************************************************************************/
53 int max_state(int a
, int b
) {
54 if (a
== STATE_CRITICAL
|| b
== STATE_CRITICAL
)
55 return STATE_CRITICAL
;
56 else if (a
== STATE_WARNING
|| b
== STATE_WARNING
)
58 else if (a
== STATE_OK
|| b
== STATE_OK
)
60 else if (a
== STATE_UNKNOWN
|| b
== STATE_UNKNOWN
)
62 else if (a
== STATE_DEPENDENT
|| b
== STATE_DEPENDENT
)
63 return STATE_DEPENDENT
;
68 /* **************************************************************************
69 * max_state_alt(STATE_x, STATE_y)
70 * compares STATE_x to STATE_y and returns result based on the following
71 * STATE_OK < STATE_DEPENDENT < STATE_UNKNOWN < STATE_WARNING < STATE_CRITICAL
73 * The main difference between max_state_alt and max_state it that it doesn't
74 * allow setting a default to UNKNOWN. It will instead prioritixe any valid
76 ****************************************************************************/
78 int max_state_alt(int a
, int b
) {
79 if (a
== STATE_CRITICAL
|| b
== STATE_CRITICAL
)
80 return STATE_CRITICAL
;
81 else if (a
== STATE_WARNING
|| b
== STATE_WARNING
)
83 else if (a
== STATE_UNKNOWN
|| b
== STATE_UNKNOWN
)
85 else if (a
== STATE_DEPENDENT
|| b
== STATE_DEPENDENT
)
86 return STATE_DEPENDENT
;
87 else if (a
== STATE_OK
|| b
== STATE_OK
)
93 void usage(const char *msg
) {
99 void usage_va(const char *fmt
, ...) {
101 printf("%s: ", progname
);
109 void usage2(const char *msg
, const char *arg
) {
110 printf("%s: %s - %s\n", progname
, msg
, arg
? arg
: "(null)");
115 void usage3(const char *msg
, int arg
) {
116 printf("%s: %s - %c\n", progname
, msg
, arg
);
121 void usage4(const char *msg
) {
122 printf("%s: %s\n", progname
, msg
);
132 void print_revision(const char *command_name
, const char *revision
) {
133 printf("%s v%s (%s %s)\n", command_name
, revision
, PACKAGE
, VERSION
);
136 bool is_numeric(char *number
) {
142 else if (sscanf(number
, "%f%c", &x
, tmp
) == 1)
148 bool is_positive(char *number
) {
149 if (is_numeric(number
) && atof(number
) > 0.0)
155 bool is_negative(char *number
) {
156 if (is_numeric(number
) && atof(number
) < 0.0)
162 bool is_nonnegative(char *number
) {
163 if (is_numeric(number
) && atof(number
) >= 0.0)
169 bool is_percentage(char *number
) {
171 if (is_numeric(number
) && (x
= atof(number
)) >= 0 && x
<= 100)
177 bool is_percentage_expression(const char str
[]) {
182 size_t len
= strlen(str
);
184 if (str
[len
- 1] != '%') {
188 char *foo
= calloc(len
+ 1, sizeof(char));
191 die(STATE_UNKNOWN
, _("calloc failed \n"));
197 bool result
= is_numeric(foo
);
204 bool is_integer(char *number
) {
207 if (!number
|| (strspn(number
, "-0123456789 ") != strlen(number
)))
210 n
= strtol(number
, NULL
, 10);
212 if (errno
!= ERANGE
&& n
>= INT_MIN
&& n
<= INT_MAX
)
218 bool is_intpos(char *number
) {
219 if (is_integer(number
) && atoi(number
) > 0)
225 bool is_intneg(char *number
) {
226 if (is_integer(number
) && atoi(number
) < 0)
232 bool is_intnonneg(char *number
) {
233 if (is_integer(number
) && atoi(number
) >= 0)
240 * Checks whether the number in the string _number_ can be put inside a int64_t
241 * On success the number will be written to the _target_ address, if _target_ is not set
244 bool is_int64(char *number
, int64_t *target
) {
248 int64_t tmp
= strtoll(number
, &endptr
, 10);
253 if (*endptr
== '\0') {
257 if (tmp
< INT64_MIN
|| tmp
> INT64_MAX
) {
261 if (target
!= NULL
) {
268 * Checks whether the number in the string _number_ can be put inside a uint64_t
269 * On success the number will be written to the _target_ address, if _target_ is not set
272 bool is_uint64(char *number
, uint64_t *target
) {
275 unsigned long long tmp
= strtoull(number
, &endptr
, 10);
281 if (*endptr
!= '\0') {
285 if (tmp
> UINT64_MAX
) {
289 if (target
!= NULL
) {
290 *target
= (uint64_t)tmp
;
296 bool is_intpercent(char *number
) {
298 if (is_integer(number
) && (i
= atoi(number
)) >= 0 && i
<= 100)
304 bool is_option(char *str
) {
307 else if (strspn(str
, "-") == 1 || strspn(str
, "-") == 2)
313 #ifdef NEED_GETTIMEOFDAY
314 int gettimeofday(struct timeval
*tv
, struct timezone
*tz
) {
316 tv
->tv_sec
= (long)time((time_t)0);
320 double delta_time(struct timeval tv
) {
323 gettimeofday(&now
, NULL
);
324 return ((double)(now
.tv_sec
- tv
.tv_sec
) + (double)(now
.tv_usec
- tv
.tv_usec
) / (double)1000000);
327 long deltime(struct timeval tv
) {
329 gettimeofday(&now
, NULL
);
330 return (now
.tv_sec
- tv
.tv_sec
) * 1000000 + now
.tv_usec
- tv
.tv_usec
;
333 void strip(char *buffer
) {
337 for (x
= strlen(buffer
); x
>= 1; x
--) {
339 if (buffer
[i
] == ' ' || buffer
[i
] == '\r' || buffer
[i
] == '\n' || buffer
[i
] == '\t')
347 /******************************************************************************
349 * Copies one string to another. Any previously existing data in
350 * the destination string is lost.
355 * str = strscpy("This is a line of text with no trailing newline");
357 *****************************************************************************/
359 char *strscpy(char *dest
, const char *src
) {
363 xasprintf(&dest
, "%s", src
);
368 /******************************************************************************
370 * Returns a pointer to the next line of a multiline string buffer
372 * Given a pointer string, find the text following the next sequence
373 * of \r and \n characters. This has the effect of skipping blank
378 * Given text as follows:
380 * ==============================
385 * multiline string buffer
386 * ==============================
391 * str = strscpy(str,"This\nis\r\na\n\nmultiline string buffer\n");
394 * printf("%d %s",i++,firstword(ptr));
398 * Produces the following:
405 * NOTE: The 'firstword()' function is conceptual only and does not
406 * exist in this package.
408 * NOTE: Although the second 'ptr' variable is not strictly needed in
409 * this example, it is good practice with these utilities. Once
410 * the * pointer is advance in this manner, it may no longer be
411 * handled with * realloc(). So at the end of the code fragment
412 * above, * strscpy(str,"foo") work perfectly fine, but
413 * strscpy(ptr,"foo") will * cause the the program to crash with
414 * a segmentation fault.
416 *****************************************************************************/
418 char *strnl(char *str
) {
422 str
= strpbrk(str
, "\r\n");
425 len
= strspn(str
, "\r\n");
426 if (str
[len
] == '\0')
429 if (strlen(str
) == 0)
434 /******************************************************************************
436 * Like strscpy, except only the portion of the source string up to
437 * the provided delimiter is copied.
441 * str = strpcpy(str,"This is a line of text with no trailing newline","x");
442 * printf("%s\n",str);
446 *This is a line of te
448 *****************************************************************************/
450 char *strpcpy(char *dest
, const char *src
, const char *str
) {
454 len
= strcspn(src
, str
);
458 if (dest
== NULL
|| strlen(dest
) < len
)
459 dest
= realloc(dest
, len
+ 1);
461 die(STATE_UNKNOWN
, _("failed realloc in strpcpy\n"));
463 strncpy(dest
, src
, len
);
469 /******************************************************************************
471 * Like strscat, except only the portion of the source string up to
472 * the provided delimiter is copied.
474 * str = strpcpy(str,"This is a line of text with no trailing newline","x");
475 * str = strpcat(str,"This is a line of text with no trailing newline","x");
476 * printf("%s\n",str);
478 *This is a line of texThis is a line of tex
480 *****************************************************************************/
482 char *strpcat(char *dest
, const char *src
, const char *str
) {
491 l2
= strcspn(src
, str
);
496 dest
= realloc(dest
, len
+ l2
+ 1);
498 die(STATE_UNKNOWN
, _("failed malloc in strscat\n"));
500 strncpy(dest
+ len
, src
, l2
);
501 dest
[len
+ l2
] = '\0';
506 /******************************************************************************
508 * asprintf, but die on failure
510 ******************************************************************************/
512 int xvasprintf(char **strp
, const char *fmt
, va_list ap
) {
513 int result
= vasprintf(strp
, fmt
, ap
);
514 if (result
== -1 || *strp
== NULL
)
515 die(STATE_UNKNOWN
, _("failed malloc in xvasprintf\n"));
519 int xasprintf(char **strp
, const char *fmt
, ...) {
523 result
= xvasprintf(strp
, fmt
, ap
);
528 /******************************************************************************
530 * Print perfdata in a standard format
532 ******************************************************************************/
534 char *perfdata(const char *label
, long int val
, const char *uom
, int warnp
, long int warn
, int critp
, long int crit
, int minp
,
535 long int minv
, int maxp
, long int maxv
) {
538 if (strpbrk(label
, "'= "))
539 xasprintf(&data
, "'%s'=%ld%s;", label
, val
, uom
);
541 xasprintf(&data
, "%s=%ld%s;", label
, val
, uom
);
544 xasprintf(&data
, "%s%ld;", data
, warn
);
546 xasprintf(&data
, "%s;", data
);
549 xasprintf(&data
, "%s%ld;", data
, crit
);
551 xasprintf(&data
, "%s;", data
);
554 xasprintf(&data
, "%s%ld;", data
, minv
);
556 xasprintf(&data
, "%s;", data
);
559 xasprintf(&data
, "%s%ld", data
, maxv
);
564 char *perfdata_uint64(const char *label
, uint64_t val
, const char *uom
, int warnp
, /* Warning present */
565 uint64_t warn
, int critp
, /* Critical present */
566 uint64_t crit
, int minp
, /* Minimum present */
567 uint64_t minv
, int maxp
, /* Maximum present */
571 if (strpbrk(label
, "'= "))
572 xasprintf(&data
, "'%s'=%" PRIu64
"%s;", label
, val
, uom
);
574 xasprintf(&data
, "%s=%" PRIu64
"%s;", label
, val
, uom
);
577 xasprintf(&data
, "%s%" PRIu64
";", data
, warn
);
579 xasprintf(&data
, "%s;", data
);
582 xasprintf(&data
, "%s%" PRIu64
";", data
, crit
);
584 xasprintf(&data
, "%s;", data
);
587 xasprintf(&data
, "%s%" PRIu64
";", data
, minv
);
589 xasprintf(&data
, "%s;", data
);
592 xasprintf(&data
, "%s%" PRIu64
, data
, maxv
);
597 char *perfdata_int64(const char *label
, int64_t val
, const char *uom
, int warnp
, /* Warning present */
598 int64_t warn
, int critp
, /* Critical present */
599 int64_t crit
, int minp
, /* Minimum present */
600 int64_t minv
, int maxp
, /* Maximum present */
604 if (strpbrk(label
, "'= "))
605 xasprintf(&data
, "'%s'=%" PRId64
"%s;", label
, val
, uom
);
607 xasprintf(&data
, "%s=%" PRId64
"%s;", label
, val
, uom
);
610 xasprintf(&data
, "%s%" PRId64
";", data
, warn
);
612 xasprintf(&data
, "%s;", data
);
615 xasprintf(&data
, "%s%" PRId64
";", data
, crit
);
617 xasprintf(&data
, "%s;", data
);
620 xasprintf(&data
, "%s%" PRId64
";", data
, minv
);
622 xasprintf(&data
, "%s;", data
);
625 xasprintf(&data
, "%s%" PRId64
, data
, maxv
);
630 char *fperfdata(const char *label
, double val
, const char *uom
, int warnp
, double warn
, int critp
, double crit
, int minp
, double minv
,
631 int maxp
, double maxv
) {
634 if (strpbrk(label
, "'= "))
635 xasprintf(&data
, "'%s'=", label
);
637 xasprintf(&data
, "%s=", label
);
639 xasprintf(&data
, "%s%f", data
, val
);
640 xasprintf(&data
, "%s%s;", data
, uom
);
643 xasprintf(&data
, "%s%f", data
, warn
);
645 xasprintf(&data
, "%s;", data
);
648 xasprintf(&data
, "%s%f", data
, crit
);
650 xasprintf(&data
, "%s;", data
);
653 xasprintf(&data
, "%s%f", data
, minv
);
656 xasprintf(&data
, "%s;", data
);
657 xasprintf(&data
, "%s%f", data
, maxv
);
663 char *sperfdata(const char *label
, double val
, const char *uom
, char *warn
, char *crit
, int minp
, double minv
, int maxp
, double maxv
) {
665 if (strpbrk(label
, "'= "))
666 xasprintf(&data
, "'%s'=", label
);
668 xasprintf(&data
, "%s=", label
);
670 xasprintf(&data
, "%s%f", data
, val
);
671 xasprintf(&data
, "%s%s;", data
, uom
);
674 xasprintf(&data
, "%s%s", data
, warn
);
676 xasprintf(&data
, "%s;", data
);
679 xasprintf(&data
, "%s%s", data
, crit
);
681 xasprintf(&data
, "%s;", data
);
684 xasprintf(&data
, "%s%f", data
, minv
);
687 xasprintf(&data
, "%s;", data
);
688 xasprintf(&data
, "%s%f", data
, maxv
);
694 char *sperfdata_int(const char *label
, int val
, const char *uom
, char *warn
, char *crit
, int minp
, int minv
, int maxp
, int maxv
) {
696 if (strpbrk(label
, "'= "))
697 xasprintf(&data
, "'%s'=", label
);
699 xasprintf(&data
, "%s=", label
);
701 xasprintf(&data
, "%s%d", data
, val
);
702 xasprintf(&data
, "%s%s;", data
, uom
);
705 xasprintf(&data
, "%s%s", data
, warn
);
707 xasprintf(&data
, "%s;", data
);
710 xasprintf(&data
, "%s%s", data
, crit
);
712 xasprintf(&data
, "%s;", data
);
715 xasprintf(&data
, "%s%d", data
, minv
);
718 xasprintf(&data
, "%s;", data
);
719 xasprintf(&data
, "%s%d", data
, maxv
);