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. */
95 static struct name_list
*fs_exclude_list
;
97 static struct name_list
*dp_exclude_list
;
99 static struct parameter_list
*path_select_list
= NULL
;
101 /* Linked list of mounted filesystems. */
102 static struct mount_entry
*mount_list
;
104 /* For long options that have no equivalent short option, use a
105 non-character as a pseudo short option, starting with CHAR_MAX + 1. */
108 SYNC_OPTION
= CHAR_MAX
+ 1,
117 int process_arguments (int, char **);
118 void print_path (const char *mypath
);
119 void set_all_thresholds (struct parameter_list
*path
);
120 int validate_arguments (uintmax_t, uintmax_t, double, double, double, double, char *);
121 void print_help (void);
122 void print_usage (void);
123 double calculate_percent(uintmax_t, uintmax_t);
124 void stat_path (struct parameter_list
*p
);
129 char *exclude_device
;
131 uintmax_t mult
= 1024 * 1024;
134 int display_mntp
= FALSE
;
135 int exact_match
= FALSE
;
136 char *warn_freespace_units
= NULL
;
137 char *crit_freespace_units
= NULL
;
138 char *warn_freespace_percent
= NULL
;
139 char *crit_freespace_percent
= NULL
;
140 char *warn_usedspace_units
= NULL
;
141 char *crit_usedspace_units
= NULL
;
142 char *warn_usedspace_percent
= NULL
;
143 char *crit_usedspace_percent
= NULL
;
144 char *warn_usedinodes_percent
= NULL
;
145 char *crit_usedinodes_percent
= NULL
;
146 char *warn_freeinodes_percent
= NULL
;
147 char *crit_freeinodes_percent
= NULL
;
148 int path_selected
= FALSE
;
150 struct stat
*stat_buf
;
154 main (int argc
, char **argv
)
156 int result
= STATE_UNKNOWN
;
157 int disk_result
= STATE_UNKNOWN
;
162 double inode_space_pct
;
163 uintmax_t total
, available
, available_to_root
, used
;
164 double dfree_pct
= -1, dused_pct
= -1;
165 double dused_units
, dfree_units
, dtotal_units
;
166 double dused_inodes_percent
, dfree_inodes_percent
;
167 double warning_high_tide
;
168 double critical_high_tide
;
171 struct mount_entry
*me
;
172 struct fs_usage fsp
, tmpfsp
;
173 struct parameter_list
*temp_list
, *path
;
174 struct name_list
*seen
= NULL
;
176 preamble
= strdup (" - free space:");
177 output
= strdup ("");
178 details
= strdup ("");
180 stat_buf
= malloc(sizeof *stat_buf
);
182 setlocale (LC_ALL
, "");
183 bindtextdomain (PACKAGE
, LOCALEDIR
);
184 textdomain (PACKAGE
);
186 mount_list
= read_file_system_list (0);
188 /* Parse extra opts if any */
189 argv
= np_extra_opts (&argc
, argv
, progname
);
191 if (process_arguments (argc
, argv
) == ERROR
)
192 usage4 (_("Could not parse arguments"));
194 /* If a list of paths has not been selected, find entire
195 mount list and create list of paths
197 if (path_selected
== FALSE
) {
198 for (me
= mount_list
; me
; me
= me
->me_next
) {
199 if (! (path
= np_find_parameter(path_select_list
, me
->me_mountdir
))) {
200 path
= np_add_parameter(&path_select_list
, me
->me_mountdir
);
202 path
->best_match
= me
;
204 set_all_thresholds(path
);
207 np_set_best_match(path_select_list
, mount_list
, exact_match
);
209 /* Error if no match found for specified paths */
210 temp_list
= path_select_list
;
213 if (! temp_list
->best_match
) {
214 die (STATE_CRITICAL
, _("DISK %s: %s not found\n"), _("CRITICAL"), temp_list
->name
);
217 temp_list
= temp_list
->name_next
;
220 /* Process for every path in list */
221 for (path
= path_select_list
; path
; path
=path
->name_next
) {
223 if (verbose
>= 3 && path
->freespace_percent
->warning
!= NULL
&& path
->freespace_percent
->critical
!= NULL
)
224 printf("Thresholds(pct) for %s warn: %f crit %f\n",path
->name
, path
->freespace_percent
->warning
->end
,
225 path
->freespace_percent
->critical
->end
);
227 if (verbose
>= 3 && path
->group
!= NULL
)
228 printf("Group of %s: %s\n",path
->name
,path
->group
);
230 /* reset disk result */
231 disk_result
= STATE_UNKNOWN
;
233 me
= path
->best_match
;
237 /* Remove filesystems already seen */
238 if (np_seen_name(seen
, me
->me_mountdir
)) {
241 if (path
->group
!= NULL
) {
242 /* find all group members */
243 fsp
.fsu_blocksize
= 0;
251 for (temp_list
= path_select_list
; temp_list
; temp_list
=temp_list
->name_next
) {
252 if (temp_list
->group
&& ! (strcmp(temp_list
->group
, path
->group
))) {
255 get_fs_usage (temp_list
->best_match
->me_mountdir
, temp_list
->best_match
->me_devname
, &tmpfsp
);
257 /* possibly differing blocksizes if disks are grouped. Calculating average */
258 fsp
.fsu_blocksize
= (fsp
.fsu_blocksize
* fsp
.fsu_blocks
+ tmpfsp
.fsu_blocksize
* tmpfsp
.fsu_blocks
) / \
259 (fsp
.fsu_blocks
+ tmpfsp
.fsu_blocks
); /* Size of a block. */
260 fsp
.fsu_blocks
+= tmpfsp
.fsu_blocks
; /* Total blocks. */
261 fsp
.fsu_bfree
+= tmpfsp
.fsu_bfree
; /* Free blocks available to superuser. */
262 /* Gnulib workaround - see comment about it a few lines below */
263 fsp
.fsu_bavail
+= (tmpfsp
.fsu_bavail
> tmpfsp
.fsu_bfree
? 0 : tmpfsp
.fsu_bavail
); /* Free blocks available to non-superuser. */
264 fsp
.fsu_files
+= tmpfsp
.fsu_files
; /* Total file nodes. */
265 fsp
.fsu_ffree
+= tmpfsp
.fsu_ffree
; /* Free file nodes. */
268 printf("Group %s: add %llu blocks (%s) \n", path
->group
, tmpfsp
.fsu_bavail
, temp_list
->name
);
269 /* printf("Group %s: add %u blocks (%s)\n", temp_list->name); *//* path->group, tmpfsp.fsu_bavail, temp_list->name); */
271 np_add_name(&seen
, temp_list
->best_match
->me_mountdir
);
274 /* modify devname and mountdir for output */
275 me
->me_mountdir
= me
->me_devname
= path
->group
;
277 np_add_name(&seen
, me
->me_mountdir
);
280 if (path
->group
== NULL
) {
281 /* Skip remote filesystems if we're not interested in them */
282 if (me
->me_remote
&& show_local_fs
) {
286 /* Skip pseudo fs's if we haven't asked for all fs's */
287 } else if (me
->me_dummy
&& !show_all_fs
) {
289 /* Skip excluded fstypes */
290 } else if (fs_exclude_list
&& np_find_name (fs_exclude_list
, me
->me_type
)) {
292 /* Skip excluded fs's */
293 } else if (dp_exclude_list
&&
294 (np_find_name (dp_exclude_list
, me
->me_devname
) ||
295 np_find_name (dp_exclude_list
, me
->me_mountdir
))) {
300 get_fs_usage (me
->me_mountdir
, me
->me_devname
, &fsp
);
303 if (fsp
.fsu_blocks
&& strcmp ("none", me
->me_mountdir
)) {
304 total
= fsp
.fsu_blocks
;
305 /* 2007-12-08 - Workaround for Gnulib reporting insanely high available
306 * space on BSD (the actual value should be negative but fsp.fsu_bavail
308 available
= fsp
.fsu_bavail
> fsp
.fsu_bfree
? 0 : fsp
.fsu_bavail
;
309 available_to_root
= fsp
.fsu_bfree
;
310 used
= total
- available_to_root
;
313 printf ("For %s, total=%llu, available=%llu, available_to_root=%llu, used=%llu, fsp.fsu_files=%llu, fsp.fsu_ffree=%llu\n",
314 me
->me_mountdir
, total
, available
, available_to_root
, used
, fsp
.fsu_files
, fsp
.fsu_ffree
);
316 dused_pct
= calculate_percent( used
, used
+ available
); /* used + available can never be > uintmax */
318 dfree_pct
= 100 - dused_pct
;
319 dused_units
= used
*fsp
.fsu_blocksize
/mult
;
320 dfree_units
= available
*fsp
.fsu_blocksize
/mult
;
321 dtotal_units
= total
*fsp
.fsu_blocksize
/mult
;
322 dused_inodes_percent
= calculate_percent(fsp
.fsu_files
- fsp
.fsu_ffree
, fsp
.fsu_files
);
323 dfree_inodes_percent
= 100 - dused_inodes_percent
;
326 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",
327 me
->me_mountdir
, dused_pct
, dfree_pct
, dused_units
, dfree_units
, dtotal_units
, dused_inodes_percent
, dfree_inodes_percent
, fsp
.fsu_blocksize
, mult
);
330 /* Threshold comparisons */
332 temp_result
= get_status(dfree_units
, path
->freespace_units
);
333 if (verbose
>=3) printf("Freespace_units result=%d\n", temp_result
);
334 disk_result
= max_state( disk_result
, temp_result
);
336 temp_result
= get_status(dfree_pct
, path
->freespace_percent
);
337 if (verbose
>=3) printf("Freespace%% result=%d\n", temp_result
);
338 disk_result
= max_state( disk_result
, temp_result
);
340 temp_result
= get_status(dused_units
, path
->usedspace_units
);
341 if (verbose
>=3) printf("Usedspace_units result=%d\n", temp_result
);
342 disk_result
= max_state( disk_result
, temp_result
);
344 temp_result
= get_status(dused_pct
, path
->usedspace_percent
);
345 if (verbose
>=3) printf("Usedspace_percent result=%d\n", temp_result
);
346 disk_result
= max_state( disk_result
, temp_result
);
348 temp_result
= get_status(dused_inodes_percent
, path
->usedinodes_percent
);
349 if (verbose
>=3) printf("Usedinodes_percent result=%d\n", temp_result
);
350 disk_result
= max_state( disk_result
, temp_result
);
352 temp_result
= get_status(dfree_inodes_percent
, path
->freeinodes_percent
);
353 if (verbose
>=3) printf("Freeinodes_percent result=%d\n", temp_result
);
354 disk_result
= max_state( disk_result
, temp_result
);
356 result
= max_state(result
, disk_result
);
358 /* What a mess of units. The output shows free space, the perf data shows used space. Yikes!
359 Hack here. Trying to get warn/crit levels from freespace_(units|percent) for perf
360 data. Assumption that start=0. Roll on new syntax...
363 /* *_high_tide must be reinitialized at each run */
364 warning_high_tide
= UINT_MAX
;
365 critical_high_tide
= UINT_MAX
;
367 if (path
->freespace_units
->warning
!= NULL
) {
368 warning_high_tide
= dtotal_units
- path
->freespace_units
->warning
->end
;
370 if (path
->freespace_percent
->warning
!= NULL
) {
371 warning_high_tide
= abs( min( (double) warning_high_tide
, (double) (1.0 - path
->freespace_percent
->warning
->end
/100)*dtotal_units
));
373 if (path
->freespace_units
->critical
!= NULL
) {
374 critical_high_tide
= dtotal_units
- path
->freespace_units
->critical
->end
;
376 if (path
->freespace_percent
->critical
!= NULL
) {
377 critical_high_tide
= abs( min( (double) critical_high_tide
, (double) (1.0 - path
->freespace_percent
->critical
->end
/100)*dtotal_units
));
380 /* Nb: *_high_tide are unset when == UINT_MAX */
381 asprintf (&perf
, "%s %s", perf
,
382 perfdata ((!strcmp(me
->me_mountdir
, "none") || display_mntp
) ? me
->me_devname
: me
->me_mountdir
,
384 (warning_high_tide
!= UINT_MAX
? TRUE
: FALSE
), warning_high_tide
,
385 (critical_high_tide
!= UINT_MAX
? TRUE
: FALSE
), critical_high_tide
,
387 TRUE
, dtotal_units
));
389 if (disk_result
==STATE_OK
&& erronly
&& !verbose
)
392 asprintf (&output
, "%s %s %.0f %s (%.0f%%",
394 (!strcmp(me
->me_mountdir
, "none") || display_mntp
) ? me
->me_devname
: me
->me_mountdir
,
398 if (dused_inodes_percent
< 0) {
399 asprintf(&output
, "%s inode=-);", output
);
401 asprintf(&output
, "%s inode=%.0f%%);", output
, dfree_inodes_percent
);
404 /* TODO: Need to do a similar debug line
405 asprintf (&details, _("%s\n\
406 %.0f of %.0f %s (%.0f%% inode=%.0f%%) free on %s (type %s mounted on %s) warn:%lu crit:%lu warn%%:%.0f%% crit%%:%.0f%%"),
407 details, dfree_units, dtotal_units, units, dfree_pct, inode_space_pct,
408 me->me_devname, me->me_type, me->me_mountdir,
409 (unsigned long)w_df, (unsigned long)c_df, w_dfp, c_dfp);
417 asprintf (&output
, "%s%s", output
, details
);
420 printf ("DISK %s%s%s|%s\n", state_text (result
), (erronly
&& result
==STATE_OK
) ? "" : preamble
, output
, perf
);
425 double calculate_percent(uintmax_t value
, uintmax_t total
) {
427 /* I don't understand the below, but it is taken from coreutils' df */
428 /* Seems to be calculating pct, in the best possible way */
429 if (value
<= TYPE_MAXIMUM(uintmax_t) / 100
431 uintmax_t u100
= value
* 100;
432 pct
= u100
/ total
+ (u100
% total
!= 0);
434 /* Possible rounding errors - see coreutils' df for more explanation */
438 long int lipct
= pct
= u
* 100 / t
;
441 /* Like 'pct = ceil (dpct);', but without ceil - from coreutils again */
442 if (ipct
- 1 < pct
&& pct
<= ipct
+ 1)
443 pct
= ipct
+ (ipct
< pct
);
449 /* process command-line arguments */
451 process_arguments (int argc
, char **argv
)
454 struct parameter_list
*se
;
455 struct parameter_list
*temp_list
= NULL
, *previous
= NULL
;
456 struct parameter_list
*temp_path_select_list
= NULL
;
457 struct mount_entry
*me
, *temp_me
;
460 int cflags
= REG_NOSUB
| REG_EXTENDED
;
461 int default_cflags
= cflags
;
462 char errbuf
[MAX_INPUT_BUFFER
];
466 static struct option longopts
[] = {
467 {"timeout", required_argument
, 0, 't'},
468 {"warning", required_argument
, 0, 'w'},
469 {"critical", required_argument
, 0, 'c'},
470 {"iwarning", required_argument
, 0, 'W'},
471 /* Dang, -C is taken. We might want to reshuffle this. */
472 {"icritical", required_argument
, 0, 'K'},
473 {"kilobytes", no_argument
, 0, 'k'},
474 {"megabytes", no_argument
, 0, 'm'},
475 {"units", required_argument
, 0, 'u'},
476 {"path", required_argument
, 0, 'p'},
477 {"partition", required_argument
, 0, 'p'},
478 {"exclude_device", required_argument
, 0, 'x'},
479 {"exclude-type", required_argument
, 0, 'X'},
480 {"group", required_argument
, 0, 'g'},
481 {"eregi-path", required_argument
, 0, 'R'},
482 {"eregi-partition", required_argument
, 0, 'R'},
483 {"ereg-path", required_argument
, 0, 'r'},
484 {"ereg-partition", required_argument
, 0, 'r'},
485 {"ignore-ereg-path", required_argument
, 0, 'i'},
486 {"ignore-ereg-partition", required_argument
, 0, 'i'},
487 {"ignore-eregi-path", required_argument
, 0, 'I'},
488 {"ignore-eregi-partition", required_argument
, 0, 'I'},
489 {"local", no_argument
, 0, 'l'},
490 {"stat-remote-fs", no_argument
, 0, 'L'},
491 {"mountpoint", no_argument
, 0, 'M'},
492 {"errors-only", no_argument
, 0, 'e'},
493 {"exact-match", no_argument
, 0, 'E'},
494 {"all", no_argument
, 0, 'A'},
495 {"verbose", no_argument
, 0, 'v'},
496 {"quiet", no_argument
, 0, 'q'},
497 {"clear", no_argument
, 0, 'C'},
498 {"version", no_argument
, 0, 'V'},
499 {"help", no_argument
, 0, 'h'},
506 np_add_name(&fs_exclude_list
, "iso9660");
508 for (c
= 1; c
< argc
; c
++)
509 if (strcmp ("-to", argv
[c
]) == 0)
510 strcpy (argv
[c
], "-t");
513 c
= getopt_long (argc
, argv
, "+?VqhveCt:c:w:K:W:u:p:x:X:mklLg:R:r:i:I:MEA", longopts
, &option
);
515 if (c
== -1 || c
== EOF
)
519 case 't': /* timeout period */
520 if (is_integer (optarg
)) {
521 timeout_interval
= atoi (optarg
);
525 usage2 (_("Timeout interval must be a positive integer"), optarg
);
528 /* See comments for 'c' */
529 case 'w': /* warning threshold */
530 if (strstr(optarg
, "%")) {
531 if (*optarg
== '@') {
532 warn_freespace_percent
= optarg
;
534 asprintf(&warn_freespace_percent
, "@%s", optarg
);
537 if (*optarg
== '@') {
538 warn_freespace_units
= optarg
;
540 asprintf(&warn_freespace_units
, "@%s", optarg
);
545 /* Awful mistake where the range values do not make sense. Normally,
546 you alert if the value is within the range, but since we are using
547 freespace, we have to alert if outside the range. Thus we artifically
548 force @ at the beginning of the range, so that it is backwards compatible
550 case 'c': /* critical threshold */
551 if (strstr(optarg
, "%")) {
552 if (*optarg
== '@') {
553 crit_freespace_percent
= optarg
;
555 asprintf(&crit_freespace_percent
, "@%s", optarg
);
558 if (*optarg
== '@') {
559 crit_freespace_units
= optarg
;
561 asprintf(&crit_freespace_units
, "@%s", optarg
);
566 case 'W': /* warning inode threshold */
567 if (*optarg
== '@') {
568 warn_freeinodes_percent
= optarg
;
570 asprintf(&warn_freeinodes_percent
, "@%s", optarg
);
573 case 'K': /* critical inode threshold */
574 if (*optarg
== '@') {
575 crit_freeinodes_percent
= optarg
;
577 asprintf(&crit_freeinodes_percent
, "@%s", optarg
);
583 if (! strcmp (optarg
, "bytes")) {
585 units
= strdup ("B");
586 } else if (! strcmp (optarg
, "kB")) {
587 mult
= (uintmax_t)1024;
588 units
= strdup ("kB");
589 } else if (! strcmp (optarg
, "MB")) {
590 mult
= (uintmax_t)1024 * 1024;
591 units
= strdup ("MB");
592 } else if (! strcmp (optarg
, "GB")) {
593 mult
= (uintmax_t)1024 * 1024 * 1024;
594 units
= strdup ("GB");
595 } else if (! strcmp (optarg
, "TB")) {
596 mult
= (uintmax_t)1024 * 1024 * 1024 * 1024;
597 units
= strdup ("TB");
599 die (STATE_UNKNOWN
, _("unit type %s not known\n"), optarg
);
602 die (STATE_UNKNOWN
, _("failed allocating storage for '%s'\n"), "units");
604 case 'k': /* display mountpoint */
608 units
= strdup ("kB");
610 case 'm': /* display mountpoint */
614 units
= strdup ("MB");
621 case 'p': /* select path */
622 if (! (warn_freespace_units
|| crit_freespace_units
|| warn_freespace_percent
||
623 crit_freespace_percent
|| warn_usedspace_units
|| crit_usedspace_units
||
624 warn_usedspace_percent
|| crit_usedspace_percent
|| warn_usedinodes_percent
||
625 crit_usedinodes_percent
|| warn_freeinodes_percent
|| crit_freeinodes_percent
)) {
626 die (STATE_UNKNOWN
, "DISK %s: %s", _("UNKNOWN"), _("Must set a threshold value before using -p\n"));
629 /* add parameter if not found. overwrite thresholds if path has already been added */
630 if (! (se
= np_find_parameter(path_select_list
, optarg
))) {
631 se
= np_add_parameter(&path_select_list
, optarg
);
634 set_all_thresholds(se
);
636 /* With autofs, it is required to stat() the path before re-populating the mount_list */
638 /* NB: We can't free the old mount_list "just like that": both list pointers and struct
639 * pointers are copied around. One of the reason it wasn't done yet is that other parts
640 * of check_disk need the same kind of cleanup so it'd better be done as a whole */
641 mount_list
= read_file_system_list (0);
642 np_set_best_match(se
, mount_list
, exact_match
);
644 path_selected
= TRUE
;
646 case 'x': /* exclude path or partition */
647 np_add_name(&dp_exclude_list
, optarg
);
649 case 'X': /* exclude file system type */
650 np_add_name(&fs_exclude_list
, optarg
);
652 case 'v': /* verbose */
655 case 'q': /* TODO: this function should eventually go away (removed 2007-09-20) */
656 /* verbose--; **replaced by line below**. -q was only a broken way of implementing -e */
664 die (STATE_UNKNOWN
, "DISK %s: %s", _("UNKNOWN"), _("Must set -E before selecting paths\n"));
669 die (STATE_UNKNOWN
, "DISK %s: %s", _("UNKNOWN"), _("Must set group value before selecting paths\n"));
676 die (STATE_UNKNOWN
, "DISK %s: %s\n", _("UNKNOWN"), _("Paths need to be selected before using -i/-I. Use -A to select all paths explicitly"));
677 err
= regcomp(&re
, optarg
, cflags
);
679 regerror (err
, &re
, errbuf
, MAX_INPUT_BUFFER
);
680 die (STATE_UNKNOWN
, "DISK %s: %s - %s\n",_("UNKNOWN"), _("Could not compile regular expression"), errbuf
);
683 temp_list
= path_select_list
;
687 if (temp_list
->best_match
) {
688 if (np_regex_match_mount_entry(temp_list
->best_match
, &re
)) {
691 printf("ignoring %s matching regex\n", temp_list
->name
);
693 temp_list
= np_del_parameter(temp_list
, previous
);
694 /* pointer to first element needs to be updated if first item gets deleted */
695 if (previous
== NULL
)
696 path_select_list
= temp_list
;
698 previous
= temp_list
;
699 temp_list
= temp_list
->name_next
;
702 previous
= temp_list
;
703 temp_list
= temp_list
->name_next
;
708 cflags
= default_cflags
;
712 optarg
= strdup(".*");
716 if (! (warn_freespace_units
|| crit_freespace_units
|| warn_freespace_percent
||
717 crit_freespace_percent
|| warn_usedspace_units
|| crit_usedspace_units
||
718 warn_usedspace_percent
|| crit_usedspace_percent
|| warn_usedinodes_percent
||
719 crit_usedinodes_percent
|| warn_freeinodes_percent
|| crit_freeinodes_percent
)) {
720 die (STATE_UNKNOWN
, "DISK %s: %s", _("UNKNOWN"), _("Must set a threshold value before using -r/-R\n"));
723 err
= regcomp(&re
, optarg
, cflags
);
725 regerror (err
, &re
, errbuf
, MAX_INPUT_BUFFER
);
726 die (STATE_UNKNOWN
, "DISK %s: %s - %s\n",_("UNKNOWN"), _("Could not compile regular expression"), errbuf
);
729 for (me
= mount_list
; me
; me
= me
->me_next
) {
730 if (np_regex_match_mount_entry(me
, &re
)) {
733 printf("%s %s matching expression %s\n", me
->me_devname
, me
->me_mountdir
, optarg
);
735 /* add parameter if not found. overwrite thresholds if path has already been added */
736 if (! (se
= np_find_parameter(path_select_list
, me
->me_mountdir
))) {
737 se
= np_add_parameter(&path_select_list
, me
->me_mountdir
);
740 set_all_thresholds(se
);
745 die (STATE_UNKNOWN
, "DISK %s: %s - %s\n",_("UNKNOWN"),
746 _("Regular expression did not match any path or disk"), optarg
);
749 path_selected
= TRUE
;
750 np_set_best_match(path_select_list
, mount_list
, exact_match
);
751 cflags
= default_cflags
;
754 case 'M': /* display mountpoint */
758 /* add all mount entries to path_select list if no partitions have been explicitly defined using -p */
759 if (path_selected
== FALSE
) {
760 struct parameter_list
*path
;
761 for (me
= mount_list
; me
; me
= me
->me_next
) {
762 if (! (path
= np_find_parameter(path_select_list
, me
->me_mountdir
)))
763 path
= np_add_parameter(&path_select_list
, me
->me_mountdir
);
764 path
->best_match
= me
;
766 set_all_thresholds(path
);
769 warn_freespace_units
= NULL
;
770 crit_freespace_units
= NULL
;
771 warn_usedspace_units
= NULL
;
772 crit_usedspace_units
= NULL
;
773 warn_freespace_percent
= NULL
;
774 crit_freespace_percent
= NULL
;
775 warn_usedspace_percent
= NULL
;
776 crit_usedspace_percent
= NULL
;
777 warn_usedinodes_percent
= NULL
;
778 crit_usedinodes_percent
= NULL
;
779 warn_freeinodes_percent
= NULL
;
780 crit_freeinodes_percent
= NULL
;
782 path_selected
= FALSE
;
785 case 'V': /* version */
786 print_revision (progname
, NP_VERSION
);
792 usage (_("Unknown argument"));
796 /* Support for "check_disk warn crit [fs]" with thresholds at used% level */
798 if (warn_usedspace_percent
== NULL
&& argc
> c
&& is_intnonneg (argv
[c
]))
799 warn_usedspace_percent
= argv
[c
++];
801 if (crit_usedspace_percent
== NULL
&& argc
> c
&& is_intnonneg (argv
[c
]))
802 crit_usedspace_percent
= argv
[c
++];
804 if (argc
> c
&& path
== NULL
) {
805 se
= np_add_parameter(&path_select_list
, strdup(argv
[c
++]));
806 path_selected
= TRUE
;
807 set_all_thresholds(se
);
811 units
= strdup ("MB");
812 mult
= (uintmax_t)1024 * 1024;
821 print_path (const char *mypath
)
826 printf (_(" for %s\n"), mypath
);
831 set_all_thresholds (struct parameter_list
*path
)
833 if (path
->freespace_units
!= NULL
) free(path
->freespace_units
);
834 set_thresholds(&path
->freespace_units
, warn_freespace_units
, crit_freespace_units
);
835 if (path
->freespace_percent
!= NULL
) free (path
->freespace_percent
);
836 set_thresholds(&path
->freespace_percent
, warn_freespace_percent
, crit_freespace_percent
);
837 if (path
->usedspace_units
!= NULL
) free (path
->usedspace_units
);
838 set_thresholds(&path
->usedspace_units
, warn_usedspace_units
, crit_usedspace_units
);
839 if (path
->usedspace_percent
!= NULL
) free (path
->usedspace_percent
);
840 set_thresholds(&path
->usedspace_percent
, warn_usedspace_percent
, crit_usedspace_percent
);
841 if (path
->usedinodes_percent
!= NULL
) free (path
->usedinodes_percent
);
842 set_thresholds(&path
->usedinodes_percent
, warn_usedinodes_percent
, crit_usedinodes_percent
);
843 if (path
->freeinodes_percent
!= NULL
) free (path
->freeinodes_percent
);
844 set_thresholds(&path
->freeinodes_percent
, warn_freeinodes_percent
, crit_freeinodes_percent
);
850 validate_arguments (uintmax_t w, uintmax_t c, double wp, double cp, double iwp, double icp, char *mypath)
852 if (w < 0 && c < 0 && wp < 0.0 && cp < 0.0) {
853 printf (_("INPUT ERROR: No thresholds specified"));
857 else if ((wp >= 0.0 || cp >= 0.0) &&
858 (wp < 0.0 || cp < 0.0 || wp > 100.0 || cp > 100.0 || cp > wp)) {
860 INPUT ERROR: C_DFP (%f) should be less than W_DFP (%.1f) and both should be between zero and 100 percent, inclusive"),
865 else if ((iwp >= 0.0 || icp >= 0.0) &&
866 (iwp < 0.0 || icp < 0.0 || iwp > 100.0 || icp > 100.0 || icp > iwp)) {
868 INPUT ERROR: C_IDFP (%f) should be less than W_IDFP (%.1f) and both should be between zero and 100 percent, inclusive"),
873 else if ((w > 0 || c > 0) && (w == 0 || c == 0 || c > w)) {
875 INPUT ERROR: C_DF (%lu) should be less than W_DF (%lu) and both should be greater than zero"),
876 (unsigned long)c, (unsigned long)w);
895 print_revision (progname
, NP_VERSION
);
897 printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
898 printf (COPYRIGHT
, copyright
, email
);
900 printf ("%s\n", _("This plugin checks the amount of used disk space on a mounted file system"));
901 printf ("%s\n", _("and generates an alert if free space is less than one of the threshold values"));
907 printf (_(UT_HELP_VRSN
));
908 printf (_(UT_EXTRA_OPTS
));
910 printf (" %s\n", "-w, --warning=INTEGER");
911 printf (" %s\n", _("Exit with WARNING status if less than INTEGER units of disk are free"));
912 printf (" %s\n", "-w, --warning=PERCENT%");
913 printf (" %s\n", _("Exit with WARNING status if less than PERCENT of disk space is free"));
914 printf (" %s\n", "-c, --critical=INTEGER");
915 printf (" %s\n", _("Exit with CRITICAL status if less than INTEGER units of disk are free"));
916 printf (" %s\n", "-c, --critical=PERCENT%");
917 printf (" %s\n", _("Exit with CRITCAL status if less than PERCENT of disk space is free"));
918 printf (" %s\n", "-W, --iwarning=PERCENT%");
919 printf (" %s\n", _("Exit with WARNING status if less than PERCENT of inode space is free"));
920 printf (" %s\n", "-K, --icritical=PERCENT%");
921 printf (" %s\n", _("Exit with CRITICAL status if less than PERCENT of inode space is free"));
922 printf (" %s\n", "-p, --path=PATH, --partition=PARTITION");
923 printf (" %s\n", _("Path or partition (may be repeated)"));
924 printf (" %s\n", "-x, --exclude_device=PATH <STRING>");
925 printf (" %s\n", _("Ignore device (only works if -p unspecified)"));
926 printf (" %s\n", "-C, --clear");
927 printf (" %s\n", _("Clear thresholds"));
928 printf (" %s\n", "-E, --exact-match");
929 printf (" %s\n", _("For paths or partitions specified with -p, only check for exact paths"));
930 printf (" %s\n", "-e, --errors-only");
931 printf (" %s\n", _("Display only devices/mountpoints with errors"));
932 printf (" %s\n", "-g, --group=NAME");
933 printf (" %s\n", _("Group paths. Thresholds apply to (free-)space of all partitions together"));
934 printf (" %s\n", "-k, --kilobytes");
935 printf (" %s\n", _("Same as '--units kB'"));
936 printf (" %s\n", "-l, --local");
937 printf (" %s\n", _("Only check local filesystems"));
938 printf (" %s\n", "-L, --stat-remote-fs");
939 printf (" %s\n", _("Only check local filesystems against thresholds. Yet call stat on remote filesystems"));
940 printf (" %s\n", _("to test if they are accessible (e.g. to detect Stale NFS Handles)"));
941 printf (" %s\n", "-M, --mountpoint");
942 printf (" %s\n", _("Display the mountpoint instead of the partition"));
943 printf (" %s\n", "-m, --megabytes");
944 printf (" %s\n", _("Same as '--units MB'"));
945 printf (" %s\n", "-A, --all");
946 printf (" %s\n", _("Explicitly select all paths. This is equivalent to -R '.*'"));
947 printf (" %s\n", "-R, --eregi-path=PATH, --eregi-partition=PARTITION");
948 printf (" %s\n", _("Case insensitive regular expression for path/partition (may be repeated)"));
949 printf (" %s\n", "-r, --ereg-path=PATH, --ereg-partition=PARTITION");
950 printf (" %s\n", _("Regular expression for path or partition (may be repeated)"));
951 printf (" %s\n", "-I, --ignore-eregi-path=PATH, --ignore-eregi-partition=PARTITION");
952 printf (" %s\n", _("Regular expression to ignore selected path/partition (case insensitive) (may be repeated)"));
953 printf (" %s\n", "-i, --ignore-ereg-path=PATH, --ignore-ereg-partition=PARTITION");
954 printf (" %s\n", _("Regular expression to ignore selected path or partition (may be repeated)"));
955 printf (_(UT_TIMEOUT
), DEFAULT_SOCKET_TIMEOUT
);
956 printf (" %s\n", "-u, --units=STRING");
957 printf (" %s\n", _("Choose bytes, kB, MB, GB, TB (default: MB)"));
958 printf (_(UT_VERBOSE
));
959 printf (" %s\n", "-X, --exclude-type=TYPE");
960 printf (" %s\n", _("Ignore all filesystems of indicated type (may be repeated)"));
964 printf ("%s\n", _("Notes:"));
965 printf (_(UT_EXTRA_OPTS_NOTES
));
969 printf ("%s\n", _("Examples:"));
970 printf (" %s\n", "check_disk -w 10% -c 5% -p /tmp -p /var -C -w 100000 -c 50000 -p /");
971 printf (" %s\n", _("Checks /tmp and /var at 10% and 5%, and / at 100MB and 50MB"));
972 printf (" %s\n", "check_disk -w 100M -c 50M -C -w 1000M -c 500M -g sidDATA -r '^/oracle/SID/data.*$'");
973 printf (" %s\n", _("Checks all filesystems not matching -r at 100M and 50M. The fs matching the -r regex"));
974 printf (" %s\n", _("are grouped which means the freespace thresholds are applied to all disks together"));
975 printf (" %s\n", "check_disk -w 100M -c 50M -C -w 1000M -c 500M -p /foo -C -w 5% -c 3% -p /bar");
976 printf (" %s\n", _("Checks /foo for 1000M/500M and /bar for 5/3%. All remaining volumes use 100M/50M"));
978 printf (_(UT_SUPPORT
));
986 printf (_("Usage:"));
987 printf (" %s -w limit -c limit [-W limit] [-K limit] {-p path | -x device}\n", progname
);
988 printf ("[-C] [-E] [-e] [-g group ] [-k] [-l] [-M] [-m] [-R path ] [-r path ]\n");
989 printf ("[-t timeout] [-u unit] [-v] [-X type]\n");
993 stat_path (struct parameter_list
*p
)
995 /* Stat entry to check that dir exists and is accessible */
997 printf("calling stat on %s\n", p
->name
);
998 if (stat (p
->name
, &stat_buf
[0])) {
1000 printf("stat failed on %s\n", p
->name
);
1001 printf("DISK %s - ", _("CRITICAL"));
1002 die (STATE_CRITICAL
, _("%s %s: %s\n"), p
->name
, _("is not accessible"), strerror(errno
));