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;
180 preamble = strdup (" - free space:");
181 output = strdup ("");
182 details = strdup ("");
183 perf = strdup ("");
185 setlocale (LC_ALL, "");
186 bindtextdomain (PACKAGE, LOCALEDIR);
187 textdomain (PACKAGE);
189 mount_list = read_file_system_list (0);
191 if (process_arguments (argc, argv) == ERROR)
192 usage4 (_("Could not parse arguments"));
194 /* If a list of paths has not been selected, find entire
195 mount list and create list of paths
196 */
197 if (path_selected == false) {
198 for (me = mount_list; me; me = me->me_next) {
199 if (! (path = np_find_parameter(path_select_list, me->me_mountdir))) {
200 path = np_add_parameter(&path_select_list, me->me_mountdir);
201 }
202 path->best_match = me;
203 path->group = group;
204 set_all_thresholds(path);
205 }
206 }
207 np_set_best_match(path_select_list, mount_list, exact_match);
209 /* Error if no match found for specified paths */
210 temp_list = path_select_list;
211 while (temp_list) {
212 if (! temp_list->best_match) {
213 die (STATE_CRITICAL, _("DISK %s: %s not found\n"), _("CRITICAL"), temp_list->name);
214 }
215 temp_list = temp_list->name_next;
216 }
219 /* Process for every path in list */
220 for (path = path_select_list; path; path=path->name_next) {
222 if (verbose > 3 && path->freespace_percent->warning != NULL && path->freespace_percent->critical != NULL)
223 printf("Thresholds(pct) for %s warn: %f crit %f\n",path->name, path->freespace_percent->warning->end,
224 path->freespace_percent->critical->end);
226 if (verbose > 3 && path->group != NULL)
227 printf("Group of %s: %s\n",path->name,path->group);
229 /* reset disk result */
230 disk_result = STATE_UNKNOWN;
232 me = path->best_match;
234 /* Filters */
236 /* Remove filesystems already seen */
237 if (np_seen_name(seen, me->me_mountdir)) {
238 continue;
239 } else {
240 if (path->group != NULL) {
241 /* find all group members */
242 fsp.fsu_blocksize = 0;
243 fsp.fsu_blocks = 0;
244 fsp.fsu_bfree = 0;
245 fsp.fsu_bavail = 0;
246 fsp.fsu_files = 0;
247 fsp.fsu_ffree = 0;
250 for (temp_list = path_select_list; temp_list; temp_list=temp_list->name_next) {
251 if (temp_list->group && ! (strcmp(temp_list->group, path->group))) {
253 get_fs_usage (temp_list->best_match->me_mountdir, temp_list->best_match->me_devname, &tmpfsp);
255 /* possibly differing blocksizes if disks are grouped. Calculating average */
256 fsp.fsu_blocksize = (fsp.fsu_blocksize * fsp.fsu_blocks + tmpfsp.fsu_blocksize * tmpfsp.fsu_blocks) / \
257 (fsp.fsu_blocks + tmpfsp.fsu_blocks); /* Size of a block. */
258 fsp.fsu_blocks += tmpfsp.fsu_blocks; /* Total blocks. */
259 fsp.fsu_bfree += tmpfsp.fsu_bfree; /* Free blocks available to superuser. */
260 fsp.fsu_bavail += tmpfsp.fsu_bavail; /* Free blocks available to non-superuser. */
261 fsp.fsu_files += tmpfsp.fsu_files; /* Total file nodes. */
262 fsp.fsu_ffree += tmpfsp.fsu_ffree; /* Free file nodes. */
264 if (verbose > 3)
265 printf("Group %s: add %llu blocks (%s) \n", path->group, tmpfsp.fsu_bavail, temp_list->name);
266 // printf("Group %s: add %u blocks (%s)\n", temp_list->name); // path->group, tmpfsp.fsu_bavail, temp_list->name);
268 np_add_name(&seen, temp_list->best_match->me_mountdir);
269 }
270 }
271 /* modify devname and mountdir for output */
272 me->me_mountdir = me->me_devname = path->group;
273 } else
274 np_add_name(&seen, me->me_mountdir);
275 }
277 if (path->group == NULL) {
278 /* Skip remote filesystems if we're not interested in them */
279 if (me->me_remote && show_local_fs) {
280 continue;
281 /* Skip pseudo fs's if we haven't asked for all fs's */
282 } else if (me->me_dummy && !show_all_fs) {
283 continue;
284 /* Skip excluded fstypes */
285 } else if (fs_exclude_list && np_find_name (fs_exclude_list, me->me_type)) {
286 continue;
287 /* Skip excluded fs's */
288 } else if (dp_exclude_list &&
289 (np_find_name (dp_exclude_list, me->me_devname) ||
290 np_find_name (dp_exclude_list, me->me_mountdir))) {
291 continue;
292 }
294 get_fs_usage (me->me_mountdir, me->me_devname, &fsp);
295 }
297 if (fsp.fsu_blocks && strcmp ("none", me->me_mountdir)) {
298 total = fsp.fsu_blocks;
299 available = fsp.fsu_bavail;
300 available_to_root = fsp.fsu_bfree;
301 used = total - available_to_root;
303 dused_pct = calculate_percent( used, used + available ); /* used + available can never be > uintmax */
305 dfree_pct = 100 - dused_pct;
306 dused_units = used*fsp.fsu_blocksize/mult;
307 dfree_units = available*fsp.fsu_blocksize/mult;
308 dtotal_units = total*fsp.fsu_blocksize/mult;
309 dused_inodes_percent = calculate_percent(fsp.fsu_files - fsp.fsu_ffree, fsp.fsu_files);
310 dfree_inodes_percent = 100 - dused_inodes_percent;
312 if (verbose >= 3) {
313 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",
314 me->me_mountdir, dused_pct, dfree_pct, dused_units, dfree_units, dtotal_units, dused_inodes_percent, dfree_inodes_percent);
315 }
317 /* Threshold comparisons */
319 temp_result = get_status(dfree_units, path->freespace_units);
320 if (verbose >=3) printf("Freespace_units result=%d\n", temp_result);
321 disk_result = max_state( disk_result, temp_result );
323 temp_result = get_status(dfree_pct, path->freespace_percent);
324 if (verbose >=3) printf("Freespace%% result=%d\n", temp_result);
325 disk_result = max_state( disk_result, temp_result );
327 temp_result = get_status(dused_units, path->usedspace_units);
328 if (verbose >=3) printf("Usedspace_units result=%d\n", temp_result);
329 disk_result = max_state( disk_result, temp_result );
331 temp_result = get_status(dused_pct, path->usedspace_percent);
332 if (verbose >=3) printf("Usedspace_percent result=%d\n", temp_result);
333 disk_result = max_state( disk_result, temp_result );
335 temp_result = get_status(dused_inodes_percent, path->usedinodes_percent);
336 if (verbose >=3) printf("Usedinodes_percent result=%d\n", temp_result);
337 disk_result = max_state( disk_result, temp_result );
339 temp_result = get_status(dfree_inodes_percent, path->freeinodes_percent);
340 if (verbose >=3) printf("Freeinodes_percent result=%d\n", temp_result);
341 disk_result = max_state( disk_result, temp_result );
343 result = max_state(result, disk_result);
345 /* What a mess of units. The output shows free space, the perf data shows used space. Yikes!
346 Hack here. Trying to get warn/crit levels from freespace_(units|percent) for perf
347 data. Assumption that start=0. Roll on new syntax...
348 */
350 /* *_high_tide must be reinitialized at each run */
351 warning_high_tide = UINT_MAX;
352 critical_high_tide = UINT_MAX;
354 if (path->freespace_units->warning != NULL) {
355 warning_high_tide = dtotal_units - path->freespace_units->warning->end;
356 }
357 if (path->freespace_percent->warning != NULL) {
358 warning_high_tide = abs( min( (double) warning_high_tide, (double) (1.0 - path->freespace_percent->warning->end/100)*dtotal_units ));
359 }
360 if (path->freespace_units->critical != NULL) {
361 critical_high_tide = dtotal_units - path->freespace_units->critical->end;
362 }
363 if (path->freespace_percent->critical != NULL) {
364 critical_high_tide = abs( min( (double) critical_high_tide, (double) (1.0 - path->freespace_percent->critical->end/100)*dtotal_units ));
365 }
367 asprintf (&perf, "%s %s", perf,
368 perfdata ((!strcmp(me->me_mountdir, "none") || display_mntp) ? me->me_devname : me->me_mountdir,
369 dused_units, units,
370 (warning_high_tide != UINT_MAX ? TRUE : FALSE), warning_high_tide,
371 (critical_high_tide != UINT_MAX ? TRUE : FALSE), critical_high_tide,
372 TRUE, 0,
373 TRUE, dtotal_units));
375 if (disk_result==STATE_OK && erronly && !verbose)
376 continue;
378 if (disk_result!=STATE_OK || verbose>=0) {
379 asprintf (&output, "%s %s %.0f %s (%.0f%%",
380 output,
381 (!strcmp(me->me_mountdir, "none") || display_mntp) ? me->me_devname : me->me_mountdir,
382 dfree_units,
383 units,
384 dfree_pct);
385 if (dused_inodes_percent < 0) {
386 asprintf(&output, "%s inode=-);", output);
387 } else {
388 asprintf(&output, "%s inode=%.0f%%);", output, dfree_inodes_percent );
389 }
390 }
392 /* TODO: Need to do a similar debug line
393 asprintf (&details, _("%s\n\
394 %.0f of %.0f %s (%.0f%% inode=%.0f%%) free on %s (type %s mounted on %s) warn:%lu crit:%lu warn%%:%.0f%% crit%%:%.0f%%"),
395 details, dfree_units, dtotal_units, units, dfree_pct, inode_space_pct,
396 me->me_devname, me->me_type, me->me_mountdir,
397 (unsigned long)w_df, (unsigned long)c_df, w_dfp, c_dfp);
398 */
400 }
402 }
404 if (verbose > 2)
405 asprintf (&output, "%s%s", output, details);
408 printf ("DISK %s%s%s|%s\n", state_text (result), (erronly && result==STATE_OK) ? "" : preamble, output, perf);
409 return result;
410 }
413 double calculate_percent(uintmax_t value, uintmax_t total) {
414 double pct = -1;
415 /* I don't understand the below, but it is taken from coreutils' df */
416 /* Seems to be calculating pct, in the best possible way */
417 if (value <= TYPE_MAXIMUM(uintmax_t) / 100
418 && total != 0) {
419 uintmax_t u100 = value * 100;
420 pct = u100 / total + (u100 % total != 0);
421 } else {
422 /* Possible rounding errors - see coreutils' df for more explanation */
423 double u = value;
424 double t = total;
425 if (t) {
426 long int lipct = pct = u * 100 / t;
427 double ipct = lipct;
429 /* Like 'pct = ceil (dpct);', but without ceil - from coreutils again */
430 if (ipct - 1 < pct && pct <= ipct + 1)
431 pct = ipct + (ipct < pct);
432 }
433 }
434 return pct;
435 }
437 /* process command-line arguments */
438 int
439 process_arguments (int argc, char **argv)
440 {
441 int c, err;
442 struct parameter_list *se, *se2;
443 struct parameter_list *temp_list;
444 struct parameter_list *temp_path_select_list = NULL;
445 struct mount_entry *me;
446 int result = OK;
447 struct stat *stat_buf;
448 regex_t re;
449 int cflags = REG_NOSUB | REG_EXTENDED;
450 char errbuf[MAX_INPUT_BUFFER];
451 bool fnd = false;
453 int option = 0;
454 static struct option longopts[] = {
455 {"timeout", required_argument, 0, 't'},
456 {"warning", required_argument, 0, 'w'},
457 {"critical", required_argument, 0, 'c'},
458 {"iwarning", required_argument, 0, 'W'},
459 /* Dang, -C is taken. We might want to reshuffle this. */
460 {"icritical", required_argument, 0, 'K'},
461 {"local", required_argument, 0, 'l'},
462 {"kilobytes", required_argument, 0, 'k'},
463 {"megabytes", required_argument, 0, 'm'},
464 {"units", required_argument, 0, 'u'},
465 {"path", required_argument, 0, 'p'},
466 {"partition", required_argument, 0, 'p'},
467 {"exclude_device", required_argument, 0, 'x'},
468 {"exclude-type", required_argument, 0, 'X'},
469 {"group", required_argument, 0, 'g'},
470 {"eregi-path", required_argument, 0, 'R'},
471 {"eregi-partition", required_argument, 0, 'R'},
472 {"ereg-path", required_argument, 0, 'r'},
473 {"ereg-partition", required_argument, 0, 'r'},
474 {"mountpoint", no_argument, 0, 'M'},
475 {"errors-only", no_argument, 0, 'e'},
476 {"exact-match", no_argument, 0, 'E'},
477 {"verbose", no_argument, 0, 'v'},
478 {"quiet", no_argument, 0, 'q'},
479 {"clear", no_argument, 0, 'C'},
480 {"version", no_argument, 0, 'V'},
481 {"help", no_argument, 0, 'h'},
482 {0, 0, 0, 0}
483 };
485 if (argc < 2)
486 return ERROR;
488 np_add_name(&fs_exclude_list, "iso9660");
490 for (c = 1; c < argc; c++)
491 if (strcmp ("-to", argv[c]) == 0)
492 strcpy (argv[c], "-t");
494 while (1) {
495 c = getopt_long (argc, argv, "+?VqhveCt:c:w:K:W:u:p:x:X:mklg:R:r:ME", longopts, &option);
497 if (c == -1 || c == EOF)
498 break;
500 switch (c) {
501 case 't': /* timeout period */
502 if (is_integer (optarg)) {
503 timeout_interval = atoi (optarg);
504 break;
505 }
506 else {
507 usage2 (_("Timeout interval must be a positive integer"), optarg);
508 }
510 /* See comments for 'c' */
511 case 'w': /* warning threshold */
512 if (strstr(optarg, "%")) {
513 if (*optarg == '@') {
514 warn_freespace_percent = optarg;
515 } else {
516 asprintf(&warn_freespace_percent, "@%s", optarg);
517 }
518 } else {
519 if (*optarg == '@') {
520 warn_freespace_units = optarg;
521 } else {
522 asprintf(&warn_freespace_units, "@%s", optarg);
523 }
524 }
525 break;
527 /* Awful mistake where the range values do not make sense. Normally,
528 you alert if the value is within the range, but since we are using
529 freespace, we have to alert if outside the range. Thus we artifically
530 force @ at the beginning of the range, so that it is backwards compatible
531 */
532 case 'c': /* critical threshold */
533 if (strstr(optarg, "%")) {
534 if (*optarg == '@') {
535 crit_freespace_percent = optarg;
536 } else {
537 asprintf(&crit_freespace_percent, "@%s", optarg);
538 }
539 } else {
540 if (*optarg == '@') {
541 crit_freespace_units = optarg;
542 } else {
543 asprintf(&crit_freespace_units, "@%s", optarg);
544 }
545 }
546 break;
548 case 'W': /* warning inode threshold */
549 if (*optarg == '@') {
550 warn_freeinodes_percent = optarg;
551 } else {
552 asprintf(&warn_freeinodes_percent, "@%s", optarg);
553 }
554 break;
555 case 'K': /* critical inode threshold */
556 if (*optarg == '@') {
557 crit_freeinodes_percent = optarg;
558 } else {
559 asprintf(&crit_freeinodes_percent, "@%s", optarg);
560 }
561 break;
562 case 'u':
563 if (units)
564 free(units);
565 if (! strcmp (optarg, "bytes")) {
566 mult = (uintmax_t)1;
567 units = strdup ("B");
568 } else if (! strcmp (optarg, "kB")) {
569 mult = (uintmax_t)1024;
570 units = strdup ("kB");
571 } else if (! strcmp (optarg, "MB")) {
572 mult = (uintmax_t)1024 * 1024;
573 units = strdup ("MB");
574 } else if (! strcmp (optarg, "GB")) {
575 mult = (uintmax_t)1024 * 1024 * 1024;
576 units = strdup ("GB");
577 } else if (! strcmp (optarg, "TB")) {
578 mult = (uintmax_t)1024 * 1024 * 1024 * 1024;
579 units = strdup ("TB");
580 } else {
581 die (STATE_UNKNOWN, _("unit type %s not known\n"), optarg);
582 }
583 if (units == NULL)
584 die (STATE_UNKNOWN, _("failed allocating storage for '%s'\n"), "units");
585 break;
586 case 'k': /* display mountpoint */
587 mult = 1024;
588 if (units)
589 free(units);
590 units = strdup ("kB");
591 break;
592 case 'm': /* display mountpoint */
593 mult = 1024 * 1024;
594 if (units)
595 free(units);
596 units = strdup ("MB");
597 break;
598 case 'l':
599 show_local_fs = 1;
600 break;
601 case 'p': /* select path */
602 if (! (warn_freespace_units || crit_freespace_units || warn_freespace_percent ||
603 crit_freespace_percent || warn_usedspace_units || crit_usedspace_units ||
604 warn_usedspace_percent || crit_usedspace_percent || warn_usedinodes_percent ||
605 crit_usedinodes_percent || warn_freeinodes_percent || crit_freeinodes_percent )) {
606 die (STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set a threshold value before using -p\n"));
607 }
609 /* get the real mountdir of the specified path. np_find_parameter won't find an entry if -p is not
610 * exactly the same string as the mountdir */
611 se2 = np_add_parameter(&temp_path_select_list, optarg);
612 np_set_best_match(se2, mount_list, FALSE);
615 /* add parameter if not found. overwrite thresholds if path has already been added */
616 if (! (se = np_find_parameter(path_select_list, optarg))) {
617 se = np_add_parameter(&path_select_list, optarg);
618 }
619 se->group = group;
620 set_all_thresholds(se);
621 path_selected = true;
622 break;
623 case 'x': /* exclude path or partition */
624 np_add_name(&dp_exclude_list, optarg);
625 break;
626 case 'X': /* exclude file system type */
627 np_add_name(&fs_exclude_list, optarg);
628 break;
629 case 'v': /* verbose */
630 verbose++;
631 break;
632 case 'q': /* verbose */
633 verbose--;
634 break;
635 case 'e':
636 erronly = TRUE;
637 break;
638 case 'E':
639 exact_match = TRUE;
640 break;
641 case 'g':
642 if (path_selected)
643 die (STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set group value before using -p\n"));
644 group = optarg;
645 break;
646 case 'R':
647 cflags |= REG_ICASE;
648 case 'r':
649 if (! (warn_freespace_units || crit_freespace_units || warn_freespace_percent ||
650 crit_freespace_percent || warn_usedspace_units || crit_usedspace_units ||
651 warn_usedspace_percent || crit_usedspace_percent || warn_usedinodes_percent ||
652 crit_usedinodes_percent || warn_freeinodes_percent || crit_freeinodes_percent )) {
653 die (STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set a threshold value before using -r/-R\n"));
654 }
656 err = regcomp(&re, optarg, cflags);
657 if (err != 0) {
658 regerror (err, &re, errbuf, MAX_INPUT_BUFFER);
659 die (STATE_UNKNOWN, "DISK %s: %s - %s\n",_("UNKNOWN"), _("Could not compile regular expression"), errbuf);
660 }
662 for (me = mount_list; me; me = me->me_next) {
663 if (np_regex_match_mount_entry(me, &re)) {
664 fnd = true;
665 if (verbose > 3)
666 printf("%s %s matching expression %s\n", me->me_devname, me->me_mountdir, optarg);
668 /* add parameter if not found. overwrite thresholds if path has already been added */
669 if (! (se = np_find_parameter(path_select_list, me->me_mountdir))) {
670 se = np_add_parameter(&path_select_list, me->me_mountdir);
671 }
672 se->group = group;
673 set_all_thresholds(se);
674 }
675 }
677 if (!fnd)
678 die (STATE_UNKNOWN, "DISK %s: %s - %s\n",_("UNKNOWN"),
679 _("Regular expression did not match any path or disk"), optarg);
681 fnd = false;
682 path_selected = true;
683 break;
684 case 'M': /* display mountpoint */
685 display_mntp = TRUE;
686 break;
687 case 'C':
688 /* add all mount entries to path_select list if no partitions have been explicitly defined using -p */
689 if (path_selected == false) {
690 struct mount_entry *me;
691 struct parameter_list *path;
692 for (me = mount_list; me; me = me->me_next) {
693 if (! (path = np_find_parameter(path_select_list, me->me_mountdir)))
694 path = np_add_parameter(&path_select_list, me->me_mountdir);
695 path->best_match = me;
696 path->group = group;
697 set_all_thresholds(path);
698 }
699 }
700 warn_freespace_units = NULL;
701 crit_freespace_units = NULL;
702 warn_usedspace_units = NULL;
703 crit_usedspace_units = NULL;
704 warn_freespace_percent = NULL;
705 crit_freespace_percent = NULL;
706 warn_usedspace_percent = NULL;
707 crit_usedspace_percent = NULL;
708 warn_usedinodes_percent = NULL;
709 crit_usedinodes_percent = NULL;
710 warn_freeinodes_percent = NULL;
711 crit_freeinodes_percent = NULL;
713 path_selected = false;
714 group = NULL;
715 break;
716 case 'V': /* version */
717 print_revision (progname, revision);
718 exit (STATE_OK);
719 case 'h': /* help */
720 print_help ();
721 exit (STATE_OK);
722 case '?': /* help */
723 usage (_("Unknown argument"));
724 }
725 }
727 /* Support for "check_disk warn crit [fs]" with thresholds at used% level */
728 c = optind;
729 if (warn_usedspace_percent == NULL && argc > c && is_intnonneg (argv[c]))
730 warn_usedspace_percent = argv[c++];
732 if (crit_usedspace_percent == NULL && argc > c && is_intnonneg (argv[c]))
733 crit_usedspace_percent = argv[c++];
735 if (argc > c && path == NULL) {
736 se = np_add_parameter(&path_select_list, strdup(argv[c++]));
737 path_selected = true;
738 set_all_thresholds(se);
739 }
741 if (units == NULL) {
742 units = strdup ("MB");
743 mult = (uintmax_t)1024 * 1024;
744 }
746 if (path_select_list) {
747 temp_list = path_select_list;
748 stat_buf = malloc(sizeof *stat_buf);
749 while (temp_list) {
750 /* Stat each entry to check that dir exists */
751 if (stat (temp_list->name, &stat_buf[0])) {
752 printf("DISK %s - ", _("CRITICAL"));
753 die (STATE_CRITICAL, _("%s does not exist\n"), temp_list->name);
754 }
755 /* if (validate_arguments (temp_list->w_df,
756 temp_list->c_df,
757 temp_list->w_dfp,
758 temp_list->c_dfp,
759 temp_list->w_idfp,
760 temp_list->c_idfp,
761 temp_list->name) == ERROR)
762 result = ERROR;
763 */
764 temp_list = temp_list->name_next;
765 }
766 free(stat_buf);
767 return result;
768 } else {
769 return TRUE;
770 /* return validate_arguments (w_df, c_df, w_dfp, c_dfp, w_idfp, c_idfp, NULL); */
771 }
772 }
776 void
777 print_path (const char *mypath)
778 {
779 if (mypath == NULL)
780 printf ("\n");
781 else
782 printf (_(" for %s\n"), mypath);
783 }
786 void
787 set_all_thresholds (struct parameter_list *path)
788 {
789 set_thresholds(&path->freespace_units, warn_freespace_units, crit_freespace_units);
790 set_thresholds(&path->freespace_percent, warn_freespace_percent, crit_freespace_percent);
791 set_thresholds(&path->usedspace_units, warn_usedspace_units, crit_usedspace_units);
792 set_thresholds(&path->usedspace_percent, warn_usedspace_percent, crit_usedspace_percent);
793 set_thresholds(&path->usedinodes_percent, warn_usedinodes_percent, crit_usedinodes_percent);
794 set_thresholds(&path->freeinodes_percent, warn_freeinodes_percent, crit_freeinodes_percent);
795 }
797 /* TODO: Remove?
799 int
800 validate_arguments (uintmax_t w, uintmax_t c, double wp, double cp, double iwp, double icp, char *mypath)
801 {
802 if (w < 0 && c < 0 && wp < 0.0 && cp < 0.0) {
803 printf (_("INPUT ERROR: No thresholds specified"));
804 print_path (mypath);
805 return ERROR;
806 }
807 else if ((wp >= 0.0 || cp >= 0.0) &&
808 (wp < 0.0 || cp < 0.0 || wp > 100.0 || cp > 100.0 || cp > wp)) {
809 printf (_("\
810 INPUT ERROR: C_DFP (%f) should be less than W_DFP (%.1f) and both should be between zero and 100 percent, inclusive"),
811 cp, wp);
812 print_path (mypath);
813 return ERROR;
814 }
815 else if ((iwp >= 0.0 || icp >= 0.0) &&
816 (iwp < 0.0 || icp < 0.0 || iwp > 100.0 || icp > 100.0 || icp > iwp)) {
817 printf (_("\
818 INPUT ERROR: C_IDFP (%f) should be less than W_IDFP (%.1f) and both should be between zero and 100 percent, inclusive"),
819 icp, iwp);
820 print_path (mypath);
821 return ERROR;
822 }
823 else if ((w > 0 || c > 0) && (w == 0 || c == 0 || c > w)) {
824 printf (_("\
825 INPUT ERROR: C_DF (%lu) should be less than W_DF (%lu) and both should be greater than zero"),
826 (unsigned long)c, (unsigned long)w);
827 print_path (mypath);
828 return ERROR;
829 }
831 return OK;
832 }
834 */
842 void
843 print_help (void)
844 {
845 print_revision (progname, revision);
847 printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
848 printf (COPYRIGHT, copyright, email);
850 printf ("%s\n", _("This plugin checks the amount of used disk space on a mounted file system"));
851 printf ("%s\n", _("and generates an alert if free space is less than one of the threshold values"));
853 printf ("\n\n");
855 print_usage ();
857 printf (_(UT_HELP_VRSN));
859 printf (" %s\n", "-w, --warning=INTEGER");
860 printf (" %s\n", _("Exit with WARNING status if less than INTEGER units of disk are free"));
861 printf (" %s\n", "-w, --warning=PERCENT%");
862 printf (" %s\n", _("Exit with WARNING status if less than PERCENT of disk space is free"));
863 printf (" %s\n", "-W, --iwarning=PERCENT%");
864 printf (" %s\n", _("Exit with WARNING status if less than PERCENT of inode space is free"));
865 printf (" %s\n", "-K, --icritical=PERCENT%");
866 printf (" %s\n", _("Exit with CRITICAL status if less than PERCENT of inode space is free"));
867 printf (" %s\n", "-c, --critical=INTEGER");
868 printf (" %s\n", _("Exit with CRITICAL status if less than INTEGER units of disk are free"));
869 printf (" %s\n", "-c, --critical=PERCENT%");
870 printf (" %s\n", _("Exit with CRITCAL status if less than PERCENT of disk space is free"));
871 printf (" %s\n", "-C, --clear");
872 printf (" %s\n", _("Clear thresholds"));
873 printf (" %s\n", "-u, --units=STRING");
874 printf (" %s\n", _("Choose bytes, kB, MB, GB, TB (default: MB)"));
875 printf (" %s\n", "-k, --kilobytes");
876 printf (" %s\n", _("Same as '--units kB'"));
877 printf (" %s\n", "-m, --megabytes");
878 printf (" %s\n", _("Same as '--units MB'"));
879 printf (" %s\n", "-l, --local");
880 printf (" %s\n", _("Only check local filesystems"));
881 printf (" %s\n", "-p, --path=PATH, --partition=PARTITION");
882 printf (" %s\n", _("Path or partition (may be repeated)"));
883 printf (" %s\n", "-r, --ereg-path=PATH, --ereg-partition=PARTITION");
884 printf (" %s\n", _("Regular expression for path or partition (may be repeated)"));
885 printf (" %s\n", "-R, --eregi-path=PATH, --eregi-partition=PARTITION");
886 printf (" %s\n", _("Case insensitive regular expression for path/partition (may be repeated)"));
887 printf (" %s\n", "-g, --group=NAME");
888 printf (" %s\n", _("Group pathes. Thresholds apply to (free-)space of all partitions together"));
889 printf (" %s\n", "-x, --exclude_device=PATH <STRING>");
890 printf (" %s\n", _("Ignore device (only works if -p unspecified)"));
891 printf (" %s\n", "-X, --exclude-type=TYPE <STRING>");
892 printf (" %s\n", _("Ignore all filesystems of indicated type (may be repeated)"));
893 printf (" %s\n", "-M, --mountpoint");
894 printf (" %s\n", _("Display the mountpoint instead of the partition"));
895 printf (" %s\n", "-E, --exact-match");
896 printf (" %s\n", _("For paths or partitions specified with -p, only check for exact paths"));
897 printf (" %s\n", "-e, --errors-only");
898 printf (" %s\n", _("Display only devices/mountpoints with errors"));
899 printf (_(UT_TIMEOUT), DEFAULT_SOCKET_TIMEOUT);
900 printf (_(UT_VERBOSE));
901 printf ("\n");
902 printf ("%s\n", _("Examples:"));
903 printf (" %s\n", "check_disk -w 10% -c 5% -p /tmp -p /var -C -w 100000 -c 50000 -p /");
904 printf (" %s\n", _("Checks /tmp and /var at 10% and 5%, and / at 100MB and 50MB"));
905 printf (_(UT_SUPPORT));
906 }
910 void
911 print_usage (void)
912 {
913 printf (_("Usage:"));
914 printf (" %s -w limit -c limit [-p path | -x device] [-t timeout]", progname);
915 printf ("[-m] [-e] [-W limit] [-K limit] [-v] [-q] [-E]\n");
916 }