From 285db2a9fa25519cacd48a76347ae2dee0c06605 Mon Sep 17 00:00:00 2001 From: Lorenz Kästle <12514511+RincewindsHat@users.noreply.github.com> Date: Tue, 18 Mar 2025 14:36:20 +0100 Subject: Move disk specific stuff from lib to plugin specific directory --- plugins/check_disk.d/utils_disk.h | 48 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 plugins/check_disk.d/utils_disk.h (limited to 'plugins/check_disk.d/utils_disk.h') diff --git a/plugins/check_disk.d/utils_disk.h b/plugins/check_disk.d/utils_disk.h new file mode 100644 index 00000000..c5e81dc1 --- /dev/null +++ b/plugins/check_disk.d/utils_disk.h @@ -0,0 +1,48 @@ +/* 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); -- cgit v1.2.3-74-g34f1 From 8ccff07bed03046a97637a54d45a9ffe77edc235 Mon Sep 17 00:00:00 2001 From: Lorenz Kästle <12514511+RincewindsHat@users.noreply.github.com> Date: Tue, 18 Mar 2025 14:37:02 +0100 Subject: refactor check_disk.d code a bit --- plugins/check_disk.d/utils_disk.c | 139 +++++++++++++++++++------------------- plugins/check_disk.d/utils_disk.h | 39 ++++++++--- 2 files changed, 100 insertions(+), 78 deletions(-) (limited to 'plugins/check_disk.d/utils_disk.h') diff --git a/plugins/check_disk.d/utils_disk.c b/plugins/check_disk.d/utils_disk.c index 2b761f5e..1d806715 100644 --- a/plugins/check_disk.d/utils_disk.c +++ b/plugins/check_disk.d/utils_disk.c @@ -63,12 +63,46 @@ int np_add_regex(struct regex_list **list, const char *regex, int cflags) { *list = new_entry; return 0; - } else { - // regcomp failed - free(new_entry); - - return regcomp_result; } + // regcomp failed + free(new_entry); + + return regcomp_result; +} + +struct parameter_list parameter_list_init(const char *name) { + struct parameter_list result = { + .name = strdup(name), + .best_match = NULL, + + .name_next = NULL, + .name_prev = NULL, + + .freespace_units = NULL, + .freespace_percent = NULL, + .usedspace_units = NULL, + .usedspace_percent = NULL, + .usedinodes_percent = NULL, + .freeinodes_percent = NULL, + + .group = NULL, + .dfree_pct = -1, + .dused_pct = -1, + .total = 0, + .available = 0, + .available_to_root = 0, + .used = 0, + .dused_units = 0, + .dfree_units = 0, + .dtotal_units = 0, + .inodes_total = 0, + .inodes_free = 0, + .inodes_free_to_root = 0, + .inodes_used = 0, + .dused_inodes_percent = 0, + .dfree_inodes_percent = 0, + }; + return result; } /* Initialises a new parameter at the end of list */ @@ -76,36 +110,8 @@ struct parameter_list *np_add_parameter(struct parameter_list **list, const char 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); + + *new_path = parameter_list_init(name); if (current == NULL) { *list = new_path; @@ -125,18 +131,22 @@ struct parameter_list *np_del_parameter(struct parameter_list *item, struct para if (item == NULL) { return NULL; } + struct parameter_list *next; - if (item->name_next) + if (item->name_next) { next = item->name_next; - else + } else { next = NULL; + } - if (next) + if (next) { next->name_prev = prev; + } - if (prev) + if (prev) { prev->name_next = next; + } if (item->name) { free(item->name); @@ -148,43 +158,42 @@ struct parameter_list *np_del_parameter(struct parameter_list *item, struct para /* 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)) + for (struct parameter_list *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) { + for (struct parameter_list *d = desired; d; d = d->name_next) { if (!d->best_match) { - struct mount_entry *me; + struct mount_entry *mount_entry; 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; + for (mount_entry = mount_list; mount_entry; mount_entry = mount_entry->me_next) { + if (strcmp(mount_entry->me_devname, d->name) == 0) { + 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) { - 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; + for (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, d->name, len) == 0))) || + (exact && strcmp(mount_entry->me_mountdir, d->name) == 0)) { + if (get_fs_usage(mount_entry->me_mountdir, mount_entry->me_devname, &fsp) >= 0) { + best_match = mount_entry; best_match_len = len; } } @@ -202,12 +211,10 @@ void np_set_best_match(struct parameter_list *desired, struct mount_entry *mount /* 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) { + for (struct name_list *n = list; n; n = n->next) { if (!strcmp(name, n->name)) { return true; } @@ -217,18 +224,16 @@ bool np_find_name(struct name_list *list, const char *name) { /* 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); + int 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 m; if (!regexec(&list->regex, name, 1, &m, 0) && m.rm_so == 0 && m.rm_eo == len) { return true; } @@ -238,8 +243,7 @@ bool np_find_regmatch(struct regex_list *list, const char *name) { } bool np_seen_name(struct name_list *list, const char *name) { - const struct name_list *s; - for (s = list; s; s = s->next) { + for (struct name_list *s = list; s; s = s->next) { if (!strcmp(s->name, name)) { return true; } @@ -248,8 +252,5 @@ bool np_seen_name(struct name_list *list, const char *name) { } 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; + return ((regexec(re, me->me_devname, (size_t)0, NULL, 0) == 0) || (regexec(re, me->me_mountdir, (size_t)0, NULL, 0) == 0)); } diff --git a/plugins/check_disk.d/utils_disk.h b/plugins/check_disk.d/utils_disk.h index c5e81dc1..1c68fed9 100644 --- a/plugins/check_disk.d/utils_disk.h +++ b/plugins/check_disk.d/utils_disk.h @@ -1,8 +1,10 @@ /* Header file for utils_disk */ -#include "mountlist.h" +#include "../../config.h" +#include "../../gl/mountlist.h" #include "utils_base.h" #include "regex.h" +#include struct name_list { char *name; @@ -16,22 +18,39 @@ struct regex_list { struct parameter_list { char *name; - thresholds *freespace_bytes; + char *group; + 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; + + uintmax_t total; + uintmax_t available; + uintmax_t available_to_root; + uintmax_t used; + uintmax_t inodes_free; + uintmax_t inodes_free_to_root; + uintmax_t inodes_used; + uintmax_t inodes_total; + + double dfree_pct; + double dused_pct; + + uint64_t dused_units; + uint64_t dfree_units; + uint64_t dtotal_units; + + double dused_inodes_percent; + double dfree_inodes_percent; + 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); @@ -39,10 +58,12 @@ 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); +struct parameter_list parameter_list_init(const char *); 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); +bool np_regex_match_mount_entry(struct mount_entry *, regex_t *); -- cgit v1.2.3-74-g34f1 From 59e0a258f9c0f393bf29cced1f35743f74e7b10c Mon Sep 17 00:00:00 2001 From: Lorenz Kästle <12514511+RincewindsHat@users.noreply.github.com> Date: Tue, 18 Mar 2025 15:57:44 +0100 Subject: Migrate disk tests from lib, tool --- .gitignore | 3 +- configure.ac | 4 +- lib/tests/Makefile.am | 6 +- lib/tests/test_disk.c | 192 -------------------------------------- lib/tests/test_disk.t | 6 -- plugins/Makefile.am | 8 +- plugins/check_disk.d/utils_disk.c | 4 +- plugins/check_disk.d/utils_disk.h | 2 +- plugins/common.h | 6 +- plugins/tests/test_check_disk.c | 192 ++++++++++++++++++++++++++++++++++++++ plugins/tests/test_check_disk.t | 6 ++ 11 files changed, 216 insertions(+), 213 deletions(-) delete mode 100644 lib/tests/test_disk.c delete mode 100755 lib/tests/test_disk.t create mode 100644 plugins/tests/test_check_disk.c create mode 100755 plugins/tests/test_check_disk.t (limited to 'plugins/check_disk.d/utils_disk.h') diff --git a/.gitignore b/.gitignore index 5245495e..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 @@ -223,7 +222,7 @@ plugins/check_disk.d/.dirstamp /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/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.c b/lib/tests/test_disk.c deleted file mode 100644 index c18db7a4..00000000 --- a/lib/tests/test_disk.c +++ /dev/null @@ -1,192 +0,0 @@ -/***************************************************************************** - * - * 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 "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) { - 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"); - ok(np_find_name(exclude_filesystem, "/home") == false, "/home not in list"); - np_add_name(&exclude_filesystem, "/home"); - 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"); - - 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"); - - ok(np_find_name(exclude_filesystem, "iso9660") == false, "Make sure no clashing in variables"); - - /* - for (temp_name = exclude_filesystem; temp_name; temp_name = temp_name->next) { - printf("Name: %s\n", temp_name->name); - } - */ - - me = (struct mount_entry *)malloc(sizeof *me); - me->me_devname = strdup("/dev/c0t0d0s0"); - me->me_mountdir = strdup("/"); - *mtail = me; - mtail = &me->me_next; - - me = (struct mount_entry *)malloc(sizeof *me); - me->me_devname = strdup("/dev/c1t0d1s0"); - me->me_mountdir = strdup("/var"); - *mtail = me; - mtail = &me->me_next; - - me = (struct mount_entry *)malloc(sizeof *me); - me->me_devname = strdup("/dev/c2t0d0s0"); - me->me_mountdir = strdup("/home"); - *mtail = me; - mtail = &me->me_next; - - 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:")); - np_test_mount_entry_regex(dummy_mount_list, strdup("/Foo"), cflags | REG_ICASE, 0, strdup("regi on non existent dev/path:")); - np_test_mount_entry_regex(dummy_mount_list, strdup("/c.t0"), cflags, 3, strdup("partial devname regex match:")); - np_test_mount_entry_regex(dummy_mount_list, strdup("c0t0"), cflags, 1, strdup("partial devname regex match:")); - np_test_mount_entry_regex(dummy_mount_list, strdup("C0t0"), cflags | REG_ICASE, 1, strdup("partial devname regi match:")); - np_test_mount_entry_regex(dummy_mount_list, strdup("home"), cflags, 1, strdup("partial pathname regex match:")); - np_test_mount_entry_regex(dummy_mount_list, strdup("hOme"), cflags | REG_ICASE, 1, strdup("partial pathname regi match:")); - 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"); - - np_set_best_match(paths, dummy_mount_list, false); - for (p = paths; p; p = p->name_next) { - struct mount_entry *temp_me; - temp_me = p->best_match; - if (!strcmp(p->name, "/home/groups")) { - ok(temp_me && !strcmp(temp_me->me_mountdir, "/home"), "/home/groups got right best match: /home"); - } else if (!strcmp(p->name, "/var")) { - ok(temp_me && !strcmp(temp_me->me_mountdir, "/var"), "/var got right best match: /var"); - } else if (!strcmp(p->name, "/tmp")) { - ok(temp_me && !strcmp(temp_me->me_mountdir, "/"), "/tmp got right best match: /"); - } else if (!strcmp(p->name, "/home/tonvoon")) { - ok(temp_me && !strcmp(temp_me->me_mountdir, "/home"), "/home/tonvoon got right best match: /home"); - } else if (!strcmp(p->name, "/dev/c2t0d0s0")) { - ok(temp_me && !strcmp(temp_me->me_devname, "/dev/c2t0d0s0"), "/dev/c2t0d0s0 got right best match: /dev/c2t0d0s0"); - } - } - - 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"); - - np_set_best_match(paths, dummy_mount_list, true); - for (p = paths; p; p = p->name_next) { - if (!strcmp(p->name, "/home/groups")) { - ok(!p->best_match, "/home/groups correctly not found"); - } else if (!strcmp(p->name, "/var")) { - ok(p->best_match, "/var found"); - } else if (!strcmp(p->name, "/tmp")) { - ok(!p->best_match, "/tmp correctly not found"); - } else if (!strcmp(p->name, "/home/tonvoon")) { - ok(!p->best_match, "/home/tonvoon not found"); - } else if (!strcmp(p->name, "/home")) { - ok(p->best_match, "/home found"); - } - } - - /* 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; - } - } - - for (p = paths; p; p = p->name_next) { - if (!strcmp(p->name, "/tmp")) - found = 1; - if (p->name_next) - prev = p; - else - last = p; - } - 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; - last = p; - count++; - } - ok(found == 0, "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)) - matches++; - } - ok(matches == expect, "%s '%s' matched %i/3 entries. ok: %i/3", desc, regstr, expect, matches); - - } else - ok(false, "regex '%s' not compilable", regstr); -} 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/plugins/Makefile.am b/plugins/Makefile.am index 30283cb4..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 \ @@ -167,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.d/utils_disk.c b/plugins/check_disk.d/utils_disk.c index 1d806715..369c85d5 100644 --- a/plugins/check_disk.d/utils_disk.c +++ b/plugins/check_disk.d/utils_disk.c @@ -26,9 +26,9 @@ * *****************************************************************************/ -#include "common.h" +#include "../common.h" #include "utils_disk.h" -#include "gl/fsusage.h" +#include "../../gl/fsusage.h" #include void np_add_name(struct name_list **list, const char *name) { diff --git a/plugins/check_disk.d/utils_disk.h b/plugins/check_disk.d/utils_disk.h index 1c68fed9..0c69f987 100644 --- a/plugins/check_disk.d/utils_disk.h +++ b/plugins/check_disk.d/utils_disk.h @@ -2,7 +2,7 @@ #include "../../config.h" #include "../../gl/mountlist.h" -#include "utils_base.h" +#include "../../lib/utils_base.h" #include "regex.h" #include 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/tests/test_check_disk.c b/plugins/tests/test_check_disk.c new file mode 100644 index 00000000..92d0d270 --- /dev/null +++ b/plugins/tests/test_check_disk.c @@ -0,0 +1,192 @@ +/***************************************************************************** + * + * 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 "../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) { + 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"); + ok(np_find_name(exclude_filesystem, "/home") == false, "/home not in list"); + np_add_name(&exclude_filesystem, "/home"); + 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"); + + 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"); + + ok(np_find_name(exclude_filesystem, "iso9660") == false, "Make sure no clashing in variables"); + + /* + for (temp_name = exclude_filesystem; temp_name; temp_name = temp_name->next) { + printf("Name: %s\n", temp_name->name); + } + */ + + me = (struct mount_entry *)malloc(sizeof *me); + me->me_devname = strdup("/dev/c0t0d0s0"); + me->me_mountdir = strdup("/"); + *mtail = me; + mtail = &me->me_next; + + me = (struct mount_entry *)malloc(sizeof *me); + me->me_devname = strdup("/dev/c1t0d1s0"); + me->me_mountdir = strdup("/var"); + *mtail = me; + mtail = &me->me_next; + + me = (struct mount_entry *)malloc(sizeof *me); + me->me_devname = strdup("/dev/c2t0d0s0"); + me->me_mountdir = strdup("/home"); + *mtail = me; + mtail = &me->me_next; + + 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:")); + np_test_mount_entry_regex(dummy_mount_list, strdup("/Foo"), cflags | REG_ICASE, 0, strdup("regi on non existent dev/path:")); + np_test_mount_entry_regex(dummy_mount_list, strdup("/c.t0"), cflags, 3, strdup("partial devname regex match:")); + np_test_mount_entry_regex(dummy_mount_list, strdup("c0t0"), cflags, 1, strdup("partial devname regex match:")); + np_test_mount_entry_regex(dummy_mount_list, strdup("C0t0"), cflags | REG_ICASE, 1, strdup("partial devname regi match:")); + np_test_mount_entry_regex(dummy_mount_list, strdup("home"), cflags, 1, strdup("partial pathname regex match:")); + np_test_mount_entry_regex(dummy_mount_list, strdup("hOme"), cflags | REG_ICASE, 1, strdup("partial pathname regi match:")); + 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"); + + np_set_best_match(paths, dummy_mount_list, false); + for (p = paths; p; p = p->name_next) { + struct mount_entry *temp_me; + temp_me = p->best_match; + if (!strcmp(p->name, "/home/groups")) { + ok(temp_me && !strcmp(temp_me->me_mountdir, "/home"), "/home/groups got right best match: /home"); + } else if (!strcmp(p->name, "/var")) { + ok(temp_me && !strcmp(temp_me->me_mountdir, "/var"), "/var got right best match: /var"); + } else if (!strcmp(p->name, "/tmp")) { + ok(temp_me && !strcmp(temp_me->me_mountdir, "/"), "/tmp got right best match: /"); + } else if (!strcmp(p->name, "/home/tonvoon")) { + ok(temp_me && !strcmp(temp_me->me_mountdir, "/home"), "/home/tonvoon got right best match: /home"); + } else if (!strcmp(p->name, "/dev/c2t0d0s0")) { + ok(temp_me && !strcmp(temp_me->me_devname, "/dev/c2t0d0s0"), "/dev/c2t0d0s0 got right best match: /dev/c2t0d0s0"); + } + } + + 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"); + + np_set_best_match(paths, dummy_mount_list, true); + for (p = paths; p; p = p->name_next) { + if (!strcmp(p->name, "/home/groups")) { + ok(!p->best_match, "/home/groups correctly not found"); + } else if (!strcmp(p->name, "/var")) { + ok(p->best_match, "/var found"); + } else if (!strcmp(p->name, "/tmp")) { + ok(!p->best_match, "/tmp correctly not found"); + } else if (!strcmp(p->name, "/home/tonvoon")) { + ok(!p->best_match, "/home/tonvoon not found"); + } else if (!strcmp(p->name, "/home")) { + ok(p->best_match, "/home found"); + } + } + + /* 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; + } + } + + for (p = paths; p; p = p->name_next) { + if (!strcmp(p->name, "/tmp")) + found = 1; + if (p->name_next) + prev = p; + else + last = p; + } + 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; + last = p; + count++; + } + ok(found == 0, "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)) + matches++; + } + ok(matches == expect, "%s '%s' matched %i/3 entries. ok: %i/3", desc, regstr, expect, matches); + + } 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"; -- cgit v1.2.3-74-g34f1 From 908aed4e6f9072e601a189d4ceff3152bdecc49d Mon Sep 17 00:00:00 2001 From: Lorenz Kästle <12514511+RincewindsHat@users.noreply.github.com> Date: Sun, 30 Mar 2025 22:37:48 +0200 Subject: Refactor check_disk and library functions --- plugins/check_disk.c | 1069 ++++++++++++++++++++----------------- plugins/check_disk.d/config.h | 92 ---- plugins/check_disk.d/utils_disk.c | 469 ++++++++++++---- plugins/check_disk.d/utils_disk.h | 142 ++++- 4 files changed, 1048 insertions(+), 724 deletions(-) delete mode 100644 plugins/check_disk.d/config.h (limited to 'plugins/check_disk.d/utils_disk.h') diff --git a/plugins/check_disk.c b/plugins/check_disk.c index 050298d6..3cab816d 100644 --- a/plugins/check_disk.c +++ b/plugins/check_disk.c @@ -33,6 +33,10 @@ 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 @@ -48,10 +52,9 @@ const char *email = "devel@monitoring-plugins.org"; #include #include "./popen.h" #include "./utils.h" -#include "./check_disk.d/utils_disk.h" #include "../gl/fsusage.h" #include "../gl/mountlist.h" -#include "check_disk.d/config.h" +#include "./check_disk.d/utils_disk.h" #if HAVE_LIMITS_H # include @@ -74,20 +77,22 @@ typedef struct { check_disk_config config; } check_disk_config_wrapper; static check_disk_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/); -static void set_all_thresholds(struct parameter_list *path, char * /*warn_freespace_units*/, char * /*crit_freespace_units*/, - char * /*warn_freespace_percent*/, char * /*crit_freespace_percent*/, char * /*warn_usedspace_units*/, - char * /*crit_usedspace_units*/, char * /*warn_usedspace_percent*/, char * /*crit_usedspace_percent*/, - char * /*warn_usedinodes_percent*/, char * /*crit_usedinodes_percent*/, char * /*warn_freeinodes_percent*/, - char * /*crit_freeinodes_percent*/); -static void print_help(void); -void print_usage(void); + +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(struct parameter_list * /*parameters*/, bool /*ignore_missing*/); -static void get_stats(struct parameter_list * /*parameters*/, struct fs_usage *fsp, bool /*ignore_missing*/, - bool /*freespace_ignore_reserved*/, uintmax_t /*mult*/, struct parameter_list * /*path_select_list*/, - struct name_list * /*seen*/); -static void get_path_stats(struct parameter_list * /*parameters*/, struct fs_usage *fsp, bool /*freespace_ignore_reserved*/, - uintmax_t /*mult*/, struct name_list * /*seen*/); +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 int verbose = 0; @@ -100,7 +105,7 @@ int main(int argc, char **argv) { char mountdir[32]; #endif - /* Parse extra opts if any */ + // Parse extra opts if any argv = np_extra_opts(&argc, argv, progname); check_disk_config_wrapper tmp_config = process_arguments(argc, argv); @@ -110,289 +115,222 @@ int main(int argc, char **argv) { check_disk_config config = tmp_config.config; - /* If a list of paths has not been selected, find entire - mount list and create list of paths - */ - if (!config.path_selected && !config.path_ignored) { - for (struct mount_entry *me = config.mount_list; me; me = me->me_next) { - struct parameter_list *path = NULL; - if (!(path = np_find_parameter(config.path_select_list, me->me_mountdir))) { - path = np_add_parameter(&config.path_select_list, me->me_mountdir); - } - path->best_match = me; - path->group = config.group; - set_all_thresholds(path, config.warn_freespace_units, config.crit_freespace_units, config.warn_freespace_percent, - config.crit_freespace_percent, config.warn_usedspace_units, config.crit_usedspace_units, - config.warn_usedspace_percent, config.crit_usedspace_percent, config.warn_usedinodes_percent, - config.crit_usedinodes_percent, config.warn_freeinodes_percent, config.crit_freeinodes_percent); - } + if (config.output_format_is_set) { + mp_set_format(config.output_format); } - if (!config.path_ignored) { - np_set_best_match(config.path_select_list, config.mount_list, config.exact_match); + if (config.erronly) { + mp_set_level_of_detail(MP_DETAIL_NON_OK_ONLY); } - /* Error if no match found for specified paths */ - struct parameter_list *temp_list = config.path_select_list; + if (!config.path_ignored) { + mp_int_fs_list_set_best_match(config.path_select_list, config.mount_list, config.exact_match); + } - char *ignored = strdup(""); - while (config.path_select_list) { - if (!config.path_select_list->best_match && config.ignore_missing) { - /* If the first element will be deleted, the temp_list must be updated with the new start address as well */ - if (config.path_select_list == temp_list) { - temp_list = config.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, config.path_select_list->name); + // 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. */ - config.path_select_list = np_del_parameter(config.path_select_list, config.path_select_list->name_prev); - } else if (!config.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"), config.path_select_list->name); - } else { - /* Continue jumping through the list */ - config.path_select_list = config.path_select_list->name_next; + die(STATE_CRITICAL, _("DISK %s: %s not found\n"), _("CRITICAL"), elem->name); } - } - config.path_select_list = temp_list; - - mp_state_enum result = STATE_UNKNOWN; - if (!config.path_select_list && config.ignore_missing) { - result = STATE_OK; - if (verbose >= 2) { - printf("None of the provided paths were found\n"); - } + elem = mp_int_fs_list_get_next(elem); } - mp_state_enum filesystem_result = STATE_UNKNOWN; - char *perf = strdup(""); - char *perf_ilabel = strdup(""); - char *output = strdup(""); - struct parameter_list *path = NULL; - /* Process for every path in list */ - for (path = config.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); + 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 { + 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); + } - if (verbose >= 3 && path->group != NULL) { - printf("Group of %s: %s\n", path->name, path->group); + // 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; } - // reset filesystem result - filesystem_result = STATE_UNKNOWN; - struct mount_entry *mount_entry = path->best_match; - if (!mount_entry) { - continue; - } - #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) { - me->me_remote = 1; + mount_entry->me_remote = 1; } #endif - /* Filters */ /* 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; } - np_add_name(&config.seen, mount_entry->me_mountdir); if (path->group == NULL) { - /* Skip remote filesystems if we're not interested in them */ - if (mount_entry->me_remote && config.show_local_fs) { - if (config.stat_remote_fs) { - if (!stat_path(path, config.ignore_missing) && config.ignore_missing) { - 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 (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; - /* Skip excluded fs's */ } + 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; - /* Skip not included fstypes */ } + 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; } - } - - if (!stat_path(path, config.ignore_missing)) { - if (config.ignore_missing) { - result = STATE_OK; - xasprintf(&ignored, "%s %s;", ignored, path->name); - } - continue; - } - struct fs_usage fsp = {0}; - get_fs_usage(mount_entry->me_mountdir, mount_entry->me_devname, &fsp); - - if (fsp.fsu_blocks && strcmp("none", mount_entry->me_mountdir)) { - get_stats(path, &fsp, config.ignore_missing, config.freespace_ignore_reserved, config.mult, config.path_select_list, - config.seen); - - 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", - mount_entry->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, config.mult); - } - - /* Threshold comparisons */ - - mp_state_enum temp_result = get_status(path->dfree_units, path->freespace_units); - if (verbose >= 3) { - printf("Freespace_units result=%d\n", temp_result); + /* 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; } - filesystem_result = max_state(filesystem_result, temp_result); - temp_result = get_status(path->dfree_pct, path->freespace_percent); - if (verbose >= 3) { - printf("Freespace%% result=%d\n", temp_result); + // 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; } - filesystem_result = max_state(filesystem_result, temp_result); + } - temp_result = get_status(path->dused_units, path->usedspace_units); - if (verbose >= 3) { - printf("Usedspace_units result=%d\n", temp_result); - } - filesystem_result = max_state(filesystem_result, temp_result); + path = mp_int_fs_list_get_next(path); + } - temp_result = get_status(path->dused_pct, path->usedspace_percent); - if (verbose >= 3) { - printf("Usedspace_percent result=%d\n", temp_result); - } - filesystem_result = max_state(filesystem_result, temp_result); + // 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); - temp_result = get_status(path->dused_inodes_percent, path->usedinodes_percent); - if (verbose >= 3) { - printf("Usedinodes_percent result=%d\n", temp_result); - } - filesystem_result = max_state(filesystem_result, temp_result); + if (fsp.fsu_blocks != 0 && strcmp("none", mount_entry->me_mountdir) != 0) { + *filesystem = get_path_stats(*filesystem, fsp, config.freespace_ignore_reserved); - temp_result = get_status(path->dfree_inodes_percent, path->freeinodes_percent); if (verbose >= 3) { - printf("Freeinodes_percent result=%d\n", temp_result); - } - filesystem_result = max_state(filesystem_result, temp_result); - - result = max_state(result, filesystem_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) * config.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 * config.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) * config.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 * config.mult))); - } - - /* Nb: *_high_tide are unset when == UINT64_MAX */ - xasprintf(&perf, "%s %s", perf, - perfdata_uint64((!strcmp(mount_entry->me_mountdir, "none") || config.display_mntp) ? mount_entry->me_devname - : mount_entry->me_mountdir, - path->dused_units * config.mult, "B", (warning_high_tide != UINT64_MAX), warning_high_tide, - (critical_high_tide != UINT64_MAX), critical_high_tide, true, 0, true, - path->dtotal_units * config.mult)); - - if (config.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(mount_entry->me_mountdir, "none") || config.display_mntp) ? mount_entry->me_devname - : mount_entry->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), warning_high_tide, - (critical_high_tide != UINT64_MAX), critical_high_tide, true, 0, true, path->inodes_total)); + 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 (filesystem_result == STATE_OK && config.erronly && !verbose) { - continue; + 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); } + } + } - char *flag_header = NULL; - if (filesystem_result && verbose >= 1) { - xasprintf(&flag_header, " %s [", state_text(filesystem_result)); + 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 (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 { - xasprintf(&flag_header, ""); + current = add_measurement_list(measurements, unit); } - xasprintf(&output, "%s%s %s %llu%s (%.1f%%", output, flag_header, - (!strcmp(mount_entry->me_mountdir, "none") || config.display_mntp) ? mount_entry->me_devname - : mount_entry->me_mountdir, - path->dfree_units, config.units, path->dfree_pct); - if (path->dused_inodes_percent < 0) { - xasprintf(&output, "%s inode=-)%s;", output, (filesystem_result ? "]" : "")); + } 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 { - xasprintf(&output, "%s inode=%.0f%%)%s;", output, path->dfree_inodes_percent, - ((filesystem_result && verbose >= 1) ? "]" : "")); + // if this is the first element of a group, the name of the previos 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); + } } - free(flag_header); } } - char *preamble = " - free space:"; - if (strcmp(output, "") == 0 && !config.erronly) { - preamble = ""; - xasprintf(&output, " - No disks were found for provided parameters"); + /* Process for every path in list */ + 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 { + // Aparently no machting fs found + 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 { + none_sc = mp_set_subcheck_state(none_sc, STATE_UNKNOWN); + } + mp_add_subcheck_to_check(&overall, none_sc); } - char *ignored_preamble = " - ignored paths:"; - printf("DISK %s%s%s%s%s|%s\n", state_text(result), (config.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; } @@ -409,11 +347,15 @@ check_disk_config_wrapper process_arguments(int argc, char **argv) { return result; } + enum { + output_format_index = CHAR_MAX + 1, + display_unit_index, + }; + 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'}, @@ -446,6 +388,8 @@ check_disk_config_wrapper 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}}; for (int index = 1; index < argc; index++) { @@ -456,6 +400,17 @@ check_disk_config_wrapper process_arguments(int argc, char **argv) { 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; + + bool path_selected = false; + char *group = NULL; + byte_unit unit = MebiBytes; + result.config.mount_list = read_file_system_list(false); np_add_regex(&result.config.fs_exclude_list, "iso9660", REG_EXTENDED); @@ -485,24 +440,24 @@ check_disk_config_wrapper process_arguments(int argc, char **argv) { if (strstr(optarg, "%")) { if (*optarg == '@') { - result.config.warn_freespace_percent = optarg; + warn_freespace_percent = optarg; } else { - xasprintf(&result.config.warn_freespace_percent, "@%s", optarg); + xasprintf(&warn_freespace_percent, "@%s", optarg); } } else { if (*optarg == '@') { - result.config.warn_freespace_units = optarg; + warn_freespace_units = optarg; } else { - xasprintf(&result.config.warn_freespace_units, "@%s", optarg); + xasprintf(&warn_freespace_units, "@%s", optarg); } } 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); @@ -510,84 +465,92 @@ check_disk_config_wrapper process_arguments(int argc, char **argv) { if (strstr(optarg, "%")) { if (*optarg == '@') { - result.config.crit_freespace_percent = optarg; + crit_freespace_percent = optarg; } else { - xasprintf(&result.config.crit_freespace_percent, "@%s", optarg); + xasprintf(&crit_freespace_percent, "@%s", optarg); } } else { if (*optarg == '@') { - result.config.crit_freespace_units = optarg; + crit_freespace_units = optarg; } else { - xasprintf(&result.config.crit_freespace_units, "@%s", optarg); + xasprintf(&crit_freespace_units, "@%s", optarg); } } break; case 'W': /* warning inode threshold */ if (*optarg == '@') { - result.config.warn_freeinodes_percent = optarg; + warn_freeinodes_percent = optarg; } else { - xasprintf(&result.config.warn_freeinodes_percent, "@%s", optarg); + xasprintf(&warn_freeinodes_percent, "@%s", optarg); } break; case 'K': /* critical inode threshold */ if (*optarg == '@') { - result.config.crit_freeinodes_percent = optarg; + crit_freeinodes_percent = optarg; } else { - xasprintf(&result.config.crit_freeinodes_percent, "@%s", optarg); + xasprintf(&crit_freeinodes_percent, "@%s", optarg); } break; case 'u': - free(result.config.units); if (!strcasecmp(optarg, "bytes")) { - result.config.mult = (uintmax_t)1; - result.config.units = strdup("B"); + unit = Bytes; } else if (!strcmp(optarg, "KiB")) { - result.config.mult = (uintmax_t)1024; - result.config.units = strdup("KiB"); + unit = KibiBytes; } else if (!strcmp(optarg, "kB")) { - result.config.mult = (uintmax_t)1000; - result.config.units = strdup("kB"); + unit = KiloBytes; } else if (!strcmp(optarg, "MiB")) { - result.config.mult = (uintmax_t)1024 * 1024; - result.config.units = strdup("MiB"); + unit = MebiBytes; } else if (!strcmp(optarg, "MB")) { - result.config.mult = (uintmax_t)1000 * 1000; - result.config.units = strdup("MB"); + unit = MegaBytes; } else if (!strcmp(optarg, "GiB")) { - result.config.mult = (uintmax_t)1024 * 1024 * 1024; - result.config.units = strdup("GiB"); + unit = GibiBytes; } else if (!strcmp(optarg, "GB")) { - result.config.mult = (uintmax_t)1000 * 1000 * 1000; - result.config.units = strdup("GB"); + unit = GigaBytes; } else if (!strcmp(optarg, "TiB")) { - result.config.mult = (uintmax_t)1024 * 1024 * 1024 * 1024; - result.config.units = strdup("TiB"); + unit = TebiBytes; } else if (!strcmp(optarg, "TB")) { - result.config.mult = (uintmax_t)1000 * 1000 * 1000 * 1000; - result.config.units = strdup("TB"); + unit = TeraBytes; } else if (!strcmp(optarg, "PiB")) { - result.config.mult = (uintmax_t)1024 * 1024 * 1024 * 1024 * 1024; - result.config.units = strdup("PiB"); + unit = PebiBytes; } else if (!strcmp(optarg, "PB")) { - result.config.mult = (uintmax_t)1000 * 1000 * 1000 * 1000 * 1000; - result.config.units = strdup("PB"); + unit = PetaBytes; } else { die(STATE_UNKNOWN, _("unit type %s not known\n"), optarg); } - if (result.config.units == NULL) { - die(STATE_UNKNOWN, _("failed allocating storage for '%s'\n"), "units"); - } break; - case 'k': /* display mountpoint */ - result.config.mult = 1024; - free(result.config.units); - result.config.units = strdup("kiB"); + case 'k': + unit = KibiBytes; break; - case 'm': /* display mountpoint */ - result.config.mult = 1024 * 1024; - free(result.config.units); - result.config.units = strdup("MiB"); + case 'm': + unit = MebiBytes; + 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': result.config.stat_remote_fs = true; @@ -599,43 +562,34 @@ check_disk_config_wrapper process_arguments(int argc, char **argv) { result.config.display_inodes_perfdata = true; break; case 'p': /* select path */ { - if (!(result.config.warn_freespace_units || result.config.crit_freespace_units || result.config.warn_freespace_percent || - result.config.crit_freespace_percent || result.config.warn_usedspace_units || result.config.crit_usedspace_units || - result.config.warn_usedspace_percent || result.config.crit_usedspace_percent || result.config.warn_usedinodes_percent || - result.config.crit_usedinodes_percent || result.config.warn_freeinodes_percent || - result.config.crit_freeinodes_percent)) { + if (!(warn_freespace_units || crit_freespace_units || warn_freespace_percent || crit_freespace_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 */ - struct parameter_list *se; - if (!(se = np_find_parameter(result.config.path_select_list, optarg))) { - se = np_add_parameter(&result.config.path_select_list, optarg); - - struct stat stat_buf = {}; - if (stat(optarg, &stat_buf) && result.config.ignore_missing) { - result.config.path_ignored = true; - break; - } + 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); + + // struct stat stat_buf = {}; + // if (stat(optarg, &stat_buf) && result.config.ignore_missing) { + // result.config.path_ignored = true; + // break; + // } } - se->group = result.config.group; - set_all_thresholds( - se, result.config.warn_freespace_units, result.config.crit_freespace_units, result.config.warn_freespace_percent, - result.config.crit_freespace_percent, result.config.warn_usedspace_units, result.config.crit_usedspace_units, - result.config.warn_usedspace_percent, result.config.crit_usedspace_percent, result.config.warn_usedinodes_percent, - result.config.crit_usedinodes_percent, result.config.warn_freeinodes_percent, result.config.crit_freeinodes_percent); + 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, result.config.ignore_missing)) { - 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 */ - result.config.mount_list = read_file_system_list(false); - np_set_best_match(se, result.config.mount_list, result.config.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); - result.config.path_selected = true; + path_selected = true; } break; case 'x': /* exclude path or partition */ np_add_name(&result.config.device_path_exclude_list, optarg); @@ -667,7 +621,7 @@ check_disk_config_wrapper process_arguments(int argc, char **argv) { result.config.erronly = true; break; case 'E': - if (result.config.path_selected) { + if (path_selected) { die(STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set -E before selecting paths\n")); } result.config.exact_match = true; @@ -676,16 +630,16 @@ check_disk_config_wrapper process_arguments(int argc, char **argv) { result.config.freespace_ignore_reserved = true; break; case 'g': - if (result.config.path_selected) { + if (path_selected) { die(STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set group value before selecting paths\n")); } - result.config.group = optarg; + group = optarg; break; case 'I': cflags |= REG_ICASE; // Intentional fallthrough case 'i': { - if (!result.config.path_selected) { + 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")); } @@ -697,29 +651,20 @@ check_disk_config_wrapper process_arguments(int argc, char **argv) { die(STATE_UNKNOWN, "DISK %s: %s - %s\n", _("UNKNOWN"), _("Could not compile regular expression"), errbuf); } - struct parameter_list *temp_list = result.config.path_select_list; - struct parameter_list *previous = NULL; - while (temp_list) { - if (temp_list->best_match) { - if (np_regex_match_mount_entry(temp_list->best_match, ®ex)) { + 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)) { if (verbose >= 3) { - printf("ignoring %s matching regex\n", temp_list->name); + printf("ignoring %s matching regex\n", elem->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) { - result.config.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; @@ -734,11 +679,8 @@ check_disk_config_wrapper process_arguments(int argc, char **argv) { cflags |= REG_ICASE; // Intentional fallthrough case 'r': { - if (!(result.config.warn_freespace_units || result.config.crit_freespace_units || result.config.warn_freespace_percent || - result.config.crit_freespace_percent || result.config.warn_usedspace_units || result.config.crit_usedspace_units || - result.config.warn_usedspace_percent || result.config.crit_usedspace_percent || result.config.warn_usedinodes_percent || - result.config.crit_usedinodes_percent || result.config.warn_freeinodes_percent || - result.config.crit_freeinodes_percent)) { + if (!(warn_freespace_units || crit_freespace_units || warn_freespace_percent || crit_freespace_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")); } @@ -760,31 +702,28 @@ check_disk_config_wrapper process_arguments(int argc, char **argv) { } /* add parameter if not found. overwrite thresholds if path has already been added */ - struct parameter_list *se = NULL; - if (!(se = np_find_parameter(result.config.path_select_list, me->me_mountdir))) { - se = np_add_parameter(&result.config.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 = result.config.group; - set_all_thresholds(se, result.config.warn_freespace_units, result.config.crit_freespace_units, - result.config.warn_freespace_percent, result.config.crit_freespace_percent, - result.config.warn_usedspace_units, result.config.crit_usedspace_units, - result.config.warn_usedspace_percent, result.config.crit_usedspace_percent, - result.config.warn_usedinodes_percent, result.config.crit_usedinodes_percent, - result.config.warn_freeinodes_percent, result.config.crit_freeinodes_percent); + se->group = group; + set_all_thresholds(se, warn_freespace_units, crit_freespace_units, warn_freespace_percent, crit_freespace_percent, + warn_freeinodes_percent, crit_freeinodes_percent); } } - if (!found && result.config.ignore_missing) { - result.config.path_ignored = true; - result.config.path_selected = true; - break; - } 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); } - result.config.path_selected = true; - np_set_best_match(result.config.path_select_list, result.config.mount_list, result.config.exact_match); + path_selected = true; + mp_int_fs_list_set_best_match(result.config.path_select_list, result.config.mount_list, result.config.exact_match); cflags = default_cflags; } break; @@ -793,37 +732,28 @@ check_disk_config_wrapper process_arguments(int argc, char **argv) { break; case 'C': { /* add all mount entries to path_select list if no partitions have been explicitly defined using -p */ - if (!result.config.path_selected) { - struct parameter_list *path; + if (!path_selected) { + parameter_list_elem *path; for (struct mount_entry *me = result.config.mount_list; me; me = me->me_next) { - if (!(path = np_find_parameter(result.config.path_select_list, me->me_mountdir))) { - path = np_add_parameter(&result.config.path_select_list, me->me_mountdir); + 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 = result.config.group; - set_all_thresholds(path, result.config.warn_freespace_units, result.config.crit_freespace_units, - result.config.warn_freespace_percent, result.config.crit_freespace_percent, - result.config.warn_usedspace_units, result.config.crit_usedspace_units, - result.config.warn_usedspace_percent, result.config.crit_usedspace_percent, - result.config.warn_usedinodes_percent, result.config.crit_usedinodes_percent, - result.config.warn_freeinodes_percent, result.config.crit_freeinodes_percent); + 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); } } - result.config.warn_freespace_units = NULL; - result.config.crit_freespace_units = NULL; - result.config.warn_usedspace_units = NULL; - result.config.crit_usedspace_units = NULL; - result.config.warn_freespace_percent = NULL; - result.config.crit_freespace_percent = NULL; - result.config.warn_usedspace_percent = NULL; - result.config.crit_usedspace_percent = NULL; - result.config.warn_usedinodes_percent = NULL; - result.config.crit_usedinodes_percent = NULL; - result.config.warn_freeinodes_percent = NULL; - result.config.crit_freeinodes_percent = NULL; - - result.config.path_selected = false; - result.config.group = NULL; + + warn_freespace_units = NULL; + crit_freespace_units = NULL; + warn_freespace_percent = NULL; + crit_freespace_percent = NULL; + warn_freeinodes_percent = NULL; + crit_freeinodes_percent = NULL; + + path_selected = false; + group = NULL; } break; case 'V': /* version */ print_revision(progname, NP_VERSION); @@ -833,68 +763,145 @@ check_disk_config_wrapper 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 */ int index = optind; - if (result.config.warn_usedspace_percent == NULL && argc > index && is_intnonneg(argv[index])) { + if (argc > index && is_intnonneg(argv[index])) { if (verbose > 0) { printf("Got an positional warn threshold: %s\n", argv[index]); } - result.config.warn_usedspace_percent = 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; + + warn_freespace_percent = mp_range_to_string(tmp_range); + + if (verbose > 0) { + printf("Positional warning threshold transformed to: %s\n", warn_freespace_percent); + } } - if (result.config.crit_usedspace_percent == NULL && argc > index && is_intnonneg(argv[index])) { + if (argc > index && is_intnonneg(argv[index])) { if (verbose > 0) { printf("Got an positional crit threshold: %s\n", argv[index]); } - result.config.crit_usedspace_percent = 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 = np_add_parameter(&result.config.path_select_list, strdup(argv[index++])); - result.config.path_selected = true; - set_all_thresholds(se, result.config.warn_freespace_units, result.config.crit_freespace_units, result.config.warn_freespace_percent, - result.config.crit_freespace_percent, result.config.warn_usedspace_units, result.config.crit_usedspace_units, - result.config.warn_usedspace_percent, result.config.crit_usedspace_percent, - result.config.warn_usedinodes_percent, result.config.crit_usedinodes_percent, - result.config.warn_freeinodes_percent, result.config.crit_freeinodes_percent); + struct parameter_list *se = mp_int_fs_list_append(&result.config.path_select_list, strdup(argv[index++])); + path_selected = true; + set_all_thresholds(se, warn_freespace_units, crit_freespace_units, warn_freespace_percent, crit_freespace_percent, + warn_freeinodes_percent, crit_freeinodes_percent); } - if (result.config.units == NULL) { - result.config.units = strdup("MiB"); - result.config.mult = (uintmax_t)1024 * 1024; + // If a list of paths has not been explicitely 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); + } + } + + // 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, char *warn_freespace_units, char *crit_freespace_units, char *warn_freespace_percent, - char *crit_freespace_percent, char *warn_usedspace_units, char *crit_usedspace_units, char *warn_usedspace_percent, - char *crit_usedspace_percent, char *warn_usedinodes_percent, char *crit_usedinodes_percent, - char *warn_freeinodes_percent, char *crit_freeinodes_percent) { - free(path->freespace_units); - set_thresholds(&path->freespace_units, warn_freespace_units, crit_freespace_units); +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); + } - free(path->freespace_percent); - set_thresholds(&path->freespace_percent, warn_freespace_percent, crit_freespace_percent); + if (crit_freespace_units) { + tmp = mp_parse_range_string(crit_freespace_units); + path->freespace_units = mp_thresholds_set_crit(path->freespace_units, tmp.range); + } - free(path->usedspace_units); - set_thresholds(&path->usedspace_units, warn_usedspace_units, crit_usedspace_units); + if (warn_freespace_percent) { + tmp = mp_parse_range_string(warn_freespace_percent); + path->freespace_percent = mp_thresholds_set_warn(path->freespace_percent, tmp.range); + } - free(path->usedspace_percent); - set_thresholds(&path->usedspace_percent, warn_usedspace_percent, crit_usedspace_percent); + if (crit_freespace_percent) { + tmp = mp_parse_range_string(crit_freespace_percent); + path->freespace_percent = mp_thresholds_set_crit(path->freespace_percent, tmp.range); + } - free(path->usedinodes_percent); - set_thresholds(&path->usedinodes_percent, warn_usedinodes_percent, crit_usedinodes_percent); + if (warn_freeinodes_percent) { + tmp = mp_parse_range_string(warn_freeinodes_percent); + path->freeinodes_percent = mp_thresholds_set_warn(path->freeinodes_percent, tmp.range); + } - free(path->freeinodes_percent); - set_thresholds(&path->freeinodes_percent, warn_freeinodes_percent, crit_freeinodes_percent); + 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) { @@ -941,8 +948,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"); @@ -950,8 +955,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"); @@ -967,12 +970,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:")); @@ -1002,7 +1018,7 @@ void print_usage(void) { printf("[-t timeout] [-u unit] [-v] [-X type_regex] [-N type]\n"); } -bool stat_path(struct parameter_list *parameters, bool ignore_missing) { +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", parameters->name); @@ -1023,97 +1039,166 @@ bool stat_path(struct parameter_list *parameters, bool ignore_missing) { return true; } -void get_stats(struct parameter_list *parameters, struct fs_usage *fsp, bool ignore_missing, bool freespace_ignore_reserved, uintmax_t mult, - struct parameter_list *path_select_list, struct name_list *seen) { - struct fs_usage tmpfsp; - bool first = true; - - if (parameters->group == NULL) { - get_path_stats(parameters, fsp, freespace_ignore_reserved, mult, seen); - } else { - /* find all group members */ - for (struct parameter_list *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, parameters->group))) { - if (!stat_path(p_list, ignore_missing)) { - continue; - } - get_fs_usage(p_list->best_match->me_mountdir, p_list->best_match->me_devname, &tmpfsp); - get_path_stats(p_list, &tmpfsp, freespace_ignore_reserved, mult, seen); - 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) { - parameters->total += p_list->total; - parameters->available += p_list->available; - parameters->available_to_root += p_list->available_to_root; - parameters->used += p_list->used; - - parameters->dused_units += p_list->dused_units; - parameters->dfree_units += p_list->dfree_units; - parameters->dtotal_units += p_list->dtotal_units; - parameters->inodes_total += p_list->inodes_total; - parameters->inodes_free += p_list->inodes_free; - parameters->inodes_free_to_root += p_list->inodes_free_to_root; - parameters->inodes_used += p_list->inodes_used; - } - first = false; - } - if (verbose >= 3) { - printf("Group %s now has: used_units=%lu free_units=%lu total_units=%lu fsu_blocksize=%lu mult=%lu\n", parameters->group, - parameters->dused_units, parameters->dfree_units, parameters->dtotal_units, tmpfsp.fsu_blocksize, mult); - } - } - /* modify devname and mountdir for output */ - parameters->best_match->me_mountdir = parameters->best_match->me_devname = parameters->group; - } - /* finally calculate percentages for either plain FS or summed up group */ - parameters->dused_pct = - calculate_percent(parameters->used, parameters->used + parameters->available); /* used + available can never be > uintmax */ - parameters->dfree_pct = 100.0 - parameters->dused_pct; - parameters->dused_inodes_percent = calculate_percent(parameters->inodes_total - parameters->inodes_free, parameters->inodes_total); - parameters->dfree_inodes_percent = 100 - parameters->dused_inodes_percent; -} +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; -void get_path_stats(struct parameter_list *parameters, struct fs_usage *fsp, bool freespace_ignore_reserved, uintmax_t mult, - struct name_list *seen) { - parameters->available = fsp->fsu_bavail; - parameters->available_to_root = fsp->fsu_bfree; - parameters->used = fsp->fsu_blocks - fsp->fsu_bfree; if (freespace_ignore_reserved) { /* option activated : we subtract the root-reserved space from the total */ - parameters->total = fsp->fsu_blocks - parameters->available_to_root + parameters->available; + total = fsp.fsu_blocks - available_to_root + available; } else { /* default behaviour : take all the blocks into account */ - parameters->total = fsp->fsu_blocks; + total = fsp.fsu_blocks; } - parameters->dused_units = parameters->used * fsp->fsu_blocksize / mult; - parameters->dfree_units = parameters->available * fsp->fsu_blocksize / mult; - parameters->dtotal_units = parameters->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...*/ - 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; + 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 */ - parameters->inodes_total = fsp->fsu_files - parameters->inodes_free_to_root + parameters->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 */ - parameters->inodes_total = fsp->fsu_files; + parameters.inodes_total = fsp.fsu_files; + } + + 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(measurement_unit.total_bytes, false)); } - np_add_name(&seen, parameters->best_match->me_mountdir); + + 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/config.h b/plugins/check_disk.d/config.h deleted file mode 100644 index d890fc1a..00000000 --- a/plugins/check_disk.d/config.h +++ /dev/null @@ -1,92 +0,0 @@ -#pragma once - -#include "../../config.h" -#include -#include - -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 ignore_missing; - bool path_ignored; - bool path_selected; - bool freespace_ignore_reserved; - - char *warn_freespace_units; - char *crit_freespace_units; - char *warn_freespace_percent; - char *crit_freespace_percent; - char *warn_usedspace_units; - char *crit_usedspace_units; - char *warn_usedspace_percent; - char *crit_usedspace_percent; - char *warn_usedinodes_percent; - char *crit_usedinodes_percent; - char *warn_freeinodes_percent; - char *crit_freeinodes_percent; - - /* 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; - struct parameter_list *path_select_list; - /* Linked list of mounted filesystems. */ - struct mount_entry *mount_list; - struct name_list *seen; - - char *units; - uintmax_t mult; - char *group; -} check_disk_config; - -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, - .ignore_missing = false, - .path_ignored = false, - .path_selected = false, - .freespace_ignore_reserved = false, - - .warn_freespace_units = NULL, - .crit_freespace_units = NULL, - .warn_freespace_percent = NULL, - .crit_freespace_percent = NULL, - .warn_usedspace_units = NULL, - .crit_usedspace_units = 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, - - .fs_exclude_list = NULL, - .fs_include_list = NULL, - .device_path_exclude_list = NULL, - .path_select_list = NULL, - .mount_list = NULL, - .seen = NULL, - - .units = NULL, - .mult = 1024 * 1024, - .group = NULL, - }; - return tmp; -} diff --git a/plugins/check_disk.d/utils_disk.c b/plugins/check_disk.d/utils_disk.c index 369c85d5..3986a8a8 100644 --- a/plugins/check_disk.d/utils_disk.c +++ b/plugins/check_disk.d/utils_disk.c @@ -29,7 +29,12 @@ #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; @@ -70,82 +75,367 @@ int np_add_regex(struct regex_list **list, const char *regex, int cflags) { return regcomp_result; } -struct parameter_list parameter_list_init(const char *name) { - struct parameter_list result = { +parameter_list_elem parameter_list_init(const char *name) { + parameter_list_elem result = { .name = strdup(name), .best_match = NULL, - .name_next = NULL, - .name_prev = NULL, - - .freespace_units = NULL, - .freespace_percent = NULL, - .usedspace_units = NULL, - .usedspace_percent = NULL, - .usedinodes_percent = NULL, - .freeinodes_percent = NULL, + .freespace_units = mp_thresholds_init(), + .freespace_percent = mp_thresholds_init(), + .freeinodes_percent = mp_thresholds_init(), .group = NULL, - .dfree_pct = -1, - .dused_pct = -1, - .total = 0, - .available = 0, - .available_to_root = 0, - .used = 0, - .dused_units = 0, - .dfree_units = 0, - .dtotal_units = 0, + .inodes_total = 0, .inodes_free = 0, .inodes_free_to_root = 0, .inodes_used = 0, - .dused_inodes_percent = 0, - .dfree_inodes_percent = 0, + + .used_bytes = 0, + .free_bytes = 0, + .total_bytes = 0, + + .next = NULL, + .prev = NULL, }; return 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); +/* 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 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(uintmax_t 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")); + } + + if (use_si_units) { + // SI units, powers of 10 + if (value < KiloBytes) { + snprintf(result, RANDOM_STRING_LENGTH, "%ju B", value); + } else if (value < MegaBytes) { + snprintf(result, RANDOM_STRING_LENGTH, "%ju KB", value / KiloBytes); + } else if (value < GigaBytes) { + snprintf(result, RANDOM_STRING_LENGTH, "%ju MB", value / MegaBytes); + } else if (value < TeraBytes) { + snprintf(result, RANDOM_STRING_LENGTH, "%ju GB", value / GigaBytes); + } else if (value < PetaBytes) { + snprintf(result, RANDOM_STRING_LENGTH, "%ju TB", value / TeraBytes); + } else { + snprintf(result, RANDOM_STRING_LENGTH, "%ju PB", value / PetaBytes); + } + } else { + // IEC units, powers of 2 ^ 10 + if (value < KibiBytes) { + snprintf(result, RANDOM_STRING_LENGTH, "%ju B", value); + } else if (value < MebiBytes) { + snprintf(result, RANDOM_STRING_LENGTH, "%ju KiB", value / KibiBytes); + } else if (value < GibiBytes) { + snprintf(result, RANDOM_STRING_LENGTH, "%ju MiB", value / MebiBytes); + } else if (value < TebiBytes) { + snprintf(result, RANDOM_STRING_LENGTH, "%ju GiB", value / GibiBytes); + } else if (value < PebiBytes) { + snprintf(result, RANDOM_STRING_LENGTH, "%ju TiB", value / TebiBytes); + } else { + snprintf(result, RANDOM_STRING_LENGTH, "%ju PiB", value / PebiBytes); + } + } + + 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 = new_path; - new_path->name_prev = NULL; + list->first = new_path; + new_path->prev = NULL; + list->length = 1; } else { - while (current->name_next) { - current = current->name_next; + while (current->next) { + current = current->next; } - current->name_next = new_path; - new_path->name_prev = current; + current->next = new_path; + new_path->prev = current; + list->length++; } 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) { +parameter_list_elem *mp_int_fs_list_find(filesystem_list list, const char *name) { + if (list.length == 0) { return NULL; } - struct parameter_list *next; + for (parameter_list_elem *temp_list = list.first; temp_list; temp_list = temp_list->next) { + if (!strcmp(temp_list->name, name)) { + return temp_list; + } + } - if (item->name_next) { - next = item->name_next; - } else { - next = NULL; + return NULL; +} + +parameter_list_elem *mp_int_fs_list_del(filesystem_list *list, parameter_list_elem *item) { + if (list->length == 0) { + return NULL; } - if (next) { - next->name_prev = prev; + 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 (prev) { - prev->name_next = next; + 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) { @@ -156,29 +446,23 @@ struct parameter_list *np_del_parameter(struct parameter_list *item, struct para 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) { - for (struct parameter_list *temp_list = list; temp_list; temp_list = temp_list->name_next) { - if (!strcmp(temp_list->name, name)) { - return temp_list; - } +parameter_list_elem *mp_int_fs_list_get_next(parameter_list_elem *current) { + if (!current) { + return NULL; } - - return NULL; + return current->next; } -void np_set_best_match(struct parameter_list *desired, struct mount_entry *mount_list, bool exact) { - for (struct parameter_list *d = desired; d; d = d->name_next) { - if (!d->best_match) { - struct mount_entry *mount_entry; - size_t name_len = strlen(d->name); - size_t best_match_len = 0; +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; - struct fs_usage fsp; /* set best match if path name exactly matches a mounted device name */ - for (mount_entry = mount_list; mount_entry; mount_entry = mount_entry->me_next) { - if (strcmp(mount_entry->me_devname, d->name) == 0) { + 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; } @@ -187,11 +471,15 @@ void np_set_best_match(struct parameter_list *desired, struct mount_entry *mount /* set best match by directory name if no match was found by devname */ if (!best_match) { - for (mount_entry = mount_list; mount_entry; mount_entry = mount_entry->me_next) { + 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, d->name, len) == 0))) || - (exact && strcmp(mount_entry->me_mountdir, d->name) == 0)) { + (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; @@ -201,56 +489,13 @@ void np_set_best_match(struct parameter_list *desired, struct mount_entry *mount } if (best_match) { - d->best_match = best_match; + elem->best_match = best_match; } else { - d->best_match = NULL; /* Not sure why this is needed as it should be null on initialisation */ + elem->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) { - if (list == NULL || name == NULL) { - return false; - } - for (struct name_list *n = list; n; n = n->next) { - if (!strcmp(name, n->name)) { - return true; + // No filesystem without a mount_entry! + // assert(elem->best_match != NULL); } } - 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; - } - - int 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 m; - 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) { - for (struct name_list *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) { - return ((regexec(re, me->me_devname, (size_t)0, NULL, 0) == 0) || (regexec(re, me->me_mountdir, (size_t)0, NULL, 0) == 0)); } diff --git a/plugins/check_disk.d/utils_disk.h b/plugins/check_disk.d/utils_disk.h index 0c69f987..a66453ea 100644 --- a/plugins/check_disk.d/utils_disk.h +++ b/plugins/check_disk.d/utils_disk.h @@ -1,14 +1,34 @@ +#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 enum : unsigned long { + Humanized = 0, + Bytes = 1, + KibiBytes = 1024, + MebiBytes = 1024 * KibiBytes, + GibiBytes = 1024 * MebiBytes, + TebiBytes = 1024 * GibiBytes, + PebiBytes = 1024 * TebiBytes, + ExbiBytes = 1024 * PebiBytes, + KiloBytes = 1000, + MegaBytes = 1000 * KiloBytes, + GigaBytes = 1000 * MegaBytes, + TeraBytes = 1000 * GigaBytes, + PetaBytes = 1000 * TeraBytes, + ExaBytes = 1000 * PetaBytes +} byte_unit; + +typedef struct name_list string_list; struct name_list { char *name; - struct name_list *next; + string_list *next; }; struct regex_list { @@ -16,54 +36,120 @@ struct regex_list { struct regex_list *next; }; +typedef struct parameter_list parameter_list_elem; struct parameter_list { char *name; char *group; - thresholds *freespace_units; - thresholds *freespace_percent; - thresholds *usedspace_units; - thresholds *usedspace_percent; - - thresholds *usedinodes_percent; - thresholds *freeinodes_percent; + mp_thresholds freespace_units; + mp_thresholds freespace_percent; + mp_thresholds freeinodes_percent; struct mount_entry *best_match; - uintmax_t total; - uintmax_t available; - uintmax_t available_to_root; - uintmax_t used; - uintmax_t inodes_free; uintmax_t inodes_free_to_root; + uintmax_t inodes_free; uintmax_t inodes_used; uintmax_t inodes_total; - double dfree_pct; - double dused_pct; + uint64_t used_bytes; + uint64_t free_bytes; + uint64_t total_bytes; - uint64_t dused_units; - uint64_t dfree_units; - uint64_t dtotal_units; + parameter_list_elem *next; + parameter_list_elem *prev; +}; + +typedef struct { + size_t length; + parameter_list_elem *first; +} filesystem_list; - double dused_inodes_percent; - double dfree_inodes_percent; +filesystem_list filesystem_list_init(); - struct parameter_list *name_next; - struct parameter_list *name_prev; +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 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); -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); -struct parameter_list parameter_list_init(const char *); +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); -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); +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); +check_disk_config check_disk_config_init(); + +char *humanize_byte_value(uintmax_t value, bool use_si_units); -- cgit v1.2.3-74-g34f1 From a4cf2e79f75dce3828be21726f10c755f652f710 Mon Sep 17 00:00:00 2001 From: Lorenz Kästle <12514511+RincewindsHat@users.noreply.github.com> Date: Sun, 30 Mar 2025 23:30:51 +0200 Subject: Remove cool, comfy c23 functionality for some dirty old hacks --- plugins/check_disk.c | 42 +++++++++++++++++++++++++++------------ plugins/check_disk.d/utils_disk.c | 2 +- plugins/check_disk.d/utils_disk.h | 38 ++++++++++++++++++----------------- 3 files changed, 50 insertions(+), 32 deletions(-) (limited to 'plugins/check_disk.d/utils_disk.h') diff --git a/plugins/check_disk.c b/plugins/check_disk.c index ddb9ee49..ac3933a6 100644 --- a/plugins/check_disk.c +++ b/plugins/check_disk.c @@ -96,6 +96,22 @@ static void print_help(void); static int verbose = 0; +// 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) { setlocale(LC_ALL, ""); bindtextdomain(PACKAGE, LOCALEDIR); @@ -409,7 +425,7 @@ check_disk_config_wrapper process_arguments(int argc, char **argv) { bool path_selected = false; char *group = NULL; - byte_unit unit = MebiBytes; + byte_unit unit = MebiBytes_factor; result.config.mount_list = read_file_system_list(false); @@ -494,25 +510,25 @@ check_disk_config_wrapper process_arguments(int argc, char **argv) { break; case 'u': if (!strcasecmp(optarg, "bytes")) { - unit = Bytes; + unit = Bytes_Factor; } else if (!strcmp(optarg, "KiB")) { - unit = KibiBytes; + unit = KibiBytes_factor; } else if (!strcmp(optarg, "kB")) { - unit = KiloBytes; + unit = KiloBytes_factor; } else if (!strcmp(optarg, "MiB")) { - unit = MebiBytes; + unit = MebiBytes_factor; } else if (!strcmp(optarg, "MB")) { - unit = MegaBytes; + unit = MegaBytes_factor; } else if (!strcmp(optarg, "GiB")) { - unit = GibiBytes; + unit = MegaBytes_factor; } else if (!strcmp(optarg, "GB")) { - unit = GigaBytes; + unit = MegaBytes_factor; } else if (!strcmp(optarg, "TiB")) { - unit = TebiBytes; + unit = MegaBytes_factor; } else if (!strcmp(optarg, "TB")) { - unit = TeraBytes; + unit = MegaBytes_factor; } else if (!strcmp(optarg, "PiB")) { - unit = PebiBytes; + unit = MegaBytes_factor; } else if (!strcmp(optarg, "PB")) { unit = PetaBytes; } else { @@ -520,10 +536,10 @@ check_disk_config_wrapper process_arguments(int argc, char **argv) { } break; case 'k': - unit = KibiBytes; + unit = KibiBytes_factor; break; case 'm': - unit = MebiBytes; + unit = MebiBytes_factor; break; case display_unit_index: if (!strcasecmp(optarg, "bytes")) { diff --git a/plugins/check_disk.d/utils_disk.c b/plugins/check_disk.d/utils_disk.c index 3986a8a8..a78b4eae 100644 --- a/plugins/check_disk.d/utils_disk.c +++ b/plugins/check_disk.d/utils_disk.c @@ -180,7 +180,7 @@ check_disk_config check_disk_config_init() { return tmp; } -char *get_unit_string(byte_unit unit) { +char *get_unit_string(byte_unit_enum unit) { switch (unit) { case Bytes: return "Bytes"; diff --git a/plugins/check_disk.d/utils_disk.h b/plugins/check_disk.d/utils_disk.h index a66453ea..1f574695 100644 --- a/plugins/check_disk.d/utils_disk.h +++ b/plugins/check_disk.d/utils_disk.h @@ -8,22 +8,24 @@ #include "regex.h" #include -typedef enum : unsigned long { - Humanized = 0, - Bytes = 1, - KibiBytes = 1024, - MebiBytes = 1024 * KibiBytes, - GibiBytes = 1024 * MebiBytes, - TebiBytes = 1024 * GibiBytes, - PebiBytes = 1024 * TebiBytes, - ExbiBytes = 1024 * PebiBytes, - KiloBytes = 1000, - MegaBytes = 1000 * KiloBytes, - GigaBytes = 1000 * MegaBytes, - TeraBytes = 1000 * GigaBytes, - PetaBytes = 1000 * TeraBytes, - ExaBytes = 1000 * PetaBytes -} byte_unit; +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 { @@ -120,7 +122,7 @@ typedef struct { struct mount_entry *mount_list; struct name_list *seen; - byte_unit display_unit; + byte_unit_enum display_unit; // byte_unit unit; bool output_format_is_set; @@ -149,7 +151,7 @@ measurement_unit create_measurement_unit_from_filesystem(parameter_list_elem fil 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); +char *get_unit_string(byte_unit_enum); check_disk_config check_disk_config_init(); char *humanize_byte_value(uintmax_t value, bool use_si_units); -- cgit v1.2.3-74-g34f1 From 1b0085c2e7196aa77d605e8cb1863064a8e5189c Mon Sep 17 00:00:00 2001 From: Lorenz Kästle <12514511+RincewindsHat@users.noreply.github.com> Date: Mon, 31 Mar 2025 00:46:10 +0200 Subject: Fixes problems after a4cf2e79f75dce3828be21726f10c755f652f710 --- plugins/check_disk.c | 2 +- plugins/check_disk.d/utils_disk.c | 62 ++++++++++++++++++++++++--------------- plugins/check_disk.d/utils_disk.h | 2 +- 3 files changed, 41 insertions(+), 25 deletions(-) (limited to 'plugins/check_disk.d/utils_disk.h') diff --git a/plugins/check_disk.c b/plugins/check_disk.c index e53ec87f..515ddff0 100644 --- a/plugins/check_disk.c +++ b/plugins/check_disk.c @@ -1112,7 +1112,7 @@ mp_subcheck evaluate_filesystem(measurement_unit measurement_unit, bool display_ 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(measurement_unit.total_bytes, false)); + humanize_byte_value((unsigned long long)measurement_unit.total_bytes, false)); } mp_perfdata used_space = perfdata_init(); diff --git a/plugins/check_disk.d/utils_disk.c b/plugins/check_disk.d/utils_disk.c index a78b4eae..eec1282b 100644 --- a/plugins/check_disk.d/utils_disk.c +++ b/plugins/check_disk.d/utils_disk.c @@ -309,7 +309,7 @@ measurement_unit create_measurement_unit_from_filesystem(parameter_list_elem fil #define RANDOM_STRING_LENGTH 64 -char *humanize_byte_value(uintmax_t value, bool use_si_units) { +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 @@ -317,36 +317,52 @@ char *humanize_byte_value(uintmax_t value, bool use_si_units) { 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) { - snprintf(result, RANDOM_STRING_LENGTH, "%ju B", value); - } else if (value < MegaBytes) { - snprintf(result, RANDOM_STRING_LENGTH, "%ju KB", value / KiloBytes); - } else if (value < GigaBytes) { - snprintf(result, RANDOM_STRING_LENGTH, "%ju MB", value / MegaBytes); - } else if (value < TeraBytes) { - snprintf(result, RANDOM_STRING_LENGTH, "%ju GB", value / GigaBytes); - } else if (value < PetaBytes) { - snprintf(result, RANDOM_STRING_LENGTH, "%ju TB", value / TeraBytes); + 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, "%ju PB", value / PetaBytes); + snprintf(result, RANDOM_STRING_LENGTH, "%llu EB", value / ExaBytes_factor); } } else { // IEC units, powers of 2 ^ 10 - if (value < KibiBytes) { - snprintf(result, RANDOM_STRING_LENGTH, "%ju B", value); - } else if (value < MebiBytes) { - snprintf(result, RANDOM_STRING_LENGTH, "%ju KiB", value / KibiBytes); - } else if (value < GibiBytes) { - snprintf(result, RANDOM_STRING_LENGTH, "%ju MiB", value / MebiBytes); - } else if (value < TebiBytes) { - snprintf(result, RANDOM_STRING_LENGTH, "%ju GiB", value / GibiBytes); - } else if (value < PebiBytes) { - snprintf(result, RANDOM_STRING_LENGTH, "%ju TiB", value / TebiBytes); + 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, "%ju PiB", value / PebiBytes); + snprintf(result, RANDOM_STRING_LENGTH, "%llu EiB", value / ExbiBytes_factor); } } diff --git a/plugins/check_disk.d/utils_disk.h b/plugins/check_disk.d/utils_disk.h index 1f574695..6831d1fd 100644 --- a/plugins/check_disk.d/utils_disk.h +++ b/plugins/check_disk.d/utils_disk.h @@ -154,4 +154,4 @@ 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(uintmax_t value, bool use_si_units); +char *humanize_byte_value(unsigned long long value, bool use_si_units); -- cgit v1.2.3-74-g34f1