mirror of
https://github.com/monitoring-plugins/monitoring-plugins.git
synced 2026-02-03 18:49:29 -05:00
Some checks failed
CodeQL / Analyze (push) Has been cancelled
Spellcheck / codespell (push) Has been cancelled
Tests / Running unit and integrationt tests (push) Has been cancelled
Tests / Running rpm build test on almalinux:9 (push) Has been cancelled
Tests / Running rpm build test on fedora:latest (push) Has been cancelled
Tests / Running rpm build test on rockylinux:8 (push) Has been cancelled
* check_disk: compare inode thresholds against the correct value * check_disk: Detect free inode number correctly in tests --------- Co-authored-by: Lorenz Kästle <lorenz.kaestle@netways.de>
1308 lines
46 KiB
C
1308 lines
46 KiB
C
/*****************************************************************************
|
|
*
|
|
* Monitoring check_disk plugin
|
|
*
|
|
* License: GPL
|
|
* Copyright (c) 1999-2024 Monitoring Plugins Development Team
|
|
*
|
|
* Description:
|
|
*
|
|
* This file contains the check_disk plugin
|
|
*
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*
|
|
*****************************************************************************/
|
|
|
|
const char *progname = "check_disk";
|
|
const char *program_name = "check_disk"; /* Required for coreutils libs */
|
|
const char *copyright = "1999-2024";
|
|
const char *email = "devel@monitoring-plugins.org";
|
|
|
|
#include "states.h"
|
|
#include "common.h"
|
|
#include "output.h"
|
|
#include "perfdata.h"
|
|
#include "utils_base.h"
|
|
#include "lib/thresholds.h"
|
|
|
|
#ifdef HAVE_SYS_STAT_H
|
|
# include <sys/stat.h>
|
|
#endif
|
|
|
|
#if HAVE_INTTYPES_H
|
|
# include <inttypes.h>
|
|
#endif
|
|
|
|
#include <assert.h>
|
|
#include <stdarg.h>
|
|
#include <stdint.h>
|
|
#include <float.h>
|
|
#include "./popen.h"
|
|
#include "./utils.h"
|
|
#include "../gl/fsusage.h"
|
|
#include "../gl/mountlist.h"
|
|
#include "./check_disk.d/utils_disk.h"
|
|
|
|
#if HAVE_LIMITS_H
|
|
# include <limits.h>
|
|
#endif
|
|
|
|
#include "regex.h"
|
|
|
|
#ifdef __CYGWIN__
|
|
# include <windows.h>
|
|
# undef ERROR
|
|
# define ERROR -1
|
|
#endif
|
|
|
|
#ifdef _AIX
|
|
# pragma alloca
|
|
#endif
|
|
|
|
typedef struct {
|
|
int errorcode;
|
|
check_disk_config config;
|
|
} check_disk_config_wrapper;
|
|
static check_disk_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
|
|
|
|
static void set_all_thresholds(parameter_list_elem *path, char *warn_freespace_units,
|
|
char *crit_freespace_units, char *warn_freespace_percent,
|
|
char *crit_freespace_percent, char *warn_freeinodes_percent,
|
|
char *crit_freeinodes_percent);
|
|
static double calculate_percent(uintmax_t /*value*/, uintmax_t /*total*/);
|
|
static bool stat_path(parameter_list_elem * /*parameters*/, bool /*ignore_missing*/);
|
|
|
|
/*
|
|
* Puts the values from a struct fs_usage into a parameter_list with an additional flag to control
|
|
* how reserved and inodes should be judged (ignored or not)
|
|
*/
|
|
static parameter_list_elem get_path_stats(parameter_list_elem parameters, struct fs_usage fsp,
|
|
bool freespace_ignore_reserved);
|
|
static mp_subcheck evaluate_filesystem(measurement_unit measurement_unit,
|
|
bool display_inodes_perfdata, byte_unit unit);
|
|
|
|
void print_usage(void);
|
|
static void print_help(void);
|
|
|
|
static 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);
|
|
textdomain(PACKAGE);
|
|
|
|
#ifdef __CYGWIN__
|
|
char mountdir[32];
|
|
#endif
|
|
|
|
// Parse extra opts if any
|
|
argv = np_extra_opts(&argc, argv, progname);
|
|
|
|
check_disk_config_wrapper tmp_config = process_arguments(argc, argv);
|
|
if (tmp_config.errorcode == ERROR) {
|
|
usage4(_("Could not parse arguments"));
|
|
}
|
|
|
|
check_disk_config config = tmp_config.config;
|
|
|
|
if (config.output_format_is_set) {
|
|
mp_set_format(config.output_format);
|
|
}
|
|
|
|
if (config.erronly) {
|
|
mp_set_level_of_detail(MP_DETAIL_NON_OK_ONLY);
|
|
}
|
|
|
|
if (!config.path_ignored) {
|
|
mp_int_fs_list_set_best_match(config.path_select_list, config.mount_list,
|
|
config.exact_match);
|
|
}
|
|
|
|
// Error if no match found for specified paths
|
|
for (parameter_list_elem *elem = config.path_select_list.first; elem;) {
|
|
if (!elem->best_match && config.ignore_missing) {
|
|
/* Delete the path from the list so that it is not stat-checked later in the code. */
|
|
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"), elem->name);
|
|
}
|
|
|
|
elem = mp_int_fs_list_get_next(elem);
|
|
}
|
|
|
|
mp_check overall = mp_check_init();
|
|
if (config.path_select_list.length == 0) {
|
|
mp_subcheck none_sc = mp_subcheck_init();
|
|
xasprintf(&none_sc.output, "No filesystems were found for the provided parameters");
|
|
if (config.ignore_missing) {
|
|
none_sc = mp_set_subcheck_state(none_sc, STATE_OK);
|
|
} else {
|
|
none_sc = mp_set_subcheck_state(none_sc, STATE_UNKNOWN);
|
|
if (verbose >= 2) {
|
|
printf("None of the provided paths were found\n");
|
|
}
|
|
}
|
|
mp_add_subcheck_to_check(&overall, none_sc);
|
|
mp_exit(overall);
|
|
}
|
|
|
|
// Filter list first
|
|
for (parameter_list_elem *path = config.path_select_list.first; path;) {
|
|
if (!path->best_match) {
|
|
path = mp_int_fs_list_del(&config.path_select_list, path);
|
|
continue;
|
|
}
|
|
|
|
struct mount_entry *mount_entry = path->best_match;
|
|
|
|
#ifdef __CYGWIN__
|
|
if (strncmp(path->name, "/cygdrive/", 10) != 0 || strlen(path->name) > 11) {
|
|
path = mp_int_fs_list_del(&config.path_select_list, path);
|
|
continue;
|
|
}
|
|
|
|
char *mountdir = NULL;
|
|
snprintf(mountdir, sizeof(mountdir), "%s:\\", me->me_mountdir + 10);
|
|
if (GetDriveType(mountdir) != DRIVE_FIXED) {
|
|
mount_entry->me_remote = 1;
|
|
}
|
|
#endif
|
|
|
|
/* Remove filesystems already seen */
|
|
if (np_seen_name(config.seen, mount_entry->me_mountdir)) {
|
|
path = mp_int_fs_list_del(&config.path_select_list, path);
|
|
continue;
|
|
}
|
|
|
|
if (path->group == NULL) {
|
|
if (config.fs_exclude_list &&
|
|
np_find_regmatch(config.fs_exclude_list, mount_entry->me_type)) {
|
|
// Skip excluded fs's
|
|
path = mp_int_fs_list_del(&config.path_select_list, path);
|
|
continue;
|
|
}
|
|
|
|
if (config.device_path_exclude_list &&
|
|
(np_find_name(config.device_path_exclude_list, mount_entry->me_devname) ||
|
|
np_find_name(config.device_path_exclude_list, mount_entry->me_mountdir))) {
|
|
// Skip excluded device or mount paths
|
|
path = mp_int_fs_list_del(&config.path_select_list, path);
|
|
continue;
|
|
}
|
|
|
|
if (config.fs_include_list &&
|
|
!np_find_regmatch(config.fs_include_list, mount_entry->me_type)) {
|
|
// Skip not included fstypes
|
|
path = mp_int_fs_list_del(&config.path_select_list, path);
|
|
continue;
|
|
}
|
|
|
|
/* Skip remote filesystems if we're not interested in them */
|
|
if (mount_entry->me_remote && config.show_local_fs) {
|
|
if (config.stat_remote_fs) {
|
|
// TODO Stat here
|
|
if (!stat_path(path, config.ignore_missing) && config.ignore_missing) {
|
|
}
|
|
}
|
|
continue;
|
|
}
|
|
|
|
// TODO why stat here? remove unstatable fs?
|
|
if (!stat_path(path, config.ignore_missing)) {
|
|
// if (config.ignore_missing) {
|
|
// xasprintf(&ignored, "%s %s;", ignored, path->name);
|
|
// }
|
|
// not accessible, remove from list
|
|
path = mp_int_fs_list_del(&config.path_select_list, path);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
path = mp_int_fs_list_get_next(path);
|
|
}
|
|
|
|
// now get the actual measurements
|
|
for (parameter_list_elem *filesystem = config.path_select_list.first; filesystem;) {
|
|
// Get actual metrics here
|
|
struct mount_entry *mount_entry = filesystem->best_match;
|
|
struct fs_usage fsp = {0};
|
|
get_fs_usage(mount_entry->me_mountdir, mount_entry->me_devname, &fsp);
|
|
|
|
if (fsp.fsu_blocks != 0 && strcmp("none", mount_entry->me_mountdir) != 0) {
|
|
*filesystem = get_path_stats(*filesystem, fsp, config.freespace_ignore_reserved);
|
|
|
|
if (verbose >= 3) {
|
|
printf("For %s, used_units=%lu free_units=%lu total_units=%lu "
|
|
"fsp.fsu_blocksize=%lu\n",
|
|
mount_entry->me_mountdir, filesystem->used_bytes, filesystem->free_bytes,
|
|
filesystem->total_bytes, fsp.fsu_blocksize);
|
|
}
|
|
} else {
|
|
// failed to retrieve file system data or not mounted?
|
|
filesystem = mp_int_fs_list_del(&config.path_select_list, filesystem);
|
|
continue;
|
|
}
|
|
filesystem = mp_int_fs_list_get_next(filesystem);
|
|
}
|
|
|
|
if (verbose > 2) {
|
|
for (parameter_list_elem *filesystem = config.path_select_list.first; filesystem;
|
|
filesystem = mp_int_fs_list_get_next(filesystem)) {
|
|
assert(filesystem->best_match != NULL);
|
|
if (filesystem->best_match == NULL) {
|
|
printf("Filesystem path %s has no mount_entry!\n", filesystem->name);
|
|
} else {
|
|
// printf("Filesystem path %s has a mount_entry!\n", filesystem->name);
|
|
}
|
|
}
|
|
}
|
|
|
|
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 {
|
|
current = add_measurement_list(measurements, unit);
|
|
}
|
|
} else {
|
|
// Grouped elements are consecutive
|
|
if (measurements == NULL) {
|
|
// first entry
|
|
measurement_unit unit =
|
|
create_measurement_unit_from_filesystem(*filesystem, config.display_mntp);
|
|
unit.name = strdup(filesystem->group);
|
|
measurements = current = add_measurement_list(NULL, unit);
|
|
} else {
|
|
// if this is the first element of a group, the name of the previous entry is
|
|
// different
|
|
if (strcmp(filesystem->group, current->unit.name) != 0) {
|
|
// so, this must be the first element of a group
|
|
measurement_unit unit =
|
|
create_measurement_unit_from_filesystem(*filesystem, config.display_mntp);
|
|
unit.name = filesystem->group;
|
|
current = add_measurement_list(measurements, unit);
|
|
|
|
} else {
|
|
// NOT the first entry of a group, add info to the other one
|
|
current->unit = add_filesystem_to_measurement_unit(current->unit, *filesystem);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Process for every path in list */
|
|
if (measurements != NULL) {
|
|
for (measurement_unit_list *unit = measurements; unit; unit = unit->next) {
|
|
mp_subcheck unit_sc = evaluate_filesystem(unit->unit, config.display_inodes_perfdata,
|
|
config.display_unit);
|
|
mp_add_subcheck_to_check(&overall, unit_sc);
|
|
}
|
|
} else {
|
|
// Apparently no machting fs found
|
|
mp_subcheck none_sc = mp_subcheck_init();
|
|
xasprintf(&none_sc.output, "No filesystems were found for the provided parameters");
|
|
|
|
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);
|
|
}
|
|
|
|
mp_exit(overall);
|
|
}
|
|
|
|
double calculate_percent(uintmax_t value, uintmax_t total) {
|
|
double pct = -1;
|
|
if (value <= DBL_MAX && total != 0) {
|
|
pct = (double)value / (double)total * 100.0;
|
|
}
|
|
|
|
return pct;
|
|
}
|
|
|
|
/* process command-line arguments */
|
|
check_disk_config_wrapper process_arguments(int argc, char **argv) {
|
|
|
|
check_disk_config_wrapper result = {
|
|
.errorcode = OK,
|
|
.config = check_disk_config_init(),
|
|
};
|
|
|
|
if (argc < 2) {
|
|
result.errorcode = ERROR;
|
|
return result;
|
|
}
|
|
|
|
enum {
|
|
output_format_index = CHAR_MAX + 1,
|
|
display_unit_index,
|
|
};
|
|
|
|
static struct option longopts[] = {{"timeout", required_argument, 0, 't'},
|
|
{"warning", required_argument, 0, 'w'},
|
|
{"critical", required_argument, 0, 'c'},
|
|
{"iwarning", required_argument, 0, 'W'},
|
|
{"icritical", required_argument, 0, 'K'},
|
|
{"kilobytes", no_argument, 0, 'k'},
|
|
{"megabytes", no_argument, 0, 'm'},
|
|
{"units", required_argument, 0, 'u'},
|
|
{"path", required_argument, 0, 'p'},
|
|
{"partition", required_argument, 0, 'p'},
|
|
{"exclude_device", required_argument, 0, 'x'},
|
|
{"exclude-type", required_argument, 0, 'X'},
|
|
{"include-type", required_argument, 0, 'N'},
|
|
{"group", required_argument, 0, 'g'},
|
|
{"eregi-path", required_argument, 0, 'R'},
|
|
{"eregi-partition", required_argument, 0, 'R'},
|
|
{"ereg-path", required_argument, 0, 'r'},
|
|
{"ereg-partition", required_argument, 0, 'r'},
|
|
{"freespace-ignore-reserved", no_argument, 0, 'f'},
|
|
{"ignore-ereg-path", required_argument, 0, 'i'},
|
|
{"ignore-ereg-partition", required_argument, 0, 'i'},
|
|
{"ignore-eregi-path", required_argument, 0, 'I'},
|
|
{"ignore-eregi-partition", required_argument, 0, 'I'},
|
|
{"ignore-missing", no_argument, 0, 'n'},
|
|
{"local", no_argument, 0, 'l'},
|
|
{"stat-remote-fs", no_argument, 0, 'L'},
|
|
{"iperfdata", no_argument, 0, 'P'},
|
|
{"mountpoint", no_argument, 0, 'M'},
|
|
{"errors-only", no_argument, 0, 'e'},
|
|
{"exact-match", no_argument, 0, 'E'},
|
|
{"all", no_argument, 0, 'A'},
|
|
{"verbose", no_argument, 0, 'v'},
|
|
{"quiet", no_argument, 0, 'q'},
|
|
{"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++) {
|
|
if (strcmp("-to", argv[index]) == 0) {
|
|
strcpy(argv[index], "-t");
|
|
}
|
|
}
|
|
|
|
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_factor;
|
|
|
|
result.config.mount_list = read_file_system_list(false);
|
|
|
|
np_add_regex(&result.config.fs_exclude_list, "iso9660", REG_EXTENDED);
|
|
|
|
while (true) {
|
|
int option = 0;
|
|
int option_index = getopt_long(
|
|
argc, argv, "+?VqhvefCt:c:w:K:W:u:p:x:X:N:mklLPg:R:r:i:I:MEAn", longopts, &option);
|
|
|
|
if (option_index == -1 || option_index == EOF) {
|
|
break;
|
|
}
|
|
|
|
switch (option_index) {
|
|
case 't': /* timeout period */
|
|
if (is_integer(optarg)) {
|
|
timeout_interval = atoi(optarg);
|
|
break;
|
|
} else {
|
|
usage2(_("Timeout interval must be a positive integer"), optarg);
|
|
}
|
|
|
|
/* See comments for 'c' */
|
|
case 'w': /* warning threshold */
|
|
if (!is_percentage_expression(optarg) && !is_numeric(optarg)) {
|
|
die(STATE_UNKNOWN, "Argument for --warning invalid or missing: %s\n", optarg);
|
|
}
|
|
|
|
if (strstr(optarg, "%")) {
|
|
if (*optarg == '@') {
|
|
warn_freespace_percent = optarg;
|
|
} else {
|
|
xasprintf(&warn_freespace_percent, "@%s", optarg);
|
|
}
|
|
} else {
|
|
if (*optarg == '@') {
|
|
warn_freespace_units = optarg;
|
|
} else {
|
|
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
|
|
*/
|
|
case 'c': /* critical threshold */
|
|
if (!is_percentage_expression(optarg) && !is_numeric(optarg)) {
|
|
die(STATE_UNKNOWN, "Argument for --critical invalid or missing: %s\n", optarg);
|
|
}
|
|
|
|
if (strstr(optarg, "%")) {
|
|
if (*optarg == '@') {
|
|
crit_freespace_percent = optarg;
|
|
} else {
|
|
xasprintf(&crit_freespace_percent, "@%s", optarg);
|
|
}
|
|
} else {
|
|
if (*optarg == '@') {
|
|
crit_freespace_units = optarg;
|
|
} else {
|
|
xasprintf(&crit_freespace_units, "@%s", optarg);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 'W': /* warning inode threshold */
|
|
if (*optarg == '@') {
|
|
warn_freeinodes_percent = optarg;
|
|
} else {
|
|
xasprintf(&warn_freeinodes_percent, "@%s", optarg);
|
|
}
|
|
break;
|
|
case 'K': /* critical inode threshold */
|
|
if (*optarg == '@') {
|
|
crit_freeinodes_percent = optarg;
|
|
} else {
|
|
xasprintf(&crit_freeinodes_percent, "@%s", optarg);
|
|
}
|
|
break;
|
|
case 'u':
|
|
if (!strcasecmp(optarg, "bytes")) {
|
|
unit = Bytes_Factor;
|
|
} else if (!strcmp(optarg, "KiB")) {
|
|
unit = KibiBytes_factor;
|
|
} else if (!strcmp(optarg, "kB")) {
|
|
unit = KiloBytes_factor;
|
|
} else if (!strcmp(optarg, "MiB")) {
|
|
unit = MebiBytes_factor;
|
|
} else if (!strcmp(optarg, "MB")) {
|
|
unit = MegaBytes_factor;
|
|
} else if (!strcmp(optarg, "GiB")) {
|
|
unit = GibiBytes_factor;
|
|
} else if (!strcmp(optarg, "GB")) {
|
|
unit = GigaBytes_factor;
|
|
} else if (!strcmp(optarg, "TiB")) {
|
|
unit = TebiBytes_factor;
|
|
} else if (!strcmp(optarg, "TB")) {
|
|
unit = TeraBytes_factor;
|
|
} else if (!strcmp(optarg, "PiB")) {
|
|
unit = PebiBytes_factor;
|
|
} else if (!strcmp(optarg, "PB")) {
|
|
unit = PetaBytes_factor;
|
|
} else {
|
|
die(STATE_UNKNOWN, _("unit type %s not known\n"), optarg);
|
|
}
|
|
break;
|
|
case 'k':
|
|
unit = KibiBytes_factor;
|
|
break;
|
|
case 'm':
|
|
unit = MebiBytes_factor;
|
|
break;
|
|
case display_unit_index:
|
|
if (!strcasecmp(optarg, "bytes")) {
|
|
result.config.display_unit = Bytes;
|
|
} else if (!strcmp(optarg, "KiB")) {
|
|
result.config.display_unit = KibiBytes;
|
|
} else if (!strcmp(optarg, "kB")) {
|
|
result.config.display_unit = KiloBytes;
|
|
} else if (!strcmp(optarg, "MiB")) {
|
|
result.config.display_unit = MebiBytes;
|
|
} else if (!strcmp(optarg, "MB")) {
|
|
result.config.display_unit = MegaBytes;
|
|
} else if (!strcmp(optarg, "GiB")) {
|
|
result.config.display_unit = GibiBytes;
|
|
} else if (!strcmp(optarg, "GB")) {
|
|
result.config.display_unit = GigaBytes;
|
|
} else if (!strcmp(optarg, "TiB")) {
|
|
result.config.display_unit = TebiBytes;
|
|
} else if (!strcmp(optarg, "TB")) {
|
|
result.config.display_unit = TeraBytes;
|
|
} else if (!strcmp(optarg, "PiB")) {
|
|
result.config.display_unit = PebiBytes;
|
|
} else if (!strcmp(optarg, "PB")) {
|
|
result.config.display_unit = PetaBytes;
|
|
} else {
|
|
die(STATE_UNKNOWN, _("unit type %s not known\n"), optarg);
|
|
}
|
|
break;
|
|
case 'L':
|
|
result.config.stat_remote_fs = true;
|
|
/* fallthrough */
|
|
case 'l':
|
|
result.config.show_local_fs = true;
|
|
break;
|
|
case 'P':
|
|
result.config.display_inodes_perfdata = true;
|
|
break;
|
|
case 'p': /* select path */ {
|
|
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 */
|
|
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;
|
|
// }
|
|
}
|
|
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;
|
|
// }
|
|
mp_int_fs_list_set_best_match(result.config.path_select_list, result.config.mount_list,
|
|
result.config.exact_match);
|
|
|
|
path_selected = true;
|
|
} break;
|
|
case 'x': /* exclude path or partition */
|
|
np_add_name(&result.config.device_path_exclude_list, optarg);
|
|
break;
|
|
case 'X': /* exclude file system type */ {
|
|
int err = np_add_regex(&result.config.fs_exclude_list, optarg, REG_EXTENDED);
|
|
if (err != 0) {
|
|
char errbuf[MAX_INPUT_BUFFER];
|
|
regerror(err, &result.config.fs_exclude_list->regex, errbuf, MAX_INPUT_BUFFER);
|
|
die(STATE_UNKNOWN, "DISK %s: %s - %s\n", _("UNKNOWN"),
|
|
_("Could not compile regular expression"), errbuf);
|
|
}
|
|
break;
|
|
case 'N': /* include file system type */
|
|
err = np_add_regex(&result.config.fs_include_list, optarg, REG_EXTENDED);
|
|
if (err != 0) {
|
|
char errbuf[MAX_INPUT_BUFFER];
|
|
regerror(err, &result.config.fs_exclude_list->regex, errbuf, MAX_INPUT_BUFFER);
|
|
die(STATE_UNKNOWN, "DISK %s: %s - %s\n", _("UNKNOWN"),
|
|
_("Could not compile regular expression"), errbuf);
|
|
}
|
|
} break;
|
|
case 'v': /* verbose */
|
|
verbose++;
|
|
break;
|
|
case 'q': /* TODO: this function should eventually go away (removed 2007-09-20) */
|
|
/* verbose--; **replaced by line below**. -q was only a broken way of implementing -e */
|
|
result.config.erronly = true;
|
|
break;
|
|
case 'e':
|
|
result.config.erronly = true;
|
|
break;
|
|
case 'E':
|
|
if (path_selected) {
|
|
die(STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"),
|
|
_("Must set -E before selecting paths\n"));
|
|
}
|
|
result.config.exact_match = true;
|
|
break;
|
|
case 'f':
|
|
result.config.freespace_ignore_reserved = true;
|
|
break;
|
|
case 'g':
|
|
if (path_selected) {
|
|
die(STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"),
|
|
_("Must set group value before selecting paths\n"));
|
|
}
|
|
group = optarg;
|
|
break;
|
|
case 'I':
|
|
cflags |= REG_ICASE;
|
|
// Intentional fallthrough
|
|
case 'i': {
|
|
if (!path_selected) {
|
|
die(STATE_UNKNOWN, "DISK %s: %s\n", _("UNKNOWN"),
|
|
_("Paths need to be selected before using -i/-I. Use -A to select all paths "
|
|
"explicitly"));
|
|
}
|
|
regex_t regex;
|
|
int err = regcomp(®ex, optarg, cflags);
|
|
if (err != 0) {
|
|
char errbuf[MAX_INPUT_BUFFER];
|
|
regerror(err, ®ex, errbuf, MAX_INPUT_BUFFER);
|
|
die(STATE_UNKNOWN, "DISK %s: %s - %s\n", _("UNKNOWN"),
|
|
_("Could not compile regular expression"), errbuf);
|
|
}
|
|
|
|
for (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", elem->name);
|
|
}
|
|
|
|
elem = mp_int_fs_list_del(&result.config.path_select_list, elem);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
elem = mp_int_fs_list_get_next(elem);
|
|
}
|
|
|
|
cflags = default_cflags;
|
|
} break;
|
|
case 'n':
|
|
result.config.ignore_missing = true;
|
|
break;
|
|
case 'A':
|
|
optarg = strdup(".*");
|
|
// Intentional fallthrough
|
|
case 'R':
|
|
cflags |= REG_ICASE;
|
|
// Intentional fallthrough
|
|
case 'r': {
|
|
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"));
|
|
}
|
|
|
|
regex_t regex;
|
|
int err = regcomp(®ex, optarg, cflags);
|
|
if (err != 0) {
|
|
char errbuf[MAX_INPUT_BUFFER];
|
|
regerror(err, ®ex, errbuf, MAX_INPUT_BUFFER);
|
|
die(STATE_UNKNOWN, "DISK %s: %s - %s\n", _("UNKNOWN"),
|
|
_("Could not compile regular expression"), errbuf);
|
|
}
|
|
|
|
bool found = false;
|
|
for (struct mount_entry *me = result.config.mount_list; me; me = me->me_next) {
|
|
if (np_regex_match_mount_entry(me, ®ex)) {
|
|
found = true;
|
|
if (verbose >= 3) {
|
|
printf("%s %s matching expression %s\n", me->me_devname, me->me_mountdir,
|
|
optarg);
|
|
}
|
|
|
|
/* add parameter if not found. overwrite thresholds if path has already been
|
|
* added */
|
|
parameter_list_elem *se = NULL;
|
|
if (!(se = mp_int_fs_list_find(result.config.path_select_list,
|
|
me->me_mountdir))) {
|
|
se =
|
|
mp_int_fs_list_append(&result.config.path_select_list, me->me_mountdir);
|
|
}
|
|
se->group = group;
|
|
set_all_thresholds(se, warn_freespace_units, crit_freespace_units,
|
|
warn_freespace_percent, crit_freespace_percent,
|
|
warn_freeinodes_percent, crit_freeinodes_percent);
|
|
}
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
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;
|
|
case 'M': /* display mountpoint */
|
|
result.config.display_mntp = true;
|
|
break;
|
|
case 'C': {
|
|
/* add all mount entries to path_select list if no partitions have been explicitly
|
|
* defined using -p */
|
|
if (!path_selected) {
|
|
parameter_list_elem *path;
|
|
for (struct mount_entry *me = result.config.mount_list; me; me = me->me_next) {
|
|
if (!(path = mp_int_fs_list_find(result.config.path_select_list,
|
|
me->me_mountdir))) {
|
|
path =
|
|
mp_int_fs_list_append(&result.config.path_select_list, me->me_mountdir);
|
|
}
|
|
path->best_match = me;
|
|
path->group = group;
|
|
set_all_thresholds(path, warn_freespace_units, crit_freespace_units,
|
|
warn_freespace_percent, crit_freespace_percent,
|
|
warn_freeinodes_percent, crit_freeinodes_percent);
|
|
}
|
|
}
|
|
|
|
warn_freespace_units = NULL;
|
|
crit_freespace_units = NULL;
|
|
warn_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);
|
|
exit(STATE_UNKNOWN);
|
|
case 'h': /* help */
|
|
print_help();
|
|
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 (argc > index && is_intnonneg(argv[index])) {
|
|
if (verbose > 0) {
|
|
printf("Got an positional warn threshold: %s\n", argv[index]);
|
|
}
|
|
char *range = argv[index++];
|
|
mp_range_parsed tmp = mp_parse_range_string(range);
|
|
if (tmp.error != MP_PARSING_SUCCES) {
|
|
die(STATE_UNKNOWN, "failed to parse warning threshold");
|
|
}
|
|
|
|
mp_range tmp_range = tmp.range;
|
|
// Invert range to use it for free instead of used
|
|
// tmp_range.alert_on_inside_range = !tmp_range.alert_on_inside_range;
|
|
|
|
warn_freespace_percent = mp_range_to_string(tmp_range);
|
|
|
|
if (verbose > 0) {
|
|
printf("Positional warning threshold transformed to: %s\n", warn_freespace_percent);
|
|
}
|
|
}
|
|
|
|
if (argc > index && is_intnonneg(argv[index])) {
|
|
if (verbose > 0) {
|
|
printf("Got an positional crit threshold: %s\n", argv[index]);
|
|
}
|
|
char *range = argv[index++];
|
|
mp_range_parsed tmp = mp_parse_range_string(range);
|
|
if (tmp.error != MP_PARSING_SUCCES) {
|
|
die(STATE_UNKNOWN, "failed to parse warning threshold");
|
|
}
|
|
|
|
mp_range tmp_range = tmp.range;
|
|
// Invert range to use it for free instead of used
|
|
// tmp_range.alert_on_inside_range = !tmp_range.alert_on_inside_range;
|
|
|
|
crit_freespace_percent = mp_range_to_string(tmp_range);
|
|
|
|
if (verbose > 0) {
|
|
printf("Positional critical threshold transformed to: %s\n", crit_freespace_percent);
|
|
}
|
|
}
|
|
|
|
if (argc > index) {
|
|
if (verbose > 0) {
|
|
printf("Got an positional filesystem: %s\n", argv[index]);
|
|
}
|
|
struct parameter_list *se =
|
|
mp_int_fs_list_append(&result.config.path_select_list, strdup(argv[index++]));
|
|
path_selected = true;
|
|
set_all_thresholds(se, warn_freespace_units, crit_freespace_units, warn_freespace_percent,
|
|
crit_freespace_percent, warn_freeinodes_percent,
|
|
crit_freeinodes_percent);
|
|
}
|
|
|
|
// If a list of paths has not been explicitly selected, find entire
|
|
// mount list and create list of paths
|
|
if (!path_selected && !result.config.path_ignored) {
|
|
for (struct mount_entry *me = result.config.mount_list; me; me = me->me_next) {
|
|
if (me->me_dummy != 0) {
|
|
// just do not add dummy filesystems
|
|
continue;
|
|
}
|
|
|
|
parameter_list_elem *path = NULL;
|
|
if (!(path = mp_int_fs_list_find(result.config.path_select_list, me->me_mountdir))) {
|
|
path = mp_int_fs_list_append(&result.config.path_select_list, me->me_mountdir);
|
|
}
|
|
path->best_match = me;
|
|
path->group = group;
|
|
set_all_thresholds(path, warn_freespace_units, crit_freespace_units,
|
|
warn_freespace_percent, crit_freespace_percent,
|
|
warn_freeinodes_percent, crit_freeinodes_percent);
|
|
}
|
|
}
|
|
|
|
// 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(parameter_list_elem *path, char *warn_freespace_units,
|
|
char *crit_freespace_units, char *warn_freespace_percent,
|
|
char *crit_freespace_percent, char *warn_freeinodes_percent,
|
|
char *crit_freeinodes_percent) {
|
|
mp_range_parsed tmp;
|
|
|
|
if (warn_freespace_units) {
|
|
tmp = mp_parse_range_string(warn_freespace_units);
|
|
path->freespace_units = mp_thresholds_set_warn(path->freespace_units, tmp.range);
|
|
}
|
|
|
|
if (crit_freespace_units) {
|
|
tmp = mp_parse_range_string(crit_freespace_units);
|
|
path->freespace_units = mp_thresholds_set_crit(path->freespace_units, tmp.range);
|
|
}
|
|
|
|
if (warn_freespace_percent) {
|
|
tmp = mp_parse_range_string(warn_freespace_percent);
|
|
path->freespace_percent = mp_thresholds_set_warn(path->freespace_percent, tmp.range);
|
|
}
|
|
|
|
if (crit_freespace_percent) {
|
|
tmp = mp_parse_range_string(crit_freespace_percent);
|
|
path->freespace_percent = mp_thresholds_set_crit(path->freespace_percent, tmp.range);
|
|
}
|
|
|
|
if (warn_freeinodes_percent) {
|
|
tmp = mp_parse_range_string(warn_freeinodes_percent);
|
|
path->freeinodes_percent = mp_thresholds_set_warn(path->freeinodes_percent, tmp.range);
|
|
}
|
|
|
|
if (crit_freeinodes_percent) {
|
|
tmp = mp_parse_range_string(crit_freeinodes_percent);
|
|
path->freeinodes_percent = mp_thresholds_set_crit(path->freeinodes_percent, tmp.range);
|
|
}
|
|
}
|
|
|
|
void print_help(void) {
|
|
print_revision(progname, NP_VERSION);
|
|
|
|
printf("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
|
|
printf(COPYRIGHT, copyright, email);
|
|
|
|
printf("%s\n", _("This plugin checks the amount of used disk space on a mounted file system"));
|
|
printf("%s\n",
|
|
_("and generates an alert if free space is less than one of the threshold values"));
|
|
|
|
printf("\n\n");
|
|
|
|
print_usage();
|
|
|
|
printf(UT_HELP_VRSN);
|
|
printf(UT_EXTRA_OPTS);
|
|
|
|
printf(" %s\n", "-w, --warning=INTEGER");
|
|
printf(" %s\n", _("Exit with WARNING status if less than INTEGER units of disk are free"));
|
|
printf(" %s\n", "-w, --warning=PERCENT%");
|
|
printf(" %s\n", _("Exit with WARNING status if less than PERCENT of disk space is free"));
|
|
printf(" %s\n", "-c, --critical=INTEGER");
|
|
printf(" %s\n", _("Exit with CRITICAL status if less than INTEGER units of disk are free"));
|
|
printf(" %s\n", "-c, --critical=PERCENT%");
|
|
printf(" %s\n", _("Exit with CRITICAL status if less than PERCENT of disk space is free"));
|
|
printf(" %s\n", "-W, --iwarning=PERCENT%");
|
|
printf(" %s\n", _("Exit with WARNING status if less than PERCENT of inode space is free"));
|
|
printf(" %s\n", "-K, --icritical=PERCENT%");
|
|
printf(" %s\n", _("Exit with CRITICAL status if less than PERCENT of inode space is free"));
|
|
printf(" %s\n", "-p, --path=PATH, --partition=PARTITION");
|
|
printf(" %s\n",
|
|
_("Mount point or block device as emitted by the mount(8) command (may be repeated)"));
|
|
printf(" %s\n", "-x, --exclude_device=PATH <STRING>");
|
|
printf(" %s\n", _("Ignore device (only works if -p unspecified)"));
|
|
printf(" %s\n", "-C, --clear");
|
|
printf(" %s\n", _("Clear thresholds"));
|
|
printf(" %s\n", "-E, --exact-match");
|
|
printf(" %s\n", _("For paths or partitions specified with -p, only check for exact paths"));
|
|
printf(" %s\n", "-e, --errors-only");
|
|
printf(" %s\n", _("Display only devices/mountpoints with errors"));
|
|
printf(" %s\n", "-f, --freespace-ignore-reserved");
|
|
printf(" %s\n", _("Don't account root-reserved blocks into freespace in perfdata"));
|
|
printf(" %s\n", "-P, --iperfdata");
|
|
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", "-l, --local");
|
|
printf(" %s\n", _("Only check local filesystems"));
|
|
printf(" %s\n", "-L, --stat-remote-fs");
|
|
printf(
|
|
" %s\n",
|
|
_("Only check local filesystems against thresholds. Yet call stat on remote filesystems"));
|
|
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", "-A, --all");
|
|
printf(" %s\n", _("Explicitly select all paths. This is equivalent to -R '.*'"));
|
|
printf(" %s\n", "-R, --eregi-path=PATH, --eregi-partition=PARTITION");
|
|
printf(" %s\n",
|
|
_("Case insensitive regular expression for path/partition (may be repeated)"));
|
|
printf(" %s\n", "-r, --ereg-path=PATH, --ereg-partition=PARTITION");
|
|
printf(" %s\n", _("Regular expression for path or partition (may be repeated)"));
|
|
printf(" %s\n", "-I, --ignore-eregi-path=PATH, --ignore-eregi-partition=PARTITION");
|
|
printf(" %s\n", _("Regular expression to ignore selected path/partition (case insensitive) "
|
|
"(may be repeated)"));
|
|
printf(" %s\n", "-i, --ignore-ereg-path=PATH, --ignore-ereg-partition=PARTITION");
|
|
printf(" %s\n",
|
|
_("Regular expression to ignore selected path or partition (may be repeated)"));
|
|
printf(" %s\n", "-n, --ignore-missing");
|
|
printf(" %s\n",
|
|
_("Return OK if no filesystem matches, filesystem does not exist or is inaccessible."));
|
|
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", _("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:"));
|
|
printf(
|
|
" %s\n",
|
|
_("- Arguments are positional! \"-w 5 -c 1 -p /foo -w6 -c2 -p /bar\" is not the same as"));
|
|
printf(" %s\n", _("\"-w 5 -c 1 -p /bar w6 -c2 -p /foo\"."));
|
|
printf(" %s\n", _("- The syntax is broadly: \"{thresholds a} {paths a} -C {thresholds b} "
|
|
"{thresholds b} ...\""));
|
|
|
|
printf("\n");
|
|
printf("%s\n", _("Examples:"));
|
|
printf(" %s\n", "check_disk -w 10% -c 5% -p /tmp -p /var -C -w 100000 -c 50000 -p /");
|
|
printf(" %s\n\n", _("Checks /tmp and /var at 10% and 5%, and / at 100MB and 50MB"));
|
|
printf(" %s\n",
|
|
"check_disk -w 100 -c 50 -C -w 1000 -c 500 -g sidDATA -r '^/oracle/SID/data.*$'");
|
|
printf(
|
|
" %s\n",
|
|
_("Checks all filesystems not matching -r at 100M and 50M. The fs matching the -r regex"));
|
|
printf(" %s\n\n",
|
|
_("are grouped which means the freespace thresholds are applied to all disks together"));
|
|
printf(" %s\n", "check_disk -w 100 -c 50 -C -w 1000 -c 500 -p /foo -C -w 5% -c 3% -p /bar");
|
|
printf(" %s\n",
|
|
_("Checks /foo for 1000M/500M and /bar for 5/3%. All remaining volumes use 100M/50M"));
|
|
|
|
printf(UT_SUPPORT);
|
|
}
|
|
|
|
void print_usage(void) {
|
|
printf("%s\n", _("Usage:"));
|
|
printf(" %s {-w absolute_limit |-w percentage_limit%% | -W inode_percentage_limit } {-c "
|
|
"absolute_limit|-c percentage_limit%% | -K "
|
|
"inode_percentage_limit } {-p path | -x device}\n",
|
|
progname);
|
|
printf("[-C] [-E] [-e] [-f] [-g group ] [-k] [-l] [-M] [-m] [-R path ] [-r path ]\n");
|
|
printf("[-t timeout] [-u unit] [-v] [-X type_regex] [-N type]\n");
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
struct stat stat_buf = {0};
|
|
if (stat(parameters->name, &stat_buf)) {
|
|
if (verbose >= 3) {
|
|
printf("stat failed on %s\n", parameters->name);
|
|
}
|
|
if (ignore_missing) {
|
|
return false;
|
|
}
|
|
printf("DISK %s - ", _("CRITICAL"));
|
|
die(STATE_CRITICAL, _("%s %s: %s\n"), parameters->name, _("is not accessible"),
|
|
strerror(errno));
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static parameter_list_elem get_path_stats(parameter_list_elem parameters, const struct fs_usage fsp,
|
|
bool freespace_ignore_reserved) {
|
|
uintmax_t available = fsp.fsu_bavail;
|
|
uintmax_t available_to_root = fsp.fsu_bfree;
|
|
uintmax_t used = fsp.fsu_blocks - fsp.fsu_bfree;
|
|
uintmax_t total;
|
|
|
|
if (freespace_ignore_reserved) {
|
|
/* option activated : we subtract the root-reserved space from the total */
|
|
total = fsp.fsu_blocks - available_to_root + available;
|
|
} else {
|
|
/* default behaviour : take all the blocks into account */
|
|
total = fsp.fsu_blocks;
|
|
}
|
|
|
|
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;
|
|
|
|
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;
|
|
} else {
|
|
/* default behaviour : take all the inodes into account */
|
|
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((unsigned long long)measurement_unit.total_bytes, false));
|
|
}
|
|
|
|
mp_perfdata used_space = perfdata_init();
|
|
used_space.label = measurement_unit.name;
|
|
used_space.value = mp_create_pd_value(measurement_unit.free_bytes);
|
|
used_space = mp_set_pd_max_value(used_space, mp_create_pd_value(measurement_unit.total_bytes));
|
|
used_space = mp_set_pd_min_value(used_space, mp_create_pd_value(0));
|
|
used_space.uom = "B";
|
|
used_space = mp_pd_set_thresholds(used_space, measurement_unit.freespace_bytes_thresholds);
|
|
freespace_bytes_sc = mp_set_subcheck_state(freespace_bytes_sc, mp_get_pd_status(used_space));
|
|
|
|
// special case for absolute space thresholds here:
|
|
// if absolute values are not set, compute the thresholds from percentage thresholds
|
|
mp_thresholds temp_thlds = measurement_unit.freespace_bytes_thresholds;
|
|
if (!temp_thlds.critical_is_set &&
|
|
measurement_unit.freespace_percent_thresholds.critical_is_set) {
|
|
mp_range tmp_range = measurement_unit.freespace_percent_thresholds.critical;
|
|
|
|
if (!tmp_range.end_infinity) {
|
|
tmp_range.end = mp_create_pd_value(mp_get_pd_value(tmp_range.end) / 100 *
|
|
measurement_unit.total_bytes);
|
|
}
|
|
|
|
if (!tmp_range.start_infinity) {
|
|
tmp_range.start = mp_create_pd_value(mp_get_pd_value(tmp_range.start) / 100 *
|
|
measurement_unit.total_bytes);
|
|
}
|
|
measurement_unit.freespace_bytes_thresholds =
|
|
mp_thresholds_set_crit(measurement_unit.freespace_bytes_thresholds, tmp_range);
|
|
used_space = mp_pd_set_thresholds(used_space, measurement_unit.freespace_bytes_thresholds);
|
|
}
|
|
|
|
if (!temp_thlds.warning_is_set &&
|
|
measurement_unit.freespace_percent_thresholds.warning_is_set) {
|
|
mp_range tmp_range = measurement_unit.freespace_percent_thresholds.warning;
|
|
if (!tmp_range.end_infinity) {
|
|
tmp_range.end = mp_create_pd_value(mp_get_pd_value(tmp_range.end) / 100 *
|
|
measurement_unit.total_bytes);
|
|
}
|
|
if (!tmp_range.start_infinity) {
|
|
tmp_range.start = mp_create_pd_value(mp_get_pd_value(tmp_range.start) / 100 *
|
|
measurement_unit.total_bytes);
|
|
}
|
|
measurement_unit.freespace_bytes_thresholds =
|
|
mp_thresholds_set_warn(measurement_unit.freespace_bytes_thresholds, tmp_range);
|
|
used_space = mp_pd_set_thresholds(used_space, measurement_unit.freespace_bytes_thresholds);
|
|
}
|
|
|
|
mp_add_perfdata_to_subcheck(&freespace_bytes_sc, used_space);
|
|
mp_add_subcheck_to_subcheck(&result, freespace_bytes_sc);
|
|
|
|
// ==========================
|
|
// Free space percentage test
|
|
mp_subcheck freespace_percent_sc = mp_subcheck_init();
|
|
freespace_percent_sc = mp_set_subcheck_default_state(freespace_percent_sc, STATE_OK);
|
|
|
|
double free_percentage =
|
|
calculate_percent(measurement_unit.free_bytes, measurement_unit.total_bytes);
|
|
xasprintf(&freespace_percent_sc.output, "Free space percentage: %g%%", free_percentage);
|
|
|
|
// Using perfdata here just to get to the test result
|
|
mp_perfdata free_space_percent_pd = perfdata_init();
|
|
free_space_percent_pd.value = mp_create_pd_value(free_percentage);
|
|
free_space_percent_pd =
|
|
mp_pd_set_thresholds(free_space_percent_pd, measurement_unit.freespace_percent_thresholds);
|
|
|
|
freespace_percent_sc =
|
|
mp_set_subcheck_state(freespace_percent_sc, mp_get_pd_status(free_space_percent_pd));
|
|
mp_add_subcheck_to_subcheck(&result, freespace_percent_sc);
|
|
|
|
// ================
|
|
// Free inodes test
|
|
// Only ever useful if the number of inodes is static (e.g. ext4),
|
|
// not when it is dynamic (e.g btrfs)
|
|
// Assumption: if the total number of inodes == 0, we have such a case and just skip the test
|
|
if (measurement_unit.inodes_total > 0) {
|
|
mp_subcheck freeindodes_percent_sc = mp_subcheck_init();
|
|
freeindodes_percent_sc = mp_set_subcheck_default_state(freeindodes_percent_sc, STATE_OK);
|
|
|
|
double free_inode_percentage =
|
|
calculate_percent(measurement_unit.inodes_free, measurement_unit.inodes_total);
|
|
|
|
mp_perfdata inode_percentage_pd = perfdata_init();
|
|
inode_percentage_pd = mp_set_pd_value(inode_percentage_pd, free_inode_percentage);
|
|
inode_percentage_pd = mp_pd_set_thresholds(inode_percentage_pd, measurement_unit.freeinodes_percent_thresholds);
|
|
|
|
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(inode_percentage_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;
|
|
}
|