/***************************************************************************** * * Library of useful functions for plugins * * License: GPL * Copyright (c) 2000 Karl DeBisschop (karl@debisschop.net) * Copyright (c) 2002-2024 Monitoring Plugins Development Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * *****************************************************************************/ #include "common.h" #include "./utils.h" #include "utils_base.h" #include #include #include #include #include #include extern void print_usage(void); extern const char *progname; #define STRLEN 64 #define TXTBLK 128 time_t start_time, end_time; /* ************************************************************************** * max_state(STATE_x, STATE_y) * compares STATE_x to STATE_y and returns result based on the following * STATE_UNKNOWN < STATE_OK < STATE_WARNING < STATE_CRITICAL * * Note that numerically the above does not hold ****************************************************************************/ int max_state(int a, int b) { if (a == STATE_CRITICAL || b == STATE_CRITICAL) return STATE_CRITICAL; else if (a == STATE_WARNING || b == STATE_WARNING) return STATE_WARNING; else if (a == STATE_OK || b == STATE_OK) return STATE_OK; else if (a == STATE_UNKNOWN || b == STATE_UNKNOWN) return STATE_UNKNOWN; else if (a == STATE_DEPENDENT || b == STATE_DEPENDENT) return STATE_DEPENDENT; else return max(a, b); } /* ************************************************************************** * max_state_alt(STATE_x, STATE_y) * compares STATE_x to STATE_y and returns result based on the following * STATE_OK < STATE_DEPENDENT < STATE_UNKNOWN < STATE_WARNING < STATE_CRITICAL * * The main difference between max_state_alt and max_state it that it doesn't * allow setting a default to UNKNOWN. It will instead prioritixe any valid * non-OK state. ****************************************************************************/ int max_state_alt(int a, int b) { if (a == STATE_CRITICAL || b == STATE_CRITICAL) return STATE_CRITICAL; else if (a == STATE_WARNING || b == STATE_WARNING) return STATE_WARNING; else if (a == STATE_UNKNOWN || b == STATE_UNKNOWN) return STATE_UNKNOWN; else if (a == STATE_DEPENDENT || b == STATE_DEPENDENT) return STATE_DEPENDENT; else if (a == STATE_OK || b == STATE_OK) return STATE_OK; else return max(a, b); } void usage(const char *msg) { printf("%s\n", msg); print_usage(); exit(STATE_UNKNOWN); } void usage_va(const char *fmt, ...) { va_list ap; printf("%s: ", progname); va_start(ap, fmt); vprintf(fmt, ap); va_end(ap); printf("\n"); exit(STATE_UNKNOWN); } void usage2(const char *msg, const char *arg) { printf("%s: %s - %s\n", progname, msg, arg ? arg : "(null)"); print_usage(); exit(STATE_UNKNOWN); } void usage3(const char *msg, int arg) { printf("%s: %s - %c\n", progname, msg, arg); print_usage(); exit(STATE_UNKNOWN); } void usage4(const char *msg) { printf("%s: %s\n", progname, msg); print_usage(); exit(STATE_UNKNOWN); } void usage5(void) { print_usage(); exit(STATE_UNKNOWN); } void print_revision(const char *command_name, const char *revision) { printf("%s v%s (%s %s)\n", command_name, revision, PACKAGE, VERSION); } bool is_numeric(char *number) { char tmp[1]; float x; if (!number) return false; else if (sscanf(number, "%f%c", &x, tmp) == 1) return true; else return false; } bool is_positive(char *number) { if (is_numeric(number) && atof(number) > 0.0) return true; else return false; } bool is_negative(char *number) { if (is_numeric(number) && atof(number) < 0.0) return true; else return false; } bool is_nonnegative(char *number) { if (is_numeric(number) && atof(number) >= 0.0) return true; else return false; } bool is_percentage(char *number) { int x; if (is_numeric(number) && (x = atof(number)) >= 0 && x <= 100) return true; else return false; } bool is_percentage_expression(const char str[]) { if (!str) { return false; } size_t len = strlen(str); if (str[len - 1] != '%') { return false; } char *foo = calloc(len + 1, sizeof(char)); if (!foo) { die(STATE_UNKNOWN, _("calloc failed \n")); } strcpy(foo, str); foo[len - 1] = '\0'; bool result = is_numeric(foo); free(foo); return result; } bool is_integer(char *number) { long int n; if (!number || (strspn(number, "-0123456789 ") != strlen(number))) return false; n = strtol(number, NULL, 10); if (errno != ERANGE && n >= INT_MIN && n <= INT_MAX) return true; else return false; } bool is_intpos(char *number) { if (is_integer(number) && atoi(number) > 0) return true; else return false; } bool is_intneg(char *number) { if (is_integer(number) && atoi(number) < 0) return true; else return false; } bool is_intnonneg(char *number) { if (is_integer(number) && atoi(number) >= 0) return true; else return false; } /* * Checks whether the number in the string _number_ can be put inside a int64_t * On success the number will be written to the _target_ address, if _target_ is not set * to NULL. */ bool is_int64(char *number, int64_t *target) { errno = 0; char *endptr = {0}; int64_t tmp = strtoll(number, &endptr, 10); if (errno != 0) { return false; } if (*endptr == '\0') { return 0; } if (tmp < INT64_MIN || tmp > INT64_MAX) { return false; } if (target != NULL) { *target = tmp; } return true; } /* * Checks whether the number in the string _number_ can be put inside a uint64_t * On success the number will be written to the _target_ address, if _target_ is not set * to NULL. */ bool is_uint64(char *number, uint64_t *target) { errno = 0; char *endptr = {0}; unsigned long long tmp = strtoull(number, &endptr, 10); if (errno != 0) { return false; } if (*endptr != '\0') { return false; } if (tmp > UINT64_MAX) { return false; } if (target != NULL) { *target = (uint64_t)tmp; } return true; } bool is_intpercent(char *number) { int i; if (is_integer(number) && (i = atoi(number)) >= 0 && i <= 100) return true; else return false; } bool is_option(char *str) { if (!str) return false; else if (strspn(str, "-") == 1 || strspn(str, "-") == 2) return true; else return false; } #ifdef NEED_GETTIMEOFDAY int gettimeofday(struct timeval *tv, struct timezone *tz) { tv->tv_usec = 0; tv->tv_sec = (long)time((time_t)0); } #endif double delta_time(struct timeval tv) { struct timeval now; gettimeofday(&now, NULL); return ((double)(now.tv_sec - tv.tv_sec) + (double)(now.tv_usec - tv.tv_usec) / (double)1000000); } long deltime(struct timeval tv) { struct timeval now; gettimeofday(&now, NULL); return (now.tv_sec - tv.tv_sec) * 1000000 + now.tv_usec - tv.tv_usec; } void strip(char *buffer) { size_t x; int i; for (x = strlen(buffer); x >= 1; x--) { i = x - 1; if (buffer[i] == ' ' || buffer[i] == '\r' || buffer[i] == '\n' || buffer[i] == '\t') buffer[i] = '\0'; else break; } return; } /****************************************************************************** * * Copies one string to another. Any previously existing data in * the destination string is lost. * * Example: * * char *str=NULL; * str = strscpy("This is a line of text with no trailing newline"); * *****************************************************************************/ char *strscpy(char *dest, const char *src) { if (src == NULL) return NULL; xasprintf(&dest, "%s", src); return dest; } /****************************************************************************** * * Returns a pointer to the next line of a multiline string buffer * * Given a pointer string, find the text following the next sequence * of \r and \n characters. This has the effect of skipping blank * lines as well * * Example: * * Given text as follows: * * ============================== * This * is * a * * multiline string buffer * ============================== * * int i=0; * char *str=NULL; * char *ptr=NULL; * str = strscpy(str,"This\nis\r\na\n\nmultiline string buffer\n"); * ptr = str; * while (ptr) { * printf("%d %s",i++,firstword(ptr)); * ptr = strnl(ptr); * } * * Produces the following: * * 1 This * 2 is * 3 a * 4 multiline * * NOTE: The 'firstword()' function is conceptual only and does not * exist in this package. * * NOTE: Although the second 'ptr' variable is not strictly needed in * this example, it is good practice with these utilities. Once * the * pointer is advance in this manner, it may no longer be * handled with * realloc(). So at the end of the code fragment * above, * strscpy(str,"foo") work perfectly fine, but * strscpy(ptr,"foo") will * cause the the program to crash with * a segmentation fault. * *****************************************************************************/ char *strnl(char *str) { size_t len; if (str == NULL) return NULL; str = strpbrk(str, "\r\n"); if (str == NULL) return NULL; len = strspn(str, "\r\n"); if (str[len] == '\0') return NULL; str += len; if (strlen(str) == 0) return NULL; return str; } /****************************************************************************** * * Like strscpy, except only the portion of the source string up to * the provided delimiter is copied. * * Example: * * str = strpcpy(str,"This is a line of text with no trailing newline","x"); * printf("%s\n",str); * * Produces: * *This is a line of te * *****************************************************************************/ char *strpcpy(char *dest, const char *src, const char *str) { size_t len; if (src) len = strcspn(src, str); else return NULL; if (dest == NULL || strlen(dest) < len) dest = realloc(dest, len + 1); if (dest == NULL) die(STATE_UNKNOWN, _("failed realloc in strpcpy\n")); strncpy(dest, src, len); dest[len] = '\0'; return dest; } /****************************************************************************** * * Like strscat, except only the portion of the source string up to * the provided delimiter is copied. * * str = strpcpy(str,"This is a line of text with no trailing newline","x"); * str = strpcat(str,"This is a line of text with no trailing newline","x"); * printf("%s\n",str); * *This is a line of texThis is a line of tex * *****************************************************************************/ char *strpcat(char *dest, const char *src, const char *str) { size_t len, l2; if (dest) len = strlen(dest); else len = 0; if (src) { l2 = strcspn(src, str); } else { return dest; } dest = realloc(dest, len + l2 + 1); if (dest == NULL) die(STATE_UNKNOWN, _("failed malloc in strscat\n")); strncpy(dest + len, src, l2); dest[len + l2] = '\0'; return dest; } /****************************************************************************** * * asprintf, but die on failure * ******************************************************************************/ int xvasprintf(char **strp, const char *fmt, va_list ap) { int result = vasprintf(strp, fmt, ap); if (result == -1 || *strp == NULL) die(STATE_UNKNOWN, _("failed malloc in xvasprintf\n")); return result; } int xasprintf(char **strp, const char *fmt, ...) { va_list ap; int result; va_start(ap, fmt); result = xvasprintf(strp, fmt, ap); va_end(ap); return result; } /****************************************************************************** * * Print perfdata in a standard format * ******************************************************************************/ char *perfdata(const char *label, long int val, const char *uom, int warnp, long int warn, int critp, long int crit, int minp, long int minv, int maxp, long int maxv) { char *data = NULL; if (strpbrk(label, "'= ")) xasprintf(&data, "'%s'=%ld%s;", label, val, uom); else xasprintf(&data, "%s=%ld%s;", label, val, uom); if (warnp) xasprintf(&data, "%s%ld;", data, warn); else xasprintf(&data, "%s;", data); if (critp) xasprintf(&data, "%s%ld;", data, crit); else xasprintf(&data, "%s;", data); if (minp) xasprintf(&data, "%s%ld;", data, minv); else xasprintf(&data, "%s;", data); if (maxp) xasprintf(&data, "%s%ld", data, maxv); return data; } char *perfdata_uint64(const char *label, uint64_t val, const char *uom, int warnp, /* Warning present */ uint64_t warn, int critp, /* Critical present */ uint64_t crit, int minp, /* Minimum present */ uint64_t minv, int maxp, /* Maximum present */ uint64_t maxv) { char *data = NULL; if (strpbrk(label, "'= ")) xasprintf(&data, "'%s'=%" PRIu64 "%s;", label, val, uom); else xasprintf(&data, "%s=%" PRIu64 "%s;", label, val, uom); if (warnp) xasprintf(&data, "%s%" PRIu64 ";", data, warn); else xasprintf(&data, "%s;", data); if (critp) xasprintf(&data, "%s%" PRIu64 ";", data, crit); else xasprintf(&data, "%s;", data); if (minp) xasprintf(&data, "%s%" PRIu64 ";", data, minv); else xasprintf(&data, "%s;", data); if (maxp) xasprintf(&data, "%s%" PRIu64, data, maxv); return data; } char *perfdata_int64(const char *label, int64_t val, const char *uom, int warnp, /* Warning present */ int64_t warn, int critp, /* Critical present */ int64_t crit, int minp, /* Minimum present */ int64_t minv, int maxp, /* Maximum present */ int64_t maxv) { char *data = NULL; if (strpbrk(label, "'= ")) xasprintf(&data, "'%s'=%" PRId64 "%s;", label, val, uom); else xasprintf(&data, "%s=%" PRId64 "%s;", label, val, uom); if (warnp) xasprintf(&data, "%s%" PRId64 ";", data, warn); else xasprintf(&data, "%s;", data); if (critp) xasprintf(&data, "%s%" PRId64 ";", data, crit); else xasprintf(&data, "%s;", data); if (minp) xasprintf(&data, "%s%" PRId64 ";", data, minv); else xasprintf(&data, "%s;", data); if (maxp) xasprintf(&data, "%s%" PRId64, data, maxv); return data; } char *fperfdata(const char *label, double val, const char *uom, int warnp, double warn, int critp, double crit, int minp, double minv, int maxp, double maxv) { char *data = NULL; if (strpbrk(label, "'= ")) xasprintf(&data, "'%s'=", label); else xasprintf(&data, "%s=", label); xasprintf(&data, "%s%f", data, val); xasprintf(&data, "%s%s;", data, uom); if (warnp) xasprintf(&data, "%s%f", data, warn); xasprintf(&data, "%s;", data); if (critp) xasprintf(&data, "%s%f", data, crit); xasprintf(&data, "%s;", data); if (minp) xasprintf(&data, "%s%f", data, minv); if (maxp) { xasprintf(&data, "%s;", data); xasprintf(&data, "%s%f", data, maxv); } return data; } char *sperfdata(const char *label, double val, const char *uom, char *warn, char *crit, int minp, double minv, int maxp, double maxv) { char *data = NULL; if (strpbrk(label, "'= ")) xasprintf(&data, "'%s'=", label); else xasprintf(&data, "%s=", label); xasprintf(&data, "%s%f", data, val); xasprintf(&data, "%s%s;", data, uom); if (warn != NULL) xasprintf(&data, "%s%s", data, warn); xasprintf(&data, "%s;", data); if (crit != NULL) xasprintf(&data, "%s%s", data, crit); xasprintf(&data, "%s;", data); if (minp) xasprintf(&data, "%s%f", data, minv); if (maxp) { xasprintf(&data, "%s;", data); xasprintf(&data, "%s%f", data, maxv); } return data; } char *sperfdata_int(const char *label, int val, const char *uom, char *warn, char *crit, int minp, int minv, int maxp, int maxv) { char *data = NULL; if (strpbrk(label, "'= ")) xasprintf(&data, "'%s'=", label); else xasprintf(&data, "%s=", label); xasprintf(&data, "%s%d", data, val); xasprintf(&data, "%s%s;", data, uom); if (warn != NULL) xasprintf(&data, "%s%s", data, warn); xasprintf(&data, "%s;", data); if (crit != NULL) xasprintf(&data, "%s%s", data, crit); xasprintf(&data, "%s;", data); if (minp) xasprintf(&data, "%s%d", data, minv); if (maxp) { xasprintf(&data, "%s;", data); xasprintf(&data, "%s%d", data, maxv); } return data; }