1 /*****************************************************************************
3 * Nagios check_disk plugin
6 * Copyright (c) 1999-2008 Nagios 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
= "nagiosplug-devel@lists.sourceforge.net";
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 */
56 /* If nonzero, show inode information. */
57 static int inode_format
= 1;
59 /* If nonzero, show even filesystems with zero size or
60 uninteresting types. */
61 static int show_all_fs
= 1;
63 /* If nonzero, show only local filesystems. */
64 static int show_local_fs
= 0;
66 /* If nonzero, show only local filesystems but call stat() on remote ones. */
67 static int stat_remote_fs
= 0;
69 /* If positive, the units to use when printing sizes;
70 if negative, the human-readable base. */
71 /* static int output_block_size; */
73 /* If nonzero, invoke the `sync' system call before getting any usage data.
74 Using this option can make df very slow, especially with many or very
75 busy disks. Note that this may make a difference on some systems --
76 SunOs4.1.3, for one. It is *not* necessary on Linux. */
77 /* static int require_sync = 0; */
79 /* Linked list of filesystem types to display.
80 If `fs_select_list' is NULL, list all types.
81 This table is generated dynamically from command-line options,
82 rather than hardcoding into the program what it thinks are the
83 valid filesystem types; let the user specify any filesystem type
84 they want to, and if there are any filesystems of that type, they
87 Some filesystem types:
88 4.2 4.3 ufs nfs swap ignore io vm efs dbg */
90 /* static struct parameter_list *fs_select_list; */
92 /* Linked list of filesystem types to omit.
93 If the list is empty, don't exclude any types. */
94 static struct name_list
*fs_exclude_list
;
96 /* Linked list of filesystem types to check.
97 If the list is empty, include all types. */
98 static struct name_list
*fs_include_list
;
100 static struct name_list
*dp_exclude_list
;
102 static struct parameter_list
*path_select_list
= NULL
;
104 /* Linked list of mounted filesystems. */
105 static struct mount_entry
*mount_list
;
107 /* For long options that have no equivalent short option, use a
108 non-character as a pseudo short option, starting with CHAR_MAX + 1. */
111 SYNC_OPTION
= CHAR_MAX
+ 1,
120 int process_arguments (int, char **);
121 void print_path (const char *mypath
);
122 void set_all_thresholds (struct parameter_list
*path
);
123 int validate_arguments (uintmax_t, uintmax_t, double, double, double, double, char *);
124 void print_help (void);
125 void print_usage (void);
126 double calculate_percent(uintmax_t, uintmax_t);
127 void stat_path (struct parameter_list
*p
);
128 void get_stats (struct parameter_list
*p
, struct fs_usage
*fsp
);
129 void get_path_stats (struct parameter_list
*p
, struct fs_usage
*fsp
);
134 char *exclude_device
;
136 uintmax_t mult
= 1024 * 1024;
139 int display_mntp
= FALSE
;
140 int exact_match
= FALSE
;
141 int freespace_ignore_reserved
= FALSE
;
142 char *warn_freespace_units
= NULL
;
143 char *crit_freespace_units
= NULL
;
144 char *warn_freespace_percent
= NULL
;
145 char *crit_freespace_percent
= NULL
;
146 char *warn_usedspace_units
= NULL
;
147 char *crit_usedspace_units
= NULL
;
148 char *warn_usedspace_percent
= NULL
;
149 char *crit_usedspace_percent
= NULL
;
150 char *warn_usedinodes_percent
= NULL
;
151 char *crit_usedinodes_percent
= NULL
;
152 char *warn_freeinodes_percent
= NULL
;
153 char *crit_freeinodes_percent
= NULL
;
154 int path_selected
= FALSE
;
156 struct stat
*stat_buf
;
157 struct name_list
*seen
= NULL
;
161 main (int argc
, char **argv
)
163 int result
= STATE_UNKNOWN
;
164 int disk_result
= STATE_UNKNOWN
;
169 double inode_space_pct
;
170 double warning_high_tide
;
171 double critical_high_tide
;
174 struct mount_entry
*me
;
175 struct fs_usage fsp
, tmpfsp
;
176 struct parameter_list
*temp_list
, *path
;
178 preamble
= strdup (" - free space:");
179 output
= strdup ("");
180 details
= strdup ("");
182 stat_buf
= malloc(sizeof *stat_buf
);
184 setlocale (LC_ALL
, "");
185 bindtextdomain (PACKAGE
, LOCALEDIR
);
186 textdomain (PACKAGE
);
188 mount_list
= read_file_system_list (0);
190 /* Parse extra opts if any */
191 argv
= np_extra_opts (&argc
, argv
, progname
);
193 if (process_arguments (argc
, argv
) == ERROR
)
194 usage4 (_("Could not parse arguments"));
196 /* If a list of paths has not been selected, find entire
197 mount list and create list of paths
199 if (path_selected
== FALSE
) {
200 for (me
= mount_list
; me
; me
= me
->me_next
) {
201 if (! (path
= np_find_parameter(path_select_list
, me
->me_mountdir
))) {
202 path
= np_add_parameter(&path_select_list
, me
->me_mountdir
);
204 path
->best_match
= me
;
206 set_all_thresholds(path
);
209 np_set_best_match(path_select_list
, mount_list
, exact_match
);
211 /* Error if no match found for specified paths */
212 temp_list
= path_select_list
;
215 if (! temp_list
->best_match
) {
216 die (STATE_CRITICAL
, _("DISK %s: %s not found\n"), _("CRITICAL"), temp_list
->name
);
219 temp_list
= temp_list
->name_next
;
222 /* Process for every path in list */
223 for (path
= path_select_list
; path
; path
=path
->name_next
) {
225 if (verbose
>= 3 && path
->freespace_percent
->warning
!= NULL
&& path
->freespace_percent
->critical
!= NULL
)
226 printf("Thresholds(pct) for %s warn: %f crit %f\n",path
->name
, path
->freespace_percent
->warning
->end
,
227 path
->freespace_percent
->critical
->end
);
229 if (verbose
>= 3 && path
->group
!= NULL
)
230 printf("Group of %s: %s\n",path
->name
,path
->group
);
232 /* reset disk result */
233 disk_result
= STATE_UNKNOWN
;
235 me
= path
->best_match
;
239 /* Remove filesystems already seen */
240 if (np_seen_name(seen
, me
->me_mountdir
)) {
243 np_add_name(&seen
, me
->me_mountdir
);
245 if (path
->group
== NULL
) {
246 /* Skip remote filesystems if we're not interested in them */
247 if (me
->me_remote
&& show_local_fs
) {
251 /* Skip pseudo fs's if we haven't asked for all fs's */
252 } else if (me
->me_dummy
&& !show_all_fs
) {
254 /* Skip excluded fstypes */
255 } else if (fs_exclude_list
&& np_find_name (fs_exclude_list
, me
->me_type
)) {
257 /* Skip excluded fs's */
258 } else if (dp_exclude_list
&&
259 (np_find_name (dp_exclude_list
, me
->me_devname
) ||
260 np_find_name (dp_exclude_list
, me
->me_mountdir
))) {
262 /* Skip not included fstypes */
263 } else if (fs_include_list
&& !np_find_name (fs_include_list
, me
->me_type
)) {
269 get_fs_usage (me
->me_mountdir
, me
->me_devname
, &fsp
);
271 if (fsp
.fsu_blocks
&& strcmp ("none", me
->me_mountdir
)) {
272 get_stats (path
, &fsp
);
275 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",
276 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
);
279 /* Threshold comparisons */
281 temp_result
= get_status(path
->dfree_units
, path
->freespace_units
);
282 if (verbose
>=3) printf("Freespace_units result=%d\n", temp_result
);
283 disk_result
= max_state( disk_result
, temp_result
);
285 temp_result
= get_status(path
->dfree_pct
, path
->freespace_percent
);
286 if (verbose
>=3) printf("Freespace%% result=%d\n", temp_result
);
287 disk_result
= max_state( disk_result
, temp_result
);
289 temp_result
= get_status(path
->dused_units
, path
->usedspace_units
);
290 if (verbose
>=3) printf("Usedspace_units result=%d\n", temp_result
);
291 disk_result
= max_state( disk_result
, temp_result
);
293 temp_result
= get_status(path
->dused_pct
, path
->usedspace_percent
);
294 if (verbose
>=3) printf("Usedspace_percent result=%d\n", temp_result
);
295 disk_result
= max_state( disk_result
, temp_result
);
297 temp_result
= get_status(path
->dused_inodes_percent
, path
->usedinodes_percent
);
298 if (verbose
>=3) printf("Usedinodes_percent result=%d\n", temp_result
);
299 disk_result
= max_state( disk_result
, temp_result
);
301 temp_result
= get_status(path
->dfree_inodes_percent
, path
->freeinodes_percent
);
302 if (verbose
>=3) printf("Freeinodes_percent result=%d\n", temp_result
);
303 disk_result
= max_state( disk_result
, temp_result
);
305 result
= max_state(result
, disk_result
);
307 /* What a mess of units. The output shows free space, the perf data shows used space. Yikes!
308 Hack here. Trying to get warn/crit levels from freespace_(units|percent) for perf
309 data. Assumption that start=0. Roll on new syntax...
312 /* *_high_tide must be reinitialized at each run */
313 warning_high_tide
= UINT_MAX
;
314 critical_high_tide
= UINT_MAX
;
316 if (path
->freespace_units
->warning
!= NULL
) {
317 warning_high_tide
= path
->dtotal_units
- path
->freespace_units
->warning
->end
;
319 if (path
->freespace_percent
->warning
!= NULL
) {
320 warning_high_tide
= abs( min( (double) warning_high_tide
, (double) (1.0 - path
->freespace_percent
->warning
->end
/100)*path
->dtotal_units
));
322 if (path
->freespace_units
->critical
!= NULL
) {
323 critical_high_tide
= path
->dtotal_units
- path
->freespace_units
->critical
->end
;
325 if (path
->freespace_percent
->critical
!= NULL
) {
326 critical_high_tide
= abs( min( (double) critical_high_tide
, (double) (1.0 - path
->freespace_percent
->critical
->end
/100)*path
->dtotal_units
));
329 /* Nb: *_high_tide are unset when == UINT_MAX */
330 xasprintf (&perf
, "%s %s", perf
,
331 perfdata ((!strcmp(me
->me_mountdir
, "none") || display_mntp
) ? me
->me_devname
: me
->me_mountdir
,
332 path
->dused_units
, units
,
333 (warning_high_tide
!= UINT_MAX
? TRUE
: FALSE
), warning_high_tide
,
334 (critical_high_tide
!= UINT_MAX
? TRUE
: FALSE
), critical_high_tide
,
336 TRUE
, path
->dtotal_units
));
338 if (disk_result
==STATE_OK
&& erronly
&& !verbose
)
341 xasprintf (&output
, "%s %s %.0f %s (%.0f%%",
343 (!strcmp(me
->me_mountdir
, "none") || display_mntp
) ? me
->me_devname
: me
->me_mountdir
,
347 if (path
->dused_inodes_percent
< 0) {
348 xasprintf(&output
, "%s inode=-);", output
);
350 xasprintf(&output
, "%s inode=%.0f%%);", output
, path
->dfree_inodes_percent
);
353 /* TODO: Need to do a similar debug line
354 xasprintf (&details, _("%s\n\
355 %.0f of %.0f %s (%.0f%% inode=%.0f%%) free on %s (type %s mounted on %s) warn:%lu crit:%lu warn%%:%.0f%% crit%%:%.0f%%"),
356 details, dfree_units, dtotal_units, units, dfree_pct, inode_space_pct,
357 me->me_devname, me->me_type, me->me_mountdir,
358 (unsigned long)w_df, (unsigned long)c_df, w_dfp, c_dfp);
366 xasprintf (&output
, "%s%s", output
, details
);
369 printf ("DISK %s%s%s|%s\n", state_text (result
), (erronly
&& result
==STATE_OK
) ? "" : preamble
, output
, perf
);
374 double calculate_percent(uintmax_t value
, uintmax_t total
) {
376 /* I don't understand the below, but it is taken from coreutils' df */
377 /* Seems to be calculating pct, in the best possible way */
378 if (value
<= TYPE_MAXIMUM(uintmax_t) / 100
380 uintmax_t u100
= value
* 100;
381 pct
= u100
/ total
+ (u100
% total
!= 0);
383 /* Possible rounding errors - see coreutils' df for more explanation */
387 long int lipct
= pct
= u
* 100 / t
;
390 /* Like 'pct = ceil (dpct);', but without ceil - from coreutils again */
391 if (ipct
- 1 < pct
&& pct
<= ipct
+ 1)
392 pct
= ipct
+ (ipct
< pct
);
398 /* process command-line arguments */
400 process_arguments (int argc
, char **argv
)
403 struct parameter_list
*se
;
404 struct parameter_list
*temp_list
= NULL
, *previous
= NULL
;
405 struct parameter_list
*temp_path_select_list
= NULL
;
406 struct mount_entry
*me
, *temp_me
;
409 int cflags
= REG_NOSUB
| REG_EXTENDED
;
410 int default_cflags
= cflags
;
411 char errbuf
[MAX_INPUT_BUFFER
];
415 static struct option longopts
[] = {
416 {"timeout", required_argument
, 0, 't'},
417 {"warning", required_argument
, 0, 'w'},
418 {"critical", required_argument
, 0, 'c'},
419 {"iwarning", required_argument
, 0, 'W'},
420 /* Dang, -C is taken. We might want to reshuffle this. */
421 {"icritical", required_argument
, 0, 'K'},
422 {"kilobytes", no_argument
, 0, 'k'},
423 {"megabytes", no_argument
, 0, 'm'},
424 {"units", required_argument
, 0, 'u'},
425 {"path", required_argument
, 0, 'p'},
426 {"partition", required_argument
, 0, 'p'},
427 {"exclude_device", required_argument
, 0, 'x'},
428 {"exclude-type", required_argument
, 0, 'X'},
429 {"include-type", required_argument
, 0, 'N'},
430 {"group", required_argument
, 0, 'g'},
431 {"eregi-path", required_argument
, 0, 'R'},
432 {"eregi-partition", required_argument
, 0, 'R'},
433 {"ereg-path", required_argument
, 0, 'r'},
434 {"ereg-partition", required_argument
, 0, 'r'},
435 {"freespace-ignore-reserved", no_argument
, 0, 'f'},
436 {"ignore-ereg-path", required_argument
, 0, 'i'},
437 {"ignore-ereg-partition", required_argument
, 0, 'i'},
438 {"ignore-eregi-path", required_argument
, 0, 'I'},
439 {"ignore-eregi-partition", required_argument
, 0, 'I'},
440 {"local", no_argument
, 0, 'l'},
441 {"stat-remote-fs", no_argument
, 0, 'L'},
442 {"mountpoint", no_argument
, 0, 'M'},
443 {"errors-only", no_argument
, 0, 'e'},
444 {"exact-match", no_argument
, 0, 'E'},
445 {"all", no_argument
, 0, 'A'},
446 {"verbose", no_argument
, 0, 'v'},
447 {"quiet", no_argument
, 0, 'q'},
448 {"clear", no_argument
, 0, 'C'},
449 {"version", no_argument
, 0, 'V'},
450 {"help", no_argument
, 0, 'h'},
457 np_add_name(&fs_exclude_list
, "iso9660");
459 for (c
= 1; c
< argc
; c
++)
460 if (strcmp ("-to", argv
[c
]) == 0)
461 strcpy (argv
[c
], "-t");
464 c
= getopt_long (argc
, argv
, "+?VqhvefCt:c:w:K:W:u:p:x:X:N:mklLg:R:r:i:I:MEA", longopts
, &option
);
466 if (c
== -1 || c
== EOF
)
470 case 't': /* timeout period */
471 if (is_integer (optarg
)) {
472 timeout_interval
= atoi (optarg
);
476 usage2 (_("Timeout interval must be a positive integer"), optarg
);
479 /* See comments for 'c' */
480 case 'w': /* warning threshold */
481 if (strstr(optarg
, "%")) {
482 if (*optarg
== '@') {
483 warn_freespace_percent
= optarg
;
485 xasprintf(&warn_freespace_percent
, "@%s", optarg
);
488 if (*optarg
== '@') {
489 warn_freespace_units
= optarg
;
491 xasprintf(&warn_freespace_units
, "@%s", optarg
);
496 /* Awful mistake where the range values do not make sense. Normally,
497 you alert if the value is within the range, but since we are using
498 freespace, we have to alert if outside the range. Thus we artifically
499 force @ at the beginning of the range, so that it is backwards compatible
501 case 'c': /* critical threshold */
502 if (strstr(optarg
, "%")) {
503 if (*optarg
== '@') {
504 crit_freespace_percent
= optarg
;
506 xasprintf(&crit_freespace_percent
, "@%s", optarg
);
509 if (*optarg
== '@') {
510 crit_freespace_units
= optarg
;
512 xasprintf(&crit_freespace_units
, "@%s", optarg
);
517 case 'W': /* warning inode threshold */
518 if (*optarg
== '@') {
519 warn_freeinodes_percent
= optarg
;
521 xasprintf(&warn_freeinodes_percent
, "@%s", optarg
);
524 case 'K': /* critical inode threshold */
525 if (*optarg
== '@') {
526 crit_freeinodes_percent
= optarg
;
528 xasprintf(&crit_freeinodes_percent
, "@%s", optarg
);
534 if (! strcmp (optarg
, "bytes")) {
536 units
= strdup ("B");
537 } else if (! strcmp (optarg
, "kB")) {
538 mult
= (uintmax_t)1024;
539 units
= strdup ("kB");
540 } else if (! strcmp (optarg
, "MB")) {
541 mult
= (uintmax_t)1024 * 1024;
542 units
= strdup ("MB");
543 } else if (! strcmp (optarg
, "GB")) {
544 mult
= (uintmax_t)1024 * 1024 * 1024;
545 units
= strdup ("GB");
546 } else if (! strcmp (optarg
, "TB")) {
547 mult
= (uintmax_t)1024 * 1024 * 1024 * 1024;
548 units
= strdup ("TB");
550 die (STATE_UNKNOWN
, _("unit type %s not known\n"), optarg
);
553 die (STATE_UNKNOWN
, _("failed allocating storage for '%s'\n"), "units");
555 case 'k': /* display mountpoint */
559 units
= strdup ("kB");
561 case 'm': /* display mountpoint */
565 units
= strdup ("MB");
572 case 'p': /* select path */
573 if (! (warn_freespace_units
|| crit_freespace_units
|| warn_freespace_percent
||
574 crit_freespace_percent
|| warn_usedspace_units
|| crit_usedspace_units
||
575 warn_usedspace_percent
|| crit_usedspace_percent
|| warn_usedinodes_percent
||
576 crit_usedinodes_percent
|| warn_freeinodes_percent
|| crit_freeinodes_percent
)) {
577 die (STATE_UNKNOWN
, "DISK %s: %s", _("UNKNOWN"), _("Must set a threshold value before using -p\n"));
580 /* add parameter if not found. overwrite thresholds if path has already been added */
581 if (! (se
= np_find_parameter(path_select_list
, optarg
))) {
582 se
= np_add_parameter(&path_select_list
, optarg
);
585 set_all_thresholds(se
);
587 /* With autofs, it is required to stat() the path before re-populating the mount_list */
589 /* NB: We can't free the old mount_list "just like that": both list pointers and struct
590 * pointers are copied around. One of the reason it wasn't done yet is that other parts
591 * of check_disk need the same kind of cleanup so it'd better be done as a whole */
592 mount_list
= read_file_system_list (0);
593 np_set_best_match(se
, mount_list
, exact_match
);
595 path_selected
= TRUE
;
597 case 'x': /* exclude path or partition */
598 np_add_name(&dp_exclude_list
, optarg
);
600 case 'X': /* exclude file system type */
601 np_add_name(&fs_exclude_list
, optarg
);
603 case 'N': /* include file system type */
604 np_add_name(&fs_include_list
, optarg
);
606 case 'v': /* verbose */
609 case 'q': /* TODO: this function should eventually go away (removed 2007-09-20) */
610 /* verbose--; **replaced by line below**. -q was only a broken way of implementing -e */
618 die (STATE_UNKNOWN
, "DISK %s: %s", _("UNKNOWN"), _("Must set -E before selecting paths\n"));
622 freespace_ignore_reserved
= TRUE
;
626 die (STATE_UNKNOWN
, "DISK %s: %s", _("UNKNOWN"), _("Must set group value before selecting paths\n"));
633 die (STATE_UNKNOWN
, "DISK %s: %s\n", _("UNKNOWN"), _("Paths need to be selected before using -i/-I. Use -A to select all paths explicitly"));
634 err
= regcomp(&re
, optarg
, cflags
);
636 regerror (err
, &re
, errbuf
, MAX_INPUT_BUFFER
);
637 die (STATE_UNKNOWN
, "DISK %s: %s - %s\n",_("UNKNOWN"), _("Could not compile regular expression"), errbuf
);
640 temp_list
= path_select_list
;
644 if (temp_list
->best_match
) {
645 if (np_regex_match_mount_entry(temp_list
->best_match
, &re
)) {
648 printf("ignoring %s matching regex\n", temp_list
->name
);
650 temp_list
= np_del_parameter(temp_list
, previous
);
651 /* pointer to first element needs to be updated if first item gets deleted */
652 if (previous
== NULL
)
653 path_select_list
= temp_list
;
655 previous
= temp_list
;
656 temp_list
= temp_list
->name_next
;
659 previous
= temp_list
;
660 temp_list
= temp_list
->name_next
;
665 cflags
= default_cflags
;
669 optarg
= strdup(".*");
673 if (! (warn_freespace_units
|| crit_freespace_units
|| warn_freespace_percent
||
674 crit_freespace_percent
|| warn_usedspace_units
|| crit_usedspace_units
||
675 warn_usedspace_percent
|| crit_usedspace_percent
|| warn_usedinodes_percent
||
676 crit_usedinodes_percent
|| warn_freeinodes_percent
|| crit_freeinodes_percent
)) {
677 die (STATE_UNKNOWN
, "DISK %s: %s", _("UNKNOWN"), _("Must set a threshold value before using -r/-R\n"));
680 err
= regcomp(&re
, optarg
, cflags
);
682 regerror (err
, &re
, errbuf
, MAX_INPUT_BUFFER
);
683 die (STATE_UNKNOWN
, "DISK %s: %s - %s\n",_("UNKNOWN"), _("Could not compile regular expression"), errbuf
);
686 for (me
= mount_list
; me
; me
= me
->me_next
) {
687 if (np_regex_match_mount_entry(me
, &re
)) {
690 printf("%s %s matching expression %s\n", me
->me_devname
, me
->me_mountdir
, optarg
);
692 /* add parameter if not found. overwrite thresholds if path has already been added */
693 if (! (se
= np_find_parameter(path_select_list
, me
->me_mountdir
))) {
694 se
= np_add_parameter(&path_select_list
, me
->me_mountdir
);
697 set_all_thresholds(se
);
702 die (STATE_UNKNOWN
, "DISK %s: %s - %s\n",_("UNKNOWN"),
703 _("Regular expression did not match any path or disk"), optarg
);
706 path_selected
= TRUE
;
707 np_set_best_match(path_select_list
, mount_list
, exact_match
);
708 cflags
= default_cflags
;
711 case 'M': /* display mountpoint */
715 /* add all mount entries to path_select list if no partitions have been explicitly defined using -p */
716 if (path_selected
== FALSE
) {
717 struct parameter_list
*path
;
718 for (me
= mount_list
; me
; me
= me
->me_next
) {
719 if (! (path
= np_find_parameter(path_select_list
, me
->me_mountdir
)))
720 path
= np_add_parameter(&path_select_list
, me
->me_mountdir
);
721 path
->best_match
= me
;
723 set_all_thresholds(path
);
726 warn_freespace_units
= NULL
;
727 crit_freespace_units
= NULL
;
728 warn_usedspace_units
= NULL
;
729 crit_usedspace_units
= NULL
;
730 warn_freespace_percent
= NULL
;
731 crit_freespace_percent
= NULL
;
732 warn_usedspace_percent
= NULL
;
733 crit_usedspace_percent
= NULL
;
734 warn_usedinodes_percent
= NULL
;
735 crit_usedinodes_percent
= NULL
;
736 warn_freeinodes_percent
= NULL
;
737 crit_freeinodes_percent
= NULL
;
739 path_selected
= FALSE
;
742 case 'V': /* version */
743 print_revision (progname
, NP_VERSION
);
749 usage (_("Unknown argument"));
753 /* Support for "check_disk warn crit [fs]" with thresholds at used% level */
755 if (warn_usedspace_percent
== NULL
&& argc
> c
&& is_intnonneg (argv
[c
]))
756 warn_usedspace_percent
= argv
[c
++];
758 if (crit_usedspace_percent
== NULL
&& argc
> c
&& is_intnonneg (argv
[c
]))
759 crit_usedspace_percent
= argv
[c
++];
761 if (argc
> c
&& path
== NULL
) {
762 se
= np_add_parameter(&path_select_list
, strdup(argv
[c
++]));
763 path_selected
= TRUE
;
764 set_all_thresholds(se
);
768 units
= strdup ("MB");
769 mult
= (uintmax_t)1024 * 1024;
778 print_path (const char *mypath
)
783 printf (_(" for %s\n"), mypath
);
788 set_all_thresholds (struct parameter_list
*path
)
790 if (path
->freespace_units
!= NULL
) free(path
->freespace_units
);
791 set_thresholds(&path
->freespace_units
, warn_freespace_units
, crit_freespace_units
);
792 if (path
->freespace_percent
!= NULL
) free (path
->freespace_percent
);
793 set_thresholds(&path
->freespace_percent
, warn_freespace_percent
, crit_freespace_percent
);
794 if (path
->usedspace_units
!= NULL
) free (path
->usedspace_units
);
795 set_thresholds(&path
->usedspace_units
, warn_usedspace_units
, crit_usedspace_units
);
796 if (path
->usedspace_percent
!= NULL
) free (path
->usedspace_percent
);
797 set_thresholds(&path
->usedspace_percent
, warn_usedspace_percent
, crit_usedspace_percent
);
798 if (path
->usedinodes_percent
!= NULL
) free (path
->usedinodes_percent
);
799 set_thresholds(&path
->usedinodes_percent
, warn_usedinodes_percent
, crit_usedinodes_percent
);
800 if (path
->freeinodes_percent
!= NULL
) free (path
->freeinodes_percent
);
801 set_thresholds(&path
->freeinodes_percent
, warn_freeinodes_percent
, crit_freeinodes_percent
);
807 validate_arguments (uintmax_t w, uintmax_t c, double wp, double cp, double iwp, double icp, char *mypath)
809 if (w < 0 && c < 0 && wp < 0.0 && cp < 0.0) {
810 printf (_("INPUT ERROR: No thresholds specified"));
814 else if ((wp >= 0.0 || cp >= 0.0) &&
815 (wp < 0.0 || cp < 0.0 || wp > 100.0 || cp > 100.0 || cp > wp)) {
817 INPUT ERROR: C_DFP (%f) should be less than W_DFP (%.1f) and both should be between zero and 100 percent, inclusive"),
822 else if ((iwp >= 0.0 || icp >= 0.0) &&
823 (iwp < 0.0 || icp < 0.0 || iwp > 100.0 || icp > 100.0 || icp > iwp)) {
825 INPUT ERROR: C_IDFP (%f) should be less than W_IDFP (%.1f) and both should be between zero and 100 percent, inclusive"),
830 else if ((w > 0 || c > 0) && (w == 0 || c == 0 || c > w)) {
832 INPUT ERROR: C_DF (%lu) should be less than W_DF (%lu) and both should be greater than zero"),
833 (unsigned long)c, (unsigned long)w);
852 print_revision (progname
, NP_VERSION
);
854 printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
855 printf (COPYRIGHT
, copyright
, email
);
857 printf ("%s\n", _("This plugin checks the amount of used disk space on a mounted file system"));
858 printf ("%s\n", _("and generates an alert if free space is less than one of the threshold values"));
864 printf (UT_HELP_VRSN
);
865 printf (UT_EXTRA_OPTS
);
867 printf (" %s\n", "-w, --warning=INTEGER");
868 printf (" %s\n", _("Exit with WARNING status if less than INTEGER units of disk are free"));
869 printf (" %s\n", "-w, --warning=PERCENT%");
870 printf (" %s\n", _("Exit with WARNING status if less than PERCENT of disk space is free"));
871 printf (" %s\n", "-c, --critical=INTEGER");
872 printf (" %s\n", _("Exit with CRITICAL status if less than INTEGER units of disk are free"));
873 printf (" %s\n", "-c, --critical=PERCENT%");
874 printf (" %s\n", _("Exit with CRITICAL status if less than PERCENT of disk space is free"));
875 printf (" %s\n", "-W, --iwarning=PERCENT%");
876 printf (" %s\n", _("Exit with WARNING status if less than PERCENT of inode space is free"));
877 printf (" %s\n", "-K, --icritical=PERCENT%");
878 printf (" %s\n", _("Exit with CRITICAL status if less than PERCENT of inode space is free"));
879 printf (" %s\n", "-p, --path=PATH, --partition=PARTITION");
880 printf (" %s\n", _("Path or partition (may be repeated)"));
881 printf (" %s\n", "-x, --exclude_device=PATH <STRING>");
882 printf (" %s\n", _("Ignore device (only works if -p unspecified)"));
883 printf (" %s\n", "-C, --clear");
884 printf (" %s\n", _("Clear thresholds"));
885 printf (" %s\n", "-E, --exact-match");
886 printf (" %s\n", _("For paths or partitions specified with -p, only check for exact paths"));
887 printf (" %s\n", "-e, --errors-only");
888 printf (" %s\n", _("Display only devices/mountpoints with errors"));
889 printf (" %s\n", "-f, --freespace-ignore-reserved");
890 printf (" %s\n", _("Don't account root-reserved blocks into freespace in perfdata"));
891 printf (" %s\n", "-g, --group=NAME");
892 printf (" %s\n", _("Group paths. Thresholds apply to (free-)space of all partitions together"));
893 printf (" %s\n", "-k, --kilobytes");
894 printf (" %s\n", _("Same as '--units kB'"));
895 printf (" %s\n", "-l, --local");
896 printf (" %s\n", _("Only check local filesystems"));
897 printf (" %s\n", "-L, --stat-remote-fs");
898 printf (" %s\n", _("Only check local filesystems against thresholds. Yet call stat on remote filesystems"));
899 printf (" %s\n", _("to test if they are accessible (e.g. to detect Stale NFS Handles)"));
900 printf (" %s\n", "-M, --mountpoint");
901 printf (" %s\n", _("Display the mountpoint instead of the partition"));
902 printf (" %s\n", "-m, --megabytes");
903 printf (" %s\n", _("Same as '--units MB'"));
904 printf (" %s\n", "-A, --all");
905 printf (" %s\n", _("Explicitly select all paths. This is equivalent to -R '.*'"));
906 printf (" %s\n", "-R, --eregi-path=PATH, --eregi-partition=PARTITION");
907 printf (" %s\n", _("Case insensitive regular expression for path/partition (may be repeated)"));
908 printf (" %s\n", "-r, --ereg-path=PATH, --ereg-partition=PARTITION");
909 printf (" %s\n", _("Regular expression for path or partition (may be repeated)"));
910 printf (" %s\n", "-I, --ignore-eregi-path=PATH, --ignore-eregi-partition=PARTITION");
911 printf (" %s\n", _("Regular expression to ignore selected path/partition (case insensitive) (may be repeated)"));
912 printf (" %s\n", "-i, --ignore-ereg-path=PATH, --ignore-ereg-partition=PARTITION");
913 printf (" %s\n", _("Regular expression to ignore selected path or partition (may be repeated)"));
914 printf (UT_TIMEOUT
, DEFAULT_SOCKET_TIMEOUT
);
915 printf (" %s\n", "-u, --units=STRING");
916 printf (" %s\n", _("Choose bytes, kB, MB, GB, TB (default: MB)"));
918 printf (" %s\n", "-X, --exclude-type=TYPE");
919 printf (" %s\n", _("Ignore all filesystems of indicated type (may be repeated)"));
920 printf (" %s\n", "-N, --include-type=TYPE");
921 printf (" %s\n", _("Check only filesystems of indicated type (may be repeated)"));
924 printf ("%s\n", _("Examples:"));
925 printf (" %s\n", "check_disk -w 10% -c 5% -p /tmp -p /var -C -w 100000 -c 50000 -p /");
926 printf (" %s\n", _("Checks /tmp and /var at 10% and 5%, and / at 100MB and 50MB"));
927 printf (" %s\n", "check_disk -w 100 -c 50 -C -w 1000 -c 500 -g sidDATA -r '^/oracle/SID/data.*$'");
928 printf (" %s\n", _("Checks all filesystems not matching -r at 100M and 50M. The fs matching the -r regex"));
929 printf (" %s\n", _("are grouped which means the freespace thresholds are applied to all disks together"));
930 printf (" %s\n", "check_disk -w 100 -c 50 -C -w 1000 -c 500 -p /foo -C -w 5% -c 3% -p /bar");
931 printf (" %s\n", _("Checks /foo for 1000M/500M and /bar for 5/3%. All remaining volumes use 100M/50M"));
941 printf ("%s\n", _("Usage:"));
942 printf (" %s -w limit -c limit [-W limit] [-K limit] {-p path | -x device}\n", progname
);
943 printf ("[-C] [-E] [-e] [-f] [-g group ] [-k] [-l] [-M] [-m] [-R path ] [-r path ]\n");
944 printf ("[-t timeout] [-u unit] [-v] [-X type] [-N type]\n");
948 stat_path (struct parameter_list
*p
)
950 /* Stat entry to check that dir exists and is accessible */
952 printf("calling stat on %s\n", p
->name
);
953 if (stat (p
->name
, &stat_buf
[0])) {
955 printf("stat failed on %s\n", p
->name
);
956 printf("DISK %s - ", _("CRITICAL"));
957 die (STATE_CRITICAL
, _("%s %s: %s\n"), p
->name
, _("is not accessible"), strerror(errno
));
963 get_stats (struct parameter_list
*p
, struct fs_usage
*fsp
) {
964 struct parameter_list
*p_list
;
965 struct fs_usage tmpfsp
;
968 if (p
->group
== NULL
) {
969 get_path_stats(p
,fsp
);
971 /* find all group members */
972 for (p_list
= path_select_list
; p_list
; p_list
=p_list
->name_next
) {
973 if (p_list
->group
&& ! (strcmp(p_list
->group
, p
->group
))) {
975 get_fs_usage (p_list
->best_match
->me_mountdir
, p_list
->best_match
->me_devname
, &tmpfsp
);
976 get_path_stats(p_list
, &tmpfsp
);
978 printf("Group %s: adding %llu blocks sized %llu, (%s) used_units=%g free_units=%g total_units=%g fsu_blocksize=%llu mult=%llu\n",
979 p_list
->group
, tmpfsp
.fsu_bavail
, tmpfsp
.fsu_blocksize
, p_list
->best_match
->me_mountdir
, p_list
->dused_units
, p_list
->dfree_units
,
980 p_list
->dtotal_units
, mult
);
982 /* prevent counting the first FS of a group twice since its parameter_list entry
983 * is used to carry the information of all file systems of the entire group */
985 p
->total
+= p_list
->total
;
986 p
->available
+= p_list
->available
;
987 p
->available_to_root
+= p_list
->available_to_root
;
988 p
->used
+= p_list
->used
;
990 p
->dused_units
+= p_list
->dused_units
;
991 p
->dfree_units
+= p_list
->dfree_units
;
992 p
->dtotal_units
+= p_list
->dtotal_units
;
993 p
->inodes_total
+= p_list
->inodes_total
;
994 p
->inodes_free
+= p_list
->inodes_free
;
999 printf("Group %s now has: used_units=%g free_units=%g total_units=%g fsu_blocksize=%llu mult=%llu\n",
1000 p
->group
, tmpfsp
.fsu_bavail
, tmpfsp
.fsu_blocksize
, p
->best_match
->me_mountdir
, p
->dused_units
,
1001 p
->dfree_units
, p
->dtotal_units
, mult
);
1003 /* modify devname and mountdir for output */
1004 p
->best_match
->me_mountdir
= p
->best_match
->me_devname
= p
->group
;
1006 /* finally calculate percentages for either plain FS or summed up group */
1007 p
->dused_pct
= calculate_percent( p
->used
, p
->used
+ p
->available
); /* used + available can never be > uintmax */
1008 p
->dfree_pct
= 100 - p
->dused_pct
;
1009 p
->dused_inodes_percent
= calculate_percent(p
->inodes_total
- p
->inodes_free
, p
->inodes_total
);
1010 p
->dfree_inodes_percent
= 100 - p
->dused_inodes_percent
;
1015 get_path_stats (struct parameter_list
*p
, struct fs_usage
*fsp
) {
1016 /* 2007-12-08 - Workaround for Gnulib reporting insanely high available
1017 * space on BSD (the actual value should be negative but fsp->fsu_bavail
1019 p
->available
= fsp
->fsu_bavail
> fsp
->fsu_bfree
? 0 : fsp
->fsu_bavail
;
1020 p
->available_to_root
= fsp
->fsu_bfree
;
1021 p
->used
= fsp
->fsu_blocks
- fsp
->fsu_bfree
;
1022 if (freespace_ignore_reserved
) {
1023 /* option activated : we substract the root-reserved space from the total */
1024 p
->total
= fsp
->fsu_blocks
- p
->available_to_root
+ p
->available
;
1026 /* default behaviour : take all the blocks into account */
1027 p
->total
= fsp
->fsu_blocks
;
1030 p
->dused_units
= p
->used
*fsp
->fsu_blocksize
/mult
;
1031 p
->dfree_units
= p
->available
*fsp
->fsu_blocksize
/mult
;
1032 p
->dtotal_units
= p
->total
*fsp
->fsu_blocksize
/mult
;
1033 p
->inodes_total
= fsp
->fsu_files
; /* Total file nodes. */
1034 p
->inodes_free
= fsp
->fsu_ffree
; /* Free file nodes. */
1035 np_add_name(&seen
, p
->best_match
->me_mountdir
);