diff --git a/.gitignore b/.gitignore
index 7f79265f..8b14f429 100644
--- a/.gitignore
+++ b/.gitignore
@@ -114,7 +114,6 @@ NP-VERSION-FILE
/lib/tests/Makefile.in
/lib/tests/test_base64
/lib/tests/test_cmd
-/lib/tests/test_disk
/lib/tests/test_tcp
/lib/tests/test_utils
/lib/tests/utils_base.Po
@@ -153,6 +152,8 @@ NP-VERSION-FILE
/plugins/check_dbi
/plugins/check_dig
/plugins/check_disk
+plugins/check_disk.d/.deps/
+plugins/check_disk.d/.dirstamp
/plugins/check_dns
/plugins/check_dummy
/plugins/check_fping
@@ -221,7 +222,7 @@ NP-VERSION-FILE
/plugins/tests/Makefile
/plugins/tests/Makefile.in
/plugins/tests/test_utils
-/plugins/tests/test_disk
+/plugins/tests/test_check_disk
/plugins/tests/test_check_swap
/plugins/tests/.deps
/plugins/tests/.dirstamp
diff --git a/configure.ac b/configure.ac
index 204fc6e3..fdc9b699 100644
--- a/configure.ac
+++ b/configure.ac
@@ -181,10 +181,10 @@ fi
# Finally, define tests if we use libtap
if test "$enable_libtap" = "yes" ; then
- EXTRA_TEST="test_utils test_disk test_tcp test_cmd test_base64"
+ EXTRA_TEST="test_utils test_tcp test_cmd test_base64"
AC_SUBST(EXTRA_TEST)
- EXTRA_PLUGIN_TESTS="tests/test_check_swap"
+ EXTRA_PLUGIN_TESTS="tests/test_check_swap tests/test_check_disk"
AC_SUBST(EXTRA_PLUGIN_TESTS)
fi
diff --git a/lib/Makefile.am b/lib/Makefile.am
index e41201c4..a9f3ff40 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -7,10 +7,9 @@ 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 output.c perfdata.c output.c thresholds.c vendor/cJSON/cJSON.c
+libmonitoringplug_a_SOURCES = utils_base.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 \
diff --git a/lib/output.c b/lib/output.c
index 61fbf832..c408a2f5 100644
--- a/lib/output.c
+++ b/lib/output.c
@@ -13,6 +13,7 @@
// == Global variables
static mp_output_format output_format = MP_FORMAT_DEFAULT;
+static mp_output_detail_level level_of_detail = MP_DETAIL_ALL;
// == Prototypes ==
static char *fmt_subcheck_output(mp_output_format output_format, mp_subcheck check, unsigned int indentation);
@@ -202,7 +203,12 @@ mp_state_enum mp_compute_subcheck_state(const mp_subcheck check) {
}
mp_subcheck_list *scl = check.subchecks;
- mp_state_enum result = check.default_state;
+
+ if (scl == NULL) {
+ return check.default_state;
+ }
+
+ mp_state_enum result = STATE_OK;
while (scl != NULL) {
result = max_state_alt(result, mp_compute_subcheck_state(scl->subcheck));
@@ -247,7 +253,9 @@ char *mp_fmt_output(mp_check check) {
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));
+ if (level_of_detail == MP_DETAIL_ALL || mp_compute_subcheck_state(subchecks->subcheck) != STATE_OK) {
+ asprintf(&result, "%s\n%s", result, fmt_subcheck_output(MP_FORMAT_MULTI_LINE, subchecks->subcheck, 1));
+ }
subchecks = subchecks->next;
}
@@ -539,3 +547,7 @@ parsed_output_format mp_parse_output_format(char *format_string) {
void mp_set_format(mp_output_format format) { output_format = format; }
mp_output_format mp_get_format(void) { return output_format; }
+
+void mp_set_level_of_detail(mp_output_detail_level level) { level_of_detail = level; }
+
+mp_output_detail_level mp_get_level_of_detail(void) { return level_of_detail; }
diff --git a/lib/output.h b/lib/output.h
index 2bdfa074..3bd91f90 100644
--- a/lib/output.h
+++ b/lib/output.h
@@ -38,8 +38,18 @@ typedef enum output_format {
/*
* Format related functions
*/
- void mp_set_format(mp_output_format format);
- mp_output_format mp_get_format(void);
+void mp_set_format(mp_output_format format);
+mp_output_format mp_get_format(void);
+
+// Output detail level
+
+typedef enum output_detail_level {
+ MP_DETAIL_ALL,
+ MP_DETAIL_NON_OK_ONLY,
+} mp_output_detail_level;
+
+void mp_set_level_of_detail(mp_output_detail_level level);
+mp_output_detail_level mp_get_level_of_detail(void);
/*
* The main state object of a plugin. Exists only ONCE per plugin.
@@ -48,7 +58,7 @@ typedef enum output_format {
* in the first layer of subchecks
*/
typedef struct {
- char *summary; // Overall summary, if not set a summary will be automatically generated
+ char *summary; // Overall summary, if not set a summary will be automatically generated
mp_subcheck_list *subchecks;
} mp_check;
diff --git a/lib/perfdata.c b/lib/perfdata.c
index 661756c5..f425ffcf 100644
--- a/lib/perfdata.c
+++ b/lib/perfdata.c
@@ -33,7 +33,7 @@ char *pd_value_to_string(const mp_perfdata_value pd) {
char *pd_to_string(mp_perfdata pd) {
assert(pd.label != NULL);
char *result = NULL;
- asprintf(&result, "%s=", pd.label);
+ asprintf(&result, "'%s'=", pd.label);
asprintf(&result, "%s%s", result, pd_value_to_string(pd.value));
@@ -514,3 +514,84 @@ perfdata_value_parser_wrapper parse_pd_value(const char *input) {
}
return result;
}
+
+mp_perfdata mp_set_pd_max_value(mp_perfdata perfdata, mp_perfdata_value value) {
+ perfdata.max = value;
+ perfdata.max_present = true;
+ return perfdata;
+}
+
+mp_perfdata mp_set_pd_min_value(mp_perfdata perfdata, mp_perfdata_value value) {
+ perfdata.min = value;
+ perfdata.min_present = true;
+ return perfdata;
+}
+
+double mp_get_pd_value(mp_perfdata_value value) {
+ assert(value.type != PD_TYPE_NONE);
+ switch (value.type) {
+ case PD_TYPE_DOUBLE:
+ return value.pd_double;
+ case PD_TYPE_INT:
+ return (double)value.pd_int;
+ case PD_TYPE_UINT:
+ return (double)value.pd_uint;
+ default:
+ return 0; // just to make the compiler happy
+ }
+}
+
+mp_perfdata_value mp_pd_value_multiply(mp_perfdata_value left, mp_perfdata_value right) {
+ if (left.type == right.type) {
+ switch (left.type) {
+ case PD_TYPE_DOUBLE:
+ left.pd_double *= right.pd_double;
+ return left;
+ case PD_TYPE_INT:
+ left.pd_int *= right.pd_int;
+ return left;
+ case PD_TYPE_UINT:
+ left.pd_uint *= right.pd_uint;
+ return left;
+ default:
+ // what to here?
+ return left;
+ }
+ }
+
+ // Different types, oh boy, just do the lazy thing for now and switch to double
+ switch (left.type) {
+ case PD_TYPE_INT:
+ left.pd_double = (double)left.pd_int;
+ left.type = PD_TYPE_DOUBLE;
+ break;
+ case PD_TYPE_UINT:
+ left.pd_double = (double)left.pd_uint;
+ left.type = PD_TYPE_DOUBLE;
+ break;
+ }
+
+ switch (right.type) {
+ case PD_TYPE_INT:
+ right.pd_double = (double)right.pd_int;
+ right.type = PD_TYPE_DOUBLE;
+ break;
+ case PD_TYPE_UINT:
+ right.pd_double = (double)right.pd_uint;
+ right.type = PD_TYPE_DOUBLE;
+ break;
+ }
+
+ left.pd_double *= right.pd_double;
+ return left;
+}
+
+mp_range mp_range_multiply(mp_range range, mp_perfdata_value factor) {
+ if (!range.end_infinity) {
+ range.end = mp_pd_value_multiply(range.end, factor);
+ }
+ if (!range.start_infinity) {
+ range.start = mp_pd_value_multiply(range.start, factor);
+ }
+ return range;
+}
diff --git a/lib/perfdata.h b/lib/perfdata.h
index 74583ee5..cb552678 100644
--- a/lib/perfdata.h
+++ b/lib/perfdata.h
@@ -171,6 +171,11 @@ 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);
+mp_perfdata mp_set_pd_max_value(mp_perfdata perfdata, mp_perfdata_value value);
+mp_perfdata mp_set_pd_min_value(mp_perfdata perfdata, mp_perfdata_value value);
+
+double mp_get_pd_value(mp_perfdata_value value);
+
/*
* Free the memory used by a pd_list
*/
@@ -178,6 +183,13 @@ void pd_list_free(pd_list[1]);
int cmp_perfdata_value(mp_perfdata_value, mp_perfdata_value);
+// ================
+// Helper functions
+// ================
+
+mp_perfdata_value mp_pd_value_multiply(mp_perfdata_value left, mp_perfdata_value right);
+mp_range mp_range_multiply(mp_range range, mp_perfdata_value factor);
+
// =================
// String formatters
// =================
diff --git a/lib/tests/Makefile.am b/lib/tests/Makefile.am
index 9be94f6d..7798a72e 100644
--- a/lib/tests/Makefile.am
+++ b/lib/tests/Makefile.am
@@ -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 test_generic_output
+EXTRA_PROGRAMS = test_utils 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 test_generic_output.t
+np_test_scripts = test_base64.t test_cmd.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 test_generic_output.c
+SOURCES = test_utils.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)
diff --git a/lib/tests/test_disk.t b/lib/tests/test_disk.t
deleted file mode 100755
index da84dfdf..00000000
--- a/lib/tests/test_disk.t
+++ /dev/null
@@ -1,6 +0,0 @@
-#!/usr/bin/perl
-use Test::More;
-if (! -e "./test_disk") {
- plan skip_all => "./test_disk not compiled - please enable libtap library to test";
-}
-exec "./test_disk";
diff --git a/lib/thresholds.c b/lib/thresholds.c
index ddefae37..de2b9315 100644
--- a/lib/thresholds.c
+++ b/lib/thresholds.c
@@ -51,9 +51,21 @@ mp_state_enum mp_get_pd_status(mp_perfdata perfdata) {
}
if (perfdata.warn_present) {
if (mp_check_range(perfdata.value, perfdata.warn)) {
- return STATE_CRITICAL;
+ return STATE_WARNING;
}
}
return STATE_OK;
}
+
+mp_thresholds mp_thresholds_set_warn(mp_thresholds thlds, mp_range warn) {
+ thlds.warning = warn;
+ thlds.warning_is_set = true;
+ return thlds;
+}
+
+mp_thresholds mp_thresholds_set_crit(mp_thresholds thlds, mp_range crit) {
+ thlds.critical = crit;
+ thlds.critical_is_set = true;
+ return thlds;
+}
diff --git a/lib/thresholds.h b/lib/thresholds.h
index 4e7defee..5f9f9247 100644
--- a/lib/thresholds.h
+++ b/lib/thresholds.h
@@ -24,5 +24,8 @@ mp_perfdata mp_pd_set_thresholds(mp_perfdata /* pd */, mp_thresholds /* th */);
mp_state_enum mp_get_pd_status(mp_perfdata /* pd */);
+mp_thresholds mp_thresholds_set_warn(mp_thresholds thlds, mp_range warn);
+mp_thresholds mp_thresholds_set_crit(mp_thresholds thlds, mp_range crit);
+
char *fmt_threshold_warning(thresholds th);
char *fmt_threshold_critical(thresholds th);
diff --git a/lib/utils_base.c b/lib/utils_base.c
index ff9540c7..c49a473f 100644
--- a/lib/utils_base.c
+++ b/lib/utils_base.c
@@ -225,27 +225,15 @@ bool mp_check_range(const mp_perfdata_value value, const mp_range my_range) {
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;
- }
+ is_inside = ((cmp_perfdata_value(my_range.start, value) < 1) && (cmp_perfdata_value(value, my_range.end) <= 0));
} 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;
- }
+ is_inside = (cmp_perfdata_value(my_range.start, value) < 0);
} 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;
- }
+ is_inside = (cmp_perfdata_value(value, my_range.end) == -1);
} else {
// range from -inf to inf, so always inside
is_inside = true;
diff --git a/lib/utils_disk.c b/lib/utils_disk.c
deleted file mode 100644
index 2b761f5e..00000000
--- a/lib/utils_disk.c
+++ /dev/null
@@ -1,255 +0,0 @@
-/*****************************************************************************
- *
- * Library for check_disk
- *
- * License: GPL
- * Copyright (c) 1999-2024 Monitoring Plugins Development Team
- *
- * Description:
- *
- * This file contains utilities for check_disk. These are tested by libtap
- *
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- *
- *****************************************************************************/
-
-#include "common.h"
-#include "utils_disk.h"
-#include "gl/fsusage.h"
-#include
-
-void np_add_name(struct name_list **list, const char *name) {
- struct name_list *new_entry;
- new_entry = (struct name_list *)malloc(sizeof *new_entry);
- new_entry->name = (char *)name;
- new_entry->next = *list;
- *list = new_entry;
-}
-
-/* @brief Initialises a new regex at the begin of list via regcomp(3)
- *
- * @details if the regex fails to compile the error code of regcomp(3) is returned
- * and list is not modified, otherwise list is modified to point to the new
- * element
- * @param list Pointer to a linked list of regex_list elements
- * @param regex the string containing the regex which should be inserted into the list
- * @param clags the cflags parameter for regcomp(3)
- */
-int np_add_regex(struct regex_list **list, const char *regex, int cflags) {
- struct regex_list *new_entry = (struct regex_list *)malloc(sizeof *new_entry);
-
- if (new_entry == NULL) {
- die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno));
- }
-
- int regcomp_result = regcomp(&new_entry->regex, regex, cflags);
-
- if (!regcomp_result) {
- // regcomp succeeded
- new_entry->next = *list;
- *list = new_entry;
-
- return 0;
- } else {
- // regcomp failed
- free(new_entry);
-
- return regcomp_result;
- }
-}
-
-/* Initialises a new parameter at the end of list */
-struct parameter_list *np_add_parameter(struct parameter_list **list, const char *name) {
- struct parameter_list *current = *list;
- struct parameter_list *new_path;
- new_path = (struct parameter_list *)malloc(sizeof *new_path);
- new_path->name = (char *)malloc(strlen(name) + 1);
- new_path->best_match = NULL;
- new_path->name_next = NULL;
- new_path->name_prev = NULL;
- new_path->freespace_bytes = NULL;
- new_path->freespace_units = NULL;
- new_path->freespace_percent = NULL;
- new_path->usedspace_bytes = NULL;
- new_path->usedspace_units = NULL;
- new_path->usedspace_percent = NULL;
- new_path->usedinodes_percent = NULL;
- new_path->freeinodes_percent = NULL;
- new_path->group = NULL;
- new_path->dfree_pct = -1;
- new_path->dused_pct = -1;
- new_path->total = 0;
- new_path->available = 0;
- new_path->available_to_root = 0;
- new_path->used = 0;
- new_path->dused_units = 0;
- new_path->dfree_units = 0;
- new_path->dtotal_units = 0;
- new_path->inodes_total = 0;
- new_path->inodes_free = 0;
- new_path->inodes_free_to_root = 0;
- new_path->inodes_used = 0;
- new_path->dused_inodes_percent = 0;
- new_path->dfree_inodes_percent = 0;
-
- strcpy(new_path->name, name);
-
- if (current == NULL) {
- *list = new_path;
- new_path->name_prev = NULL;
- } else {
- while (current->name_next) {
- current = current->name_next;
- }
- current->name_next = new_path;
- new_path->name_prev = current;
- }
- return new_path;
-}
-
-/* Delete a given parameter from list and return pointer to next element*/
-struct parameter_list *np_del_parameter(struct parameter_list *item, struct parameter_list *prev) {
- if (item == NULL) {
- return NULL;
- }
- struct parameter_list *next;
-
- if (item->name_next)
- next = item->name_next;
- else
- next = NULL;
-
- if (next)
- next->name_prev = prev;
-
- if (prev)
- prev->name_next = next;
-
- if (item->name) {
- free(item->name);
- }
- free(item);
-
- return next;
-}
-
-/* returns a pointer to the struct found in the list */
-struct parameter_list *np_find_parameter(struct parameter_list *list, const char *name) {
- struct parameter_list *temp_list;
- for (temp_list = list; temp_list; temp_list = temp_list->name_next) {
- if (!strcmp(temp_list->name, name))
- return temp_list;
- }
-
- return NULL;
-}
-
-void np_set_best_match(struct parameter_list *desired, struct mount_entry *mount_list, bool exact) {
- struct parameter_list *d;
- for (d = desired; d; d = d->name_next) {
- if (!d->best_match) {
- struct mount_entry *me;
- size_t name_len = strlen(d->name);
- size_t best_match_len = 0;
- struct mount_entry *best_match = NULL;
- struct fs_usage fsp;
-
- /* set best match if path name exactly matches a mounted device name */
- for (me = mount_list; me; me = me->me_next) {
- if (strcmp(me->me_devname, d->name) == 0) {
- if (get_fs_usage(me->me_mountdir, me->me_devname, &fsp) >= 0) {
- best_match = me;
- }
- }
- }
-
- /* set best match by directory name if no match was found by devname */
- if (!best_match) {
- for (me = mount_list; me; me = me->me_next) {
- size_t len = strlen(me->me_mountdir);
- if ((!exact &&
- (best_match_len <= len && len <= name_len && (len == 1 || strncmp(me->me_mountdir, d->name, len) == 0))) ||
- (exact && strcmp(me->me_mountdir, d->name) == 0)) {
- if (get_fs_usage(me->me_mountdir, me->me_devname, &fsp) >= 0) {
- best_match = me;
- best_match_len = len;
- }
- }
- }
- }
-
- if (best_match) {
- d->best_match = best_match;
- } else {
- d->best_match = NULL; /* Not sure why this is needed as it should be null on initialisation */
- }
- }
- }
-}
-
-/* Returns true if name is in list */
-bool np_find_name(struct name_list *list, const char *name) {
- const struct name_list *n;
-
- if (list == NULL || name == NULL) {
- return false;
- }
- for (n = list; n; n = n->next) {
- if (!strcmp(name, n->name)) {
- return true;
- }
- }
- return false;
-}
-
-/* Returns true if name is in list */
-bool np_find_regmatch(struct regex_list *list, const char *name) {
- int len;
- regmatch_t m;
-
- if (name == NULL) {
- return false;
- }
-
- len = strlen(name);
-
- for (; list; list = list->next) {
- /* Emulate a full match as if surrounded with ^( )$
- by checking whether the match spans the whole name */
- if (!regexec(&list->regex, name, 1, &m, 0) && m.rm_so == 0 && m.rm_eo == len) {
- return true;
- }
- }
-
- return false;
-}
-
-bool np_seen_name(struct name_list *list, const char *name) {
- const struct name_list *s;
- for (s = list; s; s = s->next) {
- if (!strcmp(s->name, name)) {
- return true;
- }
- }
- return false;
-}
-
-bool np_regex_match_mount_entry(struct mount_entry *me, regex_t *re) {
- if (regexec(re, me->me_devname, (size_t)0, NULL, 0) == 0 || regexec(re, me->me_mountdir, (size_t)0, NULL, 0) == 0) {
- return true;
- }
- return false;
-}
diff --git a/lib/utils_disk.h b/lib/utils_disk.h
deleted file mode 100644
index c5e81dc1..00000000
--- a/lib/utils_disk.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/* Header file for utils_disk */
-
-#include "mountlist.h"
-#include "utils_base.h"
-#include "regex.h"
-
-struct name_list {
- char *name;
- struct name_list *next;
-};
-
-struct regex_list {
- regex_t regex;
- struct regex_list *next;
-};
-
-struct parameter_list {
- char *name;
- thresholds *freespace_bytes;
- thresholds *freespace_units;
- thresholds *freespace_percent;
- thresholds *usedspace_bytes;
- thresholds *usedspace_units;
- thresholds *usedspace_percent;
- thresholds *usedinodes_percent;
- thresholds *freeinodes_percent;
- char *group;
- struct mount_entry *best_match;
- struct parameter_list *name_next;
- struct parameter_list *name_prev;
- uintmax_t total, available, available_to_root, used, inodes_free, inodes_free_to_root, inodes_used, inodes_total;
- double dfree_pct, dused_pct;
- uint64_t dused_units, dfree_units, dtotal_units;
- double dused_inodes_percent, dfree_inodes_percent;
-};
-
-void np_add_name(struct name_list **list, const char *name);
-bool np_find_name(struct name_list *list, const char *name);
-bool np_seen_name(struct name_list *list, const char *name);
-int np_add_regex(struct regex_list **list, const char *regex, int cflags);
-bool np_find_regmatch(struct regex_list *list, const char *name);
-struct parameter_list *np_add_parameter(struct parameter_list **list, const char *name);
-struct parameter_list *np_find_parameter(struct parameter_list *list, const char *name);
-struct parameter_list *np_del_parameter(struct parameter_list *item, struct parameter_list *prev);
-
-int search_parameter_list(struct parameter_list *list, const char *name);
-void np_set_best_match(struct parameter_list *desired, struct mount_entry *mount_list, bool exact);
-bool np_regex_match_mount_entry(struct mount_entry *me, regex_t *re);
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
index e2bed4c3..04fb7ed2 100644
--- a/plugins/Makefile.am
+++ b/plugins/Makefile.am
@@ -40,11 +40,13 @@ EXTRA_PROGRAMS = check_mysql check_radius check_pgsql check_snmp check_hpjd \
check_nagios check_by_ssh check_dns check_nt check_ide_smart \
check_procs check_mysql_query check_apt check_dbi check_curl \
\
- tests/test_check_swap
+ tests/test_check_swap \
+ tests/test_check_disk
SUBDIRS = picohttpparser
-np_test_scripts = tests/test_check_swap.t
+np_test_scripts = tests/test_check_swap.t \
+ tests/test_check_disk.t
EXTRA_DIST = t \
tests \
@@ -55,6 +57,7 @@ EXTRA_DIST = t \
check_hpjd.d \
check_game.d \
check_radius.d \
+ check_disk.d \
check_time.d \
check_nagios.d \
check_dbi.d \
@@ -119,6 +122,7 @@ check_curl_LDADD = $(NETLIBS) $(LIBCURLLIBS) $(SSLOBJS) $(URIPARSERLIBS) picohtt
check_dbi_LDADD = $(NETLIBS) $(DBILIBS)
check_dig_LDADD = $(NETLIBS)
check_disk_LDADD = $(BASEOBJS)
+check_disk_SOURCES = check_disk.c check_disk.d/utils_disk.c
check_dns_LDADD = $(NETLIBS)
check_dummy_LDADD = $(BASEOBJS)
check_fping_LDADD = $(NETLIBS)
@@ -165,6 +169,8 @@ endif
tests_test_check_swap_LDADD = $(BASEOBJS) $(tap_ldflags) -ltap
tests_test_check_swap_SOURCES = tests/test_check_swap.c check_swap.d/swap.c
+tests_test_check_disk_LDADD = $(BASEOBJS) $(tap_ldflags) check_disk.d/utils_disk.c -ltap
+tests_test_check_disk_SOURCES = tests/test_check_disk.c
##############################################################################
# secondary dependencies
diff --git a/plugins/check_disk.c b/plugins/check_disk.c
index 037a6f7a..515ddff0 100644
--- a/plugins/check_disk.c
+++ b/plugins/check_disk.c
@@ -31,24 +31,35 @@ const char *program_name = "check_disk"; /* Required for coreutils libs */
const char *copyright = "1999-2024";
const char *email = "devel@monitoring-plugins.org";
+#include "states.h"
#include "common.h"
+#include "output.h"
+#include "perfdata.h"
+#include "utils_base.h"
+#include "lib/thresholds.h"
+
#ifdef HAVE_SYS_STAT_H
# include
#endif
+
#if HAVE_INTTYPES_H
# include
#endif
+
#include
-#include "popen.h"
-#include "utils.h"
-#include "utils_disk.h"
#include
-#include "fsusage.h"
-#include "mountlist.h"
+#include
#include
+#include "./popen.h"
+#include "./utils.h"
+#include "../gl/fsusage.h"
+#include "../gl/mountlist.h"
+#include "./check_disk.d/utils_disk.h"
+
#if HAVE_LIMITS_H
# include
#endif
+
#include "regex.h"
#ifdef __CYGWIN__
@@ -57,424 +68,310 @@ const char *email = "devel@monitoring-plugins.org";
# define ERROR -1
#endif
-/* If nonzero, show even filesystems with zero size or
- uninteresting types. */
-static int show_all_fs = 1;
-
-/* If nonzero, show only local filesystems. */
-static int show_local_fs = 0;
-
-/* If nonzero, show only local filesystems but call stat() on remote ones. */
-static int stat_remote_fs = 0;
-
-/* If positive, the units to use when printing sizes;
- if negative, the human-readable base. */
-/* static int output_block_size; */
-
-/* If nonzero, invoke the `sync' system call before getting any usage data.
- Using this option can make df very slow, especially with many or very
- busy disks. Note that this may make a difference on some systems --
- SunOs4.1.3, for one. It is *not* necessary on Linux. */
-/* static int require_sync = 0; */
-
-/* Linked list of filesystem types to display.
- If `fs_select_list' is NULL, list all types.
- This table is generated dynamically from command-line options,
- rather than hardcoding into the program what it thinks are the
- valid filesystem types; let the user specify any filesystem type
- they want to, and if there are any filesystems of that type, they
- will be shown.
-
- Some filesystem types:
- 4.2 4.3 ufs nfs swap ignore io vm efs dbg */
-
-/* static struct parameter_list *fs_select_list; */
-
-/* Linked list of filesystem types to omit.
- If the list is empty, don't exclude any types. */
-static struct regex_list *fs_exclude_list = NULL;
-
-/* Linked list of filesystem types to check.
- If the list is empty, include all types. */
-static struct regex_list *fs_include_list;
-
-static struct name_list *dp_exclude_list;
-
-static struct parameter_list *path_select_list = NULL;
-
-/* Linked list of mounted filesystems. */
-static struct mount_entry *mount_list;
-
-/* For long options that have no equivalent short option, use a
- non-character as a pseudo short option, starting with CHAR_MAX + 1. */
-enum {
- SYNC_OPTION = CHAR_MAX + 1,
- NO_SYNC_OPTION,
- BLOCK_SIZE_OPTION
-};
-
#ifdef _AIX
# pragma alloca
#endif
-static int process_arguments(int /*argc*/, char ** /*argv*/);
-static void set_all_thresholds(struct parameter_list *path);
-static void print_help(void);
-void print_usage(void);
-static double calculate_percent(uintmax_t, uintmax_t);
-static bool stat_path(struct parameter_list *p);
-static void get_stats(struct parameter_list *p, struct fs_usage *fsp);
-static void get_path_stats(struct parameter_list *p, struct fs_usage *fsp);
+typedef struct {
+ int errorcode;
+ check_disk_config config;
+} check_disk_config_wrapper;
+static check_disk_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
+
+static void set_all_thresholds(parameter_list_elem *path, char *warn_freespace_units, char *crit_freespace_units,
+ char *warn_freespace_percent, char *crit_freespace_percent, char *warn_freeinodes_percent,
+ char *crit_freeinodes_percent);
+static double calculate_percent(uintmax_t /*value*/, uintmax_t /*total*/);
+static bool stat_path(parameter_list_elem * /*parameters*/, bool /*ignore_missing*/);
+
+/*
+ * Puts the values from a struct fs_usage into a parameter_list with an additional flag to control how reserved
+ * and inodes should be judged (ignored or not)
+ */
+static parameter_list_elem get_path_stats(parameter_list_elem parameters, struct fs_usage fsp, bool freespace_ignore_reserved);
+static mp_subcheck evaluate_filesystem(measurement_unit measurement_unit, bool display_inodes_perfdata, byte_unit unit);
+
+void print_usage(void);
+static void print_help(void);
-static char *units;
-static uintmax_t mult = 1024 * 1024;
static int verbose = 0;
-static bool erronly = false;
-static bool display_mntp = false;
-static bool exact_match = false;
-static bool ignore_missing = false;
-static bool freespace_ignore_reserved = false;
-static bool display_inodes_perfdata = false;
-static char *warn_freespace_units = NULL;
-static char *crit_freespace_units = NULL;
-static char *warn_freespace_percent = NULL;
-static char *crit_freespace_percent = NULL;
-static char *warn_usedspace_units = NULL;
-static char *crit_usedspace_units = NULL;
-static char *warn_usedspace_percent = NULL;
-static char *crit_usedspace_percent = NULL;
-static char *warn_usedinodes_percent = NULL;
-static char *crit_usedinodes_percent = NULL;
-static char *warn_freeinodes_percent = NULL;
-static char *crit_freeinodes_percent = NULL;
-static bool path_selected = false;
-static bool path_ignored = false;
-static char *group = NULL;
-static struct stat *stat_buf;
-static struct name_list *seen = NULL;
+
+// This would not be necessary in C23!!
+const byte_unit Bytes_Factor = 1;
+const byte_unit KibiBytes_factor = 1024;
+const byte_unit MebiBytes_factor = 1048576;
+const byte_unit GibiBytes_factor = 1073741824;
+const byte_unit TebiBytes_factor = 1099511627776;
+const byte_unit PebiBytes_factor = 1125899906842624;
+const byte_unit ExbiBytes_factor = 1152921504606846976;
+const byte_unit KiloBytes_factor = 1000;
+const byte_unit MegaBytes_factor = 1000000;
+const byte_unit GigaBytes_factor = 1000000000;
+const byte_unit TeraBytes_factor = 1000000000000;
+const byte_unit PetaBytes_factor = 1000000000000000;
+const byte_unit ExaBytes_factor = 1000000000000000000;
+
int main(int argc, char **argv) {
- int result = STATE_UNKNOWN;
- int disk_result = STATE_UNKNOWN;
- char *output = NULL;
- char *ignored = NULL;
- char *details = NULL;
- char *perf = NULL;
- char *perf_ilabel = NULL;
- char *preamble = " - free space:";
- char *ignored_preamble = " - ignored paths:";
- char *flag_header = NULL;
- int temp_result = STATE_UNKNOWN;
-
- struct mount_entry *me = NULL;
- struct fs_usage fsp = {0};
- struct parameter_list *temp_list = NULL;
- struct parameter_list *path = NULL;
+ setlocale(LC_ALL, "");
+ bindtextdomain(PACKAGE, LOCALEDIR);
+ textdomain(PACKAGE);
#ifdef __CYGWIN__
char mountdir[32];
#endif
- output = strdup("");
- ignored = strdup("");
- details = strdup("");
- perf = strdup("");
- perf_ilabel = strdup("");
- stat_buf = malloc(sizeof *stat_buf);
-
- setlocale(LC_ALL, "");
- bindtextdomain(PACKAGE, LOCALEDIR);
- textdomain(PACKAGE);
-
- mount_list = read_file_system_list(0);
-
- /* Parse extra opts if any */
+ // Parse extra opts if any
argv = np_extra_opts(&argc, argv, progname);
- if (process_arguments(argc, argv) == ERROR)
+ check_disk_config_wrapper tmp_config = process_arguments(argc, argv);
+ if (tmp_config.errorcode == ERROR) {
usage4(_("Could not parse arguments"));
-
- /* If a list of paths has not been selected, find entire
- mount list and create list of paths
- */
- if (path_selected == false && path_ignored == false) {
- for (me = mount_list; me; me = me->me_next) {
- if (!(path = np_find_parameter(path_select_list, me->me_mountdir))) {
- path = np_add_parameter(&path_select_list, me->me_mountdir);
- }
- path->best_match = me;
- path->group = group;
- set_all_thresholds(path);
- }
}
- if (path_ignored == false) {
- np_set_best_match(path_select_list, mount_list, exact_match);
+ check_disk_config config = tmp_config.config;
+
+ if (config.output_format_is_set) {
+ mp_set_format(config.output_format);
}
- /* Error if no match found for specified paths */
- temp_list = path_select_list;
+ if (config.erronly) {
+ mp_set_level_of_detail(MP_DETAIL_NON_OK_ONLY);
+ }
- while (path_select_list) {
- if (!path_select_list->best_match && ignore_missing == true) {
- /* If the first element will be deleted, the temp_list must be updated with the new start address as well */
- if (path_select_list == temp_list) {
- temp_list = path_select_list->name_next;
- }
- /* Add path argument to list of ignored paths to inform about missing paths being ignored and not alerted */
- xasprintf(&ignored, "%s %s;", ignored, path_select_list->name);
+ if (!config.path_ignored) {
+ mp_int_fs_list_set_best_match(config.path_select_list, config.mount_list, config.exact_match);
+ }
+
+ // Error if no match found for specified paths
+ for (parameter_list_elem *elem = config.path_select_list.first; elem;) {
+ if (!elem->best_match && config.ignore_missing) {
/* Delete the path from the list so that it is not stat-checked later in the code. */
- path_select_list = np_del_parameter(path_select_list, path_select_list->name_prev);
- } else if (!path_select_list->best_match) {
+ elem = mp_int_fs_list_del(&config.path_select_list, elem);
+ continue;
+ }
+ if (!elem->best_match) {
/* Without --ignore-missing option, exit with Critical state. */
- die(STATE_CRITICAL, _("DISK %s: %s not found\n"), _("CRITICAL"), path_select_list->name);
+ die(STATE_CRITICAL, _("DISK %s: %s not found\n"), _("CRITICAL"), elem->name);
+ }
+
+ elem = mp_int_fs_list_get_next(elem);
+ }
+
+ mp_check overall = mp_check_init();
+ if (config.path_select_list.length == 0) {
+ mp_subcheck none_sc = mp_subcheck_init();
+ xasprintf(&none_sc.output, "No filesystems were found for the provided parameters");
+ if (config.ignore_missing) {
+ none_sc = mp_set_subcheck_state(none_sc, STATE_OK);
} else {
- /* Continue jumping through the list */
- path_select_list = path_select_list->name_next;
+ none_sc = mp_set_subcheck_state(none_sc, STATE_UNKNOWN);
+ if (verbose >= 2) {
+ printf("None of the provided paths were found\n");
+ }
+ }
+ mp_add_subcheck_to_check(&overall, none_sc);
+ mp_exit(overall);
+ }
+
+ // Filter list first
+ for (parameter_list_elem *path = config.path_select_list.first; path;) {
+ if (!path->best_match) {
+ path = mp_int_fs_list_del(&config.path_select_list, path);
+ continue;
+ }
+
+ struct mount_entry *mount_entry = path->best_match;
+
+#ifdef __CYGWIN__
+ if (strncmp(path->name, "/cygdrive/", 10) != 0 || strlen(path->name) > 11) {
+ path = mp_int_fs_list_del(&config.path_select_list, path);
+ continue;
+ }
+
+ char *mountdir = NULL;
+ snprintf(mountdir, sizeof(mountdir), "%s:\\", me->me_mountdir + 10);
+ if (GetDriveType(mountdir) != DRIVE_FIXED) {
+ mount_entry->me_remote = 1;
+ }
+#endif
+
+ /* Remove filesystems already seen */
+ if (np_seen_name(config.seen, mount_entry->me_mountdir)) {
+ path = mp_int_fs_list_del(&config.path_select_list, path);
+ continue;
+ }
+
+ if (path->group == NULL) {
+ if (config.fs_exclude_list && np_find_regmatch(config.fs_exclude_list, mount_entry->me_type)) {
+ // Skip excluded fs's
+ path = mp_int_fs_list_del(&config.path_select_list, path);
+ continue;
+ }
+
+ if (config.device_path_exclude_list && (np_find_name(config.device_path_exclude_list, mount_entry->me_devname) ||
+ np_find_name(config.device_path_exclude_list, mount_entry->me_mountdir))) {
+ // Skip excluded device or mount paths
+ path = mp_int_fs_list_del(&config.path_select_list, path);
+ continue;
+ }
+
+ if (config.fs_include_list && !np_find_regmatch(config.fs_include_list, mount_entry->me_type)) {
+ // Skip not included fstypes
+ path = mp_int_fs_list_del(&config.path_select_list, path);
+ continue;
+ }
+
+ /* Skip remote filesystems if we're not interested in them */
+ if (mount_entry->me_remote && config.show_local_fs) {
+ if (config.stat_remote_fs) {
+ // TODO Stat here
+ if (!stat_path(path, config.ignore_missing) && config.ignore_missing) {
+ }
+ }
+ continue;
+ }
+
+ // TODO why stat here? remove unstatable fs?
+ if (!stat_path(path, config.ignore_missing)) {
+ // if (config.ignore_missing) {
+ // xasprintf(&ignored, "%s %s;", ignored, path->name);
+ // }
+ // not accessible, remove from list
+ path = mp_int_fs_list_del(&config.path_select_list, path);
+ continue;
+ }
+ }
+
+ path = mp_int_fs_list_get_next(path);
+ }
+
+ // now get the actual measurements
+ for (parameter_list_elem *filesystem = config.path_select_list.first; filesystem;) {
+ // Get actual metrics here
+ struct mount_entry *mount_entry = filesystem->best_match;
+ struct fs_usage fsp = {0};
+ get_fs_usage(mount_entry->me_mountdir, mount_entry->me_devname, &fsp);
+
+ if (fsp.fsu_blocks != 0 && strcmp("none", mount_entry->me_mountdir) != 0) {
+ *filesystem = get_path_stats(*filesystem, fsp, config.freespace_ignore_reserved);
+
+ if (verbose >= 3) {
+ printf("For %s, used_units=%lu free_units=%lu total_units=%lu "
+ "fsp.fsu_blocksize=%lu\n",
+ mount_entry->me_mountdir, filesystem->used_bytes, filesystem->free_bytes, filesystem->total_bytes,
+ fsp.fsu_blocksize);
+ }
+ } else {
+ // failed to retrieve file system data or not mounted?
+ filesystem = mp_int_fs_list_del(&config.path_select_list, filesystem);
+ continue;
+ }
+ filesystem = mp_int_fs_list_get_next(filesystem);
+ }
+
+ if (verbose > 2) {
+ for (parameter_list_elem *filesystem = config.path_select_list.first; filesystem;
+ filesystem = mp_int_fs_list_get_next(filesystem)) {
+ assert(filesystem->best_match != NULL);
+ if (filesystem->best_match == NULL) {
+ printf("Filesystem path %s has no mount_entry!\n", filesystem->name);
+ } else {
+ // printf("Filesystem path %s has a mount_entry!\n", filesystem->name);
+ }
}
}
- path_select_list = temp_list;
+ measurement_unit_list *measurements = NULL;
+ measurement_unit_list *current = NULL;
+ // create measuring units, because of groups
+ for (parameter_list_elem *filesystem = config.path_select_list.first; filesystem; filesystem = mp_int_fs_list_get_next(filesystem)) {
+ assert(filesystem->best_match != NULL);
- if (!path_select_list && ignore_missing == true) {
- result = STATE_OK;
- if (verbose >= 2) {
- printf("None of the provided paths were found\n");
+ if (filesystem->group == NULL) {
+ // create a measurement unit for the fs
+ measurement_unit unit = create_measurement_unit_from_filesystem(*filesystem, config.display_mntp);
+ if (measurements == NULL) {
+ measurements = current = add_measurement_list(NULL, unit);
+ } else {
+ current = add_measurement_list(measurements, unit);
+ }
+ } else {
+ // Grouped elements are consecutive
+ if (measurements == NULL) {
+ // first entry
+ measurement_unit unit = create_measurement_unit_from_filesystem(*filesystem, config.display_mntp);
+ unit.name = strdup(filesystem->group);
+ measurements = current = add_measurement_list(NULL, unit);
+ } else {
+ // if this is the first element of a group, the name of the previous entry is different
+ if (strcmp(filesystem->group, current->unit.name) != 0) {
+ // so, this must be the first element of a group
+ measurement_unit unit = create_measurement_unit_from_filesystem(*filesystem, config.display_mntp);
+ unit.name = filesystem->group;
+ current = add_measurement_list(measurements, unit);
+
+ } else {
+ // NOT the first entry of a group, add info to the other one
+ current->unit = add_filesystem_to_measurement_unit(current->unit, *filesystem);
+ }
+ }
}
}
/* Process for every path in list */
- for (path = path_select_list; path; path = path->name_next) {
- if (verbose >= 3 && path->freespace_percent->warning != NULL && path->freespace_percent->critical != NULL)
- printf("Thresholds(pct) for %s warn: %f crit %f\n", path->name, path->freespace_percent->warning->end,
- path->freespace_percent->critical->end);
-
- if (verbose >= 3 && path->group != NULL)
- printf("Group of %s: %s\n", path->name, path->group);
-
- /* reset disk result */
- disk_result = STATE_UNKNOWN;
-
- me = path->best_match;
-
- if (!me) {
- continue;
+ if (measurements != NULL) {
+ for (measurement_unit_list *unit = measurements; unit; unit = unit->next) {
+ mp_subcheck unit_sc = evaluate_filesystem(unit->unit, config.display_inodes_perfdata, config.display_unit);
+ mp_add_subcheck_to_check(&overall, unit_sc);
}
+ } else {
+ // Apparently no machting fs found
+ mp_subcheck none_sc = mp_subcheck_init();
+ xasprintf(&none_sc.output, "No filesystems were found for the provided parameters");
-#ifdef __CYGWIN__
- if (strncmp(path->name, "/cygdrive/", 10) != 0 || strlen(path->name) > 11)
- continue;
- snprintf(mountdir, sizeof(mountdir), "%s:\\", me->me_mountdir + 10);
- if (GetDriveType(mountdir) != DRIVE_FIXED)
- me->me_remote = 1;
-#endif
- /* Filters */
-
- /* Remove filesystems already seen */
- if (np_seen_name(seen, me->me_mountdir)) {
- continue;
- }
- np_add_name(&seen, me->me_mountdir);
-
- if (path->group == NULL) {
- /* Skip remote filesystems if we're not interested in them */
- if (me->me_remote && show_local_fs) {
- if (stat_remote_fs) {
- if (!stat_path(path) && ignore_missing == true) {
- result = STATE_OK;
- xasprintf(&ignored, "%s %s;", ignored, path->name);
- }
- }
- continue;
- /* Skip pseudo fs's if we haven't asked for all fs's */
- }
- if (me->me_dummy && !show_all_fs) {
- continue;
- /* Skip excluded fstypes */
- }
- if (fs_exclude_list && np_find_regmatch(fs_exclude_list, me->me_type)) {
- continue;
- /* Skip excluded fs's */
- }
- if (dp_exclude_list && (np_find_name(dp_exclude_list, me->me_devname) || np_find_name(dp_exclude_list, me->me_mountdir))) {
- continue;
- /* Skip not included fstypes */
- }
- if (fs_include_list && !np_find_regmatch(fs_include_list, me->me_type)) {
- continue;
- }
- }
-
- if (!stat_path(path)) {
- if (ignore_missing == true) {
- result = STATE_OK;
- xasprintf(&ignored, "%s %s;", ignored, path->name);
- }
- continue;
- }
- get_fs_usage(me->me_mountdir, me->me_devname, &fsp);
-
- if (fsp.fsu_blocks && strcmp("none", me->me_mountdir)) {
- get_stats(path, &fsp);
-
- if (verbose >= 3) {
- printf("For %s, used_pct=%f free_pct=%f used_units=%lu free_units=%lu total_units=%lu used_inodes_pct=%f "
- "free_inodes_pct=%f fsp.fsu_blocksize=%lu mult=%lu\n",
- me->me_mountdir, path->dused_pct, path->dfree_pct, path->dused_units, path->dfree_units, path->dtotal_units,
- path->dused_inodes_percent, path->dfree_inodes_percent, fsp.fsu_blocksize, mult);
- }
-
- /* Threshold comparisons */
-
- temp_result = get_status(path->dfree_units, path->freespace_units);
- if (verbose >= 3)
- printf("Freespace_units result=%d\n", temp_result);
- disk_result = max_state(disk_result, temp_result);
-
- temp_result = get_status(path->dfree_pct, path->freespace_percent);
- if (verbose >= 3)
- printf("Freespace%% result=%d\n", temp_result);
- disk_result = max_state(disk_result, temp_result);
-
- temp_result = get_status(path->dused_units, path->usedspace_units);
- if (verbose >= 3)
- printf("Usedspace_units result=%d\n", temp_result);
- disk_result = max_state(disk_result, temp_result);
-
- temp_result = get_status(path->dused_pct, path->usedspace_percent);
- if (verbose >= 3)
- printf("Usedspace_percent result=%d\n", temp_result);
- disk_result = max_state(disk_result, temp_result);
-
- temp_result = get_status(path->dused_inodes_percent, path->usedinodes_percent);
- if (verbose >= 3)
- printf("Usedinodes_percent result=%d\n", temp_result);
- disk_result = max_state(disk_result, temp_result);
-
- temp_result = get_status(path->dfree_inodes_percent, path->freeinodes_percent);
- if (verbose >= 3)
- printf("Freeinodes_percent result=%d\n", temp_result);
- disk_result = max_state(disk_result, temp_result);
-
- result = max_state(result, disk_result);
-
- /* What a mess of units. The output shows free space, the perf data shows used space. Yikes!
- Hack here. Trying to get warn/crit levels from freespace_(units|percent) for perf
- data. Assumption that start=0. Roll on new syntax...
- */
-
- /* *_high_tide must be reinitialized at each run */
- uint64_t warning_high_tide = UINT64_MAX;
-
- if (path->freespace_units->warning != NULL) {
- warning_high_tide = (path->dtotal_units - path->freespace_units->warning->end) * mult;
- }
- if (path->freespace_percent->warning != NULL) {
- warning_high_tide =
- min(warning_high_tide, (uint64_t)((1.0 - path->freespace_percent->warning->end / 100) * (path->dtotal_units * mult)));
- }
-
- uint64_t critical_high_tide = UINT64_MAX;
-
- if (path->freespace_units->critical != NULL) {
- critical_high_tide = (path->dtotal_units - path->freespace_units->critical->end) * mult;
- }
- if (path->freespace_percent->critical != NULL) {
- critical_high_tide =
- min(critical_high_tide, (uint64_t)((1.0 - path->freespace_percent->critical->end / 100) * (path->dtotal_units * mult)));
- }
-
- /* Nb: *_high_tide are unset when == UINT64_MAX */
- xasprintf(&perf, "%s %s", perf,
- perfdata_uint64((!strcmp(me->me_mountdir, "none") || display_mntp) ? me->me_devname : me->me_mountdir,
- path->dused_units * mult, "B", (warning_high_tide == UINT64_MAX ? false : true), warning_high_tide,
- (critical_high_tide == UINT64_MAX ? false : true), critical_high_tide, true, 0, true,
- path->dtotal_units * mult));
-
- if (display_inodes_perfdata) {
- /* *_high_tide must be reinitialized at each run */
- warning_high_tide = UINT64_MAX;
- critical_high_tide = UINT64_MAX;
-
- if (path->freeinodes_percent->warning != NULL) {
- warning_high_tide = (uint64_t)fabs(
- min((double)warning_high_tide, (double)(1.0 - path->freeinodes_percent->warning->end / 100) * path->inodes_total));
- }
- if (path->freeinodes_percent->critical != NULL) {
- critical_high_tide = (uint64_t)fabs(min(
- (double)critical_high_tide, (double)(1.0 - path->freeinodes_percent->critical->end / 100) * path->inodes_total));
- }
-
- xasprintf(&perf_ilabel, "%s (inodes)",
- (!strcmp(me->me_mountdir, "none") || display_mntp) ? me->me_devname : me->me_mountdir);
- /* Nb: *_high_tide are unset when == UINT64_MAX */
- xasprintf(&perf, "%s %s", perf,
- perfdata_uint64(perf_ilabel, path->inodes_used, "", (warning_high_tide != UINT64_MAX ? true : false),
- warning_high_tide, (critical_high_tide != UINT64_MAX ? true : false), critical_high_tide, true, 0,
- true, path->inodes_total));
- }
-
- if (disk_result == STATE_OK && erronly && !verbose)
- continue;
-
- if (disk_result && verbose >= 1) {
- xasprintf(&flag_header, " %s [", state_text(disk_result));
- } else {
- xasprintf(&flag_header, "");
- }
- xasprintf(&output, "%s%s %s %llu%s (%.1f%%", output, flag_header,
- (!strcmp(me->me_mountdir, "none") || display_mntp) ? me->me_devname : me->me_mountdir, path->dfree_units, units,
- path->dfree_pct);
- if (path->dused_inodes_percent < 0) {
- xasprintf(&output, "%s inode=-)%s;", output, (disk_result ? "]" : ""));
- } else {
- xasprintf(&output, "%s inode=%.0f%%)%s;", output, path->dfree_inodes_percent, ((disk_result && verbose >= 1) ? "]" : ""));
- }
- free(flag_header);
+ if (config.ignore_missing) {
+ none_sc = mp_set_subcheck_state(none_sc, STATE_OK);
+ } else {
+ none_sc = mp_set_subcheck_state(none_sc, STATE_UNKNOWN);
}
+ mp_add_subcheck_to_check(&overall, none_sc);
}
- if (verbose >= 2)
- xasprintf(&output, "%s%s", output, details);
-
- if (strcmp(output, "") == 0 && !erronly) {
- preamble = "";
- xasprintf(&output, " - No disks were found for provided parameters");
- }
-
- printf("DISK %s%s%s%s%s|%s\n", state_text(result), ((erronly && result == STATE_OK)) ? "" : preamble, output,
- (strcmp(ignored, "") == 0) ? "" : ignored_preamble, ignored, perf);
- return result;
+ mp_exit(overall);
}
double calculate_percent(uintmax_t value, uintmax_t total) {
double pct = -1;
if (value <= DBL_MAX && total != 0) {
- pct = (double)value / total * 100.0;
+ pct = (double)value / (double)total * 100.0;
}
+
return pct;
}
/* process command-line arguments */
-int process_arguments(int argc, char **argv) {
- int c;
- int err;
- struct parameter_list *se;
- struct parameter_list *temp_list = NULL;
- struct parameter_list *previous = NULL;
- struct mount_entry *me;
- regex_t re;
- int cflags = REG_NOSUB | REG_EXTENDED;
- int default_cflags = cflags;
- char errbuf[MAX_INPUT_BUFFER];
- int fnd = 0;
+check_disk_config_wrapper process_arguments(int argc, char **argv) {
+
+ check_disk_config_wrapper result = {
+ .errorcode = OK,
+ .config = check_disk_config_init(),
+ };
+
+ if (argc < 2) {
+ result.errorcode = ERROR;
+ return result;
+ }
+
+ enum {
+ output_format_index = CHAR_MAX + 1,
+ display_unit_index,
+ };
- int option = 0;
static struct option longopts[] = {{"timeout", required_argument, 0, 't'},
{"warning", required_argument, 0, 'w'},
{"critical", required_argument, 0, 'c'},
{"iwarning", required_argument, 0, 'W'},
- /* Dang, -C is taken. We might want to reshuffle this. */
{"icritical", required_argument, 0, 'K'},
{"kilobytes", no_argument, 0, 'k'},
{"megabytes", no_argument, 0, 'm'},
@@ -507,24 +404,42 @@ int process_arguments(int argc, char **argv) {
{"clear", no_argument, 0, 'C'},
{"version", no_argument, 0, 'V'},
{"help", no_argument, 0, 'h'},
+ {"output-format", required_argument, 0, output_format_index},
+ {"display-unit", required_argument, 0, display_unit_index},
{0, 0, 0, 0}};
- if (argc < 2)
- return ERROR;
+ for (int index = 1; index < argc; index++) {
+ if (strcmp("-to", argv[index]) == 0) {
+ strcpy(argv[index], "-t");
+ }
+ }
- np_add_regex(&fs_exclude_list, "iso9660", REG_EXTENDED);
+ int cflags = REG_NOSUB | REG_EXTENDED;
+ int default_cflags = cflags;
+ char *warn_freespace_units = NULL;
+ char *crit_freespace_units = NULL;
+ char *warn_freespace_percent = NULL;
+ char *crit_freespace_percent = NULL;
+ char *warn_freeinodes_percent = NULL;
+ char *crit_freeinodes_percent = NULL;
- for (c = 1; c < argc; c++)
- if (strcmp("-to", argv[c]) == 0)
- strcpy(argv[c], "-t");
+ bool path_selected = false;
+ char *group = NULL;
+ byte_unit unit = MebiBytes_factor;
- while (1) {
- c = getopt_long(argc, argv, "+?VqhvefCt:c:w:K:W:u:p:x:X:N:mklLPg:R:r:i:I:MEAn", longopts, &option);
+ result.config.mount_list = read_file_system_list(false);
- if (c == -1 || c == EOF)
+ np_add_regex(&result.config.fs_exclude_list, "iso9660", REG_EXTENDED);
+
+ while (true) {
+ int option = 0;
+ int option_index = getopt_long(argc, argv, "+?VqhvefCt:c:w:K:W:u:p:x:X:N:mklLPg:R:r:i:I:MEAn", longopts, &option);
+
+ if (option_index == -1 || option_index == EOF) {
break;
+ }
- switch (c) {
+ switch (option_index) {
case 't': /* timeout period */
if (is_integer(optarg)) {
timeout_interval = atoi(optarg);
@@ -555,10 +470,10 @@ int process_arguments(int argc, char **argv) {
break;
/* Awful mistake where the range values do not make sense. Normally,
- you alert if the value is within the range, but since we are using
- freespace, we have to alert if outside the range. Thus we artificially
- force @ at the beginning of the range, so that it is backwards compatible
- */
+ * you alert if the value is within the range, but since we are using
+ * freespace, we have to alert if outside the range. Thus we artificially
+ * force @ at the beginning of the range, so that it is backwards compatible
+ */
case 'c': /* critical threshold */
if (!is_percentage_expression(optarg) && !is_numeric(optarg)) {
die(STATE_UNKNOWN, "Argument for --critical invalid or missing: %s\n", optarg);
@@ -594,181 +509,184 @@ int process_arguments(int argc, char **argv) {
}
break;
case 'u':
- if (units)
- free(units);
if (!strcasecmp(optarg, "bytes")) {
- mult = (uintmax_t)1;
- units = strdup("B");
+ unit = Bytes_Factor;
} else if (!strcmp(optarg, "KiB")) {
- mult = (uintmax_t)1024;
- units = strdup("KiB");
+ unit = KibiBytes_factor;
} else if (!strcmp(optarg, "kB")) {
- mult = (uintmax_t)1000;
- units = strdup("kB");
+ unit = KiloBytes_factor;
} else if (!strcmp(optarg, "MiB")) {
- mult = (uintmax_t)1024 * 1024;
- units = strdup("MiB");
+ unit = MebiBytes_factor;
} else if (!strcmp(optarg, "MB")) {
- mult = (uintmax_t)1000 * 1000;
- units = strdup("MB");
+ unit = MegaBytes_factor;
} else if (!strcmp(optarg, "GiB")) {
- mult = (uintmax_t)1024 * 1024 * 1024;
- units = strdup("GiB");
+ unit = GibiBytes_factor;
} else if (!strcmp(optarg, "GB")) {
- mult = (uintmax_t)1000 * 1000 * 1000;
- units = strdup("GB");
+ unit = GigaBytes_factor;
} else if (!strcmp(optarg, "TiB")) {
- mult = (uintmax_t)1024 * 1024 * 1024 * 1024;
- units = strdup("TiB");
+ unit = TebiBytes_factor;
} else if (!strcmp(optarg, "TB")) {
- mult = (uintmax_t)1000 * 1000 * 1000 * 1000;
- units = strdup("TB");
+ unit = TeraBytes_factor;
} else if (!strcmp(optarg, "PiB")) {
- mult = (uintmax_t)1024 * 1024 * 1024 * 1024 * 1024;
- units = strdup("PiB");
+ unit = PebiBytes_factor;
} else if (!strcmp(optarg, "PB")) {
- mult = (uintmax_t)1000 * 1000 * 1000 * 1000 * 1000;
- units = strdup("PB");
+ unit = PetaBytes_factor;
} else {
die(STATE_UNKNOWN, _("unit type %s not known\n"), optarg);
}
- if (units == NULL)
- die(STATE_UNKNOWN, _("failed allocating storage for '%s'\n"), "units");
break;
- case 'k': /* display mountpoint */
- mult = 1024;
- if (units)
- free(units);
- units = strdup("kiB");
+ case 'k':
+ unit = KibiBytes_factor;
break;
- case 'm': /* display mountpoint */
- mult = 1024 * 1024;
- if (units)
- free(units);
- units = strdup("MiB");
+ case 'm':
+ unit = MebiBytes_factor;
+ break;
+ case display_unit_index:
+ if (!strcasecmp(optarg, "bytes")) {
+ result.config.display_unit = Bytes;
+ } else if (!strcmp(optarg, "KiB")) {
+ result.config.display_unit = KibiBytes;
+ } else if (!strcmp(optarg, "kB")) {
+ result.config.display_unit = KiloBytes;
+ } else if (!strcmp(optarg, "MiB")) {
+ result.config.display_unit = MebiBytes;
+ } else if (!strcmp(optarg, "MB")) {
+ result.config.display_unit = MegaBytes;
+ } else if (!strcmp(optarg, "GiB")) {
+ result.config.display_unit = GibiBytes;
+ } else if (!strcmp(optarg, "GB")) {
+ result.config.display_unit = GigaBytes;
+ } else if (!strcmp(optarg, "TiB")) {
+ result.config.display_unit = TebiBytes;
+ } else if (!strcmp(optarg, "TB")) {
+ result.config.display_unit = TeraBytes;
+ } else if (!strcmp(optarg, "PiB")) {
+ result.config.display_unit = PebiBytes;
+ } else if (!strcmp(optarg, "PB")) {
+ result.config.display_unit = PetaBytes;
+ } else {
+ die(STATE_UNKNOWN, _("unit type %s not known\n"), optarg);
+ }
break;
case 'L':
- stat_remote_fs = 1;
+ result.config.stat_remote_fs = true;
/* fallthrough */
case 'l':
- show_local_fs = 1;
+ result.config.show_local_fs = true;
break;
case 'P':
- display_inodes_perfdata = 1;
+ result.config.display_inodes_perfdata = true;
break;
- case 'p': /* select path */
+ case 'p': /* select path */ {
if (!(warn_freespace_units || crit_freespace_units || warn_freespace_percent || crit_freespace_percent ||
- warn_usedspace_units || crit_usedspace_units || warn_usedspace_percent || crit_usedspace_percent ||
- warn_usedinodes_percent || crit_usedinodes_percent || warn_freeinodes_percent || crit_freeinodes_percent)) {
+ warn_freeinodes_percent || crit_freeinodes_percent)) {
die(STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set a threshold value before using -p\n"));
}
/* add parameter if not found. overwrite thresholds if path has already been added */
- if (!(se = np_find_parameter(path_select_list, optarg))) {
- se = np_add_parameter(&path_select_list, optarg);
+ parameter_list_elem *search_entry;
+ if (!(search_entry = mp_int_fs_list_find(result.config.path_select_list, optarg))) {
+ search_entry = mp_int_fs_list_append(&result.config.path_select_list, optarg);
- if (stat(optarg, &stat_buf[0]) && ignore_missing == true) {
- path_ignored = true;
- break;
- }
+ // struct stat stat_buf = {};
+ // if (stat(optarg, &stat_buf) && result.config.ignore_missing) {
+ // result.config.path_ignored = true;
+ // break;
+ // }
}
- se->group = group;
- set_all_thresholds(se);
+ search_entry->group = group;
+ set_all_thresholds(search_entry, warn_freespace_units, crit_freespace_units, warn_freespace_percent, crit_freespace_percent,
+
+ warn_freeinodes_percent, crit_freeinodes_percent);
/* With autofs, it is required to stat() the path before re-populating the mount_list */
- if (!stat_path(se)) {
- break;
- }
- /* NB: We can't free the old mount_list "just like that": both list pointers and struct
- * pointers are copied around. One of the reason it wasn't done yet is that other parts
- * of check_disk need the same kind of cleanup so it'd better be done as a whole */
- mount_list = read_file_system_list(0);
- np_set_best_match(se, mount_list, exact_match);
+ // if (!stat_path(se, result.config.ignore_missing)) {
+ // break;
+ // }
+ mp_int_fs_list_set_best_match(result.config.path_select_list, result.config.mount_list, result.config.exact_match);
path_selected = true;
- break;
+ } break;
case 'x': /* exclude path or partition */
- np_add_name(&dp_exclude_list, optarg);
+ np_add_name(&result.config.device_path_exclude_list, optarg);
break;
- case 'X': /* exclude file system type */
- err = np_add_regex(&fs_exclude_list, optarg, REG_EXTENDED);
+ case 'X': /* exclude file system type */ {
+ int err = np_add_regex(&result.config.fs_exclude_list, optarg, REG_EXTENDED);
if (err != 0) {
- regerror(err, &fs_exclude_list->regex, errbuf, MAX_INPUT_BUFFER);
+ char errbuf[MAX_INPUT_BUFFER];
+ regerror(err, &result.config.fs_exclude_list->regex, errbuf, MAX_INPUT_BUFFER);
die(STATE_UNKNOWN, "DISK %s: %s - %s\n", _("UNKNOWN"), _("Could not compile regular expression"), errbuf);
}
break;
case 'N': /* include file system type */
- err = np_add_regex(&fs_include_list, optarg, REG_EXTENDED);
+ err = np_add_regex(&result.config.fs_include_list, optarg, REG_EXTENDED);
if (err != 0) {
- regerror(err, &fs_exclude_list->regex, errbuf, MAX_INPUT_BUFFER);
+ char errbuf[MAX_INPUT_BUFFER];
+ regerror(err, &result.config.fs_exclude_list->regex, errbuf, MAX_INPUT_BUFFER);
die(STATE_UNKNOWN, "DISK %s: %s - %s\n", _("UNKNOWN"), _("Could not compile regular expression"), errbuf);
}
- break;
+ } break;
case 'v': /* verbose */
verbose++;
break;
case 'q': /* TODO: this function should eventually go away (removed 2007-09-20) */
/* verbose--; **replaced by line below**. -q was only a broken way of implementing -e */
- erronly = true;
+ result.config.erronly = true;
break;
case 'e':
- erronly = true;
+ result.config.erronly = true;
break;
case 'E':
- if (path_selected)
+ if (path_selected) {
die(STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set -E before selecting paths\n"));
- exact_match = true;
+ }
+ result.config.exact_match = true;
break;
case 'f':
- freespace_ignore_reserved = true;
+ result.config.freespace_ignore_reserved = true;
break;
case 'g':
- if (path_selected)
+ if (path_selected) {
die(STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set group value before selecting paths\n"));
+ }
group = optarg;
break;
case 'I':
cflags |= REG_ICASE;
// Intentional fallthrough
- case 'i':
- if (!path_selected)
+ case 'i': {
+ if (!path_selected) {
die(STATE_UNKNOWN, "DISK %s: %s\n", _("UNKNOWN"),
_("Paths need to be selected before using -i/-I. Use -A to select all paths explicitly"));
- err = regcomp(&re, optarg, cflags);
+ }
+ regex_t regex;
+ int err = regcomp(®ex, optarg, cflags);
if (err != 0) {
- regerror(err, &re, errbuf, MAX_INPUT_BUFFER);
+ char errbuf[MAX_INPUT_BUFFER];
+ regerror(err, ®ex, errbuf, MAX_INPUT_BUFFER);
die(STATE_UNKNOWN, "DISK %s: %s - %s\n", _("UNKNOWN"), _("Could not compile regular expression"), errbuf);
}
- temp_list = path_select_list;
+ for (parameter_list_elem *elem = result.config.path_select_list.first; elem;) {
+ if (elem->best_match) {
+ if (np_regex_match_mount_entry(elem->best_match, ®ex)) {
- previous = NULL;
- while (temp_list) {
- if (temp_list->best_match) {
- if (np_regex_match_mount_entry(temp_list->best_match, &re)) {
+ if (verbose >= 3) {
+ printf("ignoring %s matching regex\n", elem->name);
+ }
- if (verbose >= 3)
- printf("ignoring %s matching regex\n", temp_list->name);
-
- temp_list = np_del_parameter(temp_list, previous);
- /* pointer to first element needs to be updated if first item gets deleted */
- if (previous == NULL)
- path_select_list = temp_list;
- } else {
- previous = temp_list;
- temp_list = temp_list->name_next;
+ elem = mp_int_fs_list_del(&result.config.path_select_list, elem);
+ continue;
}
- } else {
- previous = temp_list;
- temp_list = temp_list->name_next;
}
+
+ elem = mp_int_fs_list_get_next(elem);
}
cflags = default_cflags;
- break;
-
+ } break;
case 'n':
- ignore_missing = true;
+ result.config.ignore_missing = true;
break;
case 'A':
optarg = strdup(".*");
@@ -776,80 +694,83 @@ int process_arguments(int argc, char **argv) {
case 'R':
cflags |= REG_ICASE;
// Intentional fallthrough
- case 'r':
+ case 'r': {
if (!(warn_freespace_units || crit_freespace_units || warn_freespace_percent || crit_freespace_percent ||
- warn_usedspace_units || crit_usedspace_units || warn_usedspace_percent || crit_usedspace_percent ||
- warn_usedinodes_percent || crit_usedinodes_percent || warn_freeinodes_percent || crit_freeinodes_percent)) {
+ warn_freeinodes_percent || crit_freeinodes_percent)) {
die(STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"),
_("Must set a threshold value before using -r/-R/-A (--ereg-path/--eregi-path/--all)\n"));
}
- err = regcomp(&re, optarg, cflags);
+ regex_t regex;
+ int err = regcomp(®ex, optarg, cflags);
if (err != 0) {
- regerror(err, &re, errbuf, MAX_INPUT_BUFFER);
+ char errbuf[MAX_INPUT_BUFFER];
+ regerror(err, ®ex, errbuf, MAX_INPUT_BUFFER);
die(STATE_UNKNOWN, "DISK %s: %s - %s\n", _("UNKNOWN"), _("Could not compile regular expression"), errbuf);
}
- for (me = mount_list; me; me = me->me_next) {
- if (np_regex_match_mount_entry(me, &re)) {
- fnd = true;
- if (verbose >= 3)
+ bool found = false;
+ for (struct mount_entry *me = result.config.mount_list; me; me = me->me_next) {
+ if (np_regex_match_mount_entry(me, ®ex)) {
+ found = true;
+ if (verbose >= 3) {
printf("%s %s matching expression %s\n", me->me_devname, me->me_mountdir, optarg);
+ }
/* add parameter if not found. overwrite thresholds if path has already been added */
- if (!(se = np_find_parameter(path_select_list, me->me_mountdir))) {
- se = np_add_parameter(&path_select_list, me->me_mountdir);
+ parameter_list_elem *se = NULL;
+ if (!(se = mp_int_fs_list_find(result.config.path_select_list, me->me_mountdir))) {
+ se = mp_int_fs_list_append(&result.config.path_select_list, me->me_mountdir);
}
se->group = group;
- set_all_thresholds(se);
+ set_all_thresholds(se, warn_freespace_units, crit_freespace_units, warn_freespace_percent, crit_freespace_percent,
+ warn_freeinodes_percent, crit_freeinodes_percent);
}
}
- if (!fnd && ignore_missing == true) {
- path_ignored = true;
- path_selected = true;
- break;
- }
- if (!fnd)
- die(STATE_UNKNOWN, "DISK %s: %s - %s\n", _("UNKNOWN"), _("Regular expression did not match any path or disk"), optarg);
+ if (!found) {
+ if (result.config.ignore_missing) {
+ result.config.path_ignored = true;
+ path_selected = true;
+ break;
+ }
+
+ die(STATE_UNKNOWN, "DISK %s: %s - %s\n", _("UNKNOWN"), _("Regular expression did not match any path or disk"), optarg);
+ }
- fnd = false;
path_selected = true;
- np_set_best_match(path_select_list, mount_list, exact_match);
+ mp_int_fs_list_set_best_match(result.config.path_select_list, result.config.mount_list, result.config.exact_match);
cflags = default_cflags;
- break;
+ } break;
case 'M': /* display mountpoint */
- display_mntp = true;
+ result.config.display_mntp = true;
break;
- case 'C':
+ case 'C': {
/* add all mount entries to path_select list if no partitions have been explicitly defined using -p */
- if (path_selected == false) {
- struct parameter_list *path;
- for (me = mount_list; me; me = me->me_next) {
- if (!(path = np_find_parameter(path_select_list, me->me_mountdir)))
- path = np_add_parameter(&path_select_list, me->me_mountdir);
+ if (!path_selected) {
+ parameter_list_elem *path;
+ for (struct mount_entry *me = result.config.mount_list; me; me = me->me_next) {
+ if (!(path = mp_int_fs_list_find(result.config.path_select_list, me->me_mountdir))) {
+ path = mp_int_fs_list_append(&result.config.path_select_list, me->me_mountdir);
+ }
path->best_match = me;
path->group = group;
- set_all_thresholds(path);
+ set_all_thresholds(path, warn_freespace_units, crit_freespace_units, warn_freespace_percent, crit_freespace_percent,
+ warn_freeinodes_percent, crit_freeinodes_percent);
}
}
+
warn_freespace_units = NULL;
crit_freespace_units = NULL;
- warn_usedspace_units = NULL;
- crit_usedspace_units = NULL;
warn_freespace_percent = NULL;
crit_freespace_percent = NULL;
- warn_usedspace_percent = NULL;
- crit_usedspace_percent = NULL;
- warn_usedinodes_percent = NULL;
- crit_usedinodes_percent = NULL;
warn_freeinodes_percent = NULL;
crit_freeinodes_percent = NULL;
path_selected = false;
group = NULL;
- break;
+ } break;
case 'V': /* version */
print_revision(progname, NP_VERSION);
exit(STATE_UNKNOWN);
@@ -858,50 +779,145 @@ int process_arguments(int argc, char **argv) {
exit(STATE_UNKNOWN);
case '?': /* help */
usage(_("Unknown argument"));
+ 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);
+ }
+
+ result.config.output_format_is_set = true;
+ result.config.output_format = parser.output_format;
+ break;
+ }
}
}
/* Support for "check_disk warn crit [fs]" with thresholds at used% level */
- c = optind;
- if (warn_usedspace_percent == NULL && argc > c && is_intnonneg(argv[c]))
- warn_usedspace_percent = argv[c++];
+ int index = optind;
- if (crit_usedspace_percent == NULL && argc > c && is_intnonneg(argv[c]))
- crit_usedspace_percent = argv[c++];
+ if (argc > index && is_intnonneg(argv[index])) {
+ if (verbose > 0) {
+ printf("Got an positional warn threshold: %s\n", argv[index]);
+ }
+ char *range = argv[index++];
+ mp_range_parsed tmp = mp_parse_range_string(range);
+ if (tmp.error != MP_PARSING_SUCCES) {
+ die(STATE_UNKNOWN, "failed to parse warning threshold");
+ }
- if (argc > c) {
- se = np_add_parameter(&path_select_list, strdup(argv[c++]));
+ mp_range tmp_range = tmp.range;
+ // Invert range to use it for free instead of used
+ // tmp_range.alert_on_inside_range = !tmp_range.alert_on_inside_range;
+
+ warn_freespace_percent = mp_range_to_string(tmp_range);
+
+ if (verbose > 0) {
+ printf("Positional warning threshold transformed to: %s\n", warn_freespace_percent);
+ }
+ }
+
+ if (argc > index && is_intnonneg(argv[index])) {
+ if (verbose > 0) {
+ printf("Got an positional crit threshold: %s\n", argv[index]);
+ }
+ char *range = argv[index++];
+ mp_range_parsed tmp = mp_parse_range_string(range);
+ if (tmp.error != MP_PARSING_SUCCES) {
+ die(STATE_UNKNOWN, "failed to parse warning threshold");
+ }
+
+ mp_range tmp_range = tmp.range;
+ // Invert range to use it for free instead of used
+ // tmp_range.alert_on_inside_range = !tmp_range.alert_on_inside_range;
+
+ crit_freespace_percent = mp_range_to_string(tmp_range);
+
+ if (verbose > 0) {
+ printf("Positional critical threshold transformed to: %s\n", crit_freespace_percent);
+ }
+ }
+
+ if (argc > index) {
+ if (verbose > 0) {
+ printf("Got an positional filesystem: %s\n", argv[index]);
+ }
+ struct parameter_list *se = mp_int_fs_list_append(&result.config.path_select_list, strdup(argv[index++]));
path_selected = true;
- set_all_thresholds(se);
+ set_all_thresholds(se, warn_freespace_units, crit_freespace_units, warn_freespace_percent, crit_freespace_percent,
+ warn_freeinodes_percent, crit_freeinodes_percent);
}
- if (units == NULL) {
- units = strdup("MiB");
- mult = (uintmax_t)1024 * 1024;
+ // If a list of paths has not been explicitly selected, find entire
+ // mount list and create list of paths
+ if (!path_selected && !result.config.path_ignored) {
+ for (struct mount_entry *me = result.config.mount_list; me; me = me->me_next) {
+ if (me->me_dummy != 0) {
+ // just do not add dummy filesystems
+ continue;
+ }
+
+ parameter_list_elem *path = NULL;
+ if (!(path = mp_int_fs_list_find(result.config.path_select_list, me->me_mountdir))) {
+ path = mp_int_fs_list_append(&result.config.path_select_list, me->me_mountdir);
+ }
+ path->best_match = me;
+ path->group = group;
+ set_all_thresholds(path, warn_freespace_units, crit_freespace_units, warn_freespace_percent, crit_freespace_percent,
+ warn_freeinodes_percent, crit_freeinodes_percent);
+ }
}
- return true;
+ // Set thresholds to the appropriate unit
+ for (parameter_list_elem *tmp = result.config.path_select_list.first; tmp; tmp = mp_int_fs_list_get_next(tmp)) {
+
+ mp_perfdata_value factor = mp_create_pd_value(unit);
+
+ if (tmp->freespace_units.critical_is_set) {
+ tmp->freespace_units.critical = mp_range_multiply(tmp->freespace_units.critical, factor);
+ }
+ if (tmp->freespace_units.warning_is_set) {
+ tmp->freespace_units.warning = mp_range_multiply(tmp->freespace_units.warning, factor);
+ }
+ }
+
+ return result;
}
-void set_all_thresholds(struct parameter_list *path) {
- if (path->freespace_units != NULL)
- free(path->freespace_units);
- set_thresholds(&path->freespace_units, warn_freespace_units, crit_freespace_units);
- if (path->freespace_percent != NULL)
- free(path->freespace_percent);
- set_thresholds(&path->freespace_percent, warn_freespace_percent, crit_freespace_percent);
- if (path->usedspace_units != NULL)
- free(path->usedspace_units);
- set_thresholds(&path->usedspace_units, warn_usedspace_units, crit_usedspace_units);
- if (path->usedspace_percent != NULL)
- free(path->usedspace_percent);
- set_thresholds(&path->usedspace_percent, warn_usedspace_percent, crit_usedspace_percent);
- if (path->usedinodes_percent != NULL)
- free(path->usedinodes_percent);
- set_thresholds(&path->usedinodes_percent, warn_usedinodes_percent, crit_usedinodes_percent);
- if (path->freeinodes_percent != NULL)
- free(path->freeinodes_percent);
- set_thresholds(&path->freeinodes_percent, warn_freeinodes_percent, crit_freeinodes_percent);
+void set_all_thresholds(parameter_list_elem *path, char *warn_freespace_units, char *crit_freespace_units, char *warn_freespace_percent,
+ char *crit_freespace_percent, char *warn_freeinodes_percent, char *crit_freeinodes_percent) {
+ mp_range_parsed tmp;
+
+ if (warn_freespace_units) {
+ tmp = mp_parse_range_string(warn_freespace_units);
+ path->freespace_units = mp_thresholds_set_warn(path->freespace_units, tmp.range);
+ }
+
+ if (crit_freespace_units) {
+ tmp = mp_parse_range_string(crit_freespace_units);
+ path->freespace_units = mp_thresholds_set_crit(path->freespace_units, tmp.range);
+ }
+
+ if (warn_freespace_percent) {
+ tmp = mp_parse_range_string(warn_freespace_percent);
+ path->freespace_percent = mp_thresholds_set_warn(path->freespace_percent, tmp.range);
+ }
+
+ if (crit_freespace_percent) {
+ tmp = mp_parse_range_string(crit_freespace_percent);
+ path->freespace_percent = mp_thresholds_set_crit(path->freespace_percent, tmp.range);
+ }
+
+ if (warn_freeinodes_percent) {
+ tmp = mp_parse_range_string(warn_freeinodes_percent);
+ path->freeinodes_percent = mp_thresholds_set_warn(path->freeinodes_percent, tmp.range);
+ }
+
+ if (crit_freeinodes_percent) {
+ tmp = mp_parse_range_string(crit_freeinodes_percent);
+ path->freeinodes_percent = mp_thresholds_set_crit(path->freeinodes_percent, tmp.range);
+ }
}
void print_help(void) {
@@ -948,8 +964,6 @@ void print_help(void) {
printf(" %s\n", _("Display inode usage in perfdata"));
printf(" %s\n", "-g, --group=NAME");
printf(" %s\n", _("Group paths. Thresholds apply to (free-)space of all partitions together"));
- printf(" %s\n", "-k, --kilobytes");
- printf(" %s\n", _("Same as '--units kB'"));
printf(" %s\n", "-l, --local");
printf(" %s\n", _("Only check local filesystems"));
printf(" %s\n", "-L, --stat-remote-fs");
@@ -957,8 +971,6 @@ void print_help(void) {
printf(" %s\n", _("to test if they are accessible (e.g. to detect Stale NFS Handles)"));
printf(" %s\n", "-M, --mountpoint");
printf(" %s\n", _("Display the (block) device instead of the mount point"));
- printf(" %s\n", "-m, --megabytes");
- printf(" %s\n", _("Same as '--units MB'"));
printf(" %s\n", "-A, --all");
printf(" %s\n", _("Explicitly select all paths. This is equivalent to -R '.*'"));
printf(" %s\n", "-R, --eregi-path=PATH, --eregi-partition=PARTITION");
@@ -974,12 +986,25 @@ void print_help(void) {
printf(" %s\n", _("(Provide this option before -p / -r / --ereg-path if used)"));
printf(UT_PLUG_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
printf(" %s\n", "-u, --units=STRING");
- printf(" %s\n", _("Choose bytes, kB, MB, GB, TB (default: MB)"));
+ printf(" %s\n", _("Select the unit used for the absolute value thresholds"));
+ printf(
+ " %s\n",
+ _("Choose one of \"bytes\", \"KiB\", \"kB\", \"MiB\", \"MB\", \"GiB\", \"GB\", \"TiB\", \"TB\", \"PiB\", \"PB\" (default: MiB)"));
+ printf(" %s\n", "-k, --kilobytes");
+ printf(" %s\n", _("Same as '--units kB'"));
+ printf(" %s\n", "--display-unit");
+ printf(" %s\n", _("Select the unit used for in the output"));
+ printf(
+ " %s\n",
+ _("Choose one of \"bytes\", \"KiB\", \"kB\", \"MiB\", \"MB\", \"GiB\", \"GB\", \"TiB\", \"TB\", \"PiB\", \"PB\" (default: MiB)"));
+ printf(" %s\n", "-m, --megabytes");
+ printf(" %s\n", _("Same as '--units MB'"));
printf(UT_VERBOSE);
printf(" %s\n", "-X, --exclude-type=TYPE_REGEX");
printf(" %s\n", _("Ignore all filesystems of types matching given regex(7) (may be repeated)"));
printf(" %s\n", "-N, --include-type=TYPE_REGEX");
printf(" %s\n", _("Check only filesystems where the type matches this given regex(7) (may be repeated)"));
+ printf(UT_OUTPUT_FORMAT);
printf("\n");
printf("%s\n", _("General usage hints:"));
@@ -1009,105 +1034,187 @@ void print_usage(void) {
printf("[-t timeout] [-u unit] [-v] [-X type_regex] [-N type]\n");
}
-bool stat_path(struct parameter_list *p) {
+bool stat_path(parameter_list_elem *parameters, bool ignore_missing) {
/* Stat entry to check that dir exists and is accessible */
- if (verbose >= 3)
- printf("calling stat on %s\n", p->name);
- if (stat(p->name, &stat_buf[0])) {
- if (verbose >= 3)
- printf("stat failed on %s\n", p->name);
- if (ignore_missing == true) {
+ if (verbose >= 3) {
+ printf("calling stat on %s\n", parameters->name);
+ }
+
+ struct stat stat_buf = {0};
+ if (stat(parameters->name, &stat_buf)) {
+ if (verbose >= 3) {
+ printf("stat failed on %s\n", parameters->name);
+ }
+ if (ignore_missing) {
return false;
}
printf("DISK %s - ", _("CRITICAL"));
- die(STATE_CRITICAL, _("%s %s: %s\n"), p->name, _("is not accessible"), strerror(errno));
+ die(STATE_CRITICAL, _("%s %s: %s\n"), parameters->name, _("is not accessible"), strerror(errno));
}
+
return true;
}
-void get_stats(struct parameter_list *p, struct fs_usage *fsp) {
- struct parameter_list *p_list;
- struct fs_usage tmpfsp;
- int first = 1;
+static parameter_list_elem get_path_stats(parameter_list_elem parameters, const struct fs_usage fsp, bool freespace_ignore_reserved) {
+ uintmax_t available = fsp.fsu_bavail;
+ uintmax_t available_to_root = fsp.fsu_bfree;
+ uintmax_t used = fsp.fsu_blocks - fsp.fsu_bfree;
+ uintmax_t total;
- if (p->group == NULL) {
- get_path_stats(p, fsp);
- } else {
- /* find all group members */
- for (p_list = path_select_list; p_list; p_list = p_list->name_next) {
-#ifdef __CYGWIN__
- if (strncmp(p_list->name, "/cygdrive/", 10) != 0)
- continue;
-#endif
- if (p_list->group && !(strcmp(p_list->group, p->group))) {
- if (!stat_path(p_list))
- continue;
- get_fs_usage(p_list->best_match->me_mountdir, p_list->best_match->me_devname, &tmpfsp);
- get_path_stats(p_list, &tmpfsp);
- if (verbose >= 3)
- printf("Group %s: adding %lu blocks sized %lu, (%s) used_units=%lu free_units=%lu total_units=%lu mult=%lu\n",
- p_list->group, tmpfsp.fsu_blocks, tmpfsp.fsu_blocksize, p_list->best_match->me_mountdir, p_list->dused_units,
- p_list->dfree_units, p_list->dtotal_units, mult);
-
- /* prevent counting the first FS of a group twice since its parameter_list entry
- * is used to carry the information of all file systems of the entire group */
- if (!first) {
- p->total += p_list->total;
- p->available += p_list->available;
- p->available_to_root += p_list->available_to_root;
- p->used += p_list->used;
-
- p->dused_units += p_list->dused_units;
- p->dfree_units += p_list->dfree_units;
- p->dtotal_units += p_list->dtotal_units;
- p->inodes_total += p_list->inodes_total;
- p->inodes_free += p_list->inodes_free;
- p->inodes_free_to_root += p_list->inodes_free_to_root;
- p->inodes_used += p_list->inodes_used;
- }
- first = 0;
- }
- if (verbose >= 3)
- printf("Group %s now has: used_units=%lu free_units=%lu total_units=%lu fsu_blocksize=%lu mult=%lu\n", p->group,
- p->dused_units, p->dfree_units, p->dtotal_units, tmpfsp.fsu_blocksize, mult);
- }
- /* modify devname and mountdir for output */
- p->best_match->me_mountdir = p->best_match->me_devname = p->group;
- }
- /* finally calculate percentages for either plain FS or summed up group */
- p->dused_pct = calculate_percent(p->used, p->used + p->available); /* used + available can never be > uintmax */
- p->dfree_pct = 100.0 - p->dused_pct;
- p->dused_inodes_percent = calculate_percent(p->inodes_total - p->inodes_free, p->inodes_total);
- p->dfree_inodes_percent = 100 - p->dused_inodes_percent;
-}
-
-void get_path_stats(struct parameter_list *p, struct fs_usage *fsp) {
- p->available = fsp->fsu_bavail;
- p->available_to_root = fsp->fsu_bfree;
- p->used = fsp->fsu_blocks - fsp->fsu_bfree;
if (freespace_ignore_reserved) {
/* option activated : we subtract the root-reserved space from the total */
- p->total = fsp->fsu_blocks - p->available_to_root + p->available;
+ total = fsp.fsu_blocks - available_to_root + available;
} else {
/* default behaviour : take all the blocks into account */
- p->total = fsp->fsu_blocks;
+ total = fsp.fsu_blocks;
}
- p->dused_units = p->used * fsp->fsu_blocksize / mult;
- p->dfree_units = p->available * fsp->fsu_blocksize / mult;
- p->dtotal_units = p->total * fsp->fsu_blocksize / mult;
+ parameters.used_bytes = used * fsp.fsu_blocksize;
+ parameters.free_bytes = available * fsp.fsu_blocksize;
+ parameters.total_bytes = total * fsp.fsu_blocksize;
+
/* Free file nodes. Not sure the workaround is required, but in case...*/
- p->inodes_free = fsp->fsu_ffree;
- p->inodes_free_to_root = fsp->fsu_ffree; /* Free file nodes for root. */
- p->inodes_used = fsp->fsu_files - fsp->fsu_ffree;
+ parameters.inodes_free = fsp.fsu_ffree;
+ parameters.inodes_free_to_root = fsp.fsu_ffree; /* Free file nodes for root. */
+ parameters.inodes_used = fsp.fsu_files - fsp.fsu_ffree;
+
if (freespace_ignore_reserved) {
/* option activated : we subtract the root-reserved inodes from the total */
/* not all OS report fsp->fsu_favail, only the ones with statvfs syscall */
/* for others, fsp->fsu_ffree == fsp->fsu_favail */
- p->inodes_total = fsp->fsu_files - p->inodes_free_to_root + p->inodes_free;
+ parameters.inodes_total = fsp.fsu_files - parameters.inodes_free_to_root + parameters.inodes_free;
} else {
/* default behaviour : take all the inodes into account */
- p->inodes_total = fsp->fsu_files;
+ parameters.inodes_total = fsp.fsu_files;
}
- np_add_name(&seen, p->best_match->me_mountdir);
+
+ return parameters;
+}
+
+mp_subcheck evaluate_filesystem(measurement_unit measurement_unit, bool display_inodes_perfdata, byte_unit unit) {
+ mp_subcheck result = mp_subcheck_init();
+ result = mp_set_subcheck_default_state(result, STATE_UNKNOWN);
+ xasprintf(&result.output, "%s", measurement_unit.name);
+
+ if (!measurement_unit.is_group && measurement_unit.filesystem_type) {
+ xasprintf(&result.output, "%s (%s)", result.output, measurement_unit.filesystem_type);
+ }
+
+ /* Threshold comparisons */
+
+ // ===============================
+ // Free space absolute values test
+ mp_subcheck freespace_bytes_sc = mp_subcheck_init();
+ freespace_bytes_sc = mp_set_subcheck_default_state(freespace_bytes_sc, STATE_OK);
+
+ if (unit != Humanized) {
+ xasprintf(&freespace_bytes_sc.output, "Free space absolute: %ju%s (of %ju%s)", (uintmax_t)(measurement_unit.free_bytes / unit),
+ get_unit_string(unit), (uintmax_t)(measurement_unit.total_bytes / unit), get_unit_string(unit));
+ } else {
+ xasprintf(&freespace_bytes_sc.output, "Free space absolute: %s (of %s)", humanize_byte_value(measurement_unit.free_bytes, false),
+ humanize_byte_value((unsigned long long)measurement_unit.total_bytes, false));
+ }
+
+ mp_perfdata used_space = perfdata_init();
+ used_space.label = measurement_unit.name;
+ used_space.value = mp_create_pd_value(measurement_unit.free_bytes);
+ used_space = mp_set_pd_max_value(used_space, mp_create_pd_value(measurement_unit.total_bytes));
+ used_space = mp_set_pd_min_value(used_space, mp_create_pd_value(0));
+ used_space.uom = "B";
+ used_space = mp_pd_set_thresholds(used_space, measurement_unit.freespace_bytes_thresholds);
+ freespace_bytes_sc = mp_set_subcheck_state(freespace_bytes_sc, mp_get_pd_status(used_space));
+
+ // special case for absolute space thresholds here:
+ // if absolute values are not set, compute the thresholds from percentage thresholds
+ mp_thresholds temp_thlds = measurement_unit.freespace_bytes_thresholds;
+ if (!temp_thlds.critical_is_set && measurement_unit.freespace_percent_thresholds.critical_is_set) {
+ mp_range tmp_range = measurement_unit.freespace_percent_thresholds.critical;
+
+ if (!tmp_range.end_infinity) {
+ tmp_range.end = mp_create_pd_value(mp_get_pd_value(tmp_range.end) / 100 * measurement_unit.total_bytes);
+ }
+
+ if (!tmp_range.start_infinity) {
+ tmp_range.start = mp_create_pd_value(mp_get_pd_value(tmp_range.start) / 100 * measurement_unit.total_bytes);
+ }
+ measurement_unit.freespace_bytes_thresholds = mp_thresholds_set_crit(measurement_unit.freespace_bytes_thresholds, tmp_range);
+ used_space = mp_pd_set_thresholds(used_space, measurement_unit.freespace_bytes_thresholds);
+ }
+
+ if (!temp_thlds.warning_is_set && measurement_unit.freespace_percent_thresholds.warning_is_set) {
+ mp_range tmp_range = measurement_unit.freespace_percent_thresholds.warning;
+ if (!tmp_range.end_infinity) {
+ tmp_range.end = mp_create_pd_value(mp_get_pd_value(tmp_range.end) / 100 * measurement_unit.total_bytes);
+ }
+ if (!tmp_range.start_infinity) {
+ tmp_range.start = mp_create_pd_value(mp_get_pd_value(tmp_range.start) / 100 * measurement_unit.total_bytes);
+ }
+ measurement_unit.freespace_bytes_thresholds = mp_thresholds_set_warn(measurement_unit.freespace_bytes_thresholds, tmp_range);
+ used_space = mp_pd_set_thresholds(used_space, measurement_unit.freespace_bytes_thresholds);
+ }
+
+ mp_add_perfdata_to_subcheck(&freespace_bytes_sc, used_space);
+ mp_add_subcheck_to_subcheck(&result, freespace_bytes_sc);
+
+ // ==========================
+ // Free space percentage test
+ mp_subcheck freespace_percent_sc = mp_subcheck_init();
+ freespace_percent_sc = mp_set_subcheck_default_state(freespace_percent_sc, STATE_OK);
+
+ double free_percentage = calculate_percent(measurement_unit.free_bytes, measurement_unit.total_bytes);
+ xasprintf(&freespace_percent_sc.output, "Free space percentage: %g%%", free_percentage);
+
+ // Using perfdata here just to get to the test result
+ mp_perfdata free_space_percent_pd = perfdata_init();
+ free_space_percent_pd.value = mp_create_pd_value(free_percentage);
+ free_space_percent_pd = mp_pd_set_thresholds(free_space_percent_pd, measurement_unit.freespace_percent_thresholds);
+
+ freespace_percent_sc = mp_set_subcheck_state(freespace_percent_sc, mp_get_pd_status(free_space_percent_pd));
+ mp_add_subcheck_to_subcheck(&result, freespace_percent_sc);
+
+ // ================
+ // Free inodes test
+ // Only ever useful if the number of inodes is static (e.g. ext4),
+ // not when it is dynamic (e.g btrfs)
+ // Assumption: if the total number of inodes == 0, we have such a case and just skip the test
+ if (measurement_unit.inodes_total > 0) {
+ mp_subcheck freeindodes_percent_sc = mp_subcheck_init();
+ freeindodes_percent_sc = mp_set_subcheck_default_state(freeindodes_percent_sc, STATE_OK);
+
+ double free_inode_percentage = calculate_percent(measurement_unit.inodes_free, measurement_unit.inodes_total);
+
+ if (verbose > 0) {
+ printf("free inode percentage computed: %g\n", free_inode_percentage);
+ }
+
+ xasprintf(&freeindodes_percent_sc.output, "Inodes free: %g%% (%ju of %ju)", free_inode_percentage, measurement_unit.inodes_free,
+ measurement_unit.inodes_total);
+
+ mp_perfdata inodes_pd = perfdata_init();
+ xasprintf(&inodes_pd.label, "%s (inodes)", measurement_unit.name);
+ inodes_pd = mp_set_pd_value(inodes_pd, measurement_unit.inodes_used);
+ inodes_pd = mp_set_pd_max_value(inodes_pd, mp_create_pd_value(measurement_unit.inodes_total));
+ inodes_pd = mp_set_pd_min_value(inodes_pd, mp_create_pd_value(0));
+
+ mp_thresholds absolut_inode_thresholds = measurement_unit.freeinodes_percent_thresholds;
+
+ if (absolut_inode_thresholds.critical_is_set) {
+ absolut_inode_thresholds.critical =
+ mp_range_multiply(absolut_inode_thresholds.critical, mp_create_pd_value(measurement_unit.inodes_total / 100));
+ }
+ if (absolut_inode_thresholds.warning_is_set) {
+ absolut_inode_thresholds.warning =
+ mp_range_multiply(absolut_inode_thresholds.warning, mp_create_pd_value(measurement_unit.inodes_total / 100));
+ }
+
+ inodes_pd = mp_pd_set_thresholds(inodes_pd, absolut_inode_thresholds);
+
+ freeindodes_percent_sc = mp_set_subcheck_state(freeindodes_percent_sc, mp_get_pd_status(inodes_pd));
+ if (display_inodes_perfdata) {
+ mp_add_perfdata_to_subcheck(&freeindodes_percent_sc, inodes_pd);
+ }
+ mp_add_subcheck_to_subcheck(&result, freeindodes_percent_sc);
+ }
+
+ return result;
}
diff --git a/plugins/check_disk.d/utils_disk.c b/plugins/check_disk.d/utils_disk.c
new file mode 100644
index 00000000..eec1282b
--- /dev/null
+++ b/plugins/check_disk.d/utils_disk.c
@@ -0,0 +1,517 @@
+/*****************************************************************************
+ *
+ * Library for check_disk
+ *
+ * License: GPL
+ * Copyright (c) 1999-2024 Monitoring Plugins Development Team
+ *
+ * Description:
+ *
+ * This file contains utilities for check_disk. These are tested by libtap
+ *
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ *
+ *****************************************************************************/
+
+#include "../common.h"
+#include "utils_disk.h"
+#include "../../gl/fsusage.h"
+#include "../../lib/thresholds.h"
+#include "../../lib/states.h"
+#include
+#include
+#include
+#include
+
+void np_add_name(struct name_list **list, const char *name) {
+ struct name_list *new_entry;
+ new_entry = (struct name_list *)malloc(sizeof *new_entry);
+ new_entry->name = (char *)name;
+ new_entry->next = *list;
+ *list = new_entry;
+}
+
+/* @brief Initialises a new regex at the begin of list via regcomp(3)
+ *
+ * @details if the regex fails to compile the error code of regcomp(3) is returned
+ * and list is not modified, otherwise list is modified to point to the new
+ * element
+ * @param list Pointer to a linked list of regex_list elements
+ * @param regex the string containing the regex which should be inserted into the list
+ * @param clags the cflags parameter for regcomp(3)
+ */
+int np_add_regex(struct regex_list **list, const char *regex, int cflags) {
+ struct regex_list *new_entry = (struct regex_list *)malloc(sizeof *new_entry);
+
+ if (new_entry == NULL) {
+ die(STATE_UNKNOWN, _("Cannot allocate memory: %s"), strerror(errno));
+ }
+
+ int regcomp_result = regcomp(&new_entry->regex, regex, cflags);
+
+ if (!regcomp_result) {
+ // regcomp succeeded
+ new_entry->next = *list;
+ *list = new_entry;
+
+ return 0;
+ }
+ // regcomp failed
+ free(new_entry);
+
+ return regcomp_result;
+}
+
+parameter_list_elem parameter_list_init(const char *name) {
+ parameter_list_elem result = {
+ .name = strdup(name),
+ .best_match = NULL,
+
+ .freespace_units = mp_thresholds_init(),
+ .freespace_percent = mp_thresholds_init(),
+ .freeinodes_percent = mp_thresholds_init(),
+
+ .group = NULL,
+
+ .inodes_total = 0,
+ .inodes_free = 0,
+ .inodes_free_to_root = 0,
+ .inodes_used = 0,
+
+ .used_bytes = 0,
+ .free_bytes = 0,
+ .total_bytes = 0,
+
+ .next = NULL,
+ .prev = NULL,
+ };
+ return result;
+}
+
+/* Returns true if name is in list */
+bool np_find_name(struct name_list *list, const char *name) {
+ if (list == NULL || name == NULL) {
+ return false;
+ }
+ for (struct name_list *iterator = list; iterator; iterator = iterator->next) {
+ if (!strcmp(name, iterator->name)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/* Returns true if name is in list */
+bool np_find_regmatch(struct regex_list *list, const char *name) {
+ if (name == NULL) {
+ return false;
+ }
+
+ size_t len = strlen(name);
+
+ for (; list; list = list->next) {
+ /* Emulate a full match as if surrounded with ^( )$
+ by checking whether the match spans the whole name */
+ regmatch_t dummy_match;
+ if (!regexec(&list->regex, name, 1, &dummy_match, 0) && dummy_match.rm_so == 0 && dummy_match.rm_eo == len) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool np_seen_name(struct name_list *list, const char *name) {
+ for (struct name_list *iterator = list; iterator; iterator = iterator->next) {
+ if (!strcmp(iterator->name, name)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool np_regex_match_mount_entry(struct mount_entry *me, regex_t *re) {
+ return ((regexec(re, me->me_devname, (size_t)0, NULL, 0) == 0) || (regexec(re, me->me_mountdir, (size_t)0, NULL, 0) == 0));
+}
+
+check_disk_config check_disk_config_init() {
+ check_disk_config tmp = {
+ .erronly = false,
+ .display_mntp = false,
+ .show_local_fs = false,
+ .stat_remote_fs = false,
+ .display_inodes_perfdata = false,
+
+ .exact_match = false,
+ .freespace_ignore_reserved = false,
+
+ .ignore_missing = false,
+ .path_ignored = false,
+
+ // FS Filters
+ .fs_exclude_list = NULL,
+ .fs_include_list = NULL,
+ .device_path_exclude_list = NULL,
+
+ // Actual filesystems paths to investigate
+ .path_select_list = filesystem_list_init(),
+
+ .mount_list = NULL,
+ .seen = NULL,
+
+ .display_unit = Humanized,
+ // .unit = MebiBytes,
+
+ .output_format_is_set = false,
+ };
+ return tmp;
+}
+
+char *get_unit_string(byte_unit_enum unit) {
+ switch (unit) {
+ case Bytes:
+ return "Bytes";
+ case KibiBytes:
+ return "KiB";
+ case MebiBytes:
+ return "MiB";
+ case GibiBytes:
+ return "GiB";
+ case TebiBytes:
+ return "TiB";
+ case PebiBytes:
+ return "PiB";
+ case ExbiBytes:
+ return "EiB";
+ case KiloBytes:
+ return "KB";
+ case MegaBytes:
+ return "MB";
+ case GigaBytes:
+ return "GB";
+ case TeraBytes:
+ return "TB";
+ case PetaBytes:
+ return "PB";
+ case ExaBytes:
+ return "EB";
+ default:
+ assert(false);
+ }
+}
+
+measurement_unit measurement_unit_init() {
+ measurement_unit tmp = {
+ .name = NULL,
+ .filesystem_type = NULL,
+ .is_group = false,
+
+ .freeinodes_percent_thresholds = mp_thresholds_init(),
+ .freespace_percent_thresholds = mp_thresholds_init(),
+ .freespace_bytes_thresholds = mp_thresholds_init(),
+
+ .free_bytes = 0,
+ .used_bytes = 0,
+ .total_bytes = 0,
+
+ .inodes_total = 0,
+ .inodes_free = 0,
+ .inodes_free_to_root = 0,
+ .inodes_used = 0,
+ };
+ return tmp;
+}
+
+// Add a given element to the list, memory for the new element is freshly allocated
+// Returns a pointer to new element
+measurement_unit_list *add_measurement_list(measurement_unit_list *list, measurement_unit elem) {
+ // find last element
+ measurement_unit_list *new = NULL;
+ if (list == NULL) {
+ new = calloc(1, sizeof(measurement_unit_list));
+ if (new == NULL) {
+ die(STATE_UNKNOWN, _("allocation failed"));
+ }
+ } else {
+ measurement_unit_list *list_elem = list;
+ while (list_elem->next != NULL) {
+ list_elem = list_elem->next;
+ }
+
+ new = calloc(1, sizeof(measurement_unit_list));
+ if (new == NULL) {
+ die(STATE_UNKNOWN, _("allocation failed"));
+ }
+
+ list_elem->next = new;
+ }
+
+ new->unit = elem;
+ new->next = NULL;
+ return new;
+}
+
+measurement_unit add_filesystem_to_measurement_unit(measurement_unit unit, parameter_list_elem filesystem) {
+
+ unit.free_bytes += filesystem.free_bytes;
+ unit.used_bytes += filesystem.used_bytes;
+ unit.total_bytes += filesystem.total_bytes;
+
+ unit.inodes_total += filesystem.inodes_total;
+ unit.inodes_free += filesystem.inodes_free;
+ unit.inodes_free_to_root += filesystem.inodes_free_to_root;
+ unit.inodes_used += filesystem.inodes_used;
+ return unit;
+}
+
+measurement_unit create_measurement_unit_from_filesystem(parameter_list_elem filesystem, bool display_mntp) {
+ measurement_unit result = measurement_unit_init();
+ if (!display_mntp) {
+ result.name = strdup(filesystem.best_match->me_mountdir);
+ } else {
+ result.name = strdup(filesystem.best_match->me_devname);
+ }
+
+ if (filesystem.group) {
+ result.is_group = true;
+ } else {
+ result.is_group = false;
+ if (filesystem.best_match) {
+ result.filesystem_type = filesystem.best_match->me_type;
+ }
+ }
+
+ result.freeinodes_percent_thresholds = filesystem.freeinodes_percent;
+ result.freespace_percent_thresholds = filesystem.freespace_percent;
+ result.freespace_bytes_thresholds = filesystem.freespace_units;
+ result.free_bytes = filesystem.free_bytes;
+ result.total_bytes = filesystem.total_bytes;
+ result.used_bytes = filesystem.used_bytes;
+ result.inodes_total = filesystem.inodes_total;
+ result.inodes_used = filesystem.inodes_used;
+ result.inodes_free = filesystem.inodes_free;
+ result.inodes_free_to_root = filesystem.inodes_free_to_root;
+ return result;
+}
+
+#define RANDOM_STRING_LENGTH 64
+
+char *humanize_byte_value(unsigned long long value, bool use_si_units) {
+ // Idea: A reasonable output should have at most 3 orders of magnitude
+ // before the decimal separator
+ // 353GiB is ok, 2444 GiB should be 2.386 TiB
+ char *result = calloc(RANDOM_STRING_LENGTH, sizeof(char));
+ if (result == NULL) {
+ die(STATE_UNKNOWN, _("allocation failed"));
+ }
+ const byte_unit KibiBytes_factor = 1024;
+ const byte_unit MebiBytes_factor = 1048576;
+ const byte_unit GibiBytes_factor = 1073741824;
+ const byte_unit TebiBytes_factor = 1099511627776;
+ const byte_unit PebiBytes_factor = 1125899906842624;
+ const byte_unit ExbiBytes_factor = 1152921504606846976;
+ const byte_unit KiloBytes_factor = 1000;
+ const byte_unit MegaBytes_factor = 1000000;
+ const byte_unit GigaBytes_factor = 1000000000;
+ const byte_unit TeraBytes_factor = 1000000000000;
+ const byte_unit PetaBytes_factor = 1000000000000000;
+ const byte_unit ExaBytes_factor = 1000000000000000000;
+
+ if (use_si_units) {
+ // SI units, powers of 10
+ if (value < KiloBytes_factor) {
+ snprintf(result, RANDOM_STRING_LENGTH, "%llu B", value);
+ } else if (value < MegaBytes_factor) {
+ snprintf(result, RANDOM_STRING_LENGTH, "%llu KB", value / KiloBytes_factor);
+ } else if (value < GigaBytes_factor) {
+ snprintf(result, RANDOM_STRING_LENGTH, "%llu MB", value / MegaBytes_factor);
+ } else if (value < TeraBytes_factor) {
+ snprintf(result, RANDOM_STRING_LENGTH, "%llu GB", value / GigaBytes_factor);
+ } else if (value < PetaBytes_factor) {
+ snprintf(result, RANDOM_STRING_LENGTH, "%llu TB", value / TeraBytes_factor);
+ } else if (value < ExaBytes_factor) {
+ snprintf(result, RANDOM_STRING_LENGTH, "%llu PB", value / PetaBytes_factor);
+ } else {
+ snprintf(result, RANDOM_STRING_LENGTH, "%llu EB", value / ExaBytes_factor);
+ }
+ } else {
+ // IEC units, powers of 2 ^ 10
+ if (value < KibiBytes_factor) {
+ snprintf(result, RANDOM_STRING_LENGTH, "%llu B", value);
+ } else if (value < MebiBytes_factor) {
+ snprintf(result, RANDOM_STRING_LENGTH, "%llu KiB", value / KibiBytes_factor);
+ } else if (value < GibiBytes_factor) {
+ snprintf(result, RANDOM_STRING_LENGTH, "%llu MiB", value / MebiBytes_factor);
+ } else if (value < TebiBytes_factor) {
+ snprintf(result, RANDOM_STRING_LENGTH, "%llu GiB", value / GibiBytes_factor);
+ } else if (value < PebiBytes_factor) {
+ snprintf(result, RANDOM_STRING_LENGTH, "%llu TiB", value / TebiBytes_factor);
+ } else if (value < ExbiBytes_factor) {
+ snprintf(result, RANDOM_STRING_LENGTH, "%llu PiB", value / PebiBytes_factor);
+ } else {
+ snprintf(result, RANDOM_STRING_LENGTH, "%llu EiB", value / ExbiBytes_factor);
+ }
+ }
+
+ return result;
+}
+
+filesystem_list filesystem_list_init() {
+ filesystem_list tmp = {
+ .length = 0,
+ .first = NULL,
+ };
+ return tmp;
+}
+
+parameter_list_elem *mp_int_fs_list_append(filesystem_list *list, const char *name) {
+ parameter_list_elem *current = list->first;
+ parameter_list_elem *new_path = (struct parameter_list *)malloc(sizeof *new_path);
+ *new_path = parameter_list_init(name);
+
+ if (current == NULL) {
+ list->first = new_path;
+ new_path->prev = NULL;
+ list->length = 1;
+ } else {
+ while (current->next) {
+ current = current->next;
+ }
+ current->next = new_path;
+ new_path->prev = current;
+ list->length++;
+ }
+ return new_path;
+}
+
+parameter_list_elem *mp_int_fs_list_find(filesystem_list list, const char *name) {
+ if (list.length == 0) {
+ return NULL;
+ }
+
+ for (parameter_list_elem *temp_list = list.first; temp_list; temp_list = temp_list->next) {
+ if (!strcmp(temp_list->name, name)) {
+ return temp_list;
+ }
+ }
+
+ return NULL;
+}
+
+parameter_list_elem *mp_int_fs_list_del(filesystem_list *list, parameter_list_elem *item) {
+ if (list->length == 0) {
+ return NULL;
+ }
+
+ if (item == NULL) {
+ // Got NULL for item, interpret this as "delete first element"
+ // as a kind of compatibility to the old function
+ item = list->first;
+ }
+
+ if (list->first == item) {
+ list->length--;
+
+ list->first = item->next;
+ if (list->first) {
+ list->first->prev = NULL;
+ }
+ return list->first;
+ }
+
+ // Was not the first element, continue
+ parameter_list_elem *prev = list->first;
+ parameter_list_elem *current = list->first->next;
+
+ while (current != item && current != NULL) {
+ prev = current;
+ current = current->next;
+ }
+
+ if (current == NULL) {
+ // didn't find that element ....
+ return NULL;
+ }
+
+ // remove the element
+ parameter_list_elem *next = current->next;
+ prev->next = next;
+ list->length--;
+ if (next) {
+ next->prev = prev;
+ }
+
+ if (item->name) {
+ free(item->name);
+ }
+ free(item);
+
+ return next;
+}
+
+parameter_list_elem *mp_int_fs_list_get_next(parameter_list_elem *current) {
+ if (!current) {
+ return NULL;
+ }
+ return current->next;
+}
+
+void mp_int_fs_list_set_best_match(filesystem_list list, struct mount_entry *mount_list, bool exact) {
+ for (parameter_list_elem *elem = list.first; elem; elem = mp_int_fs_list_get_next(elem)) {
+ if (!elem->best_match) {
+ size_t name_len = strlen(elem->name);
+ struct mount_entry *best_match = NULL;
+
+ /* set best match if path name exactly matches a mounted device name */
+ for (struct mount_entry *mount_entry = mount_list; mount_entry; mount_entry = mount_entry->me_next) {
+ if (strcmp(mount_entry->me_devname, elem->name) == 0) {
+ struct fs_usage fsp;
+ if (get_fs_usage(mount_entry->me_mountdir, mount_entry->me_devname, &fsp) >= 0) {
+ best_match = mount_entry;
+ }
+ }
+ }
+
+ /* set best match by directory name if no match was found by devname */
+ if (!best_match) {
+ size_t best_match_len = 0;
+ for (struct mount_entry *mount_entry = mount_list; mount_entry; mount_entry = mount_entry->me_next) {
+ size_t len = strlen(mount_entry->me_mountdir);
+
+ if ((!exact && (best_match_len <= len && len <= name_len &&
+ (len == 1 || strncmp(mount_entry->me_mountdir, elem->name, len) == 0))) ||
+ (exact && strcmp(mount_entry->me_mountdir, elem->name) == 0)) {
+ struct fs_usage fsp;
+
+ if (get_fs_usage(mount_entry->me_mountdir, mount_entry->me_devname, &fsp) >= 0) {
+ best_match = mount_entry;
+ best_match_len = len;
+ }
+ }
+ }
+ }
+
+ if (best_match) {
+ elem->best_match = best_match;
+ } else {
+ elem->best_match = NULL; /* Not sure why this is needed as it should be null on initialisation */
+ }
+
+ // No filesystem without a mount_entry!
+ // assert(elem->best_match != NULL);
+ }
+ }
+}
diff --git a/plugins/check_disk.d/utils_disk.h b/plugins/check_disk.d/utils_disk.h
new file mode 100644
index 00000000..6831d1fd
--- /dev/null
+++ b/plugins/check_disk.d/utils_disk.h
@@ -0,0 +1,157 @@
+#pragma once
+/* Header file for utils_disk */
+
+#include "../../config.h"
+#include "../../gl/mountlist.h"
+#include "../../lib/utils_base.h"
+#include "../../lib/output.h"
+#include "regex.h"
+#include
+
+typedef unsigned long long byte_unit;
+
+typedef enum {
+ Humanized,
+ Bytes,
+ KibiBytes,
+ MebiBytes,
+ GibiBytes,
+ TebiBytes,
+ PebiBytes,
+ ExbiBytes,
+ KiloBytes,
+ MegaBytes,
+ GigaBytes,
+ TeraBytes,
+ PetaBytes,
+ ExaBytes,
+} byte_unit_enum;
+
+typedef struct name_list string_list;
+struct name_list {
+ char *name;
+ string_list *next;
+};
+
+struct regex_list {
+ regex_t regex;
+ struct regex_list *next;
+};
+
+typedef struct parameter_list parameter_list_elem;
+struct parameter_list {
+ char *name;
+ char *group;
+
+ mp_thresholds freespace_units;
+ mp_thresholds freespace_percent;
+ mp_thresholds freeinodes_percent;
+
+ struct mount_entry *best_match;
+
+ uintmax_t inodes_free_to_root;
+ uintmax_t inodes_free;
+ uintmax_t inodes_used;
+ uintmax_t inodes_total;
+
+ uint64_t used_bytes;
+ uint64_t free_bytes;
+ uint64_t total_bytes;
+
+ parameter_list_elem *next;
+ parameter_list_elem *prev;
+};
+
+typedef struct {
+ size_t length;
+ parameter_list_elem *first;
+} filesystem_list;
+
+filesystem_list filesystem_list_init();
+
+typedef struct {
+ char *name;
+ char *filesystem_type;
+ bool is_group;
+
+ mp_thresholds freespace_bytes_thresholds;
+ mp_thresholds freespace_percent_thresholds;
+ mp_thresholds freeinodes_percent_thresholds;
+
+ uintmax_t inodes_free_to_root;
+ uintmax_t inodes_free;
+ uintmax_t inodes_used;
+ uintmax_t inodes_total;
+
+ uintmax_t used_bytes;
+ uintmax_t free_bytes;
+ uintmax_t total_bytes;
+} measurement_unit;
+
+typedef struct measurement_unit_list measurement_unit_list;
+struct measurement_unit_list {
+ measurement_unit unit;
+ measurement_unit_list *next;
+};
+
+typedef struct {
+ // Output options
+ bool erronly;
+ bool display_mntp;
+ /* show only local filesystems. */
+ bool show_local_fs;
+ /* show only local filesystems but call stat() on remote ones. */
+ bool stat_remote_fs;
+ bool display_inodes_perfdata;
+
+ bool exact_match;
+ bool freespace_ignore_reserved;
+
+ bool ignore_missing;
+ bool path_ignored;
+
+ /* Linked list of filesystem types to omit.
+ If the list is empty, don't exclude any types. */
+ struct regex_list *fs_exclude_list;
+ /* Linked list of filesystem types to check.
+ If the list is empty, include all types. */
+ struct regex_list *fs_include_list;
+ struct name_list *device_path_exclude_list;
+ filesystem_list path_select_list;
+ /* Linked list of mounted filesystems. */
+ struct mount_entry *mount_list;
+ struct name_list *seen;
+
+ byte_unit_enum display_unit;
+ // byte_unit unit;
+
+ bool output_format_is_set;
+ mp_output_format output_format;
+} check_disk_config;
+
+void np_add_name(struct name_list **list, const char *name);
+bool np_find_name(struct name_list *list, const char *name);
+bool np_seen_name(struct name_list *list, const char *name);
+int np_add_regex(struct regex_list **list, const char *regex, int cflags);
+bool np_find_regmatch(struct regex_list *list, const char *name);
+
+parameter_list_elem parameter_list_init(const char *);
+
+parameter_list_elem *mp_int_fs_list_append(filesystem_list *list, const char *name);
+parameter_list_elem *mp_int_fs_list_find(filesystem_list list, const char *name);
+parameter_list_elem *mp_int_fs_list_del(filesystem_list *list, parameter_list_elem *item);
+parameter_list_elem *mp_int_fs_list_get_next(parameter_list_elem *current);
+void mp_int_fs_list_set_best_match(filesystem_list list, struct mount_entry *mount_list, bool exact);
+
+measurement_unit measurement_unit_init();
+measurement_unit_list *add_measurement_list(measurement_unit_list *list, measurement_unit elem);
+measurement_unit add_filesystem_to_measurement_unit(measurement_unit unit, parameter_list_elem filesystem);
+measurement_unit create_measurement_unit_from_filesystem(parameter_list_elem filesystem, bool display_mntp);
+
+int search_parameter_list(parameter_list_elem *list, const char *name);
+bool np_regex_match_mount_entry(struct mount_entry *, regex_t *);
+
+char *get_unit_string(byte_unit_enum);
+check_disk_config check_disk_config_init();
+
+char *humanize_byte_value(unsigned long long value, bool use_si_units);
diff --git a/plugins/common.h b/plugins/common.h
index 603bae55..35d1e549 100644
--- a/plugins/common.h
+++ b/plugins/common.h
@@ -31,7 +31,7 @@
#ifndef _COMMON_H_
#define _COMMON_H_
-#include "config.h"
+#include "../config.h"
#include "../lib/monitoringplug.h"
#ifdef HAVE_FEATURES_H
@@ -110,7 +110,7 @@
/* GNU Libraries */
#include
-#include "dirname.h"
+#include "../gl/dirname.h"
#include
@@ -190,7 +190,7 @@ enum {
* Internationalization
*
*/
-#include "gettext.h"
+#include "../gl/gettext.h"
#define _(String) gettext (String)
#if ! ENABLE_NLS
# undef textdomain
diff --git a/plugins/t/check_disk.t b/plugins/t/check_disk.t
index 9eb77ce4..0f62fb2b 100644
--- a/plugins/t/check_disk.t
+++ b/plugins/t/check_disk.t
@@ -10,6 +10,7 @@ use strict;
use Test::More;
use NPTest;
use POSIX qw(ceil floor);
+use Data::Dumper;
my $successOutput = '/^DISK OK/';
my $failureOutput = '/^DISK CRITICAL/';
@@ -20,173 +21,216 @@ my $result;
my $mountpoint_valid = getTestParameter( "NP_MOUNTPOINT_VALID", "Path to valid mountpoint", "/");
my $mountpoint2_valid = getTestParameter( "NP_MOUNTPOINT2_VALID", "Path to another valid mountpoint. Must be different from 1st one", "/var");
+my $output_format = "--output-format mp-test-json";
+
if ($mountpoint_valid eq "" or $mountpoint2_valid eq "") {
plan skip_all => "Need 2 mountpoints to test";
} else {
- plan tests => 94;
+ plan tests => 97;
}
$result = NPTest->testCmd(
- "./check_disk -w 1% -c 1% -p $mountpoint_valid -w 1% -c 1% -p $mountpoint2_valid"
+ "./check_disk -w 1% -c 1% -p $mountpoint_valid -w 1% -c 1% -P -p $mountpoint2_valid $output_format"
);
cmp_ok( $result->return_code, "==", 0, "Checking two mountpoints (must have at least 1% free in space and inodes)");
-my $c = 0;
-$_ = $result->output;
-$c++ while /\(/g; # counts number of "(" - should be two
-cmp_ok( $c, '==', 2, "Got two mountpoints in output");
+like($result->{'mp_test_result'}->{'state'}, "/OK/", "Main result is OK");
+like($result->{'mp_test_result'}->{'checks'}->[0]->{'state'}, "/OK/", "First sub result is OK");
+like($result->{'mp_test_result'}->{'checks'}->[1]->{'state'}, "/OK/", "Second sub result is OK");
-# Get perf data
-# Should use Monitoring::Plugin
-my @perf_data = sort(split(/ /, $result->perf_output));
+my $absolut_space_mp1 = $result->{'mp_test_result'}->{'checks'}->[1]->{'checks'}->[0]->{'perfdata'}->[0]->{'max'}->{'value'};
+# print("absolute space on mp1: ". $absolut_space_mp1 . "\n");
+my $free_percent_on_mp1 = ($result->{'mp_test_result'}->{'checks'}->[1]->{'checks'}->[0]->{'perfdata'}->[0]->{'value'}->{'value'} / ($absolut_space_mp1/100));
+print("free percent on mp1: ". $free_percent_on_mp1 . "\n");
+
+my $absolut_space_mp2 = $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}->[0]->{'perfdata'}->[0]->{'max'}->{'value'};
+# print("absolute space on mp2: ". $absolut_space_mp2 . "\n");
+
+my $free_percent_on_mp2 = ($result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}->[0]->{'perfdata'}->[0]->{'value'}->{'value'}/ ($absolut_space_mp2/100));
+print("free percent on mp2: ". $free_percent_on_mp2 . "\n");
+
+my @perfdata;
+@perfdata[0] = $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}->[0]->{'perfdata'}->[0];
+@perfdata[1] = $result->{'mp_test_result'}->{'checks'}->[1]->{'checks'}->[0]->{'perfdata'}->[0];
+
+# Decrease precision of numbers since the the fs might be modified between the two runs
+$perfdata[0]->{'value'}->{'value'} = int($perfdata[0]->{'value'}->{'value'} / 1000000);
+$perfdata[1]->{'value'}->{'value'} = int($perfdata[1]->{'value'}->{'value'} / 1000000);
# Calculate avg_free free on mountpoint1 and mountpoint2
# because if you check in the middle, you should get different errors
-$_ = $result->output;
-my ($free_on_mp1, $free_on_mp2) = (m/\((\d+\.\d+)%.*\((\d+\.\d+)%/);
-die "Cannot parse output: $_" unless ($free_on_mp1 && $free_on_mp2);
-my $avg_free = ceil(($free_on_mp1+$free_on_mp2)/2);
+my $avg_free_percent = ceil(($free_percent_on_mp1+$free_percent_on_mp2)/2);
+# print("avg_free: " . $avg_free_percent . "\n");
my ($more_free, $less_free);
-if ($free_on_mp1 > $free_on_mp2) {
+if ($free_percent_on_mp1 > $free_percent_on_mp2) {
$more_free = $mountpoint_valid;
$less_free = $mountpoint2_valid;
-} elsif ($free_on_mp1 < $free_on_mp2) {
+} elsif ($free_percent_on_mp1 < $free_percent_on_mp2) {
$more_free = $mountpoint2_valid;
$less_free = $mountpoint_valid;
} else {
die "Two mountpoints are the same - cannot do rest of test";
}
-if($free_on_mp1 == $avg_free || $free_on_mp2 == $avg_free) {
+
+print("less free: " . $less_free . "\n");
+print("more free: " . $more_free . "\n");
+
+if($free_percent_on_mp1 == $avg_free_percent || $free_percent_on_mp2 == $avg_free_percent) {
die "One mountpoints has average space free - cannot do rest of test";
}
+my $free_inodes_on_mp1 = $result->{'mp_test_result'}->{'checks'}->[1]->{'checks'}[2]->{'perfdata'}->[0]->{'value'}->{'value'};
+my $total_inodes_on_mp1 = $result->{'mp_test_result'}->{'checks'}->[1]->{'checks'}[2]->{'perfdata'}->[0]->{'max'}->{'value'};
+my $free_inode_percentage_on_mp1 = $free_inodes_on_mp1 / ($total_inodes_on_mp1 / 100);
-# Do same for inodes
-$_ = $result->output;
-my ($free_inode_on_mp1, $free_inode_on_mp2) = (m/inode=(\d+)%.*inode=(\d+)%/);
-die "Cannot parse free inodes: $_" unless ($free_inode_on_mp1 && $free_inode_on_mp2);
-my $avg_inode_free = ceil(($free_inode_on_mp1 + $free_inode_on_mp2)/2);
+my $free_inodes_on_mp2 = $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}[2]->{'perfdata'}->[0]->{'value'}->{'value'};
+my $total_inodes_on_mp2 = $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}[2]->{'perfdata'}->[0]->{'max'}->{'value'};
+my $free_inode_percentage_on_mp2 = $free_inodes_on_mp2 / ($total_inodes_on_mp2 / 100);
+
+my $avg_inode_free_percentage = ceil(($free_inode_percentage_on_mp1 + $free_inode_percentage_on_mp2)/2);
my ($more_inode_free, $less_inode_free);
-if ($free_inode_on_mp1 > $free_inode_on_mp2) {
+if ($free_inode_percentage_on_mp1 > $free_inode_percentage_on_mp2) {
$more_inode_free = $mountpoint_valid;
$less_inode_free = $mountpoint2_valid;
-} elsif ($free_inode_on_mp1 < $free_inode_on_mp2) {
+} elsif ($free_inode_percentage_on_mp1 < $free_inode_percentage_on_mp2) {
$more_inode_free = $mountpoint2_valid;
$less_inode_free = $mountpoint_valid;
} else {
die "Two mountpoints with same inodes free - cannot do rest of test";
}
-if($free_inode_on_mp1 == $avg_inode_free || $free_inode_on_mp2 == $avg_inode_free) {
+if($free_inode_percentage_on_mp1 == $avg_inode_free_percentage || $free_inode_percentage_on_mp2 == $avg_inode_free_percentage) {
die "One mountpoints has average inodes free - cannot do rest of test";
}
# Verify performance data
# First check absolute thresholds...
$result = NPTest->testCmd(
- "./check_disk -w 20 -c 10 -p $mountpoint_valid"
+ "./check_disk -w 20 -c 10 -p $mountpoint_valid $output_format"
);
-$_ = $result->perf_output;
-my ($warn_absth_data, $crit_absth_data, $total_absth_data) = (m/=.[^;]*;(\d+);(\d+);\d+;(\d+)/);
-# default unit is MiB, but perfdata is always bytes
-is ($warn_absth_data, $total_absth_data - (20 * (2 ** 20)), "Wrong warning in perf data using absolute thresholds");
-is ($crit_absth_data, $total_absth_data - (10 * (2 ** 20)), "Wrong critical in perf data using absolute thresholds");
+
+cmp_ok( $result->return_code, "==", 0, "with JSON test format result should always be OK");
+
+my $warn_absth_data = $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}[0]->{'perfdata'}->[0]->{'warn'}->{'end'}->{'value'};
+my $crit_absth_data = $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}[0]->{'perfdata'}->[0]->{'crit'}->{'end'}->{'value'};
+my $total_absth_data= $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}[0]->{'perfdata'}->[0]->{'max'}->{'value'};
+
+# print("warn: " .$warn_absth_data . "\n");
+# print("crit: " .$crit_absth_data . "\n");
+# print("total: " .$total_absth_data . "\n");
+
+is ($warn_absth_data <=> (20 * (2 ** 20)), 0, "Wrong warning in perf data using absolute thresholds");
+is ($crit_absth_data <=> (10 * (2 ** 20)), 0, "Wrong critical in perf data using absolute thresholds");
# Then check percent thresholds.
$result = NPTest->testCmd(
- "./check_disk -w 20% -c 10% -p $mountpoint_valid"
+ "./check_disk -w 20% -c 10% -p $mountpoint_valid $output_format"
);
-$_ = $result->perf_output;
-my ($warn_percth_data, $crit_percth_data, $total_percth_data) = (m/=.[^;]*;(\d+);(\d+);\d+;(\d+)/);
-is ($warn_percth_data, int((1-20/100)*$total_percth_data), "Wrong warning in perf data using percent thresholds");
-is ($crit_percth_data, int((1-10/100)*$total_percth_data), "Wrong critical in perf data using percent thresholds");
+
+cmp_ok( $result->return_code, "==", 0, "with JSON test format result should always be OK");
+
+my $warn_percth_data = $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}[0]->{'perfdata'}->[0]->{'warn'}->{'end'}->{'value'};
+my $crit_percth_data = $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}[0]->{'perfdata'}->[0]->{'crit'}->{'end'}->{'value'};
+my $total_percth_data = $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}[0]->{'perfdata'}->[0]->{'max'}->{'value'};
+
+print("warn_percth_data: " . $warn_percth_data . "\n");
+print("crit_percth_data: " . $crit_percth_data . "\n");
+
+is (int($warn_percth_data), int((20/100)*$total_percth_data), "Wrong warning in perf data using percent thresholds. Got " . $warn_percth_data . " with total " . $total_percth_data);
+is (int($crit_percth_data), int((10/100)*$total_percth_data), "Wrong critical in perf data using percent thresholds. Got " . $crit_percth_data . " with total " . $total_percth_data);
# Check when order of mount points are reversed, that perf data remains same
$result = NPTest->testCmd(
- "./check_disk -w 1% -c 1% -p $mountpoint2_valid -w 1% -c 1% -p $mountpoint_valid"
+ "./check_disk -w 1% -c 1% -p $mountpoint2_valid -w 1% -c 1% -p $mountpoint_valid $output_format"
);
-@_ = sort(split(/ /, $result->perf_output));
-is_deeply( \@perf_data, \@_, "perf data for both filesystems same when reversed");
+cmp_ok( $result->return_code, "==", 0, "with JSON test format result should always be OK");
+# write comparison set for perfdata here, but in reversed order, maybe there is a smarter way
+my @perfdata2;
+@perfdata2[0] = $result->{'mp_test_result'}->{'checks'}->[1]->{'checks'}->[0]->{'perfdata'}->[0];
+@perfdata2[1] = $result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}->[0]->{'perfdata'}->[0];
+# Decrease precision of numbers since the the fs might be modified between the two runs
+$perfdata2[0]->{'value'}->{'value'} = int($perfdata2[0]->{'value'}->{'value'} / 1000000);
+$perfdata2[1]->{'value'}->{'value'} = int($perfdata2[1]->{'value'}->{'value'} / 1000000);
+is_deeply(\@perfdata, \@perfdata2, "perf data for both filesystems same when reversed");
# Basic filesystem checks for sizes
-$result = NPTest->testCmd( "./check_disk -w 1 -c 1 -p $more_free" );
-cmp_ok( $result->return_code, '==', 0, "At least 1 MB available on $more_free");
-like ( $result->output, $successOutput, "OK output" );
-like ( $result->only_output, qr/free space/, "Have free space text");
-like ( $result->only_output, qr/$more_free/, "Have disk name in text");
+$result = NPTest->testCmd( "./check_disk -w 1 -c 1 -p $more_free $output_format");
+cmp_ok( $result->return_code, "==", 0, "with JSON test format result should always be OK");
+like($result->{'mp_test_result'}->{'state'}, "/OK/", "At least 1 MB available on $more_free");
-$result = NPTest->testCmd( "./check_disk -w 1 -c 1 -p $more_free -p $less_free" );
-cmp_ok( $result->return_code, '==', 0, "At least 1 MB available on $more_free and $less_free");
+$result = NPTest->testCmd( "./check_disk -w 1 -c 1 -p $more_free -p $less_free $output_format" );
+cmp_ok( $result->return_code, "==", 0, "with JSON test format result should always be OK");
+like($result->{'mp_test_result'}->{'state'}, "/OK/", "At least 1 MB available on $more_free and $less_free");
-$_ = $result->output;
-
-my ($free_mb_on_mp1, $free_mb_on_mp2) = (m/(\d+)MiB .* (\d+)MiB /g);
+my $free_mb_on_mp1 =$result->{'mp_test_result'}->{'checks'}->[0]->{'checks'}->[0]->{'perfdata'}->[0]->{'value'}->{'value'} / (1024 * 1024);
+my $free_mb_on_mp2 = $result->{'mp_test_result'}->{'checks'}->[1]->{'checks'}->[0]->{'perfdata'}->[0]->{'value'}->{'value'}/ (1024 * 1024);
die "Cannot parse output: $_" unless ($free_mb_on_mp1 && $free_mb_on_mp2);
my $free_mb_on_all = $free_mb_on_mp1 + $free_mb_on_mp2;
+$result = NPTest->testCmd( "./check_disk -e -w 1 -c 1 -p $more_free $output_format" );
+cmp_ok( $result->return_code, "==", 0, "with JSON test format result should always be OK");
-$result = NPTest->testCmd( "./check_disk -e -w 1 -c 1 -p $more_free" );
-is( $result->only_output, "DISK OK", "No print out of disks with -e for OKs");
-
-$result = NPTest->testCmd( "./check_disk 100 100 $more_free" );
-cmp_ok( $result->return_code, '==', 0, "Old syntax okay" );
+$result = NPTest->testCmd( "./check_disk 101 101 $more_free" );
+like($result->output, "/OK/", "OK in Output");
+cmp_ok( $result->return_code, '==', 0, "Old syntax okay, output was: ". $result->output . "\n" );
$result = NPTest->testCmd( "./check_disk -w 1% -c 1% -p $more_free" );
cmp_ok( $result->return_code, "==", 0, "At least 1% free" );
$result = NPTest->testCmd(
- "./check_disk -w 1% -c 1% -p $more_free -w 100% -c 100% -p $less_free"
+ "./check_disk -w 1% -c 1% -p $more_free -w 100% -c 100% -p $less_free $output_format"
);
-cmp_ok( $result->return_code, "==", 2, "Get critical on less_free mountpoint $less_free" );
-like( $result->output, $failureOutput, "Right output" );
+cmp_ok( $result->return_code, "==", 0, "with JSON test format result should always be OK");
+like($result->{'mp_test_result'}->{'state'}, "/CRITICAL/", "Get critical on less_free mountpoint $less_free");
$result = NPTest->testCmd(
- "./check_disk -w $avg_free% -c 0% -p $less_free"
+ "./check_disk -w $avg_free_percent% -c 0% -p $less_free $output_format"
);
-cmp_ok( $result->return_code, '==', 1, "Get warning on less_free mountpoint, when checking avg_free");
+cmp_ok( $result->return_code, "==", 0, "with JSON test format result should always be OK");
+like($result->{'mp_test_result'}->{'state'}, "/WARNING/", "Get warning on less_free mountpoint, when checking avg_free");
$result = NPTest->testCmd(
- "./check_disk -w $avg_free% -c $avg_free% -p $more_free"
+ "./check_disk -w $avg_free_percent% -c $avg_free_percent% -p $more_free"
);
cmp_ok( $result->return_code, '==', 0, "Get ok on more_free mountpoint, when checking avg_free");
$result = NPTest->testCmd(
- "./check_disk -w $avg_free% -c 0% -p $less_free -w $avg_free% -c $avg_free% -p $more_free"
+ "./check_disk -w $avg_free_percent% -c 0% -p $less_free -w $avg_free_percent% -c $avg_free_percent% -p $more_free"
);
cmp_ok( $result->return_code, "==", 1, "Combining above two tests, get warning");
my $all_disks = $result->output;
$result = NPTest->testCmd(
- "./check_disk -e -w $avg_free% -c 0% -p $less_free -w $avg_free% -c $avg_free% -p $more_free"
+ "./check_disk -e -w $avg_free_percent% -c 0% -p $less_free -w $avg_free_percent% -c $avg_free_percent% -p $more_free"
);
isnt( $result->output, $all_disks, "-e gives different output");
# Need spaces around filesystem name in case less_free and more_free are nested
like( $result->output, qr/ $less_free /, "Found problem $less_free");
unlike( $result->only_output, qr/ $more_free /, "Has ignored $more_free as not a problem");
-like( $result->perf_output, qr/ $more_free=/, "But $more_free is still in perf data");
+like( $result->perf_output, qr/'$more_free'=/, "But $more_free is still in perf data");
$result = NPTest->testCmd(
- "./check_disk -w $avg_free% -c 0% -p $more_free"
+ "./check_disk -w $avg_free_percent% -c 0% -p $more_free"
);
cmp_ok( $result->return_code, '==', 0, "Get ok on more_free mountpoint, checking avg_free");
$result = NPTest->testCmd(
- "./check_disk -w $avg_free% -c $avg_free% -p $less_free"
+ "./check_disk -w $avg_free_percent% -c $avg_free_percent% -p $less_free"
);
cmp_ok( $result->return_code, '==', 2, "Get critical on less_free, checking avg_free");
$result = NPTest->testCmd(
- "./check_disk -w $avg_free% -c 0% -p $more_free -w $avg_free% -c $avg_free% -p $less_free"
+ "./check_disk -w $avg_free_percent% -c 0% -p $more_free -w $avg_free_percent% -c $avg_free_percent% -p $less_free"
);
cmp_ok( $result->return_code, '==', 2, "Combining above two tests, get critical");
$result = NPTest->testCmd(
- "./check_disk -w $avg_free% -c $avg_free% -p $less_free -w $avg_free% -c 0% -p $more_free"
+ "./check_disk -w $avg_free_percent% -c $avg_free_percent% -p $less_free -w $avg_free_percent% -c 0% -p $more_free"
);
cmp_ok( $result->return_code, '==', 2, "And reversing arguments should not make a difference");
@@ -203,32 +247,32 @@ is( $result->return_code, 2, "Critical requesting 100% free inodes for both moun
$result = NPTest->testCmd( "./check_disk --iwarning 1% --icritical 1% -p $more_inode_free -K 100% -W 100% -p $less_inode_free" );
is( $result->return_code, 2, "Get critical on less_inode_free mountpoint $less_inode_free");
-$result = NPTest->testCmd( "./check_disk -W $avg_inode_free% -K 0% -p $less_inode_free" );
+$result = NPTest->testCmd( "./check_disk -W $avg_inode_free_percentage% -K 0% -p $less_inode_free" );
is( $result->return_code, 1, "Get warning on less_inode_free, when checking average");
-$result = NPTest->testCmd( "./check_disk -W $avg_inode_free% -K $avg_inode_free% -p $more_inode_free ");
+$result = NPTest->testCmd( "./check_disk -W $avg_inode_free_percentage% -K $avg_inode_free_percentage% -p $more_inode_free ");
is( $result->return_code, 0, "Get ok on more_inode_free when checking average");
-$result = NPTest->testCmd( "./check_disk -W $avg_inode_free% -K 0% -p $less_inode_free -W $avg_inode_free% -K $avg_inode_free% -p $more_inode_free" );
+$result = NPTest->testCmd( "./check_disk -W $avg_inode_free_percentage% -K 0% -p $less_inode_free -W $avg_inode_free_percentage% -K $avg_inode_free_percentage% -p $more_inode_free" );
is ($result->return_code, 1, "Combine above two tests, get warning");
$all_disks = $result->output;
-$result = NPTest->testCmd( "./check_disk -e -W $avg_inode_free% -K 0% -p $less_inode_free -W $avg_inode_free% -K $avg_inode_free% -p $more_inode_free" );
+$result = NPTest->testCmd( "./check_disk -e -W $avg_inode_free_percentage% -K 0% -p $less_inode_free -W $avg_inode_free_percentage% -K $avg_inode_free_percentage% -p $more_inode_free" );
isnt( $result->output, $all_disks, "-e gives different output");
like( $result->output, qr/$less_inode_free/, "Found problem $less_inode_free");
unlike( $result->only_output, qr/$more_inode_free\s/, "Has ignored $more_inode_free as not a problem");
like( $result->perf_output, qr/$more_inode_free/, "But $more_inode_free is still in perf data");
-$result = NPTest->testCmd( "./check_disk -W $avg_inode_free% -K 0% -p $more_inode_free" );
+$result = NPTest->testCmd( "./check_disk -W $avg_inode_free_percentage% -K 0% -p $more_inode_free" );
is( $result->return_code, 0, "Get ok on more_inode_free mountpoint, checking average");
-$result = NPTest->testCmd( "./check_disk -W $avg_inode_free% -K $avg_inode_free% -p $less_inode_free" );
+$result = NPTest->testCmd( "./check_disk -W $avg_inode_free_percentage% -K $avg_inode_free_percentage% -p $less_inode_free" );
is( $result->return_code, 2, "Get critical on less_inode_free, checking average");
-$result = NPTest->testCmd( "./check_disk -W $avg_inode_free% -K 0% -p $more_inode_free -W $avg_inode_free% -K $avg_inode_free% -p $less_inode_free" );
+$result = NPTest->testCmd( "./check_disk -W $avg_inode_free_percentage% -K 0% -p $more_inode_free -W $avg_inode_free_percentage% -K $avg_inode_free_percentage% -p $less_inode_free" );
is( $result->return_code, 2, "Combining above two tests, get critical");
-$result = NPTest->testCmd( "./check_disk -W $avg_inode_free% -K $avg_inode_free% -p $less_inode_free -W $avg_inode_free% -K 0% -p $more_inode_free" );
+$result = NPTest->testCmd( "./check_disk -W $avg_inode_free_percentage% -K $avg_inode_free_percentage% -p $less_inode_free -W $avg_inode_free_percentage% -K 0% -p $more_inode_free" );
cmp_ok( $result->return_code, '==', 2, "And reversing arguments should not make a difference");
@@ -249,9 +293,9 @@ $result = NPTest->testCmd(
);
cmp_ok( $result->return_code, "==", 3, "Invalid options: -p must come after thresholds" );
-$result = NPTest->testCmd( "./check_disk -w 100% -c 100% ".${mountpoint_valid} ); # 100% empty
-cmp_ok( $result->return_code, "==", 2, "100% empty" );
-like( $result->output, $failureOutput, "Right output" );
+$result = NPTest->testCmd( "./check_disk -w 100% -c 100% $output_format ".${mountpoint_valid} ); # 100% empty
+cmp_ok( $result->return_code, "==", 0, "100% empty" );
+like($result->{'mp_test_result'}->{'state'}, "/CRITICAL/", "100% empty");
$result = NPTest->testCmd( "./check_disk -w 100000000 -c 100000000 $mountpoint_valid" );
cmp_ok( $result->return_code, '==', 2, "Check for 100TB free" );
@@ -263,7 +307,8 @@ cmp_ok( $result->return_code, "==", 2, "100 TB empty" );
# Checking old syntax of check_disk warn crit [fs], with warn/crit at USED% thresholds
$result = NPTest->testCmd( "./check_disk 0 0 ".${mountpoint_valid} );
cmp_ok( $result->return_code, "==", 2, "Old syntax: 0% used");
-like ( $result->only_output, qr(^[^;]*;[^;]*$), "Select only one path with positional arguments");
+# like ( $result->only_output, qr(^[^;]*;[^;]*$), "Select only one path with positional arguments");
+# TODO not sure what the above should test, taking it out
$result = NPTest->testCmd( "./check_disk 100 100 $mountpoint_valid" );
cmp_ok( $result->return_code, '==', 0, "Old syntax: 100% used" );
@@ -311,8 +356,9 @@ $result = NPTest->testCmd( "./check_disk -w 0% -c 0% -p / -p /" );
unlike( $result->output, '/ \/ .* \/ /', "Should not show same filesystem twice");
# are partitions added if -C is given without path selection -p ?
-$result = NPTest->testCmd( "./check_disk -w 0% -c 0% -C -w 0% -c 0% -p $mountpoint_valid" );
-like( $result->output, '/;.*;\|/', "-C selects partitions if -p is not given");
+$result = NPTest->testCmd( "./check_disk -w 0% -c 0% -C -w 0% -c 0% -p $mountpoint_valid $output_format" );
+cmp_ok( $result->return_code, "==", 0, "with JSON test format result should always be OK");
+cmp_ok(scalar $result->{'mp_test_result'}->{'checks'}, '>', 1, "-C invokes matchall logic again");
# grouping: exit crit if the sum of free megs on mp1+mp2 is less than warn/crit
$result = NPTest->testCmd( "./check_disk -w ". ($free_mb_on_all + 1) ." -c ". ($free_mb_on_all + 1) ." -g group -p $mountpoint_valid -p $mountpoint2_valid" );
@@ -359,39 +405,37 @@ like( $result->output, qr/$mountpoint2_valid/,"ignore: output data does have $mo
# ignore-missing: exit okay, when fs is not accessible
$result = NPTest->testCmd( "./check_disk --ignore-missing -w 0% -c 0% -p /bob");
cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay for not existing filesystem /bob");
-like( $result->output, '/^DISK OK - No disks were found for provided parameters - ignored paths: /bob;.*$/', 'Output OK');
+like( $result->output, '/No filesystems were found for the provided parameters.*$/', 'Output OK');
# ignore-missing: exit okay, when regex does not match
$result = NPTest->testCmd( "./check_disk --ignore-missing -w 0% -c 0% -r /bob");
cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay for regular expression not matching");
-like( $result->output, '/^DISK OK - No disks were found for provided parameters.*$/', 'Output OK');
+like( $result->output, '/No filesystems were found for the provided parameters.*$/', 'Output OK');
# ignore-missing: exit okay, when fs with exact match (-E) is not found
$result = NPTest->testCmd( "./check_disk --ignore-missing -w 0% -c 0% -E -p /etc");
cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay when exact match does not find fs");
-like( $result->output, '/^DISK OK - No disks were found for provided parameters - ignored paths: /etc;.*$/', 'Output OK');
+like( $result->output, '/No filesystems were found for the provided parameters.*$/', 'Output OK');
# ignore-missing: exit okay, when checking one existing fs and one non-existing fs (regex)
$result = NPTest->testCmd( "./check_disk --ignore-missing -w 0% -c 0% -r '/bob' -r '^/\$'");
cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay for regular expression not matching");
-like( $result->output, '/^DISK OK - free space: \/ .*$/', 'Output OK');
# ignore-missing: exit okay, when checking one existing fs and one non-existing fs (path)
$result = NPTest->testCmd( "./check_disk --ignore-missing -w 0% -c 0% -p '/bob' -p '/'");
cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay for regular expression not matching");
-like( $result->output, '/^DISK OK - free space: / .*; - ignored paths: /bob;.*$/', 'Output OK');
+# like( $result->output, '/^DISK OK - free space: / .*; - ignored paths: /bob;.*$/', 'Output OK');
# ignore-missing: exit okay, when checking one non-existing fs (path) and one ignored
$result = NPTest->testCmd( "./check_disk -n -w 0% -c 0% -r /dummy -i /dummy2");
cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay for regular expression not matching");
-like( $result->output, '/^DISK OK - No disks were found for provided parameters\|$/', 'Output OK');
+like( $result->output, '/No filesystems were found for the provided parameters.*$/', 'Output OK');
# ignore-missing: exit okay, when regex match does not find anything
$result = NPTest->testCmd( "./check_disk -n -e -l -w 10% -c 5% -W 10% -K 5% -r /dummy");
cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay for regular expression not matching");
-like( $result->output, '/^DISK OK\|$/', 'Output OK');
# ignore-missing: exit okay, when regex match does not find anything
$result = NPTest->testCmd( "./check_disk -n -l -w 10% -c 5% -W 10% -K 5% -r /dummy");
cmp_ok( $result->return_code, '==', 0, "ignore-missing: return okay for regular expression not matching");
-like( $result->output, '/^DISK OK - No disks were found for provided parameters\|$/', 'Output OK');
+like( $result->output, '/No filesystems were found for the provided parameters.*$/', 'Output OK');
diff --git a/lib/tests/test_disk.c b/plugins/tests/test_check_disk.c
similarity index 68%
rename from lib/tests/test_disk.c
rename to plugins/tests/test_check_disk.c
index c18db7a4..35c57bce 100644
--- a/lib/tests/test_disk.c
+++ b/plugins/tests/test_check_disk.c
@@ -17,28 +17,16 @@
*****************************************************************************/
#include "common.h"
-#include "utils_disk.h"
-#include "tap.h"
+#include "../check_disk.d/utils_disk.h"
+#include "../../tap/tap.h"
#include "regex.h"
void np_test_mount_entry_regex(struct mount_entry *dummy_mount_list, char *regstr, int cflags, int expect, char *desc);
int main(int argc, char **argv) {
+ plan_tests(35);
+
struct name_list *exclude_filesystem = NULL;
- struct name_list *exclude_fstype = NULL;
- struct name_list *dummy_mountlist = NULL;
- struct name_list *temp_name;
- struct parameter_list *paths = NULL;
- struct parameter_list *p, *prev = NULL, *last = NULL;
-
- struct mount_entry *dummy_mount_list;
- struct mount_entry *me;
- struct mount_entry **mtail = &dummy_mount_list;
- int cflags = REG_NOSUB | REG_EXTENDED;
- int found = 0, count = 0;
-
- plan_tests(33);
-
ok(np_find_name(exclude_filesystem, "/var/log") == false, "/var/log not in list");
np_add_name(&exclude_filesystem, "/var/log");
ok(np_find_name(exclude_filesystem, "/var/log") == true, "is in list now");
@@ -47,6 +35,7 @@ int main(int argc, char **argv) {
ok(np_find_name(exclude_filesystem, "/home") == true, "is in list now");
ok(np_find_name(exclude_filesystem, "/var/log") == true, "/var/log still in list");
+ struct name_list *exclude_fstype = NULL;
ok(np_find_name(exclude_fstype, "iso9660") == false, "iso9660 not in list");
np_add_name(&exclude_fstype, "iso9660");
ok(np_find_name(exclude_fstype, "iso9660") == true, "is in list now");
@@ -59,7 +48,9 @@ int main(int argc, char **argv) {
}
*/
- me = (struct mount_entry *)malloc(sizeof *me);
+ struct mount_entry *dummy_mount_list;
+ struct mount_entry **mtail = &dummy_mount_list;
+ struct mount_entry *me = (struct mount_entry *)malloc(sizeof *me);
me->me_devname = strdup("/dev/c0t0d0s0");
me->me_mountdir = strdup("/");
*mtail = me;
@@ -77,6 +68,7 @@ int main(int argc, char **argv) {
*mtail = me;
mtail = &me->me_next;
+ int cflags = REG_NOSUB | REG_EXTENDED;
np_test_mount_entry_regex(dummy_mount_list, strdup("/"), cflags, 3, strdup("a"));
np_test_mount_entry_regex(dummy_mount_list, strdup("/dev"), cflags, 3, strdup("regex on dev names:"));
np_test_mount_entry_regex(dummy_mount_list, strdup("/foo"), cflags, 0, strdup("regex on non existent dev/path:"));
@@ -89,14 +81,16 @@ int main(int argc, char **argv) {
np_test_mount_entry_regex(dummy_mount_list, strdup("(/home)|(/var)"), cflags, 2, strdup("grouped regex pathname match:"));
np_test_mount_entry_regex(dummy_mount_list, strdup("(/homE)|(/Var)"), cflags | REG_ICASE, 2, strdup("grouped regi pathname match:"));
- np_add_parameter(&paths, "/home/groups");
- np_add_parameter(&paths, "/var");
- np_add_parameter(&paths, "/tmp");
- np_add_parameter(&paths, "/home/tonvoon");
- np_add_parameter(&paths, "/dev/c2t0d0s0");
+ filesystem_list test_paths = filesystem_list_init();
+ mp_int_fs_list_append(&test_paths, "/home/groups");
+ mp_int_fs_list_append(&test_paths, "/var");
+ mp_int_fs_list_append(&test_paths, "/tmp");
+ mp_int_fs_list_append(&test_paths, "/home/tonvoon");
+ mp_int_fs_list_append(&test_paths, "/dev/c2t0d0s0");
+ ok(test_paths.length == 5, "List counter works correctly with appends");
- np_set_best_match(paths, dummy_mount_list, false);
- for (p = paths; p; p = p->name_next) {
+ mp_int_fs_list_set_best_match(test_paths, dummy_mount_list, false);
+ for (parameter_list_elem *p = test_paths.first; p; p = mp_int_fs_list_get_next(p)) {
struct mount_entry *temp_me;
temp_me = p->best_match;
if (!strcmp(p->name, "/home/groups")) {
@@ -112,15 +106,19 @@ int main(int argc, char **argv) {
}
}
- paths = NULL; /* Bad boy - should free, but this is a test suite */
- np_add_parameter(&paths, "/home/groups");
- np_add_parameter(&paths, "/var");
- np_add_parameter(&paths, "/tmp");
- np_add_parameter(&paths, "/home/tonvoon");
- np_add_parameter(&paths, "/home");
+ for (parameter_list_elem *p = test_paths.first; p; p = mp_int_fs_list_get_next(p)) {
+ mp_int_fs_list_del(&test_paths, p);
+ }
+ ok(test_paths.length == 0, "List delete sets counter properly");
- np_set_best_match(paths, dummy_mount_list, true);
- for (p = paths; p; p = p->name_next) {
+ mp_int_fs_list_append(&test_paths, "/home/groups");
+ mp_int_fs_list_append(&test_paths, "/var");
+ mp_int_fs_list_append(&test_paths, "/tmp");
+ mp_int_fs_list_append(&test_paths, "/home/tonvoon");
+ mp_int_fs_list_append(&test_paths, "/home");
+
+ mp_int_fs_list_set_best_match(test_paths, dummy_mount_list, true);
+ for (parameter_list_elem *p = test_paths.first; p; p = mp_int_fs_list_get_next(p)) {
if (!strcmp(p->name, "/home/groups")) {
ok(!p->best_match, "/home/groups correctly not found");
} else if (!strcmp(p->name, "/var")) {
@@ -134,59 +132,66 @@ int main(int argc, char **argv) {
}
}
+ bool found = false;
/* test deleting first element in paths */
- paths = np_del_parameter(paths, NULL);
- for (p = paths; p; p = p->name_next) {
- if (!strcmp(p->name, "/home/groups"))
- found = 1;
- }
- ok(found == 0, "first element successfully deleted");
- found = 0;
-
- p = paths;
- while (p) {
- if (!strcmp(p->name, "/tmp"))
- p = np_del_parameter(p, prev);
- else {
- prev = p;
- p = p->name_next;
+ mp_int_fs_list_del(&test_paths, NULL);
+ for (parameter_list_elem *p = test_paths.first; p; p = mp_int_fs_list_get_next(p)) {
+ if (!strcmp(p->name, "/home/groups")) {
+ found = true;
}
}
+ ok(!found, "first element successfully deleted");
+ found = false;
- for (p = paths; p; p = p->name_next) {
- if (!strcmp(p->name, "/tmp"))
- found = 1;
- if (p->name_next)
- prev = p;
- else
- last = p;
+ parameter_list_elem *prev = NULL;
+ parameter_list_elem *p = NULL;
+ for (parameter_list_elem *path = test_paths.first; path; path = mp_int_fs_list_get_next(path)) {
+ if (!strcmp(path->name, "/tmp")) {
+ mp_int_fs_list_del(&test_paths, path);
+ }
+ p = path;
}
- ok(found == 0, "/tmp element successfully deleted");
- p = np_del_parameter(last, prev);
- for (p = paths; p; p = p->name_next) {
- if (!strcmp(p->name, "/home"))
- found = 1;
+ parameter_list_elem *last = NULL;
+ for (parameter_list_elem *path = test_paths.first; path; path = mp_int_fs_list_get_next(path)) {
+ if (!strcmp(path->name, "/tmp")) {
+ found = true;
+ }
+ if (path->next) {
+ prev = path;
+ } else {
+ last = path;
+ }
+ }
+ ok(!found, "/tmp element successfully deleted");
+
+ int count = 0;
+ mp_int_fs_list_del(&test_paths, p);
+ for (p = test_paths.first; p; p = p->next) {
+ if (!strcmp(p->name, "/home")) {
+ found = true;
+ }
last = p;
count++;
}
- ok(found == 0, "last (/home) element successfully deleted");
+ ok(!found, "last (/home) element successfully deleted");
ok(count == 2, "two elements remaining");
return exit_status();
}
void np_test_mount_entry_regex(struct mount_entry *dummy_mount_list, char *regstr, int cflags, int expect, char *desc) {
- int matches = 0;
- regex_t re;
- struct mount_entry *me;
- if (regcomp(&re, regstr, cflags) == 0) {
- for (me = dummy_mount_list; me; me = me->me_next) {
- if (np_regex_match_mount_entry(me, &re))
+ regex_t regex;
+ if (regcomp(®ex, regstr, cflags) == 0) {
+ int matches = 0;
+ for (struct mount_entry *me = dummy_mount_list; me; me = me->me_next) {
+ if (np_regex_match_mount_entry(me, ®ex)) {
matches++;
+ }
}
ok(matches == expect, "%s '%s' matched %i/3 entries. ok: %i/3", desc, regstr, expect, matches);
- } else
+ } else {
ok(false, "regex '%s' not compilable", regstr);
+ }
}
diff --git a/plugins/tests/test_check_disk.t b/plugins/tests/test_check_disk.t
new file mode 100755
index 00000000..56354650
--- /dev/null
+++ b/plugins/tests/test_check_disk.t
@@ -0,0 +1,6 @@
+#!/usr/bin/perl
+use Test::More;
+if (! -e "./test_check_disk") {
+ plan skip_all => "./test_check_disk not compiled - please enable libtap library to test";
+}
+exec "./test_check_disk";