Addition to help to state that -f will always return OK if ssh command
[monitoring-plugins.git] / plugins / check_disk.c
blobe9e7219007091d4d206efc92b07403b43c149da2
1 /*****************************************************************************
2 *
3 * Nagios check_disk plugin
4 *
5 * License: GPL
6 * Copyright (c) 1999-2008 Nagios Plugins Development Team
7 *
8 * Last Modified: $Date$
9 *
10 * Description:
12 * This file contains the check_disk plugin
15 * This program is free software: you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation, either version 3 of the License, or
18 * (at your option) any later version.
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License
26 * along with this program. If not, see <http://www.gnu.org/licenses/>.
28 * $Id$
30 *****************************************************************************/
32 const char *progname = "check_disk";
33 const char *program_name = "check_disk"; /* Required for coreutils libs */
34 const char *revision = "$Revision$";
35 const char *copyright = "1999-2008";
36 const char *email = "nagiosplug-devel@lists.sourceforge.net";
39 #include "common.h"
40 #ifdef HAVE_SYS_STAT_H
41 # include <sys/stat.h>
42 #endif
43 #if HAVE_INTTYPES_H
44 # include <inttypes.h>
45 #endif
46 #include <assert.h>
47 #include "popen.h"
48 #include "utils.h"
49 #include "utils_disk.h"
50 #include <stdarg.h>
51 #include "fsusage.h"
52 #include "mountlist.h"
53 #include "intprops.h" /* necessary for TYPE_MAXIMUM */
54 #if HAVE_LIMITS_H
55 # include <limits.h>
56 #endif
57 #include "regex.h"
60 /* If nonzero, show inode information. */
61 static int inode_format = 1;
63 /* If nonzero, show even filesystems with zero size or
64 uninteresting types. */
65 static int show_all_fs = 1;
67 /* If nonzero, show only local filesystems. */
68 static int show_local_fs = 0;
70 /* If nonzero, show only local filesystems but call stat() on remote ones. */
71 static int stat_remote_fs = 0;
73 /* If positive, the units to use when printing sizes;
74 if negative, the human-readable base. */
75 /* static int output_block_size; */
77 /* If nonzero, invoke the `sync' system call before getting any usage data.
78 Using this option can make df very slow, especially with many or very
79 busy disks. Note that this may make a difference on some systems --
80 SunOs4.1.3, for one. It is *not* necessary on Linux. */
81 /* static int require_sync = 0; */
83 /* Linked list of filesystem types to display.
84 If `fs_select_list' is NULL, list all types.
85 This table is generated dynamically from command-line options,
86 rather than hardcoding into the program what it thinks are the
87 valid filesystem types; let the user specify any filesystem type
88 they want to, and if there are any filesystems of that type, they
89 will be shown.
91 Some filesystem types:
92 4.2 4.3 ufs nfs swap ignore io vm efs dbg */
94 /* static struct parameter_list *fs_select_list; */
96 /* Linked list of filesystem types to omit.
97 If the list is empty, don't exclude any types. */
99 static struct name_list *fs_exclude_list;
101 static struct name_list *dp_exclude_list;
103 static struct parameter_list *path_select_list = NULL;
105 /* Linked list of mounted filesystems. */
106 static struct mount_entry *mount_list;
108 /* For long options that have no equivalent short option, use a
109 non-character as a pseudo short option, starting with CHAR_MAX + 1. */
110 enum
112 SYNC_OPTION = CHAR_MAX + 1,
113 NO_SYNC_OPTION,
114 BLOCK_SIZE_OPTION
117 #ifdef _AIX
118 #pragma alloca
119 #endif
121 /* Linked list of mounted filesystems. */
122 static struct mount_entry *mount_list;
124 int process_arguments (int, char **);
125 void print_path (const char *mypath);
126 void set_all_thresholds (struct parameter_list *path);
127 int validate_arguments (uintmax_t, uintmax_t, double, double, double, double, char *);
128 void print_help (void);
129 void print_usage (void);
130 double calculate_percent(uintmax_t, uintmax_t);
131 void stat_path (struct parameter_list *p);
133 double w_dfp = -1.0;
134 double c_dfp = -1.0;
135 char *path;
136 char *exclude_device;
137 char *units;
138 uintmax_t mult = 1024 * 1024;
139 int verbose = 0;
140 int erronly = FALSE;
141 int display_mntp = FALSE;
142 int exact_match = FALSE;
143 char *warn_freespace_units = NULL;
144 char *crit_freespace_units = NULL;
145 char *warn_freespace_percent = NULL;
146 char *crit_freespace_percent = NULL;
147 char *warn_usedspace_units = NULL;
148 char *crit_usedspace_units = NULL;
149 char *warn_usedspace_percent = NULL;
150 char *crit_usedspace_percent = NULL;
151 char *warn_usedinodes_percent = NULL;
152 char *crit_usedinodes_percent = NULL;
153 char *warn_freeinodes_percent = NULL;
154 char *crit_freeinodes_percent = NULL;
155 int path_selected = FALSE;
156 char *group = NULL;
157 struct stat *stat_buf;
161 main (int argc, char **argv)
163 int result = STATE_UNKNOWN;
164 int disk_result = STATE_UNKNOWN;
165 char *output;
166 char *details;
167 char *perf;
168 char *preamble;
169 double inode_space_pct;
170 uintmax_t total, available, available_to_root, used;
171 double dfree_pct = -1, dused_pct = -1;
172 double dused_units, dfree_units, dtotal_units;
173 double dused_inodes_percent, dfree_inodes_percent;
174 double warning_high_tide;
175 double critical_high_tide;
176 int temp_result;
178 struct mount_entry *me;
179 struct fs_usage fsp, tmpfsp;
180 struct parameter_list *temp_list, *path;
181 struct name_list *seen = NULL;
183 preamble = strdup (" - free space:");
184 output = strdup ("");
185 details = strdup ("");
186 perf = strdup ("");
187 stat_buf = malloc(sizeof *stat_buf);
189 setlocale (LC_ALL, "");
190 bindtextdomain (PACKAGE, LOCALEDIR);
191 textdomain (PACKAGE);
193 mount_list = read_file_system_list (0);
195 /* Parse extra opts if any */
196 argv = np_extra_opts (&argc, argv, progname);
198 if (process_arguments (argc, argv) == ERROR)
199 usage4 (_("Could not parse arguments"));
201 /* If a list of paths has not been selected, find entire
202 mount list and create list of paths
204 if (path_selected == FALSE) {
205 for (me = mount_list; me; me = me->me_next) {
206 if (! (path = np_find_parameter(path_select_list, me->me_mountdir))) {
207 path = np_add_parameter(&path_select_list, me->me_mountdir);
209 path->best_match = me;
210 path->group = group;
211 set_all_thresholds(path);
214 np_set_best_match(path_select_list, mount_list, exact_match);
216 /* Error if no match found for specified paths */
217 temp_list = path_select_list;
219 while (temp_list) {
220 if (! temp_list->best_match) {
221 die (STATE_CRITICAL, _("DISK %s: %s not found\n"), _("CRITICAL"), temp_list->name);
224 temp_list = temp_list->name_next;
227 /* Process for every path in list */
228 for (path = path_select_list; path; path=path->name_next) {
230 if (verbose > 3 && path->freespace_percent->warning != NULL && path->freespace_percent->critical != NULL)
231 printf("Thresholds(pct) for %s warn: %f crit %f\n",path->name, path->freespace_percent->warning->end,
232 path->freespace_percent->critical->end);
234 if (verbose > 3 && path->group != NULL)
235 printf("Group of %s: %s\n",path->name,path->group);
237 /* reset disk result */
238 disk_result = STATE_UNKNOWN;
240 me = path->best_match;
242 /* Filters */
244 /* Remove filesystems already seen */
245 if (np_seen_name(seen, me->me_mountdir)) {
246 continue;
247 } else {
248 if (path->group != NULL) {
249 /* find all group members */
250 fsp.fsu_blocksize = 0;
251 fsp.fsu_blocks = 0;
252 fsp.fsu_bfree = 0;
253 fsp.fsu_bavail = 0;
254 fsp.fsu_files = 0;
255 fsp.fsu_ffree = 0;
258 for (temp_list = path_select_list; temp_list; temp_list=temp_list->name_next) {
259 if (temp_list->group && ! (strcmp(temp_list->group, path->group))) {
261 stat_path(path);
262 get_fs_usage (temp_list->best_match->me_mountdir, temp_list->best_match->me_devname, &tmpfsp);
264 /* possibly differing blocksizes if disks are grouped. Calculating average */
265 fsp.fsu_blocksize = (fsp.fsu_blocksize * fsp.fsu_blocks + tmpfsp.fsu_blocksize * tmpfsp.fsu_blocks) / \
266 (fsp.fsu_blocks + tmpfsp.fsu_blocks); /* Size of a block. */
267 fsp.fsu_blocks += tmpfsp.fsu_blocks; /* Total blocks. */
268 fsp.fsu_bfree += tmpfsp.fsu_bfree; /* Free blocks available to superuser. */
269 /* Gnulib workaround - see comment about it a few lines below */
270 fsp.fsu_bavail += (tmpfsp.fsu_bavail > tmpfsp.fsu_bfree ? 0 : tmpfsp.fsu_bavail); /* Free blocks available to non-superuser. */
271 fsp.fsu_files += tmpfsp.fsu_files; /* Total file nodes. */
272 fsp.fsu_ffree += tmpfsp.fsu_ffree; /* Free file nodes. */
274 if (verbose > 3)
275 printf("Group %s: add %llu blocks (%s) \n", path->group, tmpfsp.fsu_bavail, temp_list->name);
276 /* printf("Group %s: add %u blocks (%s)\n", temp_list->name); *//* path->group, tmpfsp.fsu_bavail, temp_list->name); */
278 np_add_name(&seen, temp_list->best_match->me_mountdir);
281 /* modify devname and mountdir for output */
282 me->me_mountdir = me->me_devname = path->group;
283 } else
284 np_add_name(&seen, me->me_mountdir);
287 if (path->group == NULL) {
288 /* Skip remote filesystems if we're not interested in them */
289 if (me->me_remote && show_local_fs) {
290 if (stat_remote_fs)
291 stat_path(path);
292 continue;
293 /* Skip pseudo fs's if we haven't asked for all fs's */
294 } else if (me->me_dummy && !show_all_fs) {
295 continue;
296 /* Skip excluded fstypes */
297 } else if (fs_exclude_list && np_find_name (fs_exclude_list, me->me_type)) {
298 continue;
299 /* Skip excluded fs's */
300 } else if (dp_exclude_list &&
301 (np_find_name (dp_exclude_list, me->me_devname) ||
302 np_find_name (dp_exclude_list, me->me_mountdir))) {
303 continue;
306 stat_path(path);
307 get_fs_usage (me->me_mountdir, me->me_devname, &fsp);
310 if (fsp.fsu_blocks && strcmp ("none", me->me_mountdir)) {
311 total = fsp.fsu_blocks;
312 /* 2007-12-08 - Workaround for Gnulib reporting insanely high available
313 * space on BSD (the actual value should be negative but fsp.fsu_bavail
314 * is unsigned) */
315 available = fsp.fsu_bavail > fsp.fsu_bfree ? 0 : fsp.fsu_bavail;
316 available_to_root = fsp.fsu_bfree;
317 used = total - available_to_root;
319 if (verbose >= 3)
320 printf ("For %s, total=%llu, available=%llu, available_to_root=%llu, used=%llu, fsp.fsu_files=%llu, fsp.fsu_ffree=%llu\n",
321 me->me_mountdir, total, available, available_to_root, used, fsp.fsu_files, fsp.fsu_ffree);
323 dused_pct = calculate_percent( used, used + available ); /* used + available can never be > uintmax */
325 dfree_pct = 100 - dused_pct;
326 dused_units = used*fsp.fsu_blocksize/mult;
327 dfree_units = available*fsp.fsu_blocksize/mult;
328 dtotal_units = total*fsp.fsu_blocksize/mult;
329 dused_inodes_percent = calculate_percent(fsp.fsu_files - fsp.fsu_ffree, fsp.fsu_files);
330 dfree_inodes_percent = 100 - dused_inodes_percent;
332 if (verbose >= 3) {
333 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",
334 me->me_mountdir, dused_pct, dfree_pct, dused_units, dfree_units, dtotal_units, dused_inodes_percent, dfree_inodes_percent, fsp.fsu_blocksize, mult);
337 /* Threshold comparisons */
339 temp_result = get_status(dfree_units, path->freespace_units);
340 if (verbose >=3) printf("Freespace_units result=%d\n", temp_result);
341 disk_result = max_state( disk_result, temp_result );
343 temp_result = get_status(dfree_pct, path->freespace_percent);
344 if (verbose >=3) printf("Freespace%% result=%d\n", temp_result);
345 disk_result = max_state( disk_result, temp_result );
347 temp_result = get_status(dused_units, path->usedspace_units);
348 if (verbose >=3) printf("Usedspace_units result=%d\n", temp_result);
349 disk_result = max_state( disk_result, temp_result );
351 temp_result = get_status(dused_pct, path->usedspace_percent);
352 if (verbose >=3) printf("Usedspace_percent result=%d\n", temp_result);
353 disk_result = max_state( disk_result, temp_result );
355 temp_result = get_status(dused_inodes_percent, path->usedinodes_percent);
356 if (verbose >=3) printf("Usedinodes_percent result=%d\n", temp_result);
357 disk_result = max_state( disk_result, temp_result );
359 temp_result = get_status(dfree_inodes_percent, path->freeinodes_percent);
360 if (verbose >=3) printf("Freeinodes_percent result=%d\n", temp_result);
361 disk_result = max_state( disk_result, temp_result );
363 result = max_state(result, disk_result);
365 /* What a mess of units. The output shows free space, the perf data shows used space. Yikes!
366 Hack here. Trying to get warn/crit levels from freespace_(units|percent) for perf
367 data. Assumption that start=0. Roll on new syntax...
370 /* *_high_tide must be reinitialized at each run */
371 warning_high_tide = UINT_MAX;
372 critical_high_tide = UINT_MAX;
374 if (path->freespace_units->warning != NULL) {
375 warning_high_tide = dtotal_units - path->freespace_units->warning->end;
377 if (path->freespace_percent->warning != NULL) {
378 warning_high_tide = abs( min( (double) warning_high_tide, (double) (1.0 - path->freespace_percent->warning->end/100)*dtotal_units ));
380 if (path->freespace_units->critical != NULL) {
381 critical_high_tide = dtotal_units - path->freespace_units->critical->end;
383 if (path->freespace_percent->critical != NULL) {
384 critical_high_tide = abs( min( (double) critical_high_tide, (double) (1.0 - path->freespace_percent->critical->end/100)*dtotal_units ));
387 /* Nb: *_high_tide are unset when == UINT_MAX */
388 asprintf (&perf, "%s %s", perf,
389 perfdata ((!strcmp(me->me_mountdir, "none") || display_mntp) ? me->me_devname : me->me_mountdir,
390 dused_units, units,
391 (warning_high_tide != UINT_MAX ? TRUE : FALSE), warning_high_tide,
392 (critical_high_tide != UINT_MAX ? TRUE : FALSE), critical_high_tide,
393 TRUE, 0,
394 TRUE, dtotal_units));
396 if (disk_result==STATE_OK && erronly && !verbose)
397 continue;
399 asprintf (&output, "%s %s %.0f %s (%.0f%%",
400 output,
401 (!strcmp(me->me_mountdir, "none") || display_mntp) ? me->me_devname : me->me_mountdir,
402 dfree_units,
403 units,
404 dfree_pct);
405 if (dused_inodes_percent < 0) {
406 asprintf(&output, "%s inode=-);", output);
407 } else {
408 asprintf(&output, "%s inode=%.0f%%);", output, dfree_inodes_percent );
411 /* TODO: Need to do a similar debug line
412 asprintf (&details, _("%s\n\
413 %.0f of %.0f %s (%.0f%% inode=%.0f%%) free on %s (type %s mounted on %s) warn:%lu crit:%lu warn%%:%.0f%% crit%%:%.0f%%"),
414 details, dfree_units, dtotal_units, units, dfree_pct, inode_space_pct,
415 me->me_devname, me->me_type, me->me_mountdir,
416 (unsigned long)w_df, (unsigned long)c_df, w_dfp, c_dfp);
423 if (verbose > 2)
424 asprintf (&output, "%s%s", output, details);
427 printf ("DISK %s%s%s|%s\n", state_text (result), (erronly && result==STATE_OK) ? "" : preamble, output, perf);
428 return result;
432 double calculate_percent(uintmax_t value, uintmax_t total) {
433 double pct = -1;
434 /* I don't understand the below, but it is taken from coreutils' df */
435 /* Seems to be calculating pct, in the best possible way */
436 if (value <= TYPE_MAXIMUM(uintmax_t) / 100
437 && total != 0) {
438 uintmax_t u100 = value * 100;
439 pct = u100 / total + (u100 % total != 0);
440 } else {
441 /* Possible rounding errors - see coreutils' df for more explanation */
442 double u = value;
443 double t = total;
444 if (t) {
445 long int lipct = pct = u * 100 / t;
446 double ipct = lipct;
448 /* Like 'pct = ceil (dpct);', but without ceil - from coreutils again */
449 if (ipct - 1 < pct && pct <= ipct + 1)
450 pct = ipct + (ipct < pct);
453 return pct;
456 /* process command-line arguments */
458 process_arguments (int argc, char **argv)
460 int c, err;
461 struct parameter_list *se;
462 struct parameter_list *temp_list = NULL, *previous = NULL;
463 struct parameter_list *temp_path_select_list = NULL;
464 struct mount_entry *me, *temp_me;
465 int result = OK;
466 regex_t re;
467 int cflags = REG_NOSUB | REG_EXTENDED;
468 int default_cflags = cflags;
469 char errbuf[MAX_INPUT_BUFFER];
470 int fnd = 0;
472 int option = 0;
473 static struct option longopts[] = {
474 {"timeout", required_argument, 0, 't'},
475 {"warning", required_argument, 0, 'w'},
476 {"critical", required_argument, 0, 'c'},
477 {"iwarning", required_argument, 0, 'W'},
478 /* Dang, -C is taken. We might want to reshuffle this. */
479 {"icritical", required_argument, 0, 'K'},
480 {"kilobytes", required_argument, 0, 'k'},
481 {"megabytes", required_argument, 0, 'm'},
482 {"units", required_argument, 0, 'u'},
483 {"path", required_argument, 0, 'p'},
484 {"partition", required_argument, 0, 'p'},
485 {"exclude_device", required_argument, 0, 'x'},
486 {"exclude-type", required_argument, 0, 'X'},
487 {"group", required_argument, 0, 'g'},
488 {"eregi-path", required_argument, 0, 'R'},
489 {"eregi-partition", required_argument, 0, 'R'},
490 {"ereg-path", required_argument, 0, 'r'},
491 {"ereg-partition", required_argument, 0, 'r'},
492 {"ignore-ereg-path", required_argument, 0, 'i'},
493 {"ignore-ereg-partition", required_argument, 0, 'i'},
494 {"ignore-eregi-path", required_argument, 0, 'I'},
495 {"ignore-eregi-partition", required_argument, 0, 'I'},
496 {"local", no_argument, 0, 'l'},
497 {"stat-remote-fs", no_argument, 0, 'L'},
498 {"mountpoint", no_argument, 0, 'M'},
499 {"errors-only", no_argument, 0, 'e'},
500 {"exact-match", no_argument, 0, 'E'},
501 {"all", no_argument, 0, 'A'},
502 {"verbose", no_argument, 0, 'v'},
503 {"quiet", no_argument, 0, 'q'},
504 {"clear", no_argument, 0, 'C'},
505 {"version", no_argument, 0, 'V'},
506 {"help", no_argument, 0, 'h'},
507 {0, 0, 0, 0}
510 if (argc < 2)
511 return ERROR;
513 np_add_name(&fs_exclude_list, "iso9660");
515 for (c = 1; c < argc; c++)
516 if (strcmp ("-to", argv[c]) == 0)
517 strcpy (argv[c], "-t");
519 while (1) {
520 c = getopt_long (argc, argv, "+?VqhveCt:c:w:K:W:u:p:x:X:mklLg:R:r:i:I:MEA", longopts, &option);
522 if (c == -1 || c == EOF)
523 break;
525 switch (c) {
526 case 't': /* timeout period */
527 if (is_integer (optarg)) {
528 timeout_interval = atoi (optarg);
529 break;
531 else {
532 usage2 (_("Timeout interval must be a positive integer"), optarg);
535 /* See comments for 'c' */
536 case 'w': /* warning threshold */
537 if (strstr(optarg, "%")) {
538 if (*optarg == '@') {
539 warn_freespace_percent = optarg;
540 } else {
541 asprintf(&warn_freespace_percent, "@%s", optarg);
543 } else {
544 if (*optarg == '@') {
545 warn_freespace_units = optarg;
546 } else {
547 asprintf(&warn_freespace_units, "@%s", optarg);
550 break;
552 /* Awful mistake where the range values do not make sense. Normally,
553 you alert if the value is within the range, but since we are using
554 freespace, we have to alert if outside the range. Thus we artifically
555 force @ at the beginning of the range, so that it is backwards compatible
557 case 'c': /* critical threshold */
558 if (strstr(optarg, "%")) {
559 if (*optarg == '@') {
560 crit_freespace_percent = optarg;
561 } else {
562 asprintf(&crit_freespace_percent, "@%s", optarg);
564 } else {
565 if (*optarg == '@') {
566 crit_freespace_units = optarg;
567 } else {
568 asprintf(&crit_freespace_units, "@%s", optarg);
571 break;
573 case 'W': /* warning inode threshold */
574 if (*optarg == '@') {
575 warn_freeinodes_percent = optarg;
576 } else {
577 asprintf(&warn_freeinodes_percent, "@%s", optarg);
579 break;
580 case 'K': /* critical inode threshold */
581 if (*optarg == '@') {
582 crit_freeinodes_percent = optarg;
583 } else {
584 asprintf(&crit_freeinodes_percent, "@%s", optarg);
586 break;
587 case 'u':
588 if (units)
589 free(units);
590 if (! strcmp (optarg, "bytes")) {
591 mult = (uintmax_t)1;
592 units = strdup ("B");
593 } else if (! strcmp (optarg, "kB")) {
594 mult = (uintmax_t)1024;
595 units = strdup ("kB");
596 } else if (! strcmp (optarg, "MB")) {
597 mult = (uintmax_t)1024 * 1024;
598 units = strdup ("MB");
599 } else if (! strcmp (optarg, "GB")) {
600 mult = (uintmax_t)1024 * 1024 * 1024;
601 units = strdup ("GB");
602 } else if (! strcmp (optarg, "TB")) {
603 mult = (uintmax_t)1024 * 1024 * 1024 * 1024;
604 units = strdup ("TB");
605 } else {
606 die (STATE_UNKNOWN, _("unit type %s not known\n"), optarg);
608 if (units == NULL)
609 die (STATE_UNKNOWN, _("failed allocating storage for '%s'\n"), "units");
610 break;
611 case 'k': /* display mountpoint */
612 mult = 1024;
613 if (units)
614 free(units);
615 units = strdup ("kB");
616 break;
617 case 'm': /* display mountpoint */
618 mult = 1024 * 1024;
619 if (units)
620 free(units);
621 units = strdup ("MB");
622 break;
623 case 'L':
624 stat_remote_fs = 1;
625 case 'l':
626 show_local_fs = 1;
627 break;
628 case 'p': /* select path */
629 if (! (warn_freespace_units || crit_freespace_units || warn_freespace_percent ||
630 crit_freespace_percent || warn_usedspace_units || crit_usedspace_units ||
631 warn_usedspace_percent || crit_usedspace_percent || warn_usedinodes_percent ||
632 crit_usedinodes_percent || warn_freeinodes_percent || crit_freeinodes_percent )) {
633 die (STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set a threshold value before using -p\n"));
636 /* add parameter if not found. overwrite thresholds if path has already been added */
637 if (! (se = np_find_parameter(path_select_list, optarg))) {
638 se = np_add_parameter(&path_select_list, optarg);
640 se->group = group;
641 set_all_thresholds(se);
642 np_set_best_match(se, mount_list, exact_match);
643 stat_path(se);
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 pathes\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 pathes \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"), _("Pathes need to be selected before using -i/-I. Use -A to select all pathes 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 mount_entry *me;
761 struct parameter_list *path;
762 for (me = mount_list; me; me = me->me_next) {
763 if (! (path = np_find_parameter(path_select_list, me->me_mountdir)))
764 path = np_add_parameter(&path_select_list, me->me_mountdir);
765 path->best_match = me;
766 path->group = group;
767 set_all_thresholds(path);
770 warn_freespace_units = NULL;
771 crit_freespace_units = NULL;
772 warn_usedspace_units = NULL;
773 crit_usedspace_units = NULL;
774 warn_freespace_percent = NULL;
775 crit_freespace_percent = NULL;
776 warn_usedspace_percent = NULL;
777 crit_usedspace_percent = NULL;
778 warn_usedinodes_percent = NULL;
779 crit_usedinodes_percent = NULL;
780 warn_freeinodes_percent = NULL;
781 crit_freeinodes_percent = NULL;
783 path_selected = FALSE;
784 group = NULL;
785 break;
786 case 'V': /* version */
787 print_revision (progname, revision);
788 exit (STATE_OK);
789 case 'h': /* help */
790 print_help ();
791 exit (STATE_OK);
792 case '?': /* help */
793 usage (_("Unknown argument"));
797 /* Support for "check_disk warn crit [fs]" with thresholds at used% level */
798 c = optind;
799 if (warn_usedspace_percent == NULL && argc > c && is_intnonneg (argv[c]))
800 warn_usedspace_percent = argv[c++];
802 if (crit_usedspace_percent == NULL && argc > c && is_intnonneg (argv[c]))
803 crit_usedspace_percent = argv[c++];
805 if (argc > c && path == NULL) {
806 se = np_add_parameter(&path_select_list, strdup(argv[c++]));
807 path_selected = TRUE;
808 set_all_thresholds(se);
811 if (units == NULL) {
812 units = strdup ("MB");
813 mult = (uintmax_t)1024 * 1024;
816 return TRUE;
821 void
822 print_path (const char *mypath)
824 if (mypath == NULL)
825 printf ("\n");
826 else
827 printf (_(" for %s\n"), mypath);
831 void
832 set_all_thresholds (struct parameter_list *path)
834 if (path->freespace_units != NULL) free(path->freespace_units);
835 set_thresholds(&path->freespace_units, warn_freespace_units, crit_freespace_units);
836 if (path->freespace_percent != NULL) free (path->freespace_percent);
837 set_thresholds(&path->freespace_percent, warn_freespace_percent, crit_freespace_percent);
838 if (path->usedspace_units != NULL) free (path->usedspace_units);
839 set_thresholds(&path->usedspace_units, warn_usedspace_units, crit_usedspace_units);
840 if (path->usedspace_percent != NULL) free (path->usedspace_percent);
841 set_thresholds(&path->usedspace_percent, warn_usedspace_percent, crit_usedspace_percent);
842 if (path->usedinodes_percent != NULL) free (path->usedinodes_percent);
843 set_thresholds(&path->usedinodes_percent, warn_usedinodes_percent, crit_usedinodes_percent);
844 if (path->freeinodes_percent != NULL) free (path->freeinodes_percent);
845 set_thresholds(&path->freeinodes_percent, warn_freeinodes_percent, crit_freeinodes_percent);
848 /* TODO: Remove?
851 validate_arguments (uintmax_t w, uintmax_t c, double wp, double cp, double iwp, double icp, char *mypath)
853 if (w < 0 && c < 0 && wp < 0.0 && cp < 0.0) {
854 printf (_("INPUT ERROR: No thresholds specified"));
855 print_path (mypath);
856 return ERROR;
858 else if ((wp >= 0.0 || cp >= 0.0) &&
859 (wp < 0.0 || cp < 0.0 || wp > 100.0 || cp > 100.0 || cp > wp)) {
860 printf (_("\
861 INPUT ERROR: C_DFP (%f) should be less than W_DFP (%.1f) and both should be between zero and 100 percent, inclusive"),
862 cp, wp);
863 print_path (mypath);
864 return ERROR;
866 else if ((iwp >= 0.0 || icp >= 0.0) &&
867 (iwp < 0.0 || icp < 0.0 || iwp > 100.0 || icp > 100.0 || icp > iwp)) {
868 printf (_("\
869 INPUT ERROR: C_IDFP (%f) should be less than W_IDFP (%.1f) and both should be between zero and 100 percent, inclusive"),
870 icp, iwp);
871 print_path (mypath);
872 return ERROR;
874 else if ((w > 0 || c > 0) && (w == 0 || c == 0 || c > w)) {
875 printf (_("\
876 INPUT ERROR: C_DF (%lu) should be less than W_DF (%lu) and both should be greater than zero"),
877 (unsigned long)c, (unsigned long)w);
878 print_path (mypath);
879 return ERROR;
882 return OK;
893 void
894 print_help (void)
896 print_revision (progname, revision);
898 printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
899 printf (COPYRIGHT, copyright, email);
901 printf ("%s\n", _("This plugin checks the amount of used disk space on a mounted file system"));
902 printf ("%s\n", _("and generates an alert if free space is less than one of the threshold values"));
904 printf ("\n\n");
906 print_usage ();
908 printf (_(UT_HELP_VRSN));
909 printf (_(UT_EXTRA_OPTS));
911 printf (" %s\n", "-w, --warning=INTEGER");
912 printf (" %s\n", _("Exit with WARNING status if less than INTEGER units of disk are free"));
913 printf (" %s\n", "-w, --warning=PERCENT%");
914 printf (" %s\n", _("Exit with WARNING status if less than PERCENT of disk space is free"));
915 printf (" %s\n", "-c, --critical=INTEGER");
916 printf (" %s\n", _("Exit with CRITICAL status if less than INTEGER units of disk are free"));
917 printf (" %s\n", "-c, --critical=PERCENT%");
918 printf (" %s\n", _("Exit with CRITCAL status if less than PERCENT of disk space is free"));
919 printf (" %s\n", "-W, --iwarning=PERCENT%");
920 printf (" %s\n", _("Exit with WARNING status if less than PERCENT of inode space is free"));
921 printf (" %s\n", "-K, --icritical=PERCENT%");
922 printf (" %s\n", _("Exit with CRITICAL status if less than PERCENT of inode space is free"));
923 printf (" %s\n", "-p, --path=PATH, --partition=PARTITION");
924 printf (" %s\n", _("Path or partition (may be repeated)"));
925 printf (" %s\n", "-x, --exclude_device=PATH <STRING>");
926 printf (" %s\n", _("Ignore device (only works if -p unspecified)"));
927 printf (" %s\n", "-C, --clear");
928 printf (" %s\n", _("Clear thresholds"));
929 printf (" %s\n", "-E, --exact-match");
930 printf (" %s\n", _("For paths or partitions specified with -p, only check for exact paths"));
931 printf (" %s\n", "-e, --errors-only");
932 printf (" %s\n", _("Display only devices/mountpoints with errors"));
933 printf (" %s\n", "-g, --group=NAME");
934 printf (" %s\n", _("Group pathes. Thresholds apply to (free-)space of all partitions together"));
935 printf (" %s\n", "-k, --kilobytes");
936 printf (" %s\n", _("Same as '--units kB'"));
937 printf (" %s\n", "-l, --local");
938 printf (" %s\n", _("Only check local filesystems"));
939 printf (" %s\n", "-L, --stat-remote-fs");
940 printf (" %s\n", _("Only check local filesystems against thresholds. Yet call stat on remote filesystems"));
941 printf (" %s\n", _("to test if they are accessible (e.g. to detect Stale NFS Handles)"));
942 printf (" %s\n", "-M, --mountpoint");
943 printf (" %s\n", _("Display the mountpoint instead of the partition"));
944 printf (" %s\n", "-m, --megabytes");
945 printf (" %s\n", _("Same as '--units MB'"));
946 printf (" %s\n", "-A, --all");
947 printf (" %s\n", _("Explicitly select all pathes. This is equivalent to -R '.*'"));
948 printf (" %s\n", "-R, --eregi-path=PATH, --eregi-partition=PARTITION");
949 printf (" %s\n", _("Case insensitive regular expression for path/partition (may be repeated)"));
950 printf (" %s\n", "-r, --ereg-path=PATH, --ereg-partition=PARTITION");
951 printf (" %s\n", _("Regular expression for path or partition (may be repeated)"));
952 printf (" %s\n", "-I, --ignore-eregi-path=PATH, --ignore-eregi-partition=PARTITION");
953 printf (" %s\n", _("Regular expression to ignore selected path/partition (case insensitive) (may be repeated)"));
954 printf (" %s\n", "-i, --ignore-ereg-path=PATH, --ignore-ereg-partition=PARTITION");
955 printf (" %s\n", _("Regular expression to ignore selected path or partition (may be repeated)"));
956 printf (_(UT_TIMEOUT), DEFAULT_SOCKET_TIMEOUT);
957 printf (" %s\n", "-u, --units=STRING");
958 printf (" %s\n", _("Choose bytes, kB, MB, GB, TB (default: MB)"));
959 printf (_(UT_VERBOSE));
960 printf (" %s\n", "-X, --exclude-type=TYPE");
961 printf (" %s\n", _("Ignore all filesystems of indicated type (may be repeated)"));
963 #ifdef NP_EXTRA_OPTS
964 printf ("\n");
965 printf ("%s\n", _("Notes:"));
966 printf (_(UT_EXTRA_OPTS_NOTES));
967 #endif
969 printf ("\n");
970 printf ("%s\n", _("Examples:"));
971 printf (" %s\n", "check_disk -w 10% -c 5% -p /tmp -p /var -C -w 100000 -c 50000 -p /");
972 printf (" %s\n", _("Checks /tmp and /var at 10% and 5%, and / at 100MB and 50MB"));
973 printf (" %s\n", "check_disk -w 100M -c 50M -C -w 1000M -c 500M -g sidDATA -r '^/oracle/SID/data.*$'");
974 printf (" %s\n", _("Checks all filesystems not matching -r at 100M and 50M. The fs matching the -r regex"));
975 printf (" %s\n", _("are grouped which means the freespace thresholds are applied to all disks together"));
976 printf (" %s\n", "check_disk -w 100M -c 50M -C -w 1000M -c 500M -p /foo -C -w 5% -c 3% -p /bar");
977 printf (" %s\n", _("Checks /foo for 1000M/500M and /bar for 5/3%. All remaining volumes use 100M/50M"));
979 printf (_(UT_SUPPORT));
984 void
985 print_usage (void)
987 printf (_("Usage:"));
988 printf (" %s -w limit -c limit [-W limit] [-K limit] {-p path | -x device}\n", progname);
989 printf ("[-C] [-E] [-e] [-g group ] [-k] [-l] [-M] [-m] [-R path ] [-r path ]\n");
990 printf ("[-t timeout] [-u unit] [-v] [-X type]\n");
993 void
994 stat_path (struct parameter_list *p)
996 /* Stat entry to check that dir exists and is accessible */
997 if (verbose > 3)
998 printf("calling stat on %s\n", p->name);
999 if (stat (p->name, &stat_buf[0])) {
1000 if (verbose > 3)
1001 printf("stat failed on %s\n", p->name);
1002 printf("DISK %s - ", _("CRITICAL"));
1003 die (STATE_CRITICAL, _("%s %s: %s\n"), p->name, _("is not accessible"), strerror(errno));