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 char *warn_freespace_units
= NULL
;
142 char *crit_freespace_units
= NULL
;
143 char *warn_freespace_percent
= NULL
;
144 char *crit_freespace_percent
= NULL
;
145 char *warn_usedspace_units
= NULL
;
146 char *crit_usedspace_units
= NULL
;
147 char *warn_usedspace_percent
= NULL
;
148 char *crit_usedspace_percent
= NULL
;
149 char *warn_usedinodes_percent
= NULL
;
150 char *crit_usedinodes_percent
= NULL
;
151 char *warn_freeinodes_percent
= NULL
;
152 char *crit_freeinodes_percent
= NULL
;
153 int path_selected
= FALSE
;
155 struct stat
*stat_buf
;
156 struct name_list
*seen
= NULL
;
160 main (int argc
, char **argv
)
162 int result
= STATE_UNKNOWN
;
163 int disk_result
= STATE_UNKNOWN
;
168 double inode_space_pct
;
169 double warning_high_tide
;
170 double critical_high_tide
;
173 struct mount_entry
*me
;
174 struct fs_usage fsp
, tmpfsp
;
175 struct parameter_list
*temp_list
, *path
;
177 preamble
= strdup (" - free space:");
178 output
= strdup ("");
179 details
= strdup ("");
181 stat_buf
= malloc(sizeof *stat_buf
);
183 setlocale (LC_ALL
, "");
184 bindtextdomain (PACKAGE
, LOCALEDIR
);
185 textdomain (PACKAGE
);
187 mount_list
= read_file_system_list (0);
189 /* Parse extra opts if any */
190 argv
= np_extra_opts (&argc
, argv
, progname
);
192 if (process_arguments (argc
, argv
) == ERROR
)
193 usage4 (_("Could not parse arguments"));
195 /* If a list of paths has not been selected, find entire
196 mount list and create list of paths
198 if (path_selected
== FALSE
) {
199 for (me
= mount_list
; me
; me
= me
->me_next
) {
200 if (! (path
= np_find_parameter(path_select_list
, me
->me_mountdir
))) {
201 path
= np_add_parameter(&path_select_list
, me
->me_mountdir
);
203 path
->best_match
= me
;
205 set_all_thresholds(path
);
208 np_set_best_match(path_select_list
, mount_list
, exact_match
);
210 /* Error if no match found for specified paths */
211 temp_list
= path_select_list
;
214 if (! temp_list
->best_match
) {
215 die (STATE_CRITICAL
, _("DISK %s: %s not found\n"), _("CRITICAL"), temp_list
->name
);
218 temp_list
= temp_list
->name_next
;
221 /* Process for every path in list */
222 for (path
= path_select_list
; path
; path
=path
->name_next
) {
224 if (verbose
>= 3 && path
->freespace_percent
->warning
!= NULL
&& path
->freespace_percent
->critical
!= NULL
)
225 printf("Thresholds(pct) for %s warn: %f crit %f\n",path
->name
, path
->freespace_percent
->warning
->end
,
226 path
->freespace_percent
->critical
->end
);
228 if (verbose
>= 3 && path
->group
!= NULL
)
229 printf("Group of %s: %s\n",path
->name
,path
->group
);
231 /* reset disk result */
232 disk_result
= STATE_UNKNOWN
;
234 me
= path
->best_match
;
238 /* Remove filesystems already seen */
239 if (np_seen_name(seen
, me
->me_mountdir
)) {
242 np_add_name(&seen
, me
->me_mountdir
);
244 if (path
->group
== NULL
) {
245 /* Skip remote filesystems if we're not interested in them */
246 if (me
->me_remote
&& show_local_fs
) {
250 /* Skip pseudo fs's if we haven't asked for all fs's */
251 } else if (me
->me_dummy
&& !show_all_fs
) {
253 /* Skip excluded fstypes */
254 } else if (fs_exclude_list
&& np_find_name (fs_exclude_list
, me
->me_type
)) {
256 /* Skip excluded fs's */
257 } else if (dp_exclude_list
&&
258 (np_find_name (dp_exclude_list
, me
->me_devname
) ||
259 np_find_name (dp_exclude_list
, me
->me_mountdir
))) {
261 /* Skip not included fstypes */
262 } else if (fs_include_list
&& !np_find_name (fs_include_list
, me
->me_type
)) {
267 get_fs_usage (me
->me_mountdir
, me
->me_devname
, &fsp
);
270 if (fsp
.fsu_blocks
&& strcmp ("none", me
->me_mountdir
)) {
271 get_stats (path
, &fsp
);
274 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",
275 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
);
278 /* Threshold comparisons */
280 temp_result
= get_status(path
->dfree_units
, path
->freespace_units
);
281 if (verbose
>=3) printf("Freespace_units result=%d\n", temp_result
);
282 disk_result
= max_state( disk_result
, temp_result
);
284 temp_result
= get_status(path
->dfree_pct
, path
->freespace_percent
);
285 if (verbose
>=3) printf("Freespace%% result=%d\n", temp_result
);
286 disk_result
= max_state( disk_result
, temp_result
);
288 temp_result
= get_status(path
->dused_units
, path
->usedspace_units
);
289 if (verbose
>=3) printf("Usedspace_units result=%d\n", temp_result
);
290 disk_result
= max_state( disk_result
, temp_result
);
292 temp_result
= get_status(path
->dused_pct
, path
->usedspace_percent
);
293 if (verbose
>=3) printf("Usedspace_percent result=%d\n", temp_result
);
294 disk_result
= max_state( disk_result
, temp_result
);
296 temp_result
= get_status(path
->dused_inodes_percent
, path
->usedinodes_percent
);
297 if (verbose
>=3) printf("Usedinodes_percent result=%d\n", temp_result
);
298 disk_result
= max_state( disk_result
, temp_result
);
300 temp_result
= get_status(path
->dfree_inodes_percent
, path
->freeinodes_percent
);
301 if (verbose
>=3) printf("Freeinodes_percent result=%d\n", temp_result
);
302 disk_result
= max_state( disk_result
, temp_result
);
304 result
= max_state(result
, disk_result
);
306 /* What a mess of units. The output shows free space, the perf data shows used space. Yikes!
307 Hack here. Trying to get warn/crit levels from freespace_(units|percent) for perf
308 data. Assumption that start=0. Roll on new syntax...
311 /* *_high_tide must be reinitialized at each run */
312 warning_high_tide
= UINT_MAX
;
313 critical_high_tide
= UINT_MAX
;
315 if (path
->freespace_units
->warning
!= NULL
) {
316 warning_high_tide
= path
->dtotal_units
- path
->freespace_units
->warning
->end
;
318 if (path
->freespace_percent
->warning
!= NULL
) {
319 warning_high_tide
= abs( min( (double) warning_high_tide
, (double) (1.0 - path
->freespace_percent
->warning
->end
/100)*path
->dtotal_units
));
321 if (path
->freespace_units
->critical
!= NULL
) {
322 critical_high_tide
= path
->dtotal_units
- path
->freespace_units
->critical
->end
;
324 if (path
->freespace_percent
->critical
!= NULL
) {
325 critical_high_tide
= abs( min( (double) critical_high_tide
, (double) (1.0 - path
->freespace_percent
->critical
->end
/100)*path
->dtotal_units
));
328 /* Nb: *_high_tide are unset when == UINT_MAX */
329 xasprintf (&perf
, "%s %s", perf
,
330 perfdata ((!strcmp(me
->me_mountdir
, "none") || display_mntp
) ? me
->me_devname
: me
->me_mountdir
,
331 path
->dused_units
, units
,
332 (warning_high_tide
!= UINT_MAX
? TRUE
: FALSE
), warning_high_tide
,
333 (critical_high_tide
!= UINT_MAX
? TRUE
: FALSE
), critical_high_tide
,
335 TRUE
, path
->dtotal_units
));
337 if (disk_result
==STATE_OK
&& erronly
&& !verbose
)
340 xasprintf (&output
, "%s %s %.0f %s (%.0f%%",
342 (!strcmp(me
->me_mountdir
, "none") || display_mntp
) ? me
->me_devname
: me
->me_mountdir
,
346 if (path
->dused_inodes_percent
< 0) {
347 xasprintf(&output
, "%s inode=-);", output
);
349 xasprintf(&output
, "%s inode=%.0f%%);", output
, path
->dfree_inodes_percent
);
352 /* TODO: Need to do a similar debug line
353 xasprintf (&details, _("%s\n\
354 %.0f of %.0f %s (%.0f%% inode=%.0f%%) free on %s (type %s mounted on %s) warn:%lu crit:%lu warn%%:%.0f%% crit%%:%.0f%%"),
355 details, dfree_units, dtotal_units, units, dfree_pct, inode_space_pct,
356 me->me_devname, me->me_type, me->me_mountdir,
357 (unsigned long)w_df, (unsigned long)c_df, w_dfp, c_dfp);
365 xasprintf (&output
, "%s%s", output
, details
);
368 printf ("DISK %s%s%s|%s\n", state_text (result
), (erronly
&& result
==STATE_OK
) ? "" : preamble
, output
, perf
);
373 double calculate_percent(uintmax_t value
, uintmax_t total
) {
375 /* I don't understand the below, but it is taken from coreutils' df */
376 /* Seems to be calculating pct, in the best possible way */
377 if (value
<= TYPE_MAXIMUM(uintmax_t) / 100
379 uintmax_t u100
= value
* 100;
380 pct
= u100
/ total
+ (u100
% total
!= 0);
382 /* Possible rounding errors - see coreutils' df for more explanation */
386 long int lipct
= pct
= u
* 100 / t
;
389 /* Like 'pct = ceil (dpct);', but without ceil - from coreutils again */
390 if (ipct
- 1 < pct
&& pct
<= ipct
+ 1)
391 pct
= ipct
+ (ipct
< pct
);
397 /* process command-line arguments */
399 process_arguments (int argc
, char **argv
)
402 struct parameter_list
*se
;
403 struct parameter_list
*temp_list
= NULL
, *previous
= NULL
;
404 struct parameter_list
*temp_path_select_list
= NULL
;
405 struct mount_entry
*me
, *temp_me
;
408 int cflags
= REG_NOSUB
| REG_EXTENDED
;
409 int default_cflags
= cflags
;
410 char errbuf
[MAX_INPUT_BUFFER
];
414 static struct option longopts
[] = {
415 {"timeout", required_argument
, 0, 't'},
416 {"warning", required_argument
, 0, 'w'},
417 {"critical", required_argument
, 0, 'c'},
418 {"iwarning", required_argument
, 0, 'W'},
419 /* Dang, -C is taken. We might want to reshuffle this. */
420 {"icritical", required_argument
, 0, 'K'},
421 {"kilobytes", no_argument
, 0, 'k'},
422 {"megabytes", no_argument
, 0, 'm'},
423 {"units", required_argument
, 0, 'u'},
424 {"path", required_argument
, 0, 'p'},
425 {"partition", required_argument
, 0, 'p'},
426 {"exclude_device", required_argument
, 0, 'x'},
427 {"exclude-type", required_argument
, 0, 'X'},
428 {"include-type", required_argument
, 0, 'N'},
429 {"group", required_argument
, 0, 'g'},
430 {"eregi-path", required_argument
, 0, 'R'},
431 {"eregi-partition", required_argument
, 0, 'R'},
432 {"ereg-path", required_argument
, 0, 'r'},
433 {"ereg-partition", required_argument
, 0, 'r'},
434 {"ignore-ereg-path", required_argument
, 0, 'i'},
435 {"ignore-ereg-partition", required_argument
, 0, 'i'},
436 {"ignore-eregi-path", required_argument
, 0, 'I'},
437 {"ignore-eregi-partition", required_argument
, 0, 'I'},
438 {"local", no_argument
, 0, 'l'},
439 {"stat-remote-fs", no_argument
, 0, 'L'},
440 {"mountpoint", no_argument
, 0, 'M'},
441 {"errors-only", no_argument
, 0, 'e'},
442 {"exact-match", no_argument
, 0, 'E'},
443 {"all", no_argument
, 0, 'A'},
444 {"verbose", no_argument
, 0, 'v'},
445 {"quiet", no_argument
, 0, 'q'},
446 {"clear", no_argument
, 0, 'C'},
447 {"version", no_argument
, 0, 'V'},
448 {"help", no_argument
, 0, 'h'},
455 np_add_name(&fs_exclude_list
, "iso9660");
457 for (c
= 1; c
< argc
; c
++)
458 if (strcmp ("-to", argv
[c
]) == 0)
459 strcpy (argv
[c
], "-t");
462 c
= getopt_long (argc
, argv
, "+?VqhveCt:c:w:K:W:u:p:x:X:N:mklLg:R:r:i:I:MEA", longopts
, &option
);
464 if (c
== -1 || c
== EOF
)
468 case 't': /* timeout period */
469 if (is_integer (optarg
)) {
470 timeout_interval
= atoi (optarg
);
474 usage2 (_("Timeout interval must be a positive integer"), optarg
);
477 /* See comments for 'c' */
478 case 'w': /* warning threshold */
479 if (strstr(optarg
, "%")) {
480 if (*optarg
== '@') {
481 warn_freespace_percent
= optarg
;
483 xasprintf(&warn_freespace_percent
, "@%s", optarg
);
486 if (*optarg
== '@') {
487 warn_freespace_units
= optarg
;
489 xasprintf(&warn_freespace_units
, "@%s", optarg
);
494 /* Awful mistake where the range values do not make sense. Normally,
495 you alert if the value is within the range, but since we are using
496 freespace, we have to alert if outside the range. Thus we artifically
497 force @ at the beginning of the range, so that it is backwards compatible
499 case 'c': /* critical threshold */
500 if (strstr(optarg
, "%")) {
501 if (*optarg
== '@') {
502 crit_freespace_percent
= optarg
;
504 xasprintf(&crit_freespace_percent
, "@%s", optarg
);
507 if (*optarg
== '@') {
508 crit_freespace_units
= optarg
;
510 xasprintf(&crit_freespace_units
, "@%s", optarg
);
515 case 'W': /* warning inode threshold */
516 if (*optarg
== '@') {
517 warn_freeinodes_percent
= optarg
;
519 xasprintf(&warn_freeinodes_percent
, "@%s", optarg
);
522 case 'K': /* critical inode threshold */
523 if (*optarg
== '@') {
524 crit_freeinodes_percent
= optarg
;
526 xasprintf(&crit_freeinodes_percent
, "@%s", optarg
);
532 if (! strcmp (optarg
, "bytes")) {
534 units
= strdup ("B");
535 } else if (! strcmp (optarg
, "kB")) {
536 mult
= (uintmax_t)1024;
537 units
= strdup ("kB");
538 } else if (! strcmp (optarg
, "MB")) {
539 mult
= (uintmax_t)1024 * 1024;
540 units
= strdup ("MB");
541 } else if (! strcmp (optarg
, "GB")) {
542 mult
= (uintmax_t)1024 * 1024 * 1024;
543 units
= strdup ("GB");
544 } else if (! strcmp (optarg
, "TB")) {
545 mult
= (uintmax_t)1024 * 1024 * 1024 * 1024;
546 units
= strdup ("TB");
548 die (STATE_UNKNOWN
, _("unit type %s not known\n"), optarg
);
551 die (STATE_UNKNOWN
, _("failed allocating storage for '%s'\n"), "units");
553 case 'k': /* display mountpoint */
557 units
= strdup ("kB");
559 case 'm': /* display mountpoint */
563 units
= strdup ("MB");
570 case 'p': /* select path */
571 if (! (warn_freespace_units
|| crit_freespace_units
|| warn_freespace_percent
||
572 crit_freespace_percent
|| warn_usedspace_units
|| crit_usedspace_units
||
573 warn_usedspace_percent
|| crit_usedspace_percent
|| warn_usedinodes_percent
||
574 crit_usedinodes_percent
|| warn_freeinodes_percent
|| crit_freeinodes_percent
)) {
575 die (STATE_UNKNOWN
, "DISK %s: %s", _("UNKNOWN"), _("Must set a threshold value before using -p\n"));
578 /* add parameter if not found. overwrite thresholds if path has already been added */
579 if (! (se
= np_find_parameter(path_select_list
, optarg
))) {
580 se
= np_add_parameter(&path_select_list
, optarg
);
583 set_all_thresholds(se
);
585 /* With autofs, it is required to stat() the path before re-populating the mount_list */
587 /* NB: We can't free the old mount_list "just like that": both list pointers and struct
588 * pointers are copied around. One of the reason it wasn't done yet is that other parts
589 * of check_disk need the same kind of cleanup so it'd better be done as a whole */
590 mount_list
= read_file_system_list (0);
591 np_set_best_match(se
, mount_list
, exact_match
);
593 path_selected
= TRUE
;
595 case 'x': /* exclude path or partition */
596 np_add_name(&dp_exclude_list
, optarg
);
598 case 'X': /* exclude file system type */
599 np_add_name(&fs_exclude_list
, optarg
);
601 case 'N': /* include file system type */
602 np_add_name(&fs_include_list
, optarg
);
604 case 'v': /* verbose */
607 case 'q': /* TODO: this function should eventually go away (removed 2007-09-20) */
608 /* verbose--; **replaced by line below**. -q was only a broken way of implementing -e */
616 die (STATE_UNKNOWN
, "DISK %s: %s", _("UNKNOWN"), _("Must set -E before selecting paths\n"));
621 die (STATE_UNKNOWN
, "DISK %s: %s", _("UNKNOWN"), _("Must set group value before selecting paths\n"));
628 die (STATE_UNKNOWN
, "DISK %s: %s\n", _("UNKNOWN"), _("Paths need to be selected before using -i/-I. Use -A to select all paths explicitly"));
629 err
= regcomp(&re
, optarg
, cflags
);
631 regerror (err
, &re
, errbuf
, MAX_INPUT_BUFFER
);
632 die (STATE_UNKNOWN
, "DISK %s: %s - %s\n",_("UNKNOWN"), _("Could not compile regular expression"), errbuf
);
635 temp_list
= path_select_list
;
639 if (temp_list
->best_match
) {
640 if (np_regex_match_mount_entry(temp_list
->best_match
, &re
)) {
643 printf("ignoring %s matching regex\n", temp_list
->name
);
645 temp_list
= np_del_parameter(temp_list
, previous
);
646 /* pointer to first element needs to be updated if first item gets deleted */
647 if (previous
== NULL
)
648 path_select_list
= temp_list
;
650 previous
= temp_list
;
651 temp_list
= temp_list
->name_next
;
654 previous
= temp_list
;
655 temp_list
= temp_list
->name_next
;
660 cflags
= default_cflags
;
664 optarg
= strdup(".*");
668 if (! (warn_freespace_units
|| crit_freespace_units
|| warn_freespace_percent
||
669 crit_freespace_percent
|| warn_usedspace_units
|| crit_usedspace_units
||
670 warn_usedspace_percent
|| crit_usedspace_percent
|| warn_usedinodes_percent
||
671 crit_usedinodes_percent
|| warn_freeinodes_percent
|| crit_freeinodes_percent
)) {
672 die (STATE_UNKNOWN
, "DISK %s: %s", _("UNKNOWN"), _("Must set a threshold value before using -r/-R\n"));
675 err
= regcomp(&re
, optarg
, cflags
);
677 regerror (err
, &re
, errbuf
, MAX_INPUT_BUFFER
);
678 die (STATE_UNKNOWN
, "DISK %s: %s - %s\n",_("UNKNOWN"), _("Could not compile regular expression"), errbuf
);
681 for (me
= mount_list
; me
; me
= me
->me_next
) {
682 if (np_regex_match_mount_entry(me
, &re
)) {
685 printf("%s %s matching expression %s\n", me
->me_devname
, me
->me_mountdir
, optarg
);
687 /* add parameter if not found. overwrite thresholds if path has already been added */
688 if (! (se
= np_find_parameter(path_select_list
, me
->me_mountdir
))) {
689 se
= np_add_parameter(&path_select_list
, me
->me_mountdir
);
692 set_all_thresholds(se
);
697 die (STATE_UNKNOWN
, "DISK %s: %s - %s\n",_("UNKNOWN"),
698 _("Regular expression did not match any path or disk"), optarg
);
701 path_selected
= TRUE
;
702 np_set_best_match(path_select_list
, mount_list
, exact_match
);
703 cflags
= default_cflags
;
706 case 'M': /* display mountpoint */
710 /* add all mount entries to path_select list if no partitions have been explicitly defined using -p */
711 if (path_selected
== FALSE
) {
712 struct parameter_list
*path
;
713 for (me
= mount_list
; me
; me
= me
->me_next
) {
714 if (! (path
= np_find_parameter(path_select_list
, me
->me_mountdir
)))
715 path
= np_add_parameter(&path_select_list
, me
->me_mountdir
);
716 path
->best_match
= me
;
718 set_all_thresholds(path
);
721 warn_freespace_units
= NULL
;
722 crit_freespace_units
= NULL
;
723 warn_usedspace_units
= NULL
;
724 crit_usedspace_units
= NULL
;
725 warn_freespace_percent
= NULL
;
726 crit_freespace_percent
= NULL
;
727 warn_usedspace_percent
= NULL
;
728 crit_usedspace_percent
= NULL
;
729 warn_usedinodes_percent
= NULL
;
730 crit_usedinodes_percent
= NULL
;
731 warn_freeinodes_percent
= NULL
;
732 crit_freeinodes_percent
= NULL
;
734 path_selected
= FALSE
;
737 case 'V': /* version */
738 print_revision (progname
, NP_VERSION
);
744 usage (_("Unknown argument"));
748 /* Support for "check_disk warn crit [fs]" with thresholds at used% level */
750 if (warn_usedspace_percent
== NULL
&& argc
> c
&& is_intnonneg (argv
[c
]))
751 warn_usedspace_percent
= argv
[c
++];
753 if (crit_usedspace_percent
== NULL
&& argc
> c
&& is_intnonneg (argv
[c
]))
754 crit_usedspace_percent
= argv
[c
++];
756 if (argc
> c
&& path
== NULL
) {
757 se
= np_add_parameter(&path_select_list
, strdup(argv
[c
++]));
758 path_selected
= TRUE
;
759 set_all_thresholds(se
);
763 units
= strdup ("MB");
764 mult
= (uintmax_t)1024 * 1024;
773 print_path (const char *mypath
)
778 printf (_(" for %s\n"), mypath
);
783 set_all_thresholds (struct parameter_list
*path
)
785 if (path
->freespace_units
!= NULL
) free(path
->freespace_units
);
786 set_thresholds(&path
->freespace_units
, warn_freespace_units
, crit_freespace_units
);
787 if (path
->freespace_percent
!= NULL
) free (path
->freespace_percent
);
788 set_thresholds(&path
->freespace_percent
, warn_freespace_percent
, crit_freespace_percent
);
789 if (path
->usedspace_units
!= NULL
) free (path
->usedspace_units
);
790 set_thresholds(&path
->usedspace_units
, warn_usedspace_units
, crit_usedspace_units
);
791 if (path
->usedspace_percent
!= NULL
) free (path
->usedspace_percent
);
792 set_thresholds(&path
->usedspace_percent
, warn_usedspace_percent
, crit_usedspace_percent
);
793 if (path
->usedinodes_percent
!= NULL
) free (path
->usedinodes_percent
);
794 set_thresholds(&path
->usedinodes_percent
, warn_usedinodes_percent
, crit_usedinodes_percent
);
795 if (path
->freeinodes_percent
!= NULL
) free (path
->freeinodes_percent
);
796 set_thresholds(&path
->freeinodes_percent
, warn_freeinodes_percent
, crit_freeinodes_percent
);
802 validate_arguments (uintmax_t w, uintmax_t c, double wp, double cp, double iwp, double icp, char *mypath)
804 if (w < 0 && c < 0 && wp < 0.0 && cp < 0.0) {
805 printf (_("INPUT ERROR: No thresholds specified"));
809 else if ((wp >= 0.0 || cp >= 0.0) &&
810 (wp < 0.0 || cp < 0.0 || wp > 100.0 || cp > 100.0 || cp > wp)) {
812 INPUT ERROR: C_DFP (%f) should be less than W_DFP (%.1f) and both should be between zero and 100 percent, inclusive"),
817 else if ((iwp >= 0.0 || icp >= 0.0) &&
818 (iwp < 0.0 || icp < 0.0 || iwp > 100.0 || icp > 100.0 || icp > iwp)) {
820 INPUT ERROR: C_IDFP (%f) should be less than W_IDFP (%.1f) and both should be between zero and 100 percent, inclusive"),
825 else if ((w > 0 || c > 0) && (w == 0 || c == 0 || c > w)) {
827 INPUT ERROR: C_DF (%lu) should be less than W_DF (%lu) and both should be greater than zero"),
828 (unsigned long)c, (unsigned long)w);
847 print_revision (progname
, NP_VERSION
);
849 printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
850 printf (COPYRIGHT
, copyright
, email
);
852 printf ("%s\n", _("This plugin checks the amount of used disk space on a mounted file system"));
853 printf ("%s\n", _("and generates an alert if free space is less than one of the threshold values"));
859 printf (UT_HELP_VRSN
);
860 printf (UT_EXTRA_OPTS
);
862 printf (" %s\n", "-w, --warning=INTEGER");
863 printf (" %s\n", _("Exit with WARNING status if less than INTEGER units of disk are free"));
864 printf (" %s\n", "-w, --warning=PERCENT%");
865 printf (" %s\n", _("Exit with WARNING status if less than PERCENT of disk space is free"));
866 printf (" %s\n", "-c, --critical=INTEGER");
867 printf (" %s\n", _("Exit with CRITICAL status if less than INTEGER units of disk are free"));
868 printf (" %s\n", "-c, --critical=PERCENT%");
869 printf (" %s\n", _("Exit with CRITICAL status if less than PERCENT of disk space is free"));
870 printf (" %s\n", "-W, --iwarning=PERCENT%");
871 printf (" %s\n", _("Exit with WARNING status if less than PERCENT of inode space is free"));
872 printf (" %s\n", "-K, --icritical=PERCENT%");
873 printf (" %s\n", _("Exit with CRITICAL status if less than PERCENT of inode space is free"));
874 printf (" %s\n", "-p, --path=PATH, --partition=PARTITION");
875 printf (" %s\n", _("Path or partition (may be repeated)"));
876 printf (" %s\n", "-x, --exclude_device=PATH <STRING>");
877 printf (" %s\n", _("Ignore device (only works if -p unspecified)"));
878 printf (" %s\n", "-C, --clear");
879 printf (" %s\n", _("Clear thresholds"));
880 printf (" %s\n", "-E, --exact-match");
881 printf (" %s\n", _("For paths or partitions specified with -p, only check for exact paths"));
882 printf (" %s\n", "-e, --errors-only");
883 printf (" %s\n", _("Display only devices/mountpoints with errors"));
884 printf (" %s\n", "-g, --group=NAME");
885 printf (" %s\n", _("Group paths. Thresholds apply to (free-)space of all partitions together"));
886 printf (" %s\n", "-k, --kilobytes");
887 printf (" %s\n", _("Same as '--units kB'"));
888 printf (" %s\n", "-l, --local");
889 printf (" %s\n", _("Only check local filesystems"));
890 printf (" %s\n", "-L, --stat-remote-fs");
891 printf (" %s\n", _("Only check local filesystems against thresholds. Yet call stat on remote filesystems"));
892 printf (" %s\n", _("to test if they are accessible (e.g. to detect Stale NFS Handles)"));
893 printf (" %s\n", "-M, --mountpoint");
894 printf (" %s\n", _("Display the mountpoint instead of the partition"));
895 printf (" %s\n", "-m, --megabytes");
896 printf (" %s\n", _("Same as '--units MB'"));
897 printf (" %s\n", "-A, --all");
898 printf (" %s\n", _("Explicitly select all paths. This is equivalent to -R '.*'"));
899 printf (" %s\n", "-R, --eregi-path=PATH, --eregi-partition=PARTITION");
900 printf (" %s\n", _("Case insensitive regular expression for path/partition (may be repeated)"));
901 printf (" %s\n", "-r, --ereg-path=PATH, --ereg-partition=PARTITION");
902 printf (" %s\n", _("Regular expression for path or partition (may be repeated)"));
903 printf (" %s\n", "-I, --ignore-eregi-path=PATH, --ignore-eregi-partition=PARTITION");
904 printf (" %s\n", _("Regular expression to ignore selected path/partition (case insensitive) (may be repeated)"));
905 printf (" %s\n", "-i, --ignore-ereg-path=PATH, --ignore-ereg-partition=PARTITION");
906 printf (" %s\n", _("Regular expression to ignore selected path or partition (may be repeated)"));
907 printf (UT_TIMEOUT
, DEFAULT_SOCKET_TIMEOUT
);
908 printf (" %s\n", "-u, --units=STRING");
909 printf (" %s\n", _("Choose bytes, kB, MB, GB, TB (default: MB)"));
911 printf (" %s\n", "-X, --exclude-type=TYPE");
912 printf (" %s\n", _("Ignore all filesystems of indicated type (may be repeated)"));
913 printf (" %s\n", "-N, --include-type=TYPE");
914 printf (" %s\n", _("Check only filesystems of indicated type (may be repeated)"));
917 printf ("%s\n", _("Examples:"));
918 printf (" %s\n", "check_disk -w 10% -c 5% -p /tmp -p /var -C -w 100000 -c 50000 -p /");
919 printf (" %s\n", _("Checks /tmp and /var at 10% and 5%, and / at 100MB and 50MB"));
920 printf (" %s\n", "check_disk -w 100 -c 50 -C -w 1000 -c 500 -g sidDATA -r '^/oracle/SID/data.*$'");
921 printf (" %s\n", _("Checks all filesystems not matching -r at 100M and 50M. The fs matching the -r regex"));
922 printf (" %s\n", _("are grouped which means the freespace thresholds are applied to all disks together"));
923 printf (" %s\n", "check_disk -w 100 -c 50 -C -w 1000 -c 500 -p /foo -C -w 5% -c 3% -p /bar");
924 printf (" %s\n", _("Checks /foo for 1000M/500M and /bar for 5/3%. All remaining volumes use 100M/50M"));
934 printf ("%s\n", _("Usage:"));
935 printf (" %s -w limit -c limit [-W limit] [-K limit] {-p path | -x device}\n", progname
);
936 printf ("[-C] [-E] [-e] [-g group ] [-k] [-l] [-M] [-m] [-R path ] [-r path ]\n");
937 printf ("[-t timeout] [-u unit] [-v] [-X type] [-N type]\n");
941 stat_path (struct parameter_list
*p
)
943 /* Stat entry to check that dir exists and is accessible */
945 printf("calling stat on %s\n", p
->name
);
946 if (stat (p
->name
, &stat_buf
[0])) {
948 printf("stat failed on %s\n", p
->name
);
949 printf("DISK %s - ", _("CRITICAL"));
950 die (STATE_CRITICAL
, _("%s %s: %s\n"), p
->name
, _("is not accessible"), strerror(errno
));
956 get_stats (struct parameter_list
*p
, struct fs_usage
*fsp
) {
957 struct parameter_list
*p_list
;
958 struct fs_usage tmpfsp
;
961 if (p
->group
== NULL
) {
962 get_path_stats(p
,fsp
);
964 /* find all group members */
965 for (p_list
= path_select_list
; p_list
; p_list
=p_list
->name_next
) {
966 if (p_list
->group
&& ! (strcmp(p_list
->group
, p
->group
))) {
968 get_fs_usage (p_list
->best_match
->me_mountdir
, p_list
->best_match
->me_devname
, &tmpfsp
);
969 get_path_stats(p_list
, &tmpfsp
);
971 printf("Group %s: adding %llu blocks sized %llu, (%s) used_units=%g free_units=%g total_units=%g fsu_blocksize=%llu mult=%llu\n",
972 p_list
->group
, tmpfsp
.fsu_bavail
, tmpfsp
.fsu_blocksize
, p_list
->best_match
->me_mountdir
, p_list
->dused_units
, p_list
->dfree_units
,
973 p_list
->dtotal_units
, mult
);
975 /* prevent counting the first FS of a group twice since its parameter_list entry
976 * is used to carry the information of all file systems of the entire group */
978 p
->total
+= p_list
->total
;
979 p
->available
+= p_list
->available
;
980 p
->available_to_root
+= p_list
->available_to_root
;
981 p
->used
+= p_list
->used
;
983 p
->dused_units
+= p_list
->dused_units
;
984 p
->dfree_units
+= p_list
->dfree_units
;
985 p
->dtotal_units
+= p_list
->dtotal_units
;
986 p
->inodes_total
+= p_list
->inodes_total
;
987 p
->inodes_free
+= p_list
->inodes_free
;
992 printf("Group %s now has: used_units=%g free_units=%g total_units=%g fsu_blocksize=%llu mult=%llu\n",
993 p
->group
, tmpfsp
.fsu_bavail
, tmpfsp
.fsu_blocksize
, p
->best_match
->me_mountdir
, p
->dused_units
,
994 p
->dfree_units
, p
->dtotal_units
, mult
);
996 /* modify devname and mountdir for output */
997 p
->best_match
->me_mountdir
= p
->best_match
->me_devname
= p
->group
;
999 /* finally calculate percentages for either plain FS or summed up group */
1000 p
->dused_pct
= calculate_percent( p
->used
, p
->used
+ p
->available
); /* used + available can never be > uintmax */
1001 p
->dfree_pct
= 100 - p
->dused_pct
;
1002 p
->dused_inodes_percent
= calculate_percent(p
->inodes_total
- p
->inodes_free
, p
->inodes_total
);
1003 p
->dfree_inodes_percent
= 100 - p
->dused_inodes_percent
;
1008 get_path_stats (struct parameter_list
*p
, struct fs_usage
*fsp
) {
1009 p
->total
= fsp
->fsu_blocks
;
1010 /* 2007-12-08 - Workaround for Gnulib reporting insanely high available
1011 * space on BSD (the actual value should be negative but fsp->fsu_bavail
1013 p
->available
= fsp
->fsu_bavail
> fsp
->fsu_bfree
? 0 : fsp
->fsu_bavail
;
1014 p
->available_to_root
= fsp
->fsu_bfree
;
1015 p
->used
= p
->total
- p
->available_to_root
;
1017 p
->dused_units
= p
->used
*fsp
->fsu_blocksize
/mult
;
1018 p
->dfree_units
= p
->available
*fsp
->fsu_blocksize
/mult
;
1019 p
->dtotal_units
= p
->total
*fsp
->fsu_blocksize
/mult
;
1020 p
->inodes_total
= fsp
->fsu_files
; /* Total file nodes. */
1021 p
->inodes_free
= fsp
->fsu_ffree
; /* Free file nodes. */
1022 np_add_name(&seen
, p
->best_match
->me_mountdir
);