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=%lu mult=%lu\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, *se2;
451 struct parameter_list *temp_list;
452 struct parameter_list *temp_path_select_list = NULL;
453 struct mount_entry *me;
454 int result = OK;
455 regex_t re;
456 int cflags = REG_NOSUB | REG_EXTENDED;
457 char errbuf[MAX_INPUT_BUFFER];
458 bool fnd = false;
460 int option = 0;
461 static struct option longopts[] = {
462 {"timeout", required_argument, 0, 't'},
463 {"warning", required_argument, 0, 'w'},
464 {"critical", required_argument, 0, 'c'},
465 {"iwarning", required_argument, 0, 'W'},
466 /* Dang, -C is taken. We might want to reshuffle this. */
467 {"icritical", required_argument, 0, 'K'},
468 {"local", required_argument, 0, 'l'},
469 {"kilobytes", required_argument, 0, 'k'},
470 {"megabytes", required_argument, 0, 'm'},
471 {"units", required_argument, 0, 'u'},
472 {"path", required_argument, 0, 'p'},
473 {"partition", required_argument, 0, 'p'},
474 {"exclude_device", required_argument, 0, 'x'},
475 {"exclude-type", required_argument, 0, 'X'},
476 {"group", required_argument, 0, 'g'},
477 {"eregi-path", required_argument, 0, 'R'},
478 {"eregi-partition", required_argument, 0, 'R'},
479 {"ereg-path", required_argument, 0, 'r'},
480 {"ereg-partition", required_argument, 0, 'r'},
481 {"mountpoint", no_argument, 0, 'M'},
482 {"errors-only", no_argument, 0, 'e'},
483 {"exact-match", no_argument, 0, 'E'},
484 {"verbose", no_argument, 0, 'v'},
485 {"quiet", no_argument, 0, 'q'},
486 {"clear", no_argument, 0, 'C'},
487 {"version", no_argument, 0, 'V'},
488 {"help", no_argument, 0, 'h'},
489 {0, 0, 0, 0}
490 };
492 if (argc < 2)
493 return ERROR;
495 np_add_name(&fs_exclude_list, "iso9660");
497 for (c = 1; c < argc; c++)
498 if (strcmp ("-to", argv[c]) == 0)
499 strcpy (argv[c], "-t");
501 while (1) {
502 c = getopt_long (argc, argv, "+?VqhveCt:c:w:K:W:u:p:x:X:mklg:R:r:ME", longopts, &option);
504 if (c == -1 || c == EOF)
505 break;
507 switch (c) {
508 case 't': /* timeout period */
509 if (is_integer (optarg)) {
510 timeout_interval = atoi (optarg);
511 break;
512 }
513 else {
514 usage2 (_("Timeout interval must be a positive integer"), optarg);
515 }
517 /* See comments for 'c' */
518 case 'w': /* warning threshold */
519 if (strstr(optarg, "%")) {
520 if (*optarg == '@') {
521 warn_freespace_percent = optarg;
522 } else {
523 asprintf(&warn_freespace_percent, "@%s", optarg);
524 }
525 } else {
526 if (*optarg == '@') {
527 warn_freespace_units = optarg;
528 } else {
529 asprintf(&warn_freespace_units, "@%s", optarg);
530 }
531 }
532 break;
534 /* Awful mistake where the range values do not make sense. Normally,
535 you alert if the value is within the range, but since we are using
536 freespace, we have to alert if outside the range. Thus we artifically
537 force @ at the beginning of the range, so that it is backwards compatible
538 */
539 case 'c': /* critical threshold */
540 if (strstr(optarg, "%")) {
541 if (*optarg == '@') {
542 crit_freespace_percent = optarg;
543 } else {
544 asprintf(&crit_freespace_percent, "@%s", optarg);
545 }
546 } else {
547 if (*optarg == '@') {
548 crit_freespace_units = optarg;
549 } else {
550 asprintf(&crit_freespace_units, "@%s", optarg);
551 }
552 }
553 break;
555 case 'W': /* warning inode threshold */
556 if (*optarg == '@') {
557 warn_freeinodes_percent = optarg;
558 } else {
559 asprintf(&warn_freeinodes_percent, "@%s", optarg);
560 }
561 break;
562 case 'K': /* critical inode threshold */
563 if (*optarg == '@') {
564 crit_freeinodes_percent = optarg;
565 } else {
566 asprintf(&crit_freeinodes_percent, "@%s", optarg);
567 }
568 break;
569 case 'u':
570 if (units)
571 free(units);
572 if (! strcmp (optarg, "bytes")) {
573 mult = (uintmax_t)1;
574 units = strdup ("B");
575 } else if (! strcmp (optarg, "kB")) {
576 mult = (uintmax_t)1024;
577 units = strdup ("kB");
578 } else if (! strcmp (optarg, "MB")) {
579 mult = (uintmax_t)1024 * 1024;
580 units = strdup ("MB");
581 } else if (! strcmp (optarg, "GB")) {
582 mult = (uintmax_t)1024 * 1024 * 1024;
583 units = strdup ("GB");
584 } else if (! strcmp (optarg, "TB")) {
585 mult = (uintmax_t)1024 * 1024 * 1024 * 1024;
586 units = strdup ("TB");
587 } else {
588 die (STATE_UNKNOWN, _("unit type %s not known\n"), optarg);
589 }
590 if (units == NULL)
591 die (STATE_UNKNOWN, _("failed allocating storage for '%s'\n"), "units");
592 break;
593 case 'k': /* display mountpoint */
594 mult = 1024;
595 if (units)
596 free(units);
597 units = strdup ("kB");
598 break;
599 case 'm': /* display mountpoint */
600 mult = 1024 * 1024;
601 if (units)
602 free(units);
603 units = strdup ("MB");
604 break;
605 case 'l':
606 show_local_fs = 1;
607 break;
608 case 'p': /* select path */
609 if (! (warn_freespace_units || crit_freespace_units || warn_freespace_percent ||
610 crit_freespace_percent || warn_usedspace_units || crit_usedspace_units ||
611 warn_usedspace_percent || crit_usedspace_percent || warn_usedinodes_percent ||
612 crit_usedinodes_percent || warn_freeinodes_percent || crit_freeinodes_percent )) {
613 die (STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set a threshold value before using -p\n"));
614 }
616 /* get the real mountdir of the specified path. np_find_parameter won't find an entry if -p is not
617 * exactly the same string as the mountdir */
618 se2 = np_add_parameter(&temp_path_select_list, optarg);
619 np_set_best_match(se2, mount_list, FALSE);
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 path_selected = true;
629 break;
630 case 'x': /* exclude path or partition */
631 np_add_name(&dp_exclude_list, optarg);
632 break;
633 case 'X': /* exclude file system type */
634 np_add_name(&fs_exclude_list, optarg);
635 break;
636 case 'v': /* verbose */
637 verbose++;
638 break;
639 case 'q': /* TODO: this function should eventually go away (removed 2007-09-20) */
640 /* verbose--; **replaced by line below**. -q was only a broken way of implementing -e */
641 erronly = TRUE;
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", "-c, --critical=INTEGER");
847 printf (" %s\n", _("Exit with CRITICAL status if less than INTEGER units of disk are free"));
848 printf (" %s\n", "-c, --critical=PERCENT%");
849 printf (" %s\n", _("Exit with CRITCAL status if less than PERCENT of disk space is free"));
850 printf (" %s\n", "-W, --iwarning=PERCENT%");
851 printf (" %s\n", _("Exit with WARNING status if less than PERCENT of inode space is free"));
852 printf (" %s\n", "-K, --icritical=PERCENT%");
853 printf (" %s\n", _("Exit with CRITICAL status if less than PERCENT of inode space is free"));
854 printf (" %s\n", "-p, --path=PATH, --partition=PARTITION");
855 printf (" %s\n", _("Path or partition (may be repeated)"));
856 printf (" %s\n", "-x, --exclude_device=PATH <STRING>");
857 printf (" %s\n", _("Ignore device (only works if -p unspecified)"));
858 printf (" %s\n", "-C, --clear");
859 printf (" %s\n", _("Clear thresholds"));
860 printf (" %s\n", "-E, --exact-match");
861 printf (" %s\n", _("For paths or partitions specified with -p, only check for exact paths"));
862 printf (" %s\n", "-e, --errors-only");
863 printf (" %s\n", _("Display only devices/mountpoints with errors"));
864 printf (" %s\n", "-g, --group=NAME");
865 printf (" %s\n", _("Group pathes. Thresholds apply to (free-)space of all partitions together"));
866 printf (" %s\n", "-k, --kilobytes");
867 printf (" %s\n", _("Same as '--units kB'"));
868 printf (" %s\n", "-l, --local");
869 printf (" %s\n", _("Only check local filesystems"));
870 printf (" %s\n", "-M, --mountpoint");
871 printf (" %s\n", _("Display the mountpoint instead of the partition"));
872 printf (" %s\n", "-m, --megabytes");
873 printf (" %s\n", _("Same as '--units MB'"));
874 printf (" %s\n", "-R, --eregi-path=PATH, --eregi-partition=PARTITION");
875 printf (" %s\n", _("Case insensitive regular expression for path/partition (may be repeated)"));
876 printf (" %s\n", "-r, --ereg-path=PATH, --ereg-partition=PARTITION");
877 printf (" %s\n", _("Regular expression for path or partition (may be repeated)"));
878 printf (_(UT_TIMEOUT), DEFAULT_SOCKET_TIMEOUT);
879 printf (" %s\n", "-u, --units=STRING");
880 printf (" %s\n", _("Choose bytes, kB, MB, GB, TB (default: MB)"));
881 printf (_(UT_VERBOSE));
882 printf (" %s\n", "-X, --exclude-type=TYPE");
883 printf (" %s\n", _("Ignore all filesystems of indicated type (may be repeated)"));
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 (" %s\n", "check_disk -w 100M -c 50M -C -w 1000M -c 500M -g sidDATA -r '^/oracle/SID/data.*$'");
889 printf (" %s\n", _("Checks all filesystems not matching -r at 100M and 50M. The fs matching the -r regex"));
890 printf (" %s\n", _("are grouped which means the freespace thresholds are applied to all disks together"));
891 printf (" %s\n", "check_disk -w 100M -c 50M -C -w 1000M -c 500M -p /foo -C -w 5% -c 3% -p /bar");
892 printf (" %s\n", _("Checks /foo for 1000M/500M and /bar for 5/3%. All remaining volumes use 100M/50M"));
893 printf (_(UT_SUPPORT));
894 }
898 void
899 print_usage (void)
900 {
901 printf (_("Usage:"));
902 printf (" %s -w limit -c limit [-W limit] [-K limit] {-p path | -x device}\n", progname);
903 printf ("[-C] [-E] [-e] [-g group ] [-k] [-l] [-M] [-m] [-R path ] [-r path ]\n");
904 printf ("[-t timeout] [-u unit] [-v] [-X type]\n");
905 }