1 /*****************************************************************************
3 * Monitoring check_disk plugin
6 * Copyright (c) 1999-2008 Monitoring Plugins Development Team
10 * This file contains the check_disk plugin
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
15 * the Free Software Foundation, either version 3 of the License, or
16 * (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
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/>.
27 *****************************************************************************/
29 const char *progname
= "check_disk";
30 const char *program_name
= "check_disk"; /* Required for coreutils libs */
31 const char *copyright
= "1999-2008";
32 const char *email
= "devel@monitoring-plugins.org";
36 #ifdef HAVE_SYS_STAT_H
37 # include <sys/stat.h>
40 # include <inttypes.h>
45 #include "utils_disk.h"
48 #include "mountlist.h"
49 #include "intprops.h" /* necessary for TYPE_MAXIMUM */
61 /* If nonzero, show even filesystems with zero size or
62 uninteresting types. */
63 static int show_all_fs
= 1;
65 /* If nonzero, show only local filesystems. */
66 static int show_local_fs
= 0;
68 /* If nonzero, show only local filesystems but call stat() on remote ones. */
69 static int stat_remote_fs
= 0;
71 /* If positive, the units to use when printing sizes;
72 if negative, the human-readable base. */
73 /* static int output_block_size; */
75 /* If nonzero, invoke the `sync' system call before getting any usage data.
76 Using this option can make df very slow, especially with many or very
77 busy disks. Note that this may make a difference on some systems --
78 SunOs4.1.3, for one. It is *not* necessary on Linux. */
79 /* static int require_sync = 0; */
81 /* Linked list of filesystem types to display.
82 If `fs_select_list' is NULL, list all types.
83 This table is generated dynamically from command-line options,
84 rather than hardcoding into the program what it thinks are the
85 valid filesystem types; let the user specify any filesystem type
86 they want to, and if there are any filesystems of that type, they
89 Some filesystem types:
90 4.2 4.3 ufs nfs swap ignore io vm efs dbg */
92 /* static struct parameter_list *fs_select_list; */
94 /* Linked list of filesystem types to omit.
95 If the list is empty, don't exclude any types. */
96 static struct name_list
*fs_exclude_list
;
98 /* Linked list of filesystem types to check.
99 If the list is empty, include all types. */
100 static struct name_list
*fs_include_list
;
102 static struct name_list
*dp_exclude_list
;
104 static struct parameter_list
*path_select_list
= NULL
;
106 /* Linked list of mounted filesystems. */
107 static struct mount_entry
*mount_list
;
109 /* For long options that have no equivalent short option, use a
110 non-character as a pseudo short option, starting with CHAR_MAX + 1. */
113 SYNC_OPTION
= CHAR_MAX
+ 1,
122 int process_arguments (int, char **);
123 void print_path (const char *mypath
);
124 void set_all_thresholds (struct parameter_list
*path
);
125 int validate_arguments (uintmax_t, uintmax_t, double, double, double, double, char *);
126 void print_help (void);
127 void print_usage (void);
128 double calculate_percent(uintmax_t, uintmax_t);
129 void stat_path (struct parameter_list
*p
);
130 void get_stats (struct parameter_list
*p
, struct fs_usage
*fsp
);
131 void get_path_stats (struct parameter_list
*p
, struct fs_usage
*fsp
);
136 char *exclude_device
;
138 uintmax_t mult
= 1024 * 1024;
141 int display_mntp
= FALSE
;
142 int exact_match
= FALSE
;
143 int freespace_ignore_reserved
= FALSE
;
144 int display_inodes_perfdata
= FALSE
;
145 char *warn_freespace_units
= NULL
;
146 char *crit_freespace_units
= NULL
;
147 char *warn_freespace_percent
= NULL
;
148 char *crit_freespace_percent
= NULL
;
149 char *warn_usedspace_units
= NULL
;
150 char *crit_usedspace_units
= NULL
;
151 char *warn_usedspace_percent
= NULL
;
152 char *crit_usedspace_percent
= NULL
;
153 char *warn_usedinodes_percent
= NULL
;
154 char *crit_usedinodes_percent
= NULL
;
155 char *warn_freeinodes_percent
= NULL
;
156 char *crit_freeinodes_percent
= NULL
;
157 int path_selected
= FALSE
;
159 struct stat
*stat_buf
;
160 struct name_list
*seen
= NULL
;
164 main (int argc
, char **argv
)
166 int result
= STATE_UNKNOWN
;
167 int disk_result
= STATE_UNKNOWN
;
174 double inode_space_pct
;
175 double warning_high_tide
;
176 double critical_high_tide
;
179 struct mount_entry
*me
;
181 struct parameter_list
*temp_list
, *path
;
187 preamble
= strdup (" - free space:");
188 output
= strdup ("");
189 details
= strdup ("");
191 perf_ilabel
= strdup ("");
192 stat_buf
= malloc(sizeof *stat_buf
);
194 setlocale (LC_ALL
, "");
195 bindtextdomain (PACKAGE
, LOCALEDIR
);
196 textdomain (PACKAGE
);
198 mount_list
= read_file_system_list (0);
200 /* Parse extra opts if any */
201 argv
= np_extra_opts (&argc
, argv
, progname
);
203 if (process_arguments (argc
, argv
) == ERROR
)
204 usage4 (_("Could not parse arguments"));
206 /* If a list of paths has not been selected, find entire
207 mount list and create list of paths
209 if (path_selected
== FALSE
) {
210 for (me
= mount_list
; me
; me
= me
->me_next
) {
211 if (! (path
= np_find_parameter(path_select_list
, me
->me_mountdir
))) {
212 path
= np_add_parameter(&path_select_list
, me
->me_mountdir
);
214 path
->best_match
= me
;
216 set_all_thresholds(path
);
219 np_set_best_match(path_select_list
, mount_list
, exact_match
);
221 /* Error if no match found for specified paths */
222 temp_list
= path_select_list
;
225 if (! temp_list
->best_match
) {
226 die (STATE_CRITICAL
, _("DISK %s: %s not found\n"), _("CRITICAL"), temp_list
->name
);
229 temp_list
= temp_list
->name_next
;
232 /* Process for every path in list */
233 for (path
= path_select_list
; path
; path
=path
->name_next
) {
234 if (verbose
>= 3 && path
->freespace_percent
->warning
!= NULL
&& path
->freespace_percent
->critical
!= NULL
)
235 printf("Thresholds(pct) for %s warn: %f crit %f\n",path
->name
, path
->freespace_percent
->warning
->end
,
236 path
->freespace_percent
->critical
->end
);
238 if (verbose
>= 3 && path
->group
!= NULL
)
239 printf("Group of %s: %s\n",path
->name
,path
->group
);
241 /* reset disk result */
242 disk_result
= STATE_UNKNOWN
;
244 me
= path
->best_match
;
247 if (strncmp(path
->name
, "/cygdrive/", 10) != 0 || strlen(path
->name
) > 11)
249 snprintf(mountdir
, sizeof(mountdir
), "%s:\\", me
->me_mountdir
+ 10);
250 if (GetDriveType(mountdir
) != DRIVE_FIXED
)
255 /* Remove filesystems already seen */
256 if (np_seen_name(seen
, me
->me_mountdir
)) {
259 np_add_name(&seen
, me
->me_mountdir
);
261 if (path
->group
== NULL
) {
262 /* Skip remote filesystems if we're not interested in them */
263 if (me
->me_remote
&& show_local_fs
) {
267 /* Skip pseudo fs's if we haven't asked for all fs's */
268 } else if (me
->me_dummy
&& !show_all_fs
) {
270 /* Skip excluded fstypes */
271 } else if (fs_exclude_list
&& np_find_name (fs_exclude_list
, me
->me_type
)) {
273 /* Skip excluded fs's */
274 } else if (dp_exclude_list
&&
275 (np_find_name (dp_exclude_list
, me
->me_devname
) ||
276 np_find_name (dp_exclude_list
, me
->me_mountdir
))) {
278 /* Skip not included fstypes */
279 } else if (fs_include_list
&& !np_find_name (fs_include_list
, me
->me_type
)) {
285 get_fs_usage (me
->me_mountdir
, me
->me_devname
, &fsp
);
287 if (fsp
.fsu_blocks
&& strcmp ("none", me
->me_mountdir
)) {
288 get_stats (path
, &fsp
);
291 printf ("For %s, used_pct=%g free_pct=%g used_units=%g free_units=%g total_units=%g used_inodes_pct=%g free_inodes_pct=%g fsp.fsu_blocksize=%llu mult=%llu\n",
292 me
->me_mountdir
, path
->dused_pct
, path
->dfree_pct
, path
->dused_units
, path
->dfree_units
, path
->dtotal_units
, path
->dused_inodes_percent
, path
->dfree_inodes_percent
, fsp
.fsu_blocksize
, mult
);
295 /* Threshold comparisons */
297 temp_result
= get_status(path
->dfree_units
, path
->freespace_units
);
298 if (verbose
>=3) printf("Freespace_units result=%d\n", temp_result
);
299 disk_result
= max_state( disk_result
, temp_result
);
301 temp_result
= get_status(path
->dfree_pct
, path
->freespace_percent
);
302 if (verbose
>=3) printf("Freespace%% result=%d\n", temp_result
);
303 disk_result
= max_state( disk_result
, temp_result
);
305 temp_result
= get_status(path
->dused_units
, path
->usedspace_units
);
306 if (verbose
>=3) printf("Usedspace_units result=%d\n", temp_result
);
307 disk_result
= max_state( disk_result
, temp_result
);
309 temp_result
= get_status(path
->dused_pct
, path
->usedspace_percent
);
310 if (verbose
>=3) printf("Usedspace_percent result=%d\n", temp_result
);
311 disk_result
= max_state( disk_result
, temp_result
);
313 temp_result
= get_status(path
->dused_inodes_percent
, path
->usedinodes_percent
);
314 if (verbose
>=3) printf("Usedinodes_percent result=%d\n", temp_result
);
315 disk_result
= max_state( disk_result
, temp_result
);
317 temp_result
= get_status(path
->dfree_inodes_percent
, path
->freeinodes_percent
);
318 if (verbose
>=3) printf("Freeinodes_percent result=%d\n", temp_result
);
319 disk_result
= max_state( disk_result
, temp_result
);
321 result
= max_state(result
, disk_result
);
323 /* What a mess of units. The output shows free space, the perf data shows used space. Yikes!
324 Hack here. Trying to get warn/crit levels from freespace_(units|percent) for perf
325 data. Assumption that start=0. Roll on new syntax...
328 /* *_high_tide must be reinitialized at each run */
329 warning_high_tide
= UINT_MAX
;
330 critical_high_tide
= UINT_MAX
;
332 if (path
->freespace_units
->warning
!= NULL
) {
333 warning_high_tide
= path
->dtotal_units
- path
->freespace_units
->warning
->end
;
335 if (path
->freespace_percent
->warning
!= NULL
) {
336 warning_high_tide
= abs( min( (double) warning_high_tide
, (double) (1.0 - path
->freespace_percent
->warning
->end
/100)*path
->dtotal_units
));
338 if (path
->freespace_units
->critical
!= NULL
) {
339 critical_high_tide
= path
->dtotal_units
- path
->freespace_units
->critical
->end
;
341 if (path
->freespace_percent
->critical
!= NULL
) {
342 critical_high_tide
= abs( min( (double) critical_high_tide
, (double) (1.0 - path
->freespace_percent
->critical
->end
/100)*path
->dtotal_units
));
345 /* Nb: *_high_tide are unset when == UINT_MAX */
346 xasprintf (&perf
, "%s %s", perf
,
347 perfdata ((!strcmp(me
->me_mountdir
, "none") || display_mntp
) ? me
->me_devname
: me
->me_mountdir
,
348 path
->dused_units
, units
,
349 (warning_high_tide
!= UINT_MAX
? TRUE
: FALSE
), warning_high_tide
,
350 (critical_high_tide
!= UINT_MAX
? TRUE
: FALSE
), critical_high_tide
,
352 TRUE
, path
->dtotal_units
));
354 if (display_inodes_perfdata
) {
355 /* *_high_tide must be reinitialized at each run */
356 warning_high_tide
= UINT_MAX
;
357 critical_high_tide
= UINT_MAX
;
359 if (path
->freeinodes_percent
->warning
!= NULL
) {
360 warning_high_tide
= abs( min( (double) warning_high_tide
, (double) (1.0 - path
->freeinodes_percent
->warning
->end
/100)*path
->inodes_total
));
362 if (path
->freeinodes_percent
->critical
!= NULL
) {
363 critical_high_tide
= abs( min( (double) critical_high_tide
, (double) (1.0 - path
->freeinodes_percent
->critical
->end
/100)*path
->inodes_total
));
366 xasprintf (&perf_ilabel
, "%s (inodes)", (!strcmp(me
->me_mountdir
, "none") || display_mntp
) ? me
->me_devname
: me
->me_mountdir
);
367 /* Nb: *_high_tide are unset when == UINT_MAX */
368 xasprintf (&perf
, "%s %s", perf
,
369 perfdata (perf_ilabel
,
370 path
->inodes_used
, "",
371 (warning_high_tide
!= UINT_MAX
? TRUE
: FALSE
), warning_high_tide
,
372 (critical_high_tide
!= UINT_MAX
? TRUE
: FALSE
), critical_high_tide
,
374 TRUE
, path
->inodes_total
));
377 if (disk_result
==STATE_OK
&& erronly
&& !verbose
)
380 if(disk_result
&& verbose
>= 1) {
381 xasprintf(&flag_header
, " %s [", state_text (disk_result
));
383 xasprintf(&flag_header
, "");
385 xasprintf (&output
, "%s%s %s %.0f %s (%.0f%%",
387 (!strcmp(me
->me_mountdir
, "none") || display_mntp
) ? me
->me_devname
: me
->me_mountdir
,
391 if (path
->dused_inodes_percent
< 0) {
392 xasprintf(&output
, "%s inode=-)%s;", output
, (disk_result
? "]" : ""));
394 xasprintf(&output
, "%s inode=%.0f%%)%s;", output
, path
->dfree_inodes_percent
, ((disk_result
&& verbose
>= 1) ? "]" : ""));
397 /* TODO: Need to do a similar debug line
398 xasprintf (&details, _("%s\n\
399 %.0f of %.0f %s (%.0f%% inode=%.0f%%) free on %s (type %s mounted on %s) warn:%lu crit:%lu warn%%:%.0f%% crit%%:%.0f%%"),
400 details, dfree_units, dtotal_units, units, dfree_pct, inode_space_pct,
401 me->me_devname, me->me_type, me->me_mountdir,
402 (unsigned long)w_df, (unsigned long)c_df, w_dfp, c_dfp);
410 xasprintf (&output
, "%s%s", output
, details
);
413 printf ("DISK %s%s%s|%s\n", state_text (result
), (erronly
&& result
==STATE_OK
) ? "" : preamble
, output
, perf
);
418 double calculate_percent(uintmax_t value
, uintmax_t total
) {
420 /* I don't understand the below, but it is taken from coreutils' df */
421 /* Seems to be calculating pct, in the best possible way */
422 if (value
<= TYPE_MAXIMUM(uintmax_t) / 100
424 uintmax_t u100
= value
* 100;
425 pct
= u100
/ total
+ (u100
% total
!= 0);
427 /* Possible rounding errors - see coreutils' df for more explanation */
431 long int lipct
= pct
= u
* 100 / t
;
434 /* Like 'pct = ceil (dpct);', but without ceil - from coreutils again */
435 if (ipct
- 1 < pct
&& pct
<= ipct
+ 1)
436 pct
= ipct
+ (ipct
< pct
);
442 /* process command-line arguments */
444 process_arguments (int argc
, char **argv
)
447 struct parameter_list
*se
;
448 struct parameter_list
*temp_list
= NULL
, *previous
= NULL
;
449 struct mount_entry
*me
;
451 int cflags
= REG_NOSUB
| REG_EXTENDED
;
452 int default_cflags
= cflags
;
453 char errbuf
[MAX_INPUT_BUFFER
];
457 static struct option longopts
[] = {
458 {"timeout", required_argument
, 0, 't'},
459 {"warning", required_argument
, 0, 'w'},
460 {"critical", required_argument
, 0, 'c'},
461 {"iwarning", required_argument
, 0, 'W'},
462 /* Dang, -C is taken. We might want to reshuffle this. */
463 {"icritical", required_argument
, 0, 'K'},
464 {"kilobytes", no_argument
, 0, 'k'},
465 {"megabytes", no_argument
, 0, 'm'},
466 {"units", required_argument
, 0, 'u'},
467 {"path", required_argument
, 0, 'p'},
468 {"partition", required_argument
, 0, 'p'},
469 {"exclude_device", required_argument
, 0, 'x'},
470 {"exclude-type", required_argument
, 0, 'X'},
471 {"include-type", required_argument
, 0, 'N'},
472 {"group", required_argument
, 0, 'g'},
473 {"eregi-path", required_argument
, 0, 'R'},
474 {"eregi-partition", required_argument
, 0, 'R'},
475 {"ereg-path", required_argument
, 0, 'r'},
476 {"ereg-partition", required_argument
, 0, 'r'},
477 {"freespace-ignore-reserved", no_argument
, 0, 'f'},
478 {"ignore-ereg-path", required_argument
, 0, 'i'},
479 {"ignore-ereg-partition", required_argument
, 0, 'i'},
480 {"ignore-eregi-path", required_argument
, 0, 'I'},
481 {"ignore-eregi-partition", required_argument
, 0, 'I'},
482 {"local", no_argument
, 0, 'l'},
483 {"stat-remote-fs", no_argument
, 0, 'L'},
484 {"iperfdata", no_argument
, 0, 'P'},
485 {"mountpoint", no_argument
, 0, 'M'},
486 {"errors-only", no_argument
, 0, 'e'},
487 {"exact-match", no_argument
, 0, 'E'},
488 {"all", no_argument
, 0, 'A'},
489 {"verbose", no_argument
, 0, 'v'},
490 {"quiet", no_argument
, 0, 'q'},
491 {"clear", no_argument
, 0, 'C'},
492 {"version", no_argument
, 0, 'V'},
493 {"help", no_argument
, 0, 'h'},
500 np_add_name(&fs_exclude_list
, "iso9660");
502 for (c
= 1; c
< argc
; c
++)
503 if (strcmp ("-to", argv
[c
]) == 0)
504 strcpy (argv
[c
], "-t");
507 c
= getopt_long (argc
, argv
, "+?VqhvefCt:c:w:K:W:u:p:x:X:N:mklLPg:R:r:i:I:MEA", longopts
, &option
);
509 if (c
== -1 || c
== EOF
)
513 case 't': /* timeout period */
514 if (is_integer (optarg
)) {
515 timeout_interval
= atoi (optarg
);
519 usage2 (_("Timeout interval must be a positive integer"), optarg
);
522 /* See comments for 'c' */
523 case 'w': /* warning threshold */
524 if (strstr(optarg
, "%")) {
525 if (*optarg
== '@') {
526 warn_freespace_percent
= optarg
;
528 xasprintf(&warn_freespace_percent
, "@%s", optarg
);
531 if (*optarg
== '@') {
532 warn_freespace_units
= optarg
;
534 xasprintf(&warn_freespace_units
, "@%s", optarg
);
539 /* Awful mistake where the range values do not make sense. Normally,
540 you alert if the value is within the range, but since we are using
541 freespace, we have to alert if outside the range. Thus we artifically
542 force @ at the beginning of the range, so that it is backwards compatible
544 case 'c': /* critical threshold */
545 if (strstr(optarg
, "%")) {
546 if (*optarg
== '@') {
547 crit_freespace_percent
= optarg
;
549 xasprintf(&crit_freespace_percent
, "@%s", optarg
);
552 if (*optarg
== '@') {
553 crit_freespace_units
= optarg
;
555 xasprintf(&crit_freespace_units
, "@%s", optarg
);
560 case 'W': /* warning inode threshold */
561 if (*optarg
== '@') {
562 warn_freeinodes_percent
= optarg
;
564 xasprintf(&warn_freeinodes_percent
, "@%s", optarg
);
567 case 'K': /* critical inode threshold */
568 if (*optarg
== '@') {
569 crit_freeinodes_percent
= optarg
;
571 xasprintf(&crit_freeinodes_percent
, "@%s", optarg
);
577 if (! strcmp (optarg
, "bytes")) {
579 units
= strdup ("B");
580 } else if (! strcmp (optarg
, "kB")) {
581 mult
= (uintmax_t)1024;
582 units
= strdup ("kB");
583 } else if (! strcmp (optarg
, "MB")) {
584 mult
= (uintmax_t)1024 * 1024;
585 units
= strdup ("MB");
586 } else if (! strcmp (optarg
, "GB")) {
587 mult
= (uintmax_t)1024 * 1024 * 1024;
588 units
= strdup ("GB");
589 } else if (! strcmp (optarg
, "TB")) {
590 mult
= (uintmax_t)1024 * 1024 * 1024 * 1024;
591 units
= strdup ("TB");
593 die (STATE_UNKNOWN
, _("unit type %s not known\n"), optarg
);
596 die (STATE_UNKNOWN
, _("failed allocating storage for '%s'\n"), "units");
598 case 'k': /* display mountpoint */
602 units
= strdup ("kB");
604 case 'm': /* display mountpoint */
608 units
= strdup ("MB");
617 display_inodes_perfdata
= 1;
619 case 'p': /* select path */
620 if (! (warn_freespace_units
|| crit_freespace_units
|| warn_freespace_percent
||
621 crit_freespace_percent
|| warn_usedspace_units
|| crit_usedspace_units
||
622 warn_usedspace_percent
|| crit_usedspace_percent
|| warn_usedinodes_percent
||
623 crit_usedinodes_percent
|| warn_freeinodes_percent
|| crit_freeinodes_percent
)) {
624 die (STATE_UNKNOWN
, "DISK %s: %s", _("UNKNOWN"), _("Must set a threshold value before using -p\n"));
627 /* add parameter if not found. overwrite thresholds if path has already been added */
628 if (! (se
= np_find_parameter(path_select_list
, optarg
))) {
629 se
= np_add_parameter(&path_select_list
, optarg
);
632 set_all_thresholds(se
);
634 /* With autofs, it is required to stat() the path before re-populating the mount_list */
636 /* NB: We can't free the old mount_list "just like that": both list pointers and struct
637 * pointers are copied around. One of the reason it wasn't done yet is that other parts
638 * of check_disk need the same kind of cleanup so it'd better be done as a whole */
639 mount_list
= read_file_system_list (0);
640 np_set_best_match(se
, mount_list
, exact_match
);
642 path_selected
= TRUE
;
644 case 'x': /* exclude path or partition */
645 np_add_name(&dp_exclude_list
, optarg
);
647 case 'X': /* exclude file system type */
648 np_add_name(&fs_exclude_list
, optarg
);
650 case 'N': /* include file system type */
651 np_add_name(&fs_include_list
, optarg
);
653 case 'v': /* verbose */
656 case 'q': /* TODO: this function should eventually go away (removed 2007-09-20) */
657 /* verbose--; **replaced by line below**. -q was only a broken way of implementing -e */
665 die (STATE_UNKNOWN
, "DISK %s: %s", _("UNKNOWN"), _("Must set -E before selecting paths\n"));
669 freespace_ignore_reserved
= TRUE
;
673 die (STATE_UNKNOWN
, "DISK %s: %s", _("UNKNOWN"), _("Must set group value before selecting paths\n"));
680 die (STATE_UNKNOWN
, "DISK %s: %s\n", _("UNKNOWN"), _("Paths need to be selected before using -i/-I. Use -A to select all paths explicitly"));
681 err
= regcomp(&re
, optarg
, cflags
);
683 regerror (err
, &re
, errbuf
, MAX_INPUT_BUFFER
);
684 die (STATE_UNKNOWN
, "DISK %s: %s - %s\n",_("UNKNOWN"), _("Could not compile regular expression"), errbuf
);
687 temp_list
= path_select_list
;
691 if (temp_list
->best_match
) {
692 if (np_regex_match_mount_entry(temp_list
->best_match
, &re
)) {
695 printf("ignoring %s matching regex\n", temp_list
->name
);
697 temp_list
= np_del_parameter(temp_list
, previous
);
698 /* pointer to first element needs to be updated if first item gets deleted */
699 if (previous
== NULL
)
700 path_select_list
= temp_list
;
702 previous
= temp_list
;
703 temp_list
= temp_list
->name_next
;
706 previous
= temp_list
;
707 temp_list
= temp_list
->name_next
;
712 cflags
= default_cflags
;
716 optarg
= strdup(".*");
720 if (! (warn_freespace_units
|| crit_freespace_units
|| warn_freespace_percent
||
721 crit_freespace_percent
|| warn_usedspace_units
|| crit_usedspace_units
||
722 warn_usedspace_percent
|| crit_usedspace_percent
|| warn_usedinodes_percent
||
723 crit_usedinodes_percent
|| warn_freeinodes_percent
|| crit_freeinodes_percent
)) {
724 die (STATE_UNKNOWN
, "DISK %s: %s", _("UNKNOWN"), _("Must set a threshold value before using -r/-R\n"));
727 err
= regcomp(&re
, optarg
, cflags
);
729 regerror (err
, &re
, errbuf
, MAX_INPUT_BUFFER
);
730 die (STATE_UNKNOWN
, "DISK %s: %s - %s\n",_("UNKNOWN"), _("Could not compile regular expression"), errbuf
);
733 for (me
= mount_list
; me
; me
= me
->me_next
) {
734 if (np_regex_match_mount_entry(me
, &re
)) {
737 printf("%s %s matching expression %s\n", me
->me_devname
, me
->me_mountdir
, optarg
);
739 /* add parameter if not found. overwrite thresholds if path has already been added */
740 if (! (se
= np_find_parameter(path_select_list
, me
->me_mountdir
))) {
741 se
= np_add_parameter(&path_select_list
, me
->me_mountdir
);
744 set_all_thresholds(se
);
749 die (STATE_UNKNOWN
, "DISK %s: %s - %s\n",_("UNKNOWN"),
750 _("Regular expression did not match any path or disk"), optarg
);
753 path_selected
= TRUE
;
754 np_set_best_match(path_select_list
, mount_list
, exact_match
);
755 cflags
= default_cflags
;
758 case 'M': /* display mountpoint */
762 /* add all mount entries to path_select list if no partitions have been explicitly defined using -p */
763 if (path_selected
== FALSE
) {
764 struct parameter_list
*path
;
765 for (me
= mount_list
; me
; me
= me
->me_next
) {
766 if (! (path
= np_find_parameter(path_select_list
, me
->me_mountdir
)))
767 path
= np_add_parameter(&path_select_list
, me
->me_mountdir
);
768 path
->best_match
= me
;
770 set_all_thresholds(path
);
773 warn_freespace_units
= NULL
;
774 crit_freespace_units
= NULL
;
775 warn_usedspace_units
= NULL
;
776 crit_usedspace_units
= NULL
;
777 warn_freespace_percent
= NULL
;
778 crit_freespace_percent
= NULL
;
779 warn_usedspace_percent
= NULL
;
780 crit_usedspace_percent
= NULL
;
781 warn_usedinodes_percent
= NULL
;
782 crit_usedinodes_percent
= NULL
;
783 warn_freeinodes_percent
= NULL
;
784 crit_freeinodes_percent
= NULL
;
786 path_selected
= FALSE
;
789 case 'V': /* version */
790 print_revision (progname
, NP_VERSION
);
791 exit (STATE_UNKNOWN
);
794 exit (STATE_UNKNOWN
);
796 usage (_("Unknown argument"));
800 /* Support for "check_disk warn crit [fs]" with thresholds at used% level */
802 if (warn_usedspace_percent
== NULL
&& argc
> c
&& is_intnonneg (argv
[c
]))
803 warn_usedspace_percent
= argv
[c
++];
805 if (crit_usedspace_percent
== NULL
&& argc
> c
&& is_intnonneg (argv
[c
]))
806 crit_usedspace_percent
= argv
[c
++];
808 if (argc
> c
&& path
== NULL
) {
809 se
= np_add_parameter(&path_select_list
, strdup(argv
[c
++]));
810 path_selected
= TRUE
;
811 set_all_thresholds(se
);
815 units
= strdup ("MB");
816 mult
= (uintmax_t)1024 * 1024;
825 print_path (const char *mypath
)
830 printf (_(" for %s\n"), mypath
);
835 set_all_thresholds (struct parameter_list
*path
)
837 if (path
->freespace_units
!= NULL
) free(path
->freespace_units
);
838 set_thresholds(&path
->freespace_units
, warn_freespace_units
, crit_freespace_units
);
839 if (path
->freespace_percent
!= NULL
) free (path
->freespace_percent
);
840 set_thresholds(&path
->freespace_percent
, warn_freespace_percent
, crit_freespace_percent
);
841 if (path
->usedspace_units
!= NULL
) free (path
->usedspace_units
);
842 set_thresholds(&path
->usedspace_units
, warn_usedspace_units
, crit_usedspace_units
);
843 if (path
->usedspace_percent
!= NULL
) free (path
->usedspace_percent
);
844 set_thresholds(&path
->usedspace_percent
, warn_usedspace_percent
, crit_usedspace_percent
);
845 if (path
->usedinodes_percent
!= NULL
) free (path
->usedinodes_percent
);
846 set_thresholds(&path
->usedinodes_percent
, warn_usedinodes_percent
, crit_usedinodes_percent
);
847 if (path
->freeinodes_percent
!= NULL
) free (path
->freeinodes_percent
);
848 set_thresholds(&path
->freeinodes_percent
, warn_freeinodes_percent
, crit_freeinodes_percent
);
854 validate_arguments (uintmax_t w, uintmax_t c, double wp, double cp, double iwp, double icp, char *mypath)
856 if (w < 0 && c < 0 && wp < 0.0 && cp < 0.0) {
857 printf (_("INPUT ERROR: No thresholds specified"));
861 else if ((wp >= 0.0 || cp >= 0.0) &&
862 (wp < 0.0 || cp < 0.0 || wp > 100.0 || cp > 100.0 || cp > wp)) {
864 INPUT ERROR: C_DFP (%f) should be less than W_DFP (%.1f) and both should be between zero and 100 percent, inclusive"),
869 else if ((iwp >= 0.0 || icp >= 0.0) &&
870 (iwp < 0.0 || icp < 0.0 || iwp > 100.0 || icp > 100.0 || icp > iwp)) {
872 INPUT ERROR: C_IDFP (%f) should be less than W_IDFP (%.1f) and both should be between zero and 100 percent, inclusive"),
877 else if ((w > 0 || c > 0) && (w == 0 || c == 0 || c > w)) {
879 INPUT ERROR: C_DF (%lu) should be less than W_DF (%lu) and both should be greater than zero"),
880 (unsigned long)c, (unsigned long)w);
899 print_revision (progname
, NP_VERSION
);
901 printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
902 printf (COPYRIGHT
, copyright
, email
);
904 printf ("%s\n", _("This plugin checks the amount of used disk space on a mounted file system"));
905 printf ("%s\n", _("and generates an alert if free space is less than one of the threshold values"));
911 printf (UT_HELP_VRSN
);
912 printf (UT_EXTRA_OPTS
);
914 printf (" %s\n", "-w, --warning=INTEGER");
915 printf (" %s\n", _("Exit with WARNING status if less than INTEGER units of disk are free"));
916 printf (" %s\n", "-w, --warning=PERCENT%");
917 printf (" %s\n", _("Exit with WARNING status if less than PERCENT of disk space is free"));
918 printf (" %s\n", "-c, --critical=INTEGER");
919 printf (" %s\n", _("Exit with CRITICAL status if less than INTEGER units of disk are free"));
920 printf (" %s\n", "-c, --critical=PERCENT%");
921 printf (" %s\n", _("Exit with CRITICAL status if less than PERCENT of disk space is free"));
922 printf (" %s\n", "-W, --iwarning=PERCENT%");
923 printf (" %s\n", _("Exit with WARNING status if less than PERCENT of inode space is free"));
924 printf (" %s\n", "-K, --icritical=PERCENT%");
925 printf (" %s\n", _("Exit with CRITICAL status if less than PERCENT of inode space is free"));
926 printf (" %s\n", "-p, --path=PATH, --partition=PARTITION");
927 printf (" %s\n", _("Mount point or block device as emitted by the mount(8) command (may be repeated)"));
928 printf (" %s\n", "-x, --exclude_device=PATH <STRING>");
929 printf (" %s\n", _("Ignore device (only works if -p unspecified)"));
930 printf (" %s\n", "-C, --clear");
931 printf (" %s\n", _("Clear thresholds"));
932 printf (" %s\n", "-E, --exact-match");
933 printf (" %s\n", _("For paths or partitions specified with -p, only check for exact paths"));
934 printf (" %s\n", "-e, --errors-only");
935 printf (" %s\n", _("Display only devices/mountpoints with errors"));
936 printf (" %s\n", "-f, --freespace-ignore-reserved");
937 printf (" %s\n", _("Don't account root-reserved blocks into freespace in perfdata"));
938 printf (" %s\n", "-g, --group=NAME");
939 printf (" %s\n", _("Group paths. Thresholds apply to (free-)space of all partitions together"));
940 printf (" %s\n", "-k, --kilobytes");
941 printf (" %s\n", _("Same as '--units kB'"));
942 printf (" %s\n", "-l, --local");
943 printf (" %s\n", _("Only check local filesystems"));
944 printf (" %s\n", "-L, --stat-remote-fs");
945 printf (" %s\n", _("Only check local filesystems against thresholds. Yet call stat on remote filesystems"));
946 printf (" %s\n", _("to test if they are accessible (e.g. to detect Stale NFS Handles)"));
947 printf (" %s\n", "-M, --mountpoint");
948 printf (" %s\n", _("Display the mountpoint instead of the partition"));
949 printf (" %s\n", "-m, --megabytes");
950 printf (" %s\n", _("Same as '--units MB'"));
951 printf (" %s\n", "-A, --all");
952 printf (" %s\n", _("Explicitly select all paths. This is equivalent to -R '.*'"));
953 printf (" %s\n", "-R, --eregi-path=PATH, --eregi-partition=PARTITION");
954 printf (" %s\n", _("Case insensitive regular expression for path/partition (may be repeated)"));
955 printf (" %s\n", "-r, --ereg-path=PATH, --ereg-partition=PARTITION");
956 printf (" %s\n", _("Regular expression for path or partition (may be repeated)"));
957 printf (" %s\n", "-I, --ignore-eregi-path=PATH, --ignore-eregi-partition=PARTITION");
958 printf (" %s\n", _("Regular expression to ignore selected path/partition (case insensitive) (may be repeated)"));
959 printf (" %s\n", "-i, --ignore-ereg-path=PATH, --ignore-ereg-partition=PARTITION");
960 printf (" %s\n", _("Regular expression to ignore selected path or partition (may be repeated)"));
961 printf (UT_PLUG_TIMEOUT
, DEFAULT_SOCKET_TIMEOUT
);
962 printf (" %s\n", "-u, --units=STRING");
963 printf (" %s\n", _("Choose bytes, kB, MB, GB, TB (default: MB)"));
965 printf (" %s\n", "-X, --exclude-type=TYPE");
966 printf (" %s\n", _("Ignore all filesystems of indicated type (may be repeated)"));
967 printf (" %s\n", "-N, --include-type=TYPE");
968 printf (" %s\n", _("Check only filesystems of indicated type (may be repeated)"));
971 printf ("%s\n", _("Examples:"));
972 printf (" %s\n", "check_disk -w 10% -c 5% -p /tmp -p /var -C -w 100000 -c 50000 -p /");
973 printf (" %s\n", _("Checks /tmp and /var at 10% and 5%, and / at 100MB and 50MB"));
974 printf (" %s\n", "check_disk -w 100 -c 50 -C -w 1000 -c 500 -g sidDATA -r '^/oracle/SID/data.*$'");
975 printf (" %s\n", _("Checks all filesystems not matching -r at 100M and 50M. The fs matching the -r regex"));
976 printf (" %s\n", _("are grouped which means the freespace thresholds are applied to all disks together"));
977 printf (" %s\n", "check_disk -w 100 -c 50 -C -w 1000 -c 500 -p /foo -C -w 5% -c 3% -p /bar");
978 printf (" %s\n", _("Checks /foo for 1000M/500M and /bar for 5/3%. All remaining volumes use 100M/50M"));
988 printf ("%s\n", _("Usage:"));
989 printf (" %s -w limit -c limit [-W limit] [-K limit] {-p path | -x device}\n", progname
);
990 printf ("[-C] [-E] [-e] [-f] [-g group ] [-k] [-l] [-M] [-m] [-R path ] [-r path ]\n");
991 printf ("[-t timeout] [-u unit] [-v] [-X type] [-N type]\n");
995 stat_path (struct parameter_list
*p
)
997 /* Stat entry to check that dir exists and is accessible */
999 printf("calling stat on %s\n", p
->name
);
1000 if (stat (p
->name
, &stat_buf
[0])) {
1002 printf("stat failed on %s\n", p
->name
);
1003 printf("DISK %s - ", _("CRITICAL"));
1004 die (STATE_CRITICAL
, _("%s %s: %s\n"), p
->name
, _("is not accessible"), strerror(errno
));
1010 get_stats (struct parameter_list
*p
, struct fs_usage
*fsp
) {
1011 struct parameter_list
*p_list
;
1012 struct fs_usage tmpfsp
;
1015 if (p
->group
== NULL
) {
1016 get_path_stats(p
,fsp
);
1018 /* find all group members */
1019 for (p_list
= path_select_list
; p_list
; p_list
=p_list
->name_next
) {
1021 if (strncmp(p_list
->name
, "/cygdrive/", 10) != 0)
1024 if (p_list
->group
&& ! (strcmp(p_list
->group
, p
->group
))) {
1026 get_fs_usage (p_list
->best_match
->me_mountdir
, p_list
->best_match
->me_devname
, &tmpfsp
);
1027 get_path_stats(p_list
, &tmpfsp
);
1029 printf("Group %s: adding %llu blocks sized %llu, (%s) used_units=%g free_units=%g total_units=%g fsu_blocksize=%llu mult=%llu\n",
1030 p_list
->group
, tmpfsp
.fsu_bavail
, tmpfsp
.fsu_blocksize
, p_list
->best_match
->me_mountdir
, p_list
->dused_units
, p_list
->dfree_units
,
1031 p_list
->dtotal_units
, mult
);
1033 /* prevent counting the first FS of a group twice since its parameter_list entry
1034 * is used to carry the information of all file systems of the entire group */
1036 p
->total
+= p_list
->total
;
1037 p
->available
+= p_list
->available
;
1038 p
->available_to_root
+= p_list
->available_to_root
;
1039 p
->used
+= p_list
->used
;
1041 p
->dused_units
+= p_list
->dused_units
;
1042 p
->dfree_units
+= p_list
->dfree_units
;
1043 p
->dtotal_units
+= p_list
->dtotal_units
;
1044 p
->inodes_total
+= p_list
->inodes_total
;
1045 p
->inodes_free
+= p_list
->inodes_free
;
1046 p
->inodes_free_to_root
+= p_list
->inodes_free_to_root
;
1047 p
->inodes_used
+= p_list
->inodes_used
;
1052 printf("Group %s now has: used_units=%g free_units=%g total_units=%g fsu_blocksize=%llu mult=%llu\n",
1053 p
->group
, tmpfsp
.fsu_bavail
, tmpfsp
.fsu_blocksize
, p
->best_match
->me_mountdir
, p
->dused_units
,
1054 p
->dfree_units
, p
->dtotal_units
, mult
);
1056 /* modify devname and mountdir for output */
1057 p
->best_match
->me_mountdir
= p
->best_match
->me_devname
= p
->group
;
1059 /* finally calculate percentages for either plain FS or summed up group */
1060 p
->dused_pct
= calculate_percent( p
->used
, p
->used
+ p
->available
); /* used + available can never be > uintmax */
1061 p
->dfree_pct
= 100 - p
->dused_pct
;
1062 p
->dused_inodes_percent
= calculate_percent(p
->inodes_total
- p
->inodes_free
, p
->inodes_total
);
1063 p
->dfree_inodes_percent
= 100 - p
->dused_inodes_percent
;
1068 get_path_stats (struct parameter_list
*p
, struct fs_usage
*fsp
) {
1069 /* 2007-12-08 - Workaround for Gnulib reporting insanely high available
1070 * space on BSD (the actual value should be negative but fsp->fsu_bavail
1072 p
->available
= fsp
->fsu_bavail
> fsp
->fsu_bfree
? 0 : fsp
->fsu_bavail
;
1073 p
->available_to_root
= fsp
->fsu_bfree
;
1074 p
->used
= fsp
->fsu_blocks
- fsp
->fsu_bfree
;
1075 if (freespace_ignore_reserved
) {
1076 /* option activated : we substract the root-reserved space from the total */
1077 p
->total
= fsp
->fsu_blocks
- p
->available_to_root
+ p
->available
;
1079 /* default behaviour : take all the blocks into account */
1080 p
->total
= fsp
->fsu_blocks
;
1083 p
->dused_units
= p
->used
*fsp
->fsu_blocksize
/mult
;
1084 p
->dfree_units
= p
->available
*fsp
->fsu_blocksize
/mult
;
1085 p
->dtotal_units
= p
->total
*fsp
->fsu_blocksize
/mult
;
1086 /* Free file nodes. Not sure the workaround is required, but in case...*/
1087 p
->inodes_free
= fsp
->fsu_favail
> fsp
->fsu_ffree
? 0 : fsp
->fsu_favail
;
1088 p
->inodes_free_to_root
= fsp
->fsu_ffree
; /* Free file nodes for root. */
1089 p
->inodes_used
= fsp
->fsu_files
- fsp
->fsu_ffree
;
1090 if (freespace_ignore_reserved
) {
1091 /* option activated : we substract the root-reserved inodes from the total */
1092 /* not all OS report fsp->fsu_favail, only the ones with statvfs syscall */
1093 /* for others, fsp->fsu_ffree == fsp->fsu_favail */
1094 p
->inodes_total
= fsp
->fsu_files
- p
->inodes_free_to_root
+ p
->inodes_free
;
1096 /* default behaviour : take all the inodes into account */
1097 p
->inodes_total
= fsp
->fsu_files
;
1099 np_add_name(&seen
, p
->best_match
->me_mountdir
);