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 positive, the units to use when printing sizes;
73 if negative, the human-readable base. */
74 /* static int output_block_size; */
76 /* If nonzero, invoke the `sync' system call before getting any usage data.
77 Using this option can make df very slow, especially with many or very
78 busy disks. Note that this may make a difference on some systems --
79 SunOs4.1.3, for one. It is *not* necessary on Linux. */
80 /* static int require_sync = 0; */
82 /* Linked list of filesystem types to display.
83 If `fs_select_list' is NULL, list all types.
84 This table is generated dynamically from command-line options,
85 rather than hardcoding into the program what it thinks are the
86 valid filesystem types; let the user specify any filesystem type
87 they want to, and if there are any filesystems of that type, they
88 will be shown.
90 Some filesystem types:
91 4.2 4.3 ufs nfs swap ignore io vm efs dbg */
93 /* static struct parameter_list *fs_select_list; */
95 /* Linked list of filesystem types to omit.
96 If the list is empty, don't exclude any types. */
98 static struct name_list *fs_exclude_list;
100 static struct name_list *dp_exclude_list;
102 static struct parameter_list *path_select_list = NULL;
104 /* Linked list of mounted filesystems. */
105 static struct mount_entry *mount_list;
107 /* For long options that have no equivalent short option, use a
108 non-character as a pseudo short option, starting with CHAR_MAX + 1. */
109 enum
110 {
111 SYNC_OPTION = CHAR_MAX + 1,
112 NO_SYNC_OPTION,
113 BLOCK_SIZE_OPTION
114 };
116 #ifdef _AIX
117 #pragma alloca
118 #endif
120 /* Linked list of mounted filesystems. */
121 static struct mount_entry *mount_list;
123 int process_arguments (int, char **);
124 void print_path (const char *mypath);
125 void set_all_thresholds (struct parameter_list *path);
126 int validate_arguments (uintmax_t, uintmax_t, double, double, double, double, char *);
127 void print_help (void);
128 void print_usage (void);
129 double calculate_percent(uintmax_t, uintmax_t);
131 double w_dfp = -1.0;
132 double c_dfp = -1.0;
133 char *path;
134 char *exclude_device;
135 char *units;
136 uintmax_t mult = 1024 * 1024;
137 int verbose = 0;
138 int erronly = FALSE;
139 int display_mntp = FALSE;
140 int exact_match = FALSE;
141 char *warn_freespace_units = NULL;
142 char *crit_freespace_units = NULL;
143 char *warn_freespace_percent = NULL;
144 char *crit_freespace_percent = NULL;
145 char *warn_usedspace_units = NULL;
146 char *crit_usedspace_units = NULL;
147 char *warn_usedspace_percent = NULL;
148 char *crit_usedspace_percent = NULL;
149 char *warn_usedinodes_percent = NULL;
150 char *crit_usedinodes_percent = NULL;
151 char *warn_freeinodes_percent = NULL;
152 char *crit_freeinodes_percent = NULL;
153 bool path_selected = false;
154 char *group = NULL;
157 int
158 main (int argc, char **argv)
159 {
160 int result = STATE_UNKNOWN;
161 int disk_result = STATE_UNKNOWN;
162 char *output;
163 char *details;
164 char *perf;
165 char *preamble;
166 double inode_space_pct;
167 uintmax_t total, available, available_to_root, used;
168 double dfree_pct = -1, dused_pct = -1;
169 double dused_units, dfree_units, dtotal_units;
170 double dused_inodes_percent, dfree_inodes_percent;
171 double warning_high_tide;
172 double critical_high_tide;
173 int temp_result;
175 struct mount_entry *me;
176 struct fs_usage fsp, tmpfsp;
177 struct parameter_list *temp_list, *path;
178 struct name_list *seen = NULL;
179 struct stat *stat_buf;
181 preamble = strdup (" - free space:");
182 output = strdup ("");
183 details = strdup ("");
184 perf = strdup ("");
186 setlocale (LC_ALL, "");
187 bindtextdomain (PACKAGE, LOCALEDIR);
188 textdomain (PACKAGE);
190 mount_list = read_file_system_list (0);
192 if (process_arguments (argc, argv) == ERROR)
193 usage4 (_("Could not parse arguments"));
195 /* If a list of paths has not been selected, find entire
196 mount list and create list of paths
197 */
198 if (path_selected == false) {
199 for (me = mount_list; me; me = me->me_next) {
200 if (! (path = np_find_parameter(path_select_list, me->me_mountdir))) {
201 path = np_add_parameter(&path_select_list, me->me_mountdir);
202 }
203 path->best_match = me;
204 path->group = group;
205 set_all_thresholds(path);
206 }
207 }
208 np_set_best_match(path_select_list, mount_list, exact_match);
210 /* Error if no match found for specified paths */
211 temp_list = path_select_list;
213 stat_buf = malloc(sizeof *stat_buf);
214 while (temp_list) {
215 if (! temp_list->best_match) {
216 die (STATE_CRITICAL, _("DISK %s: %s not found\n"), _("CRITICAL"), temp_list->name);
217 }
219 /* Stat each entry to check that dir exists */
220 if (stat (temp_list->name, &stat_buf[0])) {
221 printf("DISK %s - ", _("CRITICAL"));
222 die (STATE_CRITICAL, _("%s %s: %s\n"), temp_list->name, _("is not accessible"), strerror(errno));
223 }
224 temp_list = temp_list->name_next;
225 }
226 free(stat_buf);
228 /* Process for every path in list */
229 for (path = path_select_list; path; path=path->name_next) {
231 if (verbose > 3 && path->freespace_percent->warning != NULL && path->freespace_percent->critical != NULL)
232 printf("Thresholds(pct) for %s warn: %f crit %f\n",path->name, path->freespace_percent->warning->end,
233 path->freespace_percent->critical->end);
235 if (verbose > 3 && path->group != NULL)
236 printf("Group of %s: %s\n",path->name,path->group);
238 /* reset disk result */
239 disk_result = STATE_UNKNOWN;
241 me = path->best_match;
243 /* Filters */
245 /* Remove filesystems already seen */
246 if (np_seen_name(seen, me->me_mountdir)) {
247 continue;
248 } else {
249 if (path->group != NULL) {
250 /* find all group members */
251 fsp.fsu_blocksize = 0;
252 fsp.fsu_blocks = 0;
253 fsp.fsu_bfree = 0;
254 fsp.fsu_bavail = 0;
255 fsp.fsu_files = 0;
256 fsp.fsu_ffree = 0;
259 for (temp_list = path_select_list; temp_list; temp_list=temp_list->name_next) {
260 if (temp_list->group && ! (strcmp(temp_list->group, path->group))) {
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 fsp.fsu_bavail += 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 continue;
290 /* Skip pseudo fs's if we haven't asked for all fs's */
291 } else if (me->me_dummy && !show_all_fs) {
292 continue;
293 /* Skip excluded fstypes */
294 } else if (fs_exclude_list && np_find_name (fs_exclude_list, me->me_type)) {
295 continue;
296 /* Skip excluded fs's */
297 } else if (dp_exclude_list &&
298 (np_find_name (dp_exclude_list, me->me_devname) ||
299 np_find_name (dp_exclude_list, me->me_mountdir))) {
300 continue;
301 }
303 get_fs_usage (me->me_mountdir, me->me_devname, &fsp);
304 }
306 if (fsp.fsu_blocks && strcmp ("none", me->me_mountdir)) {
307 total = fsp.fsu_blocks;
308 available = fsp.fsu_bavail;
309 available_to_root = fsp.fsu_bfree;
310 used = total - available_to_root;
312 dused_pct = calculate_percent( used, used + available ); /* used + available can never be > uintmax */
314 dfree_pct = 100 - dused_pct;
315 dused_units = used*fsp.fsu_blocksize/mult;
316 dfree_units = available*fsp.fsu_blocksize/mult;
317 dtotal_units = total*fsp.fsu_blocksize/mult;
318 dused_inodes_percent = calculate_percent(fsp.fsu_files - fsp.fsu_ffree, fsp.fsu_files);
319 dfree_inodes_percent = 100 - dused_inodes_percent;
321 if (verbose >= 3) {
322 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",
323 me->me_mountdir, dused_pct, dfree_pct, dused_units, dfree_units, dtotal_units, dused_inodes_percent, dfree_inodes_percent, fsp.fsu_blocksize, mult);
324 }
326 /* Threshold comparisons */
328 temp_result = get_status(dfree_units, path->freespace_units);
329 if (verbose >=3) printf("Freespace_units result=%d\n", temp_result);
330 disk_result = max_state( disk_result, temp_result );
332 temp_result = get_status(dfree_pct, path->freespace_percent);
333 if (verbose >=3) printf("Freespace%% result=%d\n", temp_result);
334 disk_result = max_state( disk_result, temp_result );
336 temp_result = get_status(dused_units, path->usedspace_units);
337 if (verbose >=3) printf("Usedspace_units result=%d\n", temp_result);
338 disk_result = max_state( disk_result, temp_result );
340 temp_result = get_status(dused_pct, path->usedspace_percent);
341 if (verbose >=3) printf("Usedspace_percent result=%d\n", temp_result);
342 disk_result = max_state( disk_result, temp_result );
344 temp_result = get_status(dused_inodes_percent, path->usedinodes_percent);
345 if (verbose >=3) printf("Usedinodes_percent result=%d\n", temp_result);
346 disk_result = max_state( disk_result, temp_result );
348 temp_result = get_status(dfree_inodes_percent, path->freeinodes_percent);
349 if (verbose >=3) printf("Freeinodes_percent result=%d\n", temp_result);
350 disk_result = max_state( disk_result, temp_result );
352 result = max_state(result, disk_result);
354 /* What a mess of units. The output shows free space, the perf data shows used space. Yikes!
355 Hack here. Trying to get warn/crit levels from freespace_(units|percent) for perf
356 data. Assumption that start=0. Roll on new syntax...
357 */
359 /* *_high_tide must be reinitialized at each run */
360 warning_high_tide = UINT_MAX;
361 critical_high_tide = UINT_MAX;
363 if (path->freespace_units->warning != NULL) {
364 warning_high_tide = dtotal_units - path->freespace_units->warning->end;
365 }
366 if (path->freespace_percent->warning != NULL) {
367 warning_high_tide = abs( min( (double) warning_high_tide, (double) (1.0 - path->freespace_percent->warning->end/100)*dtotal_units ));
368 }
369 if (path->freespace_units->critical != NULL) {
370 critical_high_tide = dtotal_units - path->freespace_units->critical->end;
371 }
372 if (path->freespace_percent->critical != NULL) {
373 critical_high_tide = abs( min( (double) critical_high_tide, (double) (1.0 - path->freespace_percent->critical->end/100)*dtotal_units ));
374 }
376 /* Nb: *_high_tide are unset when == UINT_MAX */
377 asprintf (&perf, "%s %s", perf,
378 perfdata ((!strcmp(me->me_mountdir, "none") || display_mntp) ? me->me_devname : me->me_mountdir,
379 dused_units, units,
380 (warning_high_tide != UINT_MAX ? TRUE : FALSE), warning_high_tide,
381 (critical_high_tide != UINT_MAX ? TRUE : FALSE), critical_high_tide,
382 TRUE, 0,
383 TRUE, dtotal_units));
385 if (disk_result==STATE_OK && erronly && !verbose)
386 continue;
388 asprintf (&output, "%s %s %.0f %s (%.0f%%",
389 output,
390 (!strcmp(me->me_mountdir, "none") || display_mntp) ? me->me_devname : me->me_mountdir,
391 dfree_units,
392 units,
393 dfree_pct);
394 if (dused_inodes_percent < 0) {
395 asprintf(&output, "%s inode=-);", output);
396 } else {
397 asprintf(&output, "%s inode=%.0f%%);", output, dfree_inodes_percent );
398 }
400 /* TODO: Need to do a similar debug line
401 asprintf (&details, _("%s\n\
402 %.0f of %.0f %s (%.0f%% inode=%.0f%%) free on %s (type %s mounted on %s) warn:%lu crit:%lu warn%%:%.0f%% crit%%:%.0f%%"),
403 details, dfree_units, dtotal_units, units, dfree_pct, inode_space_pct,
404 me->me_devname, me->me_type, me->me_mountdir,
405 (unsigned long)w_df, (unsigned long)c_df, w_dfp, c_dfp);
406 */
408 }
410 }
412 if (verbose > 2)
413 asprintf (&output, "%s%s", output, details);
416 printf ("DISK %s%s%s|%s\n", state_text (result), (erronly && result==STATE_OK) ? "" : preamble, output, perf);
417 return result;
418 }
421 double calculate_percent(uintmax_t value, uintmax_t total) {
422 double pct = -1;
423 /* I don't understand the below, but it is taken from coreutils' df */
424 /* Seems to be calculating pct, in the best possible way */
425 if (value <= TYPE_MAXIMUM(uintmax_t) / 100
426 && total != 0) {
427 uintmax_t u100 = value * 100;
428 pct = u100 / total + (u100 % total != 0);
429 } else {
430 /* Possible rounding errors - see coreutils' df for more explanation */
431 double u = value;
432 double t = total;
433 if (t) {
434 long int lipct = pct = u * 100 / t;
435 double ipct = lipct;
437 /* Like 'pct = ceil (dpct);', but without ceil - from coreutils again */
438 if (ipct - 1 < pct && pct <= ipct + 1)
439 pct = ipct + (ipct < pct);
440 }
441 }
442 return pct;
443 }
445 /* process command-line arguments */
446 int
447 process_arguments (int argc, char **argv)
448 {
449 int c, err;
450 struct parameter_list *se;
451 struct parameter_list *temp_list = NULL, *previous = NULL;
452 struct parameter_list *temp_path_select_list = NULL;
453 struct mount_entry *me, *temp_me;
454 int result = OK;
455 regex_t re;
456 int cflags = REG_NOSUB | REG_EXTENDED;
457 int default_cflags = cflags;
458 char errbuf[MAX_INPUT_BUFFER];
459 int fnd = 0;
461 int option = 0;
462 static struct option longopts[] = {
463 {"timeout", required_argument, 0, 't'},
464 {"warning", required_argument, 0, 'w'},
465 {"critical", required_argument, 0, 'c'},
466 {"iwarning", required_argument, 0, 'W'},
467 /* Dang, -C is taken. We might want to reshuffle this. */
468 {"icritical", required_argument, 0, 'K'},
469 {"local", required_argument, 0, 'l'},
470 {"kilobytes", required_argument, 0, 'k'},
471 {"megabytes", required_argument, 0, 'm'},
472 {"units", required_argument, 0, 'u'},
473 {"path", required_argument, 0, 'p'},
474 {"partition", required_argument, 0, 'p'},
475 {"exclude_device", required_argument, 0, 'x'},
476 {"exclude-type", required_argument, 0, 'X'},
477 {"group", required_argument, 0, 'g'},
478 {"eregi-path", required_argument, 0, 'R'},
479 {"eregi-partition", required_argument, 0, 'R'},
480 {"ereg-path", required_argument, 0, 'r'},
481 {"ereg-partition", required_argument, 0, 'r'},
482 {"ignore-ereg-path", required_argument, 0, 'i'},
483 {"ignore-ereg-partition", required_argument, 0, 'i'},
484 {"ignore-eregi-path", required_argument, 0, 'I'},
485 {"ignore-eregi-partition", required_argument, 0, 'I'},
486 {"mountpoint", no_argument, 0, 'M'},
487 {"errors-only", no_argument, 0, 'e'},
488 {"exact-match", no_argument, 0, 'E'},
489 {"all", no_argument, 0, 'A'},
490 {"verbose", no_argument, 0, 'v'},
491 {"quiet", no_argument, 0, 'q'},
492 {"clear", no_argument, 0, 'C'},
493 {"version", no_argument, 0, 'V'},
494 {"help", no_argument, 0, 'h'},
495 {0, 0, 0, 0}
496 };
498 if (argc < 2)
499 return ERROR;
501 np_add_name(&fs_exclude_list, "iso9660");
503 for (c = 1; c < argc; c++)
504 if (strcmp ("-to", argv[c]) == 0)
505 strcpy (argv[c], "-t");
507 while (1) {
508 c = getopt_long (argc, argv, "+?VqhveCt:c:w:K:W:u:p:x:X:mklg:R:r:i:I:MEA", longopts, &option);
510 if (c == -1 || c == EOF)
511 break;
513 switch (c) {
514 case 't': /* timeout period */
515 if (is_integer (optarg)) {
516 timeout_interval = atoi (optarg);
517 break;
518 }
519 else {
520 usage2 (_("Timeout interval must be a positive integer"), optarg);
521 }
523 /* See comments for 'c' */
524 case 'w': /* warning threshold */
525 if (strstr(optarg, "%")) {
526 if (*optarg == '@') {
527 warn_freespace_percent = optarg;
528 } else {
529 asprintf(&warn_freespace_percent, "@%s", optarg);
530 }
531 } else {
532 if (*optarg == '@') {
533 warn_freespace_units = optarg;
534 } else {
535 asprintf(&warn_freespace_units, "@%s", optarg);
536 }
537 }
538 break;
540 /* Awful mistake where the range values do not make sense. Normally,
541 you alert if the value is within the range, but since we are using
542 freespace, we have to alert if outside the range. Thus we artifically
543 force @ at the beginning of the range, so that it is backwards compatible
544 */
545 case 'c': /* critical threshold */
546 if (strstr(optarg, "%")) {
547 if (*optarg == '@') {
548 crit_freespace_percent = optarg;
549 } else {
550 asprintf(&crit_freespace_percent, "@%s", optarg);
551 }
552 } else {
553 if (*optarg == '@') {
554 crit_freespace_units = optarg;
555 } else {
556 asprintf(&crit_freespace_units, "@%s", optarg);
557 }
558 }
559 break;
561 case 'W': /* warning inode threshold */
562 if (*optarg == '@') {
563 warn_freeinodes_percent = optarg;
564 } else {
565 asprintf(&warn_freeinodes_percent, "@%s", optarg);
566 }
567 break;
568 case 'K': /* critical inode threshold */
569 if (*optarg == '@') {
570 crit_freeinodes_percent = optarg;
571 } else {
572 asprintf(&crit_freeinodes_percent, "@%s", optarg);
573 }
574 break;
575 case 'u':
576 if (units)
577 free(units);
578 if (! strcmp (optarg, "bytes")) {
579 mult = (uintmax_t)1;
580 units = strdup ("B");
581 } else if (! strcmp (optarg, "kB")) {
582 mult = (uintmax_t)1024;
583 units = strdup ("kB");
584 } else if (! strcmp (optarg, "MB")) {
585 mult = (uintmax_t)1024 * 1024;
586 units = strdup ("MB");
587 } else if (! strcmp (optarg, "GB")) {
588 mult = (uintmax_t)1024 * 1024 * 1024;
589 units = strdup ("GB");
590 } else if (! strcmp (optarg, "TB")) {
591 mult = (uintmax_t)1024 * 1024 * 1024 * 1024;
592 units = strdup ("TB");
593 } else {
594 die (STATE_UNKNOWN, _("unit type %s not known\n"), optarg);
595 }
596 if (units == NULL)
597 die (STATE_UNKNOWN, _("failed allocating storage for '%s'\n"), "units");
598 break;
599 case 'k': /* display mountpoint */
600 mult = 1024;
601 if (units)
602 free(units);
603 units = strdup ("kB");
604 break;
605 case 'm': /* display mountpoint */
606 mult = 1024 * 1024;
607 if (units)
608 free(units);
609 units = strdup ("MB");
610 break;
611 case 'l':
612 show_local_fs = 1;
613 break;
614 case 'p': /* select path */
615 if (! (warn_freespace_units || crit_freespace_units || warn_freespace_percent ||
616 crit_freespace_percent || warn_usedspace_units || crit_usedspace_units ||
617 warn_usedspace_percent || crit_usedspace_percent || warn_usedinodes_percent ||
618 crit_usedinodes_percent || warn_freeinodes_percent || crit_freeinodes_percent )) {
619 die (STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set a threshold value before using -p\n"));
620 }
622 /* add parameter if not found. overwrite thresholds if path has already been added */
623 if (! (se = np_find_parameter(path_select_list, optarg))) {
624 se = np_add_parameter(&path_select_list, optarg);
625 }
626 se->group = group;
627 set_all_thresholds(se);
628 np_set_best_match(se, mount_list, exact_match);
629 path_selected = true;
630 break;
631 case 'x': /* exclude path or partition */
632 np_add_name(&dp_exclude_list, optarg);
633 break;
634 case 'X': /* exclude file system type */
635 np_add_name(&fs_exclude_list, optarg);
636 break;
637 case 'v': /* verbose */
638 verbose++;
639 break;
640 case 'q': /* TODO: this function should eventually go away (removed 2007-09-20) */
641 /* verbose--; **replaced by line below**. -q was only a broken way of implementing -e */
642 erronly = TRUE;
643 break;
644 case 'e':
645 erronly = TRUE;
646 break;
647 case 'E':
648 if (path_selected)
649 die (STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set -E before selecting pathes\n"));
650 exact_match = TRUE;
651 break;
652 case 'g':
653 if (path_selected)
654 die (STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set group value before selecting pathes \n"));
655 group = optarg;
656 break;
657 case 'I':
658 cflags |= REG_ICASE;
659 case 'i':
660 if (!path_selected)
661 die (STATE_UNKNOWN, "DISK %s: %s\n", _("UNKNOWN"), _("Pathes need to be selected before using -i/-I. Use -A to select all pathes explicitly"));
662 err = regcomp(&re, optarg, cflags);
663 if (err != 0) {
664 regerror (err, &re, errbuf, MAX_INPUT_BUFFER);
665 die (STATE_UNKNOWN, "DISK %s: %s - %s\n",_("UNKNOWN"), _("Could not compile regular expression"), errbuf);
666 }
668 temp_list = path_select_list;
670 previous = NULL;
671 while (temp_list) {
672 if (temp_list->best_match) {
673 if (np_regex_match_mount_entry(temp_list->best_match, &re)) {
675 if (verbose >=3)
676 printf("ignoring %s matching regex\n", temp_list->name);
678 temp_list = np_del_parameter(temp_list, previous);
679 /* pointer to first element needs to be uĆ¼dated if first item gets deleted */
680 if (previous == NULL)
681 path_select_list = temp_list;
682 } else {
683 previous = temp_list;
684 temp_list = temp_list->name_next;
685 }
686 } else {
687 previous = temp_list;
688 temp_list = temp_list->name_next;
689 }
690 }
693 cflags = default_cflags;
694 break;
696 case 'A':
697 optarg = strdup(".*");
698 case 'R':
699 cflags |= REG_ICASE;
700 case 'r':
701 if (! (warn_freespace_units || crit_freespace_units || warn_freespace_percent ||
702 crit_freespace_percent || warn_usedspace_units || crit_usedspace_units ||
703 warn_usedspace_percent || crit_usedspace_percent || warn_usedinodes_percent ||
704 crit_usedinodes_percent || warn_freeinodes_percent || crit_freeinodes_percent )) {
705 die (STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set a threshold value before using -r/-R\n"));
706 }
708 err = regcomp(&re, optarg, cflags);
709 if (err != 0) {
710 regerror (err, &re, errbuf, MAX_INPUT_BUFFER);
711 die (STATE_UNKNOWN, "DISK %s: %s - %s\n",_("UNKNOWN"), _("Could not compile regular expression"), errbuf);
712 }
714 for (me = mount_list; me; me = me->me_next) {
715 if (np_regex_match_mount_entry(me, &re)) {
716 fnd = true;
717 if (verbose > 3)
718 printf("%s %s matching expression %s\n", me->me_devname, me->me_mountdir, optarg);
720 /* add parameter if not found. overwrite thresholds if path has already been added */
721 if (! (se = np_find_parameter(path_select_list, me->me_mountdir))) {
722 se = np_add_parameter(&path_select_list, me->me_mountdir);
723 }
724 se->group = group;
725 set_all_thresholds(se);
726 }
727 }
729 if (!fnd)
730 die (STATE_UNKNOWN, "DISK %s: %s - %s\n",_("UNKNOWN"),
731 _("Regular expression did not match any path or disk"), optarg);
733 fnd = false;
734 path_selected = true;
735 np_set_best_match(path_select_list, mount_list, exact_match);
736 cflags = default_cflags;
738 break;
739 case 'M': /* display mountpoint */
740 display_mntp = TRUE;
741 break;
742 case 'C':
743 /* add all mount entries to path_select list if no partitions have been explicitly defined using -p */
744 if (path_selected == false) {
745 struct mount_entry *me;
746 struct parameter_list *path;
747 for (me = mount_list; me; me = me->me_next) {
748 if (! (path = np_find_parameter(path_select_list, me->me_mountdir)))
749 path = np_add_parameter(&path_select_list, me->me_mountdir);
750 path->best_match = me;
751 path->group = group;
752 set_all_thresholds(path);
753 }
754 }
755 warn_freespace_units = NULL;
756 crit_freespace_units = NULL;
757 warn_usedspace_units = NULL;
758 crit_usedspace_units = NULL;
759 warn_freespace_percent = NULL;
760 crit_freespace_percent = NULL;
761 warn_usedspace_percent = NULL;
762 crit_usedspace_percent = NULL;
763 warn_usedinodes_percent = NULL;
764 crit_usedinodes_percent = NULL;
765 warn_freeinodes_percent = NULL;
766 crit_freeinodes_percent = NULL;
768 path_selected = false;
769 group = NULL;
770 break;
771 case 'V': /* version */
772 print_revision (progname, revision);
773 exit (STATE_OK);
774 case 'h': /* help */
775 print_help ();
776 exit (STATE_OK);
777 case '?': /* help */
778 usage (_("Unknown argument"));
779 }
780 }
782 /* Support for "check_disk warn crit [fs]" with thresholds at used% level */
783 c = optind;
784 if (warn_usedspace_percent == NULL && argc > c && is_intnonneg (argv[c]))
785 warn_usedspace_percent = argv[c++];
787 if (crit_usedspace_percent == NULL && argc > c && is_intnonneg (argv[c]))
788 crit_usedspace_percent = argv[c++];
790 if (argc > c && path == NULL) {
791 se = np_add_parameter(&path_select_list, strdup(argv[c++]));
792 path_selected = true;
793 set_all_thresholds(se);
794 }
796 if (units == NULL) {
797 units = strdup ("MB");
798 mult = (uintmax_t)1024 * 1024;
799 }
801 return TRUE;
802 }
806 void
807 print_path (const char *mypath)
808 {
809 if (mypath == NULL)
810 printf ("\n");
811 else
812 printf (_(" for %s\n"), mypath);
813 }
816 void
817 set_all_thresholds (struct parameter_list *path)
818 {
819 set_thresholds(&path->freespace_units, warn_freespace_units, crit_freespace_units);
820 set_thresholds(&path->freespace_percent, warn_freespace_percent, crit_freespace_percent);
821 set_thresholds(&path->usedspace_units, warn_usedspace_units, crit_usedspace_units);
822 set_thresholds(&path->usedspace_percent, warn_usedspace_percent, crit_usedspace_percent);
823 set_thresholds(&path->usedinodes_percent, warn_usedinodes_percent, crit_usedinodes_percent);
824 set_thresholds(&path->freeinodes_percent, warn_freeinodes_percent, crit_freeinodes_percent);
825 }
827 /* TODO: Remove?
829 int
830 validate_arguments (uintmax_t w, uintmax_t c, double wp, double cp, double iwp, double icp, char *mypath)
831 {
832 if (w < 0 && c < 0 && wp < 0.0 && cp < 0.0) {
833 printf (_("INPUT ERROR: No thresholds specified"));
834 print_path (mypath);
835 return ERROR;
836 }
837 else if ((wp >= 0.0 || cp >= 0.0) &&
838 (wp < 0.0 || cp < 0.0 || wp > 100.0 || cp > 100.0 || cp > wp)) {
839 printf (_("\
840 INPUT ERROR: C_DFP (%f) should be less than W_DFP (%.1f) and both should be between zero and 100 percent, inclusive"),
841 cp, wp);
842 print_path (mypath);
843 return ERROR;
844 }
845 else if ((iwp >= 0.0 || icp >= 0.0) &&
846 (iwp < 0.0 || icp < 0.0 || iwp > 100.0 || icp > 100.0 || icp > iwp)) {
847 printf (_("\
848 INPUT ERROR: C_IDFP (%f) should be less than W_IDFP (%.1f) and both should be between zero and 100 percent, inclusive"),
849 icp, iwp);
850 print_path (mypath);
851 return ERROR;
852 }
853 else if ((w > 0 || c > 0) && (w == 0 || c == 0 || c > w)) {
854 printf (_("\
855 INPUT ERROR: C_DF (%lu) should be less than W_DF (%lu) and both should be greater than zero"),
856 (unsigned long)c, (unsigned long)w);
857 print_path (mypath);
858 return ERROR;
859 }
861 return OK;
862 }
864 */
872 void
873 print_help (void)
874 {
875 print_revision (progname, revision);
877 printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
878 printf (COPYRIGHT, copyright, email);
880 printf ("%s\n", _("This plugin checks the amount of used disk space on a mounted file system"));
881 printf ("%s\n", _("and generates an alert if free space is less than one of the threshold values"));
883 printf ("\n\n");
885 print_usage ();
887 printf (_(UT_HELP_VRSN));
889 printf (" %s\n", "-w, --warning=INTEGER");
890 printf (" %s\n", _("Exit with WARNING status if less than INTEGER units of disk are free"));
891 printf (" %s\n", "-w, --warning=PERCENT%");
892 printf (" %s\n", _("Exit with WARNING status if less than PERCENT of disk space is free"));
893 printf (" %s\n", "-c, --critical=INTEGER");
894 printf (" %s\n", _("Exit with CRITICAL status if less than INTEGER units of disk are free"));
895 printf (" %s\n", "-c, --critical=PERCENT%");
896 printf (" %s\n", _("Exit with CRITCAL status if less than PERCENT of disk space is free"));
897 printf (" %s\n", "-W, --iwarning=PERCENT%");
898 printf (" %s\n", _("Exit with WARNING status if less than PERCENT of inode space is free"));
899 printf (" %s\n", "-K, --icritical=PERCENT%");
900 printf (" %s\n", _("Exit with CRITICAL status if less than PERCENT of inode space is free"));
901 printf (" %s\n", "-p, --path=PATH, --partition=PARTITION");
902 printf (" %s\n", _("Path or partition (may be repeated)"));
903 printf (" %s\n", "-x, --exclude_device=PATH <STRING>");
904 printf (" %s\n", _("Ignore device (only works if -p unspecified)"));
905 printf (" %s\n", "-C, --clear");
906 printf (" %s\n", _("Clear thresholds"));
907 printf (" %s\n", "-E, --exact-match");
908 printf (" %s\n", _("For paths or partitions specified with -p, only check for exact paths"));
909 printf (" %s\n", "-e, --errors-only");
910 printf (" %s\n", _("Display only devices/mountpoints with errors"));
911 printf (" %s\n", "-g, --group=NAME");
912 printf (" %s\n", _("Group pathes. Thresholds apply to (free-)space of all partitions together"));
913 printf (" %s\n", "-k, --kilobytes");
914 printf (" %s\n", _("Same as '--units kB'"));
915 printf (" %s\n", "-l, --local");
916 printf (" %s\n", _("Only check local filesystems"));
917 printf (" %s\n", "-M, --mountpoint");
918 printf (" %s\n", _("Display the mountpoint instead of the partition"));
919 printf (" %s\n", "-m, --megabytes");
920 printf (" %s\n", _("Same as '--units MB'"));
921 printf (" %s\n", "-A, --all");
922 printf (" %s\n", _("Explicitly select all pathes. This is equivalent to -R '.*'"));
923 printf (" %s\n", "-R, --eregi-path=PATH, --eregi-partition=PARTITION");
924 printf (" %s\n", _("Case insensitive regular expression for path/partition (may be repeated)"));
925 printf (" %s\n", "-r, --ereg-path=PATH, --ereg-partition=PARTITION");
926 printf (" %s\n", _("Regular expression for path or partition (may be repeated)"));
927 printf (" %s\n", "-I, --ignore-eregi-path=PATH, --ignore-eregi-partition=PARTITION");
928 printf (" %s\n", _("Regular expression to ignore selected path/partition (case insensitive) (may be repeated)"));
929 printf (" %s\n", "-i, --ignore-ereg-path=PATH, --ignore-ereg-partition=PARTITION");
930 printf (" %s\n", _("Regular expression to ignore selected path or partition (may be repeated)"));
931 printf (_(UT_TIMEOUT), DEFAULT_SOCKET_TIMEOUT);
932 printf (" %s\n", "-u, --units=STRING");
933 printf (" %s\n", _("Choose bytes, kB, MB, GB, TB (default: MB)"));
934 printf (_(UT_VERBOSE));
935 printf (" %s\n", "-X, --exclude-type=TYPE");
936 printf (" %s\n", _("Ignore all filesystems of indicated type (may be repeated)"));
937 printf ("\n");
938 printf ("%s\n", _("Examples:"));
939 printf (" %s\n", "check_disk -w 10% -c 5% -p /tmp -p /var -C -w 100000 -c 50000 -p /");
940 printf (" %s\n", _("Checks /tmp and /var at 10% and 5%, and / at 100MB and 50MB"));
941 printf (" %s\n", "check_disk -w 100M -c 50M -C -w 1000M -c 500M -g sidDATA -r '^/oracle/SID/data.*$'");
942 printf (" %s\n", _("Checks all filesystems not matching -r at 100M and 50M. The fs matching the -r regex"));
943 printf (" %s\n", _("are grouped which means the freespace thresholds are applied to all disks together"));
944 printf (" %s\n", "check_disk -w 100M -c 50M -C -w 1000M -c 500M -p /foo -C -w 5% -c 3% -p /bar");
945 printf (" %s\n", _("Checks /foo for 1000M/500M and /bar for 5/3%. All remaining volumes use 100M/50M"));
946 printf (_(UT_SUPPORT));
947 }
951 void
952 print_usage (void)
953 {
954 printf (_("Usage:"));
955 printf (" %s -w limit -c limit [-W limit] [-K limit] {-p path | -x device}\n", progname);
956 printf ("[-C] [-E] [-e] [-g group ] [-k] [-l] [-M] [-m] [-R path ] [-r path ]\n");
957 printf ("[-t timeout] [-u unit] [-v] [-X type]\n");
958 }