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\n",
323 me->me_mountdir, dused_pct, dfree_pct, dused_units, dfree_units, dtotal_units, dused_inodes_percent, dfree_inodes_percent);
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 asprintf (&perf, "%s %s", perf,
377 perfdata ((!strcmp(me->me_mountdir, "none") || display_mntp) ? me->me_devname : me->me_mountdir,
378 dused_units, units,
379 (warning_high_tide != UINT_MAX ? TRUE : FALSE), warning_high_tide,
380 (critical_high_tide != UINT_MAX ? TRUE : FALSE), critical_high_tide,
381 TRUE, 0,
382 TRUE, dtotal_units));
384 if (disk_result==STATE_OK && erronly && !verbose)
385 continue;
387 if (disk_result!=STATE_OK || verbose>=0) {
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 }
399 }
401 /* TODO: Need to do a similar debug line
402 asprintf (&details, _("%s\n\
403 %.0f of %.0f %s (%.0f%% inode=%.0f%%) free on %s (type %s mounted on %s) warn:%lu crit:%lu warn%%:%.0f%% crit%%:%.0f%%"),
404 details, dfree_units, dtotal_units, units, dfree_pct, inode_space_pct,
405 me->me_devname, me->me_type, me->me_mountdir,
406 (unsigned long)w_df, (unsigned long)c_df, w_dfp, c_dfp);
407 */
409 }
411 }
413 if (verbose > 2)
414 asprintf (&output, "%s%s", output, details);
417 printf ("DISK %s%s%s|%s\n", state_text (result), (erronly && result==STATE_OK) ? "" : preamble, output, perf);
418 return result;
419 }
422 double calculate_percent(uintmax_t value, uintmax_t total) {
423 double pct = -1;
424 /* I don't understand the below, but it is taken from coreutils' df */
425 /* Seems to be calculating pct, in the best possible way */
426 if (value <= TYPE_MAXIMUM(uintmax_t) / 100
427 && total != 0) {
428 uintmax_t u100 = value * 100;
429 pct = u100 / total + (u100 % total != 0);
430 } else {
431 /* Possible rounding errors - see coreutils' df for more explanation */
432 double u = value;
433 double t = total;
434 if (t) {
435 long int lipct = pct = u * 100 / t;
436 double ipct = lipct;
438 /* Like 'pct = ceil (dpct);', but without ceil - from coreutils again */
439 if (ipct - 1 < pct && pct <= ipct + 1)
440 pct = ipct + (ipct < pct);
441 }
442 }
443 return pct;
444 }
446 /* process command-line arguments */
447 int
448 process_arguments (int argc, char **argv)
449 {
450 int c, err;
451 struct parameter_list *se, *se2;
452 struct parameter_list *temp_list;
453 struct parameter_list *temp_path_select_list = NULL;
454 struct mount_entry *me;
455 int result = OK;
456 regex_t re;
457 int cflags = REG_NOSUB | REG_EXTENDED;
458 char errbuf[MAX_INPUT_BUFFER];
459 bool fnd = false;
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 {"mountpoint", no_argument, 0, 'M'},
483 {"errors-only", no_argument, 0, 'e'},
484 {"exact-match", no_argument, 0, 'E'},
485 {"verbose", no_argument, 0, 'v'},
486 {"quiet", no_argument, 0, 'q'},
487 {"clear", no_argument, 0, 'C'},
488 {"version", no_argument, 0, 'V'},
489 {"help", no_argument, 0, 'h'},
490 {0, 0, 0, 0}
491 };
493 if (argc < 2)
494 return ERROR;
496 np_add_name(&fs_exclude_list, "iso9660");
498 for (c = 1; c < argc; c++)
499 if (strcmp ("-to", argv[c]) == 0)
500 strcpy (argv[c], "-t");
502 while (1) {
503 c = getopt_long (argc, argv, "+?VqhveCt:c:w:K:W:u:p:x:X:mklg:R:r:ME", longopts, &option);
505 if (c == -1 || c == EOF)
506 break;
508 switch (c) {
509 case 't': /* timeout period */
510 if (is_integer (optarg)) {
511 timeout_interval = atoi (optarg);
512 break;
513 }
514 else {
515 usage2 (_("Timeout interval must be a positive integer"), optarg);
516 }
518 /* See comments for 'c' */
519 case 'w': /* warning threshold */
520 if (strstr(optarg, "%")) {
521 if (*optarg == '@') {
522 warn_freespace_percent = optarg;
523 } else {
524 asprintf(&warn_freespace_percent, "@%s", optarg);
525 }
526 } else {
527 if (*optarg == '@') {
528 warn_freespace_units = optarg;
529 } else {
530 asprintf(&warn_freespace_units, "@%s", optarg);
531 }
532 }
533 break;
535 /* Awful mistake where the range values do not make sense. Normally,
536 you alert if the value is within the range, but since we are using
537 freespace, we have to alert if outside the range. Thus we artifically
538 force @ at the beginning of the range, so that it is backwards compatible
539 */
540 case 'c': /* critical threshold */
541 if (strstr(optarg, "%")) {
542 if (*optarg == '@') {
543 crit_freespace_percent = optarg;
544 } else {
545 asprintf(&crit_freespace_percent, "@%s", optarg);
546 }
547 } else {
548 if (*optarg == '@') {
549 crit_freespace_units = optarg;
550 } else {
551 asprintf(&crit_freespace_units, "@%s", optarg);
552 }
553 }
554 break;
556 case 'W': /* warning inode threshold */
557 if (*optarg == '@') {
558 warn_freeinodes_percent = optarg;
559 } else {
560 asprintf(&warn_freeinodes_percent, "@%s", optarg);
561 }
562 break;
563 case 'K': /* critical inode threshold */
564 if (*optarg == '@') {
565 crit_freeinodes_percent = optarg;
566 } else {
567 asprintf(&crit_freeinodes_percent, "@%s", optarg);
568 }
569 break;
570 case 'u':
571 if (units)
572 free(units);
573 if (! strcmp (optarg, "bytes")) {
574 mult = (uintmax_t)1;
575 units = strdup ("B");
576 } else if (! strcmp (optarg, "kB")) {
577 mult = (uintmax_t)1024;
578 units = strdup ("kB");
579 } else if (! strcmp (optarg, "MB")) {
580 mult = (uintmax_t)1024 * 1024;
581 units = strdup ("MB");
582 } else if (! strcmp (optarg, "GB")) {
583 mult = (uintmax_t)1024 * 1024 * 1024;
584 units = strdup ("GB");
585 } else if (! strcmp (optarg, "TB")) {
586 mult = (uintmax_t)1024 * 1024 * 1024 * 1024;
587 units = strdup ("TB");
588 } else {
589 die (STATE_UNKNOWN, _("unit type %s not known\n"), optarg);
590 }
591 if (units == NULL)
592 die (STATE_UNKNOWN, _("failed allocating storage for '%s'\n"), "units");
593 break;
594 case 'k': /* display mountpoint */
595 mult = 1024;
596 if (units)
597 free(units);
598 units = strdup ("kB");
599 break;
600 case 'm': /* display mountpoint */
601 mult = 1024 * 1024;
602 if (units)
603 free(units);
604 units = strdup ("MB");
605 break;
606 case 'l':
607 show_local_fs = 1;
608 break;
609 case 'p': /* select path */
610 if (! (warn_freespace_units || crit_freespace_units || warn_freespace_percent ||
611 crit_freespace_percent || warn_usedspace_units || crit_usedspace_units ||
612 warn_usedspace_percent || crit_usedspace_percent || warn_usedinodes_percent ||
613 crit_usedinodes_percent || warn_freeinodes_percent || crit_freeinodes_percent )) {
614 die (STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set a threshold value before using -p\n"));
615 }
617 /* get the real mountdir of the specified path. np_find_parameter won't find an entry if -p is not
618 * exactly the same string as the mountdir */
619 se2 = np_add_parameter(&temp_path_select_list, optarg);
620 np_set_best_match(se2, mount_list, FALSE);
623 /* add parameter if not found. overwrite thresholds if path has already been added */
624 if (! (se = np_find_parameter(path_select_list, optarg))) {
625 se = np_add_parameter(&path_select_list, optarg);
626 }
627 se->group = group;
628 set_all_thresholds(se);
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': /* verbose */
641 verbose--;
642 break;
643 case 'e':
644 erronly = TRUE;
645 break;
646 case 'E':
647 exact_match = TRUE;
648 break;
649 case 'g':
650 if (path_selected)
651 die (STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set group value before using -p\n"));
652 group = optarg;
653 break;
654 case 'R':
655 cflags |= REG_ICASE;
656 case 'r':
657 if (! (warn_freespace_units || crit_freespace_units || warn_freespace_percent ||
658 crit_freespace_percent || warn_usedspace_units || crit_usedspace_units ||
659 warn_usedspace_percent || crit_usedspace_percent || warn_usedinodes_percent ||
660 crit_usedinodes_percent || warn_freeinodes_percent || crit_freeinodes_percent )) {
661 die (STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set a threshold value before using -r/-R\n"));
662 }
664 err = regcomp(&re, optarg, cflags);
665 if (err != 0) {
666 regerror (err, &re, errbuf, MAX_INPUT_BUFFER);
667 die (STATE_UNKNOWN, "DISK %s: %s - %s\n",_("UNKNOWN"), _("Could not compile regular expression"), errbuf);
668 }
670 for (me = mount_list; me; me = me->me_next) {
671 if (np_regex_match_mount_entry(me, &re)) {
672 fnd = true;
673 if (verbose > 3)
674 printf("%s %s matching expression %s\n", me->me_devname, me->me_mountdir, optarg);
676 /* add parameter if not found. overwrite thresholds if path has already been added */
677 if (! (se = np_find_parameter(path_select_list, me->me_mountdir))) {
678 se = np_add_parameter(&path_select_list, me->me_mountdir);
679 }
680 se->group = group;
681 set_all_thresholds(se);
682 }
683 }
685 if (!fnd)
686 die (STATE_UNKNOWN, "DISK %s: %s - %s\n",_("UNKNOWN"),
687 _("Regular expression did not match any path or disk"), optarg);
689 fnd = false;
690 path_selected = true;
691 break;
692 case 'M': /* display mountpoint */
693 display_mntp = TRUE;
694 break;
695 case 'C':
696 /* add all mount entries to path_select list if no partitions have been explicitly defined using -p */
697 if (path_selected == false) {
698 struct mount_entry *me;
699 struct parameter_list *path;
700 for (me = mount_list; me; me = me->me_next) {
701 if (! (path = np_find_parameter(path_select_list, me->me_mountdir)))
702 path = np_add_parameter(&path_select_list, me->me_mountdir);
703 path->best_match = me;
704 path->group = group;
705 set_all_thresholds(path);
706 }
707 }
708 warn_freespace_units = NULL;
709 crit_freespace_units = NULL;
710 warn_usedspace_units = NULL;
711 crit_usedspace_units = NULL;
712 warn_freespace_percent = NULL;
713 crit_freespace_percent = NULL;
714 warn_usedspace_percent = NULL;
715 crit_usedspace_percent = NULL;
716 warn_usedinodes_percent = NULL;
717 crit_usedinodes_percent = NULL;
718 warn_freeinodes_percent = NULL;
719 crit_freeinodes_percent = NULL;
721 path_selected = false;
722 group = NULL;
723 break;
724 case 'V': /* version */
725 print_revision (progname, revision);
726 exit (STATE_OK);
727 case 'h': /* help */
728 print_help ();
729 exit (STATE_OK);
730 case '?': /* help */
731 usage (_("Unknown argument"));
732 }
733 }
735 /* Support for "check_disk warn crit [fs]" with thresholds at used% level */
736 c = optind;
737 if (warn_usedspace_percent == NULL && argc > c && is_intnonneg (argv[c]))
738 warn_usedspace_percent = argv[c++];
740 if (crit_usedspace_percent == NULL && argc > c && is_intnonneg (argv[c]))
741 crit_usedspace_percent = argv[c++];
743 if (argc > c && path == NULL) {
744 se = np_add_parameter(&path_select_list, strdup(argv[c++]));
745 path_selected = true;
746 set_all_thresholds(se);
747 }
749 if (units == NULL) {
750 units = strdup ("MB");
751 mult = (uintmax_t)1024 * 1024;
752 }
754 return TRUE;
755 }
759 void
760 print_path (const char *mypath)
761 {
762 if (mypath == NULL)
763 printf ("\n");
764 else
765 printf (_(" for %s\n"), mypath);
766 }
769 void
770 set_all_thresholds (struct parameter_list *path)
771 {
772 set_thresholds(&path->freespace_units, warn_freespace_units, crit_freespace_units);
773 set_thresholds(&path->freespace_percent, warn_freespace_percent, crit_freespace_percent);
774 set_thresholds(&path->usedspace_units, warn_usedspace_units, crit_usedspace_units);
775 set_thresholds(&path->usedspace_percent, warn_usedspace_percent, crit_usedspace_percent);
776 set_thresholds(&path->usedinodes_percent, warn_usedinodes_percent, crit_usedinodes_percent);
777 set_thresholds(&path->freeinodes_percent, warn_freeinodes_percent, crit_freeinodes_percent);
778 }
780 /* TODO: Remove?
782 int
783 validate_arguments (uintmax_t w, uintmax_t c, double wp, double cp, double iwp, double icp, char *mypath)
784 {
785 if (w < 0 && c < 0 && wp < 0.0 && cp < 0.0) {
786 printf (_("INPUT ERROR: No thresholds specified"));
787 print_path (mypath);
788 return ERROR;
789 }
790 else if ((wp >= 0.0 || cp >= 0.0) &&
791 (wp < 0.0 || cp < 0.0 || wp > 100.0 || cp > 100.0 || cp > wp)) {
792 printf (_("\
793 INPUT ERROR: C_DFP (%f) should be less than W_DFP (%.1f) and both should be between zero and 100 percent, inclusive"),
794 cp, wp);
795 print_path (mypath);
796 return ERROR;
797 }
798 else if ((iwp >= 0.0 || icp >= 0.0) &&
799 (iwp < 0.0 || icp < 0.0 || iwp > 100.0 || icp > 100.0 || icp > iwp)) {
800 printf (_("\
801 INPUT ERROR: C_IDFP (%f) should be less than W_IDFP (%.1f) and both should be between zero and 100 percent, inclusive"),
802 icp, iwp);
803 print_path (mypath);
804 return ERROR;
805 }
806 else if ((w > 0 || c > 0) && (w == 0 || c == 0 || c > w)) {
807 printf (_("\
808 INPUT ERROR: C_DF (%lu) should be less than W_DF (%lu) and both should be greater than zero"),
809 (unsigned long)c, (unsigned long)w);
810 print_path (mypath);
811 return ERROR;
812 }
814 return OK;
815 }
817 */
825 void
826 print_help (void)
827 {
828 print_revision (progname, revision);
830 printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
831 printf (COPYRIGHT, copyright, email);
833 printf ("%s\n", _("This plugin checks the amount of used disk space on a mounted file system"));
834 printf ("%s\n", _("and generates an alert if free space is less than one of the threshold values"));
836 printf ("\n\n");
838 print_usage ();
840 printf (_(UT_HELP_VRSN));
842 printf (" %s\n", "-w, --warning=INTEGER");
843 printf (" %s\n", _("Exit with WARNING status if less than INTEGER units of disk are free"));
844 printf (" %s\n", "-w, --warning=PERCENT%");
845 printf (" %s\n", _("Exit with WARNING status if less than PERCENT of disk space is free"));
846 printf (" %s\n", "-W, --iwarning=PERCENT%");
847 printf (" %s\n", _("Exit with WARNING status if less than PERCENT of inode space is free"));
848 printf (" %s\n", "-K, --icritical=PERCENT%");
849 printf (" %s\n", _("Exit with CRITICAL status if less than PERCENT of inode space is free"));
850 printf (" %s\n", "-c, --critical=INTEGER");
851 printf (" %s\n", _("Exit with CRITICAL status if less than INTEGER units of disk are free"));
852 printf (" %s\n", "-c, --critical=PERCENT%");
853 printf (" %s\n", _("Exit with CRITCAL status if less than PERCENT of disk space is free"));
854 printf (" %s\n", "-C, --clear");
855 printf (" %s\n", _("Clear thresholds"));
856 printf (" %s\n", "-u, --units=STRING");
857 printf (" %s\n", _("Choose bytes, kB, MB, GB, TB (default: MB)"));
858 printf (" %s\n", "-k, --kilobytes");
859 printf (" %s\n", _("Same as '--units kB'"));
860 printf (" %s\n", "-m, --megabytes");
861 printf (" %s\n", _("Same as '--units MB'"));
862 printf (" %s\n", "-l, --local");
863 printf (" %s\n", _("Only check local filesystems"));
864 printf (" %s\n", "-p, --path=PATH, --partition=PARTITION");
865 printf (" %s\n", _("Path or partition (may be repeated)"));
866 printf (" %s\n", "-r, --ereg-path=PATH, --ereg-partition=PARTITION");
867 printf (" %s\n", _("Regular expression for path or partition (may be repeated)"));
868 printf (" %s\n", "-R, --eregi-path=PATH, --eregi-partition=PARTITION");
869 printf (" %s\n", _("Case insensitive regular expression for path/partition (may be repeated)"));
870 printf (" %s\n", "-g, --group=NAME");
871 printf (" %s\n", _("Group pathes. Thresholds apply to (free-)space of all partitions together"));
872 printf (" %s\n", "-x, --exclude_device=PATH <STRING>");
873 printf (" %s\n", _("Ignore device (only works if -p unspecified)"));
874 printf (" %s\n", "-X, --exclude-type=TYPE <STRING>");
875 printf (" %s\n", _("Ignore all filesystems of indicated type (may be repeated)"));
876 printf (" %s\n", "-M, --mountpoint");
877 printf (" %s\n", _("Display the mountpoint instead of the partition"));
878 printf (" %s\n", "-E, --exact-match");
879 printf (" %s\n", _("For paths or partitions specified with -p, only check for exact paths"));
880 printf (" %s\n", "-e, --errors-only");
881 printf (" %s\n", _("Display only devices/mountpoints with errors"));
882 printf (_(UT_TIMEOUT), DEFAULT_SOCKET_TIMEOUT);
883 printf (_(UT_VERBOSE));
884 printf ("\n");
885 printf ("%s\n", _("Examples:"));
886 printf (" %s\n", "check_disk -w 10% -c 5% -p /tmp -p /var -C -w 100000 -c 50000 -p /");
887 printf (" %s\n", _("Checks /tmp and /var at 10% and 5%, and / at 100MB and 50MB"));
888 printf (_(UT_SUPPORT));
889 }
893 void
894 print_usage (void)
895 {
896 printf (_("Usage:"));
897 printf (" %s -w limit -c limit [-p path | -x device] [-t timeout]", progname);
898 printf ("[-m] [-e] [-W limit] [-K limit] [-v] [-q] [-E]\n");
899 }