summaryrefslogtreecommitdiffstats
path: root/plugins/check_disk.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/check_disk.c')
-rw-r--r--plugins/check_disk.c2240
1 files changed, 1157 insertions, 1083 deletions
diff --git a/plugins/check_disk.c b/plugins/check_disk.c
index b3dd301c..515ddff0 100644
--- a/plugins/check_disk.c
+++ b/plugins/check_disk.c
@@ -1,1146 +1,1220 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_disk plugin 3 * Monitoring check_disk plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 1999-2008 Monitoring Plugins Development Team 6 * Copyright (c) 1999-2024 Monitoring Plugins Development Team
7* 7 *
8* Description: 8 * Description:
9* 9 *
10* This file contains the check_disk plugin 10 * This file contains the check_disk plugin
11* 11 *
12* 12 *
13* This program is free software: you can redistribute it and/or modify 13 * This program is free software: you can redistribute it and/or modify
14* it under the terms of the GNU General Public License as published by 14 * it under the terms of the GNU General Public License as published by
15* the Free Software Foundation, either version 3 of the License, or 15 * the Free Software Foundation, either version 3 of the License, or
16* (at your option) any later version. 16 * (at your option) any later version.
17* 17 *
18* This program is distributed in the hope that it will be useful, 18 * This program is distributed in the hope that it will be useful,
19* but WITHOUT ANY WARRANTY; without even the implied warranty of 19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21* GNU General Public License for more details. 21 * GNU General Public License for more details.
22* 22 *
23* You should have received a copy of the GNU General Public License 23 * You should have received a copy of the GNU General Public License
24* along with this program. If not, see <http://www.gnu.org/licenses/>. 24 * along with this program. If not, see <http://www.gnu.org/licenses/>.
25* 25 *
26* 26 *
27*****************************************************************************/ 27 *****************************************************************************/
28 28
29const char *progname = "check_disk"; 29const char *progname = "check_disk";
30const char *program_name = "check_disk"; /* Required for coreutils libs */ 30const char *program_name = "check_disk"; /* Required for coreutils libs */
31const char *copyright = "1999-2008"; 31const char *copyright = "1999-2024";
32const char *email = "devel@monitoring-plugins.org"; 32const char *email = "devel@monitoring-plugins.org";
33 33
34 34#include "states.h"
35#include "common.h" 35#include "common.h"
36#include "output.h"
37#include "perfdata.h"
38#include "utils_base.h"
39#include "lib/thresholds.h"
40
36#ifdef HAVE_SYS_STAT_H 41#ifdef HAVE_SYS_STAT_H
37# include <sys/stat.h> 42# include <sys/stat.h>
38#endif 43#endif
44
39#if HAVE_INTTYPES_H 45#if HAVE_INTTYPES_H
40# include <inttypes.h> 46# include <inttypes.h>
41#endif 47#endif
48
42#include <assert.h> 49#include <assert.h>
43#include "popen.h"
44#include "utils.h"
45#include "utils_disk.h"
46#include <stdarg.h> 50#include <stdarg.h>
47#include "fsusage.h" 51#include <stdint.h>
48#include "mountlist.h"
49#include <float.h> 52#include <float.h>
53#include "./popen.h"
54#include "./utils.h"
55#include "../gl/fsusage.h"
56#include "../gl/mountlist.h"
57#include "./check_disk.d/utils_disk.h"
58
50#if HAVE_LIMITS_H 59#if HAVE_LIMITS_H
51# include <limits.h> 60# include <limits.h>
52#endif 61#endif
62
53#include "regex.h" 63#include "regex.h"
54 64
55#ifdef __CYGWIN__ 65#ifdef __CYGWIN__
56# include <windows.h> 66# include <windows.h>
57# undef ERROR 67# undef ERROR
58# define ERROR -1 68# define ERROR -1
59#endif 69#endif
60 70
61/* If nonzero, show even filesystems with zero size or 71#ifdef _AIX
62 uninteresting types. */ 72# pragma alloca
63static int show_all_fs = 1; 73#endif
64
65/* If nonzero, show only local filesystems. */
66static int show_local_fs = 0;
67
68/* If nonzero, show only local filesystems but call stat() on remote ones. */
69static int stat_remote_fs = 0;
70
71/* If positive, the units to use when printing sizes;
72 if negative, the human-readable base. */
73/* static int output_block_size; */
74 74
75/* If nonzero, invoke the `sync' system call before getting any usage data. 75typedef struct {
76 Using this option can make df very slow, especially with many or very 76 int errorcode;
77 busy disks. Note that this may make a difference on some systems -- 77 check_disk_config config;
78 SunOs4.1.3, for one. It is *not* necessary on Linux. */ 78} check_disk_config_wrapper;
79/* static int require_sync = 0; */ 79static check_disk_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
80 80
81/* Linked list of filesystem types to display. 81static void set_all_thresholds(parameter_list_elem *path, char *warn_freespace_units, char *crit_freespace_units,
82 If `fs_select_list' is NULL, list all types. 82 char *warn_freespace_percent, char *crit_freespace_percent, char *warn_freeinodes_percent,
83 This table is generated dynamically from command-line options, 83 char *crit_freeinodes_percent);
84 rather than hardcoding into the program what it thinks are the 84static double calculate_percent(uintmax_t /*value*/, uintmax_t /*total*/);
85 valid filesystem types; let the user specify any filesystem type 85static bool stat_path(parameter_list_elem * /*parameters*/, bool /*ignore_missing*/);
86 they want to, and if there are any filesystems of that type, they
87 will be shown.
88 86
89 Some filesystem types: 87/*
90 4.2 4.3 ufs nfs swap ignore io vm efs dbg */ 88 * Puts the values from a struct fs_usage into a parameter_list with an additional flag to control how reserved
89 * and inodes should be judged (ignored or not)
90 */
91static parameter_list_elem get_path_stats(parameter_list_elem parameters, struct fs_usage fsp, bool freespace_ignore_reserved);
92static mp_subcheck evaluate_filesystem(measurement_unit measurement_unit, bool display_inodes_perfdata, byte_unit unit);
91 93
92/* static struct parameter_list *fs_select_list; */ 94void print_usage(void);
95static void print_help(void);
93 96
94/* Linked list of filesystem types to omit. 97static int verbose = 0;
95 If the list is empty, don't exclude any types. */
96static struct regex_list *fs_exclude_list = NULL;
97 98
98/* Linked list of filesystem types to check. 99// This would not be necessary in C23!!
99 If the list is empty, include all types. */ 100const byte_unit Bytes_Factor = 1;
100static struct regex_list *fs_include_list; 101const byte_unit KibiBytes_factor = 1024;
102const byte_unit MebiBytes_factor = 1048576;
103const byte_unit GibiBytes_factor = 1073741824;
104const byte_unit TebiBytes_factor = 1099511627776;
105const byte_unit PebiBytes_factor = 1125899906842624;
106const byte_unit ExbiBytes_factor = 1152921504606846976;
107const byte_unit KiloBytes_factor = 1000;
108const byte_unit MegaBytes_factor = 1000000;
109const byte_unit GigaBytes_factor = 1000000000;
110const byte_unit TeraBytes_factor = 1000000000000;
111const byte_unit PetaBytes_factor = 1000000000000000;
112const byte_unit ExaBytes_factor = 1000000000000000000;
113
114
115int main(int argc, char **argv) {
116 setlocale(LC_ALL, "");
117 bindtextdomain(PACKAGE, LOCALEDIR);
118 textdomain(PACKAGE);
101 119
102static struct name_list *dp_exclude_list; 120#ifdef __CYGWIN__
121 char mountdir[32];
122#endif
103 123
104static struct parameter_list *path_select_list = NULL; 124 // Parse extra opts if any
125 argv = np_extra_opts(&argc, argv, progname);
126
127 check_disk_config_wrapper tmp_config = process_arguments(argc, argv);
128 if (tmp_config.errorcode == ERROR) {
129 usage4(_("Could not parse arguments"));
130 }
131
132 check_disk_config config = tmp_config.config;
133
134 if (config.output_format_is_set) {
135 mp_set_format(config.output_format);
136 }
137
138 if (config.erronly) {
139 mp_set_level_of_detail(MP_DETAIL_NON_OK_ONLY);
140 }
141
142 if (!config.path_ignored) {
143 mp_int_fs_list_set_best_match(config.path_select_list, config.mount_list, config.exact_match);
144 }
145
146 // Error if no match found for specified paths
147 for (parameter_list_elem *elem = config.path_select_list.first; elem;) {
148 if (!elem->best_match && config.ignore_missing) {
149 /* Delete the path from the list so that it is not stat-checked later in the code. */
150 elem = mp_int_fs_list_del(&config.path_select_list, elem);
151 continue;
152 }
153 if (!elem->best_match) {
154 /* Without --ignore-missing option, exit with Critical state. */
155 die(STATE_CRITICAL, _("DISK %s: %s not found\n"), _("CRITICAL"), elem->name);
156 }
157
158 elem = mp_int_fs_list_get_next(elem);
159 }
160
161 mp_check overall = mp_check_init();
162 if (config.path_select_list.length == 0) {
163 mp_subcheck none_sc = mp_subcheck_init();
164 xasprintf(&none_sc.output, "No filesystems were found for the provided parameters");
165 if (config.ignore_missing) {
166 none_sc = mp_set_subcheck_state(none_sc, STATE_OK);
167 } else {
168 none_sc = mp_set_subcheck_state(none_sc, STATE_UNKNOWN);
169 if (verbose >= 2) {
170 printf("None of the provided paths were found\n");
171 }
172 }
173 mp_add_subcheck_to_check(&overall, none_sc);
174 mp_exit(overall);
175 }
105 176
106/* Linked list of mounted filesystems. */ 177 // Filter list first
107static struct mount_entry *mount_list; 178 for (parameter_list_elem *path = config.path_select_list.first; path;) {
179 if (!path->best_match) {
180 path = mp_int_fs_list_del(&config.path_select_list, path);
181 continue;
182 }
108 183
109/* For long options that have no equivalent short option, use a 184 struct mount_entry *mount_entry = path->best_match;
110 non-character as a pseudo short option, starting with CHAR_MAX + 1. */
111enum
112{
113 SYNC_OPTION = CHAR_MAX + 1,
114 NO_SYNC_OPTION,
115 BLOCK_SIZE_OPTION
116};
117 185
118#ifdef _AIX 186#ifdef __CYGWIN__
119#pragma alloca 187 if (strncmp(path->name, "/cygdrive/", 10) != 0 || strlen(path->name) > 11) {
188 path = mp_int_fs_list_del(&config.path_select_list, path);
189 continue;
190 }
191
192 char *mountdir = NULL;
193 snprintf(mountdir, sizeof(mountdir), "%s:\\", me->me_mountdir + 10);
194 if (GetDriveType(mountdir) != DRIVE_FIXED) {
195 mount_entry->me_remote = 1;
196 }
120#endif 197#endif
121 198
122static int process_arguments (int, char **); 199 /* Remove filesystems already seen */
123static void set_all_thresholds (struct parameter_list *path); 200 if (np_seen_name(config.seen, mount_entry->me_mountdir)) {
124static void print_help (void); 201 path = mp_int_fs_list_del(&config.path_select_list, path);
125void print_usage (void); 202 continue;
126static double calculate_percent(uintmax_t, uintmax_t); 203 }
127static bool stat_path (struct parameter_list *p); 204
128static void get_stats (struct parameter_list *p, struct fs_usage *fsp); 205 if (path->group == NULL) {
129static void get_path_stats (struct parameter_list *p, struct fs_usage *fsp); 206 if (config.fs_exclude_list && np_find_regmatch(config.fs_exclude_list, mount_entry->me_type)) {
130 207 // Skip excluded fs's
131static char *units; 208 path = mp_int_fs_list_del(&config.path_select_list, path);
132static uintmax_t mult = 1024 * 1024; 209 continue;
133static int verbose = 0; 210 }
134static bool erronly = false;
135static bool display_mntp = false;
136static bool exact_match = false;
137static bool ignore_missing = false;
138static bool freespace_ignore_reserved = false;
139static bool display_inodes_perfdata = false;
140static char *warn_freespace_units = NULL;
141static char *crit_freespace_units = NULL;
142static char *warn_freespace_percent = NULL;
143static char *crit_freespace_percent = NULL;
144static char *warn_usedspace_units = NULL;
145static char *crit_usedspace_units = NULL;
146static char *warn_usedspace_percent = NULL;
147static char *crit_usedspace_percent = NULL;
148static char *warn_usedinodes_percent = NULL;
149static char *crit_usedinodes_percent = NULL;
150static char *warn_freeinodes_percent = NULL;
151static char *crit_freeinodes_percent = NULL;
152static bool path_selected = false;
153static bool path_ignored = false;
154static char *group = NULL;
155static struct stat *stat_buf;
156static struct name_list *seen = NULL;
157
158
159int
160main (int argc, char **argv)
161{
162 int result = STATE_UNKNOWN;
163 int disk_result = STATE_UNKNOWN;
164 char *output;
165 char *ignored;
166 char *details;
167 char *perf;
168 char *perf_ilabel;
169 char *preamble = " - free space:";
170 char *ignored_preamble = " - ignored paths:";
171 char *flag_header;
172 int temp_result;
173
174 struct mount_entry *me;
175 struct fs_usage fsp;
176 struct parameter_list *temp_list, *path;
177 211
178#ifdef __CYGWIN__ 212 if (config.device_path_exclude_list && (np_find_name(config.device_path_exclude_list, mount_entry->me_devname) ||
179 char mountdir[32]; 213 np_find_name(config.device_path_exclude_list, mount_entry->me_mountdir))) {
180#endif 214 // Skip excluded device or mount paths
215 path = mp_int_fs_list_del(&config.path_select_list, path);
216 continue;
217 }
181 218
182 output = strdup (""); 219 if (config.fs_include_list && !np_find_regmatch(config.fs_include_list, mount_entry->me_type)) {
183 ignored = strdup (""); 220 // Skip not included fstypes
184 details = strdup (""); 221 path = mp_int_fs_list_del(&config.path_select_list, path);
185 perf = strdup (""); 222 continue;
186 perf_ilabel = strdup (""); 223 }
187 stat_buf = malloc(sizeof *stat_buf);
188
189 setlocale (LC_ALL, "");
190 bindtextdomain (PACKAGE, LOCALEDIR);
191 textdomain (PACKAGE);
192
193 mount_list = read_file_system_list (0);
194
195 /* Parse extra opts if any */
196 argv = np_extra_opts (&argc, argv, progname);
197
198 if (process_arguments (argc, argv) == ERROR)
199 usage4 (_("Could not parse arguments"));
200
201 /* If a list of paths has not been selected, find entire
202 mount list and create list of paths
203 */
204 if (path_selected == false && path_ignored == false) {
205 for (me = mount_list; me; me = me->me_next) {
206 if (! (path = np_find_parameter(path_select_list, me->me_mountdir))) {
207 path = np_add_parameter(&path_select_list, me->me_mountdir);
208 }
209 path->best_match = me;
210 path->group = group;
211 set_all_thresholds(path);
212 }
213 }
214
215 if (path_ignored == false) {
216 np_set_best_match(path_select_list, mount_list, exact_match);
217 }
218
219 /* Error if no match found for specified paths */
220 temp_list = path_select_list;
221
222 while (path_select_list) {
223 if (! path_select_list->best_match && ignore_missing == true) {
224 /* If the first element will be deleted, the temp_list must be updated with the new start address as well */
225 if (path_select_list == temp_list) {
226 temp_list = path_select_list->name_next;
227 }
228 /* Add path argument to list of ignored paths to inform about missing paths being ignored and not alerted */
229 xasprintf (&ignored, "%s %s;", ignored, path_select_list->name);
230 /* Delete the path from the list so that it is not stat-checked later in the code. */
231 path_select_list = np_del_parameter(path_select_list, path_select_list->name_prev);
232 } else if (! path_select_list->best_match) {
233 /* Without --ignore-missing option, exit with Critical state. */
234 die (STATE_CRITICAL, _("DISK %s: %s not found\n"), _("CRITICAL"), path_select_list->name);
235 } else {
236 /* Continue jumping through the list */
237 path_select_list = path_select_list->name_next;
238 }
239 }
240
241 path_select_list = temp_list;
242
243 if (! path_select_list && ignore_missing == true) {
244 result = STATE_OK;
245 if (verbose >= 2) {
246 printf ("None of the provided paths were found\n");
247 }
248 }
249
250 /* Process for every path in list */
251 for (path = path_select_list; path; path=path->name_next) {
252 if (verbose >= 3 && path->freespace_percent->warning != NULL && path->freespace_percent->critical != NULL)
253 printf("Thresholds(pct) for %s warn: %f crit %f\n",
254 path->name,
255 path->freespace_percent->warning->end,
256 path->freespace_percent->critical->end);
257
258 if (verbose >= 3 && path->group != NULL)
259 printf("Group of %s: %s\n",path->name,path->group);
260
261 /* reset disk result */
262 disk_result = STATE_UNKNOWN;
263
264 me = path->best_match;
265
266 if (!me) {
267 continue;
268 }
269 224
270#ifdef __CYGWIN__ 225 /* Skip remote filesystems if we're not interested in them */
271 if (strncmp(path->name, "/cygdrive/", 10) != 0 || strlen(path->name) > 11) 226 if (mount_entry->me_remote && config.show_local_fs) {
272 continue; 227 if (config.stat_remote_fs) {
273 snprintf(mountdir, sizeof(mountdir), "%s:\\", me->me_mountdir + 10); 228 // TODO Stat here
274 if (GetDriveType(mountdir) != DRIVE_FIXED) 229 if (!stat_path(path, config.ignore_missing) && config.ignore_missing) {
275 me->me_remote = 1; 230 }
276#endif 231 }
277 /* Filters */ 232 continue;
278 233 }
279 /* Remove filesystems already seen */
280 if (np_seen_name(seen, me->me_mountdir)) {
281 continue;
282 }
283 np_add_name(&seen, me->me_mountdir);
284
285 if (path->group == NULL) {
286 /* Skip remote filesystems if we're not interested in them */
287 if (me->me_remote && show_local_fs) {
288 if (stat_remote_fs) {
289 if (!stat_path(path) && ignore_missing == true) {
290 result = STATE_OK;
291 xasprintf (&ignored, "%s %s;", ignored, path->name);
292 }
293 }
294 continue;
295 /* Skip pseudo fs's if we haven't asked for all fs's */
296 } else if (me->me_dummy && !show_all_fs) {
297 continue;
298 /* Skip excluded fstypes */
299 } else if (fs_exclude_list && np_find_regmatch (fs_exclude_list, me->me_type)) {
300 continue;
301 /* Skip excluded fs's */
302 } else if (dp_exclude_list &&
303 (np_find_name (dp_exclude_list, me->me_devname) ||
304 np_find_name (dp_exclude_list, me->me_mountdir))) {
305 continue;
306 /* Skip not included fstypes */
307 } else if (fs_include_list && !np_find_regmatch(fs_include_list, me->me_type)) {
308 continue;
309 }
310 }
311
312 if (!stat_path(path)) {
313 if (ignore_missing == true) {
314 result = STATE_OK;
315 xasprintf (&ignored, "%s %s;", ignored, path->name);
316 }
317 continue;
318 }
319 get_fs_usage (me->me_mountdir, me->me_devname, &fsp);
320
321 if (fsp.fsu_blocks && strcmp ("none", me->me_mountdir)) {
322 get_stats (path, &fsp);
323
324 if (verbose >= 3) {
325 printf ("For %s, used_pct=%f free_pct=%f used_units=%lu free_units=%lu total_units=%lu used_inodes_pct=%f free_inodes_pct=%f fsp.fsu_blocksize=%lu mult=%lu\n",
326 me->me_mountdir,
327 path->dused_pct,
328 path->dfree_pct,
329 path->dused_units,
330 path->dfree_units,
331 path->dtotal_units,
332 path->dused_inodes_percent,
333 path->dfree_inodes_percent,
334 fsp.fsu_blocksize,
335 mult);
336 }
337
338 /* Threshold comparisons */
339
340 temp_result = get_status(path->dfree_units, path->freespace_units);
341 if (verbose >=3) printf("Freespace_units result=%d\n", temp_result);
342 disk_result = max_state( disk_result, temp_result );
343
344 temp_result = get_status(path->dfree_pct, path->freespace_percent);
345 if (verbose >=3) printf("Freespace%% result=%d\n", temp_result);
346 disk_result = max_state( disk_result, temp_result );
347
348 temp_result = get_status(path->dused_units, path->usedspace_units);
349 if (verbose >=3) printf("Usedspace_units result=%d\n", temp_result);
350 disk_result = max_state( disk_result, temp_result );
351
352 temp_result = get_status(path->dused_pct, path->usedspace_percent);
353 if (verbose >=3) printf("Usedspace_percent result=%d\n", temp_result);
354 disk_result = max_state( disk_result, temp_result );
355
356 temp_result = get_status(path->dused_inodes_percent, path->usedinodes_percent);
357 if (verbose >=3) printf("Usedinodes_percent result=%d\n", temp_result);
358 disk_result = max_state( disk_result, temp_result );
359
360 temp_result = get_status(path->dfree_inodes_percent, path->freeinodes_percent);
361 if (verbose >=3) printf("Freeinodes_percent result=%d\n", temp_result);
362 disk_result = max_state( disk_result, temp_result );
363
364 result = max_state(result, disk_result);
365
366 /* What a mess of units. The output shows free space, the perf data shows used space. Yikes!
367 Hack here. Trying to get warn/crit levels from freespace_(units|percent) for perf
368 data. Assumption that start=0. Roll on new syntax...
369 */
370
371 /* *_high_tide must be reinitialized at each run */
372 uint64_t warning_high_tide = UINT64_MAX;
373
374 if (path->freespace_units->warning != NULL) {
375 warning_high_tide = (path->dtotal_units - path->freespace_units->warning->end) * mult;
376 }
377 if (path->freespace_percent->warning != NULL) {
378 warning_high_tide = min( warning_high_tide, (uint64_t)((1.0 - path->freespace_percent->warning->end/100) * (path->dtotal_units * mult)) );
379 }
380
381 uint64_t critical_high_tide = UINT64_MAX;
382
383 if (path->freespace_units->critical != NULL) {
384 critical_high_tide = (path->dtotal_units - path->freespace_units->critical->end) * mult;
385 }
386 if (path->freespace_percent->critical != NULL) {
387 critical_high_tide = min( critical_high_tide, (uint64_t)((1.0 - path->freespace_percent->critical->end/100) * (path->dtotal_units * mult)) );
388 }
389
390 /* Nb: *_high_tide are unset when == UINT64_MAX */
391 xasprintf (&perf, "%s %s", perf,
392 perfdata_uint64 (
393 (!strcmp(me->me_mountdir, "none") || display_mntp) ? me->me_devname : me->me_mountdir,
394 path->dused_units * mult, "B",
395 (warning_high_tide == UINT64_MAX ? false : true), warning_high_tide,
396 (critical_high_tide == UINT64_MAX ? false : true), critical_high_tide,
397 true, 0,
398 true, path->dtotal_units * mult));
399
400 if (display_inodes_perfdata) {
401 /* *_high_tide must be reinitialized at each run */
402 warning_high_tide = UINT64_MAX;
403 critical_high_tide = UINT64_MAX;
404
405 if (path->freeinodes_percent->warning != NULL) {
406 warning_high_tide = (uint64_t) fabs( min( (double) warning_high_tide, (double) (1.0 - path->freeinodes_percent->warning->end/100)*path->inodes_total ));
407 }
408 if (path->freeinodes_percent->critical != NULL) {
409 critical_high_tide = (uint64_t) fabs( min( (double) critical_high_tide, (double) (1.0 - path->freeinodes_percent->critical->end/100)*path->inodes_total ));
410 }
411
412 xasprintf (&perf_ilabel, "%s (inodes)", (!strcmp(me->me_mountdir, "none") || display_mntp) ? me->me_devname : me->me_mountdir);
413 /* Nb: *_high_tide are unset when == UINT64_MAX */
414 xasprintf (&perf, "%s %s", perf,
415 perfdata_uint64 (perf_ilabel,
416 path->inodes_used, "",
417 (warning_high_tide != UINT64_MAX ? true : false), warning_high_tide,
418 (critical_high_tide != UINT64_MAX ? true : false), critical_high_tide,
419 true, 0,
420 true, path->inodes_total));
421 }
422
423 if (disk_result==STATE_OK && erronly && !verbose)
424 continue;
425
426 if(disk_result && verbose >= 1) {
427 xasprintf(&flag_header, " %s [", state_text (disk_result));
428 } else {
429 xasprintf(&flag_header, "");
430 }
431 xasprintf (&output, "%s%s %s %llu%s (%.1f%%",
432 output, flag_header,
433 (!strcmp(me->me_mountdir, "none") || display_mntp) ? me->me_devname : me->me_mountdir,
434 path->dfree_units,
435 units,
436 path->dfree_pct);
437 if (path->dused_inodes_percent < 0) {
438 xasprintf(&output, "%s inode=-)%s;", output, (disk_result ? "]" : ""));
439 } else {
440 xasprintf(&output, "%s inode=%.0f%%)%s;", output, path->dfree_inodes_percent, ((disk_result && verbose >= 1) ? "]" : ""));
441 }
442 free(flag_header);
443 }
444 }
445
446 if (verbose >= 2)
447 xasprintf (&output, "%s%s", output, details);
448
449 if (strcmp(output, "") == 0 && ! erronly) {
450 preamble = "";
451 xasprintf (&output, " - No disks were found for provided parameters");
452 }
453
454 printf ("DISK %s%s%s%s%s|%s\n", state_text (result), ((erronly && result==STATE_OK)) ? "" : preamble, output, (strcmp(ignored, "") == 0) ? "" : ignored_preamble, ignored, perf);
455 return result;
456}
457 234
235 // TODO why stat here? remove unstatable fs?
236 if (!stat_path(path, config.ignore_missing)) {
237 // if (config.ignore_missing) {
238 // xasprintf(&ignored, "%s %s;", ignored, path->name);
239 // }
240 // not accessible, remove from list
241 path = mp_int_fs_list_del(&config.path_select_list, path);
242 continue;
243 }
244 }
245
246 path = mp_int_fs_list_get_next(path);
247 }
248
249 // now get the actual measurements
250 for (parameter_list_elem *filesystem = config.path_select_list.first; filesystem;) {
251 // Get actual metrics here
252 struct mount_entry *mount_entry = filesystem->best_match;
253 struct fs_usage fsp = {0};
254 get_fs_usage(mount_entry->me_mountdir, mount_entry->me_devname, &fsp);
255
256 if (fsp.fsu_blocks != 0 && strcmp("none", mount_entry->me_mountdir) != 0) {
257 *filesystem = get_path_stats(*filesystem, fsp, config.freespace_ignore_reserved);
258
259 if (verbose >= 3) {
260 printf("For %s, used_units=%lu free_units=%lu total_units=%lu "
261 "fsp.fsu_blocksize=%lu\n",
262 mount_entry->me_mountdir, filesystem->used_bytes, filesystem->free_bytes, filesystem->total_bytes,
263 fsp.fsu_blocksize);
264 }
265 } else {
266 // failed to retrieve file system data or not mounted?
267 filesystem = mp_int_fs_list_del(&config.path_select_list, filesystem);
268 continue;
269 }
270 filesystem = mp_int_fs_list_get_next(filesystem);
271 }
272
273 if (verbose > 2) {
274 for (parameter_list_elem *filesystem = config.path_select_list.first; filesystem;
275 filesystem = mp_int_fs_list_get_next(filesystem)) {
276 assert(filesystem->best_match != NULL);
277 if (filesystem->best_match == NULL) {
278 printf("Filesystem path %s has no mount_entry!\n", filesystem->name);
279 } else {
280 // printf("Filesystem path %s has a mount_entry!\n", filesystem->name);
281 }
282 }
283 }
284
285 measurement_unit_list *measurements = NULL;
286 measurement_unit_list *current = NULL;
287 // create measuring units, because of groups
288 for (parameter_list_elem *filesystem = config.path_select_list.first; filesystem; filesystem = mp_int_fs_list_get_next(filesystem)) {
289 assert(filesystem->best_match != NULL);
290
291 if (filesystem->group == NULL) {
292 // create a measurement unit for the fs
293 measurement_unit unit = create_measurement_unit_from_filesystem(*filesystem, config.display_mntp);
294 if (measurements == NULL) {
295 measurements = current = add_measurement_list(NULL, unit);
296 } else {
297 current = add_measurement_list(measurements, unit);
298 }
299 } else {
300 // Grouped elements are consecutive
301 if (measurements == NULL) {
302 // first entry
303 measurement_unit unit = create_measurement_unit_from_filesystem(*filesystem, config.display_mntp);
304 unit.name = strdup(filesystem->group);
305 measurements = current = add_measurement_list(NULL, unit);
306 } else {
307 // if this is the first element of a group, the name of the previous entry is different
308 if (strcmp(filesystem->group, current->unit.name) != 0) {
309 // so, this must be the first element of a group
310 measurement_unit unit = create_measurement_unit_from_filesystem(*filesystem, config.display_mntp);
311 unit.name = filesystem->group;
312 current = add_measurement_list(measurements, unit);
313
314 } else {
315 // NOT the first entry of a group, add info to the other one
316 current->unit = add_filesystem_to_measurement_unit(current->unit, *filesystem);
317 }
318 }
319 }
320 }
321
322 /* Process for every path in list */
323 if (measurements != NULL) {
324 for (measurement_unit_list *unit = measurements; unit; unit = unit->next) {
325 mp_subcheck unit_sc = evaluate_filesystem(unit->unit, config.display_inodes_perfdata, config.display_unit);
326 mp_add_subcheck_to_check(&overall, unit_sc);
327 }
328 } else {
329 // Apparently no machting fs found
330 mp_subcheck none_sc = mp_subcheck_init();
331 xasprintf(&none_sc.output, "No filesystems were found for the provided parameters");
332
333 if (config.ignore_missing) {
334 none_sc = mp_set_subcheck_state(none_sc, STATE_OK);
335 } else {
336 none_sc = mp_set_subcheck_state(none_sc, STATE_UNKNOWN);
337 }
338 mp_add_subcheck_to_check(&overall, none_sc);
339 }
340
341 mp_exit(overall);
342}
458 343
459double calculate_percent(uintmax_t value, uintmax_t total) { 344double calculate_percent(uintmax_t value, uintmax_t total) {
460 double pct = -1; 345 double pct = -1;
461 if(value <= DBL_MAX && total != 0) { 346 if (value <= DBL_MAX && total != 0) {
462 pct = (double)value / total * 100.0; 347 pct = (double)value / (double)total * 100.0;
463 } 348 }
464 return pct; 349
350 return pct;
465} 351}
466 352
467/* process command-line arguments */ 353/* process command-line arguments */
468int 354check_disk_config_wrapper process_arguments(int argc, char **argv) {
469process_arguments (int argc, char **argv) 355
470{ 356 check_disk_config_wrapper result = {
471 int c, err; 357 .errorcode = OK,
472 struct parameter_list *se; 358 .config = check_disk_config_init(),
473 struct parameter_list *temp_list = NULL, *previous = NULL; 359 };
474 struct mount_entry *me; 360
475 regex_t re; 361 if (argc < 2) {
476 int cflags = REG_NOSUB | REG_EXTENDED; 362 result.errorcode = ERROR;
477 int default_cflags = cflags; 363 return result;
478 char errbuf[MAX_INPUT_BUFFER]; 364 }
479 int fnd = 0; 365
480 366 enum {
481 int option = 0; 367 output_format_index = CHAR_MAX + 1,
482 static struct option longopts[] = { 368 display_unit_index,
483 {"timeout", required_argument, 0, 't'}, 369 };
484 {"warning", required_argument, 0, 'w'}, 370
485 {"critical", required_argument, 0, 'c'}, 371 static struct option longopts[] = {{"timeout", required_argument, 0, 't'},
486 {"iwarning", required_argument, 0, 'W'}, 372 {"warning", required_argument, 0, 'w'},
487 /* Dang, -C is taken. We might want to reshuffle this. */ 373 {"critical", required_argument, 0, 'c'},
488 {"icritical", required_argument, 0, 'K'}, 374 {"iwarning", required_argument, 0, 'W'},
489 {"kilobytes", no_argument, 0, 'k'}, 375 {"icritical", required_argument, 0, 'K'},
490 {"megabytes", no_argument, 0, 'm'}, 376 {"kilobytes", no_argument, 0, 'k'},
491 {"units", required_argument, 0, 'u'}, 377 {"megabytes", no_argument, 0, 'm'},
492 {"path", required_argument, 0, 'p'}, 378 {"units", required_argument, 0, 'u'},
493 {"partition", required_argument, 0, 'p'}, 379 {"path", required_argument, 0, 'p'},
494 {"exclude_device", required_argument, 0, 'x'}, 380 {"partition", required_argument, 0, 'p'},
495 {"exclude-type", required_argument, 0, 'X'}, 381 {"exclude_device", required_argument, 0, 'x'},
496 {"include-type", required_argument, 0, 'N'}, 382 {"exclude-type", required_argument, 0, 'X'},
497 {"group", required_argument, 0, 'g'}, 383 {"include-type", required_argument, 0, 'N'},
498 {"eregi-path", required_argument, 0, 'R'}, 384 {"group", required_argument, 0, 'g'},
499 {"eregi-partition", required_argument, 0, 'R'}, 385 {"eregi-path", required_argument, 0, 'R'},
500 {"ereg-path", required_argument, 0, 'r'}, 386 {"eregi-partition", required_argument, 0, 'R'},
501 {"ereg-partition", required_argument, 0, 'r'}, 387 {"ereg-path", required_argument, 0, 'r'},
502 {"freespace-ignore-reserved", no_argument, 0, 'f'}, 388 {"ereg-partition", required_argument, 0, 'r'},
503 {"ignore-ereg-path", required_argument, 0, 'i'}, 389 {"freespace-ignore-reserved", no_argument, 0, 'f'},
504 {"ignore-ereg-partition", required_argument, 0, 'i'}, 390 {"ignore-ereg-path", required_argument, 0, 'i'},
505 {"ignore-eregi-path", required_argument, 0, 'I'}, 391 {"ignore-ereg-partition", required_argument, 0, 'i'},
506 {"ignore-eregi-partition", required_argument, 0, 'I'}, 392 {"ignore-eregi-path", required_argument, 0, 'I'},
507 {"ignore-missing", no_argument, 0, 'n'}, 393 {"ignore-eregi-partition", required_argument, 0, 'I'},
508 {"local", no_argument, 0, 'l'}, 394 {"ignore-missing", no_argument, 0, 'n'},
509 {"stat-remote-fs", no_argument, 0, 'L'}, 395 {"local", no_argument, 0, 'l'},
510 {"iperfdata", no_argument, 0, 'P'}, 396 {"stat-remote-fs", no_argument, 0, 'L'},
511 {"mountpoint", no_argument, 0, 'M'}, 397 {"iperfdata", no_argument, 0, 'P'},
512 {"errors-only", no_argument, 0, 'e'}, 398 {"mountpoint", no_argument, 0, 'M'},
513 {"exact-match", no_argument, 0, 'E'}, 399 {"errors-only", no_argument, 0, 'e'},
514 {"all", no_argument, 0, 'A'}, 400 {"exact-match", no_argument, 0, 'E'},
515 {"verbose", no_argument, 0, 'v'}, 401 {"all", no_argument, 0, 'A'},
516 {"quiet", no_argument, 0, 'q'}, 402 {"verbose", no_argument, 0, 'v'},
517 {"clear", no_argument, 0, 'C'}, 403 {"quiet", no_argument, 0, 'q'},
518 {"version", no_argument, 0, 'V'}, 404 {"clear", no_argument, 0, 'C'},
519 {"help", no_argument, 0, 'h'}, 405 {"version", no_argument, 0, 'V'},
520 {0, 0, 0, 0} 406 {"help", no_argument, 0, 'h'},
521 }; 407 {"output-format", required_argument, 0, output_format_index},
522 408 {"display-unit", required_argument, 0, display_unit_index},
523 if (argc < 2) 409 {0, 0, 0, 0}};
524 return ERROR; 410
525 411 for (int index = 1; index < argc; index++) {
526 np_add_regex(&fs_exclude_list, "iso9660", REG_EXTENDED); 412 if (strcmp("-to", argv[index]) == 0) {
527 413 strcpy(argv[index], "-t");
528 for (c = 1; c < argc; c++) 414 }
529 if (strcmp ("-to", argv[c]) == 0) 415 }
530 strcpy (argv[c], "-t"); 416
531 417 int cflags = REG_NOSUB | REG_EXTENDED;
532 while (1) { 418 int default_cflags = cflags;
533 c = getopt_long (argc, argv, "+?VqhvefCt:c:w:K:W:u:p:x:X:N:mklLPg:R:r:i:I:MEAn", longopts, &option); 419 char *warn_freespace_units = NULL;
534 420 char *crit_freespace_units = NULL;
535 if (c == -1 || c == EOF) 421 char *warn_freespace_percent = NULL;
536 break; 422 char *crit_freespace_percent = NULL;
537 423 char *warn_freeinodes_percent = NULL;
538 switch (c) { 424 char *crit_freeinodes_percent = NULL;
539 case 't': /* timeout period */ 425
540 if (is_integer (optarg)) { 426 bool path_selected = false;
541 timeout_interval = atoi (optarg); 427 char *group = NULL;
542 break; 428 byte_unit unit = MebiBytes_factor;
543 } 429
544 else { 430 result.config.mount_list = read_file_system_list(false);
545 usage2 (_("Timeout interval must be a positive integer"), optarg); 431
546 } 432 np_add_regex(&result.config.fs_exclude_list, "iso9660", REG_EXTENDED);
547 433
548 /* See comments for 'c' */ 434 while (true) {
549 case 'w': /* warning threshold */ 435 int option = 0;
436 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);
437
438 if (option_index == -1 || option_index == EOF) {
439 break;
440 }
441
442 switch (option_index) {
443 case 't': /* timeout period */
444 if (is_integer(optarg)) {
445 timeout_interval = atoi(optarg);
446 break;
447 } else {
448 usage2(_("Timeout interval must be a positive integer"), optarg);
449 }
450
451 /* See comments for 'c' */
452 case 'w': /* warning threshold */
550 if (!is_percentage_expression(optarg) && !is_numeric(optarg)) { 453 if (!is_percentage_expression(optarg) && !is_numeric(optarg)) {
551 die(STATE_UNKNOWN, "Argument for --warning invalid or missing: %s\n", optarg); 454 die(STATE_UNKNOWN, "Argument for --warning invalid or missing: %s\n", optarg);
552 } 455 }
553 456
554 if (strstr(optarg, "%")) { 457 if (strstr(optarg, "%")) {
555 if (*optarg == '@') { 458 if (*optarg == '@') {
556 warn_freespace_percent = optarg; 459 warn_freespace_percent = optarg;
557 } else { 460 } else {
558 xasprintf(&warn_freespace_percent, "@%s", optarg); 461 xasprintf(&warn_freespace_percent, "@%s", optarg);
559 } 462 }
560 } else { 463 } else {
561 if (*optarg == '@') { 464 if (*optarg == '@') {
562 warn_freespace_units = optarg; 465 warn_freespace_units = optarg;
563 } else { 466 } else {
564 xasprintf(&warn_freespace_units, "@%s", optarg); 467 xasprintf(&warn_freespace_units, "@%s", optarg);
565 } 468 }
566 } 469 }
567 break; 470 break;
568 471
569 /* Awful mistake where the range values do not make sense. Normally, 472 /* Awful mistake where the range values do not make sense. Normally,
570 you alert if the value is within the range, but since we are using 473 * you alert if the value is within the range, but since we are using
571 freespace, we have to alert if outside the range. Thus we artificially 474 * freespace, we have to alert if outside the range. Thus we artificially
572 force @ at the beginning of the range, so that it is backwards compatible 475 * force @ at the beginning of the range, so that it is backwards compatible
573 */ 476 */
574 case 'c': /* critical threshold */ 477 case 'c': /* critical threshold */
575 if (!is_percentage_expression(optarg) && !is_numeric(optarg)) { 478 if (!is_percentage_expression(optarg) && !is_numeric(optarg)) {
576 die(STATE_UNKNOWN, "Argument for --critical invalid or missing: %s\n", optarg); 479 die(STATE_UNKNOWN, "Argument for --critical invalid or missing: %s\n", optarg);
577 } 480 }
578 481
579 if (strstr(optarg, "%")) { 482 if (strstr(optarg, "%")) {
580 if (*optarg == '@') { 483 if (*optarg == '@') {
581 crit_freespace_percent = optarg; 484 crit_freespace_percent = optarg;
582 } else { 485 } else {
583 xasprintf(&crit_freespace_percent, "@%s", optarg); 486 xasprintf(&crit_freespace_percent, "@%s", optarg);
584 } 487 }
585 } else { 488 } else {
586 if (*optarg == '@') { 489 if (*optarg == '@') {
587 crit_freespace_units = optarg; 490 crit_freespace_units = optarg;
588 } else { 491 } else {
589 xasprintf(&crit_freespace_units, "@%s", optarg); 492 xasprintf(&crit_freespace_units, "@%s", optarg);
590 } 493 }
591 } 494 }
592 break; 495 break;
593
594 case 'W': /* warning inode threshold */
595 if (*optarg == '@') {
596 warn_freeinodes_percent = optarg;
597 } else {
598 xasprintf(&warn_freeinodes_percent, "@%s", optarg);
599 }
600 break;
601 case 'K': /* critical inode threshold */
602 if (*optarg == '@') {
603 crit_freeinodes_percent = optarg;
604 } else {
605 xasprintf(&crit_freeinodes_percent, "@%s", optarg);
606 }
607 break;
608 case 'u':
609 if (units)
610 free(units);
611 if (! strcasecmp (optarg, "bytes")) {
612 mult = (uintmax_t)1;
613 units = strdup ("B");
614 } else if (!strcmp(optarg, "KiB")) {
615 mult = (uintmax_t)1024;
616 units = strdup ("KiB");
617 } else if (! strcmp (optarg, "kB")) {
618 mult = (uintmax_t)1000;
619 units = strdup ("kB");
620 } else if (!strcmp(optarg, "MiB")) {
621 mult = (uintmax_t)1024 * 1024;
622 units = strdup ("MiB");
623 } else if (! strcmp (optarg, "MB")) {
624 mult = (uintmax_t)1000 * 1000;
625 units = strdup ("MB");
626 } else if (!strcmp(optarg, "GiB")) {
627 mult = (uintmax_t)1024 * 1024 * 1024;
628 units = strdup ("GiB");
629 } else if (! strcmp (optarg, "GB")){
630 mult = (uintmax_t)1000 * 1000 * 1000;
631 units = strdup ("GB");
632 } else if (!strcmp(optarg, "TiB")) {
633 mult = (uintmax_t)1024 * 1024 * 1024 * 1024;
634 units = strdup ("TiB");
635 } else if (! strcmp (optarg, "TB")) {
636 mult = (uintmax_t)1000 * 1000 * 1000 * 1000;
637 units = strdup ("TB");
638 } else if (!strcmp(optarg, "PiB")) {
639 mult = (uintmax_t)1024 * 1024 * 1024 * 1024 * 1024;
640 units = strdup ("PiB");
641 } else if (! strcmp (optarg, "PB")){
642 mult = (uintmax_t)1000 * 1000 * 1000 * 1000 * 1000;
643 units = strdup ("PB");
644 } else {
645 die (STATE_UNKNOWN, _("unit type %s not known\n"), optarg);
646 }
647 if (units == NULL)
648 die (STATE_UNKNOWN, _("failed allocating storage for '%s'\n"), "units");
649 break;
650 case 'k': /* display mountpoint */
651 mult = 1024;
652 if (units)
653 free(units);
654 units = strdup ("kiB");
655 break;
656 case 'm': /* display mountpoint */
657 mult = 1024 * 1024;
658 if (units)
659 free(units);
660 units = strdup ("MiB");
661 break;
662 case 'L':
663 stat_remote_fs = 1;
664 /* fallthrough */
665 case 'l':
666 show_local_fs = 1;
667 break;
668 case 'P':
669 display_inodes_perfdata = 1;
670 break;
671 case 'p': /* select path */
672 if (! (warn_freespace_units || crit_freespace_units || warn_freespace_percent ||
673 crit_freespace_percent || warn_usedspace_units || crit_usedspace_units ||
674 warn_usedspace_percent || crit_usedspace_percent || warn_usedinodes_percent ||
675 crit_usedinodes_percent || warn_freeinodes_percent || crit_freeinodes_percent )) {
676 die (STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set a threshold value before using -p\n"));
677 }
678
679 /* add parameter if not found. overwrite thresholds if path has already been added */
680 if (! (se = np_find_parameter(path_select_list, optarg))) {
681 se = np_add_parameter(&path_select_list, optarg);
682
683 if (stat(optarg, &stat_buf[0]) && ignore_missing == true) {
684 path_ignored = true;
685 break;
686 }
687 }
688 se->group = group;
689 set_all_thresholds(se);
690
691 /* With autofs, it is required to stat() the path before re-populating the mount_list */
692 if (!stat_path(se)) {
693 break;
694 }
695 /* NB: We can't free the old mount_list "just like that": both list pointers and struct
696 * pointers are copied around. One of the reason it wasn't done yet is that other parts
697 * of check_disk need the same kind of cleanup so it'd better be done as a whole */
698 mount_list = read_file_system_list (0);
699 np_set_best_match(se, mount_list, exact_match);
700
701 path_selected = true;
702 break;
703 case 'x': /* exclude path or partition */
704 np_add_name(&dp_exclude_list, optarg);
705 break;
706 case 'X': /* exclude file system type */
707 err = np_add_regex(&fs_exclude_list, optarg, REG_EXTENDED);
708 if (err != 0) {
709 regerror (err, &fs_exclude_list->regex, errbuf, MAX_INPUT_BUFFER);
710 die (STATE_UNKNOWN, "DISK %s: %s - %s\n",_("UNKNOWN"), _("Could not compile regular expression"), errbuf);
711 }
712 break;
713 case 'N': /* include file system type */
714 err = np_add_regex(&fs_include_list, optarg, REG_EXTENDED);
715 if (err != 0) {
716 regerror (err, &fs_exclude_list->regex, errbuf, MAX_INPUT_BUFFER);
717 die (STATE_UNKNOWN, "DISK %s: %s - %s\n",_("UNKNOWN"), _("Could not compile regular expression"), errbuf);
718 }
719 break;
720 case 'v': /* verbose */
721 verbose++;
722 break;
723 case 'q': /* TODO: this function should eventually go away (removed 2007-09-20) */
724 /* verbose--; **replaced by line below**. -q was only a broken way of implementing -e */
725 erronly = true;
726 break;
727 case 'e':
728 erronly = true;
729 break;
730 case 'E':
731 if (path_selected)
732 die (STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set -E before selecting paths\n"));
733 exact_match = true;
734 break;
735 case 'f':
736 freespace_ignore_reserved = true;
737 break;
738 case 'g':
739 if (path_selected)
740 die (STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set group value before selecting paths\n"));
741 group = optarg;
742 break;
743 case 'I':
744 cflags |= REG_ICASE;
745 // Intentional fallthrough
746 case 'i':
747 if (!path_selected)
748 die (STATE_UNKNOWN, "DISK %s: %s\n", _("UNKNOWN"), _("Paths need to be selected before using -i/-I. Use -A to select all paths explicitly"));
749 err = regcomp(&re, optarg, cflags);
750 if (err != 0) {
751 regerror (err, &re, errbuf, MAX_INPUT_BUFFER);
752 die (STATE_UNKNOWN, "DISK %s: %s - %s\n",_("UNKNOWN"), _("Could not compile regular expression"), errbuf);
753 }
754
755 temp_list = path_select_list;
756
757 previous = NULL;
758 while (temp_list) {
759 if (temp_list->best_match) {
760 if (np_regex_match_mount_entry(temp_list->best_match, &re)) {
761
762 if (verbose >=3)
763 printf("ignoring %s matching regex\n", temp_list->name);
764
765 temp_list = np_del_parameter(temp_list, previous);
766 /* pointer to first element needs to be updated if first item gets deleted */
767 if (previous == NULL)
768 path_select_list = temp_list;
769 } else {
770 previous = temp_list;
771 temp_list = temp_list->name_next;
772 }
773 } else {
774 previous = temp_list;
775 temp_list = temp_list->name_next;
776 }
777 }
778
779
780 cflags = default_cflags;
781 break;
782
783 case 'n':
784 ignore_missing = true;
785 break;
786 case 'A':
787 optarg = strdup(".*");
788 // Intentional fallthrough
789 case 'R':
790 cflags |= REG_ICASE;
791 // Intentional fallthrough
792 case 'r':
793 if (! (warn_freespace_units || crit_freespace_units || warn_freespace_percent ||
794 crit_freespace_percent || warn_usedspace_units || crit_usedspace_units ||
795 warn_usedspace_percent || crit_usedspace_percent || warn_usedinodes_percent ||
796 crit_usedinodes_percent || warn_freeinodes_percent || crit_freeinodes_percent )) {
797 die (STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set a threshold value before using -r/-R/-A (--ereg-path/--eregi-path/--all)\n"));
798 }
799
800 err = regcomp(&re, optarg, cflags);
801 if (err != 0) {
802 regerror (err, &re, errbuf, MAX_INPUT_BUFFER);
803 die (STATE_UNKNOWN, "DISK %s: %s - %s\n",_("UNKNOWN"), _("Could not compile regular expression"), errbuf);
804 }
805
806 for (me = mount_list; me; me = me->me_next) {
807 if (np_regex_match_mount_entry(me, &re)) {
808 fnd = true;
809 if (verbose >= 3)
810 printf("%s %s matching expression %s\n", me->me_devname, me->me_mountdir, optarg);
811
812 /* add parameter if not found. overwrite thresholds if path has already been added */
813 if (! (se = np_find_parameter(path_select_list, me->me_mountdir))) {
814 se = np_add_parameter(&path_select_list, me->me_mountdir);
815 }
816 se->group = group;
817 set_all_thresholds(se);
818 }
819 }
820
821 if (!fnd && ignore_missing == true) {
822 path_ignored = true;
823 path_selected = true;
824 break;
825 } else if (!fnd)
826 die (STATE_UNKNOWN, "DISK %s: %s - %s\n",_("UNKNOWN"),
827 _("Regular expression did not match any path or disk"), optarg);
828
829 fnd = false;
830 path_selected = true;
831 np_set_best_match(path_select_list, mount_list, exact_match);
832 cflags = default_cflags;
833
834 break;
835 case 'M': /* display mountpoint */
836 display_mntp = true;
837 break;
838 case 'C':
839 /* add all mount entries to path_select list if no partitions have been explicitly defined using -p */
840 if (path_selected == false) {
841 struct parameter_list *path;
842 for (me = mount_list; me; me = me->me_next) {
843 if (! (path = np_find_parameter(path_select_list, me->me_mountdir)))
844 path = np_add_parameter(&path_select_list, me->me_mountdir);
845 path->best_match = me;
846 path->group = group;
847 set_all_thresholds(path);
848 }
849 }
850 warn_freespace_units = NULL;
851 crit_freespace_units = NULL;
852 warn_usedspace_units = NULL;
853 crit_usedspace_units = NULL;
854 warn_freespace_percent = NULL;
855 crit_freespace_percent = NULL;
856 warn_usedspace_percent = NULL;
857 crit_usedspace_percent = NULL;
858 warn_usedinodes_percent = NULL;
859 crit_usedinodes_percent = NULL;
860 warn_freeinodes_percent = NULL;
861 crit_freeinodes_percent = NULL;
862
863 path_selected = false;
864 group = NULL;
865 break;
866 case 'V': /* version */
867 print_revision (progname, NP_VERSION);
868 exit (STATE_UNKNOWN);
869 case 'h': /* help */
870 print_help ();
871 exit (STATE_UNKNOWN);
872 case '?': /* help */
873 usage (_("Unknown argument"));
874 }
875 }
876
877 /* Support for "check_disk warn crit [fs]" with thresholds at used% level */
878 c = optind;
879 if (warn_usedspace_percent == NULL && argc > c && is_intnonneg (argv[c]))
880 warn_usedspace_percent = argv[c++];
881
882 if (crit_usedspace_percent == NULL && argc > c && is_intnonneg (argv[c]))
883 crit_usedspace_percent = argv[c++];
884
885 if (argc > c) {
886 se = np_add_parameter(&path_select_list, strdup(argv[c++]));
887 path_selected = true;
888 set_all_thresholds(se);
889 }
890
891 if (units == NULL) {
892 units = strdup ("MiB");
893 mult = (uintmax_t)1024 * 1024;
894 }
895
896 return true;
897}
898 496
899void 497 case 'W': /* warning inode threshold */
900set_all_thresholds (struct parameter_list *path) 498 if (*optarg == '@') {
901{ 499 warn_freeinodes_percent = optarg;
902 if (path->freespace_units != NULL) free(path->freespace_units); 500 } else {
903 set_thresholds(&path->freespace_units, warn_freespace_units, crit_freespace_units); 501 xasprintf(&warn_freeinodes_percent, "@%s", optarg);
904 if (path->freespace_percent != NULL) free (path->freespace_percent); 502 }
905 set_thresholds(&path->freespace_percent, warn_freespace_percent, crit_freespace_percent); 503 break;
906 if (path->usedspace_units != NULL) free (path->usedspace_units); 504 case 'K': /* critical inode threshold */
907 set_thresholds(&path->usedspace_units, warn_usedspace_units, crit_usedspace_units); 505 if (*optarg == '@') {
908 if (path->usedspace_percent != NULL) free (path->usedspace_percent); 506 crit_freeinodes_percent = optarg;
909 set_thresholds(&path->usedspace_percent, warn_usedspace_percent, crit_usedspace_percent); 507 } else {
910 if (path->usedinodes_percent != NULL) free (path->usedinodes_percent); 508 xasprintf(&crit_freeinodes_percent, "@%s", optarg);
911 set_thresholds(&path->usedinodes_percent, warn_usedinodes_percent, crit_usedinodes_percent); 509 }
912 if (path->freeinodes_percent != NULL) free (path->freeinodes_percent); 510 break;
913 set_thresholds(&path->freeinodes_percent, warn_freeinodes_percent, crit_freeinodes_percent); 511 case 'u':
914} 512 if (!strcasecmp(optarg, "bytes")) {
513 unit = Bytes_Factor;
514 } else if (!strcmp(optarg, "KiB")) {
515 unit = KibiBytes_factor;
516 } else if (!strcmp(optarg, "kB")) {
517 unit = KiloBytes_factor;
518 } else if (!strcmp(optarg, "MiB")) {
519 unit = MebiBytes_factor;
520 } else if (!strcmp(optarg, "MB")) {
521 unit = MegaBytes_factor;
522 } else if (!strcmp(optarg, "GiB")) {
523 unit = GibiBytes_factor;
524 } else if (!strcmp(optarg, "GB")) {
525 unit = GigaBytes_factor;
526 } else if (!strcmp(optarg, "TiB")) {
527 unit = TebiBytes_factor;
528 } else if (!strcmp(optarg, "TB")) {
529 unit = TeraBytes_factor;
530 } else if (!strcmp(optarg, "PiB")) {
531 unit = PebiBytes_factor;
532 } else if (!strcmp(optarg, "PB")) {
533 unit = PetaBytes_factor;
534 } else {
535 die(STATE_UNKNOWN, _("unit type %s not known\n"), optarg);
536 }
537 break;
538 case 'k':
539 unit = KibiBytes_factor;
540 break;
541 case 'm':
542 unit = MebiBytes_factor;
543 break;
544 case display_unit_index:
545 if (!strcasecmp(optarg, "bytes")) {
546 result.config.display_unit = Bytes;
547 } else if (!strcmp(optarg, "KiB")) {
548 result.config.display_unit = KibiBytes;
549 } else if (!strcmp(optarg, "kB")) {
550 result.config.display_unit = KiloBytes;
551 } else if (!strcmp(optarg, "MiB")) {
552 result.config.display_unit = MebiBytes;
553 } else if (!strcmp(optarg, "MB")) {
554 result.config.display_unit = MegaBytes;
555 } else if (!strcmp(optarg, "GiB")) {
556 result.config.display_unit = GibiBytes;
557 } else if (!strcmp(optarg, "GB")) {
558 result.config.display_unit = GigaBytes;
559 } else if (!strcmp(optarg, "TiB")) {
560 result.config.display_unit = TebiBytes;
561 } else if (!strcmp(optarg, "TB")) {
562 result.config.display_unit = TeraBytes;
563 } else if (!strcmp(optarg, "PiB")) {
564 result.config.display_unit = PebiBytes;
565 } else if (!strcmp(optarg, "PB")) {
566 result.config.display_unit = PetaBytes;
567 } else {
568 die(STATE_UNKNOWN, _("unit type %s not known\n"), optarg);
569 }
570 break;
571 case 'L':
572 result.config.stat_remote_fs = true;
573 /* fallthrough */
574 case 'l':
575 result.config.show_local_fs = true;
576 break;
577 case 'P':
578 result.config.display_inodes_perfdata = true;
579 break;
580 case 'p': /* select path */ {
581 if (!(warn_freespace_units || crit_freespace_units || warn_freespace_percent || crit_freespace_percent ||
582 warn_freeinodes_percent || crit_freeinodes_percent)) {
583 die(STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set a threshold value before using -p\n"));
584 }
915 585
916void 586 /* add parameter if not found. overwrite thresholds if path has already been added */
917print_help (void) 587 parameter_list_elem *search_entry;
918{ 588 if (!(search_entry = mp_int_fs_list_find(result.config.path_select_list, optarg))) {
919 print_revision (progname, NP_VERSION); 589 search_entry = mp_int_fs_list_append(&result.config.path_select_list, optarg);
920 590
921 printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n"); 591 // struct stat stat_buf = {};
922 printf (COPYRIGHT, copyright, email); 592 // if (stat(optarg, &stat_buf) && result.config.ignore_missing) {
923 593 // result.config.path_ignored = true;
924 printf ("%s\n", _("This plugin checks the amount of used disk space on a mounted file system")); 594 // break;
925 printf ("%s\n", _("and generates an alert if free space is less than one of the threshold values")); 595 // }
926 596 }
927 printf ("\n\n"); 597 search_entry->group = group;
928 598 set_all_thresholds(search_entry, warn_freespace_units, crit_freespace_units, warn_freespace_percent, crit_freespace_percent,
929 print_usage (); 599
930 600 warn_freeinodes_percent, crit_freeinodes_percent);
931 printf (UT_HELP_VRSN); 601
932 printf (UT_EXTRA_OPTS); 602 /* With autofs, it is required to stat() the path before re-populating the mount_list */
933 603 // if (!stat_path(se, result.config.ignore_missing)) {
934 printf (" %s\n", "-w, --warning=INTEGER"); 604 // break;
935 printf (" %s\n", _("Exit with WARNING status if less than INTEGER units of disk are free")); 605 // }
936 printf (" %s\n", "-w, --warning=PERCENT%"); 606 mp_int_fs_list_set_best_match(result.config.path_select_list, result.config.mount_list, result.config.exact_match);
937 printf (" %s\n", _("Exit with WARNING status if less than PERCENT of disk space is free")); 607
938 printf (" %s\n", "-c, --critical=INTEGER"); 608 path_selected = true;
939 printf (" %s\n", _("Exit with CRITICAL status if less than INTEGER units of disk are free")); 609 } break;
940 printf (" %s\n", "-c, --critical=PERCENT%"); 610 case 'x': /* exclude path or partition */
941 printf (" %s\n", _("Exit with CRITICAL status if less than PERCENT of disk space is free")); 611 np_add_name(&result.config.device_path_exclude_list, optarg);
942 printf (" %s\n", "-W, --iwarning=PERCENT%"); 612 break;
943 printf (" %s\n", _("Exit with WARNING status if less than PERCENT of inode space is free")); 613 case 'X': /* exclude file system type */ {
944 printf (" %s\n", "-K, --icritical=PERCENT%"); 614 int err = np_add_regex(&result.config.fs_exclude_list, optarg, REG_EXTENDED);
945 printf (" %s\n", _("Exit with CRITICAL status if less than PERCENT of inode space is free")); 615 if (err != 0) {
946 printf (" %s\n", "-p, --path=PATH, --partition=PARTITION"); 616 char errbuf[MAX_INPUT_BUFFER];
947 printf (" %s\n", _("Mount point or block device as emitted by the mount(8) command (may be repeated)")); 617 regerror(err, &result.config.fs_exclude_list->regex, errbuf, MAX_INPUT_BUFFER);
948 printf (" %s\n", "-x, --exclude_device=PATH <STRING>"); 618 die(STATE_UNKNOWN, "DISK %s: %s - %s\n", _("UNKNOWN"), _("Could not compile regular expression"), errbuf);
949 printf (" %s\n", _("Ignore device (only works if -p unspecified)")); 619 }
950 printf (" %s\n", "-C, --clear"); 620 break;
951 printf (" %s\n", _("Clear thresholds")); 621 case 'N': /* include file system type */
952 printf (" %s\n", "-E, --exact-match"); 622 err = np_add_regex(&result.config.fs_include_list, optarg, REG_EXTENDED);
953 printf (" %s\n", _("For paths or partitions specified with -p, only check for exact paths")); 623 if (err != 0) {
954 printf (" %s\n", "-e, --errors-only"); 624 char errbuf[MAX_INPUT_BUFFER];
955 printf (" %s\n", _("Display only devices/mountpoints with errors")); 625 regerror(err, &result.config.fs_exclude_list->regex, errbuf, MAX_INPUT_BUFFER);
956 printf (" %s\n", "-f, --freespace-ignore-reserved"); 626 die(STATE_UNKNOWN, "DISK %s: %s - %s\n", _("UNKNOWN"), _("Could not compile regular expression"), errbuf);
957 printf (" %s\n", _("Don't account root-reserved blocks into freespace in perfdata")); 627 }
958 printf (" %s\n", "-P, --iperfdata"); 628 } break;
959 printf (" %s\n", _("Display inode usage in perfdata")); 629 case 'v': /* verbose */
960 printf (" %s\n", "-g, --group=NAME"); 630 verbose++;
961 printf (" %s\n", _("Group paths. Thresholds apply to (free-)space of all partitions together")); 631 break;
962 printf (" %s\n", "-k, --kilobytes"); 632 case 'q': /* TODO: this function should eventually go away (removed 2007-09-20) */
963 printf (" %s\n", _("Same as '--units kB'")); 633 /* verbose--; **replaced by line below**. -q was only a broken way of implementing -e */
964 printf (" %s\n", "-l, --local"); 634 result.config.erronly = true;
965 printf (" %s\n", _("Only check local filesystems")); 635 break;
966 printf (" %s\n", "-L, --stat-remote-fs"); 636 case 'e':
967 printf (" %s\n", _("Only check local filesystems against thresholds. Yet call stat on remote filesystems")); 637 result.config.erronly = true;
968 printf (" %s\n", _("to test if they are accessible (e.g. to detect Stale NFS Handles)")); 638 break;
969 printf (" %s\n", "-M, --mountpoint"); 639 case 'E':
970 printf (" %s\n", _("Display the (block) device instead of the mount point")); 640 if (path_selected) {
971 printf (" %s\n", "-m, --megabytes"); 641 die(STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set -E before selecting paths\n"));
972 printf (" %s\n", _("Same as '--units MB'")); 642 }
973 printf (" %s\n", "-A, --all"); 643 result.config.exact_match = true;
974 printf (" %s\n", _("Explicitly select all paths. This is equivalent to -R '.*'")); 644 break;
975 printf (" %s\n", "-R, --eregi-path=PATH, --eregi-partition=PARTITION"); 645 case 'f':
976 printf (" %s\n", _("Case insensitive regular expression for path/partition (may be repeated)")); 646 result.config.freespace_ignore_reserved = true;
977 printf (" %s\n", "-r, --ereg-path=PATH, --ereg-partition=PARTITION"); 647 break;
978 printf (" %s\n", _("Regular expression for path or partition (may be repeated)")); 648 case 'g':
979 printf (" %s\n", "-I, --ignore-eregi-path=PATH, --ignore-eregi-partition=PARTITION"); 649 if (path_selected) {
980 printf (" %s\n", _("Regular expression to ignore selected path/partition (case insensitive) (may be repeated)")); 650 die(STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set group value before selecting paths\n"));
981 printf (" %s\n", "-i, --ignore-ereg-path=PATH, --ignore-ereg-partition=PARTITION"); 651 }
982 printf (" %s\n", _("Regular expression to ignore selected path or partition (may be repeated)")); 652 group = optarg;
983 printf (" %s\n", "-n, --ignore-missing"); 653 break;
984 printf (" %s\n", _("Return OK if no filesystem matches, filesystem does not exist or is inaccessible.")); 654 case 'I':
985 printf (" %s\n", _("(Provide this option before -p / -r / --ereg-path if used)")); 655 cflags |= REG_ICASE;
986 printf (UT_PLUG_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 656 // Intentional fallthrough
987 printf (" %s\n", "-u, --units=STRING"); 657 case 'i': {
988 printf (" %s\n", _("Choose bytes, kB, MB, GB, TB (default: MB)")); 658 if (!path_selected) {
989 printf (UT_VERBOSE); 659 die(STATE_UNKNOWN, "DISK %s: %s\n", _("UNKNOWN"),
990 printf (" %s\n", "-X, --exclude-type=TYPE_REGEX"); 660 _("Paths need to be selected before using -i/-I. Use -A to select all paths explicitly"));
991 printf (" %s\n", _("Ignore all filesystems of types matching given regex(7) (may be repeated)")); 661 }
992 printf (" %s\n", "-N, --include-type=TYPE_REGEX"); 662 regex_t regex;
993 printf (" %s\n", _("Check only filesystems where the type matches this given regex(7) (may be repeated)")); 663 int err = regcomp(&regex, optarg, cflags);
994 664 if (err != 0) {
995 printf ("\n"); 665 char errbuf[MAX_INPUT_BUFFER];
996 printf ("%s\n", _("General usage hints:")); 666 regerror(err, &regex, errbuf, MAX_INPUT_BUFFER);
997 printf (" %s\n", _("- Arguments are positional! \"-w 5 -c 1 -p /foo -w6 -c2 -p /bar\" is not the same as")); 667 die(STATE_UNKNOWN, "DISK %s: %s - %s\n", _("UNKNOWN"), _("Could not compile regular expression"), errbuf);
998 printf (" %s\n", _("\"-w 5 -c 1 -p /bar w6 -c2 -p /foo\".")); 668 }
999 printf (" %s\n", _("- The syntax is broadly: \"{thresholds a} {paths a} -C {thresholds b} {thresholds b} ...\""));
1000
1001
1002
1003 printf ("\n");
1004 printf ("%s\n", _("Examples:"));
1005 printf (" %s\n", "check_disk -w 10% -c 5% -p /tmp -p /var -C -w 100000 -c 50000 -p /");
1006 printf (" %s\n\n", _("Checks /tmp and /var at 10% and 5%, and / at 100MB and 50MB"));
1007 printf (" %s\n", "check_disk -w 100 -c 50 -C -w 1000 -c 500 -g sidDATA -r '^/oracle/SID/data.*$'");
1008 printf (" %s\n", _("Checks all filesystems not matching -r at 100M and 50M. The fs matching the -r regex"));
1009 printf (" %s\n\n", _("are grouped which means the freespace thresholds are applied to all disks together"));
1010 printf (" %s\n", "check_disk -w 100 -c 50 -C -w 1000 -c 500 -p /foo -C -w 5% -c 3% -p /bar");
1011 printf (" %s\n", _("Checks /foo for 1000M/500M and /bar for 5/3%. All remaining volumes use 100M/50M"));
1012
1013 printf (UT_SUPPORT);
1014}
1015 669
670 for (parameter_list_elem *elem = result.config.path_select_list.first; elem;) {
671 if (elem->best_match) {
672 if (np_regex_match_mount_entry(elem->best_match, &regex)) {
1016 673
674 if (verbose >= 3) {
675 printf("ignoring %s matching regex\n", elem->name);
676 }
677
678 elem = mp_int_fs_list_del(&result.config.path_select_list, elem);
679 continue;
680 }
681 }
682
683 elem = mp_int_fs_list_get_next(elem);
684 }
685
686 cflags = default_cflags;
687 } break;
688 case 'n':
689 result.config.ignore_missing = true;
690 break;
691 case 'A':
692 optarg = strdup(".*");
693 // Intentional fallthrough
694 case 'R':
695 cflags |= REG_ICASE;
696 // Intentional fallthrough
697 case 'r': {
698 if (!(warn_freespace_units || crit_freespace_units || warn_freespace_percent || crit_freespace_percent ||
699 warn_freeinodes_percent || crit_freeinodes_percent)) {
700 die(STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"),
701 _("Must set a threshold value before using -r/-R/-A (--ereg-path/--eregi-path/--all)\n"));
702 }
1017 703
1018void 704 regex_t regex;
1019print_usage (void) 705 int err = regcomp(&regex, optarg, cflags);
1020{ 706 if (err != 0) {
1021 printf ("%s\n", _("Usage:")); 707 char errbuf[MAX_INPUT_BUFFER];
1022 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); 708 regerror(err, &regex, errbuf, MAX_INPUT_BUFFER);
1023 printf ("[-C] [-E] [-e] [-f] [-g group ] [-k] [-l] [-M] [-m] [-R path ] [-r path ]\n"); 709 die(STATE_UNKNOWN, "DISK %s: %s - %s\n", _("UNKNOWN"), _("Could not compile regular expression"), errbuf);
1024 printf ("[-t timeout] [-u unit] [-v] [-X type_regex] [-N type]\n"); 710 }
711
712 bool found = false;
713 for (struct mount_entry *me = result.config.mount_list; me; me = me->me_next) {
714 if (np_regex_match_mount_entry(me, &regex)) {
715 found = true;
716 if (verbose >= 3) {
717 printf("%s %s matching expression %s\n", me->me_devname, me->me_mountdir, optarg);
718 }
719
720 /* add parameter if not found. overwrite thresholds if path has already been added */
721 parameter_list_elem *se = NULL;
722 if (!(se = mp_int_fs_list_find(result.config.path_select_list, me->me_mountdir))) {
723 se = mp_int_fs_list_append(&result.config.path_select_list, me->me_mountdir);
724 }
725 se->group = group;
726 set_all_thresholds(se, warn_freespace_units, crit_freespace_units, warn_freespace_percent, crit_freespace_percent,
727 warn_freeinodes_percent, crit_freeinodes_percent);
728 }
729 }
730
731 if (!found) {
732 if (result.config.ignore_missing) {
733 result.config.path_ignored = true;
734 path_selected = true;
735 break;
736 }
737
738 die(STATE_UNKNOWN, "DISK %s: %s - %s\n", _("UNKNOWN"), _("Regular expression did not match any path or disk"), optarg);
739 }
740
741 path_selected = true;
742 mp_int_fs_list_set_best_match(result.config.path_select_list, result.config.mount_list, result.config.exact_match);
743 cflags = default_cflags;
744
745 } break;
746 case 'M': /* display mountpoint */
747 result.config.display_mntp = true;
748 break;
749 case 'C': {
750 /* add all mount entries to path_select list if no partitions have been explicitly defined using -p */
751 if (!path_selected) {
752 parameter_list_elem *path;
753 for (struct mount_entry *me = result.config.mount_list; me; me = me->me_next) {
754 if (!(path = mp_int_fs_list_find(result.config.path_select_list, me->me_mountdir))) {
755 path = mp_int_fs_list_append(&result.config.path_select_list, me->me_mountdir);
756 }
757 path->best_match = me;
758 path->group = group;
759 set_all_thresholds(path, warn_freespace_units, crit_freespace_units, warn_freespace_percent, crit_freespace_percent,
760 warn_freeinodes_percent, crit_freeinodes_percent);
761 }
762 }
763
764 warn_freespace_units = NULL;
765 crit_freespace_units = NULL;
766 warn_freespace_percent = NULL;
767 crit_freespace_percent = NULL;
768 warn_freeinodes_percent = NULL;
769 crit_freeinodes_percent = NULL;
770
771 path_selected = false;
772 group = NULL;
773 } break;
774 case 'V': /* version */
775 print_revision(progname, NP_VERSION);
776 exit(STATE_UNKNOWN);
777 case 'h': /* help */
778 print_help();
779 exit(STATE_UNKNOWN);
780 case '?': /* help */
781 usage(_("Unknown argument"));
782 case output_format_index: {
783 parsed_output_format parser = mp_parse_output_format(optarg);
784 if (!parser.parsing_success) {
785 // TODO List all available formats here, maybe add anothoer usage function
786 printf("Invalid output format: %s\n", optarg);
787 exit(STATE_UNKNOWN);
788 }
789
790 result.config.output_format_is_set = true;
791 result.config.output_format = parser.output_format;
792 break;
793 }
794 }
795 }
796
797 /* Support for "check_disk warn crit [fs]" with thresholds at used% level */
798 int index = optind;
799
800 if (argc > index && is_intnonneg(argv[index])) {
801 if (verbose > 0) {
802 printf("Got an positional warn threshold: %s\n", argv[index]);
803 }
804 char *range = argv[index++];
805 mp_range_parsed tmp = mp_parse_range_string(range);
806 if (tmp.error != MP_PARSING_SUCCES) {
807 die(STATE_UNKNOWN, "failed to parse warning threshold");
808 }
809
810 mp_range tmp_range = tmp.range;
811 // Invert range to use it for free instead of used
812 // tmp_range.alert_on_inside_range = !tmp_range.alert_on_inside_range;
813
814 warn_freespace_percent = mp_range_to_string(tmp_range);
815
816 if (verbose > 0) {
817 printf("Positional warning threshold transformed to: %s\n", warn_freespace_percent);
818 }
819 }
820
821 if (argc > index && is_intnonneg(argv[index])) {
822 if (verbose > 0) {
823 printf("Got an positional crit threshold: %s\n", argv[index]);
824 }
825 char *range = argv[index++];
826 mp_range_parsed tmp = mp_parse_range_string(range);
827 if (tmp.error != MP_PARSING_SUCCES) {
828 die(STATE_UNKNOWN, "failed to parse warning threshold");
829 }
830
831 mp_range tmp_range = tmp.range;
832 // Invert range to use it for free instead of used
833 // tmp_range.alert_on_inside_range = !tmp_range.alert_on_inside_range;
834
835 crit_freespace_percent = mp_range_to_string(tmp_range);
836
837 if (verbose > 0) {
838 printf("Positional critical threshold transformed to: %s\n", crit_freespace_percent);
839 }
840 }
841
842 if (argc > index) {
843 if (verbose > 0) {
844 printf("Got an positional filesystem: %s\n", argv[index]);
845 }
846 struct parameter_list *se = mp_int_fs_list_append(&result.config.path_select_list, strdup(argv[index++]));
847 path_selected = true;
848 set_all_thresholds(se, warn_freespace_units, crit_freespace_units, warn_freespace_percent, crit_freespace_percent,
849 warn_freeinodes_percent, crit_freeinodes_percent);
850 }
851
852 // If a list of paths has not been explicitly selected, find entire
853 // mount list and create list of paths
854 if (!path_selected && !result.config.path_ignored) {
855 for (struct mount_entry *me = result.config.mount_list; me; me = me->me_next) {
856 if (me->me_dummy != 0) {
857 // just do not add dummy filesystems
858 continue;
859 }
860
861 parameter_list_elem *path = NULL;
862 if (!(path = mp_int_fs_list_find(result.config.path_select_list, me->me_mountdir))) {
863 path = mp_int_fs_list_append(&result.config.path_select_list, me->me_mountdir);
864 }
865 path->best_match = me;
866 path->group = group;
867 set_all_thresholds(path, warn_freespace_units, crit_freespace_units, warn_freespace_percent, crit_freespace_percent,
868 warn_freeinodes_percent, crit_freeinodes_percent);
869 }
870 }
871
872 // Set thresholds to the appropriate unit
873 for (parameter_list_elem *tmp = result.config.path_select_list.first; tmp; tmp = mp_int_fs_list_get_next(tmp)) {
874
875 mp_perfdata_value factor = mp_create_pd_value(unit);
876
877 if (tmp->freespace_units.critical_is_set) {
878 tmp->freespace_units.critical = mp_range_multiply(tmp->freespace_units.critical, factor);
879 }
880 if (tmp->freespace_units.warning_is_set) {
881 tmp->freespace_units.warning = mp_range_multiply(tmp->freespace_units.warning, factor);
882 }
883 }
884
885 return result;
1025} 886}
1026 887
1027bool 888void set_all_thresholds(parameter_list_elem *path, char *warn_freespace_units, char *crit_freespace_units, char *warn_freespace_percent,
1028stat_path (struct parameter_list *p) 889 char *crit_freespace_percent, char *warn_freeinodes_percent, char *crit_freeinodes_percent) {
1029{ 890 mp_range_parsed tmp;
1030 /* Stat entry to check that dir exists and is accessible */ 891
1031 if (verbose >= 3) 892 if (warn_freespace_units) {
1032 printf("calling stat on %s\n", p->name); 893 tmp = mp_parse_range_string(warn_freespace_units);
1033 if (stat (p->name, &stat_buf[0])) { 894 path->freespace_units = mp_thresholds_set_warn(path->freespace_units, tmp.range);
1034 if (verbose >= 3) 895 }
1035 printf("stat failed on %s\n", p->name); 896
1036 if (ignore_missing == true) { 897 if (crit_freespace_units) {
1037 return false; 898 tmp = mp_parse_range_string(crit_freespace_units);
1038 } else { 899 path->freespace_units = mp_thresholds_set_crit(path->freespace_units, tmp.range);
1039 printf("DISK %s - ", _("CRITICAL")); 900 }
1040 die (STATE_CRITICAL, _("%s %s: %s\n"), p->name, _("is not accessible"), strerror(errno)); 901
1041 } 902 if (warn_freespace_percent) {
1042 } 903 tmp = mp_parse_range_string(warn_freespace_percent);
1043 return true; 904 path->freespace_percent = mp_thresholds_set_warn(path->freespace_percent, tmp.range);
905 }
906
907 if (crit_freespace_percent) {
908 tmp = mp_parse_range_string(crit_freespace_percent);
909 path->freespace_percent = mp_thresholds_set_crit(path->freespace_percent, tmp.range);
910 }
911
912 if (warn_freeinodes_percent) {
913 tmp = mp_parse_range_string(warn_freeinodes_percent);
914 path->freeinodes_percent = mp_thresholds_set_warn(path->freeinodes_percent, tmp.range);
915 }
916
917 if (crit_freeinodes_percent) {
918 tmp = mp_parse_range_string(crit_freeinodes_percent);
919 path->freeinodes_percent = mp_thresholds_set_crit(path->freeinodes_percent, tmp.range);
920 }
1044} 921}
1045 922
923void print_help(void) {
924 print_revision(progname, NP_VERSION);
925
926 printf("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
927 printf(COPYRIGHT, copyright, email);
928
929 printf("%s\n", _("This plugin checks the amount of used disk space on a mounted file system"));
930 printf("%s\n", _("and generates an alert if free space is less than one of the threshold values"));
931
932 printf("\n\n");
933
934 print_usage();
935
936 printf(UT_HELP_VRSN);
937 printf(UT_EXTRA_OPTS);
938
939 printf(" %s\n", "-w, --warning=INTEGER");
940 printf(" %s\n", _("Exit with WARNING status if less than INTEGER units of disk are free"));
941 printf(" %s\n", "-w, --warning=PERCENT%");
942 printf(" %s\n", _("Exit with WARNING status if less than PERCENT of disk space is free"));
943 printf(" %s\n", "-c, --critical=INTEGER");
944 printf(" %s\n", _("Exit with CRITICAL status if less than INTEGER units of disk are free"));
945 printf(" %s\n", "-c, --critical=PERCENT%");
946 printf(" %s\n", _("Exit with CRITICAL status if less than PERCENT of disk space is free"));
947 printf(" %s\n", "-W, --iwarning=PERCENT%");
948 printf(" %s\n", _("Exit with WARNING status if less than PERCENT of inode space is free"));
949 printf(" %s\n", "-K, --icritical=PERCENT%");
950 printf(" %s\n", _("Exit with CRITICAL status if less than PERCENT of inode space is free"));
951 printf(" %s\n", "-p, --path=PATH, --partition=PARTITION");
952 printf(" %s\n", _("Mount point or block device as emitted by the mount(8) command (may be repeated)"));
953 printf(" %s\n", "-x, --exclude_device=PATH <STRING>");
954 printf(" %s\n", _("Ignore device (only works if -p unspecified)"));
955 printf(" %s\n", "-C, --clear");
956 printf(" %s\n", _("Clear thresholds"));
957 printf(" %s\n", "-E, --exact-match");
958 printf(" %s\n", _("For paths or partitions specified with -p, only check for exact paths"));
959 printf(" %s\n", "-e, --errors-only");
960 printf(" %s\n", _("Display only devices/mountpoints with errors"));
961 printf(" %s\n", "-f, --freespace-ignore-reserved");
962 printf(" %s\n", _("Don't account root-reserved blocks into freespace in perfdata"));
963 printf(" %s\n", "-P, --iperfdata");
964 printf(" %s\n", _("Display inode usage in perfdata"));
965 printf(" %s\n", "-g, --group=NAME");
966 printf(" %s\n", _("Group paths. Thresholds apply to (free-)space of all partitions together"));
967 printf(" %s\n", "-l, --local");
968 printf(" %s\n", _("Only check local filesystems"));
969 printf(" %s\n", "-L, --stat-remote-fs");
970 printf(" %s\n", _("Only check local filesystems against thresholds. Yet call stat on remote filesystems"));
971 printf(" %s\n", _("to test if they are accessible (e.g. to detect Stale NFS Handles)"));
972 printf(" %s\n", "-M, --mountpoint");
973 printf(" %s\n", _("Display the (block) device instead of the mount point"));
974 printf(" %s\n", "-A, --all");
975 printf(" %s\n", _("Explicitly select all paths. This is equivalent to -R '.*'"));
976 printf(" %s\n", "-R, --eregi-path=PATH, --eregi-partition=PARTITION");
977 printf(" %s\n", _("Case insensitive regular expression for path/partition (may be repeated)"));
978 printf(" %s\n", "-r, --ereg-path=PATH, --ereg-partition=PARTITION");
979 printf(" %s\n", _("Regular expression for path or partition (may be repeated)"));
980 printf(" %s\n", "-I, --ignore-eregi-path=PATH, --ignore-eregi-partition=PARTITION");
981 printf(" %s\n", _("Regular expression to ignore selected path/partition (case insensitive) (may be repeated)"));
982 printf(" %s\n", "-i, --ignore-ereg-path=PATH, --ignore-ereg-partition=PARTITION");
983 printf(" %s\n", _("Regular expression to ignore selected path or partition (may be repeated)"));
984 printf(" %s\n", "-n, --ignore-missing");
985 printf(" %s\n", _("Return OK if no filesystem matches, filesystem does not exist or is inaccessible."));
986 printf(" %s\n", _("(Provide this option before -p / -r / --ereg-path if used)"));
987 printf(UT_PLUG_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
988 printf(" %s\n", "-u, --units=STRING");
989 printf(" %s\n", _("Select the unit used for the absolute value thresholds"));
990 printf(
991 " %s\n",
992 _("Choose one of \"bytes\", \"KiB\", \"kB\", \"MiB\", \"MB\", \"GiB\", \"GB\", \"TiB\", \"TB\", \"PiB\", \"PB\" (default: MiB)"));
993 printf(" %s\n", "-k, --kilobytes");
994 printf(" %s\n", _("Same as '--units kB'"));
995 printf(" %s\n", "--display-unit");
996 printf(" %s\n", _("Select the unit used for in the output"));
997 printf(
998 " %s\n",
999 _("Choose one of \"bytes\", \"KiB\", \"kB\", \"MiB\", \"MB\", \"GiB\", \"GB\", \"TiB\", \"TB\", \"PiB\", \"PB\" (default: MiB)"));
1000 printf(" %s\n", "-m, --megabytes");
1001 printf(" %s\n", _("Same as '--units MB'"));
1002 printf(UT_VERBOSE);
1003 printf(" %s\n", "-X, --exclude-type=TYPE_REGEX");
1004 printf(" %s\n", _("Ignore all filesystems of types matching given regex(7) (may be repeated)"));
1005 printf(" %s\n", "-N, --include-type=TYPE_REGEX");
1006 printf(" %s\n", _("Check only filesystems where the type matches this given regex(7) (may be repeated)"));
1007 printf(UT_OUTPUT_FORMAT);
1008
1009 printf("\n");
1010 printf("%s\n", _("General usage hints:"));
1011 printf(" %s\n", _("- Arguments are positional! \"-w 5 -c 1 -p /foo -w6 -c2 -p /bar\" is not the same as"));
1012 printf(" %s\n", _("\"-w 5 -c 1 -p /bar w6 -c2 -p /foo\"."));
1013 printf(" %s\n", _("- The syntax is broadly: \"{thresholds a} {paths a} -C {thresholds b} {thresholds b} ...\""));
1014
1015 printf("\n");
1016 printf("%s\n", _("Examples:"));
1017 printf(" %s\n", "check_disk -w 10% -c 5% -p /tmp -p /var -C -w 100000 -c 50000 -p /");
1018 printf(" %s\n\n", _("Checks /tmp and /var at 10% and 5%, and / at 100MB and 50MB"));
1019 printf(" %s\n", "check_disk -w 100 -c 50 -C -w 1000 -c 500 -g sidDATA -r '^/oracle/SID/data.*$'");
1020 printf(" %s\n", _("Checks all filesystems not matching -r at 100M and 50M. The fs matching the -r regex"));
1021 printf(" %s\n\n", _("are grouped which means the freespace thresholds are applied to all disks together"));
1022 printf(" %s\n", "check_disk -w 100 -c 50 -C -w 1000 -c 500 -p /foo -C -w 5% -c 3% -p /bar");
1023 printf(" %s\n", _("Checks /foo for 1000M/500M and /bar for 5/3%. All remaining volumes use 100M/50M"));
1024
1025 printf(UT_SUPPORT);
1026}
1046 1027
1047void 1028void print_usage(void) {
1048get_stats (struct parameter_list *p, struct fs_usage *fsp) { 1029 printf("%s\n", _("Usage:"));
1049 struct parameter_list *p_list; 1030 printf(" %s {-w absolute_limit |-w percentage_limit%% | -W inode_percentage_limit } {-c absolute_limit|-c percentage_limit%% | -K "
1050 struct fs_usage tmpfsp; 1031 "inode_percentage_limit } {-p path | -x device}\n",
1051 int first = 1; 1032 progname);
1033 printf("[-C] [-E] [-e] [-f] [-g group ] [-k] [-l] [-M] [-m] [-R path ] [-r path ]\n");
1034 printf("[-t timeout] [-u unit] [-v] [-X type_regex] [-N type]\n");
1035}
1052 1036
1053 if (p->group == NULL) { 1037bool stat_path(parameter_list_elem *parameters, bool ignore_missing) {
1054 get_path_stats(p,fsp); 1038 /* Stat entry to check that dir exists and is accessible */
1055 } else { 1039 if (verbose >= 3) {
1056 /* find all group members */ 1040 printf("calling stat on %s\n", parameters->name);
1057 for (p_list = path_select_list; p_list; p_list=p_list->name_next) { 1041 }
1058#ifdef __CYGWIN__ 1042
1059 if (strncmp(p_list->name, "/cygdrive/", 10) != 0) 1043 struct stat stat_buf = {0};
1060 continue; 1044 if (stat(parameters->name, &stat_buf)) {
1061#endif 1045 if (verbose >= 3) {
1062 if (p_list->group && ! (strcmp(p_list->group, p->group))) { 1046 printf("stat failed on %s\n", parameters->name);
1063 if (! stat_path(p_list)) 1047 }
1064 continue; 1048 if (ignore_missing) {
1065 get_fs_usage (p_list->best_match->me_mountdir, p_list->best_match->me_devname, &tmpfsp); 1049 return false;
1066 get_path_stats(p_list, &tmpfsp); 1050 }
1067 if (verbose >= 3) 1051 printf("DISK %s - ", _("CRITICAL"));
1068 printf("Group %s: adding %lu blocks sized %lu, (%s) used_units=%lu free_units=%lu total_units=%lu mult=%lu\n", 1052 die(STATE_CRITICAL, _("%s %s: %s\n"), parameters->name, _("is not accessible"), strerror(errno));
1069 p_list->group, 1053 }
1070 tmpfsp.fsu_blocks, 1054
1071 tmpfsp.fsu_blocksize, 1055 return true;
1072 p_list->best_match->me_mountdir, 1056}
1073 p_list->dused_units,
1074 p_list->dfree_units,
1075 p_list->dtotal_units,
1076 mult);
1077
1078 /* prevent counting the first FS of a group twice since its parameter_list entry
1079 * is used to carry the information of all file systems of the entire group */
1080 if (! first) {
1081 p->total += p_list->total;
1082 p->available += p_list->available;
1083 p->available_to_root += p_list->available_to_root;
1084 p->used += p_list->used;
1085
1086 p->dused_units += p_list->dused_units;
1087 p->dfree_units += p_list->dfree_units;
1088 p->dtotal_units += p_list->dtotal_units;
1089 p->inodes_total += p_list->inodes_total;
1090 p->inodes_free += p_list->inodes_free;
1091 p->inodes_free_to_root += p_list->inodes_free_to_root;
1092 p->inodes_used += p_list->inodes_used;
1093 }
1094 first = 0;
1095 }
1096 if (verbose >= 3)
1097 printf("Group %s now has: used_units=%lu free_units=%lu total_units=%lu fsu_blocksize=%lu mult=%lu\n",
1098 p->group,
1099 p->dused_units,
1100 p->dfree_units,
1101 p->dtotal_units,
1102 tmpfsp.fsu_blocksize,
1103 mult);
1104 }
1105 /* modify devname and mountdir for output */
1106 p->best_match->me_mountdir = p->best_match->me_devname = p->group;
1107 }
1108 /* finally calculate percentages for either plain FS or summed up group */
1109 p->dused_pct = calculate_percent( p->used, p->used + p->available ); /* used + available can never be > uintmax */
1110 p->dfree_pct = 100.0 - p->dused_pct;
1111 p->dused_inodes_percent = calculate_percent(p->inodes_total - p->inodes_free, p->inodes_total);
1112 p->dfree_inodes_percent = 100 - p->dused_inodes_percent;
1113 1057
1058static parameter_list_elem get_path_stats(parameter_list_elem parameters, const struct fs_usage fsp, bool freespace_ignore_reserved) {
1059 uintmax_t available = fsp.fsu_bavail;
1060 uintmax_t available_to_root = fsp.fsu_bfree;
1061 uintmax_t used = fsp.fsu_blocks - fsp.fsu_bfree;
1062 uintmax_t total;
1063
1064 if (freespace_ignore_reserved) {
1065 /* option activated : we subtract the root-reserved space from the total */
1066 total = fsp.fsu_blocks - available_to_root + available;
1067 } else {
1068 /* default behaviour : take all the blocks into account */
1069 total = fsp.fsu_blocks;
1070 }
1071
1072 parameters.used_bytes = used * fsp.fsu_blocksize;
1073 parameters.free_bytes = available * fsp.fsu_blocksize;
1074 parameters.total_bytes = total * fsp.fsu_blocksize;
1075
1076 /* Free file nodes. Not sure the workaround is required, but in case...*/
1077 parameters.inodes_free = fsp.fsu_ffree;
1078 parameters.inodes_free_to_root = fsp.fsu_ffree; /* Free file nodes for root. */
1079 parameters.inodes_used = fsp.fsu_files - fsp.fsu_ffree;
1080
1081 if (freespace_ignore_reserved) {
1082 /* option activated : we subtract the root-reserved inodes from the total */
1083 /* not all OS report fsp->fsu_favail, only the ones with statvfs syscall */
1084 /* for others, fsp->fsu_ffree == fsp->fsu_favail */
1085 parameters.inodes_total = fsp.fsu_files - parameters.inodes_free_to_root + parameters.inodes_free;
1086 } else {
1087 /* default behaviour : take all the inodes into account */
1088 parameters.inodes_total = fsp.fsu_files;
1089 }
1090
1091 return parameters;
1114} 1092}
1115 1093
1116void 1094mp_subcheck evaluate_filesystem(measurement_unit measurement_unit, bool display_inodes_perfdata, byte_unit unit) {
1117get_path_stats (struct parameter_list *p, struct fs_usage *fsp) { 1095 mp_subcheck result = mp_subcheck_init();
1118 p->available = fsp->fsu_bavail; 1096 result = mp_set_subcheck_default_state(result, STATE_UNKNOWN);
1119 p->available_to_root = fsp->fsu_bfree; 1097 xasprintf(&result.output, "%s", measurement_unit.name);
1120 p->used = fsp->fsu_blocks - fsp->fsu_bfree; 1098
1121 if (freespace_ignore_reserved) { 1099 if (!measurement_unit.is_group && measurement_unit.filesystem_type) {
1122 /* option activated : we subtract the root-reserved space from the total */ 1100 xasprintf(&result.output, "%s (%s)", result.output, measurement_unit.filesystem_type);
1123 p->total = fsp->fsu_blocks - p->available_to_root + p->available; 1101 }
1124 } else { 1102
1125 /* default behaviour : take all the blocks into account */ 1103 /* Threshold comparisons */
1126 p->total = fsp->fsu_blocks; 1104
1127 } 1105 // ===============================
1128 1106 // Free space absolute values test
1129 p->dused_units = p->used*fsp->fsu_blocksize/mult; 1107 mp_subcheck freespace_bytes_sc = mp_subcheck_init();
1130 p->dfree_units = p->available*fsp->fsu_blocksize/mult; 1108 freespace_bytes_sc = mp_set_subcheck_default_state(freespace_bytes_sc, STATE_OK);
1131 p->dtotal_units = p->total*fsp->fsu_blocksize/mult; 1109
1132 /* Free file nodes. Not sure the workaround is required, but in case...*/ 1110 if (unit != Humanized) {
1133 p->inodes_free = fsp->fsu_ffree; 1111 xasprintf(&freespace_bytes_sc.output, "Free space absolute: %ju%s (of %ju%s)", (uintmax_t)(measurement_unit.free_bytes / unit),
1134 p->inodes_free_to_root = fsp->fsu_ffree; /* Free file nodes for root. */ 1112 get_unit_string(unit), (uintmax_t)(measurement_unit.total_bytes / unit), get_unit_string(unit));
1135 p->inodes_used = fsp->fsu_files - fsp->fsu_ffree; 1113 } else {
1136 if (freespace_ignore_reserved) { 1114 xasprintf(&freespace_bytes_sc.output, "Free space absolute: %s (of %s)", humanize_byte_value(measurement_unit.free_bytes, false),
1137 /* option activated : we subtract the root-reserved inodes from the total */ 1115 humanize_byte_value((unsigned long long)measurement_unit.total_bytes, false));
1138 /* not all OS report fsp->fsu_favail, only the ones with statvfs syscall */ 1116 }
1139 /* for others, fsp->fsu_ffree == fsp->fsu_favail */ 1117
1140 p->inodes_total = fsp->fsu_files - p->inodes_free_to_root + p->inodes_free; 1118 mp_perfdata used_space = perfdata_init();
1141 } else { 1119 used_space.label = measurement_unit.name;
1142 /* default behaviour : take all the inodes into account */ 1120 used_space.value = mp_create_pd_value(measurement_unit.free_bytes);
1143 p->inodes_total = fsp->fsu_files; 1121 used_space = mp_set_pd_max_value(used_space, mp_create_pd_value(measurement_unit.total_bytes));
1144 } 1122 used_space = mp_set_pd_min_value(used_space, mp_create_pd_value(0));
1145 np_add_name(&seen, p->best_match->me_mountdir); 1123 used_space.uom = "B";
1124 used_space = mp_pd_set_thresholds(used_space, measurement_unit.freespace_bytes_thresholds);
1125 freespace_bytes_sc = mp_set_subcheck_state(freespace_bytes_sc, mp_get_pd_status(used_space));
1126
1127 // special case for absolute space thresholds here:
1128 // if absolute values are not set, compute the thresholds from percentage thresholds
1129 mp_thresholds temp_thlds = measurement_unit.freespace_bytes_thresholds;
1130 if (!temp_thlds.critical_is_set && measurement_unit.freespace_percent_thresholds.critical_is_set) {
1131 mp_range tmp_range = measurement_unit.freespace_percent_thresholds.critical;
1132
1133 if (!tmp_range.end_infinity) {
1134 tmp_range.end = mp_create_pd_value(mp_get_pd_value(tmp_range.end) / 100 * measurement_unit.total_bytes);
1135 }
1136
1137 if (!tmp_range.start_infinity) {
1138 tmp_range.start = mp_create_pd_value(mp_get_pd_value(tmp_range.start) / 100 * measurement_unit.total_bytes);
1139 }
1140 measurement_unit.freespace_bytes_thresholds = mp_thresholds_set_crit(measurement_unit.freespace_bytes_thresholds, tmp_range);
1141 used_space = mp_pd_set_thresholds(used_space, measurement_unit.freespace_bytes_thresholds);
1142 }
1143
1144 if (!temp_thlds.warning_is_set && measurement_unit.freespace_percent_thresholds.warning_is_set) {
1145 mp_range tmp_range = measurement_unit.freespace_percent_thresholds.warning;
1146 if (!tmp_range.end_infinity) {
1147 tmp_range.end = mp_create_pd_value(mp_get_pd_value(tmp_range.end) / 100 * measurement_unit.total_bytes);
1148 }
1149 if (!tmp_range.start_infinity) {
1150 tmp_range.start = mp_create_pd_value(mp_get_pd_value(tmp_range.start) / 100 * measurement_unit.total_bytes);
1151 }
1152 measurement_unit.freespace_bytes_thresholds = mp_thresholds_set_warn(measurement_unit.freespace_bytes_thresholds, tmp_range);
1153 used_space = mp_pd_set_thresholds(used_space, measurement_unit.freespace_bytes_thresholds);
1154 }
1155
1156 mp_add_perfdata_to_subcheck(&freespace_bytes_sc, used_space);
1157 mp_add_subcheck_to_subcheck(&result, freespace_bytes_sc);
1158
1159 // ==========================
1160 // Free space percentage test
1161 mp_subcheck freespace_percent_sc = mp_subcheck_init();
1162 freespace_percent_sc = mp_set_subcheck_default_state(freespace_percent_sc, STATE_OK);
1163
1164 double free_percentage = calculate_percent(measurement_unit.free_bytes, measurement_unit.total_bytes);
1165 xasprintf(&freespace_percent_sc.output, "Free space percentage: %g%%", free_percentage);
1166
1167 // Using perfdata here just to get to the test result
1168 mp_perfdata free_space_percent_pd = perfdata_init();
1169 free_space_percent_pd.value = mp_create_pd_value(free_percentage);
1170 free_space_percent_pd = mp_pd_set_thresholds(free_space_percent_pd, measurement_unit.freespace_percent_thresholds);
1171
1172 freespace_percent_sc = mp_set_subcheck_state(freespace_percent_sc, mp_get_pd_status(free_space_percent_pd));
1173 mp_add_subcheck_to_subcheck(&result, freespace_percent_sc);
1174
1175 // ================
1176 // Free inodes test
1177 // Only ever useful if the number of inodes is static (e.g. ext4),
1178 // not when it is dynamic (e.g btrfs)
1179 // Assumption: if the total number of inodes == 0, we have such a case and just skip the test
1180 if (measurement_unit.inodes_total > 0) {
1181 mp_subcheck freeindodes_percent_sc = mp_subcheck_init();
1182 freeindodes_percent_sc = mp_set_subcheck_default_state(freeindodes_percent_sc, STATE_OK);
1183
1184 double free_inode_percentage = calculate_percent(measurement_unit.inodes_free, measurement_unit.inodes_total);
1185
1186 if (verbose > 0) {
1187 printf("free inode percentage computed: %g\n", free_inode_percentage);
1188 }
1189
1190 xasprintf(&freeindodes_percent_sc.output, "Inodes free: %g%% (%ju of %ju)", free_inode_percentage, measurement_unit.inodes_free,
1191 measurement_unit.inodes_total);
1192
1193 mp_perfdata inodes_pd = perfdata_init();
1194 xasprintf(&inodes_pd.label, "%s (inodes)", measurement_unit.name);
1195 inodes_pd = mp_set_pd_value(inodes_pd, measurement_unit.inodes_used);
1196 inodes_pd = mp_set_pd_max_value(inodes_pd, mp_create_pd_value(measurement_unit.inodes_total));
1197 inodes_pd = mp_set_pd_min_value(inodes_pd, mp_create_pd_value(0));
1198
1199 mp_thresholds absolut_inode_thresholds = measurement_unit.freeinodes_percent_thresholds;
1200
1201 if (absolut_inode_thresholds.critical_is_set) {
1202 absolut_inode_thresholds.critical =
1203 mp_range_multiply(absolut_inode_thresholds.critical, mp_create_pd_value(measurement_unit.inodes_total / 100));
1204 }
1205 if (absolut_inode_thresholds.warning_is_set) {
1206 absolut_inode_thresholds.warning =
1207 mp_range_multiply(absolut_inode_thresholds.warning, mp_create_pd_value(measurement_unit.inodes_total / 100));
1208 }
1209
1210 inodes_pd = mp_pd_set_thresholds(inodes_pd, absolut_inode_thresholds);
1211
1212 freeindodes_percent_sc = mp_set_subcheck_state(freeindodes_percent_sc, mp_get_pd_status(inodes_pd));
1213 if (display_inodes_perfdata) {
1214 mp_add_perfdata_to_subcheck(&freeindodes_percent_sc, inodes_pd);
1215 }
1216 mp_add_subcheck_to_subcheck(&result, freeindodes_percent_sc);
1217 }
1218
1219 return result;
1146} 1220}