4872efca77b6216c478b85702f918af8224da29d
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 set_all_thresholds(se);
738 }
740 if (units == NULL) {
741 units = strdup ("MB");
742 mult = (uintmax_t)1024 * 1024;
743 }
745 if (path_select_list) {
746 temp_list = path_select_list;
747 stat_buf = malloc(sizeof *stat_buf);
748 while (temp_list) {
749 /* Stat each entry to check that dir exists */
750 if (stat (temp_list->name, &stat_buf[0])) {
751 printf("DISK %s - ", _("CRITICAL"));
752 die (STATE_CRITICAL, _("%s does not exist\n"), temp_list->name);
753 }
754 /* if (validate_arguments (temp_list->w_df,
755 temp_list->c_df,
756 temp_list->w_dfp,
757 temp_list->c_dfp,
758 temp_list->w_idfp,
759 temp_list->c_idfp,
760 temp_list->name) == ERROR)
761 result = ERROR;
762 */
763 temp_list = temp_list->name_next;
764 }
765 free(stat_buf);
766 return result;
767 } else {
768 return TRUE;
769 /* return validate_arguments (w_df, c_df, w_dfp, c_dfp, w_idfp, c_idfp, NULL); */
770 }
771 }
775 void
776 print_path (const char *mypath)
777 {
778 if (mypath == NULL)
779 printf ("\n");
780 else
781 printf (_(" for %s\n"), mypath);
782 }
785 void
786 set_all_thresholds (struct parameter_list *path)
787 {
788 set_thresholds(&path->freespace_units, warn_freespace_units, crit_freespace_units);
789 set_thresholds(&path->freespace_percent, warn_freespace_percent, crit_freespace_percent);
790 set_thresholds(&path->usedspace_units, warn_usedspace_units, crit_usedspace_units);
791 set_thresholds(&path->usedspace_percent, warn_usedspace_percent, crit_usedspace_percent);
792 set_thresholds(&path->usedinodes_percent, warn_usedinodes_percent, crit_usedinodes_percent);
793 set_thresholds(&path->freeinodes_percent, warn_freeinodes_percent, crit_freeinodes_percent);
794 }
796 /* TODO: Remove?
798 int
799 validate_arguments (uintmax_t w, uintmax_t c, double wp, double cp, double iwp, double icp, char *mypath)
800 {
801 if (w < 0 && c < 0 && wp < 0.0 && cp < 0.0) {
802 printf (_("INPUT ERROR: No thresholds specified"));
803 print_path (mypath);
804 return ERROR;
805 }
806 else if ((wp >= 0.0 || cp >= 0.0) &&
807 (wp < 0.0 || cp < 0.0 || wp > 100.0 || cp > 100.0 || cp > wp)) {
808 printf (_("\
809 INPUT ERROR: C_DFP (%f) should be less than W_DFP (%.1f) and both should be between zero and 100 percent, inclusive"),
810 cp, wp);
811 print_path (mypath);
812 return ERROR;
813 }
814 else if ((iwp >= 0.0 || icp >= 0.0) &&
815 (iwp < 0.0 || icp < 0.0 || iwp > 100.0 || icp > 100.0 || icp > iwp)) {
816 printf (_("\
817 INPUT ERROR: C_IDFP (%f) should be less than W_IDFP (%.1f) and both should be between zero and 100 percent, inclusive"),
818 icp, iwp);
819 print_path (mypath);
820 return ERROR;
821 }
822 else if ((w > 0 || c > 0) && (w == 0 || c == 0 || c > w)) {
823 printf (_("\
824 INPUT ERROR: C_DF (%lu) should be less than W_DF (%lu) and both should be greater than zero"),
825 (unsigned long)c, (unsigned long)w);
826 print_path (mypath);
827 return ERROR;
828 }
830 return OK;
831 }
833 */
841 void
842 print_help (void)
843 {
844 print_revision (progname, revision);
846 printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
847 printf (COPYRIGHT, copyright, email);
849 printf ("%s\n", _("This plugin checks the amount of used disk space on a mounted file system"));
850 printf ("%s\n", _("and generates an alert if free space is less than one of the threshold values"));
852 printf ("\n\n");
854 print_usage ();
856 printf (_(UT_HELP_VRSN));
858 printf (" %s\n", "-w, --warning=INTEGER");
859 printf (" %s\n", _("Exit with WARNING status if less than INTEGER units of disk are free"));
860 printf (" %s\n", "-w, --warning=PERCENT%");
861 printf (" %s\n", _("Exit with WARNING status if less than PERCENT of disk space is free"));
862 printf (" %s\n", "-W, --iwarning=PERCENT%");
863 printf (" %s\n", _("Exit with WARNING status if less than PERCENT of inode space is free"));
864 printf (" %s\n", "-K, --icritical=PERCENT%");
865 printf (" %s\n", _("Exit with CRITICAL status if less than PERCENT of inode space is free"));
866 printf (" %s\n", "-c, --critical=INTEGER");
867 printf (" %s\n", _("Exit with CRITICAL status if less than INTEGER units of disk are free"));
868 printf (" %s\n", "-c, --critical=PERCENT%");
869 printf (" %s\n", _("Exit with CRITCAL status if less than PERCENT of disk space is free"));
870 printf (" %s\n", "-C, --clear");
871 printf (" %s\n", _("Clear thresholds"));
872 printf (" %s\n", "-u, --units=STRING");
873 printf (" %s\n", _("Choose bytes, kB, MB, GB, TB (default: MB)"));
874 printf (" %s\n", "-k, --kilobytes");
875 printf (" %s\n", _("Same as '--units kB'"));
876 printf (" %s\n", "-m, --megabytes");
877 printf (" %s\n", _("Same as '--units MB'"));
878 printf (" %s\n", "-l, --local");
879 printf (" %s\n", _("Only check local filesystems"));
880 printf (" %s\n", "-p, --path=PATH, --partition=PARTITION");
881 printf (" %s\n", _("Path or partition (may be repeated)"));
882 printf (" %s\n", "-r, --ereg-path=PATH, --ereg-partition=PARTITION");
883 printf (" %s\n", _("Regular expression for path or partition (may be repeated)"));
884 printf (" %s\n", "-R, --eregi-path=PATH, --eregi-partition=PARTITION");
885 printf (" %s\n", _("Case insensitive regular expression for path/partition (may be repeated)"));
886 printf (" %s\n", "-g, --group=NAME");
887 printf (" %s\n", _("Group pathes. Thresholds apply to (free-)space of all partitions together"));
888 printf (" %s\n", "-x, --exclude_device=PATH <STRING>");
889 printf (" %s\n", _("Ignore device (only works if -p unspecified)"));
890 printf (" %s\n", "-X, --exclude-type=TYPE <STRING>");
891 printf (" %s\n", _("Ignore all filesystems of indicated type (may be repeated)"));
892 printf (" %s\n", "-M, --mountpoint");
893 printf (" %s\n", _("Display the mountpoint instead of the partition"));
894 printf (" %s\n", "-E, --exact-match");
895 printf (" %s\n", _("For paths or partitions specified with -p, only check for exact paths"));
896 printf (" %s\n", "-e, --errors-only");
897 printf (" %s\n", _("Display only devices/mountpoints with errors"));
898 printf (_(UT_TIMEOUT), DEFAULT_SOCKET_TIMEOUT);
899 printf (_(UT_VERBOSE));
900 printf ("\n");
901 printf ("%s\n", _("Examples:"));
902 printf (" %s\n", "check_disk -w 10% -c 5% -p /tmp -p /var -C -w 100000 -c 50000 -p /");
903 printf (" %s\n", _("Checks /tmp and /var at 10% and 5%, and / at 100MB and 50MB"));
904 printf (_(UT_SUPPORT));
905 }
909 void
910 print_usage (void)
911 {
912 printf (_("Usage:"));
913 printf (" %s -w limit -c limit [-p path | -x device] [-t timeout]", progname);
914 printf ("[-m] [-e] [-W limit] [-K limit] [-v] [-q] [-E]\n");
915 }