1 /******************************************************************************
2 *
3 * Nagios check_disk plugin
4 *
5 * License: GPL
6 * Copyright (c) 1999-2006 nagios-plugins team
7 *
8 * Last Modified: $Date$
9 *
10 * Description:
11 *
12 * This file contains the check_disk plugin
13 *
14 * License Information:
15 *
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
20 *
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29 *
30 * $Id$
31 *
32 *****************************************************************************/
34 const char *progname = "check_disk";
35 const char *program_name = "check_disk"; /* Required for coreutils libs */
36 const char *revision = "$Revision$";
37 const char *copyright = "1999-2006";
38 const char *email = "nagiosplug-devel@lists.sourceforge.net";
41 #include "common.h"
42 #ifdef HAVE_SYS_STAT_H
43 # include <sys/stat.h>
44 #endif
45 #if HAVE_INTTYPES_H
46 # include <inttypes.h>
47 #endif
48 #include <assert.h>
49 #include "popen.h"
50 #include "utils.h"
51 #include "utils_disk.h"
52 #include <stdarg.h>
53 #include "fsusage.h"
54 #include "mountlist.h"
55 #include "intprops.h" /* necessary for TYPE_MAXIMUM */
56 #if HAVE_LIMITS_H
57 # include <limits.h>
58 #endif
59 #include "regex.h"
62 /* If nonzero, show inode information. */
63 static int inode_format = 1;
65 /* If nonzero, show even filesystems with zero size or
66 uninteresting types. */
67 static int show_all_fs = 1;
69 /* If nonzero, show only local filesystems. */
70 static int show_local_fs = 0;
72 /* If nonzero, show only local filesystems but call stat() on remote ones. */
73 static int stat_remote_fs = 0;
75 /* If positive, the units to use when printing sizes;
76 if negative, the human-readable base. */
77 /* static int output_block_size; */
79 /* If nonzero, invoke the `sync' system call before getting any usage data.
80 Using this option can make df very slow, especially with many or very
81 busy disks. Note that this may make a difference on some systems --
82 SunOs4.1.3, for one. It is *not* necessary on Linux. */
83 /* static int require_sync = 0; */
85 /* Linked list of filesystem types to display.
86 If `fs_select_list' is NULL, list all types.
87 This table is generated dynamically from command-line options,
88 rather than hardcoding into the program what it thinks are the
89 valid filesystem types; let the user specify any filesystem type
90 they want to, and if there are any filesystems of that type, they
91 will be shown.
93 Some filesystem types:
94 4.2 4.3 ufs nfs swap ignore io vm efs dbg */
96 /* static struct parameter_list *fs_select_list; */
98 /* Linked list of filesystem types to omit.
99 If the list is empty, don't exclude any types. */
101 static struct name_list *fs_exclude_list;
103 static struct name_list *dp_exclude_list;
105 static struct parameter_list *path_select_list = NULL;
107 /* Linked list of mounted filesystems. */
108 static struct mount_entry *mount_list;
110 /* For long options that have no equivalent short option, use a
111 non-character as a pseudo short option, starting with CHAR_MAX + 1. */
112 enum
113 {
114 SYNC_OPTION = CHAR_MAX + 1,
115 NO_SYNC_OPTION,
116 BLOCK_SIZE_OPTION
117 };
119 #ifdef _AIX
120 #pragma alloca
121 #endif
123 /* Linked list of mounted filesystems. */
124 static struct mount_entry *mount_list;
126 int process_arguments (int, char **);
127 void print_path (const char *mypath);
128 void set_all_thresholds (struct parameter_list *path);
129 int validate_arguments (uintmax_t, uintmax_t, double, double, double, double, char *);
130 void print_help (void);
131 void print_usage (void);
132 double calculate_percent(uintmax_t, uintmax_t);
133 void stat_path (struct parameter_list *p);
135 double w_dfp = -1.0;
136 double c_dfp = -1.0;
137 char *path;
138 char *exclude_device;
139 char *units;
140 uintmax_t mult = 1024 * 1024;
141 int verbose = 0;
142 int erronly = FALSE;
143 int display_mntp = FALSE;
144 int exact_match = FALSE;
145 char *warn_freespace_units = NULL;
146 char *crit_freespace_units = NULL;
147 char *warn_freespace_percent = NULL;
148 char *crit_freespace_percent = NULL;
149 char *warn_usedspace_units = NULL;
150 char *crit_usedspace_units = NULL;
151 char *warn_usedspace_percent = NULL;
152 char *crit_usedspace_percent = NULL;
153 char *warn_usedinodes_percent = NULL;
154 char *crit_usedinodes_percent = NULL;
155 char *warn_freeinodes_percent = NULL;
156 char *crit_freeinodes_percent = NULL;
157 int path_selected = FALSE;
158 char *group = NULL;
159 struct stat *stat_buf;
162 int
163 main (int argc, char **argv)
164 {
165 int result = STATE_UNKNOWN;
166 int disk_result = STATE_UNKNOWN;
167 char *output;
168 char *details;
169 char *perf;
170 char *preamble;
171 double inode_space_pct;
172 uintmax_t total, available, available_to_root, used;
173 double dfree_pct = -1, dused_pct = -1;
174 double dused_units, dfree_units, dtotal_units;
175 double dused_inodes_percent, dfree_inodes_percent;
176 double warning_high_tide;
177 double critical_high_tide;
178 int temp_result;
180 struct mount_entry *me;
181 struct fs_usage fsp, tmpfsp;
182 struct parameter_list *temp_list, *path;
183 struct name_list *seen = NULL;
185 preamble = strdup (" - free space:");
186 output = strdup ("");
187 details = strdup ("");
188 perf = strdup ("");
189 stat_buf = malloc(sizeof *stat_buf);
191 setlocale (LC_ALL, "");
192 bindtextdomain (PACKAGE, LOCALEDIR);
193 textdomain (PACKAGE);
195 mount_list = read_file_system_list (0);
197 if (process_arguments (argc, argv) == ERROR)
198 usage4 (_("Could not parse arguments"));
200 /* If a list of paths has not been selected, find entire
201 mount list and create list of paths
202 */
203 if (path_selected == FALSE) {
204 for (me = mount_list; me; me = me->me_next) {
205 if (! (path = np_find_parameter(path_select_list, me->me_mountdir))) {
206 path = np_add_parameter(&path_select_list, me->me_mountdir);
207 }
208 path->best_match = me;
209 path->group = group;
210 set_all_thresholds(path);
211 }
212 }
213 np_set_best_match(path_select_list, mount_list, exact_match);
215 /* Error if no match found for specified paths */
216 temp_list = path_select_list;
218 while (temp_list) {
219 if (! temp_list->best_match) {
220 die (STATE_CRITICAL, _("DISK %s: %s not found\n"), _("CRITICAL"), temp_list->name);
221 }
223 temp_list = temp_list->name_next;
224 }
226 /* Process for every path in list */
227 for (path = path_select_list; path; path=path->name_next) {
229 if (verbose > 3 && path->freespace_percent->warning != NULL && path->freespace_percent->critical != NULL)
230 printf("Thresholds(pct) for %s warn: %f crit %f\n",path->name, path->freespace_percent->warning->end,
231 path->freespace_percent->critical->end);
233 if (verbose > 3 && path->group != NULL)
234 printf("Group of %s: %s\n",path->name,path->group);
236 /* reset disk result */
237 disk_result = STATE_UNKNOWN;
239 me = path->best_match;
241 /* Filters */
243 /* Remove filesystems already seen */
244 if (np_seen_name(seen, me->me_mountdir)) {
245 continue;
246 } else {
247 if (path->group != NULL) {
248 /* find all group members */
249 fsp.fsu_blocksize = 0;
250 fsp.fsu_blocks = 0;
251 fsp.fsu_bfree = 0;
252 fsp.fsu_bavail = 0;
253 fsp.fsu_files = 0;
254 fsp.fsu_ffree = 0;
257 for (temp_list = path_select_list; temp_list; temp_list=temp_list->name_next) {
258 if (temp_list->group && ! (strcmp(temp_list->group, path->group))) {
260 stat_path(path);
261 get_fs_usage (temp_list->best_match->me_mountdir, temp_list->best_match->me_devname, &tmpfsp);
263 /* possibly differing blocksizes if disks are grouped. Calculating average */
264 fsp.fsu_blocksize = (fsp.fsu_blocksize * fsp.fsu_blocks + tmpfsp.fsu_blocksize * tmpfsp.fsu_blocks) / \
265 (fsp.fsu_blocks + tmpfsp.fsu_blocks); /* Size of a block. */
266 fsp.fsu_blocks += tmpfsp.fsu_blocks; /* Total blocks. */
267 fsp.fsu_bfree += tmpfsp.fsu_bfree; /* Free blocks available to superuser. */
268 /* Gnulib workaround - see comment about it a few lines below */
269 fsp.fsu_bavail += (tmpfsp.fsu_bavail > tmpfsp.fsu_bfree ? 0 : tmpfsp.fsu_bavail); /* Free blocks available to non-superuser. */
270 fsp.fsu_files += tmpfsp.fsu_files; /* Total file nodes. */
271 fsp.fsu_ffree += tmpfsp.fsu_ffree; /* Free file nodes. */
273 if (verbose > 3)
274 printf("Group %s: add %llu blocks (%s) \n", path->group, tmpfsp.fsu_bavail, temp_list->name);
275 /* printf("Group %s: add %u blocks (%s)\n", temp_list->name); *//* path->group, tmpfsp.fsu_bavail, temp_list->name); */
277 np_add_name(&seen, temp_list->best_match->me_mountdir);
278 }
279 }
280 /* modify devname and mountdir for output */
281 me->me_mountdir = me->me_devname = path->group;
282 } else
283 np_add_name(&seen, me->me_mountdir);
284 }
286 if (path->group == NULL) {
287 /* Skip remote filesystems if we're not interested in them */
288 if (me->me_remote && show_local_fs) {
289 if (stat_remote_fs)
290 stat_path(path);
291 continue;
292 /* Skip pseudo fs's if we haven't asked for all fs's */
293 } else if (me->me_dummy && !show_all_fs) {
294 continue;
295 /* Skip excluded fstypes */
296 } else if (fs_exclude_list && np_find_name (fs_exclude_list, me->me_type)) {
297 continue;
298 /* Skip excluded fs's */
299 } else if (dp_exclude_list &&
300 (np_find_name (dp_exclude_list, me->me_devname) ||
301 np_find_name (dp_exclude_list, me->me_mountdir))) {
302 continue;
303 }
305 stat_path(path);
306 get_fs_usage (me->me_mountdir, me->me_devname, &fsp);
307 }
309 if (fsp.fsu_blocks && strcmp ("none", me->me_mountdir)) {
310 total = fsp.fsu_blocks;
311 /* 2007-12-08 - Workaround for Gnulib reporting insanely high available
312 * space on BSD (the actual value should be negative but fsp.fsu_bavail
313 * is unsigned) */
314 available = fsp.fsu_bavail > fsp.fsu_bfree ? 0 : fsp.fsu_bavail;
315 available_to_root = fsp.fsu_bfree;
316 used = total - available_to_root;
318 if (verbose >= 3)
319 printf ("For %s, total=%llu, available=%llu, available_to_root=%llu, used=%llu, fsp.fsu_files=%llu, fsp.fsu_ffree=%llu\n",
320 me->me_mountdir, total, available, available_to_root, used, fsp.fsu_files, fsp.fsu_ffree);
322 dused_pct = calculate_percent( used, used + available ); /* used + available can never be > uintmax */
324 dfree_pct = 100 - dused_pct;
325 dused_units = used*fsp.fsu_blocksize/mult;
326 dfree_units = available*fsp.fsu_blocksize/mult;
327 dtotal_units = total*fsp.fsu_blocksize/mult;
328 dused_inodes_percent = calculate_percent(fsp.fsu_files - fsp.fsu_ffree, fsp.fsu_files);
329 dfree_inodes_percent = 100 - dused_inodes_percent;
331 if (verbose >= 3) {
332 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",
333 me->me_mountdir, dused_pct, dfree_pct, dused_units, dfree_units, dtotal_units, dused_inodes_percent, dfree_inodes_percent, fsp.fsu_blocksize, mult);
334 }
336 /* Threshold comparisons */
338 temp_result = get_status(dfree_units, path->freespace_units);
339 if (verbose >=3) printf("Freespace_units result=%d\n", temp_result);
340 disk_result = max_state( disk_result, temp_result );
342 temp_result = get_status(dfree_pct, path->freespace_percent);
343 if (verbose >=3) printf("Freespace%% result=%d\n", temp_result);
344 disk_result = max_state( disk_result, temp_result );
346 temp_result = get_status(dused_units, path->usedspace_units);
347 if (verbose >=3) printf("Usedspace_units result=%d\n", temp_result);
348 disk_result = max_state( disk_result, temp_result );
350 temp_result = get_status(dused_pct, path->usedspace_percent);
351 if (verbose >=3) printf("Usedspace_percent result=%d\n", temp_result);
352 disk_result = max_state( disk_result, temp_result );
354 temp_result = get_status(dused_inodes_percent, path->usedinodes_percent);
355 if (verbose >=3) printf("Usedinodes_percent result=%d\n", temp_result);
356 disk_result = max_state( disk_result, temp_result );
358 temp_result = get_status(dfree_inodes_percent, path->freeinodes_percent);
359 if (verbose >=3) printf("Freeinodes_percent result=%d\n", temp_result);
360 disk_result = max_state( disk_result, temp_result );
362 result = max_state(result, disk_result);
364 /* What a mess of units. The output shows free space, the perf data shows used space. Yikes!
365 Hack here. Trying to get warn/crit levels from freespace_(units|percent) for perf
366 data. Assumption that start=0. Roll on new syntax...
367 */
369 /* *_high_tide must be reinitialized at each run */
370 warning_high_tide = UINT_MAX;
371 critical_high_tide = UINT_MAX;
373 if (path->freespace_units->warning != NULL) {
374 warning_high_tide = dtotal_units - path->freespace_units->warning->end;
375 }
376 if (path->freespace_percent->warning != NULL) {
377 warning_high_tide = abs( min( (double) warning_high_tide, (double) (1.0 - path->freespace_percent->warning->end/100)*dtotal_units ));
378 }
379 if (path->freespace_units->critical != NULL) {
380 critical_high_tide = dtotal_units - path->freespace_units->critical->end;
381 }
382 if (path->freespace_percent->critical != NULL) {
383 critical_high_tide = abs( min( (double) critical_high_tide, (double) (1.0 - path->freespace_percent->critical->end/100)*dtotal_units ));
384 }
386 /* Nb: *_high_tide are unset when == UINT_MAX */
387 asprintf (&perf, "%s %s", perf,
388 perfdata ((!strcmp(me->me_mountdir, "none") || display_mntp) ? me->me_devname : me->me_mountdir,
389 dused_units, units,
390 (warning_high_tide != UINT_MAX ? TRUE : FALSE), warning_high_tide,
391 (critical_high_tide != UINT_MAX ? TRUE : FALSE), critical_high_tide,
392 TRUE, 0,
393 TRUE, dtotal_units));
395 if (disk_result==STATE_OK && erronly && !verbose)
396 continue;
398 asprintf (&output, "%s %s %.0f %s (%.0f%%",
399 output,
400 (!strcmp(me->me_mountdir, "none") || display_mntp) ? me->me_devname : me->me_mountdir,
401 dfree_units,
402 units,
403 dfree_pct);
404 if (dused_inodes_percent < 0) {
405 asprintf(&output, "%s inode=-);", output);
406 } else {
407 asprintf(&output, "%s inode=%.0f%%);", output, dfree_inodes_percent );
408 }
410 /* TODO: Need to do a similar debug line
411 asprintf (&details, _("%s\n\
412 %.0f of %.0f %s (%.0f%% inode=%.0f%%) free on %s (type %s mounted on %s) warn:%lu crit:%lu warn%%:%.0f%% crit%%:%.0f%%"),
413 details, dfree_units, dtotal_units, units, dfree_pct, inode_space_pct,
414 me->me_devname, me->me_type, me->me_mountdir,
415 (unsigned long)w_df, (unsigned long)c_df, w_dfp, c_dfp);
416 */
418 }
420 }
422 if (verbose > 2)
423 asprintf (&output, "%s%s", output, details);
426 printf ("DISK %s%s%s|%s\n", state_text (result), (erronly && result==STATE_OK) ? "" : preamble, output, perf);
427 return result;
428 }
431 double calculate_percent(uintmax_t value, uintmax_t total) {
432 double pct = -1;
433 /* I don't understand the below, but it is taken from coreutils' df */
434 /* Seems to be calculating pct, in the best possible way */
435 if (value <= TYPE_MAXIMUM(uintmax_t) / 100
436 && total != 0) {
437 uintmax_t u100 = value * 100;
438 pct = u100 / total + (u100 % total != 0);
439 } else {
440 /* Possible rounding errors - see coreutils' df for more explanation */
441 double u = value;
442 double t = total;
443 if (t) {
444 long int lipct = pct = u * 100 / t;
445 double ipct = lipct;
447 /* Like 'pct = ceil (dpct);', but without ceil - from coreutils again */
448 if (ipct - 1 < pct && pct <= ipct + 1)
449 pct = ipct + (ipct < pct);
450 }
451 }
452 return pct;
453 }
455 /* process command-line arguments */
456 int
457 process_arguments (int argc, char **argv)
458 {
459 int c, err;
460 struct parameter_list *se;
461 struct parameter_list *temp_list = NULL, *previous = NULL;
462 struct parameter_list *temp_path_select_list = NULL;
463 struct mount_entry *me, *temp_me;
464 int result = OK;
465 regex_t re;
466 int cflags = REG_NOSUB | REG_EXTENDED;
467 int default_cflags = cflags;
468 char errbuf[MAX_INPUT_BUFFER];
469 int fnd = 0;
471 int option = 0;
472 static struct option longopts[] = {
473 {"timeout", required_argument, 0, 't'},
474 {"warning", required_argument, 0, 'w'},
475 {"critical", required_argument, 0, 'c'},
476 {"iwarning", required_argument, 0, 'W'},
477 /* Dang, -C is taken. We might want to reshuffle this. */
478 {"icritical", required_argument, 0, 'K'},
479 {"local", required_argument, 0, 'l'},
480 {"stat-remote-fs", required_argument, 0, 'L'},
481 {"kilobytes", required_argument, 0, 'k'},
482 {"megabytes", required_argument, 0, 'm'},
483 {"units", required_argument, 0, 'u'},
484 {"path", required_argument, 0, 'p'},
485 {"partition", required_argument, 0, 'p'},
486 {"exclude_device", required_argument, 0, 'x'},
487 {"exclude-type", required_argument, 0, 'X'},
488 {"group", required_argument, 0, 'g'},
489 {"eregi-path", required_argument, 0, 'R'},
490 {"eregi-partition", required_argument, 0, 'R'},
491 {"ereg-path", required_argument, 0, 'r'},
492 {"ereg-partition", required_argument, 0, 'r'},
493 {"ignore-ereg-path", required_argument, 0, 'i'},
494 {"ignore-ereg-partition", required_argument, 0, 'i'},
495 {"ignore-eregi-path", required_argument, 0, 'I'},
496 {"ignore-eregi-partition", required_argument, 0, 'I'},
497 {"mountpoint", no_argument, 0, 'M'},
498 {"errors-only", no_argument, 0, 'e'},
499 {"exact-match", no_argument, 0, 'E'},
500 {"all", no_argument, 0, 'A'},
501 {"verbose", no_argument, 0, 'v'},
502 {"quiet", no_argument, 0, 'q'},
503 {"clear", no_argument, 0, 'C'},
504 {"version", no_argument, 0, 'V'},
505 {"help", no_argument, 0, 'h'},
506 {0, 0, 0, 0}
507 };
509 if (argc < 2)
510 return ERROR;
512 np_add_name(&fs_exclude_list, "iso9660");
514 for (c = 1; c < argc; c++)
515 if (strcmp ("-to", argv[c]) == 0)
516 strcpy (argv[c], "-t");
518 while (1) {
519 c = getopt_long (argc, argv, "+?VqhveCt:c:w:K:W:u:p:x:X:mklLg:R:r:i:I:MEA", longopts, &option);
521 if (c == -1 || c == EOF)
522 break;
524 switch (c) {
525 case 't': /* timeout period */
526 if (is_integer (optarg)) {
527 timeout_interval = atoi (optarg);
528 break;
529 }
530 else {
531 usage2 (_("Timeout interval must be a positive integer"), optarg);
532 }
534 /* See comments for 'c' */
535 case 'w': /* warning threshold */
536 if (strstr(optarg, "%")) {
537 if (*optarg == '@') {
538 warn_freespace_percent = optarg;
539 } else {
540 asprintf(&warn_freespace_percent, "@%s", optarg);
541 }
542 } else {
543 if (*optarg == '@') {
544 warn_freespace_units = optarg;
545 } else {
546 asprintf(&warn_freespace_units, "@%s", optarg);
547 }
548 }
549 break;
551 /* Awful mistake where the range values do not make sense. Normally,
552 you alert if the value is within the range, but since we are using
553 freespace, we have to alert if outside the range. Thus we artifically
554 force @ at the beginning of the range, so that it is backwards compatible
555 */
556 case 'c': /* critical threshold */
557 if (strstr(optarg, "%")) {
558 if (*optarg == '@') {
559 crit_freespace_percent = optarg;
560 } else {
561 asprintf(&crit_freespace_percent, "@%s", optarg);
562 }
563 } else {
564 if (*optarg == '@') {
565 crit_freespace_units = optarg;
566 } else {
567 asprintf(&crit_freespace_units, "@%s", optarg);
568 }
569 }
570 break;
572 case 'W': /* warning inode threshold */
573 if (*optarg == '@') {
574 warn_freeinodes_percent = optarg;
575 } else {
576 asprintf(&warn_freeinodes_percent, "@%s", optarg);
577 }
578 break;
579 case 'K': /* critical inode threshold */
580 if (*optarg == '@') {
581 crit_freeinodes_percent = optarg;
582 } else {
583 asprintf(&crit_freeinodes_percent, "@%s", optarg);
584 }
585 break;
586 case 'u':
587 if (units)
588 free(units);
589 if (! strcmp (optarg, "bytes")) {
590 mult = (uintmax_t)1;
591 units = strdup ("B");
592 } else if (! strcmp (optarg, "kB")) {
593 mult = (uintmax_t)1024;
594 units = strdup ("kB");
595 } else if (! strcmp (optarg, "MB")) {
596 mult = (uintmax_t)1024 * 1024;
597 units = strdup ("MB");
598 } else if (! strcmp (optarg, "GB")) {
599 mult = (uintmax_t)1024 * 1024 * 1024;
600 units = strdup ("GB");
601 } else if (! strcmp (optarg, "TB")) {
602 mult = (uintmax_t)1024 * 1024 * 1024 * 1024;
603 units = strdup ("TB");
604 } else {
605 die (STATE_UNKNOWN, _("unit type %s not known\n"), optarg);
606 }
607 if (units == NULL)
608 die (STATE_UNKNOWN, _("failed allocating storage for '%s'\n"), "units");
609 break;
610 case 'k': /* display mountpoint */
611 mult = 1024;
612 if (units)
613 free(units);
614 units = strdup ("kB");
615 break;
616 case 'm': /* display mountpoint */
617 mult = 1024 * 1024;
618 if (units)
619 free(units);
620 units = strdup ("MB");
621 break;
622 case 'L':
623 stat_remote_fs = 1;
624 case 'l':
625 show_local_fs = 1;
626 break;
627 case 'p': /* select path */
628 if (! (warn_freespace_units || crit_freespace_units || warn_freespace_percent ||
629 crit_freespace_percent || warn_usedspace_units || crit_usedspace_units ||
630 warn_usedspace_percent || crit_usedspace_percent || warn_usedinodes_percent ||
631 crit_usedinodes_percent || warn_freeinodes_percent || crit_freeinodes_percent )) {
632 die (STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set a threshold value before using -p\n"));
633 }
635 /* add parameter if not found. overwrite thresholds if path has already been added */
636 if (! (se = np_find_parameter(path_select_list, optarg))) {
637 se = np_add_parameter(&path_select_list, optarg);
638 }
639 se->group = group;
640 set_all_thresholds(se);
641 np_set_best_match(se, mount_list, exact_match);
642 stat_path(se);
643 path_selected = TRUE;
644 break;
645 case 'x': /* exclude path or partition */
646 np_add_name(&dp_exclude_list, optarg);
647 break;
648 case 'X': /* exclude file system type */
649 np_add_name(&fs_exclude_list, optarg);
650 break;
651 case 'v': /* verbose */
652 verbose++;
653 break;
654 case 'q': /* TODO: this function should eventually go away (removed 2007-09-20) */
655 /* verbose--; **replaced by line below**. -q was only a broken way of implementing -e */
656 erronly = TRUE;
657 break;
658 case 'e':
659 erronly = TRUE;
660 break;
661 case 'E':
662 if (path_selected)
663 die (STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set -E before selecting pathes\n"));
664 exact_match = TRUE;
665 break;
666 case 'g':
667 if (path_selected)
668 die (STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set group value before selecting pathes \n"));
669 group = optarg;
670 break;
671 case 'I':
672 cflags |= REG_ICASE;
673 case 'i':
674 if (!path_selected)
675 die (STATE_UNKNOWN, "DISK %s: %s\n", _("UNKNOWN"), _("Pathes need to be selected before using -i/-I. Use -A to select all pathes explicitly"));
676 err = regcomp(&re, optarg, cflags);
677 if (err != 0) {
678 regerror (err, &re, errbuf, MAX_INPUT_BUFFER);
679 die (STATE_UNKNOWN, "DISK %s: %s - %s\n",_("UNKNOWN"), _("Could not compile regular expression"), errbuf);
680 }
682 temp_list = path_select_list;
684 previous = NULL;
685 while (temp_list) {
686 if (temp_list->best_match) {
687 if (np_regex_match_mount_entry(temp_list->best_match, &re)) {
689 if (verbose >=3)
690 printf("ignoring %s matching regex\n", temp_list->name);
692 temp_list = np_del_parameter(temp_list, previous);
693 /* pointer to first element needs to be uĆ¼dated if first item gets deleted */
694 if (previous == NULL)
695 path_select_list = temp_list;
696 } else {
697 previous = temp_list;
698 temp_list = temp_list->name_next;
699 }
700 } else {
701 previous = temp_list;
702 temp_list = temp_list->name_next;
703 }
704 }
707 cflags = default_cflags;
708 break;
710 case 'A':
711 optarg = strdup(".*");
712 case 'R':
713 cflags |= REG_ICASE;
714 case 'r':
715 if (! (warn_freespace_units || crit_freespace_units || warn_freespace_percent ||
716 crit_freespace_percent || warn_usedspace_units || crit_usedspace_units ||
717 warn_usedspace_percent || crit_usedspace_percent || warn_usedinodes_percent ||
718 crit_usedinodes_percent || warn_freeinodes_percent || crit_freeinodes_percent )) {
719 die (STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set a threshold value before using -r/-R\n"));
720 }
722 err = regcomp(&re, optarg, cflags);
723 if (err != 0) {
724 regerror (err, &re, errbuf, MAX_INPUT_BUFFER);
725 die (STATE_UNKNOWN, "DISK %s: %s - %s\n",_("UNKNOWN"), _("Could not compile regular expression"), errbuf);
726 }
728 for (me = mount_list; me; me = me->me_next) {
729 if (np_regex_match_mount_entry(me, &re)) {
730 fnd = TRUE;
731 if (verbose > 3)
732 printf("%s %s matching expression %s\n", me->me_devname, me->me_mountdir, optarg);
734 /* add parameter if not found. overwrite thresholds if path has already been added */
735 if (! (se = np_find_parameter(path_select_list, me->me_mountdir))) {
736 se = np_add_parameter(&path_select_list, me->me_mountdir);
737 }
738 se->group = group;
739 set_all_thresholds(se);
740 }
741 }
743 if (!fnd)
744 die (STATE_UNKNOWN, "DISK %s: %s - %s\n",_("UNKNOWN"),
745 _("Regular expression did not match any path or disk"), optarg);
747 fnd = FALSE;
748 path_selected = TRUE;
749 np_set_best_match(path_select_list, mount_list, exact_match);
750 cflags = default_cflags;
752 break;
753 case 'M': /* display mountpoint */
754 display_mntp = TRUE;
755 break;
756 case 'C':
757 /* add all mount entries to path_select list if no partitions have been explicitly defined using -p */
758 if (path_selected == FALSE) {
759 struct mount_entry *me;
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);
767 }
768 }
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, revision);
787 exit (STATE_OK);
788 case 'h': /* help */
789 print_help ();
790 exit (STATE_OK);
791 case '?': /* help */
792 usage (_("Unknown argument"));
793 }
794 }
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);
808 }
810 if (units == NULL) {
811 units = strdup ("MB");
812 mult = (uintmax_t)1024 * 1024;
813 }
815 return TRUE;
816 }
820 void
821 print_path (const char *mypath)
822 {
823 if (mypath == NULL)
824 printf ("\n");
825 else
826 printf (_(" for %s\n"), mypath);
827 }
830 void
831 set_all_thresholds (struct parameter_list *path)
832 {
833 set_thresholds(&path->freespace_units, warn_freespace_units, crit_freespace_units);
834 set_thresholds(&path->freespace_percent, warn_freespace_percent, crit_freespace_percent);
835 set_thresholds(&path->usedspace_units, warn_usedspace_units, crit_usedspace_units);
836 set_thresholds(&path->usedspace_percent, warn_usedspace_percent, crit_usedspace_percent);
837 set_thresholds(&path->usedinodes_percent, warn_usedinodes_percent, crit_usedinodes_percent);
838 set_thresholds(&path->freeinodes_percent, warn_freeinodes_percent, crit_freeinodes_percent);
839 }
841 /* TODO: Remove?
843 int
844 validate_arguments (uintmax_t w, uintmax_t c, double wp, double cp, double iwp, double icp, char *mypath)
845 {
846 if (w < 0 && c < 0 && wp < 0.0 && cp < 0.0) {
847 printf (_("INPUT ERROR: No thresholds specified"));
848 print_path (mypath);
849 return ERROR;
850 }
851 else if ((wp >= 0.0 || cp >= 0.0) &&
852 (wp < 0.0 || cp < 0.0 || wp > 100.0 || cp > 100.0 || cp > wp)) {
853 printf (_("\
854 INPUT ERROR: C_DFP (%f) should be less than W_DFP (%.1f) and both should be between zero and 100 percent, inclusive"),
855 cp, wp);
856 print_path (mypath);
857 return ERROR;
858 }
859 else if ((iwp >= 0.0 || icp >= 0.0) &&
860 (iwp < 0.0 || icp < 0.0 || iwp > 100.0 || icp > 100.0 || icp > iwp)) {
861 printf (_("\
862 INPUT ERROR: C_IDFP (%f) should be less than W_IDFP (%.1f) and both should be between zero and 100 percent, inclusive"),
863 icp, iwp);
864 print_path (mypath);
865 return ERROR;
866 }
867 else if ((w > 0 || c > 0) && (w == 0 || c == 0 || c > w)) {
868 printf (_("\
869 INPUT ERROR: C_DF (%lu) should be less than W_DF (%lu) and both should be greater than zero"),
870 (unsigned long)c, (unsigned long)w);
871 print_path (mypath);
872 return ERROR;
873 }
875 return OK;
876 }
878 */
886 void
887 print_help (void)
888 {
889 print_revision (progname, revision);
891 printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
892 printf (COPYRIGHT, copyright, email);
894 printf ("%s\n", _("This plugin checks the amount of used disk space on a mounted file system"));
895 printf ("%s\n", _("and generates an alert if free space is less than one of the threshold values"));
897 printf ("\n\n");
899 print_usage ();
901 printf (_(UT_HELP_VRSN));
903 printf (" %s\n", "-w, --warning=INTEGER");
904 printf (" %s\n", _("Exit with WARNING status if less than INTEGER units of disk are free"));
905 printf (" %s\n", "-w, --warning=PERCENT%");
906 printf (" %s\n", _("Exit with WARNING status if less than PERCENT of disk space is free"));
907 printf (" %s\n", "-c, --critical=INTEGER");
908 printf (" %s\n", _("Exit with CRITICAL status if less than INTEGER units of disk are free"));
909 printf (" %s\n", "-c, --critical=PERCENT%");
910 printf (" %s\n", _("Exit with CRITCAL status if less than PERCENT of disk space is free"));
911 printf (" %s\n", "-W, --iwarning=PERCENT%");
912 printf (" %s\n", _("Exit with WARNING status if less than PERCENT of inode space is free"));
913 printf (" %s\n", "-K, --icritical=PERCENT%");
914 printf (" %s\n", _("Exit with CRITICAL status if less than PERCENT of inode space is free"));
915 printf (" %s\n", "-p, --path=PATH, --partition=PARTITION");
916 printf (" %s\n", _("Path or partition (may be repeated)"));
917 printf (" %s\n", "-x, --exclude_device=PATH <STRING>");
918 printf (" %s\n", _("Ignore device (only works if -p unspecified)"));
919 printf (" %s\n", "-C, --clear");
920 printf (" %s\n", _("Clear thresholds"));
921 printf (" %s\n", "-E, --exact-match");
922 printf (" %s\n", _("For paths or partitions specified with -p, only check for exact paths"));
923 printf (" %s\n", "-e, --errors-only");
924 printf (" %s\n", _("Display only devices/mountpoints with errors"));
925 printf (" %s\n", "-g, --group=NAME");
926 printf (" %s\n", _("Group pathes. Thresholds apply to (free-)space of all partitions together"));
927 printf (" %s\n", "-k, --kilobytes");
928 printf (" %s\n", _("Same as '--units kB'"));
929 printf (" %s\n", "-l, --local");
930 printf (" %s\n", _("Only check local filesystems"));
931 printf (" %s\n", "-L, --stat-remote-fs");
932 printf (" %s\n", _("Only check local filesystems against thresholds. Yet call stat on remote filesystems"));
933 printf (" %s\n", _("to test if they are accessible (e.g. to detect Stale NFS Handles)"));
934 printf (" %s\n", "-M, --mountpoint");
935 printf (" %s\n", _("Display the mountpoint instead of the partition"));
936 printf (" %s\n", "-m, --megabytes");
937 printf (" %s\n", _("Same as '--units MB'"));
938 printf (" %s\n", "-A, --all");
939 printf (" %s\n", _("Explicitly select all pathes. This is equivalent to -R '.*'"));
940 printf (" %s\n", "-R, --eregi-path=PATH, --eregi-partition=PARTITION");
941 printf (" %s\n", _("Case insensitive regular expression for path/partition (may be repeated)"));
942 printf (" %s\n", "-r, --ereg-path=PATH, --ereg-partition=PARTITION");
943 printf (" %s\n", _("Regular expression for path or partition (may be repeated)"));
944 printf (" %s\n", "-I, --ignore-eregi-path=PATH, --ignore-eregi-partition=PARTITION");
945 printf (" %s\n", _("Regular expression to ignore selected path/partition (case insensitive) (may be repeated)"));
946 printf (" %s\n", "-i, --ignore-ereg-path=PATH, --ignore-ereg-partition=PARTITION");
947 printf (" %s\n", _("Regular expression to ignore selected path or partition (may be repeated)"));
948 printf (_(UT_TIMEOUT), DEFAULT_SOCKET_TIMEOUT);
949 printf (" %s\n", "-u, --units=STRING");
950 printf (" %s\n", _("Choose bytes, kB, MB, GB, TB (default: MB)"));
951 printf (_(UT_VERBOSE));
952 printf (" %s\n", "-X, --exclude-type=TYPE");
953 printf (" %s\n", _("Ignore all filesystems of indicated type (may be repeated)"));
954 printf ("\n");
955 printf ("%s\n", _("Examples:"));
956 printf (" %s\n", "check_disk -w 10% -c 5% -p /tmp -p /var -C -w 100000 -c 50000 -p /");
957 printf (" %s\n", _("Checks /tmp and /var at 10% and 5%, and / at 100MB and 50MB"));
958 printf (" %s\n", "check_disk -w 100M -c 50M -C -w 1000M -c 500M -g sidDATA -r '^/oracle/SID/data.*$'");
959 printf (" %s\n", _("Checks all filesystems not matching -r at 100M and 50M. The fs matching the -r regex"));
960 printf (" %s\n", _("are grouped which means the freespace thresholds are applied to all disks together"));
961 printf (" %s\n", "check_disk -w 100M -c 50M -C -w 1000M -c 500M -p /foo -C -w 5% -c 3% -p /bar");
962 printf (" %s\n", _("Checks /foo for 1000M/500M and /bar for 5/3%. All remaining volumes use 100M/50M"));
963 printf (_(UT_SUPPORT));
964 }
968 void
969 print_usage (void)
970 {
971 printf (_("Usage:"));
972 printf (" %s -w limit -c limit [-W limit] [-K limit] {-p path | -x device}\n", progname);
973 printf ("[-C] [-E] [-e] [-g group ] [-k] [-l] [-M] [-m] [-R path ] [-r path ]\n");
974 printf ("[-t timeout] [-u unit] [-v] [-X type]\n");
975 }
977 void
978 stat_path (struct parameter_list *p)
979 {
980 /* Stat entry to check that dir exists and is accessible */
981 if (verbose > 3)
982 printf("calling stat on %s\n", p->name);
983 if (stat (p->name, &stat_buf[0])) {
984 if (verbose > 3)
985 printf("stat failed on %s\n", p->name);
986 printf("DISK %s - ", _("CRITICAL"));
987 die (STATE_CRITICAL, _("%s %s: %s\n"), p->name, _("is not accessible"), strerror(errno));
988 }
989 }