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;
443 struct parameter_list *temp_list;
444 struct mount_entry *me;
445 int result = OK;
446 struct stat *stat_buf;
447 regex_t re;
448 int cflags = REG_NOSUB | REG_EXTENDED;
449 char errbuf[MAX_INPUT_BUFFER];
450 bool fnd = false;
452 int option = 0;
453 static struct option longopts[] = {
454 {"timeout", required_argument, 0, 't'},
455 {"warning", required_argument, 0, 'w'},
456 {"critical", required_argument, 0, 'c'},
457 {"iwarning", required_argument, 0, 'W'},
458 /* Dang, -C is taken. We might want to reshuffle this. */
459 {"icritical", required_argument, 0, 'K'},
460 {"local", required_argument, 0, 'l'},
461 {"kilobytes", required_argument, 0, 'k'},
462 {"megabytes", required_argument, 0, 'm'},
463 {"units", required_argument, 0, 'u'},
464 {"path", required_argument, 0, 'p'},
465 {"partition", required_argument, 0, 'p'},
466 {"exclude_device", required_argument, 0, 'x'},
467 {"exclude-type", required_argument, 0, 'X'},
468 {"group", required_argument, 0, 'g'},
469 {"eregi-path", required_argument, 0, 'R'},
470 {"eregi-partition", required_argument, 0, 'R'},
471 {"ereg-path", required_argument, 0, 'r'},
472 {"ereg-partition", required_argument, 0, 'r'},
473 {"mountpoint", no_argument, 0, 'M'},
474 {"errors-only", no_argument, 0, 'e'},
475 {"exact-match", no_argument, 0, 'E'},
476 {"verbose", no_argument, 0, 'v'},
477 {"quiet", no_argument, 0, 'q'},
478 {"clear", no_argument, 0, 'C'},
479 {"version", no_argument, 0, 'V'},
480 {"help", no_argument, 0, 'h'},
481 {0, 0, 0, 0}
482 };
484 if (argc < 2)
485 return ERROR;
487 np_add_name(&fs_exclude_list, "iso9660");
489 for (c = 1; c < argc; c++)
490 if (strcmp ("-to", argv[c]) == 0)
491 strcpy (argv[c], "-t");
493 while (1) {
494 c = getopt_long (argc, argv, "+?VqhveCt:c:w:K:W:u:p:x:X:mklg:R:r:ME", longopts, &option);
496 if (c == -1 || c == EOF)
497 break;
499 switch (c) {
500 case 't': /* timeout period */
501 if (is_integer (optarg)) {
502 timeout_interval = atoi (optarg);
503 break;
504 }
505 else {
506 usage2 (_("Timeout interval must be a positive integer"), optarg);
507 }
509 /* See comments for 'c' */
510 case 'w': /* warning threshold */
511 if (strstr(optarg, "%")) {
512 if (*optarg == '@') {
513 warn_freespace_percent = optarg;
514 } else {
515 asprintf(&warn_freespace_percent, "@%s", optarg);
516 }
517 } else {
518 if (*optarg == '@') {
519 warn_freespace_units = optarg;
520 } else {
521 asprintf(&warn_freespace_units, "@%s", optarg);
522 }
523 }
524 break;
526 /* Awful mistake where the range values do not make sense. Normally,
527 you alert if the value is within the range, but since we are using
528 freespace, we have to alert if outside the range. Thus we artifically
529 force @ at the beginning of the range, so that it is backwards compatible
530 */
531 case 'c': /* critical threshold */
532 if (strstr(optarg, "%")) {
533 if (*optarg == '@') {
534 crit_freespace_percent = optarg;
535 } else {
536 asprintf(&crit_freespace_percent, "@%s", optarg);
537 }
538 } else {
539 if (*optarg == '@') {
540 crit_freespace_units = optarg;
541 } else {
542 asprintf(&crit_freespace_units, "@%s", optarg);
543 }
544 }
545 break;
547 case 'W': /* warning inode threshold */
548 if (*optarg == '@') {
549 warn_freeinodes_percent = optarg;
550 } else {
551 asprintf(&warn_freeinodes_percent, "@%s", optarg);
552 }
553 break;
554 case 'K': /* critical inode threshold */
555 if (*optarg == '@') {
556 crit_freeinodes_percent = optarg;
557 } else {
558 asprintf(&crit_freeinodes_percent, "@%s", optarg);
559 }
560 break;
561 case 'u':
562 if (units)
563 free(units);
564 if (! strcmp (optarg, "bytes")) {
565 mult = (uintmax_t)1;
566 units = strdup ("B");
567 } else if (! strcmp (optarg, "kB")) {
568 mult = (uintmax_t)1024;
569 units = strdup ("kB");
570 } else if (! strcmp (optarg, "MB")) {
571 mult = (uintmax_t)1024 * 1024;
572 units = strdup ("MB");
573 } else if (! strcmp (optarg, "GB")) {
574 mult = (uintmax_t)1024 * 1024 * 1024;
575 units = strdup ("GB");
576 } else if (! strcmp (optarg, "TB")) {
577 mult = (uintmax_t)1024 * 1024 * 1024 * 1024;
578 units = strdup ("TB");
579 } else {
580 die (STATE_UNKNOWN, _("unit type %s not known\n"), optarg);
581 }
582 if (units == NULL)
583 die (STATE_UNKNOWN, _("failed allocating storage for '%s'\n"), "units");
584 break;
585 case 'k': /* display mountpoint */
586 mult = 1024;
587 if (units)
588 free(units);
589 units = strdup ("kB");
590 break;
591 case 'm': /* display mountpoint */
592 mult = 1024 * 1024;
593 if (units)
594 free(units);
595 units = strdup ("MB");
596 break;
597 case 'l':
598 show_local_fs = 1;
599 break;
600 case 'p': /* select path */
601 if (! (warn_freespace_units || crit_freespace_units || warn_freespace_percent ||
602 crit_freespace_percent || warn_usedspace_units || crit_usedspace_units ||
603 warn_usedspace_percent || crit_usedspace_percent || warn_usedinodes_percent ||
604 crit_usedinodes_percent || warn_freeinodes_percent || crit_freeinodes_percent )) {
605 die (STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set a threshold value before using -p\n"));
606 }
608 /* add parameter if not found. overwrite thresholds if path has already been added */
609 if (! (se = np_find_parameter(path_select_list, optarg))) {
610 se = np_add_parameter(&path_select_list, optarg);
611 }
612 se->group = group;
613 set_all_thresholds(se);
614 path_selected = true;
615 break;
616 case 'x': /* exclude path or partition */
617 np_add_name(&dp_exclude_list, optarg);
618 break;
619 case 'X': /* exclude file system type */
620 np_add_name(&fs_exclude_list, optarg);
621 break;
622 case 'v': /* verbose */
623 verbose++;
624 break;
625 case 'q': /* verbose */
626 verbose--;
627 break;
628 case 'e':
629 erronly = TRUE;
630 break;
631 case 'E':
632 exact_match = TRUE;
633 break;
634 case 'g':
635 if (path_selected)
636 die (STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set group value before using -p\n"));
637 group = optarg;
638 break;
639 case 'R':
640 cflags |= REG_ICASE;
641 case 'r':
642 if (! (warn_freespace_units || crit_freespace_units || warn_freespace_percent ||
643 crit_freespace_percent || warn_usedspace_units || crit_usedspace_units ||
644 warn_usedspace_percent || crit_usedspace_percent || warn_usedinodes_percent ||
645 crit_usedinodes_percent || warn_freeinodes_percent || crit_freeinodes_percent )) {
646 die (STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set a threshold value before using -r/-R\n"));
647 }
649 err = regcomp(&re, optarg, cflags);
650 if (err != 0) {
651 regerror (err, &re, errbuf, MAX_INPUT_BUFFER);
652 die (STATE_UNKNOWN, "DISK %s: %s - %s\n",_("UNKNOWN"), _("Could not compile regular expression"), errbuf);
653 }
655 for (me = mount_list; me; me = me->me_next) {
656 if (np_regex_match_mount_entry(me, &re)) {
657 fnd = true;
658 if (verbose > 3)
659 printf("%s %s matching expression %s\n", me->me_devname, me->me_mountdir, optarg);
661 /* add parameter if not found. overwrite thresholds if path has already been added */
662 if (! (se = np_find_parameter(path_select_list, me->me_mountdir))) {
663 se = np_add_parameter(&path_select_list, me->me_mountdir);
664 }
665 se->group = group;
666 set_all_thresholds(se);
667 }
668 }
670 if (!fnd)
671 die (STATE_UNKNOWN, "DISK %s: %s - %s\n",_("UNKNOWN"),
672 _("Regular expression did not match any path or disk"), optarg);
674 fnd = false;
675 path_selected = true;
676 break;
677 case 'M': /* display mountpoint */
678 display_mntp = TRUE;
679 break;
680 case 'C':
681 /* add all mount entries to path_select list if no partitions have been explicitly defined using -p */
682 if (path_selected == false) {
683 struct mount_entry *me;
684 struct parameter_list *path;
685 for (me = mount_list; me; me = me->me_next) {
686 if (! (path = np_find_parameter(path_select_list, me->me_mountdir)))
687 path = np_add_parameter(&path_select_list, me->me_mountdir);
688 path->best_match = me;
689 path->group = group;
690 set_all_thresholds(path);
691 }
692 }
693 warn_freespace_units = NULL;
694 crit_freespace_units = NULL;
695 warn_usedspace_units = NULL;
696 crit_usedspace_units = NULL;
697 warn_freespace_percent = NULL;
698 crit_freespace_percent = NULL;
699 warn_usedspace_percent = NULL;
700 crit_usedspace_percent = NULL;
701 warn_usedinodes_percent = NULL;
702 crit_usedinodes_percent = NULL;
703 warn_freeinodes_percent = NULL;
704 crit_freeinodes_percent = NULL;
706 path_selected = false;
707 group = NULL;
708 break;
709 case 'V': /* version */
710 print_revision (progname, revision);
711 exit (STATE_OK);
712 case 'h': /* help */
713 print_help ();
714 exit (STATE_OK);
715 case '?': /* help */
716 usage (_("Unknown argument"));
717 }
718 }
720 /* Support for "check_disk warn crit [fs]" with thresholds at used% level */
721 c = optind;
722 if (warn_usedspace_percent == NULL && argc > c && is_intnonneg (argv[c]))
723 warn_usedspace_percent = argv[c++];
725 if (crit_usedspace_percent == NULL && argc > c && is_intnonneg (argv[c]))
726 crit_usedspace_percent = argv[c++];
728 if (argc > c && path == NULL) {
729 se = np_add_parameter(&path_select_list, strdup(argv[c++]));
730 set_all_thresholds(se);
731 }
733 if (units == NULL) {
734 units = strdup ("MB");
735 mult = (uintmax_t)1024 * 1024;
736 }
738 if (path_select_list) {
739 temp_list = path_select_list;
740 stat_buf = malloc(sizeof *stat_buf);
741 while (temp_list) {
742 /* Stat each entry to check that dir exists */
743 if (stat (temp_list->name, &stat_buf[0])) {
744 printf("DISK %s - ", _("CRITICAL"));
745 die (STATE_CRITICAL, _("%s does not exist\n"), temp_list->name);
746 }
747 /* if (validate_arguments (temp_list->w_df,
748 temp_list->c_df,
749 temp_list->w_dfp,
750 temp_list->c_dfp,
751 temp_list->w_idfp,
752 temp_list->c_idfp,
753 temp_list->name) == ERROR)
754 result = ERROR;
755 */
756 temp_list = temp_list->name_next;
757 }
758 free(stat_buf);
759 return result;
760 } else {
761 return TRUE;
762 /* return validate_arguments (w_df, c_df, w_dfp, c_dfp, w_idfp, c_idfp, NULL); */
763 }
764 }
768 void
769 print_path (const char *mypath)
770 {
771 if (mypath == NULL)
772 printf ("\n");
773 else
774 printf (_(" for %s\n"), mypath);
775 }
778 void
779 set_all_thresholds (struct parameter_list *path)
780 {
781 set_thresholds(&path->freespace_units, warn_freespace_units, crit_freespace_units);
782 set_thresholds(&path->freespace_percent, warn_freespace_percent, crit_freespace_percent);
783 set_thresholds(&path->usedspace_units, warn_usedspace_units, crit_usedspace_units);
784 set_thresholds(&path->usedspace_percent, warn_usedspace_percent, crit_usedspace_percent);
785 set_thresholds(&path->usedinodes_percent, warn_usedinodes_percent, crit_usedinodes_percent);
786 set_thresholds(&path->freeinodes_percent, warn_freeinodes_percent, crit_freeinodes_percent);
787 }
789 /* TODO: Remove?
791 int
792 validate_arguments (uintmax_t w, uintmax_t c, double wp, double cp, double iwp, double icp, char *mypath)
793 {
794 if (w < 0 && c < 0 && wp < 0.0 && cp < 0.0) {
795 printf (_("INPUT ERROR: No thresholds specified"));
796 print_path (mypath);
797 return ERROR;
798 }
799 else if ((wp >= 0.0 || cp >= 0.0) &&
800 (wp < 0.0 || cp < 0.0 || wp > 100.0 || cp > 100.0 || cp > wp)) {
801 printf (_("\
802 INPUT ERROR: C_DFP (%f) should be less than W_DFP (%.1f) and both should be between zero and 100 percent, inclusive"),
803 cp, wp);
804 print_path (mypath);
805 return ERROR;
806 }
807 else if ((iwp >= 0.0 || icp >= 0.0) &&
808 (iwp < 0.0 || icp < 0.0 || iwp > 100.0 || icp > 100.0 || icp > iwp)) {
809 printf (_("\
810 INPUT ERROR: C_IDFP (%f) should be less than W_IDFP (%.1f) and both should be between zero and 100 percent, inclusive"),
811 icp, iwp);
812 print_path (mypath);
813 return ERROR;
814 }
815 else if ((w > 0 || c > 0) && (w == 0 || c == 0 || c > w)) {
816 printf (_("\
817 INPUT ERROR: C_DF (%lu) should be less than W_DF (%lu) and both should be greater than zero"),
818 (unsigned long)c, (unsigned long)w);
819 print_path (mypath);
820 return ERROR;
821 }
823 return OK;
824 }
826 */
834 void
835 print_help (void)
836 {
837 print_revision (progname, revision);
839 printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
840 printf (COPYRIGHT, copyright, email);
842 printf ("%s\n", _("This plugin checks the amount of used disk space on a mounted file system"));
843 printf ("%s\n", _("and generates an alert if free space is less than one of the threshold values"));
845 printf ("\n\n");
847 print_usage ();
849 printf (_(UT_HELP_VRSN));
851 printf (" %s\n", "-w, --warning=INTEGER");
852 printf (" %s\n", _("Exit with WARNING status if less than INTEGER units of disk are free"));
853 printf (" %s\n", "-w, --warning=PERCENT%");
854 printf (" %s\n", _("Exit with WARNING status if less than PERCENT of disk space is free"));
855 printf (" %s\n", "-W, --iwarning=PERCENT%");
856 printf (" %s\n", _("Exit with WARNING status if less than PERCENT of inode space is free"));
857 printf (" %s\n", "-K, --icritical=PERCENT%");
858 printf (" %s\n", _("Exit with CRITICAL status if less than PERCENT of inode space is free"));
859 printf (" %s\n", "-c, --critical=INTEGER");
860 printf (" %s\n", _("Exit with CRITICAL status if less than INTEGER units of disk are free"));
861 printf (" %s\n", "-c, --critical=PERCENT%");
862 printf (" %s\n", _("Exit with CRITCAL status if less than PERCENT of disk space is free"));
863 printf (" %s\n", "-C, --clear");
864 printf (" %s\n", _("Clear thresholds"));
865 printf (" %s\n", "-u, --units=STRING");
866 printf (" %s\n", _("Choose bytes, kB, MB, GB, TB (default: MB)"));
867 printf (" %s\n", "-k, --kilobytes");
868 printf (" %s\n", _("Same as '--units kB'"));
869 printf (" %s\n", "-m, --megabytes");
870 printf (" %s\n", _("Same as '--units MB'"));
871 printf (" %s\n", "-l, --local");
872 printf (" %s\n", _("Only check local filesystems"));
873 printf (" %s\n", "-p, --path=PATH, --partition=PARTITION");
874 printf (" %s\n", _("Path or partition (may be repeated)"));
875 printf (" %s\n", "-r, --ereg-path=PATH, --ereg-partition=PARTITION");
876 printf (" %s\n", _("Regular expression for path or partition (may be repeated)"));
877 printf (" %s\n", "-R, --eregi-path=PATH, --eregi-partition=PARTITION");
878 printf (" %s\n", _("Case insensitive regular expression for path/partition (may be repeated)"));
879 printf (" %s\n", "-g, --group=NAME");
880 printf (" %s\n", _("Group pathes. Thresholds apply to (free-)space of all partitions together"));
881 printf (" %s\n", "-x, --exclude_device=PATH <STRING>");
882 printf (" %s\n", _("Ignore device (only works if -p unspecified)"));
883 printf (" %s\n", "-X, --exclude-type=TYPE <STRING>");
884 printf (" %s\n", _("Ignore all filesystems of indicated type (may be repeated)"));
885 printf (" %s\n", "-M, --mountpoint");
886 printf (" %s\n", _("Display the mountpoint instead of the partition"));
887 printf (" %s\n", "-E, --exact-match");
888 printf (" %s\n", _("For paths or partitions specified with -p, only check for exact paths"));
889 printf (" %s\n", "-e, --errors-only");
890 printf (" %s\n", _("Display only devices/mountpoints with errors"));
891 printf (_(UT_TIMEOUT), DEFAULT_SOCKET_TIMEOUT);
892 printf (_(UT_VERBOSE));
893 printf ("\n");
894 printf ("%s\n", _("Examples:"));
895 printf (" %s\n", "check_disk -w 10% -c 5% -p /tmp -p /var -C -w 100000 -c 50000 -p /");
896 printf (" %s\n", _("Checks /tmp and /var at 10% and 5%, and / at 100MB and 50MB"));
897 printf (_(UT_SUPPORT));
898 }
902 void
903 print_usage (void)
904 {
905 printf (_("Usage:"));
906 printf (" %s -w limit -c limit [-p path | -x device] [-t timeout]", progname);
907 printf ("[-m] [-e] [-W limit] [-K limit] [-v] [-q] [-E]\n");
908 }