From 77f2c84d2f599d86a60586494169dcab17853e3a Mon Sep 17 00:00:00 2001 From: Matthias Eble Date: Mon, 15 Nov 2010 23:59:35 +0100 Subject: [PATCH] Fix check_disk free space calculation if blocksizes differ within a disk group (Bekar - #2973603) Various values (dused_pct, dfree_pct, inodes_free, inodes_total, ...) are now carried in the parameter_list structure. Assignments have been moved to a subroutine preventing code redundancies. Group metrics are now calculated based on units rather than blocks. This fixes freespace calculation when blocksizes differ within a group. --- NEWS | 2 + lib/utils_disk.c | 13 ++++ lib/utils_disk.h | 4 + plugins/check_disk.c | 175 +++++++++++++++++++++++-------------------- 4 files changed, 113 insertions(+), 81 deletions(-) diff --git a/NEWS b/NEWS index 0d6d3b0..a00febc 100644 --- a/NEWS +++ b/NEWS @@ -3,10 +3,12 @@ This file documents the major additions and syntax changes between releases. ... ENHANCEMENTS check_nt UPTIME accepts warning/critical thresholds (Ryan Kelly) + FIXES check_snmp now attempts to convert string responses into a double value. If the full string is a value, check_snmp will consider it a numeric value and thus apply threshold checks and return performance data. This reverts back to 1.4.14 behaviour with strings + Fix check_disk free space calculation if blocksizes differ within a disk group (Bekar - #2973603) 1.4.15 27th July 2010 ENHANCEMENTS diff --git a/lib/utils_disk.c b/lib/utils_disk.c index 3d20f4d..5be2b2c 100644 --- a/lib/utils_disk.c +++ b/lib/utils_disk.c @@ -58,6 +58,19 @@ np_add_parameter(struct parameter_list **list, const char *name) 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->dused_inodes_percent = 0; + new_path->dfree_inodes_percent = 0; if (current == NULL) { *list = new_path; diff --git a/lib/utils_disk.h b/lib/utils_disk.h index f99b905..83a3763 100644 --- a/lib/utils_disk.h +++ b/lib/utils_disk.h @@ -24,6 +24,10 @@ struct parameter_list char *group; struct mount_entry *best_match; struct parameter_list *name_next; + uintmax_t total, available, available_to_root, used, inodes_free, inodes_total; + double dfree_pct, dused_pct; + double dused_units, dfree_units, dtotal_units; + double dused_inodes_percent, dfree_inodes_percent; }; void np_add_name (struct name_list **list, const char *name); diff --git a/plugins/check_disk.c b/plugins/check_disk.c index 851d800..f889764 100644 --- a/plugins/check_disk.c +++ b/plugins/check_disk.c @@ -122,6 +122,8 @@ void print_help (void); void print_usage (void); double calculate_percent(uintmax_t, uintmax_t); void stat_path (struct parameter_list *p); +void get_stats (struct parameter_list *p, struct fs_usage *fsp); +void get_path_stats (struct parameter_list *p, struct fs_usage *fsp); double w_dfp = -1.0; double c_dfp = -1.0; @@ -148,6 +150,7 @@ char *crit_freeinodes_percent = NULL; int path_selected = FALSE; char *group = NULL; struct stat *stat_buf; +struct name_list *seen = NULL; int @@ -160,10 +163,6 @@ main (int argc, char **argv) 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; @@ -171,7 +170,6 @@ main (int argc, char **argv) struct mount_entry *me; struct fs_usage fsp, tmpfsp; struct parameter_list *temp_list, *path; - struct name_list *seen = NULL; preamble = strdup (" - free space:"); output = strdup (""); @@ -237,45 +235,8 @@ main (int argc, char **argv) /* Remove filesystems already seen */ if (np_seen_name(seen, me->me_mountdir)) { continue; - } else { - if (path->group != NULL) { - /* find all group members */ - fsp.fsu_blocksize = 0; - fsp.fsu_blocks = 0; - fsp.fsu_bfree = 0; - fsp.fsu_bavail = 0; - fsp.fsu_files = 0; - fsp.fsu_ffree = 0; - - - for (temp_list = path_select_list; temp_list; temp_list=temp_list->name_next) { - if (temp_list->group && ! (strcmp(temp_list->group, path->group))) { - - stat_path(path); - get_fs_usage (temp_list->best_match->me_mountdir, temp_list->best_match->me_devname, &tmpfsp); - - /* possibly differing blocksizes if disks are grouped. Calculating average */ - fsp.fsu_blocksize = (fsp.fsu_blocksize * fsp.fsu_blocks + tmpfsp.fsu_blocksize * tmpfsp.fsu_blocks) / \ - (fsp.fsu_blocks + tmpfsp.fsu_blocks); /* Size of a block. */ - fsp.fsu_blocks += tmpfsp.fsu_blocks; /* Total blocks. */ - fsp.fsu_bfree += tmpfsp.fsu_bfree; /* Free blocks available to superuser. */ - /* Gnulib workaround - see comment about it a few lines below */ - fsp.fsu_bavail += (tmpfsp.fsu_bavail > tmpfsp.fsu_bfree ? 0 : tmpfsp.fsu_bavail); /* Free blocks available to non-superuser. */ - fsp.fsu_files += tmpfsp.fsu_files; /* Total file nodes. */ - fsp.fsu_ffree += tmpfsp.fsu_ffree; /* Free file nodes. */ - - if (verbose >= 3) - printf("Group %s: add %llu blocks (%s) \n", path->group, tmpfsp.fsu_bavail, temp_list->name); - /* printf("Group %s: add %u blocks (%s)\n", temp_list->name); *//* path->group, tmpfsp.fsu_bavail, temp_list->name); */ - - np_add_name(&seen, temp_list->best_match->me_mountdir); - } - } - /* modify devname and mountdir for output */ - me->me_mountdir = me->me_devname = path->group; - } else - np_add_name(&seen, me->me_mountdir); - } + } + np_add_name(&seen, me->me_mountdir); if (path->group == NULL) { /* Skip remote filesystems if we're not interested in them */ @@ -301,55 +262,36 @@ main (int argc, char **argv) } if (fsp.fsu_blocks && strcmp ("none", me->me_mountdir)) { - total = fsp.fsu_blocks; - /* 2007-12-08 - Workaround for Gnulib reporting insanely high available - * space on BSD (the actual value should be negative but fsp.fsu_bavail - * is unsigned) */ - available = fsp.fsu_bavail > fsp.fsu_bfree ? 0 : fsp.fsu_bavail; - available_to_root = fsp.fsu_bfree; - used = total - available_to_root; - - if (verbose >= 3) - printf ("For %s, total=%llu, available=%llu, available_to_root=%llu, used=%llu, fsp.fsu_files=%llu, fsp.fsu_ffree=%llu\n", - me->me_mountdir, total, available, available_to_root, used, fsp.fsu_files, fsp.fsu_ffree); - - 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; + get_stats (path, &fsp); 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 fsp.fsu_blocksize=%llu mult=%llu\n", - me->me_mountdir, dused_pct, dfree_pct, dused_units, dfree_units, dtotal_units, dused_inodes_percent, dfree_inodes_percent, fsp.fsu_blocksize, mult); + me->me_mountdir, path->dused_pct, path->dfree_pct, path->dused_units, path->dfree_units, path->dtotal_units, path->dused_inodes_percent, path->dfree_inodes_percent, fsp.fsu_blocksize, mult); } /* Threshold comparisons */ - temp_result = get_status(dfree_units, path->freespace_units); + temp_result = get_status(path->dfree_units, path->freespace_units); if (verbose >=3) printf("Freespace_units result=%d\n", temp_result); disk_result = max_state( disk_result, temp_result ); - temp_result = get_status(dfree_pct, path->freespace_percent); + temp_result = get_status(path->dfree_pct, path->freespace_percent); if (verbose >=3) printf("Freespace%% result=%d\n", temp_result); disk_result = max_state( disk_result, temp_result ); - temp_result = get_status(dused_units, path->usedspace_units); + temp_result = get_status(path->dused_units, path->usedspace_units); if (verbose >=3) printf("Usedspace_units result=%d\n", temp_result); disk_result = max_state( disk_result, temp_result ); - temp_result = get_status(dused_pct, path->usedspace_percent); + temp_result = get_status(path->dused_pct, path->usedspace_percent); if (verbose >=3) printf("Usedspace_percent result=%d\n", temp_result); disk_result = max_state( disk_result, temp_result ); - temp_result = get_status(dused_inodes_percent, path->usedinodes_percent); + temp_result = get_status(path->dused_inodes_percent, path->usedinodes_percent); if (verbose >=3) printf("Usedinodes_percent result=%d\n", temp_result); disk_result = max_state( disk_result, temp_result ); - temp_result = get_status(dfree_inodes_percent, path->freeinodes_percent); + temp_result = get_status(path->dfree_inodes_percent, path->freeinodes_percent); if (verbose >=3) printf("Freeinodes_percent result=%d\n", temp_result); disk_result = max_state( disk_result, temp_result ); @@ -365,26 +307,26 @@ main (int argc, char **argv) critical_high_tide = UINT_MAX; if (path->freespace_units->warning != NULL) { - warning_high_tide = dtotal_units - path->freespace_units->warning->end; + warning_high_tide = path->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 )); + warning_high_tide = abs( min( (double) warning_high_tide, (double) (1.0 - path->freespace_percent->warning->end/100)*path->dtotal_units )); } if (path->freespace_units->critical != NULL) { - critical_high_tide = dtotal_units - path->freespace_units->critical->end; + critical_high_tide = path->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 )); + critical_high_tide = abs( min( (double) critical_high_tide, (double) (1.0 - path->freespace_percent->critical->end/100)*path->dtotal_units )); } /* Nb: *_high_tide are unset when == UINT_MAX */ asprintf (&perf, "%s %s", perf, perfdata ((!strcmp(me->me_mountdir, "none") || display_mntp) ? me->me_devname : me->me_mountdir, - dused_units, units, + path->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)); + TRUE, path->dtotal_units)); if (disk_result==STATE_OK && erronly && !verbose) continue; @@ -392,13 +334,13 @@ main (int argc, char **argv) asprintf (&output, "%s %s %.0f %s (%.0f%%", output, (!strcmp(me->me_mountdir, "none") || display_mntp) ? me->me_devname : me->me_mountdir, - dfree_units, + path->dfree_units, units, - dfree_pct); - if (dused_inodes_percent < 0) { + path->dfree_pct); + if (path->dused_inodes_percent < 0) { asprintf(&output, "%s inode=-);", output); } else { - asprintf(&output, "%s inode=%.0f%%);", output, dfree_inodes_percent ); + asprintf(&output, "%s inode=%.0f%%);", output, path->dfree_inodes_percent ); } /* TODO: Need to do a similar debug line @@ -996,3 +938,74 @@ stat_path (struct parameter_list *p) die (STATE_CRITICAL, _("%s %s: %s\n"), p->name, _("is not accessible"), strerror(errno)); } } + + +void +get_stats (struct parameter_list *p, struct fs_usage *fsp) { + struct parameter_list *p_list; + struct fs_usage tmpfsp; + int first = 1; + + if (p->group == NULL) { + get_path_stats(p,fsp); + } else { + /* find all group members */ + for (p_list = path_select_list; p_list; p_list=p_list->name_next) { + if (p_list->group && ! (strcmp(p_list->group, p->group))) { + stat_path(p_list); + get_fs_usage (p_list->best_match->me_mountdir, p_list->best_match->me_devname, &tmpfsp); + get_path_stats(p_list, &tmpfsp); + if (verbose >= 3) + printf("Group %s: adding %llu blocks sized %llu, (%s) used_units=%g free_units=%g total_units=%g fsu_blocksize=%llu mult=%llu\n", + p_list->group, tmpfsp.fsu_bavail, tmpfsp.fsu_blocksize, p_list->best_match->me_mountdir, p_list->dused_units, p_list->dfree_units, + p_list->dtotal_units, mult); + + /* prevent counting the first FS of a group twice since its parameter_list entry + * is used to carry the information of all file systems of the entire group */ + if (! first) { + p->total += p_list->total; + p->available += p_list->available; + p->available_to_root += p_list->available_to_root; + p->used += p_list->used; + + p->dused_units += p_list->dused_units; + p->dfree_units += p_list->dfree_units; + p->dtotal_units += p_list->dtotal_units; + p->inodes_total += p_list->inodes_total; + p->inodes_free += p_list->inodes_free; + } + first = 0; + } + if (verbose >= 3) + printf("Group %s now has: used_units=%g free_units=%g total_units=%g fsu_blocksize=%llu mult=%llu\n", + p->group, tmpfsp.fsu_bavail, tmpfsp.fsu_blocksize, p->best_match->me_mountdir, p->dused_units, + p->dfree_units, p->dtotal_units, mult); + } + /* modify devname and mountdir for output */ + p->best_match->me_mountdir = p->best_match->me_devname = p->group; + } + /* finally calculate percentages for either plain FS or summed up group */ + p->dused_pct = calculate_percent( p->used, p->used + p->available ); /* used + available can never be > uintmax */ + p->dfree_pct = 100 - p->dused_pct; + p->dused_inodes_percent = calculate_percent(p->inodes_total - p->inodes_free, p->inodes_total); + p->dfree_inodes_percent = 100 - p->dused_inodes_percent; + +} + +void +get_path_stats (struct parameter_list *p, struct fs_usage *fsp) { + p->total = fsp->fsu_blocks; + /* 2007-12-08 - Workaround for Gnulib reporting insanely high available + * space on BSD (the actual value should be negative but fsp->fsu_bavail + * is unsigned) */ + p->available = fsp->fsu_bavail > fsp->fsu_bfree ? 0 : fsp->fsu_bavail; + p->available_to_root = fsp->fsu_bfree; + p->used = p->total - p->available_to_root; + + p->dused_units = p->used*fsp->fsu_blocksize/mult; + p->dfree_units = p->available*fsp->fsu_blocksize/mult; + p->dtotal_units = p->total*fsp->fsu_blocksize/mult; + p->inodes_total = fsp->fsu_files; /* Total file nodes. */ + p->inodes_free = fsp->fsu_ffree; /* Free file nodes. */ + np_add_name(&seen, p->best_match->me_mountdir); +} -- 2.30.2