Fix Debian bug #307905: Incorrect usage output
[monitoring-plugins.git] / plugins / check_disk.c
blob5c0eec592615e413f518e6b71bc3ccce39fa6d1e
1 /*****************************************************************************
2 *
3 * Nagios check_disk plugin
4 *
5 * License: GPL
6 * Copyright (c) 1999-2008 Nagios Plugins Development Team
7 *
8 * Description:
9 *
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";
35 #include "common.h"
36 #ifdef HAVE_SYS_STAT_H
37 # include <sys/stat.h>
38 #endif
39 #if HAVE_INTTYPES_H
40 # include <inttypes.h>
41 #endif
42 #include <assert.h>
43 #include "popen.h"
44 #include "utils.h"
45 #include "utils_disk.h"
46 #include <stdarg.h>
47 #include "fsusage.h"
48 #include "mountlist.h"
49 #include "intprops.h" /* necessary for TYPE_MAXIMUM */
50 #if HAVE_LIMITS_H
51 # include <limits.h>
52 #endif
53 #include "regex.h"
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
85 will be shown.
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. */
106 enum
108 SYNC_OPTION = CHAR_MAX + 1,
109 NO_SYNC_OPTION,
110 BLOCK_SIZE_OPTION
113 #ifdef _AIX
114 #pragma alloca
115 #endif
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);
126 double w_dfp = -1.0;
127 double c_dfp = -1.0;
128 char *path;
129 char *exclude_device;
130 char *units;
131 uintmax_t mult = 1024 * 1024;
132 int verbose = 0;
133 int erronly = FALSE;
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;
149 char *group = NULL;
150 struct stat *stat_buf;
154 main (int argc, char **argv)
156 int result = STATE_UNKNOWN;
157 int disk_result = STATE_UNKNOWN;
158 char *output;
159 char *details;
160 char *perf;
161 char *preamble;
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;
169 int temp_result;
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 ("");
179 perf = 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;
203 path->group = group;
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;
212 while (temp_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;
235 /* Filters */
237 /* Remove filesystems already seen */
238 if (np_seen_name(seen, me->me_mountdir)) {
239 continue;
240 } else {
241 if (path->group != NULL) {
242 /* find all group members */
243 fsp.fsu_blocksize = 0;
244 fsp.fsu_blocks = 0;
245 fsp.fsu_bfree = 0;
246 fsp.fsu_bavail = 0;
247 fsp.fsu_files = 0;
248 fsp.fsu_ffree = 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))) {
254 stat_path(path);
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. */
267 if (verbose >= 3)
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;
276 } else
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) {
283 if (stat_remote_fs)
284 stat_path(path);
285 continue;
286 /* Skip pseudo fs's if we haven't asked for all fs's */
287 } else if (me->me_dummy && !show_all_fs) {
288 continue;
289 /* Skip excluded fstypes */
290 } else if (fs_exclude_list && np_find_name (fs_exclude_list, me->me_type)) {
291 continue;
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))) {
296 continue;
299 stat_path(path);
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
307 * is unsigned) */
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;
312 if (verbose >= 3)
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;
325 if (verbose >= 3) {
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,
383 dused_units, units,
384 (warning_high_tide != UINT_MAX ? TRUE : FALSE), warning_high_tide,
385 (critical_high_tide != UINT_MAX ? TRUE : FALSE), critical_high_tide,
386 TRUE, 0,
387 TRUE, dtotal_units));
389 if (disk_result==STATE_OK && erronly && !verbose)
390 continue;
392 asprintf (&output, "%s %s %.0f %s (%.0f%%",
393 output,
394 (!strcmp(me->me_mountdir, "none") || display_mntp) ? me->me_devname : me->me_mountdir,
395 dfree_units,
396 units,
397 dfree_pct);
398 if (dused_inodes_percent < 0) {
399 asprintf(&output, "%s inode=-);", output);
400 } else {
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);
416 if (verbose >= 2)
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);
421 return result;
425 double calculate_percent(uintmax_t value, uintmax_t total) {
426 double pct = -1;
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
430 && total != 0) {
431 uintmax_t u100 = value * 100;
432 pct = u100 / total + (u100 % total != 0);
433 } else {
434 /* Possible rounding errors - see coreutils' df for more explanation */
435 double u = value;
436 double t = total;
437 if (t) {
438 long int lipct = pct = u * 100 / t;
439 double ipct = lipct;
441 /* Like 'pct = ceil (dpct);', but without ceil - from coreutils again */
442 if (ipct - 1 < pct && pct <= ipct + 1)
443 pct = ipct + (ipct < pct);
446 return pct;
449 /* process command-line arguments */
451 process_arguments (int argc, char **argv)
453 int c, err;
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;
458 int result = OK;
459 regex_t re;
460 int cflags = REG_NOSUB | REG_EXTENDED;
461 int default_cflags = cflags;
462 char errbuf[MAX_INPUT_BUFFER];
463 int fnd = 0;
465 int option = 0;
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'},
500 {0, 0, 0, 0}
503 if (argc < 2)
504 return ERROR;
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");
512 while (1) {
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)
516 break;
518 switch (c) {
519 case 't': /* timeout period */
520 if (is_integer (optarg)) {
521 timeout_interval = atoi (optarg);
522 break;
524 else {
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;
533 } else {
534 asprintf(&warn_freespace_percent, "@%s", optarg);
536 } else {
537 if (*optarg == '@') {
538 warn_freespace_units = optarg;
539 } else {
540 asprintf(&warn_freespace_units, "@%s", optarg);
543 break;
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;
554 } else {
555 asprintf(&crit_freespace_percent, "@%s", optarg);
557 } else {
558 if (*optarg == '@') {
559 crit_freespace_units = optarg;
560 } else {
561 asprintf(&crit_freespace_units, "@%s", optarg);
564 break;
566 case 'W': /* warning inode threshold */
567 if (*optarg == '@') {
568 warn_freeinodes_percent = optarg;
569 } else {
570 asprintf(&warn_freeinodes_percent, "@%s", optarg);
572 break;
573 case 'K': /* critical inode threshold */
574 if (*optarg == '@') {
575 crit_freeinodes_percent = optarg;
576 } else {
577 asprintf(&crit_freeinodes_percent, "@%s", optarg);
579 break;
580 case 'u':
581 if (units)
582 free(units);
583 if (! strcmp (optarg, "bytes")) {
584 mult = (uintmax_t)1;
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");
598 } else {
599 die (STATE_UNKNOWN, _("unit type %s not known\n"), optarg);
601 if (units == NULL)
602 die (STATE_UNKNOWN, _("failed allocating storage for '%s'\n"), "units");
603 break;
604 case 'k': /* display mountpoint */
605 mult = 1024;
606 if (units)
607 free(units);
608 units = strdup ("kB");
609 break;
610 case 'm': /* display mountpoint */
611 mult = 1024 * 1024;
612 if (units)
613 free(units);
614 units = strdup ("MB");
615 break;
616 case 'L':
617 stat_remote_fs = 1;
618 case 'l':
619 show_local_fs = 1;
620 break;
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);
633 se->group = group;
634 set_all_thresholds(se);
636 /* With autofs, it is required to stat() the path before re-populating the mount_list */
637 stat_path(se);
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;
645 break;
646 case 'x': /* exclude path or partition */
647 np_add_name(&dp_exclude_list, optarg);
648 break;
649 case 'X': /* exclude file system type */
650 np_add_name(&fs_exclude_list, optarg);
651 break;
652 case 'v': /* verbose */
653 verbose++;
654 break;
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 */
657 erronly = TRUE;
658 break;
659 case 'e':
660 erronly = TRUE;
661 break;
662 case 'E':
663 if (path_selected)
664 die (STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set -E before selecting paths\n"));
665 exact_match = TRUE;
666 break;
667 case 'g':
668 if (path_selected)
669 die (STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set group value before selecting paths\n"));
670 group = optarg;
671 break;
672 case 'I':
673 cflags |= REG_ICASE;
674 case 'i':
675 if (!path_selected)
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);
678 if (err != 0) {
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;
685 previous = NULL;
686 while (temp_list) {
687 if (temp_list->best_match) {
688 if (np_regex_match_mount_entry(temp_list->best_match, &re)) {
690 if (verbose >=3)
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;
697 } else {
698 previous = temp_list;
699 temp_list = temp_list->name_next;
701 } else {
702 previous = temp_list;
703 temp_list = temp_list->name_next;
708 cflags = default_cflags;
709 break;
711 case 'A':
712 optarg = strdup(".*");
713 case 'R':
714 cflags |= REG_ICASE;
715 case 'r':
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);
724 if (err != 0) {
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)) {
731 fnd = TRUE;
732 if (verbose >= 3)
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);
739 se->group = group;
740 set_all_thresholds(se);
744 if (!fnd)
745 die (STATE_UNKNOWN, "DISK %s: %s - %s\n",_("UNKNOWN"),
746 _("Regular expression did not match any path or disk"), optarg);
748 fnd = FALSE;
749 path_selected = TRUE;
750 np_set_best_match(path_select_list, mount_list, exact_match);
751 cflags = default_cflags;
753 break;
754 case 'M': /* display mountpoint */
755 display_mntp = TRUE;
756 break;
757 case 'C':
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;
765 path->group = group;
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;
783 group = NULL;
784 break;
785 case 'V': /* version */
786 print_revision (progname, NP_VERSION);
787 exit (STATE_OK);
788 case 'h': /* help */
789 print_help ();
790 exit (STATE_OK);
791 case '?': /* help */
792 usage (_("Unknown argument"));
796 /* Support for "check_disk warn crit [fs]" with thresholds at used% level */
797 c = optind;
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);
810 if (units == NULL) {
811 units = strdup ("MB");
812 mult = (uintmax_t)1024 * 1024;
815 return TRUE;
820 void
821 print_path (const char *mypath)
823 if (mypath == NULL)
824 printf ("\n");
825 else
826 printf (_(" for %s\n"), mypath);
830 void
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);
847 /* TODO: Remove?
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"));
854 print_path (mypath);
855 return ERROR;
857 else if ((wp >= 0.0 || cp >= 0.0) &&
858 (wp < 0.0 || cp < 0.0 || wp > 100.0 || cp > 100.0 || cp > wp)) {
859 printf (_("\
860 INPUT ERROR: C_DFP (%f) should be less than W_DFP (%.1f) and both should be between zero and 100 percent, inclusive"),
861 cp, wp);
862 print_path (mypath);
863 return ERROR;
865 else if ((iwp >= 0.0 || icp >= 0.0) &&
866 (iwp < 0.0 || icp < 0.0 || iwp > 100.0 || icp > 100.0 || icp > iwp)) {
867 printf (_("\
868 INPUT ERROR: C_IDFP (%f) should be less than W_IDFP (%.1f) and both should be between zero and 100 percent, inclusive"),
869 icp, iwp);
870 print_path (mypath);
871 return ERROR;
873 else if ((w > 0 || c > 0) && (w == 0 || c == 0 || c > w)) {
874 printf (_("\
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);
877 print_path (mypath);
878 return ERROR;
881 return OK;
892 void
893 print_help (void)
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"));
903 printf ("\n\n");
905 print_usage ();
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)"));
962 #ifdef NP_EXTRA_OPTS
963 printf ("\n");
964 printf ("%s\n", _("Notes:"));
965 printf (_(UT_EXTRA_OPTS_NOTES));
966 #endif
968 printf ("\n");
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));
983 void
984 print_usage (void)
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");
992 void
993 stat_path (struct parameter_list *p)
995 /* Stat entry to check that dir exists and is accessible */
996 if (verbose >= 3)
997 printf("calling stat on %s\n", p->name);
998 if (stat (p->name, &stat_buf[0])) {
999 if (verbose >= 3)
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));