From 0645c9fc2c7f801ba3c7d68a17c137a63ada299f Mon Sep 17 00:00:00 2001 From: Lorenz Kästle <12514511+RincewindsHat@users.noreply.github.com> Date: Tue, 18 Feb 2025 21:58:34 +0100 Subject: Implement new output functionality --- lib/perfdata.c | 516 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 516 insertions(+) create mode 100644 lib/perfdata.c (limited to 'lib/perfdata.c') diff --git a/lib/perfdata.c b/lib/perfdata.c new file mode 100644 index 00000000..f894df39 --- /dev/null +++ b/lib/perfdata.c @@ -0,0 +1,516 @@ +#include "./perfdata.h" +#include "../plugins/common.h" +#include "../plugins/utils.h" +#include "utils_base.h" + +#include +#include +#include + +char *pd_value_to_string(const mp_perfdata_value pd) { + char *result = NULL; + + assert(pd.type != PD_TYPE_NONE); + + switch (pd.type) { + case PD_TYPE_INT: + xasprintf(&result, "%lli", pd.pd_int); + break; + case PD_TYPE_UINT: + xasprintf(&result, "%llu", pd.pd_int); + break; + case PD_TYPE_DOUBLE: + xasprintf(&result, "%f", pd.pd_double); + break; + default: + // die here + die(STATE_UNKNOWN, "Invalid mp_perfdata mode\n"); + } + + return result; +} + +char *pd_to_string(mp_perfdata pd) { + assert(pd.label != NULL); + char *result = NULL; + xasprintf(&result, "%s=", pd.label); + + xasprintf(&result, "%s%s", result, pd_value_to_string(pd.value)); + + if (pd.uom != NULL) { + xasprintf(&result, "%s%s", result, pd.uom); + } + + if (pd.warn_present) { + xasprintf(&result, "%s;%s", result, mp_range_to_string(pd.warn)); + } else { + xasprintf(&result, "%s;", result); + } + + if (pd.crit_present) { + xasprintf(&result, "%s;%s", result, mp_range_to_string(pd.crit)); + } else { + xasprintf(&result, "%s;", result); + } + if (pd.min_present) { + xasprintf(&result, "%s;%s", result, pd_value_to_string(pd.min)); + } else { + xasprintf(&result, "%s;", result); + } + + if (pd.max_present) { + xasprintf(&result, "%s;%s", result, pd_value_to_string(pd.max)); + } + + /*printf("pd_to_string: %s\n", result); */ + + return result; +} + +char *pd_list_to_string(const pd_list pd) { + char *result = pd_to_string(pd.data); + + for (pd_list *elem = pd.next; elem != NULL; elem = elem->next) { + xasprintf(&result, "%s %s", result, pd_to_string(elem->data)); + } + + return result; +} + +mp_perfdata perfdata_init() { + mp_perfdata pd = {}; + return pd; +} + +pd_list *pd_list_init() { + pd_list *tmp = (pd_list *)calloc(1, sizeof(pd_list)); + if (tmp == NULL) { + die(STATE_UNKNOWN, "calloc failed\n"); + } + tmp->next = NULL; + return tmp; +} + +mp_range mp_range_init() { + mp_range result = { + .alert_on_inside_range = OUTSIDE, + .start = {}, + .start_infinity = true, + .end = {}, + .end_infinity = true, + }; + + return result; +} + +mp_range mp_range_set_start(mp_range input, mp_perfdata_value perf_val) { + input.start = perf_val; + input.start_infinity = false; + return input; +} + +mp_range mp_range_set_end(mp_range input, mp_perfdata_value perf_val) { + input.end = perf_val; + input.end_infinity = false; + return input; +} + +void pd_list_append(pd_list pdl[1], const mp_perfdata pd) { + assert(pdl != NULL); + + if (pdl->data.value.type == PD_TYPE_NONE) { + // first entry is still empty + pdl->data = pd; + } else { + // find last element in the list + pd_list *curr = pdl; + pd_list *next = pdl->next; + + while (next != NULL) { + curr = next; + next = next->next; + } + + if (curr->data.value.type == PD_TYPE_NONE) { + // still empty + curr->data = pd; + } else { + // new a new one + curr->next = pd_list_init(); + curr->next->data = pd; + } + } +} + +void pd_list_free(pd_list pdl[1]) { + while (pdl != NULL) { + pd_list *old = pdl; + pdl = pdl->next; + free(old); + } +} + +/* + * returns -1 if a < b, 0 if a == b, 1 if a > b + */ +int cmp_perfdata_value(const mp_perfdata_value a, const mp_perfdata_value b) { + // Test if types are different + if (a.type == b.type) { + + switch (a.type) { + case PD_TYPE_UINT: + if (a.pd_uint < b.pd_uint) { + return -1; + } else if (a.pd_uint == b.pd_uint) { + return 0; + } else { + return 1; + } + break; + case PD_TYPE_INT: + if (a.pd_int < b.pd_int) { + return -1; + } else if (a.pd_int == b.pd_int) { + return 0; + } else { + return 1; + } + break; + case PD_TYPE_DOUBLE: + if (a.pd_int < b.pd_int) { + return -1; + } else if (a.pd_int == b.pd_int) { + return 0; + } else { + return 1; + } + break; + default: + die(STATE_UNKNOWN, "Error in %s line: %d!", __FILE__, __LINE__); + } + } + + // Get dirty here + long double floating_a = 0; + + switch (a.type) { + case PD_TYPE_UINT: + floating_a = a.pd_uint; + break; + case PD_TYPE_INT: + floating_a = a.pd_int; + break; + case PD_TYPE_DOUBLE: + floating_a = a.pd_double; + break; + default: + die(STATE_UNKNOWN, "Error in %s line: %d!", __FILE__, __LINE__); + } + + long double floating_b = 0; + switch (b.type) { + case PD_TYPE_UINT: + floating_b = b.pd_uint; + break; + case PD_TYPE_INT: + floating_b = b.pd_int; + break; + case PD_TYPE_DOUBLE: + floating_b = b.pd_double; + break; + default: + die(STATE_UNKNOWN, "Error in %s line: %d!", __FILE__, __LINE__); + } + + if (floating_a < floating_b) { + return -1; + } + if (floating_a == floating_b) { + return 0; + } + return 1; +} + +char *mp_range_to_string(const mp_range input) { + char *result = ""; + if (input.alert_on_inside_range == INSIDE) { + xasprintf(&result, "@"); + } + + if (input.start_infinity) { + xasprintf(&result, "%s~:", result); + } else { + xasprintf(&result, "%s%s:", result, pd_value_to_string(input.start)); + } + + if (!input.end_infinity) { + xasprintf(&result, "%s%s", result, pd_value_to_string(input.end)); + } + return result; +} + +mp_perfdata mp_set_pd_value_float(mp_perfdata pd, float value) { return mp_set_pd_value_double(pd, value); } + +mp_perfdata mp_set_pd_value_double(mp_perfdata pd, double value) { + pd.value.pd_double = value; + pd.value.type = PD_TYPE_DOUBLE; + return pd; +} + +mp_perfdata mp_set_pd_value_int(mp_perfdata pd, int value) { return mp_set_pd_value_long_long(pd, (long long)value); } + +mp_perfdata mp_set_pd_value_u_int(mp_perfdata pd, unsigned int value) { return mp_set_pd_value_u_long_long(pd, (unsigned long long)value); } + +mp_perfdata mp_set_pd_value_long(mp_perfdata pd, long value) { return mp_set_pd_value_long_long(pd, (long long)value); } + +mp_perfdata mp_set_pd_value_u_long(mp_perfdata pd, unsigned long value) { + return mp_set_pd_value_u_long_long(pd, (unsigned long long)value); +} + +mp_perfdata mp_set_pd_value_long_long(mp_perfdata pd, long long value) { + pd.value.pd_int = value; + pd.value.type = PD_TYPE_INT; + return pd; +} + +mp_perfdata mp_set_pd_value_u_long_long(mp_perfdata pd, unsigned long long value) { + pd.value.pd_uint = value; + pd.value.type = PD_TYPE_UINT; + return pd; +} + +mp_perfdata_value mp_create_pd_value_double(double value) { + mp_perfdata_value res = {0}; + res.type = PD_TYPE_DOUBLE; + res.pd_double = value; + return res; +} + +mp_perfdata_value mp_create_pd_value_float(float value) { return mp_create_pd_value_double((double)value); } + +mp_perfdata_value mp_create_pd_value_int(int value) { return mp_create_pd_value_long_long((long long)value); } + +mp_perfdata_value mp_create_pd_value_u_int(unsigned int value) { return mp_create_pd_value_u_long_long((unsigned long long)value); } + +mp_perfdata_value mp_create_pd_value_long(long value) { return mp_create_pd_value_long_long((long long)value); } + +mp_perfdata_value mp_create_pd_value_u_long(unsigned long value) { return mp_create_pd_value_u_long_long((unsigned long long)value); } + +mp_perfdata_value mp_create_pd_value_long_long(long long value) { + mp_perfdata_value res = {0}; + res.type = PD_TYPE_INT; + res.pd_int = value; + return res; +} + +mp_perfdata_value mp_create_pd_value_u_long_long(unsigned long long value) { + mp_perfdata_value res = {0}; + res.type = PD_TYPE_UINT; + res.pd_uint = value; + return res; +} + +char *fmt_range(range foo) { return foo.text; } + +typedef struct integer_parser_wrapper { + int error; + mp_perfdata_value value; +} integer_parser_wrapper; + +typedef struct double_parser_wrapper { + int error; + mp_perfdata_value value; +} double_parser_wrapper; + +typedef struct perfdata_value_parser_wrapper { + int error; + mp_perfdata_value value; +} perfdata_value_parser_wrapper; + +double_parser_wrapper parse_double(const char *input); +integer_parser_wrapper parse_integer(const char *input); +perfdata_value_parser_wrapper parse_pd_value(const char *input); + +mp_range_parsed mp_parse_range_string(const char *input) { + if (input == NULL) { + mp_range_parsed result = { + .error = MP_RANGE_PARSING_FAILURE, + }; + return result; + } + + if (strlen(input) == 0) { + mp_range_parsed result = { + .error = MP_RANGE_PARSING_FAILURE, + }; + return result; + } + + mp_range_parsed result = { + .range = mp_range_init(), + .error = MP_PARSING_SUCCES, + }; + + if (input[0] == '@') { + // found an '@' at beginning, so invert the range logic + result.range.alert_on_inside_range = INSIDE; + + // advance the pointer one symbol + input++; + } + + char *working_copy = strdup(input); + input = working_copy; + + char *separator = index(working_copy, ':'); + if (separator != NULL) { + // Found a separator + // set the separator to 0, so we have two different strings + *separator = '\0'; + + if (input[0] == '~') { + // the beginning starts with '~', so it might be infinity + if (&input[1] != separator) { + // the next symbol after '~' is not the separator! + // so input is probably wrong + result.error = MP_RANGE_PARSING_FAILURE; + free(working_copy); + return result; + } + + result.range.start_infinity = true; + } else { + // No '~' at the beginning, so this should be a number + result.range.start_infinity = false; + perfdata_value_parser_wrapper parsed_pd = parse_pd_value(input); + + if (parsed_pd.error != MP_PARSING_SUCCES) { + result.error = parsed_pd.error; + free(working_copy); + return result; + } + + result.range.start = parsed_pd.value; + result.range.start_infinity = false; + } + // got the first part now + // advance the pointer + input = separator + 1; + } + + // End part or no separator + if (input[0] == '\0') { + // the end is infinite + result.range.end_infinity = true; + } else { + perfdata_value_parser_wrapper parsed_pd = parse_pd_value(input); + + if (parsed_pd.error != MP_PARSING_SUCCES) { + result.error = parsed_pd.error; + return result; + } + result.range.end = parsed_pd.value; + result.range.end_infinity = false; + } + free(working_copy); + return result; +} + +double_parser_wrapper parse_double(const char *input) { + double_parser_wrapper result = { + .error = MP_PARSING_SUCCES, + }; + + if (input == NULL) { + result.error = MP_PARSING_FAILURE; + return result; + } + + char *endptr = NULL; + errno = 0; + double tmp = strtod(input, &endptr); + + if (input == endptr) { + // man 3 strtod says, no conversion performed + result.error = MP_PARSING_FAILURE; + return result; + } + + if (errno) { + // some other error + // TODO maybe differentiate a little bit + result.error = MP_PARSING_FAILURE; + return result; + } + + result.value = mp_create_pd_value(tmp); + return result; +} + +integer_parser_wrapper parse_integer(const char *input) { + integer_parser_wrapper result = { + .error = MP_PARSING_SUCCES, + }; + + if (input == NULL) { + result.error = MP_PARSING_FAILURE; + return result; + } + + char *endptr = NULL; + errno = 0; + long long tmp = strtoll(input, &endptr, 0); + + // validating *sigh* + if (*endptr != '\0') { + // something went wrong in strtoll + if (tmp == LLONG_MIN) { + // underflow + result.error = MP_RANGE_PARSING_UNDERFLOW; + return result; + } + + if (tmp == LLONG_MAX) { + // overflow + result.error = MP_RANGE_PARSING_OVERFLOW; + return result; + } + + // still wrong, but not sure why, probably invalid characters + if (errno == EINVAL) { + result.error = MP_RANGE_PARSING_INVALID_CHAR; + return result; + } + + // some other error, do catch all here + result.error = MP_RANGE_PARSING_FAILURE; + return result; + } + + // no error, should be fine + result.value = mp_create_pd_value(tmp); + return result; +} + +perfdata_value_parser_wrapper parse_pd_value(const char *input) { + // try integer first + integer_parser_wrapper tmp_int = parse_integer(input); + + if (tmp_int.error == MP_PARSING_SUCCES) { + perfdata_value_parser_wrapper result = { + .error = tmp_int.error, + .value = tmp_int.value, + }; + return result; + } + + double_parser_wrapper tmp_double = parse_double(input); + perfdata_value_parser_wrapper result = {}; + if (tmp_double.error == MP_PARSING_SUCCES) { + result.error = tmp_double.error; + result.value = tmp_double.value; + } else { + result.error = tmp_double.error; + } + return result; +} -- cgit v1.2.3-74-g34f1 From 24f21473fb493edf7fced3b4f680c99123145014 Mon Sep 17 00:00:00 2001 From: Lorenz Kästle <12514511+RincewindsHat@users.noreply.github.com> Date: Wed, 19 Feb 2025 16:59:32 +0100 Subject: Use asprintf in lib directly instead of xasprintf --- lib/output.c | 32 ++++++++++++++++---------------- lib/perfdata.c | 36 ++++++++++++++++++------------------ 2 files changed, 34 insertions(+), 34 deletions(-) (limited to 'lib/perfdata.c') diff --git a/lib/output.c b/lib/output.c index 62a00fed..4c5041c8 100644 --- a/lib/output.c +++ b/lib/output.c @@ -23,7 +23,7 @@ static inline char *fmt_subcheck_perfdata(mp_subcheck check) { int added = 0; if (check.perfdata != NULL) { - added = xasprintf(&result, "%s", pd_list_to_string(*check.perfdata)); + added = asprintf(&result, "%s", pd_list_to_string(*check.perfdata)); } if (check.subchecks == NULL) { @@ -35,10 +35,10 @@ static inline char *fmt_subcheck_perfdata(mp_subcheck check) { while (subchecks != NULL) { if (added > 0) { - added = xasprintf(&result, "%s%s", result, fmt_subcheck_perfdata(subchecks->subcheck)); + added = asprintf(&result, "%s%s", result, fmt_subcheck_perfdata(subchecks->subcheck)); } else { // TODO free previous result here? - added = xasprintf(&result, "%s", result, fmt_subcheck_perfdata(subchecks->subcheck)); + added = asprintf(&result, "%s", fmt_subcheck_perfdata(subchecks->subcheck)); } subchecks = subchecks->next; @@ -185,7 +185,7 @@ char *get_subcheck_summary(mp_check check) { subchecks = subchecks->next; } char *result = NULL; - xasprintf(&result, "ok=%d, warning=%d, critical=%d, unknown=%d", ok, warning, critical, unknown); + asprintf(&result, "ok=%d, warning=%d, critical=%d, unknown=%d", ok, warning, critical, unknown); return result; } @@ -238,7 +238,7 @@ char *mp_fmt_output(mp_check check) { check.summary = get_subcheck_summary(check); } - xasprintf(&result, "%s: %s", state_text(mp_compute_check_state(check)), check.summary); + asprintf(&result, "%s: %s", state_text(mp_compute_check_state(check)), check.summary); return result; case MP_FORMAT_ONE_LINE: { @@ -251,12 +251,12 @@ char *mp_fmt_output(mp_check check) { check.summary = get_subcheck_summary(check); } - xasprintf(&result, "%s: %s", state_text(mp_compute_check_state(check)), check.summary); + asprintf(&result, "%s: %s", state_text(mp_compute_check_state(check)), check.summary); mp_subcheck_list *subchecks = check.subchecks; while (subchecks != NULL) { - xasprintf(&result, "%s - %s", result, fmt_subcheck_output(MP_FORMAT_ONE_LINE, subchecks->subcheck, 1)); + asprintf(&result, "%s - %s", result, fmt_subcheck_output(MP_FORMAT_ONE_LINE, subchecks->subcheck, 1)); subchecks = subchecks->next; } @@ -267,12 +267,12 @@ char *mp_fmt_output(mp_check check) { check.summary = get_subcheck_summary(check); } - xasprintf(&result, "[%s] - %s", state_text(mp_compute_check_state(check)), check.summary); + asprintf(&result, "[%s] - %s", state_text(mp_compute_check_state(check)), check.summary); mp_subcheck_list *subchecks = check.subchecks; while (subchecks != NULL) { - xasprintf(&result, "%s\n%s", result, fmt_subcheck_output(MP_FORMAT_ICINGA_WEB_2, subchecks->subcheck, 1)); + asprintf(&result, "%s\n%s", result, fmt_subcheck_output(MP_FORMAT_ICINGA_WEB_2, subchecks->subcheck, 1)); subchecks = subchecks->next; } @@ -281,16 +281,16 @@ char *mp_fmt_output(mp_check check) { while (subchecks != NULL) { if (pd_string == NULL) { - xasprintf(&pd_string, "%s", fmt_subcheck_perfdata(subchecks->subcheck)); + asprintf(&pd_string, "%s", fmt_subcheck_perfdata(subchecks->subcheck)); } else { - xasprintf(&pd_string, "%s %s", pd_string, fmt_subcheck_perfdata(subchecks->subcheck)); + asprintf(&pd_string, "%s %s", pd_string, fmt_subcheck_perfdata(subchecks->subcheck)); } subchecks = subchecks->next; } if (pd_string != NULL && strlen(pd_string) > 0) { - xasprintf(&result, "%s|%s", result, pd_string); + asprintf(&result, "%s|%s", result, pd_string); } break; @@ -358,23 +358,23 @@ static inline char *fmt_subcheck_output(mp_output_format output_format, mp_subch switch (output_format) { case MP_FORMAT_ICINGA_WEB_2: - xasprintf(&result, "%s\\_[%s] - %s", generate_indentation_string(indentation), state_text(mp_compute_subcheck_state(check)), + asprintf(&result, "%s\\_[%s] - %s", generate_indentation_string(indentation), state_text(mp_compute_subcheck_state(check)), check.output); subchecks = check.subchecks; while (subchecks != NULL) { - xasprintf(&result, "%s\n%s", result, fmt_subcheck_output(output_format, subchecks->subcheck, indentation + 1)); + asprintf(&result, "%s\n%s", result, fmt_subcheck_output(output_format, subchecks->subcheck, indentation + 1)); subchecks = subchecks->next; } return result; case MP_FORMAT_ONE_LINE: - xasprintf(&result, "[%s] - %s", state_text(mp_compute_subcheck_state(check)), check.output); + asprintf(&result, "[%s] - %s", state_text(mp_compute_subcheck_state(check)), check.output); subchecks = check.subchecks; while (subchecks != NULL) { - xasprintf(&result, " - %s\n%s", result, fmt_subcheck_output(output_format, subchecks->subcheck, indentation + 1)); + asprintf(&result, " - %s\n%s", result, fmt_subcheck_output(output_format, subchecks->subcheck, indentation + 1)); subchecks = subchecks->next; } return result; diff --git a/lib/perfdata.c b/lib/perfdata.c index f894df39..661756c5 100644 --- a/lib/perfdata.c +++ b/lib/perfdata.c @@ -14,13 +14,13 @@ char *pd_value_to_string(const mp_perfdata_value pd) { switch (pd.type) { case PD_TYPE_INT: - xasprintf(&result, "%lli", pd.pd_int); + asprintf(&result, "%lli", pd.pd_int); break; case PD_TYPE_UINT: - xasprintf(&result, "%llu", pd.pd_int); + asprintf(&result, "%llu", pd.pd_int); break; case PD_TYPE_DOUBLE: - xasprintf(&result, "%f", pd.pd_double); + asprintf(&result, "%f", pd.pd_double); break; default: // die here @@ -33,33 +33,33 @@ char *pd_value_to_string(const mp_perfdata_value pd) { char *pd_to_string(mp_perfdata pd) { assert(pd.label != NULL); char *result = NULL; - xasprintf(&result, "%s=", pd.label); + asprintf(&result, "%s=", pd.label); - xasprintf(&result, "%s%s", result, pd_value_to_string(pd.value)); + asprintf(&result, "%s%s", result, pd_value_to_string(pd.value)); if (pd.uom != NULL) { - xasprintf(&result, "%s%s", result, pd.uom); + asprintf(&result, "%s%s", result, pd.uom); } if (pd.warn_present) { - xasprintf(&result, "%s;%s", result, mp_range_to_string(pd.warn)); + asprintf(&result, "%s;%s", result, mp_range_to_string(pd.warn)); } else { - xasprintf(&result, "%s;", result); + asprintf(&result, "%s;", result); } if (pd.crit_present) { - xasprintf(&result, "%s;%s", result, mp_range_to_string(pd.crit)); + asprintf(&result, "%s;%s", result, mp_range_to_string(pd.crit)); } else { - xasprintf(&result, "%s;", result); + asprintf(&result, "%s;", result); } if (pd.min_present) { - xasprintf(&result, "%s;%s", result, pd_value_to_string(pd.min)); + asprintf(&result, "%s;%s", result, pd_value_to_string(pd.min)); } else { - xasprintf(&result, "%s;", result); + asprintf(&result, "%s;", result); } if (pd.max_present) { - xasprintf(&result, "%s;%s", result, pd_value_to_string(pd.max)); + asprintf(&result, "%s;%s", result, pd_value_to_string(pd.max)); } /*printf("pd_to_string: %s\n", result); */ @@ -71,7 +71,7 @@ char *pd_list_to_string(const pd_list pd) { char *result = pd_to_string(pd.data); for (pd_list *elem = pd.next; elem != NULL; elem = elem->next) { - xasprintf(&result, "%s %s", result, pd_to_string(elem->data)); + asprintf(&result, "%s %s", result, pd_to_string(elem->data)); } return result; @@ -234,17 +234,17 @@ int cmp_perfdata_value(const mp_perfdata_value a, const mp_perfdata_value b) { char *mp_range_to_string(const mp_range input) { char *result = ""; if (input.alert_on_inside_range == INSIDE) { - xasprintf(&result, "@"); + asprintf(&result, "@"); } if (input.start_infinity) { - xasprintf(&result, "%s~:", result); + asprintf(&result, "%s~:", result); } else { - xasprintf(&result, "%s%s:", result, pd_value_to_string(input.start)); + asprintf(&result, "%s%s:", result, pd_value_to_string(input.start)); } if (!input.end_infinity) { - xasprintf(&result, "%s%s", result, pd_value_to_string(input.end)); + asprintf(&result, "%s%s", result, pd_value_to_string(input.end)); } return result; } -- cgit v1.2.3-74-g34f1