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.c1971
1 files changed, 969 insertions, 1002 deletions
diff --git a/plugins/check_disk.c b/plugins/check_disk.c
index b3dd301..037a6f7 100644
--- a/plugins/check_disk.c
+++ b/plugins/check_disk.c
@@ -1,43 +1,42 @@
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
35#include "common.h" 34#include "common.h"
36#ifdef HAVE_SYS_STAT_H 35#ifdef HAVE_SYS_STAT_H
37# include <sys/stat.h> 36# include <sys/stat.h>
38#endif 37#endif
39#if HAVE_INTTYPES_H 38#if HAVE_INTTYPES_H
40# include <inttypes.h> 39# include <inttypes.h>
41#endif 40#endif
42#include <assert.h> 41#include <assert.h>
43#include "popen.h" 42#include "popen.h"
@@ -48,14 +47,14 @@ const char *email = "devel@monitoring-plugins.org";
48#include "mountlist.h" 47#include "mountlist.h"
49#include <float.h> 48#include <float.h>
50#if HAVE_LIMITS_H 49#if HAVE_LIMITS_H
51# include <limits.h> 50# include <limits.h>
52#endif 51#endif
53#include "regex.h" 52#include "regex.h"
54 53
55#ifdef __CYGWIN__ 54#ifdef __CYGWIN__
56# include <windows.h> 55# include <windows.h>
57# undef ERROR 56# undef ERROR
58# define ERROR -1 57# define ERROR -1
59#endif 58#endif
60 59
61/* If nonzero, show even filesystems with zero size or 60/* If nonzero, show even filesystems with zero size or
@@ -108,25 +107,24 @@ static struct mount_entry *mount_list;
108 107
109/* For long options that have no equivalent short option, use a 108/* For long options that have no equivalent short option, use a
110 non-character as a pseudo short option, starting with CHAR_MAX + 1. */ 109 non-character as a pseudo short option, starting with CHAR_MAX + 1. */
111enum 110enum {
112{ 111 SYNC_OPTION = CHAR_MAX + 1,
113 SYNC_OPTION = CHAR_MAX + 1, 112 NO_SYNC_OPTION,
114 NO_SYNC_OPTION, 113 BLOCK_SIZE_OPTION
115 BLOCK_SIZE_OPTION
116}; 114};
117 115
118#ifdef _AIX 116#ifdef _AIX
119#pragma alloca 117# pragma alloca
120#endif 118#endif
121 119
122static int process_arguments (int, char **); 120static int process_arguments(int /*argc*/, char ** /*argv*/);
123static void set_all_thresholds (struct parameter_list *path); 121static void set_all_thresholds(struct parameter_list *path);
124static void print_help (void); 122static void print_help(void);
125void print_usage (void); 123void print_usage(void);
126static double calculate_percent(uintmax_t, uintmax_t); 124static double calculate_percent(uintmax_t, uintmax_t);
127static bool stat_path (struct parameter_list *p); 125static bool stat_path(struct parameter_list *p);
128static void get_stats (struct parameter_list *p, struct fs_usage *fsp); 126static void get_stats(struct parameter_list *p, struct fs_usage *fsp);
129static void get_path_stats (struct parameter_list *p, struct fs_usage *fsp); 127static void get_path_stats(struct parameter_list *p, struct fs_usage *fsp);
130 128
131static char *units; 129static char *units;
132static uintmax_t mult = 1024 * 1024; 130static uintmax_t mult = 1024 * 1024;
@@ -155,992 +153,961 @@ static char *group = NULL;
155static struct stat *stat_buf; 153static struct stat *stat_buf;
156static struct name_list *seen = NULL; 154static struct name_list *seen = NULL;
157 155
158 156int main(int argc, char **argv) {
159int 157 int result = STATE_UNKNOWN;
160main (int argc, char **argv) 158 int disk_result = STATE_UNKNOWN;
161{ 159 char *output = NULL;
162 int result = STATE_UNKNOWN; 160 char *ignored = NULL;
163 int disk_result = STATE_UNKNOWN; 161 char *details = NULL;
164 char *output; 162 char *perf = NULL;
165 char *ignored; 163 char *perf_ilabel = NULL;
166 char *details; 164 char *preamble = " - free space:";
167 char *perf; 165 char *ignored_preamble = " - ignored paths:";
168 char *perf_ilabel; 166 char *flag_header = NULL;
169 char *preamble = " - free space:"; 167 int temp_result = STATE_UNKNOWN;
170 char *ignored_preamble = " - ignored paths:"; 168
171 char *flag_header; 169 struct mount_entry *me = NULL;
172 int temp_result; 170 struct fs_usage fsp = {0};
173 171 struct parameter_list *temp_list = NULL;
174 struct mount_entry *me; 172 struct parameter_list *path = NULL;
175 struct fs_usage fsp;
176 struct parameter_list *temp_list, *path;
177 173
178#ifdef __CYGWIN__ 174#ifdef __CYGWIN__
179 char mountdir[32]; 175 char mountdir[32];
180#endif 176#endif
181 177
182 output = strdup (""); 178 output = strdup("");
183 ignored = strdup (""); 179 ignored = strdup("");
184 details = strdup (""); 180 details = strdup("");
185 perf = strdup (""); 181 perf = strdup("");
186 perf_ilabel = strdup (""); 182 perf_ilabel = strdup("");
187 stat_buf = malloc(sizeof *stat_buf); 183 stat_buf = malloc(sizeof *stat_buf);
188 184
189 setlocale (LC_ALL, ""); 185 setlocale(LC_ALL, "");
190 bindtextdomain (PACKAGE, LOCALEDIR); 186 bindtextdomain(PACKAGE, LOCALEDIR);
191 textdomain (PACKAGE); 187 textdomain(PACKAGE);
192 188
193 mount_list = read_file_system_list (0); 189 mount_list = read_file_system_list(0);
194 190
195 /* Parse extra opts if any */ 191 /* Parse extra opts if any */
196 argv = np_extra_opts (&argc, argv, progname); 192 argv = np_extra_opts(&argc, argv, progname);
197 193
198 if (process_arguments (argc, argv) == ERROR) 194 if (process_arguments(argc, argv) == ERROR)
199 usage4 (_("Could not parse arguments")); 195 usage4(_("Could not parse arguments"));
200 196
201 /* If a list of paths has not been selected, find entire 197 /* If a list of paths has not been selected, find entire
202 mount list and create list of paths 198 mount list and create list of paths
203 */ 199 */
204 if (path_selected == false && path_ignored == false) { 200 if (path_selected == false && path_ignored == false) {
205 for (me = mount_list; me; me = me->me_next) { 201 for (me = mount_list; me; me = me->me_next) {
206 if (! (path = np_find_parameter(path_select_list, me->me_mountdir))) { 202 if (!(path = np_find_parameter(path_select_list, me->me_mountdir))) {
207 path = np_add_parameter(&path_select_list, me->me_mountdir); 203 path = np_add_parameter(&path_select_list, me->me_mountdir);
208 } 204 }
209 path->best_match = me; 205 path->best_match = me;
210 path->group = group; 206 path->group = group;
211 set_all_thresholds(path); 207 set_all_thresholds(path);
212 } 208 }
213 } 209 }
214 210
215 if (path_ignored == false) { 211 if (path_ignored == false) {
216 np_set_best_match(path_select_list, mount_list, exact_match); 212 np_set_best_match(path_select_list, mount_list, exact_match);
217 } 213 }
218 214
219 /* Error if no match found for specified paths */ 215 /* Error if no match found for specified paths */
220 temp_list = path_select_list; 216 temp_list = path_select_list;
221 217
222 while (path_select_list) { 218 while (path_select_list) {
223 if (! path_select_list->best_match && ignore_missing == true) { 219 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 */ 220 /* 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) { 221 if (path_select_list == temp_list) {
226 temp_list = path_select_list->name_next; 222 temp_list = path_select_list->name_next;
227 } 223 }
228 /* Add path argument to list of ignored paths to inform about missing paths being ignored and not alerted */ 224 /* 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); 225 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. */ 226 /* 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); 227 path_select_list = np_del_parameter(path_select_list, path_select_list->name_prev);
232 } else if (! path_select_list->best_match) { 228 } else if (!path_select_list->best_match) {
233 /* Without --ignore-missing option, exit with Critical state. */ 229 /* Without --ignore-missing option, exit with Critical state. */
234 die (STATE_CRITICAL, _("DISK %s: %s not found\n"), _("CRITICAL"), path_select_list->name); 230 die(STATE_CRITICAL, _("DISK %s: %s not found\n"), _("CRITICAL"), path_select_list->name);
235 } else { 231 } else {
236 /* Continue jumping through the list */ 232 /* Continue jumping through the list */
237 path_select_list = path_select_list->name_next; 233 path_select_list = path_select_list->name_next;
238 } 234 }
239 } 235 }
240 236
241 path_select_list = temp_list; 237 path_select_list = temp_list;
242 238
243 if (! path_select_list && ignore_missing == true) { 239 if (!path_select_list && ignore_missing == true) {
244 result = STATE_OK; 240 result = STATE_OK;
245 if (verbose >= 2) { 241 if (verbose >= 2) {
246 printf ("None of the provided paths were found\n"); 242 printf("None of the provided paths were found\n");
247 } 243 }
248 } 244 }
249 245
250 /* Process for every path in list */ 246 /* Process for every path in list */
251 for (path = path_select_list; path; path=path->name_next) { 247 for (path = path_select_list; path; path = path->name_next) {
252 if (verbose >= 3 && path->freespace_percent->warning != NULL && path->freespace_percent->critical != NULL) 248 if (verbose >= 3 && path->freespace_percent->warning != NULL && path->freespace_percent->critical != NULL)
253 printf("Thresholds(pct) for %s warn: %f crit %f\n", 249 printf("Thresholds(pct) for %s warn: %f crit %f\n", path->name, path->freespace_percent->warning->end,
254 path->name, 250 path->freespace_percent->critical->end);
255 path->freespace_percent->warning->end, 251
256 path->freespace_percent->critical->end); 252 if (verbose >= 3 && path->group != NULL)
257 253 printf("Group of %s: %s\n", path->name, path->group);
258 if (verbose >= 3 && path->group != NULL) 254
259 printf("Group of %s: %s\n",path->name,path->group); 255 /* reset disk result */
260 256 disk_result = STATE_UNKNOWN;
261 /* reset disk result */ 257
262 disk_result = STATE_UNKNOWN; 258 me = path->best_match;
263 259
264 me = path->best_match; 260 if (!me) {
265 261 continue;
266 if (!me) { 262 }
267 continue;
268 }
269 263
270#ifdef __CYGWIN__ 264#ifdef __CYGWIN__
271 if (strncmp(path->name, "/cygdrive/", 10) != 0 || strlen(path->name) > 11) 265 if (strncmp(path->name, "/cygdrive/", 10) != 0 || strlen(path->name) > 11)
272 continue; 266 continue;
273 snprintf(mountdir, sizeof(mountdir), "%s:\\", me->me_mountdir + 10); 267 snprintf(mountdir, sizeof(mountdir), "%s:\\", me->me_mountdir + 10);
274 if (GetDriveType(mountdir) != DRIVE_FIXED) 268 if (GetDriveType(mountdir) != DRIVE_FIXED)
275 me->me_remote = 1; 269 me->me_remote = 1;
276#endif 270#endif
277 /* Filters */ 271 /* Filters */
278 272
279 /* Remove filesystems already seen */ 273 /* Remove filesystems already seen */
280 if (np_seen_name(seen, me->me_mountdir)) { 274 if (np_seen_name(seen, me->me_mountdir)) {
281 continue; 275 continue;
282 } 276 }
283 np_add_name(&seen, me->me_mountdir); 277 np_add_name(&seen, me->me_mountdir);
284 278
285 if (path->group == NULL) { 279 if (path->group == NULL) {
286 /* Skip remote filesystems if we're not interested in them */ 280 /* Skip remote filesystems if we're not interested in them */
287 if (me->me_remote && show_local_fs) { 281 if (me->me_remote && show_local_fs) {
288 if (stat_remote_fs) { 282 if (stat_remote_fs) {
289 if (!stat_path(path) && ignore_missing == true) { 283 if (!stat_path(path) && ignore_missing == true) {
290 result = STATE_OK; 284 result = STATE_OK;
291 xasprintf (&ignored, "%s %s;", ignored, path->name); 285 xasprintf(&ignored, "%s %s;", ignored, path->name);
292 } 286 }
293 } 287 }
294 continue; 288 continue;
295 /* Skip pseudo fs's if we haven't asked for all fs's */ 289 /* Skip pseudo fs's if we haven't asked for all fs's */
296 } else if (me->me_dummy && !show_all_fs) { 290 }
297 continue; 291 if (me->me_dummy && !show_all_fs) {
298 /* Skip excluded fstypes */ 292 continue;
299 } else if (fs_exclude_list && np_find_regmatch (fs_exclude_list, me->me_type)) { 293 /* Skip excluded fstypes */
300 continue; 294 }
301 /* Skip excluded fs's */ 295 if (fs_exclude_list && np_find_regmatch(fs_exclude_list, me->me_type)) {
302 } else if (dp_exclude_list && 296 continue;
303 (np_find_name (dp_exclude_list, me->me_devname) || 297 /* Skip excluded fs's */
304 np_find_name (dp_exclude_list, me->me_mountdir))) { 298 }
305 continue; 299 if (dp_exclude_list && (np_find_name(dp_exclude_list, me->me_devname) || np_find_name(dp_exclude_list, me->me_mountdir))) {
306 /* Skip not included fstypes */ 300 continue;
307 } else if (fs_include_list && !np_find_regmatch(fs_include_list, me->me_type)) { 301 /* Skip not included fstypes */
308 continue; 302 }
309 } 303 if (fs_include_list && !np_find_regmatch(fs_include_list, me->me_type)) {
310 } 304 continue;
311 305 }
312 if (!stat_path(path)) { 306 }
313 if (ignore_missing == true) { 307
314 result = STATE_OK; 308 if (!stat_path(path)) {
315 xasprintf (&ignored, "%s %s;", ignored, path->name); 309 if (ignore_missing == true) {
316 } 310 result = STATE_OK;
317 continue; 311 xasprintf(&ignored, "%s %s;", ignored, path->name);
318 } 312 }
319 get_fs_usage (me->me_mountdir, me->me_devname, &fsp); 313 continue;
320 314 }
321 if (fsp.fsu_blocks && strcmp ("none", me->me_mountdir)) { 315 get_fs_usage(me->me_mountdir, me->me_devname, &fsp);
322 get_stats (path, &fsp); 316
323 317 if (fsp.fsu_blocks && strcmp("none", me->me_mountdir)) {
324 if (verbose >= 3) { 318 get_stats(path, &fsp);
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", 319
326 me->me_mountdir, 320 if (verbose >= 3) {
327 path->dused_pct, 321 printf("For %s, used_pct=%f free_pct=%f used_units=%lu free_units=%lu total_units=%lu used_inodes_pct=%f "
328 path->dfree_pct, 322 "free_inodes_pct=%f fsp.fsu_blocksize=%lu mult=%lu\n",
329 path->dused_units, 323 me->me_mountdir, path->dused_pct, path->dfree_pct, path->dused_units, path->dfree_units, path->dtotal_units,
330 path->dfree_units, 324 path->dused_inodes_percent, path->dfree_inodes_percent, fsp.fsu_blocksize, mult);
331 path->dtotal_units, 325 }
332 path->dused_inodes_percent, 326
333 path->dfree_inodes_percent, 327 /* Threshold comparisons */
334 fsp.fsu_blocksize, 328
335 mult); 329 temp_result = get_status(path->dfree_units, path->freespace_units);
336 } 330 if (verbose >= 3)
337 331 printf("Freespace_units result=%d\n", temp_result);
338 /* Threshold comparisons */ 332 disk_result = max_state(disk_result, temp_result);
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 333
334 temp_result = get_status(path->dfree_pct, path->freespace_percent);
335 if (verbose >= 3)
336 printf("Freespace%% result=%d\n", temp_result);
337 disk_result = max_state(disk_result, temp_result);
338
339 temp_result = get_status(path->dused_units, path->usedspace_units);
340 if (verbose >= 3)
341 printf("Usedspace_units result=%d\n", temp_result);
342 disk_result = max_state(disk_result, temp_result);
343
344 temp_result = get_status(path->dused_pct, path->usedspace_percent);
345 if (verbose >= 3)
346 printf("Usedspace_percent result=%d\n", temp_result);
347 disk_result = max_state(disk_result, temp_result);
348
349 temp_result = get_status(path->dused_inodes_percent, path->usedinodes_percent);
350 if (verbose >= 3)
351 printf("Usedinodes_percent result=%d\n", temp_result);
352 disk_result = max_state(disk_result, temp_result);
353
354 temp_result = get_status(path->dfree_inodes_percent, path->freeinodes_percent);
355 if (verbose >= 3)
356 printf("Freeinodes_percent result=%d\n", temp_result);
357 disk_result = max_state(disk_result, temp_result);
358
359 result = max_state(result, disk_result);
360
361 /* What a mess of units. The output shows free space, the perf data shows used space. Yikes!
362 Hack here. Trying to get warn/crit levels from freespace_(units|percent) for perf
363 data. Assumption that start=0. Roll on new syntax...
364 */
365
366 /* *_high_tide must be reinitialized at each run */
367 uint64_t warning_high_tide = UINT64_MAX;
368
369 if (path->freespace_units->warning != NULL) {
370 warning_high_tide = (path->dtotal_units - path->freespace_units->warning->end) * mult;
371 }
372 if (path->freespace_percent->warning != NULL) {
373 warning_high_tide =
374 min(warning_high_tide, (uint64_t)((1.0 - path->freespace_percent->warning->end / 100) * (path->dtotal_units * mult)));
375 }
376
377 uint64_t critical_high_tide = UINT64_MAX;
378
379 if (path->freespace_units->critical != NULL) {
380 critical_high_tide = (path->dtotal_units - path->freespace_units->critical->end) * mult;
381 }
382 if (path->freespace_percent->critical != NULL) {
383 critical_high_tide =
384 min(critical_high_tide, (uint64_t)((1.0 - path->freespace_percent->critical->end / 100) * (path->dtotal_units * mult)));
385 }
386
387 /* Nb: *_high_tide are unset when == UINT64_MAX */
388 xasprintf(&perf, "%s %s", perf,
389 perfdata_uint64((!strcmp(me->me_mountdir, "none") || display_mntp) ? me->me_devname : me->me_mountdir,
390 path->dused_units * mult, "B", (warning_high_tide == UINT64_MAX ? false : true), warning_high_tide,
391 (critical_high_tide == UINT64_MAX ? false : true), critical_high_tide, true, 0, true,
392 path->dtotal_units * mult));
393
394 if (display_inodes_perfdata) {
395 /* *_high_tide must be reinitialized at each run */
396 warning_high_tide = UINT64_MAX;
397 critical_high_tide = UINT64_MAX;
398
399 if (path->freeinodes_percent->warning != NULL) {
400 warning_high_tide = (uint64_t)fabs(
401 min((double)warning_high_tide, (double)(1.0 - path->freeinodes_percent->warning->end / 100) * path->inodes_total));
402 }
403 if (path->freeinodes_percent->critical != NULL) {
404 critical_high_tide = (uint64_t)fabs(min(
405 (double)critical_high_tide, (double)(1.0 - path->freeinodes_percent->critical->end / 100) * path->inodes_total));
406 }
407
408 xasprintf(&perf_ilabel, "%s (inodes)",
409 (!strcmp(me->me_mountdir, "none") || display_mntp) ? me->me_devname : me->me_mountdir);
410 /* Nb: *_high_tide are unset when == UINT64_MAX */
411 xasprintf(&perf, "%s %s", perf,
412 perfdata_uint64(perf_ilabel, path->inodes_used, "", (warning_high_tide != UINT64_MAX ? true : false),
413 warning_high_tide, (critical_high_tide != UINT64_MAX ? true : false), critical_high_tide, true, 0,
414 true, path->inodes_total));
415 }
416
417 if (disk_result == STATE_OK && erronly && !verbose)
418 continue;
419
420 if (disk_result && verbose >= 1) {
421 xasprintf(&flag_header, " %s [", state_text(disk_result));
422 } else {
423 xasprintf(&flag_header, "");
424 }
425 xasprintf(&output, "%s%s %s %llu%s (%.1f%%", output, flag_header,
426 (!strcmp(me->me_mountdir, "none") || display_mntp) ? me->me_devname : me->me_mountdir, path->dfree_units, units,
427 path->dfree_pct);
428 if (path->dused_inodes_percent < 0) {
429 xasprintf(&output, "%s inode=-)%s;", output, (disk_result ? "]" : ""));
430 } else {
431 xasprintf(&output, "%s inode=%.0f%%)%s;", output, path->dfree_inodes_percent, ((disk_result && verbose >= 1) ? "]" : ""));
432 }
433 free(flag_header);
434 }
435 }
436
437 if (verbose >= 2)
438 xasprintf(&output, "%s%s", output, details);
439
440 if (strcmp(output, "") == 0 && !erronly) {
441 preamble = "";
442 xasprintf(&output, " - No disks were found for provided parameters");
443 }
444
445 printf("DISK %s%s%s%s%s|%s\n", state_text(result), ((erronly && result == STATE_OK)) ? "" : preamble, output,
446 (strcmp(ignored, "") == 0) ? "" : ignored_preamble, ignored, perf);
447 return result;
448}
458 449
459double calculate_percent(uintmax_t value, uintmax_t total) { 450double calculate_percent(uintmax_t value, uintmax_t total) {
460 double pct = -1; 451 double pct = -1;
461 if(value <= DBL_MAX && total != 0) { 452 if (value <= DBL_MAX && total != 0) {
462 pct = (double)value / total * 100.0; 453 pct = (double)value / total * 100.0;
463 } 454 }
464 return pct; 455 return pct;
465} 456}
466 457
467/* process command-line arguments */ 458/* process command-line arguments */
468int 459int process_arguments(int argc, char **argv) {
469process_arguments (int argc, char **argv) 460 int c;
470{ 461 int err;
471 int c, err; 462 struct parameter_list *se;
472 struct parameter_list *se; 463 struct parameter_list *temp_list = NULL;
473 struct parameter_list *temp_list = NULL, *previous = NULL; 464 struct parameter_list *previous = NULL;
474 struct mount_entry *me; 465 struct mount_entry *me;
475 regex_t re; 466 regex_t re;
476 int cflags = REG_NOSUB | REG_EXTENDED; 467 int cflags = REG_NOSUB | REG_EXTENDED;
477 int default_cflags = cflags; 468 int default_cflags = cflags;
478 char errbuf[MAX_INPUT_BUFFER]; 469 char errbuf[MAX_INPUT_BUFFER];
479 int fnd = 0; 470 int fnd = 0;
480 471
481 int option = 0; 472 int option = 0;
482 static struct option longopts[] = { 473 static struct option longopts[] = {{"timeout", required_argument, 0, 't'},
483 {"timeout", required_argument, 0, 't'}, 474 {"warning", required_argument, 0, 'w'},
484 {"warning", required_argument, 0, 'w'}, 475 {"critical", required_argument, 0, 'c'},
485 {"critical", required_argument, 0, 'c'}, 476 {"iwarning", required_argument, 0, 'W'},
486 {"iwarning", required_argument, 0, 'W'}, 477 /* Dang, -C is taken. We might want to reshuffle this. */
487 /* Dang, -C is taken. We might want to reshuffle this. */ 478 {"icritical", required_argument, 0, 'K'},
488 {"icritical", required_argument, 0, 'K'}, 479 {"kilobytes", no_argument, 0, 'k'},
489 {"kilobytes", no_argument, 0, 'k'}, 480 {"megabytes", no_argument, 0, 'm'},
490 {"megabytes", no_argument, 0, 'm'}, 481 {"units", required_argument, 0, 'u'},
491 {"units", required_argument, 0, 'u'}, 482 {"path", required_argument, 0, 'p'},
492 {"path", required_argument, 0, 'p'}, 483 {"partition", required_argument, 0, 'p'},
493 {"partition", required_argument, 0, 'p'}, 484 {"exclude_device", required_argument, 0, 'x'},
494 {"exclude_device", required_argument, 0, 'x'}, 485 {"exclude-type", required_argument, 0, 'X'},
495 {"exclude-type", required_argument, 0, 'X'}, 486 {"include-type", required_argument, 0, 'N'},
496 {"include-type", required_argument, 0, 'N'}, 487 {"group", required_argument, 0, 'g'},
497 {"group", required_argument, 0, 'g'}, 488 {"eregi-path", required_argument, 0, 'R'},
498 {"eregi-path", required_argument, 0, 'R'}, 489 {"eregi-partition", required_argument, 0, 'R'},
499 {"eregi-partition", required_argument, 0, 'R'}, 490 {"ereg-path", required_argument, 0, 'r'},
500 {"ereg-path", required_argument, 0, 'r'}, 491 {"ereg-partition", required_argument, 0, 'r'},
501 {"ereg-partition", required_argument, 0, 'r'}, 492 {"freespace-ignore-reserved", no_argument, 0, 'f'},
502 {"freespace-ignore-reserved", no_argument, 0, 'f'}, 493 {"ignore-ereg-path", required_argument, 0, 'i'},
503 {"ignore-ereg-path", required_argument, 0, 'i'}, 494 {"ignore-ereg-partition", required_argument, 0, 'i'},
504 {"ignore-ereg-partition", required_argument, 0, 'i'}, 495 {"ignore-eregi-path", required_argument, 0, 'I'},
505 {"ignore-eregi-path", required_argument, 0, 'I'}, 496 {"ignore-eregi-partition", required_argument, 0, 'I'},
506 {"ignore-eregi-partition", required_argument, 0, 'I'}, 497 {"ignore-missing", no_argument, 0, 'n'},
507 {"ignore-missing", no_argument, 0, 'n'}, 498 {"local", no_argument, 0, 'l'},
508 {"local", no_argument, 0, 'l'}, 499 {"stat-remote-fs", no_argument, 0, 'L'},
509 {"stat-remote-fs", no_argument, 0, 'L'}, 500 {"iperfdata", no_argument, 0, 'P'},
510 {"iperfdata", no_argument, 0, 'P'}, 501 {"mountpoint", no_argument, 0, 'M'},
511 {"mountpoint", no_argument, 0, 'M'}, 502 {"errors-only", no_argument, 0, 'e'},
512 {"errors-only", no_argument, 0, 'e'}, 503 {"exact-match", no_argument, 0, 'E'},
513 {"exact-match", no_argument, 0, 'E'}, 504 {"all", no_argument, 0, 'A'},
514 {"all", no_argument, 0, 'A'}, 505 {"verbose", no_argument, 0, 'v'},
515 {"verbose", no_argument, 0, 'v'}, 506 {"quiet", no_argument, 0, 'q'},
516 {"quiet", no_argument, 0, 'q'}, 507 {"clear", no_argument, 0, 'C'},
517 {"clear", no_argument, 0, 'C'}, 508 {"version", no_argument, 0, 'V'},
518 {"version", no_argument, 0, 'V'}, 509 {"help", no_argument, 0, 'h'},
519 {"help", no_argument, 0, 'h'}, 510 {0, 0, 0, 0}};
520 {0, 0, 0, 0} 511
521 }; 512 if (argc < 2)
522 513 return ERROR;
523 if (argc < 2) 514
524 return ERROR; 515 np_add_regex(&fs_exclude_list, "iso9660", REG_EXTENDED);
525 516
526 np_add_regex(&fs_exclude_list, "iso9660", REG_EXTENDED); 517 for (c = 1; c < argc; c++)
527 518 if (strcmp("-to", argv[c]) == 0)
528 for (c = 1; c < argc; c++) 519 strcpy(argv[c], "-t");
529 if (strcmp ("-to", argv[c]) == 0) 520
530 strcpy (argv[c], "-t"); 521 while (1) {
531 522 c = getopt_long(argc, argv, "+?VqhvefCt:c:w:K:W:u:p:x:X:N:mklLPg:R:r:i:I:MEAn", longopts, &option);
532 while (1) { 523
533 c = getopt_long (argc, argv, "+?VqhvefCt:c:w:K:W:u:p:x:X:N:mklLPg:R:r:i:I:MEAn", longopts, &option); 524 if (c == -1 || c == EOF)
534 525 break;
535 if (c == -1 || c == EOF) 526
536 break; 527 switch (c) {
537 528 case 't': /* timeout period */
538 switch (c) { 529 if (is_integer(optarg)) {
539 case 't': /* timeout period */ 530 timeout_interval = atoi(optarg);
540 if (is_integer (optarg)) { 531 break;
541 timeout_interval = atoi (optarg); 532 } else {
542 break; 533 usage2(_("Timeout interval must be a positive integer"), optarg);
543 } 534 }
544 else { 535
545 usage2 (_("Timeout interval must be a positive integer"), optarg); 536 /* See comments for 'c' */
546 } 537 case 'w': /* warning threshold */
547
548 /* See comments for 'c' */
549 case 'w': /* warning threshold */
550 if (!is_percentage_expression(optarg) && !is_numeric(optarg)) { 538 if (!is_percentage_expression(optarg) && !is_numeric(optarg)) {
551 die(STATE_UNKNOWN, "Argument for --warning invalid or missing: %s\n", optarg); 539 die(STATE_UNKNOWN, "Argument for --warning invalid or missing: %s\n", optarg);
552 } 540 }
553 541
554 if (strstr(optarg, "%")) { 542 if (strstr(optarg, "%")) {
555 if (*optarg == '@') { 543 if (*optarg == '@') {
556 warn_freespace_percent = optarg; 544 warn_freespace_percent = optarg;
557 } else { 545 } else {
558 xasprintf(&warn_freespace_percent, "@%s", optarg); 546 xasprintf(&warn_freespace_percent, "@%s", optarg);
559 } 547 }
560 } else { 548 } else {
561 if (*optarg == '@') { 549 if (*optarg == '@') {
562 warn_freespace_units = optarg; 550 warn_freespace_units = optarg;
563 } else { 551 } else {
564 xasprintf(&warn_freespace_units, "@%s", optarg); 552 xasprintf(&warn_freespace_units, "@%s", optarg);
565 } 553 }
566 } 554 }
567 break; 555 break;
568 556
569 /* Awful mistake where the range values do not make sense. Normally, 557 /* 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 558 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 559 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 560 force @ at the beginning of the range, so that it is backwards compatible
573 */ 561 */
574 case 'c': /* critical threshold */ 562 case 'c': /* critical threshold */
575 if (!is_percentage_expression(optarg) && !is_numeric(optarg)) { 563 if (!is_percentage_expression(optarg) && !is_numeric(optarg)) {
576 die(STATE_UNKNOWN, "Argument for --critical invalid or missing: %s\n", optarg); 564 die(STATE_UNKNOWN, "Argument for --critical invalid or missing: %s\n", optarg);
577 } 565 }
578 566
579 if (strstr(optarg, "%")) { 567 if (strstr(optarg, "%")) {
580 if (*optarg == '@') { 568 if (*optarg == '@') {
581 crit_freespace_percent = optarg; 569 crit_freespace_percent = optarg;
582 } else { 570 } else {
583 xasprintf(&crit_freespace_percent, "@%s", optarg); 571 xasprintf(&crit_freespace_percent, "@%s", optarg);
584 } 572 }
585 } else { 573 } else {
586 if (*optarg == '@') { 574 if (*optarg == '@') {
587 crit_freespace_units = optarg; 575 crit_freespace_units = optarg;
588 } else { 576 } else {
589 xasprintf(&crit_freespace_units, "@%s", optarg); 577 xasprintf(&crit_freespace_units, "@%s", optarg);
590 } 578 }
591 } 579 }
592 break; 580 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 581
899void 582 case 'W': /* warning inode threshold */
900set_all_thresholds (struct parameter_list *path) 583 if (*optarg == '@') {
901{ 584 warn_freeinodes_percent = optarg;
902 if (path->freespace_units != NULL) free(path->freespace_units); 585 } else {
903 set_thresholds(&path->freespace_units, warn_freespace_units, crit_freespace_units); 586 xasprintf(&warn_freeinodes_percent, "@%s", optarg);
904 if (path->freespace_percent != NULL) free (path->freespace_percent); 587 }
905 set_thresholds(&path->freespace_percent, warn_freespace_percent, crit_freespace_percent); 588 break;
906 if (path->usedspace_units != NULL) free (path->usedspace_units); 589 case 'K': /* critical inode threshold */
907 set_thresholds(&path->usedspace_units, warn_usedspace_units, crit_usedspace_units); 590 if (*optarg == '@') {
908 if (path->usedspace_percent != NULL) free (path->usedspace_percent); 591 crit_freeinodes_percent = optarg;
909 set_thresholds(&path->usedspace_percent, warn_usedspace_percent, crit_usedspace_percent); 592 } else {
910 if (path->usedinodes_percent != NULL) free (path->usedinodes_percent); 593 xasprintf(&crit_freeinodes_percent, "@%s", optarg);
911 set_thresholds(&path->usedinodes_percent, warn_usedinodes_percent, crit_usedinodes_percent); 594 }
912 if (path->freeinodes_percent != NULL) free (path->freeinodes_percent); 595 break;
913 set_thresholds(&path->freeinodes_percent, warn_freeinodes_percent, crit_freeinodes_percent); 596 case 'u':
914} 597 if (units)
598 free(units);
599 if (!strcasecmp(optarg, "bytes")) {
600 mult = (uintmax_t)1;
601 units = strdup("B");
602 } else if (!strcmp(optarg, "KiB")) {
603 mult = (uintmax_t)1024;
604 units = strdup("KiB");
605 } else if (!strcmp(optarg, "kB")) {
606 mult = (uintmax_t)1000;
607 units = strdup("kB");
608 } else if (!strcmp(optarg, "MiB")) {
609 mult = (uintmax_t)1024 * 1024;
610 units = strdup("MiB");
611 } else if (!strcmp(optarg, "MB")) {
612 mult = (uintmax_t)1000 * 1000;
613 units = strdup("MB");
614 } else if (!strcmp(optarg, "GiB")) {
615 mult = (uintmax_t)1024 * 1024 * 1024;
616 units = strdup("GiB");
617 } else if (!strcmp(optarg, "GB")) {
618 mult = (uintmax_t)1000 * 1000 * 1000;
619 units = strdup("GB");
620 } else if (!strcmp(optarg, "TiB")) {
621 mult = (uintmax_t)1024 * 1024 * 1024 * 1024;
622 units = strdup("TiB");
623 } else if (!strcmp(optarg, "TB")) {
624 mult = (uintmax_t)1000 * 1000 * 1000 * 1000;
625 units = strdup("TB");
626 } else if (!strcmp(optarg, "PiB")) {
627 mult = (uintmax_t)1024 * 1024 * 1024 * 1024 * 1024;
628 units = strdup("PiB");
629 } else if (!strcmp(optarg, "PB")) {
630 mult = (uintmax_t)1000 * 1000 * 1000 * 1000 * 1000;
631 units = strdup("PB");
632 } else {
633 die(STATE_UNKNOWN, _("unit type %s not known\n"), optarg);
634 }
635 if (units == NULL)
636 die(STATE_UNKNOWN, _("failed allocating storage for '%s'\n"), "units");
637 break;
638 case 'k': /* display mountpoint */
639 mult = 1024;
640 if (units)
641 free(units);
642 units = strdup("kiB");
643 break;
644 case 'm': /* display mountpoint */
645 mult = 1024 * 1024;
646 if (units)
647 free(units);
648 units = strdup("MiB");
649 break;
650 case 'L':
651 stat_remote_fs = 1;
652 /* fallthrough */
653 case 'l':
654 show_local_fs = 1;
655 break;
656 case 'P':
657 display_inodes_perfdata = 1;
658 break;
659 case 'p': /* select path */
660 if (!(warn_freespace_units || crit_freespace_units || warn_freespace_percent || crit_freespace_percent ||
661 warn_usedspace_units || crit_usedspace_units || warn_usedspace_percent || crit_usedspace_percent ||
662 warn_usedinodes_percent || crit_usedinodes_percent || warn_freeinodes_percent || crit_freeinodes_percent)) {
663 die(STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set a threshold value before using -p\n"));
664 }
915 665
916void 666 /* add parameter if not found. overwrite thresholds if path has already been added */
917print_help (void) 667 if (!(se = np_find_parameter(path_select_list, optarg))) {
918{ 668 se = np_add_parameter(&path_select_list, optarg);
919 print_revision (progname, NP_VERSION); 669
920 670 if (stat(optarg, &stat_buf[0]) && ignore_missing == true) {
921 printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n"); 671 path_ignored = true;
922 printf (COPYRIGHT, copyright, email); 672 break;
923 673 }
924 printf ("%s\n", _("This plugin checks the amount of used disk space on a mounted file system")); 674 }
925 printf ("%s\n", _("and generates an alert if free space is less than one of the threshold values")); 675 se->group = group;
926 676 set_all_thresholds(se);
927 printf ("\n\n"); 677
928 678 /* With autofs, it is required to stat() the path before re-populating the mount_list */
929 print_usage (); 679 if (!stat_path(se)) {
930 680 break;
931 printf (UT_HELP_VRSN); 681 }
932 printf (UT_EXTRA_OPTS); 682 /* NB: We can't free the old mount_list "just like that": both list pointers and struct
933 683 * pointers are copied around. One of the reason it wasn't done yet is that other parts
934 printf (" %s\n", "-w, --warning=INTEGER"); 684 * of check_disk need the same kind of cleanup so it'd better be done as a whole */
935 printf (" %s\n", _("Exit with WARNING status if less than INTEGER units of disk are free")); 685 mount_list = read_file_system_list(0);
936 printf (" %s\n", "-w, --warning=PERCENT%"); 686 np_set_best_match(se, mount_list, exact_match);
937 printf (" %s\n", _("Exit with WARNING status if less than PERCENT of disk space is free")); 687
938 printf (" %s\n", "-c, --critical=INTEGER"); 688 path_selected = true;
939 printf (" %s\n", _("Exit with CRITICAL status if less than INTEGER units of disk are free")); 689 break;
940 printf (" %s\n", "-c, --critical=PERCENT%"); 690 case 'x': /* exclude path or partition */
941 printf (" %s\n", _("Exit with CRITICAL status if less than PERCENT of disk space is free")); 691 np_add_name(&dp_exclude_list, optarg);
942 printf (" %s\n", "-W, --iwarning=PERCENT%"); 692 break;
943 printf (" %s\n", _("Exit with WARNING status if less than PERCENT of inode space is free")); 693 case 'X': /* exclude file system type */
944 printf (" %s\n", "-K, --icritical=PERCENT%"); 694 err = np_add_regex(&fs_exclude_list, optarg, REG_EXTENDED);
945 printf (" %s\n", _("Exit with CRITICAL status if less than PERCENT of inode space is free")); 695 if (err != 0) {
946 printf (" %s\n", "-p, --path=PATH, --partition=PARTITION"); 696 regerror(err, &fs_exclude_list->regex, errbuf, MAX_INPUT_BUFFER);
947 printf (" %s\n", _("Mount point or block device as emitted by the mount(8) command (may be repeated)")); 697 die(STATE_UNKNOWN, "DISK %s: %s - %s\n", _("UNKNOWN"), _("Could not compile regular expression"), errbuf);
948 printf (" %s\n", "-x, --exclude_device=PATH <STRING>"); 698 }
949 printf (" %s\n", _("Ignore device (only works if -p unspecified)")); 699 break;
950 printf (" %s\n", "-C, --clear"); 700 case 'N': /* include file system type */
951 printf (" %s\n", _("Clear thresholds")); 701 err = np_add_regex(&fs_include_list, optarg, REG_EXTENDED);
952 printf (" %s\n", "-E, --exact-match"); 702 if (err != 0) {
953 printf (" %s\n", _("For paths or partitions specified with -p, only check for exact paths")); 703 regerror(err, &fs_exclude_list->regex, errbuf, MAX_INPUT_BUFFER);
954 printf (" %s\n", "-e, --errors-only"); 704 die(STATE_UNKNOWN, "DISK %s: %s - %s\n", _("UNKNOWN"), _("Could not compile regular expression"), errbuf);
955 printf (" %s\n", _("Display only devices/mountpoints with errors")); 705 }
956 printf (" %s\n", "-f, --freespace-ignore-reserved"); 706 break;
957 printf (" %s\n", _("Don't account root-reserved blocks into freespace in perfdata")); 707 case 'v': /* verbose */
958 printf (" %s\n", "-P, --iperfdata"); 708 verbose++;
959 printf (" %s\n", _("Display inode usage in perfdata")); 709 break;
960 printf (" %s\n", "-g, --group=NAME"); 710 case 'q': /* TODO: this function should eventually go away (removed 2007-09-20) */
961 printf (" %s\n", _("Group paths. Thresholds apply to (free-)space of all partitions together")); 711 /* verbose--; **replaced by line below**. -q was only a broken way of implementing -e */
962 printf (" %s\n", "-k, --kilobytes"); 712 erronly = true;
963 printf (" %s\n", _("Same as '--units kB'")); 713 break;
964 printf (" %s\n", "-l, --local"); 714 case 'e':
965 printf (" %s\n", _("Only check local filesystems")); 715 erronly = true;
966 printf (" %s\n", "-L, --stat-remote-fs"); 716 break;
967 printf (" %s\n", _("Only check local filesystems against thresholds. Yet call stat on remote filesystems")); 717 case 'E':
968 printf (" %s\n", _("to test if they are accessible (e.g. to detect Stale NFS Handles)")); 718 if (path_selected)
969 printf (" %s\n", "-M, --mountpoint"); 719 die(STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set -E before selecting paths\n"));
970 printf (" %s\n", _("Display the (block) device instead of the mount point")); 720 exact_match = true;
971 printf (" %s\n", "-m, --megabytes"); 721 break;
972 printf (" %s\n", _("Same as '--units MB'")); 722 case 'f':
973 printf (" %s\n", "-A, --all"); 723 freespace_ignore_reserved = true;
974 printf (" %s\n", _("Explicitly select all paths. This is equivalent to -R '.*'")); 724 break;
975 printf (" %s\n", "-R, --eregi-path=PATH, --eregi-partition=PARTITION"); 725 case 'g':
976 printf (" %s\n", _("Case insensitive regular expression for path/partition (may be repeated)")); 726 if (path_selected)
977 printf (" %s\n", "-r, --ereg-path=PATH, --ereg-partition=PARTITION"); 727 die(STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set group value before selecting paths\n"));
978 printf (" %s\n", _("Regular expression for path or partition (may be repeated)")); 728 group = optarg;
979 printf (" %s\n", "-I, --ignore-eregi-path=PATH, --ignore-eregi-partition=PARTITION"); 729 break;
980 printf (" %s\n", _("Regular expression to ignore selected path/partition (case insensitive) (may be repeated)")); 730 case 'I':
981 printf (" %s\n", "-i, --ignore-ereg-path=PATH, --ignore-ereg-partition=PARTITION"); 731 cflags |= REG_ICASE;
982 printf (" %s\n", _("Regular expression to ignore selected path or partition (may be repeated)")); 732 // Intentional fallthrough
983 printf (" %s\n", "-n, --ignore-missing"); 733 case 'i':
984 printf (" %s\n", _("Return OK if no filesystem matches, filesystem does not exist or is inaccessible.")); 734 if (!path_selected)
985 printf (" %s\n", _("(Provide this option before -p / -r / --ereg-path if used)")); 735 die(STATE_UNKNOWN, "DISK %s: %s\n", _("UNKNOWN"),
986 printf (UT_PLUG_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 736 _("Paths need to be selected before using -i/-I. Use -A to select all paths explicitly"));
987 printf (" %s\n", "-u, --units=STRING"); 737 err = regcomp(&re, optarg, cflags);
988 printf (" %s\n", _("Choose bytes, kB, MB, GB, TB (default: MB)")); 738 if (err != 0) {
989 printf (UT_VERBOSE); 739 regerror(err, &re, errbuf, MAX_INPUT_BUFFER);
990 printf (" %s\n", "-X, --exclude-type=TYPE_REGEX"); 740 die(STATE_UNKNOWN, "DISK %s: %s - %s\n", _("UNKNOWN"), _("Could not compile regular expression"), errbuf);
991 printf (" %s\n", _("Ignore all filesystems of types matching given regex(7) (may be repeated)")); 741 }
992 printf (" %s\n", "-N, --include-type=TYPE_REGEX"); 742
993 printf (" %s\n", _("Check only filesystems where the type matches this given regex(7) (may be repeated)")); 743 temp_list = path_select_list;
994 744
995 printf ("\n"); 745 previous = NULL;
996 printf ("%s\n", _("General usage hints:")); 746 while (temp_list) {
997 printf (" %s\n", _("- Arguments are positional! \"-w 5 -c 1 -p /foo -w6 -c2 -p /bar\" is not the same as")); 747 if (temp_list->best_match) {
998 printf (" %s\n", _("\"-w 5 -c 1 -p /bar w6 -c2 -p /foo\".")); 748 if (np_regex_match_mount_entry(temp_list->best_match, &re)) {
999 printf (" %s\n", _("- The syntax is broadly: \"{thresholds a} {paths a} -C {thresholds b} {thresholds b} ...\"")); 749
1000 750 if (verbose >= 3)
1001 751 printf("ignoring %s matching regex\n", temp_list->name);
1002 752
1003 printf ("\n"); 753 temp_list = np_del_parameter(temp_list, previous);
1004 printf ("%s\n", _("Examples:")); 754 /* pointer to first element needs to be updated if first item gets deleted */
1005 printf (" %s\n", "check_disk -w 10% -c 5% -p /tmp -p /var -C -w 100000 -c 50000 -p /"); 755 if (previous == NULL)
1006 printf (" %s\n\n", _("Checks /tmp and /var at 10% and 5%, and / at 100MB and 50MB")); 756 path_select_list = temp_list;
1007 printf (" %s\n", "check_disk -w 100 -c 50 -C -w 1000 -c 500 -g sidDATA -r '^/oracle/SID/data.*$'"); 757 } else {
1008 printf (" %s\n", _("Checks all filesystems not matching -r at 100M and 50M. The fs matching the -r regex")); 758 previous = temp_list;
1009 printf (" %s\n\n", _("are grouped which means the freespace thresholds are applied to all disks together")); 759 temp_list = temp_list->name_next;
1010 printf (" %s\n", "check_disk -w 100 -c 50 -C -w 1000 -c 500 -p /foo -C -w 5% -c 3% -p /bar"); 760 }
1011 printf (" %s\n", _("Checks /foo for 1000M/500M and /bar for 5/3%. All remaining volumes use 100M/50M")); 761 } else {
1012 762 previous = temp_list;
1013 printf (UT_SUPPORT); 763 temp_list = temp_list->name_next;
1014} 764 }
765 }
1015 766
767 cflags = default_cflags;
768 break;
769
770 case 'n':
771 ignore_missing = true;
772 break;
773 case 'A':
774 optarg = strdup(".*");
775 // Intentional fallthrough
776 case 'R':
777 cflags |= REG_ICASE;
778 // Intentional fallthrough
779 case 'r':
780 if (!(warn_freespace_units || crit_freespace_units || warn_freespace_percent || crit_freespace_percent ||
781 warn_usedspace_units || crit_usedspace_units || warn_usedspace_percent || crit_usedspace_percent ||
782 warn_usedinodes_percent || crit_usedinodes_percent || warn_freeinodes_percent || crit_freeinodes_percent)) {
783 die(STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"),
784 _("Must set a threshold value before using -r/-R/-A (--ereg-path/--eregi-path/--all)\n"));
785 }
1016 786
787 err = regcomp(&re, optarg, cflags);
788 if (err != 0) {
789 regerror(err, &re, errbuf, MAX_INPUT_BUFFER);
790 die(STATE_UNKNOWN, "DISK %s: %s - %s\n", _("UNKNOWN"), _("Could not compile regular expression"), errbuf);
791 }
792
793 for (me = mount_list; me; me = me->me_next) {
794 if (np_regex_match_mount_entry(me, &re)) {
795 fnd = true;
796 if (verbose >= 3)
797 printf("%s %s matching expression %s\n", me->me_devname, me->me_mountdir, optarg);
798
799 /* add parameter if not found. overwrite thresholds if path has already been added */
800 if (!(se = np_find_parameter(path_select_list, me->me_mountdir))) {
801 se = np_add_parameter(&path_select_list, me->me_mountdir);
802 }
803 se->group = group;
804 set_all_thresholds(se);
805 }
806 }
1017 807
1018void 808 if (!fnd && ignore_missing == true) {
1019print_usage (void) 809 path_ignored = true;
1020{ 810 path_selected = true;
1021 printf ("%s\n", _("Usage:")); 811 break;
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); 812 }
1023 printf ("[-C] [-E] [-e] [-f] [-g group ] [-k] [-l] [-M] [-m] [-R path ] [-r path ]\n"); 813 if (!fnd)
1024 printf ("[-t timeout] [-u unit] [-v] [-X type_regex] [-N type]\n"); 814 die(STATE_UNKNOWN, "DISK %s: %s - %s\n", _("UNKNOWN"), _("Regular expression did not match any path or disk"), optarg);
815
816 fnd = false;
817 path_selected = true;
818 np_set_best_match(path_select_list, mount_list, exact_match);
819 cflags = default_cflags;
820
821 break;
822 case 'M': /* display mountpoint */
823 display_mntp = true;
824 break;
825 case 'C':
826 /* add all mount entries to path_select list if no partitions have been explicitly defined using -p */
827 if (path_selected == false) {
828 struct parameter_list *path;
829 for (me = mount_list; me; me = me->me_next) {
830 if (!(path = np_find_parameter(path_select_list, me->me_mountdir)))
831 path = np_add_parameter(&path_select_list, me->me_mountdir);
832 path->best_match = me;
833 path->group = group;
834 set_all_thresholds(path);
835 }
836 }
837 warn_freespace_units = NULL;
838 crit_freespace_units = NULL;
839 warn_usedspace_units = NULL;
840 crit_usedspace_units = NULL;
841 warn_freespace_percent = NULL;
842 crit_freespace_percent = NULL;
843 warn_usedspace_percent = NULL;
844 crit_usedspace_percent = NULL;
845 warn_usedinodes_percent = NULL;
846 crit_usedinodes_percent = NULL;
847 warn_freeinodes_percent = NULL;
848 crit_freeinodes_percent = NULL;
849
850 path_selected = false;
851 group = NULL;
852 break;
853 case 'V': /* version */
854 print_revision(progname, NP_VERSION);
855 exit(STATE_UNKNOWN);
856 case 'h': /* help */
857 print_help();
858 exit(STATE_UNKNOWN);
859 case '?': /* help */
860 usage(_("Unknown argument"));
861 }
862 }
863
864 /* Support for "check_disk warn crit [fs]" with thresholds at used% level */
865 c = optind;
866 if (warn_usedspace_percent == NULL && argc > c && is_intnonneg(argv[c]))
867 warn_usedspace_percent = argv[c++];
868
869 if (crit_usedspace_percent == NULL && argc > c && is_intnonneg(argv[c]))
870 crit_usedspace_percent = argv[c++];
871
872 if (argc > c) {
873 se = np_add_parameter(&path_select_list, strdup(argv[c++]));
874 path_selected = true;
875 set_all_thresholds(se);
876 }
877
878 if (units == NULL) {
879 units = strdup("MiB");
880 mult = (uintmax_t)1024 * 1024;
881 }
882
883 return true;
1025} 884}
1026 885
1027bool 886void set_all_thresholds(struct parameter_list *path) {
1028stat_path (struct parameter_list *p) 887 if (path->freespace_units != NULL)
1029{ 888 free(path->freespace_units);
1030 /* Stat entry to check that dir exists and is accessible */ 889 set_thresholds(&path->freespace_units, warn_freespace_units, crit_freespace_units);
1031 if (verbose >= 3) 890 if (path->freespace_percent != NULL)
1032 printf("calling stat on %s\n", p->name); 891 free(path->freespace_percent);
1033 if (stat (p->name, &stat_buf[0])) { 892 set_thresholds(&path->freespace_percent, warn_freespace_percent, crit_freespace_percent);
1034 if (verbose >= 3) 893 if (path->usedspace_units != NULL)
1035 printf("stat failed on %s\n", p->name); 894 free(path->usedspace_units);
1036 if (ignore_missing == true) { 895 set_thresholds(&path->usedspace_units, warn_usedspace_units, crit_usedspace_units);
1037 return false; 896 if (path->usedspace_percent != NULL)
1038 } else { 897 free(path->usedspace_percent);
1039 printf("DISK %s - ", _("CRITICAL")); 898 set_thresholds(&path->usedspace_percent, warn_usedspace_percent, crit_usedspace_percent);
1040 die (STATE_CRITICAL, _("%s %s: %s\n"), p->name, _("is not accessible"), strerror(errno)); 899 if (path->usedinodes_percent != NULL)
1041 } 900 free(path->usedinodes_percent);
1042 } 901 set_thresholds(&path->usedinodes_percent, warn_usedinodes_percent, crit_usedinodes_percent);
1043 return true; 902 if (path->freeinodes_percent != NULL)
903 free(path->freeinodes_percent);
904 set_thresholds(&path->freeinodes_percent, warn_freeinodes_percent, crit_freeinodes_percent);
1044} 905}
1045 906
907void print_help(void) {
908 print_revision(progname, NP_VERSION);
909
910 printf("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
911 printf(COPYRIGHT, copyright, email);
912
913 printf("%s\n", _("This plugin checks the amount of used disk space on a mounted file system"));
914 printf("%s\n", _("and generates an alert if free space is less than one of the threshold values"));
915
916 printf("\n\n");
917
918 print_usage();
919
920 printf(UT_HELP_VRSN);
921 printf(UT_EXTRA_OPTS);
922
923 printf(" %s\n", "-w, --warning=INTEGER");
924 printf(" %s\n", _("Exit with WARNING status if less than INTEGER units of disk are free"));
925 printf(" %s\n", "-w, --warning=PERCENT%");
926 printf(" %s\n", _("Exit with WARNING status if less than PERCENT of disk space is free"));
927 printf(" %s\n", "-c, --critical=INTEGER");
928 printf(" %s\n", _("Exit with CRITICAL status if less than INTEGER units of disk are free"));
929 printf(" %s\n", "-c, --critical=PERCENT%");
930 printf(" %s\n", _("Exit with CRITICAL status if less than PERCENT of disk space is free"));
931 printf(" %s\n", "-W, --iwarning=PERCENT%");
932 printf(" %s\n", _("Exit with WARNING status if less than PERCENT of inode space is free"));
933 printf(" %s\n", "-K, --icritical=PERCENT%");
934 printf(" %s\n", _("Exit with CRITICAL status if less than PERCENT of inode space is free"));
935 printf(" %s\n", "-p, --path=PATH, --partition=PARTITION");
936 printf(" %s\n", _("Mount point or block device as emitted by the mount(8) command (may be repeated)"));
937 printf(" %s\n", "-x, --exclude_device=PATH <STRING>");
938 printf(" %s\n", _("Ignore device (only works if -p unspecified)"));
939 printf(" %s\n", "-C, --clear");
940 printf(" %s\n", _("Clear thresholds"));
941 printf(" %s\n", "-E, --exact-match");
942 printf(" %s\n", _("For paths or partitions specified with -p, only check for exact paths"));
943 printf(" %s\n", "-e, --errors-only");
944 printf(" %s\n", _("Display only devices/mountpoints with errors"));
945 printf(" %s\n", "-f, --freespace-ignore-reserved");
946 printf(" %s\n", _("Don't account root-reserved blocks into freespace in perfdata"));
947 printf(" %s\n", "-P, --iperfdata");
948 printf(" %s\n", _("Display inode usage in perfdata"));
949 printf(" %s\n", "-g, --group=NAME");
950 printf(" %s\n", _("Group paths. Thresholds apply to (free-)space of all partitions together"));
951 printf(" %s\n", "-k, --kilobytes");
952 printf(" %s\n", _("Same as '--units kB'"));
953 printf(" %s\n", "-l, --local");
954 printf(" %s\n", _("Only check local filesystems"));
955 printf(" %s\n", "-L, --stat-remote-fs");
956 printf(" %s\n", _("Only check local filesystems against thresholds. Yet call stat on remote filesystems"));
957 printf(" %s\n", _("to test if they are accessible (e.g. to detect Stale NFS Handles)"));
958 printf(" %s\n", "-M, --mountpoint");
959 printf(" %s\n", _("Display the (block) device instead of the mount point"));
960 printf(" %s\n", "-m, --megabytes");
961 printf(" %s\n", _("Same as '--units MB'"));
962 printf(" %s\n", "-A, --all");
963 printf(" %s\n", _("Explicitly select all paths. This is equivalent to -R '.*'"));
964 printf(" %s\n", "-R, --eregi-path=PATH, --eregi-partition=PARTITION");
965 printf(" %s\n", _("Case insensitive regular expression for path/partition (may be repeated)"));
966 printf(" %s\n", "-r, --ereg-path=PATH, --ereg-partition=PARTITION");
967 printf(" %s\n", _("Regular expression for path or partition (may be repeated)"));
968 printf(" %s\n", "-I, --ignore-eregi-path=PATH, --ignore-eregi-partition=PARTITION");
969 printf(" %s\n", _("Regular expression to ignore selected path/partition (case insensitive) (may be repeated)"));
970 printf(" %s\n", "-i, --ignore-ereg-path=PATH, --ignore-ereg-partition=PARTITION");
971 printf(" %s\n", _("Regular expression to ignore selected path or partition (may be repeated)"));
972 printf(" %s\n", "-n, --ignore-missing");
973 printf(" %s\n", _("Return OK if no filesystem matches, filesystem does not exist or is inaccessible."));
974 printf(" %s\n", _("(Provide this option before -p / -r / --ereg-path if used)"));
975 printf(UT_PLUG_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
976 printf(" %s\n", "-u, --units=STRING");
977 printf(" %s\n", _("Choose bytes, kB, MB, GB, TB (default: MB)"));
978 printf(UT_VERBOSE);
979 printf(" %s\n", "-X, --exclude-type=TYPE_REGEX");
980 printf(" %s\n", _("Ignore all filesystems of types matching given regex(7) (may be repeated)"));
981 printf(" %s\n", "-N, --include-type=TYPE_REGEX");
982 printf(" %s\n", _("Check only filesystems where the type matches this given regex(7) (may be repeated)"));
983
984 printf("\n");
985 printf("%s\n", _("General usage hints:"));
986 printf(" %s\n", _("- Arguments are positional! \"-w 5 -c 1 -p /foo -w6 -c2 -p /bar\" is not the same as"));
987 printf(" %s\n", _("\"-w 5 -c 1 -p /bar w6 -c2 -p /foo\"."));
988 printf(" %s\n", _("- The syntax is broadly: \"{thresholds a} {paths a} -C {thresholds b} {thresholds b} ...\""));
989
990 printf("\n");
991 printf("%s\n", _("Examples:"));
992 printf(" %s\n", "check_disk -w 10% -c 5% -p /tmp -p /var -C -w 100000 -c 50000 -p /");
993 printf(" %s\n\n", _("Checks /tmp and /var at 10% and 5%, and / at 100MB and 50MB"));
994 printf(" %s\n", "check_disk -w 100 -c 50 -C -w 1000 -c 500 -g sidDATA -r '^/oracle/SID/data.*$'");
995 printf(" %s\n", _("Checks all filesystems not matching -r at 100M and 50M. The fs matching the -r regex"));
996 printf(" %s\n\n", _("are grouped which means the freespace thresholds are applied to all disks together"));
997 printf(" %s\n", "check_disk -w 100 -c 50 -C -w 1000 -c 500 -p /foo -C -w 5% -c 3% -p /bar");
998 printf(" %s\n", _("Checks /foo for 1000M/500M and /bar for 5/3%. All remaining volumes use 100M/50M"));
999
1000 printf(UT_SUPPORT);
1001}
1046 1002
1047void 1003void print_usage(void) {
1048get_stats (struct parameter_list *p, struct fs_usage *fsp) { 1004 printf("%s\n", _("Usage:"));
1049 struct parameter_list *p_list; 1005 printf(" %s {-w absolute_limit |-w percentage_limit%% | -W inode_percentage_limit } {-c absolute_limit|-c percentage_limit%% | -K "
1050 struct fs_usage tmpfsp; 1006 "inode_percentage_limit } {-p path | -x device}\n",
1051 int first = 1; 1007 progname);
1008 printf("[-C] [-E] [-e] [-f] [-g group ] [-k] [-l] [-M] [-m] [-R path ] [-r path ]\n");
1009 printf("[-t timeout] [-u unit] [-v] [-X type_regex] [-N type]\n");
1010}
1052 1011
1053 if (p->group == NULL) { 1012bool stat_path(struct parameter_list *p) {
1054 get_path_stats(p,fsp); 1013 /* Stat entry to check that dir exists and is accessible */
1055 } else { 1014 if (verbose >= 3)
1056 /* find all group members */ 1015 printf("calling stat on %s\n", p->name);
1057 for (p_list = path_select_list; p_list; p_list=p_list->name_next) { 1016 if (stat(p->name, &stat_buf[0])) {
1017 if (verbose >= 3)
1018 printf("stat failed on %s\n", p->name);
1019 if (ignore_missing == true) {
1020 return false;
1021 }
1022 printf("DISK %s - ", _("CRITICAL"));
1023 die(STATE_CRITICAL, _("%s %s: %s\n"), p->name, _("is not accessible"), strerror(errno));
1024 }
1025 return true;
1026}
1027
1028void get_stats(struct parameter_list *p, struct fs_usage *fsp) {
1029 struct parameter_list *p_list;
1030 struct fs_usage tmpfsp;
1031 int first = 1;
1032
1033 if (p->group == NULL) {
1034 get_path_stats(p, fsp);
1035 } else {
1036 /* find all group members */
1037 for (p_list = path_select_list; p_list; p_list = p_list->name_next) {
1058#ifdef __CYGWIN__ 1038#ifdef __CYGWIN__
1059 if (strncmp(p_list->name, "/cygdrive/", 10) != 0) 1039 if (strncmp(p_list->name, "/cygdrive/", 10) != 0)
1060 continue; 1040 continue;
1061#endif 1041#endif
1062 if (p_list->group && ! (strcmp(p_list->group, p->group))) { 1042 if (p_list->group && !(strcmp(p_list->group, p->group))) {
1063 if (! stat_path(p_list)) 1043 if (!stat_path(p_list))
1064 continue; 1044 continue;
1065 get_fs_usage (p_list->best_match->me_mountdir, p_list->best_match->me_devname, &tmpfsp); 1045 get_fs_usage(p_list->best_match->me_mountdir, p_list->best_match->me_devname, &tmpfsp);
1066 get_path_stats(p_list, &tmpfsp); 1046 get_path_stats(p_list, &tmpfsp);
1067 if (verbose >= 3) 1047 if (verbose >= 3)
1068 printf("Group %s: adding %lu blocks sized %lu, (%s) used_units=%lu free_units=%lu total_units=%lu mult=%lu\n", 1048 printf("Group %s: adding %lu blocks sized %lu, (%s) used_units=%lu free_units=%lu total_units=%lu mult=%lu\n",
1069 p_list->group, 1049 p_list->group, tmpfsp.fsu_blocks, tmpfsp.fsu_blocksize, p_list->best_match->me_mountdir, p_list->dused_units,
1070 tmpfsp.fsu_blocks, 1050 p_list->dfree_units, p_list->dtotal_units, mult);
1071 tmpfsp.fsu_blocksize, 1051
1072 p_list->best_match->me_mountdir, 1052 /* prevent counting the first FS of a group twice since its parameter_list entry
1073 p_list->dused_units, 1053 * is used to carry the information of all file systems of the entire group */
1074 p_list->dfree_units, 1054 if (!first) {
1075 p_list->dtotal_units, 1055 p->total += p_list->total;
1076 mult); 1056 p->available += p_list->available;
1077 1057 p->available_to_root += p_list->available_to_root;
1078 /* prevent counting the first FS of a group twice since its parameter_list entry 1058 p->used += p_list->used;
1079 * is used to carry the information of all file systems of the entire group */ 1059
1080 if (! first) { 1060 p->dused_units += p_list->dused_units;
1081 p->total += p_list->total; 1061 p->dfree_units += p_list->dfree_units;
1082 p->available += p_list->available; 1062 p->dtotal_units += p_list->dtotal_units;
1083 p->available_to_root += p_list->available_to_root; 1063 p->inodes_total += p_list->inodes_total;
1084 p->used += p_list->used; 1064 p->inodes_free += p_list->inodes_free;
1085 1065 p->inodes_free_to_root += p_list->inodes_free_to_root;
1086 p->dused_units += p_list->dused_units; 1066 p->inodes_used += p_list->inodes_used;
1087 p->dfree_units += p_list->dfree_units; 1067 }
1088 p->dtotal_units += p_list->dtotal_units; 1068 first = 0;
1089 p->inodes_total += p_list->inodes_total; 1069 }
1090 p->inodes_free += p_list->inodes_free; 1070 if (verbose >= 3)
1091 p->inodes_free_to_root += p_list->inodes_free_to_root; 1071 printf("Group %s now has: used_units=%lu free_units=%lu total_units=%lu fsu_blocksize=%lu mult=%lu\n", p->group,
1092 p->inodes_used += p_list->inodes_used; 1072 p->dused_units, p->dfree_units, p->dtotal_units, tmpfsp.fsu_blocksize, mult);
1093 } 1073 }
1094 first = 0; 1074 /* modify devname and mountdir for output */
1095 } 1075 p->best_match->me_mountdir = p->best_match->me_devname = p->group;
1096 if (verbose >= 3) 1076 }
1097 printf("Group %s now has: used_units=%lu free_units=%lu total_units=%lu fsu_blocksize=%lu mult=%lu\n", 1077 /* finally calculate percentages for either plain FS or summed up group */
1098 p->group, 1078 p->dused_pct = calculate_percent(p->used, p->used + p->available); /* used + available can never be > uintmax */
1099 p->dused_units, 1079 p->dfree_pct = 100.0 - p->dused_pct;
1100 p->dfree_units, 1080 p->dused_inodes_percent = calculate_percent(p->inodes_total - p->inodes_free, p->inodes_total);
1101 p->dtotal_units, 1081 p->dfree_inodes_percent = 100 - p->dused_inodes_percent;
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
1114} 1082}
1115 1083
1116void 1084void get_path_stats(struct parameter_list *p, struct fs_usage *fsp) {
1117get_path_stats (struct parameter_list *p, struct fs_usage *fsp) { 1085 p->available = fsp->fsu_bavail;
1118 p->available = fsp->fsu_bavail; 1086 p->available_to_root = fsp->fsu_bfree;
1119 p->available_to_root = fsp->fsu_bfree; 1087 p->used = fsp->fsu_blocks - fsp->fsu_bfree;
1120 p->used = fsp->fsu_blocks - fsp->fsu_bfree; 1088 if (freespace_ignore_reserved) {
1121 if (freespace_ignore_reserved) { 1089 /* option activated : we subtract the root-reserved space from the total */
1122 /* option activated : we subtract the root-reserved space from the total */ 1090 p->total = fsp->fsu_blocks - p->available_to_root + p->available;
1123 p->total = fsp->fsu_blocks - p->available_to_root + p->available; 1091 } else {
1124 } else { 1092 /* default behaviour : take all the blocks into account */
1125 /* default behaviour : take all the blocks into account */ 1093 p->total = fsp->fsu_blocks;
1126 p->total = fsp->fsu_blocks; 1094 }
1127 } 1095
1128 1096 p->dused_units = p->used * fsp->fsu_blocksize / mult;
1129 p->dused_units = p->used*fsp->fsu_blocksize/mult; 1097 p->dfree_units = p->available * fsp->fsu_blocksize / mult;
1130 p->dfree_units = p->available*fsp->fsu_blocksize/mult; 1098 p->dtotal_units = p->total * fsp->fsu_blocksize / mult;
1131 p->dtotal_units = p->total*fsp->fsu_blocksize/mult; 1099 /* Free file nodes. Not sure the workaround is required, but in case...*/
1132 /* Free file nodes. Not sure the workaround is required, but in case...*/ 1100 p->inodes_free = fsp->fsu_ffree;
1133 p->inodes_free = fsp->fsu_ffree; 1101 p->inodes_free_to_root = fsp->fsu_ffree; /* Free file nodes for root. */
1134 p->inodes_free_to_root = fsp->fsu_ffree; /* Free file nodes for root. */ 1102 p->inodes_used = fsp->fsu_files - fsp->fsu_ffree;
1135 p->inodes_used = fsp->fsu_files - fsp->fsu_ffree; 1103 if (freespace_ignore_reserved) {
1136 if (freespace_ignore_reserved) { 1104 /* option activated : we subtract the root-reserved inodes from the total */
1137 /* option activated : we subtract the root-reserved inodes from the total */ 1105 /* not all OS report fsp->fsu_favail, only the ones with statvfs syscall */
1138 /* not all OS report fsp->fsu_favail, only the ones with statvfs syscall */ 1106 /* for others, fsp->fsu_ffree == fsp->fsu_favail */
1139 /* for others, fsp->fsu_ffree == fsp->fsu_favail */ 1107 p->inodes_total = fsp->fsu_files - p->inodes_free_to_root + p->inodes_free;
1140 p->inodes_total = fsp->fsu_files - p->inodes_free_to_root + p->inodes_free; 1108 } else {
1141 } else { 1109 /* default behaviour : take all the inodes into account */
1142 /* default behaviour : take all the inodes into account */ 1110 p->inodes_total = fsp->fsu_files;
1143 p->inodes_total = fsp->fsu_files; 1111 }
1144 } 1112 np_add_name(&seen, p->best_match->me_mountdir);
1145 np_add_name(&seen, p->best_match->me_mountdir);
1146} 1113}