mirror of
https://github.com/monitoring-plugins/monitoring-plugins.git
synced 2026-06-09 00:32:05 -04:00
Merge pull request #2064 from RincewindsHat/feature/new_output_infra
Feature/new output infra
This commit is contained in:
commit
75658bd04d
28 changed files with 5602 additions and 197 deletions
3
.github/prepare_debian.sh
vendored
3
.github/prepare_debian.sh
vendored
|
|
@ -61,7 +61,8 @@ apt-get -y install perl \
|
|||
libmariadb-dev \
|
||||
cron \
|
||||
iputils-ping \
|
||||
iproute2
|
||||
iproute2 \
|
||||
libjson-perl
|
||||
|
||||
# remove ipv6 interface from hosts
|
||||
sed '/^::1/d' /etc/hosts > /tmp/hosts
|
||||
|
|
|
|||
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -103,6 +103,8 @@ NP-VERSION-FILE
|
|||
/lib/libmonitoringplug.a
|
||||
/lib/Makefile
|
||||
/lib/Makefile.in
|
||||
/lib/vendor/cJSON/.deps
|
||||
/lib/vendor/cJSON/.dirstamp
|
||||
|
||||
# /lib/tests/
|
||||
/lib/tests/base64.Po
|
||||
|
|
|
|||
|
|
@ -7,8 +7,21 @@ noinst_LIBRARIES = libmonitoringplug.a
|
|||
AM_CPPFLAGS = -DNP_STATE_DIR_PREFIX=\"$(localstatedir)\" \
|
||||
-I$(srcdir) -I$(top_srcdir)/gl -I$(top_srcdir)/intl -I$(top_srcdir)/plugins
|
||||
|
||||
libmonitoringplug_a_SOURCES = utils_base.c utils_disk.c utils_tcp.c utils_cmd.c maxfd.c
|
||||
EXTRA_DIST = utils_base.h utils_disk.h utils_tcp.h utils_cmd.h parse_ini.h extra_opts.h maxfd.h
|
||||
libmonitoringplug_a_SOURCES = utils_base.c utils_disk.c utils_tcp.c utils_cmd.c maxfd.c output.c perfdata.c output.c thresholds.c vendor/cJSON/cJSON.c
|
||||
|
||||
EXTRA_DIST = utils_base.h \
|
||||
utils_disk.h \
|
||||
utils_tcp.h \
|
||||
utils_cmd.h \
|
||||
parse_ini.h \
|
||||
extra_opts.h \
|
||||
maxfd.h \
|
||||
perfdata.h \
|
||||
output.h \
|
||||
thresholds.h \
|
||||
states.h \
|
||||
vendor/cJSON/cJSON.h \
|
||||
monitoringplug.h
|
||||
|
||||
if USE_PARSE_INI
|
||||
libmonitoringplug_a_SOURCES += parse_ini.c extra_opts.c
|
||||
|
|
@ -16,4 +29,3 @@ endif USE_PARSE_INI
|
|||
|
||||
test test-debug:
|
||||
cd tests && make $@
|
||||
|
||||
|
|
|
|||
7
lib/monitoringplug.h
Normal file
7
lib/monitoringplug.h
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "./states.h"
|
||||
#include "./utils_base.h"
|
||||
#include "./thresholds.h"
|
||||
#include "./maxfd.h"
|
||||
#include "./output.h"
|
||||
535
lib/output.c
Normal file
535
lib/output.c
Normal file
|
|
@ -0,0 +1,535 @@
|
|||
#include "./output.h"
|
||||
#include "./utils_base.h"
|
||||
#include "../plugins/utils.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
// #include <cjson/cJSON.h>
|
||||
#include "./vendor/cJSON/cJSON.h"
|
||||
#include "perfdata.h"
|
||||
#include "states.h"
|
||||
|
||||
// == Prototypes ==
|
||||
static char *fmt_subcheck_output(mp_output_format output_format, mp_subcheck check, unsigned int indentation);
|
||||
static inline cJSON *json_serialize_subcheck(mp_subcheck subcheck);
|
||||
|
||||
// == Implementation ==
|
||||
|
||||
/*
|
||||
* Generate output string for a mp_subcheck object
|
||||
*/
|
||||
static inline char *fmt_subcheck_perfdata(mp_subcheck check) {
|
||||
char *result = strdup("");
|
||||
int added = 0;
|
||||
|
||||
if (check.perfdata != NULL) {
|
||||
added = asprintf(&result, "%s", pd_list_to_string(*check.perfdata));
|
||||
}
|
||||
|
||||
if (check.subchecks == NULL) {
|
||||
// No subchecks, return here
|
||||
return result;
|
||||
}
|
||||
|
||||
mp_subcheck_list *subchecks = check.subchecks;
|
||||
|
||||
while (subchecks != NULL) {
|
||||
if (added > 0) {
|
||||
added = asprintf(&result, "%s%s", result, fmt_subcheck_perfdata(subchecks->subcheck));
|
||||
} else {
|
||||
// TODO free previous result here?
|
||||
added = asprintf(&result, "%s", fmt_subcheck_perfdata(subchecks->subcheck));
|
||||
}
|
||||
|
||||
subchecks = subchecks->next;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialiser for a mp_check object. Always use this to get a new one!
|
||||
* It sets useful defaults
|
||||
*/
|
||||
mp_check mp_check_init(void) {
|
||||
mp_check check = {0};
|
||||
check.format = MP_FORMAT_DEFAULT;
|
||||
return check;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialiser for a mp_subcheck object. Always use this to get a new one!
|
||||
* It sets useful defaults
|
||||
*/
|
||||
mp_subcheck mp_subcheck_init(void) {
|
||||
mp_subcheck tmp = {0};
|
||||
tmp.default_state = STATE_UNKNOWN; // Default state is unknown
|
||||
tmp.state_set_explicitly = false;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a subcheck to a (the one and only) check object
|
||||
*/
|
||||
int mp_add_subcheck_to_check(mp_check check[static 1], mp_subcheck subcheck) {
|
||||
assert(subcheck.output != NULL); // There must be output in a subcheck
|
||||
|
||||
mp_subcheck_list *tmp = NULL;
|
||||
|
||||
if (check->subchecks == NULL) {
|
||||
check->subchecks = (mp_subcheck_list *)calloc(1, sizeof(mp_subcheck_list));
|
||||
if (check->subchecks == NULL) {
|
||||
die(STATE_UNKNOWN, "%s - %s #%d: %s", __FILE__, __func__, __LINE__, "malloc failed");
|
||||
}
|
||||
|
||||
check->subchecks->subcheck = subcheck;
|
||||
check->subchecks->next = NULL;
|
||||
} else {
|
||||
// Search for the end
|
||||
tmp = (mp_subcheck_list *)calloc(1, sizeof(mp_subcheck_list));
|
||||
if (tmp == NULL) {
|
||||
die(STATE_UNKNOWN, "%s - %s #%d: %s", __FILE__, __func__, __LINE__, "malloc failed");
|
||||
}
|
||||
|
||||
tmp->subcheck = subcheck;
|
||||
tmp->next = check->subchecks;
|
||||
|
||||
check->subchecks = tmp;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a mp_perfdata data point to a mp_subcheck object
|
||||
*/
|
||||
void mp_add_perfdata_to_subcheck(mp_subcheck check[static 1], const mp_perfdata perfData) {
|
||||
if (check->perfdata == NULL) {
|
||||
check->perfdata = pd_list_init();
|
||||
}
|
||||
pd_list_append(check->perfdata, perfData);
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a mp_subcheck object to another one. The seconde mp_subcheck (argument) is the lower in the
|
||||
* hierarchy
|
||||
*/
|
||||
int mp_add_subcheck_to_subcheck(mp_subcheck check[static 1], mp_subcheck subcheck) {
|
||||
if (subcheck.output == NULL) {
|
||||
die(STATE_UNKNOWN, "%s - %s #%d: %s", __FILE__, __func__, __LINE__, "Sub check output is NULL");
|
||||
}
|
||||
|
||||
mp_subcheck_list *tmp = NULL;
|
||||
|
||||
if (check->subchecks == NULL) {
|
||||
check->subchecks = (mp_subcheck_list *)calloc(1, sizeof(mp_subcheck_list));
|
||||
if (check->subchecks == NULL) {
|
||||
die(STATE_UNKNOWN, "%s - %s #%d: %s", __FILE__, __func__, __LINE__, "malloc failed");
|
||||
}
|
||||
|
||||
tmp = check->subchecks;
|
||||
} else {
|
||||
// Search for the end
|
||||
tmp = check->subchecks;
|
||||
|
||||
while (tmp->next != NULL) {
|
||||
tmp = tmp->next;
|
||||
}
|
||||
|
||||
tmp->next = (mp_subcheck_list *)calloc(1, sizeof(mp_subcheck_list));
|
||||
if (tmp->next == NULL) {
|
||||
die(STATE_UNKNOWN, "%s - %s #%d: %s", __FILE__, __func__, __LINE__, "malloc failed");
|
||||
}
|
||||
|
||||
tmp = tmp->next;
|
||||
}
|
||||
|
||||
tmp->subcheck = subcheck;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a manual summary to a mp_check object, effectively replacing
|
||||
* the autogenerated one
|
||||
*/
|
||||
void mp_add_summary(mp_check check[static 1], char *summary) { check->summary = summary; }
|
||||
|
||||
/*
|
||||
* Generate the summary string of a mp_check object based on it's subchecks
|
||||
*/
|
||||
char *get_subcheck_summary(mp_check check) {
|
||||
mp_subcheck_list *subchecks = check.subchecks;
|
||||
|
||||
unsigned int ok = 0;
|
||||
unsigned int warning = 0;
|
||||
unsigned int critical = 0;
|
||||
unsigned int unknown = 0;
|
||||
while (subchecks != NULL) {
|
||||
switch (subchecks->subcheck.state) {
|
||||
case STATE_OK:
|
||||
ok++;
|
||||
break;
|
||||
case STATE_WARNING:
|
||||
warning++;
|
||||
break;
|
||||
case STATE_CRITICAL:
|
||||
critical++;
|
||||
break;
|
||||
case STATE_UNKNOWN:
|
||||
unknown++;
|
||||
break;
|
||||
default:
|
||||
die(STATE_UNKNOWN, "Unknown state in get_subcheck_summary");
|
||||
}
|
||||
subchecks = subchecks->next;
|
||||
}
|
||||
char *result = NULL;
|
||||
asprintf(&result, "ok=%d, warning=%d, critical=%d, unknown=%d", ok, warning, critical, unknown);
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Generate the result state of a mp_subcheck object based on it's own state and it's subchecks states
|
||||
*/
|
||||
mp_state_enum mp_compute_subcheck_state(const mp_subcheck check) {
|
||||
if (check.state_set_explicitly) {
|
||||
return check.state;
|
||||
}
|
||||
|
||||
mp_subcheck_list *scl = check.subchecks;
|
||||
mp_state_enum result = check.default_state;
|
||||
|
||||
while (scl != NULL) {
|
||||
result = max_state_alt(result, mp_compute_subcheck_state(scl->subcheck));
|
||||
scl = scl->next;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Generate the result state of a mp_check object based on it's own state and it's subchecks states
|
||||
*/
|
||||
mp_state_enum mp_compute_check_state(const mp_check check) {
|
||||
assert(check.subchecks != NULL); // a mp_check without subchecks is invalid, die here
|
||||
|
||||
mp_subcheck_list *scl = check.subchecks;
|
||||
mp_state_enum result = STATE_OK;
|
||||
|
||||
while (scl != NULL) {
|
||||
result = max_state_alt(result, mp_compute_subcheck_state(scl->subcheck));
|
||||
scl = scl->next;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Generate output string for a mp_check object
|
||||
* Non static to be available for testing functions
|
||||
*/
|
||||
char *mp_fmt_output(mp_check check) {
|
||||
char *result = NULL;
|
||||
|
||||
switch (check.format) {
|
||||
case MP_FORMAT_MULTI_LINE: {
|
||||
if (check.summary == NULL) {
|
||||
check.summary = get_subcheck_summary(check);
|
||||
}
|
||||
|
||||
asprintf(&result, "[%s] - %s", state_text(mp_compute_check_state(check)), check.summary);
|
||||
|
||||
mp_subcheck_list *subchecks = check.subchecks;
|
||||
|
||||
while (subchecks != NULL) {
|
||||
asprintf(&result, "%s\n%s", result, fmt_subcheck_output(MP_FORMAT_MULTI_LINE, subchecks->subcheck, 1));
|
||||
subchecks = subchecks->next;
|
||||
}
|
||||
|
||||
char *pd_string = NULL;
|
||||
subchecks = check.subchecks;
|
||||
|
||||
while (subchecks != NULL) {
|
||||
if (pd_string == NULL) {
|
||||
asprintf(&pd_string, "%s", fmt_subcheck_perfdata(subchecks->subcheck));
|
||||
} else {
|
||||
asprintf(&pd_string, "%s %s", pd_string, fmt_subcheck_perfdata(subchecks->subcheck));
|
||||
}
|
||||
|
||||
subchecks = subchecks->next;
|
||||
}
|
||||
|
||||
if (pd_string != NULL && strlen(pd_string) > 0) {
|
||||
asprintf(&result, "%s|%s", result, pd_string);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case MP_FORMAT_TEST_JSON: {
|
||||
cJSON *resultObject = cJSON_CreateObject();
|
||||
if (resultObject == NULL) {
|
||||
die(STATE_UNKNOWN, "cJSON_CreateObject failed");
|
||||
}
|
||||
|
||||
cJSON *resultState = cJSON_CreateString(state_text(mp_compute_check_state(check)));
|
||||
cJSON_AddItemToObject(resultObject, "state", resultState);
|
||||
|
||||
if (check.summary == NULL) {
|
||||
check.summary = get_subcheck_summary(check);
|
||||
}
|
||||
|
||||
cJSON *summary = cJSON_CreateString(check.summary);
|
||||
cJSON_AddItemToObject(resultObject, "summary", summary);
|
||||
|
||||
if (check.subchecks != NULL) {
|
||||
cJSON *subchecks = cJSON_CreateArray();
|
||||
|
||||
mp_subcheck_list *sc = check.subchecks;
|
||||
|
||||
while (sc != NULL) {
|
||||
cJSON *sc_json = json_serialize_subcheck(sc->subcheck);
|
||||
cJSON_AddItemToArray(subchecks, sc_json);
|
||||
sc = sc->next;
|
||||
}
|
||||
|
||||
cJSON_AddItemToObject(resultObject, "checks", subchecks);
|
||||
}
|
||||
|
||||
result = cJSON_PrintUnformatted(resultObject);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
die(STATE_UNKNOWN, "Invalid format");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper function to properly indent the output lines when using multiline
|
||||
* formats
|
||||
*/
|
||||
static char *generate_indentation_string(unsigned int indentation) {
|
||||
char *result = calloc(indentation + 1, sizeof(char));
|
||||
|
||||
for (unsigned int i = 0; i < indentation; i++) {
|
||||
result[i] = '\t';
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper function to generate the output string of mp_subcheck
|
||||
*/
|
||||
static inline char *fmt_subcheck_output(mp_output_format output_format, mp_subcheck check, unsigned int indentation) {
|
||||
char *result = NULL;
|
||||
mp_subcheck_list *subchecks = NULL;
|
||||
|
||||
switch (output_format) {
|
||||
case MP_FORMAT_MULTI_LINE:
|
||||
asprintf(&result, "%s\\_[%s] - %s", generate_indentation_string(indentation), state_text(mp_compute_subcheck_state(check)),
|
||||
check.output);
|
||||
|
||||
subchecks = check.subchecks;
|
||||
|
||||
while (subchecks != NULL) {
|
||||
asprintf(&result, "%s\n%s", result, fmt_subcheck_output(output_format, subchecks->subcheck, indentation + 1));
|
||||
subchecks = subchecks->next;
|
||||
}
|
||||
return result;
|
||||
default:
|
||||
die(STATE_UNKNOWN, "Invalid format");
|
||||
}
|
||||
}
|
||||
|
||||
static inline cJSON *json_serialise_pd_value(mp_perfdata_value value) {
|
||||
cJSON *result = cJSON_CreateObject();
|
||||
|
||||
switch (value.type) {
|
||||
case PD_TYPE_DOUBLE:
|
||||
cJSON_AddStringToObject(result, "type", "double");
|
||||
break;
|
||||
case PD_TYPE_INT:
|
||||
cJSON_AddStringToObject(result, "type", "int");
|
||||
break;
|
||||
case PD_TYPE_UINT:
|
||||
cJSON_AddStringToObject(result, "type", "uint");
|
||||
break;
|
||||
case PD_TYPE_NONE:
|
||||
die(STATE_UNKNOWN, "Perfdata type was None in json_serialise_pd_value");
|
||||
}
|
||||
cJSON_AddStringToObject(result, "value", pd_value_to_string(value));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline cJSON *json_serialise_range(mp_range range) {
|
||||
cJSON *result = cJSON_CreateObject();
|
||||
|
||||
if (range.alert_on_inside_range) {
|
||||
cJSON_AddBoolToObject(result, "alert_on_inside", true);
|
||||
} else {
|
||||
cJSON_AddBoolToObject(result, "alert_on_inside", false);
|
||||
}
|
||||
|
||||
if (range.end_infinity) {
|
||||
cJSON_AddStringToObject(result, "end", "inf");
|
||||
} else {
|
||||
cJSON_AddItemToObject(result, "end", json_serialise_pd_value(range.end));
|
||||
}
|
||||
|
||||
if (range.start_infinity) {
|
||||
cJSON_AddStringToObject(result, "start", "inf");
|
||||
} else {
|
||||
cJSON_AddItemToObject(result, "start", json_serialise_pd_value(range.end));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline cJSON *json_serialise_pd(mp_perfdata pd_val) {
|
||||
cJSON *result = cJSON_CreateObject();
|
||||
|
||||
// Label
|
||||
cJSON_AddStringToObject(result, "label", pd_val.label);
|
||||
|
||||
// Value
|
||||
cJSON_AddItemToObject(result, "value", json_serialise_pd_value(pd_val.value));
|
||||
|
||||
// Uom
|
||||
cJSON_AddStringToObject(result, "uom", pd_val.uom);
|
||||
|
||||
// Warn/Crit
|
||||
if (pd_val.warn_present) {
|
||||
cJSON *warn = json_serialise_range(pd_val.warn);
|
||||
cJSON_AddItemToObject(result, "warn", warn);
|
||||
}
|
||||
if (pd_val.crit_present) {
|
||||
cJSON *crit = json_serialise_range(pd_val.crit);
|
||||
cJSON_AddItemToObject(result, "crit", crit);
|
||||
}
|
||||
|
||||
if (pd_val.min_present) {
|
||||
cJSON_AddItemToObject(result, "min", json_serialise_pd_value(pd_val.min));
|
||||
}
|
||||
if (pd_val.max_present) {
|
||||
cJSON_AddItemToObject(result, "max", json_serialise_pd_value(pd_val.max));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline cJSON *json_serialise_pd_list(pd_list *list) {
|
||||
cJSON *result = cJSON_CreateArray();
|
||||
|
||||
do {
|
||||
cJSON *pd_value = json_serialise_pd(list->data);
|
||||
cJSON_AddItemToArray(result, pd_value);
|
||||
list = list->next;
|
||||
} while (list != NULL);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline cJSON *json_serialize_subcheck(mp_subcheck subcheck) {
|
||||
cJSON *result = cJSON_CreateObject();
|
||||
|
||||
// Human readable output
|
||||
cJSON *output = cJSON_CreateString(subcheck.output);
|
||||
cJSON_AddItemToObject(result, "output", output);
|
||||
|
||||
// Test state (aka Exit Code)
|
||||
cJSON *state = cJSON_CreateString(state_text(mp_compute_subcheck_state(subcheck)));
|
||||
cJSON_AddItemToObject(result, "state", state);
|
||||
|
||||
// Perfdata
|
||||
if (subcheck.perfdata != NULL) {
|
||||
cJSON *perfdata = json_serialise_pd_list(subcheck.perfdata);
|
||||
cJSON_AddItemToObject(result, "perfdata", perfdata);
|
||||
}
|
||||
|
||||
if (subcheck.subchecks != NULL) {
|
||||
cJSON *subchecks = cJSON_CreateArray();
|
||||
|
||||
mp_subcheck_list *sc = subcheck.subchecks;
|
||||
|
||||
while (sc != NULL) {
|
||||
cJSON *sc_json = json_serialize_subcheck(sc->subcheck);
|
||||
cJSON_AddItemToArray(subchecks, sc_json);
|
||||
sc = sc->next;
|
||||
}
|
||||
|
||||
cJSON_AddItemToObject(result, "checks", subchecks);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Wrapper function to print the output string of a mp_check object
|
||||
* Use this in concrete plugins.
|
||||
*/
|
||||
void mp_print_output(mp_check check) { puts(mp_fmt_output(check)); }
|
||||
|
||||
/*
|
||||
* Convenience function to print the output string of a mp_check object and exit
|
||||
* the program with the resulting state.
|
||||
* Intended to be used to exit a monitoring plugin.
|
||||
*/
|
||||
void mp_exit(mp_check check) {
|
||||
mp_print_output(check);
|
||||
if (check.format == MP_FORMAT_TEST_JSON) {
|
||||
exit(0);
|
||||
}
|
||||
|
||||
exit(mp_compute_check_state(check));
|
||||
}
|
||||
|
||||
/*
|
||||
* Function to set the result state of a mp_subcheck object explicitly.
|
||||
* This will overwrite the default state AND states derived from it's subchecks
|
||||
*/
|
||||
mp_subcheck mp_set_subcheck_state(mp_subcheck check, mp_state_enum state) {
|
||||
check.state = state;
|
||||
check.state_set_explicitly = true;
|
||||
return check;
|
||||
}
|
||||
|
||||
/*
|
||||
* Function to set the default result state of a mp_subcheck object. This state
|
||||
* will be used if neither an explicit state is set (see *mp_set_subcheck_state*)
|
||||
* nor does it include other subchecks
|
||||
*/
|
||||
mp_subcheck mp_set_subcheck_default_state(mp_subcheck check, mp_state_enum state) {
|
||||
check.default_state = state;
|
||||
return check;
|
||||
}
|
||||
|
||||
char *mp_output_format_map[] = {
|
||||
[MP_FORMAT_MULTI_LINE] = "multi-line",
|
||||
[MP_FORMAT_TEST_JSON] = "mp-test-json",
|
||||
};
|
||||
|
||||
/*
|
||||
* Function to parse the output from a string
|
||||
*/
|
||||
parsed_output_format mp_parse_output_format(char *format_string) {
|
||||
parsed_output_format result = {
|
||||
.parsing_success = false,
|
||||
.output_format = MP_FORMAT_DEFAULT,
|
||||
};
|
||||
|
||||
for (mp_output_format i = 0; i < (sizeof(mp_output_format_map) / sizeof(char *)); i++) {
|
||||
if (strcasecmp(mp_output_format_map[i], format_string) == 0) {
|
||||
result.parsing_success = true;
|
||||
result.output_format = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
85
lib/output.h
Normal file
85
lib/output.h
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
#pragma once
|
||||
|
||||
#include "../config.h"
|
||||
#include "./perfdata.h"
|
||||
#include "./states.h"
|
||||
|
||||
/*
|
||||
* A partial check result
|
||||
*/
|
||||
typedef struct {
|
||||
mp_state_enum state; // OK, Warning, Critical ... set explicitly
|
||||
mp_state_enum default_state; // OK, Warning, Critical .. if not set explicitly
|
||||
bool state_set_explicitly; // was the state set explicitly (or should it be derived from subchecks)
|
||||
|
||||
char *output; // Text output for humans ("Filesystem xyz is fine", "Could not create TCP connection to..")
|
||||
pd_list *perfdata; // Performance data for this check
|
||||
struct subcheck_list *subchecks; // subchecks deeper in the hierarchy
|
||||
} mp_subcheck;
|
||||
|
||||
/*
|
||||
* A list of subchecks, used in subchecks and the main check
|
||||
*/
|
||||
typedef struct subcheck_list {
|
||||
mp_subcheck subcheck;
|
||||
struct subcheck_list *next;
|
||||
} mp_subcheck_list;
|
||||
|
||||
/*
|
||||
* Possible output formats
|
||||
*/
|
||||
typedef enum output_format {
|
||||
MP_FORMAT_MULTI_LINE,
|
||||
MP_FORMAT_TEST_JSON,
|
||||
} mp_output_format;
|
||||
|
||||
#define MP_FORMAT_DEFAULT MP_FORMAT_MULTI_LINE
|
||||
|
||||
/*
|
||||
* The main state object of a plugin. Exists only ONCE per plugin.
|
||||
* This is the "root" of a tree of singular checks.
|
||||
* The final result is always derived from the children and the "worst" state
|
||||
* in the first layer of subchecks
|
||||
*/
|
||||
typedef struct {
|
||||
mp_output_format format; // The output format
|
||||
char *summary; // Overall summary, if not set a summary will be automatically generated
|
||||
mp_subcheck_list *subchecks;
|
||||
} mp_check;
|
||||
|
||||
mp_check mp_check_init(void);
|
||||
mp_subcheck mp_subcheck_init(void);
|
||||
|
||||
mp_subcheck mp_set_subcheck_state(mp_subcheck, mp_state_enum);
|
||||
mp_subcheck mp_set_subcheck_default_state(mp_subcheck, mp_state_enum);
|
||||
|
||||
int mp_add_subcheck_to_check(mp_check check[static 1], mp_subcheck);
|
||||
int mp_add_subcheck_to_subcheck(mp_subcheck check[static 1], mp_subcheck);
|
||||
|
||||
void mp_add_perfdata_to_subcheck(mp_subcheck check[static 1], mp_perfdata);
|
||||
|
||||
void mp_add_summary(mp_check check[static 1], char *summary);
|
||||
|
||||
mp_state_enum mp_compute_check_state(mp_check);
|
||||
mp_state_enum mp_compute_subcheck_state(mp_subcheck);
|
||||
|
||||
typedef struct {
|
||||
bool parsing_success;
|
||||
mp_output_format output_format;
|
||||
} parsed_output_format;
|
||||
parsed_output_format mp_parse_output_format(char *format_string);
|
||||
|
||||
// TODO free and stuff
|
||||
// void mp_cleanup_check(mp_check check[static 1]);
|
||||
|
||||
char *mp_fmt_output(mp_check);
|
||||
|
||||
void mp_print_output(mp_check);
|
||||
|
||||
/*
|
||||
* ==================
|
||||
* Exit functionality
|
||||
* ==================
|
||||
*/
|
||||
|
||||
void mp_exit(mp_check) __attribute__((noreturn));
|
||||
516
lib/perfdata.c
Normal file
516
lib/perfdata.c
Normal file
|
|
@ -0,0 +1,516 @@
|
|||
#include "./perfdata.h"
|
||||
#include "../plugins/common.h"
|
||||
#include "../plugins/utils.h"
|
||||
#include "utils_base.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
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:
|
||||
asprintf(&result, "%lli", pd.pd_int);
|
||||
break;
|
||||
case PD_TYPE_UINT:
|
||||
asprintf(&result, "%llu", pd.pd_int);
|
||||
break;
|
||||
case PD_TYPE_DOUBLE:
|
||||
asprintf(&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;
|
||||
asprintf(&result, "%s=", pd.label);
|
||||
|
||||
asprintf(&result, "%s%s", result, pd_value_to_string(pd.value));
|
||||
|
||||
if (pd.uom != NULL) {
|
||||
asprintf(&result, "%s%s", result, pd.uom);
|
||||
}
|
||||
|
||||
if (pd.warn_present) {
|
||||
asprintf(&result, "%s;%s", result, mp_range_to_string(pd.warn));
|
||||
} else {
|
||||
asprintf(&result, "%s;", result);
|
||||
}
|
||||
|
||||
if (pd.crit_present) {
|
||||
asprintf(&result, "%s;%s", result, mp_range_to_string(pd.crit));
|
||||
} else {
|
||||
asprintf(&result, "%s;", result);
|
||||
}
|
||||
if (pd.min_present) {
|
||||
asprintf(&result, "%s;%s", result, pd_value_to_string(pd.min));
|
||||
} else {
|
||||
asprintf(&result, "%s;", result);
|
||||
}
|
||||
|
||||
if (pd.max_present) {
|
||||
asprintf(&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) {
|
||||
asprintf(&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) {
|
||||
asprintf(&result, "@");
|
||||
}
|
||||
|
||||
if (input.start_infinity) {
|
||||
asprintf(&result, "%s~:", result);
|
||||
} else {
|
||||
asprintf(&result, "%s%s:", result, pd_value_to_string(input.start));
|
||||
}
|
||||
|
||||
if (!input.end_infinity) {
|
||||
asprintf(&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;
|
||||
}
|
||||
203
lib/perfdata.h
Normal file
203
lib/perfdata.h
Normal file
|
|
@ -0,0 +1,203 @@
|
|||
#pragma once
|
||||
|
||||
#include "../config.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
// Enum for the specific type of a perfdata_value
|
||||
typedef enum pd_value_type {
|
||||
PD_TYPE_NONE = 0,
|
||||
PD_TYPE_INT,
|
||||
PD_TYPE_UINT,
|
||||
PD_TYPE_DOUBLE
|
||||
} pd_value_type;
|
||||
|
||||
typedef struct {
|
||||
enum pd_value_type type;
|
||||
union {
|
||||
long long pd_int;
|
||||
unsigned long long pd_uint;
|
||||
double pd_double;
|
||||
};
|
||||
} mp_perfdata_value;
|
||||
|
||||
#define MP_OUTSIDE false
|
||||
#define MP_INSIDE true
|
||||
|
||||
/*
|
||||
* New range type with generic numerical values
|
||||
*/
|
||||
typedef struct mp_range_struct {
|
||||
mp_perfdata_value start;
|
||||
bool start_infinity; /* false (default) or true */
|
||||
|
||||
mp_perfdata_value end;
|
||||
bool end_infinity;
|
||||
|
||||
bool alert_on_inside_range; /* OUTSIDE (default) or INSIDE */
|
||||
} mp_range;
|
||||
|
||||
/*
|
||||
* Old range type with floating point values
|
||||
*/
|
||||
typedef struct range_struct {
|
||||
double start;
|
||||
bool start_infinity;
|
||||
double end;
|
||||
int end_infinity;
|
||||
int alert_on; /* OUTSIDE (default) or INSIDE */
|
||||
char *text; /* original unparsed text input */
|
||||
} range;
|
||||
|
||||
/*
|
||||
* Perfdata type for storing perfdata output
|
||||
*/
|
||||
typedef struct perfdata_struct {
|
||||
char *label;
|
||||
char *uom;
|
||||
mp_perfdata_value value;
|
||||
|
||||
bool warn_present;
|
||||
mp_range warn;
|
||||
|
||||
bool crit_present;
|
||||
mp_range crit;
|
||||
|
||||
bool min_present;
|
||||
mp_perfdata_value min;
|
||||
|
||||
bool max_present;
|
||||
mp_perfdata_value max;
|
||||
} mp_perfdata;
|
||||
|
||||
/*
|
||||
* List of mp_perfdata values
|
||||
*/
|
||||
typedef struct pd_list_struct {
|
||||
mp_perfdata data;
|
||||
struct pd_list_struct *next;
|
||||
} pd_list;
|
||||
|
||||
/*
|
||||
* ============
|
||||
* Initializers
|
||||
* ============
|
||||
*/
|
||||
/*
|
||||
* Initialize mp_perfdata value. Always use this to generate a new one
|
||||
*/
|
||||
mp_perfdata perfdata_init(void);
|
||||
|
||||
/*
|
||||
* Initialize pd_list value. Always use this to generate a new one
|
||||
*/
|
||||
pd_list *pd_list_init(void);
|
||||
|
||||
/*
|
||||
* Initialize a new mp_range value, with unset values (start and end are infinite
|
||||
*/
|
||||
mp_range mp_range_init(void);
|
||||
|
||||
/*
|
||||
* Worker functions
|
||||
*/
|
||||
|
||||
mp_range mp_range_set_start(mp_range, mp_perfdata_value);
|
||||
mp_range mp_range_set_end(mp_range, mp_perfdata_value);
|
||||
|
||||
/*
|
||||
* Parsing a range from a string
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
MP_PARSING_SUCCES = 0,
|
||||
MP_PARSING_FAILURE,
|
||||
MP_RANGE_PARSING_FAILURE,
|
||||
MP_RANGE_PARSING_UNDERFLOW,
|
||||
MP_RANGE_PARSING_OVERFLOW,
|
||||
MP_RANGE_PARSING_INVALID_CHAR,
|
||||
} mp_range_parser_error;
|
||||
|
||||
typedef struct mp_range_parsed {
|
||||
mp_range_parser_error error;
|
||||
mp_range range;
|
||||
} mp_range_parsed;
|
||||
|
||||
mp_range_parsed mp_parse_range_string(const char * /*input*/);
|
||||
|
||||
/*
|
||||
* Appends a mp_perfdata value to a pd_list
|
||||
*/
|
||||
void pd_list_append(pd_list[1], mp_perfdata);
|
||||
|
||||
#define mp_set_pd_value(P, V) \
|
||||
_Generic((V), \
|
||||
float: mp_set_pd_value_float, \
|
||||
double: mp_set_pd_value_double, \
|
||||
int: mp_set_pd_value_int, \
|
||||
unsigned int: mp_set_pd_value_u_int, \
|
||||
long: mp_set_pd_value_long, \
|
||||
unsigned long: mp_set_pd_value_u_long, \
|
||||
long long: mp_set_pd_value_long_long, \
|
||||
unsigned long long: mp_set_pd_value_u_long_long)(P, V)
|
||||
|
||||
mp_perfdata mp_set_pd_value_float(mp_perfdata, float);
|
||||
mp_perfdata mp_set_pd_value_double(mp_perfdata, double);
|
||||
mp_perfdata mp_set_pd_value_int(mp_perfdata, int);
|
||||
mp_perfdata mp_set_pd_value_u_int(mp_perfdata, unsigned int);
|
||||
mp_perfdata mp_set_pd_value_long(mp_perfdata, long);
|
||||
mp_perfdata mp_set_pd_value_u_long(mp_perfdata, unsigned long);
|
||||
mp_perfdata mp_set_pd_value_long_long(mp_perfdata, long long);
|
||||
mp_perfdata mp_set_pd_value_u_long_long(mp_perfdata, unsigned long long);
|
||||
|
||||
#define mp_create_pd_value(V) \
|
||||
_Generic((V), \
|
||||
float: mp_create_pd_value_float, \
|
||||
double: mp_create_pd_value_double, \
|
||||
int: mp_create_pd_value_int, \
|
||||
unsigned int: mp_create_pd_value_u_int, \
|
||||
long: mp_create_pd_value_long, \
|
||||
unsigned long: mp_create_pd_value_u_long, \
|
||||
long long: mp_create_pd_value_long_long, \
|
||||
unsigned long long: mp_create_pd_value_u_long_long)(V)
|
||||
|
||||
mp_perfdata_value mp_create_pd_value_float(float);
|
||||
mp_perfdata_value mp_create_pd_value_double(double);
|
||||
mp_perfdata_value mp_create_pd_value_int(int);
|
||||
mp_perfdata_value mp_create_pd_value_u_int(unsigned int);
|
||||
mp_perfdata_value mp_create_pd_value_long(long);
|
||||
mp_perfdata_value mp_create_pd_value_u_long(unsigned long);
|
||||
mp_perfdata_value mp_create_pd_value_long_long(long long);
|
||||
mp_perfdata_value mp_create_pd_value_u_long_long(unsigned long long);
|
||||
|
||||
/*
|
||||
* Free the memory used by a pd_list
|
||||
*/
|
||||
void pd_list_free(pd_list[1]);
|
||||
|
||||
int cmp_perfdata_value(mp_perfdata_value, mp_perfdata_value);
|
||||
|
||||
// =================
|
||||
// String formatters
|
||||
// =================
|
||||
/*
|
||||
* Generate string from mp_perfdata value
|
||||
*/
|
||||
char *pd_to_string(mp_perfdata);
|
||||
|
||||
/*
|
||||
* Generate string from perfdata_value value
|
||||
*/
|
||||
char *pd_value_to_string(mp_perfdata_value);
|
||||
|
||||
/*
|
||||
* Generate string from pd_list value for the final output
|
||||
*/
|
||||
char *pd_list_to_string(pd_list);
|
||||
|
||||
/*
|
||||
* Generate string from a mp_range value
|
||||
*/
|
||||
char *mp_range_to_string(mp_range);
|
||||
char *fmt_range(range);
|
||||
71
lib/states.h
Normal file
71
lib/states.h
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
#ifndef _MP_STATES_
|
||||
#define _MP_STATES_
|
||||
|
||||
#include "../config.h"
|
||||
#include <sys/param.h>
|
||||
|
||||
typedef enum state_enum {
|
||||
STATE_OK,
|
||||
STATE_WARNING,
|
||||
STATE_CRITICAL,
|
||||
STATE_UNKNOWN,
|
||||
STATE_DEPENDENT
|
||||
} mp_state_enum;
|
||||
|
||||
/* **************************************************************************
|
||||
* 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
|
||||
****************************************************************************/
|
||||
|
||||
static inline mp_state_enum max_state(mp_state_enum a, mp_state_enum b) {
|
||||
if (a == STATE_CRITICAL || b == STATE_CRITICAL) {
|
||||
return STATE_CRITICAL;
|
||||
}
|
||||
if (a == STATE_WARNING || b == STATE_WARNING) {
|
||||
return STATE_WARNING;
|
||||
}
|
||||
if (a == STATE_OK || b == STATE_OK) {
|
||||
return STATE_OK;
|
||||
}
|
||||
if (a == STATE_UNKNOWN || b == STATE_UNKNOWN) {
|
||||
return STATE_UNKNOWN;
|
||||
}
|
||||
if (a == STATE_DEPENDENT || b == STATE_DEPENDENT) {
|
||||
return STATE_DEPENDENT;
|
||||
}
|
||||
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.
|
||||
****************************************************************************/
|
||||
|
||||
static inline mp_state_enum max_state_alt(mp_state_enum a, mp_state_enum b) {
|
||||
if (a == STATE_CRITICAL || b == STATE_CRITICAL) {
|
||||
return STATE_CRITICAL;
|
||||
}
|
||||
if (a == STATE_WARNING || b == STATE_WARNING) {
|
||||
return STATE_WARNING;
|
||||
}
|
||||
if (a == STATE_UNKNOWN || b == STATE_UNKNOWN) {
|
||||
return STATE_UNKNOWN;
|
||||
}
|
||||
if (a == STATE_DEPENDENT || b == STATE_DEPENDENT) {
|
||||
return STATE_DEPENDENT;
|
||||
}
|
||||
if (a == STATE_OK || b == STATE_OK) {
|
||||
return STATE_OK;
|
||||
}
|
||||
return MAX(a, b);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -8,9 +8,9 @@ check_PROGRAMS = @EXTRA_TEST@
|
|||
AM_CPPFLAGS = -DNP_STATE_DIR_PREFIX=\"$(localstatedir)\" \
|
||||
-I$(top_srcdir)/lib -I$(top_srcdir)/gl -I$(top_srcdir)/intl -I$(top_srcdir)/plugins
|
||||
|
||||
EXTRA_PROGRAMS = test_utils test_disk test_tcp test_cmd test_base64 test_ini1 test_ini3 test_opts1 test_opts2 test_opts3
|
||||
EXTRA_PROGRAMS = test_utils test_disk test_tcp test_cmd test_base64 test_ini1 test_ini3 test_opts1 test_opts2 test_opts3 test_generic_output
|
||||
|
||||
np_test_scripts = test_base64.t test_cmd.t test_disk.t test_ini1.t test_ini3.t test_opts1.t test_opts2.t test_opts3.t test_tcp.t test_utils.t
|
||||
np_test_scripts = test_base64.t test_cmd.t test_disk.t test_ini1.t test_ini3.t test_opts1.t test_opts2.t test_opts3.t test_tcp.t test_utils.t test_generic_output.t
|
||||
np_test_files = config-dos.ini config-opts.ini config-tiny.ini plugin.ini plugins.ini
|
||||
EXTRA_DIST = $(np_test_scripts) $(np_test_files) var
|
||||
|
||||
|
|
@ -29,7 +29,7 @@ AM_CFLAGS = -g -I$(top_srcdir)/lib -I$(top_srcdir)/gl $(tap_cflags)
|
|||
AM_LDFLAGS = $(tap_ldflags) -ltap
|
||||
LDADD = $(top_srcdir)/lib/libmonitoringplug.a $(top_srcdir)/gl/libgnu.a $(LIB_CRYPTO)
|
||||
|
||||
SOURCES = test_utils.c test_disk.c test_tcp.c test_cmd.c test_base64.c test_ini1.c test_ini3.c test_opts1.c test_opts2.c test_opts3.c
|
||||
SOURCES = test_utils.c test_disk.c test_tcp.c test_cmd.c test_base64.c test_ini1.c test_ini3.c test_opts1.c test_opts2.c test_opts3.c test_generic_output.c
|
||||
|
||||
test: ${noinst_PROGRAMS}
|
||||
perl -MTest::Harness -e '$$Test::Harness::switches=""; runtests(map {$$_ .= ".t"} @ARGV)' $(EXTRA_PROGRAMS)
|
||||
|
|
|
|||
315
lib/tests/test_generic_output.c
Normal file
315
lib/tests/test_generic_output.c
Normal file
|
|
@ -0,0 +1,315 @@
|
|||
#include "../lib/output.h"
|
||||
#include "../../tap/tap.h"
|
||||
#include "./states.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
void test_one_subcheck(void);
|
||||
void test_two_subchecks(void);
|
||||
|
||||
void test_perfdata_formatting(void);
|
||||
void test_perfdata_formatting2(void);
|
||||
|
||||
void test_deep_check_hierarchy(void);
|
||||
void test_deep_check_hierarchy2(void);
|
||||
|
||||
void test_default_states1(void);
|
||||
void test_default_states2(void);
|
||||
|
||||
int main(void) {
|
||||
plan_tests(19);
|
||||
|
||||
diag("Simple test with one subcheck");
|
||||
test_one_subcheck();
|
||||
|
||||
diag("Test with two subchecks");
|
||||
test_two_subchecks();
|
||||
|
||||
diag("Test for performance data formatting");
|
||||
test_perfdata_formatting();
|
||||
|
||||
diag("Another test for performance data formatting");
|
||||
test_perfdata_formatting2();
|
||||
|
||||
diag("Test for deeper hierarchies");
|
||||
test_deep_check_hierarchy();
|
||||
|
||||
diag("Another test for deeper hierarchies");
|
||||
test_deep_check_hierarchy2();
|
||||
|
||||
diag("Testing the default state logic");
|
||||
test_default_states1();
|
||||
|
||||
diag("Testing the default state logic #2");
|
||||
test_default_states2();
|
||||
|
||||
return exit_status();
|
||||
}
|
||||
|
||||
void test_one_subcheck(void) {
|
||||
mp_subcheck sc1 = mp_subcheck_init();
|
||||
|
||||
sc1.output = "foobar";
|
||||
sc1 = mp_set_subcheck_state(sc1, STATE_WARNING);
|
||||
|
||||
mp_check check = mp_check_init();
|
||||
mp_add_subcheck_to_check(&check, sc1);
|
||||
|
||||
ok(mp_compute_check_state(check) == STATE_WARNING, "Main state should be warning");
|
||||
|
||||
char *output = mp_fmt_output(check);
|
||||
|
||||
// diag("Formatted output");
|
||||
// diag(output);
|
||||
|
||||
char expected[] = "[WARNING] - ok=0, warning=1, critical=0, unknown=0\n"
|
||||
"\t\\_[WARNING] - foobar\n";
|
||||
|
||||
// diag("Expected output");
|
||||
// diag(expected);
|
||||
|
||||
ok(strcmp(output, expected) == 0, "Simple output test");
|
||||
}
|
||||
|
||||
void test_perfdata_formatting2(void) {
|
||||
mp_perfdata pd1 = perfdata_init();
|
||||
mp_perfdata pd2 = perfdata_init();
|
||||
|
||||
pd1.label = "foo";
|
||||
pd2.label = "bar";
|
||||
|
||||
pd1 = mp_set_pd_value(pd1, 23);
|
||||
pd2 = mp_set_pd_value(pd2, 1LL);
|
||||
|
||||
pd_list *tmp = pd_list_init();
|
||||
|
||||
pd_list_append(tmp, pd1);
|
||||
pd_list_append(tmp, pd2);
|
||||
|
||||
char *result = pd_list_to_string(*tmp);
|
||||
|
||||
ok(strcmp(result, "foo=23;;; bar=1;;;") == 0, "Perfdata string formatting");
|
||||
}
|
||||
|
||||
void test_perfdata_formatting(void) {
|
||||
mp_perfdata pd1 = perfdata_init();
|
||||
|
||||
pd1.uom = "s";
|
||||
pd1.label = "foo";
|
||||
|
||||
pd1 = mp_set_pd_value(pd1, 23);
|
||||
|
||||
char *pd_string = pd_to_string(pd1);
|
||||
|
||||
ok(strcmp(pd_string, "foo=23s;;;") == 0, "Perfdata string formatting");
|
||||
}
|
||||
|
||||
void test_two_subchecks(void) {
|
||||
mp_subcheck sc1 = mp_subcheck_init();
|
||||
|
||||
sc1.output = "foobar";
|
||||
sc1 = mp_set_subcheck_state(sc1, STATE_WARNING);
|
||||
|
||||
ok(mp_compute_subcheck_state(sc1) == STATE_WARNING, "Test subcheck state directly after setting it");
|
||||
|
||||
mp_perfdata pd1 = perfdata_init();
|
||||
|
||||
pd1 = mp_set_pd_value(pd1, 23);
|
||||
|
||||
pd1.uom = "s";
|
||||
pd1.label = "foo";
|
||||
|
||||
mp_add_perfdata_to_subcheck(&sc1, pd1);
|
||||
|
||||
mp_subcheck sc2 = mp_subcheck_init();
|
||||
sc2.output = "baz";
|
||||
sc2 = mp_set_subcheck_state(sc2, STATE_OK);
|
||||
|
||||
ok(mp_compute_subcheck_state(sc2) == STATE_OK, "Test subcheck 2 state after setting it");
|
||||
|
||||
mp_add_subcheck_to_subcheck(&sc1, sc2);
|
||||
|
||||
ok(mp_compute_subcheck_state(sc1) == STATE_WARNING, "Test subcheck state after adding a subcheck");
|
||||
|
||||
mp_check check = mp_check_init();
|
||||
mp_add_subcheck_to_check(&check, sc1);
|
||||
|
||||
ok(mp_compute_check_state(check) == STATE_WARNING, "Test main check result");
|
||||
|
||||
char *output = mp_fmt_output(check);
|
||||
|
||||
// diag("Formatted output. Length: %u", strlen(output));
|
||||
// diag(output);
|
||||
|
||||
ok(output != NULL, "Output should not be NULL");
|
||||
|
||||
char expected[] = "[WARNING] - ok=0, warning=1, critical=0, unknown=0\n"
|
||||
"\t\\_[WARNING] - foobar\n"
|
||||
"\t\t\\_[OK] - baz\n"
|
||||
"|foo=23s;;; \n";
|
||||
|
||||
// diag("Expected output. Length: %u", strlen(expected));
|
||||
// diag(expected);
|
||||
|
||||
ok(strcmp(output, expected) == 0, "Output is as expected");
|
||||
}
|
||||
|
||||
void test_deep_check_hierarchy(void) {
|
||||
// level 4
|
||||
mp_subcheck sc4 = mp_subcheck_init();
|
||||
sc4.output = "level4";
|
||||
sc4 = mp_set_subcheck_state(sc4, STATE_OK);
|
||||
|
||||
// level 3
|
||||
mp_subcheck sc3 = mp_subcheck_init();
|
||||
sc3.output = "level3";
|
||||
sc3 = mp_set_subcheck_state(sc3, STATE_OK);
|
||||
|
||||
// level 2
|
||||
mp_subcheck sc2 = mp_subcheck_init();
|
||||
sc2.output = "baz";
|
||||
sc2 = mp_set_subcheck_state(sc2, STATE_OK);
|
||||
|
||||
// level 1
|
||||
mp_subcheck sc1 = mp_subcheck_init();
|
||||
|
||||
sc1.output = "foobar";
|
||||
sc1 = mp_set_subcheck_state(sc1, STATE_WARNING);
|
||||
|
||||
mp_perfdata pd1 = perfdata_init();
|
||||
|
||||
pd1.uom = "s";
|
||||
pd1.label = "foo";
|
||||
pd1 = mp_set_pd_value(pd1, 23);
|
||||
|
||||
mp_add_perfdata_to_subcheck(&sc1, pd1);
|
||||
|
||||
// main check
|
||||
mp_check check = mp_check_init();
|
||||
|
||||
mp_add_subcheck_to_subcheck(&sc3, sc4);
|
||||
mp_add_subcheck_to_subcheck(&sc2, sc3);
|
||||
mp_add_subcheck_to_subcheck(&sc1, sc2);
|
||||
mp_add_subcheck_to_check(&check, sc1);
|
||||
|
||||
char *output = mp_fmt_output(check);
|
||||
|
||||
size_t output_length = strlen(output);
|
||||
|
||||
// diag("Formatted output of length %i", output_length);
|
||||
// diag(output);
|
||||
|
||||
ok(output != NULL, "Output should not be NULL");
|
||||
|
||||
char expected[] = "[WARNING] - ok=0, warning=1, critical=0, unknown=0\n"
|
||||
"\t\\_[WARNING] - foobar\n"
|
||||
"\t\t\\_[OK] - baz\n"
|
||||
"\t\t\t\\_[OK] - level3\n"
|
||||
"\t\t\t\t\\_[OK] - level4\n"
|
||||
"|foo=23s;;; \n";
|
||||
|
||||
size_t expected_length = strlen(expected);
|
||||
|
||||
// diag("Expected output of length: %i", expected_length);
|
||||
// diag(expected);
|
||||
|
||||
ok(output_length == expected_length, "Outputs are of equal length");
|
||||
ok(strcmp(output, expected) == 0, "Output is as expected");
|
||||
}
|
||||
|
||||
void test_deep_check_hierarchy2(void) {
|
||||
// level 1
|
||||
mp_subcheck sc1 = mp_subcheck_init();
|
||||
|
||||
sc1.output = "foobar";
|
||||
sc1 = mp_set_subcheck_state(sc1, STATE_WARNING);
|
||||
|
||||
mp_perfdata pd1 = perfdata_init();
|
||||
pd1.uom = "s";
|
||||
pd1.label = "foo";
|
||||
pd1 = mp_set_pd_value(pd1, 23);
|
||||
|
||||
mp_add_perfdata_to_subcheck(&sc1, pd1);
|
||||
|
||||
// level 2
|
||||
mp_subcheck sc2 = mp_subcheck_init();
|
||||
sc2.output = "baz";
|
||||
sc2 = mp_set_subcheck_state(sc2, STATE_OK);
|
||||
|
||||
mp_perfdata pd2 = perfdata_init();
|
||||
pd2.uom = "B";
|
||||
pd2.label = "baz";
|
||||
pd2 = mp_set_pd_value(pd2, 1024);
|
||||
mp_add_perfdata_to_subcheck(&sc2, pd2);
|
||||
|
||||
// level 3
|
||||
mp_subcheck sc3 = mp_subcheck_init();
|
||||
sc3.output = "level3";
|
||||
sc3 = mp_set_subcheck_state(sc3, STATE_OK);
|
||||
|
||||
mp_perfdata pd3 = perfdata_init();
|
||||
pd3.label = "floatMe";
|
||||
pd3 = mp_set_pd_value(pd3, 1024.1024);
|
||||
mp_add_perfdata_to_subcheck(&sc3, pd3);
|
||||
|
||||
// level 4
|
||||
mp_subcheck sc4 = mp_subcheck_init();
|
||||
sc4.output = "level4";
|
||||
sc4 = mp_set_subcheck_state(sc4, STATE_OK);
|
||||
|
||||
mp_check check = mp_check_init();
|
||||
|
||||
mp_add_subcheck_to_subcheck(&sc3, sc4);
|
||||
mp_add_subcheck_to_subcheck(&sc2, sc3);
|
||||
mp_add_subcheck_to_subcheck(&sc1, sc2);
|
||||
mp_add_subcheck_to_check(&check, sc1);
|
||||
|
||||
char *output = mp_fmt_output(check);
|
||||
|
||||
// diag("Formatted output of length: %i", strlen(output));
|
||||
// diag(output);
|
||||
|
||||
ok(output != NULL, "Output should not be NULL");
|
||||
|
||||
char expected[] = "[WARNING] - ok=0, warning=1, critical=0, unknown=0\n"
|
||||
"\t\\_[WARNING] - foobar\n"
|
||||
"\t\t\\_[OK] - baz\n"
|
||||
"\t\t\t\\_[OK] - level3\n"
|
||||
"\t\t\t\t\\_[OK] - level4\n"
|
||||
"|foo=23s;;; baz=1024B;;; floatMe=1024.102400;;; \n";
|
||||
|
||||
// diag("Expected output of length: %i", strlen(expected));
|
||||
// diag(expected);
|
||||
|
||||
ok(strcmp(output, expected) == 0, "Output is as expected");
|
||||
}
|
||||
|
||||
void test_default_states1(void) {
|
||||
mp_subcheck sc = mp_subcheck_init();
|
||||
|
||||
mp_state_enum state1 = mp_compute_subcheck_state(sc);
|
||||
ok(state1 == STATE_UNKNOWN, "Default default state is Unknown");
|
||||
|
||||
sc = mp_set_subcheck_default_state(sc, STATE_CRITICAL);
|
||||
|
||||
mp_state_enum state2 = mp_compute_subcheck_state(sc);
|
||||
ok(state2 == STATE_CRITICAL, "Default state is Critical");
|
||||
|
||||
sc = mp_set_subcheck_state(sc, STATE_OK);
|
||||
|
||||
mp_state_enum state3 = mp_compute_subcheck_state(sc);
|
||||
ok(state3 == STATE_OK, "Default state is Critical");
|
||||
}
|
||||
|
||||
void test_default_states2(void) {
|
||||
mp_check check = mp_check_init();
|
||||
|
||||
mp_subcheck sc = mp_subcheck_init();
|
||||
sc.output = "placeholder";
|
||||
sc = mp_set_subcheck_default_state(sc, STATE_CRITICAL);
|
||||
|
||||
mp_add_subcheck_to_check(&check, sc);
|
||||
|
||||
mp_state_enum result_state = mp_compute_check_state(check);
|
||||
ok(result_state == STATE_CRITICAL, "Derived state is the proper default state");
|
||||
}
|
||||
6
lib/tests/test_generic_output.t
Normal file
6
lib/tests/test_generic_output.t
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
#!/usr/bin/perl
|
||||
use Test::More;
|
||||
if (! -e "./test_generic_output") {
|
||||
plan skip_all => "./test_generic_output not compiled - please enable libtap library to test";
|
||||
}
|
||||
exec "./test_generic_output";
|
||||
59
lib/thresholds.c
Normal file
59
lib/thresholds.c
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
#include "./thresholds.h"
|
||||
#include "./utils_base.h"
|
||||
#include "perfdata.h"
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
mp_thresholds mp_thresholds_init() {
|
||||
mp_thresholds tmp = {
|
||||
.critical = {},
|
||||
.critical_is_set = false,
|
||||
.warning = {},
|
||||
.warning_is_set = false,
|
||||
};
|
||||
return tmp;
|
||||
}
|
||||
|
||||
char *fmt_threshold_warning(const thresholds th) {
|
||||
if (th.warning == NULL) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return fmt_range(*th.warning);
|
||||
}
|
||||
|
||||
char *fmt_threshold_critical(const thresholds th) {
|
||||
if (th.critical == NULL) {
|
||||
return "";
|
||||
}
|
||||
return fmt_range(*th.critical);
|
||||
}
|
||||
|
||||
mp_perfdata mp_pd_set_thresholds(mp_perfdata perfdata, mp_thresholds threshold) {
|
||||
if (threshold.critical_is_set) {
|
||||
perfdata.crit = threshold.critical;
|
||||
perfdata.crit_present = true;
|
||||
}
|
||||
|
||||
if (threshold.warning_is_set) {
|
||||
perfdata.warn = threshold.warning;
|
||||
perfdata.warn_present = true;
|
||||
}
|
||||
|
||||
return perfdata;
|
||||
}
|
||||
|
||||
mp_state_enum mp_get_pd_status(mp_perfdata perfdata) {
|
||||
if (perfdata.crit_present) {
|
||||
if (mp_check_range(perfdata.value, perfdata.crit)) {
|
||||
return STATE_CRITICAL;
|
||||
}
|
||||
}
|
||||
if (perfdata.warn_present) {
|
||||
if (mp_check_range(perfdata.value, perfdata.warn)) {
|
||||
return STATE_CRITICAL;
|
||||
}
|
||||
}
|
||||
|
||||
return STATE_OK;
|
||||
}
|
||||
28
lib/thresholds.h
Normal file
28
lib/thresholds.h
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
#pragma once
|
||||
|
||||
#include "./perfdata.h"
|
||||
#include "states.h"
|
||||
|
||||
/*
|
||||
* Old threshold type using the old range type
|
||||
*/
|
||||
typedef struct thresholds_struct {
|
||||
range *warning;
|
||||
range *critical;
|
||||
} thresholds;
|
||||
|
||||
typedef struct mp_thresholds_struct {
|
||||
bool warning_is_set;
|
||||
mp_range warning;
|
||||
bool critical_is_set;
|
||||
mp_range critical;
|
||||
} mp_thresholds;
|
||||
|
||||
mp_thresholds mp_thresholds_init(void);
|
||||
|
||||
mp_perfdata mp_pd_set_thresholds(mp_perfdata /* pd */, mp_thresholds /* th */);
|
||||
|
||||
mp_state_enum mp_get_pd_status(mp_perfdata /* pd */);
|
||||
|
||||
char *fmt_threshold_warning(thresholds th);
|
||||
char *fmt_threshold_critical(thresholds th);
|
||||
167
lib/utils_base.c
167
lib/utils_base.c
|
|
@ -55,22 +55,24 @@ void np_init(char *plugin_name, int argc, char **argv) {
|
|||
die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno));
|
||||
}
|
||||
this_monitoring_plugin->plugin_name = strdup(plugin_name);
|
||||
if (this_monitoring_plugin->plugin_name == NULL)
|
||||
if (this_monitoring_plugin->plugin_name == NULL) {
|
||||
die(STATE_UNKNOWN, _("Cannot execute strdup: %s"), strerror(errno));
|
||||
}
|
||||
this_monitoring_plugin->argc = argc;
|
||||
this_monitoring_plugin->argv = argv;
|
||||
}
|
||||
}
|
||||
|
||||
void np_set_args(int argc, char **argv) {
|
||||
if (this_monitoring_plugin == NULL)
|
||||
if (this_monitoring_plugin == NULL) {
|
||||
die(STATE_UNKNOWN, _("This requires np_init to be called"));
|
||||
}
|
||||
|
||||
this_monitoring_plugin->argc = argc;
|
||||
this_monitoring_plugin->argv = argv;
|
||||
}
|
||||
|
||||
void np_cleanup() {
|
||||
void np_cleanup(void) {
|
||||
if (this_monitoring_plugin != NULL) {
|
||||
if (this_monitoring_plugin->state != NULL) {
|
||||
if (this_monitoring_plugin->state->state_data) {
|
||||
|
|
@ -162,8 +164,9 @@ range *parse_range_string(char *str) {
|
|||
int _set_thresholds(thresholds **my_thresholds, char *warn_string, char *critical_string) {
|
||||
thresholds *temp_thresholds = NULL;
|
||||
|
||||
if ((temp_thresholds = calloc(1, sizeof(thresholds))) == NULL)
|
||||
if ((temp_thresholds = calloc(1, sizeof(thresholds))) == NULL) {
|
||||
die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno));
|
||||
}
|
||||
|
||||
temp_thresholds->warning = NULL;
|
||||
temp_thresholds->critical = NULL;
|
||||
|
|
@ -215,6 +218,46 @@ void print_thresholds(const char *threshold_name, thresholds *my_threshold) {
|
|||
printf("\n");
|
||||
}
|
||||
|
||||
/* Returns true if alert should be raised based on the range, false otherwise */
|
||||
bool mp_check_range(const mp_perfdata_value value, const mp_range my_range) {
|
||||
bool is_inside = false;
|
||||
|
||||
if (my_range.end_infinity == false && my_range.start_infinity == false) {
|
||||
// range: .........|---inside---|...........
|
||||
// value
|
||||
if ((cmp_perfdata_value(my_range.start, value) < 1) && (cmp_perfdata_value(value, my_range.end) <= 0)) {
|
||||
is_inside = true;
|
||||
} else {
|
||||
is_inside = false;
|
||||
}
|
||||
} else if (my_range.start_infinity == false && my_range.end_infinity == true) {
|
||||
// range: .........|---inside---------
|
||||
// value
|
||||
if (cmp_perfdata_value(my_range.start, value) < 0) {
|
||||
is_inside = true;
|
||||
} else {
|
||||
is_inside = false;
|
||||
}
|
||||
} else if (my_range.start_infinity == true && my_range.end_infinity == false) {
|
||||
// range: -inside--------|....................
|
||||
// value
|
||||
if (cmp_perfdata_value(value, my_range.end) == -1) {
|
||||
is_inside = true;
|
||||
} else {
|
||||
is_inside = false;
|
||||
}
|
||||
} else {
|
||||
// range from -inf to inf, so always inside
|
||||
is_inside = true;
|
||||
}
|
||||
|
||||
if ((is_inside && my_range.alert_on_inside_range == INSIDE) || (!is_inside && my_range.alert_on_inside_range == OUTSIDE)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Returns true if alert should be raised based on the range */
|
||||
bool check_range(double value, range *my_range) {
|
||||
bool no = false;
|
||||
|
|
@ -228,24 +271,24 @@ bool check_range(double value, range *my_range) {
|
|||
if (my_range->end_infinity == false && my_range->start_infinity == false) {
|
||||
if ((my_range->start <= value) && (value <= my_range->end)) {
|
||||
return no;
|
||||
} else {
|
||||
return yes;
|
||||
}
|
||||
} else if (my_range->start_infinity == false && my_range->end_infinity == true) {
|
||||
return yes;
|
||||
}
|
||||
|
||||
if (my_range->start_infinity == false && my_range->end_infinity == true) {
|
||||
if (my_range->start <= value) {
|
||||
return no;
|
||||
} else {
|
||||
return yes;
|
||||
}
|
||||
} else if (my_range->start_infinity == true && my_range->end_infinity == false) {
|
||||
return yes;
|
||||
}
|
||||
|
||||
if (my_range->start_infinity == true && my_range->end_infinity == false) {
|
||||
if (value <= my_range->end) {
|
||||
return no;
|
||||
} else {
|
||||
return yes;
|
||||
}
|
||||
} else {
|
||||
return no;
|
||||
return yes;
|
||||
}
|
||||
return no;
|
||||
}
|
||||
|
||||
/* Returns status */
|
||||
|
|
@ -265,7 +308,8 @@ int get_status(double value, thresholds *my_thresholds) {
|
|||
|
||||
char *np_escaped_string(const char *string) {
|
||||
char *data;
|
||||
int i, j = 0;
|
||||
int i;
|
||||
int j = 0;
|
||||
data = strdup(string);
|
||||
for (i = 0; data[i]; i++) {
|
||||
if (data[i] == '\\') {
|
||||
|
|
@ -302,7 +346,8 @@ int np_check_if_root(void) { return (geteuid() == 0); }
|
|||
* data strings.
|
||||
*/
|
||||
char *np_extract_value(const char *varlist, const char *name, char sep) {
|
||||
char *tmp = NULL, *value = NULL;
|
||||
char *tmp = NULL;
|
||||
char *value = NULL;
|
||||
int i;
|
||||
|
||||
while (1) {
|
||||
|
|
@ -325,15 +370,17 @@ char *np_extract_value(const char *varlist, const char *name, char sep) {
|
|||
|
||||
if ((tmp = index(varlist, sep))) {
|
||||
/* Value is delimited by a comma */
|
||||
if (tmp - varlist == 0)
|
||||
if (tmp - varlist == 0) {
|
||||
continue;
|
||||
}
|
||||
value = (char *)calloc(1, tmp - varlist + 1);
|
||||
strncpy(value, varlist, tmp - varlist);
|
||||
value[tmp - varlist] = '\0';
|
||||
} else {
|
||||
/* Value is delimited by a \0 */
|
||||
if (strlen(varlist) == 0)
|
||||
if (strlen(varlist) == 0) {
|
||||
continue;
|
||||
}
|
||||
value = (char *)calloc(1, strlen(varlist) + 1);
|
||||
strncpy(value, varlist, strlen(varlist));
|
||||
value[strlen(varlist)] = '\0';
|
||||
|
|
@ -351,9 +398,11 @@ char *np_extract_value(const char *varlist, const char *name, char sep) {
|
|||
}
|
||||
|
||||
/* Clean-up trailing spaces/newlines */
|
||||
if (value)
|
||||
for (i = strlen(value) - 1; isspace(value[i]); i--)
|
||||
if (value) {
|
||||
for (i = strlen(value) - 1; isspace(value[i]); i--) {
|
||||
value[i] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
|
@ -378,14 +427,18 @@ const char *state_text(int result) {
|
|||
* return the corresponding STATE_ value or ERROR)
|
||||
*/
|
||||
int mp_translate_state(char *state_text) {
|
||||
if (!strcasecmp(state_text, "OK") || !strcmp(state_text, "0"))
|
||||
if (!strcasecmp(state_text, "OK") || !strcmp(state_text, "0")) {
|
||||
return STATE_OK;
|
||||
if (!strcasecmp(state_text, "WARNING") || !strcmp(state_text, "1"))
|
||||
}
|
||||
if (!strcasecmp(state_text, "WARNING") || !strcmp(state_text, "1")) {
|
||||
return STATE_WARNING;
|
||||
if (!strcasecmp(state_text, "CRITICAL") || !strcmp(state_text, "2"))
|
||||
}
|
||||
if (!strcasecmp(state_text, "CRITICAL") || !strcmp(state_text, "2")) {
|
||||
return STATE_CRITICAL;
|
||||
if (!strcasecmp(state_text, "UNKNOWN") || !strcmp(state_text, "3"))
|
||||
}
|
||||
if (!strcasecmp(state_text, "UNKNOWN") || !strcmp(state_text, "3")) {
|
||||
return STATE_UNKNOWN;
|
||||
}
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
|
|
@ -394,7 +447,7 @@ int mp_translate_state(char *state_text) {
|
|||
* hopefully a unique key per service/plugin invocation. Use the extra-opts
|
||||
* parse of argv, so that uniqueness in parameters are reflected there.
|
||||
*/
|
||||
char *_np_state_generate_key() {
|
||||
char *_np_state_generate_key(void) {
|
||||
int i;
|
||||
char **argv = this_monitoring_plugin->argv;
|
||||
char keyname[41];
|
||||
|
|
@ -441,7 +494,7 @@ char *_np_state_generate_key() {
|
|||
return p;
|
||||
}
|
||||
|
||||
void _cleanup_state_data() {
|
||||
void _cleanup_state_data(void) {
|
||||
if (this_monitoring_plugin->state->state_data != NULL) {
|
||||
np_free(this_monitoring_plugin->state->state_data->data);
|
||||
np_free(this_monitoring_plugin->state->state_data);
|
||||
|
|
@ -453,19 +506,21 @@ void _cleanup_state_data() {
|
|||
* envvar NAGIOS_PLUGIN_STATE_DIRECTORY
|
||||
* statically compiled shared state directory
|
||||
*/
|
||||
char *_np_state_calculate_location_prefix() {
|
||||
char *_np_state_calculate_location_prefix(void) {
|
||||
char *env_dir;
|
||||
|
||||
/* Do not allow passing MP_STATE_PATH in setuid plugins
|
||||
* for security reasons */
|
||||
if (!mp_suid()) {
|
||||
env_dir = getenv("MP_STATE_PATH");
|
||||
if (env_dir && env_dir[0] != '\0')
|
||||
if (env_dir && env_dir[0] != '\0') {
|
||||
return env_dir;
|
||||
}
|
||||
/* This is the former ENV, for backward-compatibility */
|
||||
env_dir = getenv("NAGIOS_PLUGIN_STATE_DIRECTORY");
|
||||
if (env_dir && env_dir[0] != '\0')
|
||||
if (env_dir && env_dir[0] != '\0') {
|
||||
return env_dir;
|
||||
}
|
||||
}
|
||||
|
||||
return NP_STATE_DIR_PREFIX;
|
||||
|
|
@ -483,19 +538,22 @@ void np_enable_state(char *keyname, int expected_data_version) {
|
|||
char *p = NULL;
|
||||
int ret;
|
||||
|
||||
if (this_monitoring_plugin == NULL)
|
||||
if (this_monitoring_plugin == NULL) {
|
||||
die(STATE_UNKNOWN, _("This requires np_init to be called"));
|
||||
}
|
||||
|
||||
this_state = (state_key *)calloc(1, sizeof(state_key));
|
||||
if (this_state == NULL)
|
||||
if (this_state == NULL) {
|
||||
die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno));
|
||||
}
|
||||
|
||||
if (keyname == NULL) {
|
||||
temp_keyname = _np_state_generate_key();
|
||||
} else {
|
||||
temp_keyname = strdup(keyname);
|
||||
if (temp_keyname == NULL)
|
||||
if (temp_keyname == NULL) {
|
||||
die(STATE_UNKNOWN, _("Cannot execute strdup: %s"), strerror(errno));
|
||||
}
|
||||
}
|
||||
/* Die if invalid characters used for keyname */
|
||||
p = temp_keyname;
|
||||
|
|
@ -513,8 +571,9 @@ void np_enable_state(char *keyname, int expected_data_version) {
|
|||
/* Calculate filename */
|
||||
ret = asprintf(&temp_filename, "%s/%lu/%s/%s", _np_state_calculate_location_prefix(), (unsigned long)geteuid(),
|
||||
this_monitoring_plugin->plugin_name, this_state->name);
|
||||
if (ret < 0)
|
||||
if (ret < 0) {
|
||||
die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno));
|
||||
}
|
||||
|
||||
this_state->_filename = temp_filename;
|
||||
|
||||
|
|
@ -528,21 +587,23 @@ void np_enable_state(char *keyname, int expected_data_version) {
|
|||
* If numerically lower, then return as no previous state. die with UNKNOWN
|
||||
* if exceptional error.
|
||||
*/
|
||||
state_data *np_state_read() {
|
||||
state_data *np_state_read(void) {
|
||||
state_data *this_state_data = NULL;
|
||||
FILE *statefile;
|
||||
bool rc = false;
|
||||
|
||||
if (this_monitoring_plugin == NULL)
|
||||
if (this_monitoring_plugin == NULL) {
|
||||
die(STATE_UNKNOWN, _("This requires np_init to be called"));
|
||||
}
|
||||
|
||||
/* Open file. If this fails, no previous state found */
|
||||
statefile = fopen(this_monitoring_plugin->state->_filename, "r");
|
||||
if (statefile != NULL) {
|
||||
|
||||
this_state_data = (state_data *)calloc(1, sizeof(state_data));
|
||||
if (this_state_data == NULL)
|
||||
if (this_state_data == NULL) {
|
||||
die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno));
|
||||
}
|
||||
|
||||
this_state_data->data = NULL;
|
||||
this_monitoring_plugin->state->state_data = this_state_data;
|
||||
|
|
@ -581,8 +642,9 @@ bool _np_state_read_file(FILE *f) {
|
|||
|
||||
/* Note: This introduces a limit of 1024 bytes in the string data */
|
||||
line = (char *)calloc(1, 1024);
|
||||
if (line == NULL)
|
||||
if (line == NULL) {
|
||||
die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno));
|
||||
}
|
||||
|
||||
while (!failure && (fgets(line, 1024, f)) != NULL) {
|
||||
pos = strlen(line);
|
||||
|
|
@ -590,38 +652,42 @@ bool _np_state_read_file(FILE *f) {
|
|||
line[pos - 1] = '\0';
|
||||
}
|
||||
|
||||
if (line[0] == '#')
|
||||
if (line[0] == '#') {
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (expected) {
|
||||
case STATE_FILE_VERSION:
|
||||
i = atoi(line);
|
||||
if (i != NP_STATE_FORMAT_VERSION)
|
||||
if (i != NP_STATE_FORMAT_VERSION) {
|
||||
failure++;
|
||||
else
|
||||
} else {
|
||||
expected = STATE_DATA_VERSION;
|
||||
}
|
||||
break;
|
||||
case STATE_DATA_VERSION:
|
||||
i = atoi(line);
|
||||
if (i != this_monitoring_plugin->state->data_version)
|
||||
if (i != this_monitoring_plugin->state->data_version) {
|
||||
failure++;
|
||||
else
|
||||
} else {
|
||||
expected = STATE_DATA_TIME;
|
||||
}
|
||||
break;
|
||||
case STATE_DATA_TIME:
|
||||
/* If time > now, error */
|
||||
data_time = strtoul(line, NULL, 10);
|
||||
if (data_time > current_time)
|
||||
if (data_time > current_time) {
|
||||
failure++;
|
||||
else {
|
||||
} else {
|
||||
this_monitoring_plugin->state->state_data->time = data_time;
|
||||
expected = STATE_DATA_TEXT;
|
||||
}
|
||||
break;
|
||||
case STATE_DATA_TEXT:
|
||||
this_monitoring_plugin->state->state_data->data = strdup(line);
|
||||
if (this_monitoring_plugin->state->state_data->data == NULL)
|
||||
if (this_monitoring_plugin->state->state_data->data == NULL) {
|
||||
die(STATE_UNKNOWN, _("Cannot execute strdup: %s"), strerror(errno));
|
||||
}
|
||||
expected = STATE_DATA_END;
|
||||
status = true;
|
||||
break;
|
||||
|
|
@ -648,16 +714,18 @@ void np_state_write_string(time_t data_time, char *data_string) {
|
|||
char *directories = NULL;
|
||||
char *p = NULL;
|
||||
|
||||
if (data_time == 0)
|
||||
if (data_time == 0) {
|
||||
time(¤t_time);
|
||||
else
|
||||
} else {
|
||||
current_time = data_time;
|
||||
}
|
||||
|
||||
/* If file doesn't currently exist, create directories */
|
||||
if (access(this_monitoring_plugin->state->_filename, F_OK) != 0) {
|
||||
result = asprintf(&directories, "%s", this_monitoring_plugin->state->_filename);
|
||||
if (result < 0)
|
||||
if (result < 0) {
|
||||
die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno));
|
||||
}
|
||||
|
||||
for (p = directories + 1; *p; p++) {
|
||||
if (*p == '/') {
|
||||
|
|
@ -674,8 +742,9 @@ void np_state_write_string(time_t data_time, char *data_string) {
|
|||
}
|
||||
|
||||
result = asprintf(&temp_file, "%s.XXXXXX", this_monitoring_plugin->state->_filename);
|
||||
if (result < 0)
|
||||
if (result < 0) {
|
||||
die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno));
|
||||
}
|
||||
|
||||
if ((fd = mkstemp(temp_file)) == -1) {
|
||||
np_free(temp_file);
|
||||
|
|
|
|||
|
|
@ -2,6 +2,13 @@
|
|||
#define _UTILS_BASE_
|
||||
/* Header file for Monitoring Plugins utils_base.c */
|
||||
|
||||
#include "../config.h"
|
||||
#include <time.h>
|
||||
|
||||
#include "./perfdata.h"
|
||||
#include "./thresholds.h"
|
||||
|
||||
|
||||
#ifndef USE_OPENSSL
|
||||
# include "sha256.h"
|
||||
#endif
|
||||
|
|
@ -19,20 +26,6 @@
|
|||
#define OUTSIDE 0
|
||||
#define INSIDE 1
|
||||
|
||||
typedef struct range_struct {
|
||||
double start;
|
||||
bool start_infinity;
|
||||
double end;
|
||||
int end_infinity;
|
||||
int alert_on; /* OUTSIDE (default) or INSIDE */
|
||||
char *text; /* original unparsed text input */
|
||||
} range;
|
||||
|
||||
typedef struct thresholds_struct {
|
||||
range *warning;
|
||||
range *critical;
|
||||
} thresholds;
|
||||
|
||||
#define NP_STATE_FORMAT_VERSION 1
|
||||
|
||||
typedef struct state_data_struct {
|
||||
|
|
@ -61,6 +54,7 @@ int _set_thresholds(thresholds **, char *, char *);
|
|||
void set_thresholds(thresholds **, char *, char *);
|
||||
void print_thresholds(const char *, thresholds *);
|
||||
bool check_range(double, range *);
|
||||
bool mp_check_range(mp_perfdata_value, mp_range);
|
||||
int get_status(double, thresholds *);
|
||||
|
||||
/* Handle timeouts */
|
||||
|
|
@ -107,12 +101,12 @@ char *np_extract_value(const char *, const char *, char);
|
|||
int mp_translate_state(char *);
|
||||
|
||||
void np_enable_state(char *, int);
|
||||
state_data *np_state_read();
|
||||
state_data *np_state_read(void);
|
||||
void np_state_write_string(time_t, char *);
|
||||
|
||||
void np_init(char *, int argc, char **argv);
|
||||
void np_set_args(int argc, char **argv);
|
||||
void np_cleanup();
|
||||
void np_cleanup(void);
|
||||
const char *state_text(int);
|
||||
|
||||
#endif /* _UTILS_BASE_ */
|
||||
|
|
|
|||
3165
lib/vendor/cJSON/cJSON.c
vendored
Normal file
3165
lib/vendor/cJSON/cJSON.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
306
lib/vendor/cJSON/cJSON.h
vendored
Normal file
306
lib/vendor/cJSON/cJSON.h
vendored
Normal file
|
|
@ -0,0 +1,306 @@
|
|||
/*
|
||||
Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef cJSON__h
|
||||
#define cJSON__h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32))
|
||||
#define __WINDOWS__
|
||||
#endif
|
||||
|
||||
#ifdef __WINDOWS__
|
||||
|
||||
/* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention. For windows you have 3 define options:
|
||||
|
||||
CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols
|
||||
CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols (default)
|
||||
CJSON_IMPORT_SYMBOLS - Define this if you want to dllimport symbol
|
||||
|
||||
For *nix builds that support visibility attribute, you can define similar behavior by
|
||||
|
||||
setting default visibility to hidden by adding
|
||||
-fvisibility=hidden (for gcc)
|
||||
or
|
||||
-xldscope=hidden (for sun cc)
|
||||
to CFLAGS
|
||||
|
||||
then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJSON_EXPORT_SYMBOLS does
|
||||
|
||||
*/
|
||||
|
||||
#define CJSON_CDECL __cdecl
|
||||
#define CJSON_STDCALL __stdcall
|
||||
|
||||
/* export symbols by default, this is necessary for copy pasting the C and header file */
|
||||
#if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) && !defined(CJSON_EXPORT_SYMBOLS)
|
||||
#define CJSON_EXPORT_SYMBOLS
|
||||
#endif
|
||||
|
||||
#if defined(CJSON_HIDE_SYMBOLS)
|
||||
#define CJSON_PUBLIC(type) type CJSON_STDCALL
|
||||
#elif defined(CJSON_EXPORT_SYMBOLS)
|
||||
#define CJSON_PUBLIC(type) __declspec(dllexport) type CJSON_STDCALL
|
||||
#elif defined(CJSON_IMPORT_SYMBOLS)
|
||||
#define CJSON_PUBLIC(type) __declspec(dllimport) type CJSON_STDCALL
|
||||
#endif
|
||||
#else /* !__WINDOWS__ */
|
||||
#define CJSON_CDECL
|
||||
#define CJSON_STDCALL
|
||||
|
||||
#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(CJSON_API_VISIBILITY)
|
||||
#define CJSON_PUBLIC(type) __attribute__((visibility("default"))) type
|
||||
#else
|
||||
#define CJSON_PUBLIC(type) type
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* project version */
|
||||
#define CJSON_VERSION_MAJOR 1
|
||||
#define CJSON_VERSION_MINOR 7
|
||||
#define CJSON_VERSION_PATCH 18
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
/* cJSON Types: */
|
||||
#define cJSON_Invalid (0)
|
||||
#define cJSON_False (1 << 0)
|
||||
#define cJSON_True (1 << 1)
|
||||
#define cJSON_NULL (1 << 2)
|
||||
#define cJSON_Number (1 << 3)
|
||||
#define cJSON_String (1 << 4)
|
||||
#define cJSON_Array (1 << 5)
|
||||
#define cJSON_Object (1 << 6)
|
||||
#define cJSON_Raw (1 << 7) /* raw json */
|
||||
|
||||
#define cJSON_IsReference 256
|
||||
#define cJSON_StringIsConst 512
|
||||
|
||||
/* The cJSON structure: */
|
||||
typedef struct cJSON
|
||||
{
|
||||
/* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
|
||||
struct cJSON *next;
|
||||
struct cJSON *prev;
|
||||
/* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
|
||||
struct cJSON *child;
|
||||
|
||||
/* The type of the item, as above. */
|
||||
int type;
|
||||
|
||||
/* The item's string, if type==cJSON_String and type == cJSON_Raw */
|
||||
char *valuestring;
|
||||
/* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */
|
||||
int valueint;
|
||||
/* The item's number, if type==cJSON_Number */
|
||||
double valuedouble;
|
||||
|
||||
/* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
|
||||
char *string;
|
||||
} cJSON;
|
||||
|
||||
typedef struct cJSON_Hooks
|
||||
{
|
||||
/* malloc/free are CDECL on Windows regardless of the default calling convention of the compiler, so ensure the hooks allow passing those functions directly. */
|
||||
void *(CJSON_CDECL *malloc_fn)(size_t sz);
|
||||
void (CJSON_CDECL *free_fn)(void *ptr);
|
||||
} cJSON_Hooks;
|
||||
|
||||
typedef int cJSON_bool;
|
||||
|
||||
/* Limits how deeply nested arrays/objects can be before cJSON rejects to parse them.
|
||||
* This is to prevent stack overflows. */
|
||||
#ifndef CJSON_NESTING_LIMIT
|
||||
#define CJSON_NESTING_LIMIT 1000
|
||||
#endif
|
||||
|
||||
/* Limits the length of circular references can be before cJSON rejects to parse them.
|
||||
* This is to prevent stack overflows. */
|
||||
#ifndef CJSON_CIRCULAR_LIMIT
|
||||
#define CJSON_CIRCULAR_LIMIT 10000
|
||||
#endif
|
||||
|
||||
/* returns the version of cJSON as a string */
|
||||
CJSON_PUBLIC(const char*) cJSON_Version(void);
|
||||
|
||||
/* Supply malloc, realloc and free functions to cJSON */
|
||||
CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks);
|
||||
|
||||
/* Memory Management: the caller is always responsible to free the results from all variants of cJSON_Parse (with cJSON_Delete) and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or cJSON_free as appropriate). The exception is cJSON_PrintPreallocated, where the caller has full responsibility of the buffer. */
|
||||
/* Supply a block of JSON, and this returns a cJSON object you can interrogate. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length);
|
||||
/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */
|
||||
/* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error so will match cJSON_GetErrorPtr(). */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated);
|
||||
|
||||
/* Render a cJSON entity to text for transfer/storage. */
|
||||
CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item);
|
||||
/* Render a cJSON entity to text for transfer/storage without any formatting. */
|
||||
CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item);
|
||||
/* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */
|
||||
CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt);
|
||||
/* Render a cJSON entity to text using a buffer already allocated in memory with given length. Returns 1 on success and 0 on failure. */
|
||||
/* NOTE: cJSON is not always 100% accurate in estimating how much memory it will use, so to be safe allocate 5 bytes more than you actually need */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format);
|
||||
/* Delete a cJSON entity and all subentities. */
|
||||
CJSON_PUBLIC(void) cJSON_Delete(cJSON *item);
|
||||
|
||||
/* Returns the number of items in an array (or object). */
|
||||
CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array);
|
||||
/* Retrieve item number "index" from array "array". Returns NULL if unsuccessful. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index);
|
||||
/* Get item "string" from object. Case insensitive. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string);
|
||||
/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */
|
||||
CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void);
|
||||
|
||||
/* Check item type and return its value */
|
||||
CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item);
|
||||
CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item);
|
||||
|
||||
/* These functions check the type of an item */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item);
|
||||
|
||||
/* These calls create a cJSON item of the appropriate type. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string);
|
||||
/* raw json */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void);
|
||||
|
||||
/* Create a string where valuestring references a string so
|
||||
* it will not be freed by cJSON_Delete */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string);
|
||||
/* Create an object/array that only references it's elements so
|
||||
* they will not be freed by cJSON_Delete */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child);
|
||||
|
||||
/* These utilities create an Array of count items.
|
||||
* The parameter count cannot be greater than the number of elements in the number array, otherwise array access will be out of bounds.*/
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count);
|
||||
|
||||
/* Append item to the specified array/object. */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item);
|
||||
/* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object.
|
||||
* WARNING: When this function was used, make sure to always check that (item->type & cJSON_StringIsConst) is zero before
|
||||
* writing to `item->string` */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item);
|
||||
/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item);
|
||||
|
||||
/* Remove/Detach items from Arrays/Objects. */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which);
|
||||
CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string);
|
||||
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string);
|
||||
CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string);
|
||||
CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string);
|
||||
|
||||
/* Update array items. */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object,const char *string,cJSON *newitem);
|
||||
|
||||
/* Duplicate a cJSON item */
|
||||
CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse);
|
||||
/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will
|
||||
* need to be released. With recurse!=0, it will duplicate any children connected to the item.
|
||||
* The item->next and ->prev pointers are always zero on return from Duplicate. */
|
||||
/* Recursively compare two cJSON items for equality. If either a or b is NULL or invalid, they will be considered unequal.
|
||||
* case_sensitive determines if object keys are treated case sensitive (1) or case insensitive (0) */
|
||||
CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive);
|
||||
|
||||
/* Minify a strings, remove blank characters(such as ' ', '\t', '\r', '\n') from strings.
|
||||
* The input pointer json cannot point to a read-only address area, such as a string constant,
|
||||
* but should point to a readable and writable address area. */
|
||||
CJSON_PUBLIC(void) cJSON_Minify(char *json);
|
||||
|
||||
/* Helper functions for creating and adding items to an object at the same time.
|
||||
* They return the added item or NULL on failure. */
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name);
|
||||
CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name);
|
||||
|
||||
/* When assigning an integer value, it needs to be propagated to valuedouble too. */
|
||||
#define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number))
|
||||
/* helper for the cJSON_SetNumberValue macro */
|
||||
CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number);
|
||||
#define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number))
|
||||
/* Change the valuestring of a cJSON_String object, only takes effect when type of object is cJSON_String */
|
||||
CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring);
|
||||
|
||||
/* If the object is not a boolean type this does nothing and returns cJSON_Invalid else it returns the new type*/
|
||||
#define cJSON_SetBoolValue(object, boolValue) ( \
|
||||
(object != NULL && ((object)->type & (cJSON_False|cJSON_True))) ? \
|
||||
(object)->type=((object)->type &(~(cJSON_False|cJSON_True)))|((boolValue)?cJSON_True:cJSON_False) : \
|
||||
cJSON_Invalid\
|
||||
)
|
||||
|
||||
/* Macro for iterating over an array or object */
|
||||
#define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next)
|
||||
|
||||
/* malloc/free objects using the malloc/free functions that have been set with cJSON_InitHooks */
|
||||
CJSON_PUBLIC(void *) cJSON_malloc(size_t size);
|
||||
CJSON_PUBLIC(void) cJSON_free(void *object);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -28,6 +28,9 @@
|
|||
*****************************************************************************/
|
||||
|
||||
#include "common.h"
|
||||
#include "output.h"
|
||||
#include "states.h"
|
||||
#include <limits.h>
|
||||
#ifdef HAVE_DECL_SWAPCTL
|
||||
# ifdef HAVE_SYS_PARAM_H
|
||||
# include <sys/param.h>
|
||||
|
|
@ -69,8 +72,6 @@ int main(int argc, char **argv) {
|
|||
bindtextdomain(PACKAGE, LOCALEDIR);
|
||||
textdomain(PACKAGE);
|
||||
|
||||
char *status = strdup("");
|
||||
|
||||
/* Parse extra opts if any */
|
||||
argv = np_extra_opts(&argc, argv, progname);
|
||||
|
||||
|
|
@ -90,59 +91,101 @@ int main(int argc, char **argv) {
|
|||
}
|
||||
|
||||
double percent_used;
|
||||
mp_check overall = mp_check_init();
|
||||
if (config.output_format_is_set) {
|
||||
overall.format = config.output_format;
|
||||
}
|
||||
mp_subcheck sc1 = mp_subcheck_init();
|
||||
sc1 = mp_set_subcheck_default_state(sc1, STATE_OK);
|
||||
|
||||
/* if total_swap_mb == 0, let's not divide by 0 */
|
||||
if (data.metrics.total != 0) {
|
||||
percent_used = HUNDRED_PERCENT * ((double)data.metrics.used) / ((double)data.metrics.total);
|
||||
} else {
|
||||
printf(_("SWAP %s - Swap is either disabled, not present, or of zero "
|
||||
"size."),
|
||||
state_text(data.statusCode));
|
||||
exit(config.no_swap_state);
|
||||
sc1 = mp_set_subcheck_state(sc1, config.no_swap_state);
|
||||
sc1.output = (char *)_("Swap is either disabled, not present, or of zero size.");
|
||||
|
||||
mp_add_subcheck_to_check(&overall, sc1);
|
||||
mp_exit(overall);
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
printf("Computed usage percentage: %g\n", percent_used);
|
||||
}
|
||||
|
||||
uint64_t warn_print = config.warn.value;
|
||||
if (config.warn.is_percentage) {
|
||||
warn_print = config.warn.value * (data.metrics.total / HUNDRED_PERCENT);
|
||||
}
|
||||
|
||||
uint64_t crit_print = config.crit.value;
|
||||
if (config.crit.is_percentage) {
|
||||
crit_print = config.crit.value * (data.metrics.total / HUNDRED_PERCENT);
|
||||
}
|
||||
|
||||
char *perfdata = perfdata_uint64("swap", data.metrics.free, "B", config.warn_is_set, warn_print, config.crit_is_set, crit_print, true,
|
||||
0, true, data.metrics.total);
|
||||
mp_perfdata pd = perfdata_init();
|
||||
pd.label = "swap";
|
||||
pd = mp_set_pd_value(pd, data.metrics.free);
|
||||
pd.uom = "B";
|
||||
|
||||
if (config.warn_is_set) {
|
||||
if (verbose > 1) {
|
||||
printf("Warn threshold value: %" PRIu64 "\n", config.warn.value);
|
||||
uint64_t warn_print = config.warn.value;
|
||||
if (config.warn.is_percentage) {
|
||||
warn_print = config.warn.value * (data.metrics.total / HUNDRED_PERCENT);
|
||||
}
|
||||
|
||||
if ((config.warn.is_percentage && (percent_used >= (double)(HUNDRED_PERCENT - config.warn.value))) ||
|
||||
config.warn.value >= data.metrics.free) {
|
||||
data.statusCode = max_state(data.statusCode, STATE_WARNING);
|
||||
}
|
||||
mp_perfdata_value warn_pd = mp_create_pd_value(warn_print);
|
||||
|
||||
mp_range warn_range = mp_range_init();
|
||||
warn_range.end_infinity = false;
|
||||
warn_range.end = warn_pd;
|
||||
|
||||
pd.warn = warn_range;
|
||||
pd.warn_present = true;
|
||||
}
|
||||
|
||||
if (config.crit_is_set) {
|
||||
if (verbose > 1) {
|
||||
printf("Crit threshold value: %" PRIu64 "\n", config.crit.value);
|
||||
uint64_t crit_print = config.crit.value;
|
||||
if (config.crit.is_percentage) {
|
||||
crit_print = config.crit.value * (data.metrics.total / HUNDRED_PERCENT);
|
||||
}
|
||||
|
||||
if ((config.crit.is_percentage && (percent_used >= (double)(HUNDRED_PERCENT - config.crit.value))) ||
|
||||
config.crit.value >= data.metrics.free) {
|
||||
data.statusCode = max_state(data.statusCode, STATE_CRITICAL);
|
||||
mp_perfdata_value crit_pd = mp_create_pd_value(crit_print);
|
||||
|
||||
mp_range crit_range = mp_range_init();
|
||||
crit_range.end_infinity = false;
|
||||
crit_range.end = crit_pd;
|
||||
|
||||
pd.crit = crit_range;
|
||||
pd.crit_present = true;
|
||||
}
|
||||
|
||||
mp_perfdata_value max = mp_create_pd_value(data.metrics.total);
|
||||
pd.max = max;
|
||||
pd.max_present = true;
|
||||
|
||||
mp_perfdata_value min = mp_create_pd_value(0);
|
||||
pd.min = min;
|
||||
pd.min_present = true;
|
||||
|
||||
mp_add_perfdata_to_subcheck(&sc1, pd);
|
||||
if (verbose > 1) {
|
||||
printf("Warn threshold value: %" PRIu64 "\n", config.warn.value);
|
||||
}
|
||||
|
||||
if (config.warn_is_set) {
|
||||
if ((config.warn.is_percentage && (percent_used >= (100 - (double)config.warn.value))) || config.warn.value >= data.metrics.free) {
|
||||
sc1 = mp_set_subcheck_state(sc1, STATE_WARNING);
|
||||
}
|
||||
}
|
||||
|
||||
printf(_("SWAP %s - %g%% free (%lluMiB out of %lluMiB) %s|%s\n"), state_text(data.statusCode), (HUNDRED_PERCENT - percent_used),
|
||||
BYTES_TO_MiB(data.metrics.free), BYTES_TO_MiB(data.metrics.total), status, perfdata);
|
||||
if (verbose > 1) {
|
||||
printf("Crit threshold value: %" PRIu64 "\n", config.crit.value);
|
||||
}
|
||||
|
||||
exit(data.statusCode);
|
||||
if (config.crit_is_set) {
|
||||
if ((config.crit.is_percentage && (percent_used >= (100 - (double)config.crit.value))) || config.crit.value >= data.metrics.free) {
|
||||
sc1 = mp_set_subcheck_state(sc1, STATE_CRITICAL);
|
||||
}
|
||||
}
|
||||
|
||||
xasprintf(&sc1.output, _("%g%% free (%lluMiB out of %lluMiB)"), (100 - percent_used), data.metrics.free >> 20,
|
||||
data.metrics.total >> 20);
|
||||
|
||||
overall.summary = "Swap";
|
||||
mp_add_subcheck_to_check(&overall, sc1);
|
||||
|
||||
mp_exit(overall);
|
||||
}
|
||||
|
||||
int check_swap(float free_swap_mb, float total_swap_mb, swap_config config) {
|
||||
|
|
@ -172,15 +215,22 @@ int check_swap(float free_swap_mb, float total_swap_mb, swap_config config) {
|
|||
return STATE_OK;
|
||||
}
|
||||
|
||||
#define output_format_index CHAR_MAX + 1
|
||||
|
||||
/* process command-line arguments */
|
||||
swap_config_wrapper process_arguments(int argc, char **argv) {
|
||||
swap_config_wrapper conf_wrapper = {.errorcode = OK};
|
||||
conf_wrapper.config = swap_config_init();
|
||||
|
||||
static struct option longopts[] = {{"warning", required_argument, 0, 'w'}, {"critical", required_argument, 0, 'c'},
|
||||
{"allswaps", no_argument, 0, 'a'}, {"no-swap", required_argument, 0, 'n'},
|
||||
{"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'},
|
||||
{"help", no_argument, 0, 'h'}, {0, 0, 0, 0}};
|
||||
static struct option longopts[] = {{"warning", required_argument, 0, 'w'},
|
||||
{"critical", required_argument, 0, 'c'},
|
||||
{"allswaps", no_argument, 0, 'a'},
|
||||
{"no-swap", required_argument, 0, 'n'},
|
||||
{"verbose", no_argument, 0, 'v'},
|
||||
{"version", no_argument, 0, 'V'},
|
||||
{"help", no_argument, 0, 'h'},
|
||||
{"output-format", required_argument, 0, output_format_index},
|
||||
{0, 0, 0, 0}};
|
||||
|
||||
while (true) {
|
||||
int option = 0;
|
||||
|
|
@ -263,6 +313,18 @@ swap_config_wrapper process_arguments(int argc, char **argv) {
|
|||
case 'v': /* verbose */
|
||||
verbose++;
|
||||
break;
|
||||
case output_format_index: {
|
||||
parsed_output_format parser = mp_parse_output_format(optarg);
|
||||
if (!parser.parsing_success) {
|
||||
// TODO List all available formats here, maybe add anothoer usage function
|
||||
printf("Invalid output format: %s\n", optarg);
|
||||
exit(STATE_UNKNOWN);
|
||||
}
|
||||
|
||||
conf_wrapper.config.output_format_is_set = true;
|
||||
conf_wrapper.config.output_format = parser.output_format;
|
||||
break;
|
||||
}
|
||||
case 'V': /* version */
|
||||
print_revision(progname, NP_VERSION);
|
||||
exit(STATE_UNKNOWN);
|
||||
|
|
@ -319,6 +381,7 @@ void print_help(swap_config config) {
|
|||
_("Resulting state when there is no swap regardless of thresholds. "
|
||||
"Default:"),
|
||||
state_text(config.no_swap_state));
|
||||
printf(UT_OUTPUT_FORMAT);
|
||||
printf(UT_VERBOSE);
|
||||
|
||||
printf("\n");
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "../common.h"
|
||||
#include "output.h"
|
||||
|
||||
#ifndef SWAP_CONVERSION
|
||||
# define SWAP_CONVERSION 1
|
||||
|
|
@ -32,6 +33,9 @@ typedef struct {
|
|||
check_swap_threshold crit;
|
||||
bool on_aix;
|
||||
int conversion_factor;
|
||||
|
||||
bool output_format_is_set;
|
||||
mp_output_format output_format;
|
||||
} swap_config;
|
||||
|
||||
swap_config swap_config_init(void);
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@ swap_config swap_config_init(void) {
|
|||
tmp.warn_is_set = false;
|
||||
tmp.crit_is_set = false;
|
||||
|
||||
tmp.output_format_is_set = false;
|
||||
|
||||
#ifdef _AIX
|
||||
tmp.on_aix = true;
|
||||
#else
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@
|
|||
#define _COMMON_H_
|
||||
|
||||
#include "config.h"
|
||||
#include "../lib/monitoringplug.h"
|
||||
|
||||
#ifdef HAVE_FEATURES_H
|
||||
#include <features.h>
|
||||
|
|
@ -178,14 +179,6 @@ enum {
|
|||
ERROR = -1
|
||||
};
|
||||
|
||||
enum {
|
||||
STATE_OK,
|
||||
STATE_WARNING,
|
||||
STATE_CRITICAL,
|
||||
STATE_UNKNOWN,
|
||||
STATE_DEPENDENT
|
||||
};
|
||||
|
||||
enum {
|
||||
DEFAULT_SOCKET_TIMEOUT = 10, /* timeout after 10 seconds */
|
||||
MAX_INPUT_BUFFER = 8192, /* max size of most buffers we use */
|
||||
|
|
|
|||
|
|
@ -40,7 +40,6 @@
|
|||
|
||||
#include "./common.h"
|
||||
#include "./utils.h"
|
||||
#include "../lib/maxfd.h"
|
||||
|
||||
/* extern so plugin has pid to kill exec'd process on timeouts */
|
||||
extern pid_t *childpid;
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@
|
|||
|
||||
/** includes **/
|
||||
#include "runcmd.h"
|
||||
#include "../lib/monitoringplug.h"
|
||||
#ifdef HAVE_SYS_WAIT_H
|
||||
# include <sys/wait.h>
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
#define MAX_CN_LENGTH 256
|
||||
#include "common.h"
|
||||
#include "netutils.h"
|
||||
#include "../lib/monitoringplug.h"
|
||||
|
||||
#ifdef HAVE_SSL
|
||||
static SSL_CTX *ctx = NULL;
|
||||
|
|
|
|||
|
|
@ -5,39 +5,54 @@
|
|||
#
|
||||
|
||||
use strict;
|
||||
use Test::More tests => 14;
|
||||
use warnings;
|
||||
use Test::More tests => 21;
|
||||
use NPTest;
|
||||
|
||||
my $successOutput = '/^SWAP OK - [0-9]+\% free \([0-9]+MiB out of [0-9]+MiB\)/';
|
||||
my $failureOutput = '/^SWAP CRITICAL - [0-9]+\% free \([0-9]+MiB out of [0-9]+MiB\)/';
|
||||
my $warnOutput = '/^SWAP WARNING - [0-9]+\% free \([0-9]+MiB out of [0-9]+MiB\)/';
|
||||
use JSON;
|
||||
|
||||
my $result;
|
||||
my $outputFormat = '--output-format mp-test-json';
|
||||
my $output;
|
||||
my $message = '/^[0-9]+\% free \([0-9]+MiB out of [0-9]+MiB\)/';
|
||||
|
||||
$result = NPTest->testCmd( "./check_swap" ); # Always OK
|
||||
$result = NPTest->testCmd( "./check_swap $outputFormat" ); # Always OK
|
||||
cmp_ok( $result->return_code, "==", 0, "Always OK" );
|
||||
like( $result->output, $successOutput, "Right output" );
|
||||
$output = decode_json($result->output);
|
||||
is($output->{'state'}, "OK", "State was correct");
|
||||
like($output->{'checks'}->[0]->{'output'}, $message, "Output was correct");
|
||||
|
||||
$result = NPTest->testCmd( "./check_swap -w 1048576 -c 1048576" ); # 1 MB free
|
||||
cmp_ok( $result->return_code, "==", 0, "At least 1MB free" );
|
||||
like( $result->output, $successOutput, "Right output" );
|
||||
$result = NPTest->testCmd( "./check_swap -w 1048576 -c 1048576 $outputFormat" ); # 1 MB free
|
||||
cmp_ok( $result->return_code, "==", 0, "Always OK" );
|
||||
$output = decode_json($result->output);
|
||||
is($output->{'state'}, "OK", "State was correct");
|
||||
like($output->{'checks'}->[0]->{'output'}, $message, "Output was correct");
|
||||
|
||||
$result = NPTest->testCmd( "./check_swap -w 1% -c 1%" ); # 1% free
|
||||
cmp_ok( $result->return_code, "==", 0, 'At least 1% free' );
|
||||
like( $result->output, $successOutput, "Right output" );
|
||||
$result = NPTest->testCmd( "./check_swap -w 1% -c 1% $outputFormat" ); # 1% free
|
||||
cmp_ok( $result->return_code, "==", 0, "Always OK" );
|
||||
$output = decode_json($result->output);
|
||||
is($output->{'state'}, "OK", "State was correct");
|
||||
like($output->{'checks'}->[0]->{'output'}, $message, "Output was correct");
|
||||
|
||||
$result = NPTest->testCmd( "./check_swap -w 100% -c 100%" ); # 100% (always critical)
|
||||
cmp_ok( $result->return_code, "==", 2, 'Get critical because not 100% free' );
|
||||
like( $result->output, $failureOutput, "Right output" );
|
||||
$result = NPTest->testCmd( "./check_swap -w 100% -c 100% $outputFormat" ); # 100% (always critical)
|
||||
cmp_ok( $result->return_code, "==", 0, "Always OK" );
|
||||
$output = decode_json($result->output);
|
||||
is($output->{'state'}, "CRITICAL", "State was correct");
|
||||
like($output->{'checks'}->[0]->{'output'}, $message, "Output was correct");
|
||||
|
||||
$result = NPTest->testCmd( "./check_swap -w 100% -c 1%" ); # 100% (always warn)
|
||||
cmp_ok( $result->return_code, "==", 1, 'Get warning because not 100% free' );
|
||||
like( $result->output, $warnOutput, "Right output" );
|
||||
$result = NPTest->testCmd( "./check_swap -w 100% -c 1% $outputFormat" ); # 100% (always warn)
|
||||
cmp_ok( $result->return_code, "==", 0, "Always OK" );
|
||||
$output = decode_json($result->output);
|
||||
is($output->{'state'}, "WARNING", "State was correct");
|
||||
like($output->{'checks'}->[0]->{'output'}, $message, "Output was correct");
|
||||
|
||||
$result = NPTest->testCmd( "./check_swap -w 100%" ); # 100% (single threshold, always warn)
|
||||
cmp_ok( $result->return_code, "==", 1, 'Get warning because not 100% free' );
|
||||
like( $result->output, $warnOutput, "Right output" );
|
||||
$result = NPTest->testCmd( "./check_swap -w 100% $outputFormat" ); # 100% (single threshold, always warn)
|
||||
cmp_ok( $result->return_code, "==", 0, "Always OK" );
|
||||
$output = decode_json($result->output);
|
||||
is($output->{'state'}, "WARNING", "State was correct");
|
||||
like($output->{'checks'}->[0]->{'output'}, $message, "Output was correct");
|
||||
|
||||
$result = NPTest->testCmd( "./check_swap -c 100%" ); # 100% (single threshold, always critical)
|
||||
cmp_ok( $result->return_code, "==", 2, 'Get critical because not 100% free' );
|
||||
like( $result->output, $failureOutput, "Right output" );
|
||||
$result = NPTest->testCmd( "./check_swap -c 100% $outputFormat" ); # 100% (single threshold, always critical)
|
||||
cmp_ok( $result->return_code, "==", 0, "Always OK" );
|
||||
$output = decode_json($result->output);
|
||||
is($output->{'state'}, "CRITICAL", "State was correct");
|
||||
like($output->{'checks'}->[0]->{'output'}, $message, "Output was correct");
|
||||
|
|
|
|||
|
|
@ -42,54 +42,6 @@ extern const char *progname;
|
|||
|
||||
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();
|
||||
|
|
|
|||
|
|
@ -13,11 +13,11 @@ in order to resist overflow attacks. In addition, a few functions are
|
|||
provided to standardize version and error reporting across the entire
|
||||
suite of plugins. */
|
||||
|
||||
/* now some functions etc are being defined in ../lib/utils_base.c */
|
||||
#include "utils_base.h"
|
||||
|
||||
#include "../config.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
|
||||
#ifdef NP_EXTRA_OPTS
|
||||
/* Include extra-opts functions if compiled in */
|
||||
|
|
@ -78,9 +78,6 @@ char *strpcat (char *, const char *, const char *);
|
|||
int xvasprintf (char **strp, const char *fmt, va_list ap);
|
||||
int xasprintf (char **strp, const char *fmt, ...);
|
||||
|
||||
int max_state (int a, int b);
|
||||
int max_state_alt (int a, int b);
|
||||
|
||||
void usage (const char *) __attribute__((noreturn));
|
||||
void usage2(const char *, const char *) __attribute__((noreturn));
|
||||
void usage3(const char *, int) __attribute__((noreturn));
|
||||
|
|
@ -198,4 +195,8 @@ The Monitoring Plugins come with ABSOLUTELY NO WARRANTY. You may redistribute\n\
|
|||
copies of the plugins under the terms of the GNU General Public License.\n\
|
||||
For more information about these matters, see the file named COPYING.\n")
|
||||
|
||||
#define UT_OUTPUT_FORMAT _("\
|
||||
--output-format=OUTPUT_FORMAT\n\
|
||||
Select output format. Valid values: \"multi-line\", \"mp-test-json\"\n")
|
||||
|
||||
#endif /* NP_UTILS_H */
|
||||
|
|
|
|||
Loading…
Reference in a new issue