Merge pull request #2113 from RincewindsHat/refactor/check_disk

Refactor/check disk
This commit is contained in:
Lorenz Kästle 2025-03-31 23:58:02 +02:00 committed by GitHub
commit 4924bc877f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
22 changed files with 1784 additions and 1133 deletions

5
.gitignore vendored
View file

@ -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

View file

@ -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

View file

@ -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 \

View file

@ -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; }

View file

@ -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;

View file

@ -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;
}

View file

@ -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
// =================

View file

@ -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)

View file

@ -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";

View file

@ -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;
}

View file

@ -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);

View file

@ -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;

View file

@ -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 <http://www.gnu.org/licenses/>.
*
*
*****************************************************************************/
#include "common.h"
#include "utils_disk.h"
#include "gl/fsusage.h"
#include <string.h>
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;
}

View file

@ -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);

View file

@ -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

File diff suppressed because it is too large Load diff

View file

@ -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 <http://www.gnu.org/licenses/>.
*
*
*****************************************************************************/
#include "../common.h"
#include "utils_disk.h"
#include "../../gl/fsusage.h"
#include "../../lib/thresholds.h"
#include "../../lib/states.h"
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
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);
}
}
}

View file

@ -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 <stdint.h>
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);

View file

@ -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 <getopt.h>
#include "dirname.h"
#include "../gl/dirname.h"
#include <locale.h>
@ -190,7 +190,7 @@ enum {
* Internationalization
*
*/
#include "gettext.h"
#include "../gl/gettext.h"
#define _(String) gettext (String)
#if ! ENABLE_NLS
# undef textdomain

View file

@ -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');

View file

@ -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(&regex, 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, &regex)) {
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);
}
}

View file

@ -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";