X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=plugins%2Fcheck_disk.c;h=3b9e36b158dc2762e8559c8ccc876e194ab95db4;hb=19b97afb125056ed6021d6f6ecf5a9b0ace2b314;hp=fd3b9770a93b014aa7ca117ee603a112a42b9516;hpb=2b5611ed6492be4d121daba00ca8cf91ccb47fa9;p=nagiosplug.git diff --git a/plugins/check_disk.c b/plugins/check_disk.c index fd3b977..3b9e36b 100644 --- a/plugins/check_disk.c +++ b/plugins/check_disk.c @@ -1,5 +1,18 @@ /****************************************************************************** * +* Nagios check_disk plugin +* +* License: GPL +* Copyright (c) 1999-2006 nagios-plugins team +* +* Last Modified: $Date$ +* +* Description: +* +* This file contains the check_disk plugin +* +* License Information: +* * 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 2 of the License, or @@ -14,75 +27,39 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * +* $Id$ +* *****************************************************************************/ const char *progname = "check_disk"; +const char *program_name = "check_disk"; /* Required for coreutils libs */ const char *revision = "$Revision$"; -const char *copyright = "1999-2003"; -const char *authors = "Nagios Plugin Development Team"; +const char *copyright = "1999-2006"; const char *email = "nagiosplug-devel@lists.sourceforge.net"; -const char *summary = "\ -This plugin checks the amount of used disk space on a mounted file system\n\ -and generates an alert if free space is less than one of the threshold values."; - -const char *option_summary = "\ --w limit -c limit [-p path | -x device] [-t timeout] [-m] [-e]\n\ - [-v] [-q]"; - -const char *options = "\ - -w, --warning=INTEGER\n\ - Exit with WARNING status if less than INTEGER kilobytes of disk are free\n\ - -w, --warning=PERCENT%%\n\ - Exit with WARNING status if less than PERCENT of disk space is free\n\ - -c, --critical=INTEGER\n\ - Exit with CRITICAL status if less than INTEGER kilobytes of disk are free\n\ - -c, --critical=PERCENT%%\n\ - Exit with CRITCAL status if less than PERCENT of disk space is free\n\ - -u, --units=STRING\n\ - Choose bytes, kB, MB, GB, TB (default: MB)\n\ - -k, --kilobytes\n\ - Same as '--units kB'\n\ - -m, --megabytes\n\ - Same as '--units MB'\n\ - -l, --local\n\ - Only check local filesystems\n\ - -p, --path=PATH, --partition=PARTITION\n\ - Path or partition (may be repeated)\n\ - -x, --exclude_device=PATH \n\ - Ignore device (only works if -p unspecified)\n\ - -X, --exclude-type=TYPE \n\ - Ignore all filesystems of indicated type (may be repeated)\n\ - -M, --mountpoint\n\ - Display the mountpoint instead of the partition\n\ - -e, --errors-only\n\ - Display only devices/mountpoints with errors\n\ - -v, --verbose\n\ - Show details for command-line debugging (do not use with nagios server)\n\ - -h, --help\n\ - Print detailed help screen\n\ - -V, --version\n\ - Print version information\n"; - -const char *notes = "\ -\n"; #include "common.h" +#ifdef HAVE_SYS_STAT_H +# include +#endif #if HAVE_INTTYPES_H # include #endif #include #include "popen.h" #include "utils.h" +#include "utils_disk.h" #include -#include "../lib/fsusage.h" -#include "../lib/mountlist.h" +#include "fsusage.h" +#include "mountlist.h" +#include "intprops.h" /* necessary for TYPE_MAXIMUM */ #if HAVE_LIMITS_H # include #endif + /* If nonzero, show inode information. */ -static int inode_format; +static int inode_format = 1; /* If nonzero, show even filesystems with zero size or uninteresting types. */ @@ -93,22 +70,13 @@ static int show_local_fs = 0; /* If positive, the units to use when printing sizes; if negative, the human-readable base. */ -static int output_block_size; +/* static int output_block_size; */ /* If nonzero, invoke the `sync' system call before getting any usage data. Using this option can make df very slow, especially with many or very busy disks. Note that this may make a difference on some systems -- SunOs4.1.3, for one. It is *not* necessary on Linux. */ -static int require_sync = 0; - -/* A filesystem type to display. */ - -struct name_list -{ - char *name; - int found; - struct name_list *name_next; -}; +/* static int require_sync = 0; */ /* Linked list of filesystem types to display. If `fs_select_list' is NULL, list all types. @@ -121,7 +89,7 @@ struct name_list Some filesystem types: 4.2 4.3 ufs nfs swap ignore io vm efs dbg */ -static struct name_list *fs_select_list; +/* static struct parameter_list *fs_select_list; */ /* Linked list of filesystem types to omit. If the list is empty, don't exclude any types. */ @@ -130,9 +98,7 @@ static struct name_list *fs_exclude_list; static struct name_list *dp_exclude_list; -static struct name_list *path_select_list; - -static struct name_list *dev_select_list; +static struct parameter_list *path_select_list = NULL; /* Linked list of mounted filesystems. */ static struct mount_entry *mount_list; @@ -150,393 +116,667 @@ enum #pragma alloca #endif +/* Linked list of mounted filesystems. */ +static struct mount_entry *mount_list; + int process_arguments (int, char **); -int validate_arguments (void); -int check_disk (int usp, int free_disk); -int walk_name_list (struct name_list *list, const char *name); +void print_path (const char *mypath); +int validate_arguments (uintmax_t, uintmax_t, double, double, double, double, char *); void print_help (void); void print_usage (void); - -int w_df = -1; -int c_df = -1; -float w_dfp = -1.0; -float c_dfp = -1.0; -char *path = ""; -char *exclude_device = ""; -char *units = "MB"; -unsigned long mult = 1024 * 1024; +double calculate_percent(uintmax_t, uintmax_t); + +double w_dfp = -1.0; +double c_dfp = -1.0; +char *path; +char *exclude_device; +char *units; +uintmax_t mult = 1024 * 1024; int verbose = 0; int erronly = FALSE; int display_mntp = FALSE; +int exact_match = FALSE; +char *warn_freespace_units = NULL; +char *crit_freespace_units = NULL; +char *warn_freespace_percent = NULL; +char *crit_freespace_percent = NULL; +char *warn_usedspace_units = NULL; +char *crit_usedspace_units = NULL; +char *warn_usedspace_percent = NULL; +char *crit_usedspace_percent = NULL; +char *warn_usedinodes_percent = NULL; +char *crit_usedinodes_percent = NULL; +char *warn_freeinodes_percent = NULL; +char *crit_freeinodes_percent = NULL; -/* Linked list of mounted filesystems. */ -static struct mount_entry *mount_list; int main (int argc, char **argv) { - int usp = -1; - int total_disk = -1; - int used_disk = -1; - int free_disk = -1; - int result = STATE_UNKNOWN; - int disk_result = STATE_UNKNOWN; - char *command_line = ""; - char input_buffer[MAX_INPUT_BUFFER]; - char file_system[MAX_INPUT_BUFFER]; - char mntp[MAX_INPUT_BUFFER]; - char *output = ""; - char *details = ""; - float free_space, free_space_pct, total_space; - - struct mount_entry *me; - struct fs_usage fsp; - struct name_list *temp_list; - char *disk; - - mount_list = read_filesystem_list (0); - - if (process_arguments (argc, argv) != OK) - usage ("Could not parse arguments\n"); - - for (me = mount_list; me; me = me->me_next) { - - if (path_select_list && - (walk_name_list (path_select_list, me->me_mountdir) || - walk_name_list (path_select_list, me->me_devname) ) ) - get_fs_usage (me->me_mountdir, me->me_devname, &fsp); - else if (dev_select_list || path_select_list) - continue; - else if (me->me_remote && show_local_fs) - continue; - else if (me->me_dummy && !show_all_fs) - continue; - else if (fs_exclude_list && walk_name_list (fs_exclude_list, me->me_type)) - continue; - else if (dp_exclude_list && - walk_name_list (dp_exclude_list, me->me_devname) || - walk_name_list (dp_exclude_list, me->me_mountdir)) - continue; - else - get_fs_usage (me->me_mountdir, me->me_devname, &fsp); - - if (fsp.fsu_blocks && strcmp ("none", me->me_mountdir)) { - usp = (fsp.fsu_blocks - fsp.fsu_bavail) * 100 / fsp.fsu_blocks; - disk_result = check_disk (usp, fsp.fsu_bavail); - result = max_state (disk_result, result); - if (disk_result==STATE_OK && erronly && !verbose) - continue; - - free_space = (float)fsp.fsu_bavail*fsp.fsu_blocksize/mult; - free_space_pct = (float)fsp.fsu_bavail*100/fsp.fsu_blocks; - total_space = (float)fsp.fsu_blocks*fsp.fsu_blocksize/mult; - if (disk_result!=STATE_OK || verbose>=0) - asprintf (&output, "%s [%.0f %s (%2.0f%%) free on %s]", - output, - free_space, - units, - free_space_pct, - (!strcmp(file_system, "none") || display_mntp) ? me->me_devname : me->me_mountdir); - asprintf (&details, "%s\n%.0f of %.0f %s (%2.0f%%) free on %s (type %s mounted on %s)", - details, - free_space, - total_space, - units, - free_space_pct, - me->me_devname, - me->me_type, - me->me_mountdir); - } - - } - - if (verbose > 2) - asprintf (&output, "%s%s", output, details); - - /* Override result if paths specified and not found */ - temp_list = path_select_list; - while (temp_list) { - if (temp_list->found != TRUE) { - asprintf (&output, "%s [%s not found]", output, temp_list->name); - result = STATE_CRITICAL; - } - temp_list = temp_list->name_next; - } - - terminate (result, "DISK %s%s\n", state_text (result), output, details); + int result = STATE_UNKNOWN; + int disk_result = STATE_UNKNOWN; + char *output; + char *details; + char *perf; + char *preamble; + double inode_space_pct; + uintmax_t total, available, available_to_root, used; + double dfree_pct = -1, dused_pct = -1; + double dused_units, dfree_units, dtotal_units; + double dused_inodes_percent, dfree_inodes_percent; + double warning_high_tide; + double critical_high_tide; + int temp_result; + + struct mount_entry *me; + struct fs_usage fsp; + struct parameter_list *temp_list, *path; + struct name_list *seen = NULL; + + preamble = strdup (" - free space:"); + output = strdup (""); + details = strdup (""); + perf = strdup (""); + + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + mount_list = read_file_system_list (0); + + if (process_arguments (argc, argv) == ERROR) + usage4 (_("Could not parse arguments")); + + /* If a list of paths has not been selected, find entire + mount list and create list of paths + */ + if (! path_select_list) { + for (me = mount_list; me; me = me->me_next) { + path = np_add_parameter(&path_select_list, me->me_mountdir); + path->best_match = me; + set_thresholds(&path->freespace_units, warn_freespace_units, crit_freespace_units); + set_thresholds(&path->freespace_percent, warn_freespace_percent, crit_freespace_percent); + set_thresholds(&path->usedspace_units, warn_usedspace_units, crit_usedspace_units); + set_thresholds(&path->usedspace_percent, warn_usedspace_percent, crit_usedspace_percent); + set_thresholds(&path->usedinodes_percent, warn_usedinodes_percent, crit_usedinodes_percent); + set_thresholds(&path->freeinodes_percent, warn_freeinodes_percent, crit_freeinodes_percent); + } + } else { + np_set_best_match(path_select_list, mount_list, exact_match); + + /* Error if no match found for specified paths */ + temp_list = path_select_list; + while (temp_list) { + if (! temp_list->best_match) { + die (STATE_CRITICAL, _("DISK %s: %s not found\n"), _("CRITICAL"), temp_list->name); + } + temp_list = temp_list->name_next; + } + } + + /* Process for every path in list */ + for (path = path_select_list; path; path=path->name_next) { + + /* reset disk result */ + disk_result = STATE_UNKNOWN; + + me = path->best_match; + + /* Filters */ + + /* Remove filesystems already seen */ + if (np_seen_name(seen, me->me_mountdir)) { + continue; + } else { + np_add_name(&seen, me->me_mountdir); + } + /* Skip remote filesystems if we're not interested in them */ + if (me->me_remote && show_local_fs) { + continue; + /* Skip pseudo fs's if we haven't asked for all fs's */ + } else if (me->me_dummy && !show_all_fs) { + continue; + /* Skip excluded fstypes */ + } else if (fs_exclude_list && np_find_name (fs_exclude_list, me->me_type)) { + continue; + /* Skip excluded fs's */ + } else if (dp_exclude_list && + (np_find_name (dp_exclude_list, me->me_devname) || + np_find_name (dp_exclude_list, me->me_mountdir))) { + continue; + } + + get_fs_usage (me->me_mountdir, me->me_devname, &fsp); + + if (fsp.fsu_blocks && strcmp ("none", me->me_mountdir)) { + total = fsp.fsu_blocks; + available = fsp.fsu_bavail; + available_to_root = fsp.fsu_bfree; + used = total - available_to_root; + + dused_pct = calculate_percent( used, used + available ); /* used + available can never be > uintmax */ + + dfree_pct = 100 - dused_pct; + dused_units = used*fsp.fsu_blocksize/mult; + dfree_units = available*fsp.fsu_blocksize/mult; + dtotal_units = total*fsp.fsu_blocksize/mult; + dused_inodes_percent = calculate_percent(fsp.fsu_files - fsp.fsu_ffree, fsp.fsu_files); + dfree_inodes_percent = 100 - dused_inodes_percent; + + if (verbose >= 3) { + printf ("For %s, used_pct=%g free_pct=%g used_units=%g free_units=%g total_units=%g used_inodes_pct=%g free_inodes_pct=%g\n", + me->me_mountdir, dused_pct, dfree_pct, dused_units, dfree_units, dtotal_units, dused_inodes_percent, dfree_inodes_percent); + } + + /* Threshold comparisons */ + + temp_result = get_status(dfree_units, path->freespace_units); + if (verbose >=3) printf("Freespace_units result=%d\n", temp_result); + disk_result = max_state( disk_result, temp_result ); + + temp_result = get_status(dfree_pct, path->freespace_percent); + if (verbose >=3) printf("Freespace%% result=%d\n", temp_result); + disk_result = max_state( disk_result, temp_result ); + + temp_result = get_status(dused_units, path->usedspace_units); + if (verbose >=3) printf("Usedspace_units result=%d\n", temp_result); + disk_result = max_state( disk_result, temp_result ); + + temp_result = get_status(dused_pct, path->usedspace_percent); + if (verbose >=3) printf("Usedspace_percent result=%d\n", temp_result); + disk_result = max_state( disk_result, temp_result ); + + temp_result = get_status(dused_inodes_percent, path->usedinodes_percent); + if (verbose >=3) printf("Usedinodes_percent result=%d\n", temp_result); + disk_result = max_state( disk_result, temp_result ); + + temp_result = get_status(dfree_inodes_percent, path->freeinodes_percent); + if (verbose >=3) printf("Freeinodes_percent result=%d\n", temp_result); + disk_result = max_state( disk_result, temp_result ); + + result = max_state(result, disk_result); + + /* What a mess of units. The output shows free space, the perf data shows used space. Yikes! + Hack here. Trying to get warn/crit levels from freespace_(units|percent) for perf + data. Assumption that start=0. Roll on new syntax... + */ + + /* *_high_tide must be reinitialized at each run */ + warning_high_tide = UINT_MAX; + critical_high_tide = UINT_MAX; + + if (path->freespace_units->warning != NULL) { + warning_high_tide = dtotal_units - path->freespace_units->warning->end; + } + if (path->freespace_percent->warning != NULL) { + warning_high_tide = abs( min( (double) warning_high_tide, (double) (1.0 - path->freespace_percent->warning->end/100)*dtotal_units )); + } + if (path->freespace_units->critical != NULL) { + critical_high_tide = dtotal_units - path->freespace_units->critical->end; + } + if (path->freespace_percent->critical != NULL) { + critical_high_tide = abs( min( (double) critical_high_tide, (double) (1.0 - path->freespace_percent->critical->end/100)*dtotal_units )); + } + + asprintf (&perf, "%s %s", perf, + perfdata ((!strcmp(me->me_mountdir, "none") || display_mntp) ? me->me_devname : me->me_mountdir, + dused_units, units, + (warning_high_tide != UINT_MAX ? TRUE : FALSE), warning_high_tide, + (critical_high_tide != UINT_MAX ? TRUE : FALSE), critical_high_tide, + TRUE, 0, + TRUE, dtotal_units)); + + if (disk_result==STATE_OK && erronly && !verbose) + continue; + + if (disk_result!=STATE_OK || verbose>=0) { + asprintf (&output, "%s %s %.0f %s (%.0f%%", + output, + (!strcmp(me->me_mountdir, "none") || display_mntp) ? me->me_devname : me->me_mountdir, + dfree_units, + units, + dfree_pct); + if (dused_inodes_percent < 0) { + asprintf(&output, "%s inode=-);", output); + } else { + asprintf(&output, "%s inode=%.0f%%);", output, dfree_inodes_percent ); + } + } + + /* TODO: Need to do a similar debug line + asprintf (&details, _("%s\n\ +%.0f of %.0f %s (%.0f%% inode=%.0f%%) free on %s (type %s mounted on %s) warn:%lu crit:%lu warn%%:%.0f%% crit%%:%.0f%%"), + details, dfree_units, dtotal_units, units, dfree_pct, inode_space_pct, + me->me_devname, me->me_type, me->me_mountdir, + (unsigned long)w_df, (unsigned long)c_df, w_dfp, c_dfp); + */ + + } + + } + + if (verbose > 2) + asprintf (&output, "%s%s", output, details); + + + printf ("DISK %s%s%s|%s\n", state_text (result), (erronly && result==STATE_OK) ? "" : preamble, output, perf); + return result; } +double calculate_percent(uintmax_t value, uintmax_t total) { + double pct = -1; + /* I don't understand the below, but it is taken from coreutils' df */ + /* Seems to be calculating pct, in the best possible way */ + if (value <= TYPE_MAXIMUM(uintmax_t) / 100 + && total != 0) { + uintmax_t u100 = value * 100; + pct = u100 / total + (u100 % total != 0); + } else { + /* Possible rounding errors - see coreutils' df for more explanation */ + double u = value; + double t = total; + if (t) { + long int lipct = pct = u * 100 / t; + double ipct = lipct; + + /* Like 'pct = ceil (dpct);', but without ceil - from coreutils again */ + if (ipct - 1 < pct && pct <= ipct + 1) + pct = ipct + (ipct < pct); + } + } + return pct; +} - /* process command-line arguments */ int process_arguments (int argc, char **argv) { - int c; - struct name_list *se; - struct name_list **pathtail = &path_select_list; - struct name_list **devtail = &dev_select_list; - struct name_list **fstail = &fs_exclude_list; - struct name_list **dptail = &dp_exclude_list; - - int option_index = 0; - static struct option long_options[] = { - {"timeout", required_argument, 0, 't'}, - {"warning", required_argument, 0, 'w'}, - {"critical", required_argument, 0, 'c'}, - {"local", required_argument, 0, 'l'}, - {"kilobytes", required_argument, 0, 'k'}, - {"megabytes", required_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'}, - {"mountpoint", no_argument, 0, 'M'}, - {"errors-only", no_argument, 0, 'e'}, - {"verbose", no_argument, 0, 'v'}, - {"quiet", no_argument, 0, 'q'}, - {"version", no_argument, 0, 'V'}, - {"help", no_argument, 0, 'h'}, - {0, 0, 0, 0} - }; - - if (argc < 2) - return ERROR; - - se = (struct name_list *) malloc (sizeof (struct name_list)); - se->name = strdup ("iso9660"); - se->name_next = NULL; - *fstail = se; - fstail = &se->name_next; - - for (c = 1; c < argc; c++) - if (strcmp ("-to", argv[c]) == 0) - strcpy (argv[c], "-t"); - - while (1) { - c = getopt_long (argc, argv, "+?Vqhvet:c:w:u:p:x:X:mklM", long_options, &option_index); - - if (c == -1 || c == EOF) - break; - - switch (c) { - case 't': /* timeout period */ - if (is_integer (optarg)) { - timeout_interval = atoi (optarg); - break; - } - else { - usage ("Timeout Interval must be an integer!\n"); - } - case 'w': /* warning time threshold */ - if (is_intnonneg (optarg)) { - w_df = atoi (optarg); - break; - } - else if (strpbrk (optarg, ",:") && - strstr (optarg, "%") && - sscanf (optarg, "%d%*[:,]%f%%", &w_df, &w_dfp) == 2) { - break; - } - else if (strstr (optarg, "%") && sscanf (optarg, "%f%%", &w_dfp) == 1) { - break; - } - else { - usage ("Warning threshold must be integer or percentage!\n"); - } - case 'c': /* critical time threshold */ - if (is_intnonneg (optarg)) { - c_df = atoi (optarg); - break; - } - else if (strpbrk (optarg, ",:") && - strstr (optarg, "%") && - sscanf (optarg, "%d%*[,:]%f%%", &c_df, &c_dfp) == 2) { - break; - } - else if (strstr (optarg, "%") && sscanf (optarg, "%f%%", &c_dfp) == 1) { - break; - } - else { - usage ("Critical threshold must be integer or percentage!\n"); - } - case 'u': - if (! strcmp (optarg, "bytes")) { - mult = 1; - units = "B"; - } else if (! strcmp (optarg, "kB")) { - mult = 1024; - units = "kB"; - } else if (! strcmp (optarg, "MB")) { - mult = 1024 * 1024; - units = "MB"; - } else if (! strcmp (optarg, "GB")) { - mult = 1024 * 1024 * 1024; - units = "GB"; - } else if (! strcmp (optarg, "TB")) { - mult = (unsigned long)1024 * 1024 * 1024 * 1024; - units = "TB"; - } else { - terminate (STATE_UNKNOWN, "unit type %s not known\n", optarg); - } - break; - case 'k': /* display mountpoint */ - mult = 1024; - units = "kB"; - break; - case 'm': /* display mountpoint */ - mult = 1024 * 1024; - units = "MB"; - break; - case 'l': - show_local_fs = 1; - break; - case 'p': /* select path */ - se = (struct name_list *) malloc (sizeof (struct name_list)); - se->name = strdup (optarg); - se->name_next = NULL; - *pathtail = se; - pathtail = &se->name_next; - break; - case 'x': /* exclude path or partition */ - se = (struct name_list *) malloc (sizeof (struct name_list)); - se->name = strdup (optarg); - se->name_next = NULL; - *dptail = se; - dptail = &se->name_next; - break; - break; - case 'X': /* exclude file system type */ - se = (struct name_list *) malloc (sizeof (struct name_list)); - se->name = strdup (optarg); - se->name_next = NULL; - *fstail = se; - fstail = &se->name_next; - break; - case 'v': /* verbose */ - verbose++; - break; - case 'q': /* verbose */ - verbose--; - break; - case 'e': - erronly = TRUE; - break; - case 'M': /* display mountpoint */ - display_mntp = TRUE; - break; - case 'V': /* version */ - print_revision (progname, revision); - exit (STATE_OK); - case 'h': /* help */ - print_help (); - exit (STATE_OK); - case '?': /* help */ - usage ("check_disk: unrecognized option\n"); - break; - } - } - - c = optind; - if (w_dfp == -1 && argc > c && is_intnonneg (argv[c])) - w_dfp = (100.0 - atof (argv[c++])); - - if (c_dfp == -1 && argc > c && is_intnonneg (argv[c])) - c_dfp = (100.0 - atof (argv[c++])); - - if (argc > c && strlen (path) == 0) - path = argv[c++]; - - return validate_arguments (); + int c; + struct parameter_list *se; + struct parameter_list *temp_list; + int result = OK; + struct stat *stat_buf; + + int option = 0; + static struct option longopts[] = { + {"timeout", required_argument, 0, 't'}, + {"warning", required_argument, 0, 'w'}, + {"critical", required_argument, 0, 'c'}, + {"iwarning", required_argument, 0, 'W'}, + /* Dang, -C is taken. We might want to reshuffle this. */ + {"icritical", required_argument, 0, 'K'}, + {"local", required_argument, 0, 'l'}, + {"kilobytes", required_argument, 0, 'k'}, + {"megabytes", required_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'}, + {"mountpoint", no_argument, 0, 'M'}, + {"errors-only", no_argument, 0, 'e'}, + {"exact-match", no_argument, 0, 'E'}, + {"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'}, + {0, 0, 0, 0} + }; + + if (argc < 2) + return ERROR; + + np_add_name(&fs_exclude_list, "iso9660"); + + for (c = 1; c < argc; c++) + if (strcmp ("-to", argv[c]) == 0) + strcpy (argv[c], "-t"); + + while (1) { + c = getopt_long (argc, argv, "+?VqhveCt:c:w:K:W:u:p:x:X:mklME", longopts, &option); + + if (c == -1 || c == EOF) + break; + + switch (c) { + 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 (strstr(optarg, "%")) { + if (*optarg == '@') { + warn_freespace_percent = optarg; + } else { + asprintf(&warn_freespace_percent, "@%s", optarg); + } + } else { + if (*optarg == '@') { + warn_freespace_units = optarg; + } else { + asprintf(&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 artifically + force @ at the beginning of the range, so that it is backwards compatible + */ + case 'c': /* critical threshold */ + if (strstr(optarg, "%")) { + if (*optarg == '@') { + crit_freespace_percent = optarg; + } else { + asprintf(&crit_freespace_percent, "@%s", optarg); + } + } else { + if (*optarg == '@') { + crit_freespace_units = optarg; + } else { + asprintf(&crit_freespace_units, "@%s", optarg); + } + } + break; + + case 'W': /* warning inode threshold */ + if (*optarg == '@') { + warn_freeinodes_percent = optarg; + } else { + asprintf(&warn_freeinodes_percent, "@%s", optarg); + } + break; + case 'K': /* critical inode threshold */ + if (*optarg == '@') { + crit_freeinodes_percent = optarg; + } else { + asprintf(&crit_freeinodes_percent, "@%s", optarg); + } + break; + case 'u': + if (units) + free(units); + if (! strcmp (optarg, "bytes")) { + mult = (uintmax_t)1; + units = strdup ("B"); + } else if (! strcmp (optarg, "kB")) { + mult = (uintmax_t)1024; + units = strdup ("kB"); + } else if (! strcmp (optarg, "MB")) { + mult = (uintmax_t)1024 * 1024; + units = strdup ("MB"); + } else if (! strcmp (optarg, "GB")) { + mult = (uintmax_t)1024 * 1024 * 1024; + units = strdup ("GB"); + } else if (! strcmp (optarg, "TB")) { + mult = (uintmax_t)1024 * 1024 * 1024 * 1024; + units = strdup ("TB"); + } else { + die (STATE_UNKNOWN, _("unit type %s not known\n"), optarg); + } + if (units == NULL) + die (STATE_UNKNOWN, _("failed allocating storage for '%s'\n"), "units"); + break; + case 'k': /* display mountpoint */ + mult = 1024; + if (units) + free(units); + units = strdup ("kB"); + break; + case 'm': /* display mountpoint */ + mult = 1024 * 1024; + if (units) + free(units); + units = strdup ("MB"); + break; + case 'l': + show_local_fs = 1; + break; + case 'p': /* select path */ + if (! (warn_freespace_units || crit_freespace_units || warn_freespace_percent || + crit_freespace_percent || warn_usedspace_units || crit_usedspace_units || + warn_usedspace_percent || crit_usedspace_percent || warn_usedinodes_percent || + crit_usedinodes_percent || warn_freeinodes_percent || crit_freeinodes_percent )) { + die (STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set a threshold value before using -p\n")); + } + se = np_add_parameter(&path_select_list, optarg); + set_thresholds(&se->freespace_units, warn_freespace_units, crit_freespace_units); + set_thresholds(&se->freespace_percent, warn_freespace_percent, crit_freespace_percent); + set_thresholds(&se->usedspace_units, warn_usedspace_units, crit_usedspace_units); + set_thresholds(&se->usedspace_percent, warn_usedspace_percent, crit_usedspace_percent); + set_thresholds(&se->usedinodes_percent, warn_usedinodes_percent, crit_usedinodes_percent); + set_thresholds(&se->freeinodes_percent, warn_freeinodes_percent, crit_freeinodes_percent); + break; + case 'x': /* exclude path or partition */ + np_add_name(&dp_exclude_list, optarg); + break; + case 'X': /* exclude file system type */ + np_add_name(&fs_exclude_list, optarg); + break; + case 'v': /* verbose */ + verbose++; + break; + case 'q': /* verbose */ + verbose--; + break; + case 'e': + erronly = TRUE; + break; + case 'E': + exact_match = TRUE; + break; + case 'M': /* display mountpoint */ + display_mntp = TRUE; + break; + case 'C': + warn_freespace_units = NULL; + crit_freespace_units = NULL; + warn_usedspace_units = NULL; + crit_usedspace_units = NULL; + warn_freespace_percent = NULL; + crit_freespace_percent = NULL; + warn_usedspace_percent = NULL; + crit_usedspace_percent = NULL; + warn_usedinodes_percent = NULL; + crit_usedinodes_percent = NULL; + warn_freeinodes_percent = NULL; + crit_freeinodes_percent = NULL; + break; + case 'V': /* version */ + print_revision (progname, revision); + exit (STATE_OK); + case 'h': /* help */ + print_help (); + exit (STATE_OK); + case '?': /* help */ + usage (_("Unknown argument")); + } + } + + /* Support for "check_disk warn crit [fs]" with thresholds at used% level */ + c = optind; + if (warn_usedspace_percent == NULL && argc > c && is_intnonneg (argv[c])) + warn_usedspace_percent = argv[c++]; + + if (crit_usedspace_percent == NULL && argc > c && is_intnonneg (argv[c])) + crit_usedspace_percent = argv[c++]; + + if (argc > c && path == NULL) { + se = np_add_parameter(&path_select_list, strdup(argv[c++])); + set_thresholds(&se->freespace_units, warn_freespace_units, crit_freespace_units); + set_thresholds(&se->freespace_percent, warn_freespace_percent, crit_freespace_percent); + set_thresholds(&se->usedspace_units, warn_usedspace_units, crit_usedspace_units); + set_thresholds(&se->usedspace_percent, warn_usedspace_percent, crit_usedspace_percent); + set_thresholds(&se->usedinodes_percent, warn_usedinodes_percent, crit_usedinodes_percent); + set_thresholds(&se->freeinodes_percent, warn_freeinodes_percent, crit_freeinodes_percent); + } + + if (units == NULL) { + units = strdup ("MB"); + mult = (uintmax_t)1024 * 1024; + } + + if (path_select_list) { + temp_list = path_select_list; + stat_buf = malloc(sizeof *stat_buf); + while (temp_list) { + /* Stat each entry to check that dir exists */ + if (stat (temp_list->name, &stat_buf[0])) { + printf("DISK %s - ", _("CRITICAL")); + die (STATE_CRITICAL, _("%s does not exist\n"), temp_list->name); + } + /* if (validate_arguments (temp_list->w_df, + temp_list->c_df, + temp_list->w_dfp, + temp_list->c_dfp, + temp_list->w_idfp, + temp_list->c_idfp, + temp_list->name) == ERROR) + result = ERROR; + */ + temp_list = temp_list->name_next; + } + free(stat_buf); + return result; + } else { + return TRUE; + /* return validate_arguments (w_df, c_df, w_dfp, c_dfp, w_idfp, c_idfp, NULL); */ + } } -int -validate_arguments () +void +print_path (const char *mypath) { - if (w_df < 0 && c_df < 0 && w_dfp < 0 && c_dfp < 0) { - printf ("INPUT ERROR: Unable to parse command line\n"); - return ERROR; - } - else if ((w_dfp >= 0 || c_dfp >= 0) - && (w_dfp < 0 || c_dfp < 0 || w_dfp > 100 || c_dfp > 100 - || c_dfp > w_dfp)) { - printf - ("INPUT ERROR: C_DFP (%f) should be less than W_DFP (%f) and both should be between zero and 100 percent, inclusive\n", - c_dfp, w_dfp); - return ERROR; - } - else if ((w_df > 0 || c_df > 0) && (w_df < 0 || c_df < 0 || c_df > w_df)) { - printf - ("INPUT ERROR: C_DF (%d) should be less than W_DF (%d) and both should be greater than zero\n", - c_df, w_df); - return ERROR; - } - else { - return OK; - } + if (mypath == NULL) + printf ("\n"); + else + printf (_(" for %s\n"), mypath); } - +/* TODO: Remove? + int -check_disk (int usp, int free_disk) +validate_arguments (uintmax_t w, uintmax_t c, double wp, double cp, double iwp, double icp, char *mypath) { - int result = STATE_UNKNOWN; - /* check the percent used space against thresholds */ - if (usp >= 0 && usp >= (100.0 - c_dfp)) - result = STATE_CRITICAL; - else if (c_df >= 0 && free_disk <= c_df) - result = STATE_CRITICAL; - else if (usp >= 0 && usp >= (100.0 - w_dfp)) - result = STATE_WARNING; - else if (w_df >= 0 && free_disk <= w_df) - result = STATE_WARNING; - else if (usp >= 0.0) - result = STATE_OK; - return result; + if (w < 0 && c < 0 && wp < 0.0 && cp < 0.0) { + printf (_("INPUT ERROR: No thresholds specified")); + print_path (mypath); + return ERROR; + } + else if ((wp >= 0.0 || cp >= 0.0) && + (wp < 0.0 || cp < 0.0 || wp > 100.0 || cp > 100.0 || cp > wp)) { + printf (_("\ +INPUT ERROR: C_DFP (%f) should be less than W_DFP (%.1f) and both should be between zero and 100 percent, inclusive"), + cp, wp); + print_path (mypath); + return ERROR; + } + else if ((iwp >= 0.0 || icp >= 0.0) && + (iwp < 0.0 || icp < 0.0 || iwp > 100.0 || icp > 100.0 || icp > iwp)) { + printf (_("\ +INPUT ERROR: C_IDFP (%f) should be less than W_IDFP (%.1f) and both should be between zero and 100 percent, inclusive"), + icp, iwp); + print_path (mypath); + return ERROR; + } + else if ((w > 0 || c > 0) && (w == 0 || c == 0 || c > w)) { + printf (_("\ +INPUT ERROR: C_DF (%lu) should be less than W_DF (%lu) and both should be greater than zero"), + (unsigned long)c, (unsigned long)w); + print_path (mypath); + return ERROR; + } + + return OK; } +*/ + + -int -walk_name_list (struct name_list *list, const char *name) -{ - while (list) { - if (! strcmp(list->name, name)) { - list->found = 1; - return TRUE; - } - list = list->name_next; - } - return FALSE; -} - void print_help (void) { - print_revision (progname, revision); - printf ("Copyright (c) %s %s\n\t<%s>\n\n%s\n", - copyright, authors, email, summary); - print_usage (); - printf ("\nOptions:\n"); - printf (options); - printf (notes); - support (); + print_revision (progname, revision); + + printf ("Copyright (c) 1999 Ethan Galstad \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 (" %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", "-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", "-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 CRITCAL status if less than PERCENT of disk space is free")); + printf (" %s\n", "-C, --clear"); + printf (" %s\n", _("Clear thresholds")); + printf (" %s\n", "-u, --units=STRING"); + printf (" %s\n", _("Choose bytes, kB, MB, GB, TB (default: MB)")); + printf (" %s\n", "-k, --kilobytes"); + printf (" %s\n", _("Same as '--units kB'")); + printf (" %s\n", "-m, --megabytes"); + printf (" %s\n", _("Same as '--units MB'")); + printf (" %s\n", "-l, --local"); + printf (" %s\n", _("Only check local filesystems")); + printf (" %s\n", "-p, --path=PATH, --partition=PARTITION"); + printf (" %s\n", _("Path or partition (may be repeated)")); + printf (" %s\n", "-x, --exclude_device=PATH "); + printf (" %s\n", _("Ignore device (only works if -p unspecified)")); + printf (" %s\n", "-X, --exclude-type=TYPE "); + printf (" %s\n", _("Ignore all filesystems of indicated type (may be repeated)")); + printf (" %s\n", "-m, --mountpoint"); + printf (" %s\n", _("Display the mountpoint instead of the partition")); + 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 (_(UT_TIMEOUT), DEFAULT_SOCKET_TIMEOUT); + printf (_(UT_VERBOSE)); + 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", _("Checks /tmp and /var at 10% and 5%, and / at 100MB and 50MB")); + printf (_(UT_SUPPORT)); } + + void print_usage (void) { - printf - ("Usage: %s %s\n" - " %s (-h|--help)\n" - " %s (-V|--version)\n", progname, option_summary, progname, progname); + printf (_("Usage:")); + printf (" %s -w limit -c limit [-p path | -x device] [-t timeout]", progname); + printf ("[-m] [-e] [-W limit] [-K limit] [-v] [-q] [-E]\n"); }