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 nonzero, show only local filesystems but call stat() on remote ones. */
73 static int stat_remote_fs = 0;
75 /* If positive, the units to use when printing sizes;
76 if negative, the human-readable base. */
77 /* static int output_block_size; */
79 /* If nonzero, invoke the `sync' system call before getting any usage data.
80 Using this option can make df very slow, especially with many or very
81 busy disks. Note that this may make a difference on some systems --
82 SunOs4.1.3, for one. It is *not* necessary on Linux. */
83 /* static int require_sync = 0; */
85 /* Linked list of filesystem types to display.
86 If `fs_select_list' is NULL, list all types.
87 This table is generated dynamically from command-line options,
88 rather than hardcoding into the program what it thinks are the
89 valid filesystem types; let the user specify any filesystem type
90 they want to, and if there are any filesystems of that type, they
91 will be shown.
93 Some filesystem types:
94 4.2 4.3 ufs nfs swap ignore io vm efs dbg */
96 /* static struct parameter_list *fs_select_list; */
98 /* Linked list of filesystem types to omit.
99 If the list is empty, don't exclude any types. */
101 static struct name_list *fs_exclude_list;
103 static struct name_list *dp_exclude_list;
105 static struct parameter_list *path_select_list = NULL;
107 /* Linked list of mounted filesystems. */
108 static struct mount_entry *mount_list;
110 /* For long options that have no equivalent short option, use a
111 non-character as a pseudo short option, starting with CHAR_MAX + 1. */
112 enum
113 {
114 SYNC_OPTION = CHAR_MAX + 1,
115 NO_SYNC_OPTION,
116 BLOCK_SIZE_OPTION
117 };
119 #ifdef _AIX
120 #pragma alloca
121 #endif
123 /* Linked list of mounted filesystems. */
124 static struct mount_entry *mount_list;
126 int process_arguments (int, char **);
127 void print_path (const char *mypath);
128 void set_all_thresholds (struct parameter_list *path);
129 int validate_arguments (uintmax_t, uintmax_t, double, double, double, double, char *);
130 void print_help (void);
131 void print_usage (void);
132 double calculate_percent(uintmax_t, uintmax_t);
133 void stat_path (struct parameter_list *p);
135 double w_dfp = -1.0;
136 double c_dfp = -1.0;
137 char *path;
138 char *exclude_device;
139 char *units;
140 uintmax_t mult = 1024 * 1024;
141 int verbose = 0;
142 int erronly = FALSE;
143 int display_mntp = FALSE;
144 int exact_match = FALSE;
145 char *warn_freespace_units = NULL;
146 char *crit_freespace_units = NULL;
147 char *warn_freespace_percent = NULL;
148 char *crit_freespace_percent = NULL;
149 char *warn_usedspace_units = NULL;
150 char *crit_usedspace_units = NULL;
151 char *warn_usedspace_percent = NULL;
152 char *crit_usedspace_percent = NULL;
153 char *warn_usedinodes_percent = NULL;
154 char *crit_usedinodes_percent = NULL;
155 char *warn_freeinodes_percent = NULL;
156 char *crit_freeinodes_percent = NULL;
157 int path_selected = FALSE;
158 char *group = NULL;
159 struct stat *stat_buf;
162 int
163 main (int argc, char **argv)
164 {
165 int result = STATE_UNKNOWN;
166 int disk_result = STATE_UNKNOWN;
167 char *output;
168 char *details;
169 char *perf;
170 char *preamble;
171 double inode_space_pct;
172 uintmax_t total, available, available_to_root, used;
173 double dfree_pct = -1, dused_pct = -1;
174 double dused_units, dfree_units, dtotal_units;
175 double dused_inodes_percent, dfree_inodes_percent;
176 double warning_high_tide;
177 double critical_high_tide;
178 int temp_result;
180 struct mount_entry *me;
181 struct fs_usage fsp, tmpfsp;
182 struct parameter_list *temp_list, *path;
183 struct name_list *seen = NULL;
185 preamble = strdup (" - free space:");
186 output = strdup ("");
187 details = strdup ("");
188 perf = strdup ("");
189 stat_buf = malloc(sizeof *stat_buf);
191 setlocale (LC_ALL, "");
192 bindtextdomain (PACKAGE, LOCALEDIR);
193 textdomain (PACKAGE);
195 mount_list = read_file_system_list (0);
197 if (process_arguments (argc, argv) == ERROR)
198 usage4 (_("Could not parse arguments"));
200 /* If a list of paths has not been selected, find entire
201 mount list and create list of paths
202 */
203 if (path_selected == FALSE) {
204 for (me = mount_list; me; me = me->me_next) {
205 if (! (path = np_find_parameter(path_select_list, me->me_mountdir))) {
206 path = np_add_parameter(&path_select_list, me->me_mountdir);
207 }
208 path->best_match = me;
209 path->group = group;
210 set_all_thresholds(path);
211 }
212 }
213 np_set_best_match(path_select_list, mount_list, exact_match);
215 /* Error if no match found for specified paths */
216 temp_list = path_select_list;
218 while (temp_list) {
219 if (! temp_list->best_match) {
220 die (STATE_CRITICAL, _("DISK %s: %s not found\n"), _("CRITICAL"), temp_list->name);
221 }
223 temp_list = temp_list->name_next;
224 }
226 /* Process for every path in list */
227 for (path = path_select_list; path; path=path->name_next) {
229 if (verbose > 3 && path->freespace_percent->warning != NULL && path->freespace_percent->critical != NULL)
230 printf("Thresholds(pct) for %s warn: %f crit %f\n",path->name, path->freespace_percent->warning->end,
231 path->freespace_percent->critical->end);
233 if (verbose > 3 && path->group != NULL)
234 printf("Group of %s: %s\n",path->name,path->group);
236 /* reset disk result */
237 disk_result = STATE_UNKNOWN;
239 me = path->best_match;
241 /* Filters */
243 /* Remove filesystems already seen */
244 if (np_seen_name(seen, me->me_mountdir)) {
245 continue;
246 } else {
247 if (path->group != NULL) {
248 /* find all group members */
249 fsp.fsu_blocksize = 0;
250 fsp.fsu_blocks = 0;
251 fsp.fsu_bfree = 0;
252 fsp.fsu_bavail = 0;
253 fsp.fsu_files = 0;
254 fsp.fsu_ffree = 0;
257 for (temp_list = path_select_list; temp_list; temp_list=temp_list->name_next) {
258 if (temp_list->group && ! (strcmp(temp_list->group, path->group))) {
260 stat_path(path);
261 get_fs_usage (temp_list->best_match->me_mountdir, temp_list->best_match->me_devname, &tmpfsp);
263 /* possibly differing blocksizes if disks are grouped. Calculating average */
264 fsp.fsu_blocksize = (fsp.fsu_blocksize * fsp.fsu_blocks + tmpfsp.fsu_blocksize * tmpfsp.fsu_blocks) / \
265 (fsp.fsu_blocks + tmpfsp.fsu_blocks); /* Size of a block. */
266 fsp.fsu_blocks += tmpfsp.fsu_blocks; /* Total blocks. */
267 fsp.fsu_bfree += tmpfsp.fsu_bfree; /* Free blocks available to superuser. */
268 fsp.fsu_bavail += tmpfsp.fsu_bavail; /* Free blocks available to non-superuser. */
269 fsp.fsu_files += tmpfsp.fsu_files; /* Total file nodes. */
270 fsp.fsu_ffree += tmpfsp.fsu_ffree; /* Free file nodes. */
272 if (verbose > 3)
273 printf("Group %s: add %llu blocks (%s) \n", path->group, tmpfsp.fsu_bavail, temp_list->name);
274 /* printf("Group %s: add %u blocks (%s)\n", temp_list->name); // path->group, tmpfsp.fsu_bavail, temp_list->name); */
276 np_add_name(&seen, temp_list->best_match->me_mountdir);
277 }
278 }
279 /* modify devname and mountdir for output */
280 me->me_mountdir = me->me_devname = path->group;
281 } else
282 np_add_name(&seen, me->me_mountdir);
283 }
285 if (path->group == NULL) {
286 /* Skip remote filesystems if we're not interested in them */
287 if (me->me_remote && show_local_fs) {
288 if (stat_remote_fs)
289 stat_path(path);
290 continue;
291 /* Skip pseudo fs's if we haven't asked for all fs's */
292 } else if (me->me_dummy && !show_all_fs) {
293 continue;
294 /* Skip excluded fstypes */
295 } else if (fs_exclude_list && np_find_name (fs_exclude_list, me->me_type)) {
296 continue;
297 /* Skip excluded fs's */
298 } else if (dp_exclude_list &&
299 (np_find_name (dp_exclude_list, me->me_devname) ||
300 np_find_name (dp_exclude_list, me->me_mountdir))) {
301 continue;
302 }
304 stat_path(path);
305 get_fs_usage (me->me_mountdir, me->me_devname, &fsp);
306 }
308 if (fsp.fsu_blocks && strcmp ("none", me->me_mountdir)) {
309 total = fsp.fsu_blocks;
310 available = fsp.fsu_bavail;
311 available_to_root = fsp.fsu_bfree;
312 used = total - available_to_root;
314 dused_pct = calculate_percent( used, used + available ); /* used + available can never be > uintmax */
316 dfree_pct = 100 - dused_pct;
317 dused_units = used*fsp.fsu_blocksize/mult;
318 dfree_units = available*fsp.fsu_blocksize/mult;
319 dtotal_units = total*fsp.fsu_blocksize/mult;
320 dused_inodes_percent = calculate_percent(fsp.fsu_files - fsp.fsu_ffree, fsp.fsu_files);
321 dfree_inodes_percent = 100 - dused_inodes_percent;
323 if (verbose >= 3) {
324 printf ("For %s, used_pct=%g free_pct=%g used_units=%g free_units=%g total_units=%g used_inodes_pct=%g free_inodes_pct=%g fsp.fsu_blocksize=%llu mult=%llu\n",
325 me->me_mountdir, dused_pct, dfree_pct, dused_units, dfree_units, dtotal_units, dused_inodes_percent, dfree_inodes_percent, fsp.fsu_blocksize, mult);
326 }
328 /* Threshold comparisons */
330 temp_result = get_status(dfree_units, path->freespace_units);
331 if (verbose >=3) printf("Freespace_units result=%d\n", temp_result);
332 disk_result = max_state( disk_result, temp_result );
334 temp_result = get_status(dfree_pct, path->freespace_percent);
335 if (verbose >=3) printf("Freespace%% result=%d\n", temp_result);
336 disk_result = max_state( disk_result, temp_result );
338 temp_result = get_status(dused_units, path->usedspace_units);
339 if (verbose >=3) printf("Usedspace_units result=%d\n", temp_result);
340 disk_result = max_state( disk_result, temp_result );
342 temp_result = get_status(dused_pct, path->usedspace_percent);
343 if (verbose >=3) printf("Usedspace_percent result=%d\n", temp_result);
344 disk_result = max_state( disk_result, temp_result );
346 temp_result = get_status(dused_inodes_percent, path->usedinodes_percent);
347 if (verbose >=3) printf("Usedinodes_percent result=%d\n", temp_result);
348 disk_result = max_state( disk_result, temp_result );
350 temp_result = get_status(dfree_inodes_percent, path->freeinodes_percent);
351 if (verbose >=3) printf("Freeinodes_percent result=%d\n", temp_result);
352 disk_result = max_state( disk_result, temp_result );
354 result = max_state(result, disk_result);
356 /* What a mess of units. The output shows free space, the perf data shows used space. Yikes!
357 Hack here. Trying to get warn/crit levels from freespace_(units|percent) for perf
358 data. Assumption that start=0. Roll on new syntax...
359 */
361 /* *_high_tide must be reinitialized at each run */
362 warning_high_tide = UINT_MAX;
363 critical_high_tide = UINT_MAX;
365 if (path->freespace_units->warning != NULL) {
366 warning_high_tide = dtotal_units - path->freespace_units->warning->end;
367 }
368 if (path->freespace_percent->warning != NULL) {
369 warning_high_tide = abs( min( (double) warning_high_tide, (double) (1.0 - path->freespace_percent->warning->end/100)*dtotal_units ));
370 }
371 if (path->freespace_units->critical != NULL) {
372 critical_high_tide = dtotal_units - path->freespace_units->critical->end;
373 }
374 if (path->freespace_percent->critical != NULL) {
375 critical_high_tide = abs( min( (double) critical_high_tide, (double) (1.0 - path->freespace_percent->critical->end/100)*dtotal_units ));
376 }
378 /* Nb: *_high_tide are unset when == UINT_MAX */
379 asprintf (&perf, "%s %s", perf,
380 perfdata ((!strcmp(me->me_mountdir, "none") || display_mntp) ? me->me_devname : me->me_mountdir,
381 dused_units, units,
382 (warning_high_tide != UINT_MAX ? TRUE : FALSE), warning_high_tide,
383 (critical_high_tide != UINT_MAX ? TRUE : FALSE), critical_high_tide,
384 TRUE, 0,
385 TRUE, dtotal_units));
387 if (disk_result==STATE_OK && erronly && !verbose)
388 continue;
390 asprintf (&output, "%s %s %.0f %s (%.0f%%",
391 output,
392 (!strcmp(me->me_mountdir, "none") || display_mntp) ? me->me_devname : me->me_mountdir,
393 dfree_units,
394 units,
395 dfree_pct);
396 if (dused_inodes_percent < 0) {
397 asprintf(&output, "%s inode=-);", output);
398 } else {
399 asprintf(&output, "%s inode=%.0f%%);", output, dfree_inodes_percent );
400 }
402 /* TODO: Need to do a similar debug line
403 asprintf (&details, _("%s\n\
404 %.0f of %.0f %s (%.0f%% inode=%.0f%%) free on %s (type %s mounted on %s) warn:%lu crit:%lu warn%%:%.0f%% crit%%:%.0f%%"),
405 details, dfree_units, dtotal_units, units, dfree_pct, inode_space_pct,
406 me->me_devname, me->me_type, me->me_mountdir,
407 (unsigned long)w_df, (unsigned long)c_df, w_dfp, c_dfp);
408 */
410 }
412 }
414 if (verbose > 2)
415 asprintf (&output, "%s%s", output, details);
418 printf ("DISK %s%s%s|%s\n", state_text (result), (erronly && result==STATE_OK) ? "" : preamble, output, perf);
419 return result;
420 }
423 double calculate_percent(uintmax_t value, uintmax_t total) {
424 double pct = -1;
425 /* I don't understand the below, but it is taken from coreutils' df */
426 /* Seems to be calculating pct, in the best possible way */
427 if (value <= TYPE_MAXIMUM(uintmax_t) / 100
428 && total != 0) {
429 uintmax_t u100 = value * 100;
430 pct = u100 / total + (u100 % total != 0);
431 } else {
432 /* Possible rounding errors - see coreutils' df for more explanation */
433 double u = value;
434 double t = total;
435 if (t) {
436 long int lipct = pct = u * 100 / t;
437 double ipct = lipct;
439 /* Like 'pct = ceil (dpct);', but without ceil - from coreutils again */
440 if (ipct - 1 < pct && pct <= ipct + 1)
441 pct = ipct + (ipct < pct);
442 }
443 }
444 return pct;
445 }
447 /* process command-line arguments */
448 int
449 process_arguments (int argc, char **argv)
450 {
451 int c, err;
452 struct parameter_list *se;
453 struct parameter_list *temp_list = NULL, *previous = NULL;
454 struct parameter_list *temp_path_select_list = NULL;
455 struct mount_entry *me, *temp_me;
456 int result = OK;
457 regex_t re;
458 int cflags = REG_NOSUB | REG_EXTENDED;
459 int default_cflags = cflags;
460 char errbuf[MAX_INPUT_BUFFER];
461 int fnd = 0;
463 int option = 0;
464 static struct option longopts[] = {
465 {"timeout", required_argument, 0, 't'},
466 {"warning", required_argument, 0, 'w'},
467 {"critical", required_argument, 0, 'c'},
468 {"iwarning", required_argument, 0, 'W'},
469 /* Dang, -C is taken. We might want to reshuffle this. */
470 {"icritical", required_argument, 0, 'K'},
471 {"local", required_argument, 0, 'l'},
472 {"stat-remote-fs", required_argument, 0, 'L'},
473 {"kilobytes", required_argument, 0, 'k'},
474 {"megabytes", required_argument, 0, 'm'},
475 {"units", required_argument, 0, 'u'},
476 {"path", required_argument, 0, 'p'},
477 {"partition", required_argument, 0, 'p'},
478 {"exclude_device", required_argument, 0, 'x'},
479 {"exclude-type", required_argument, 0, 'X'},
480 {"group", required_argument, 0, 'g'},
481 {"eregi-path", required_argument, 0, 'R'},
482 {"eregi-partition", required_argument, 0, 'R'},
483 {"ereg-path", required_argument, 0, 'r'},
484 {"ereg-partition", required_argument, 0, 'r'},
485 {"ignore-ereg-path", required_argument, 0, 'i'},
486 {"ignore-ereg-partition", required_argument, 0, 'i'},
487 {"ignore-eregi-path", required_argument, 0, 'I'},
488 {"ignore-eregi-partition", required_argument, 0, 'I'},
489 {"mountpoint", no_argument, 0, 'M'},
490 {"errors-only", no_argument, 0, 'e'},
491 {"exact-match", no_argument, 0, 'E'},
492 {"all", no_argument, 0, 'A'},
493 {"verbose", no_argument, 0, 'v'},
494 {"quiet", no_argument, 0, 'q'},
495 {"clear", no_argument, 0, 'C'},
496 {"version", no_argument, 0, 'V'},
497 {"help", no_argument, 0, 'h'},
498 {0, 0, 0, 0}
499 };
501 if (argc < 2)
502 return ERROR;
504 np_add_name(&fs_exclude_list, "iso9660");
506 for (c = 1; c < argc; c++)
507 if (strcmp ("-to", argv[c]) == 0)
508 strcpy (argv[c], "-t");
510 while (1) {
511 c = getopt_long (argc, argv, "+?VqhveCt:c:w:K:W:u:p:x:X:mklLg:R:r:i:I:MEA", longopts, &option);
513 if (c == -1 || c == EOF)
514 break;
516 switch (c) {
517 case 't': /* timeout period */
518 if (is_integer (optarg)) {
519 timeout_interval = atoi (optarg);
520 break;
521 }
522 else {
523 usage2 (_("Timeout interval must be a positive integer"), optarg);
524 }
526 /* See comments for 'c' */
527 case 'w': /* warning threshold */
528 if (strstr(optarg, "%")) {
529 if (*optarg == '@') {
530 warn_freespace_percent = optarg;
531 } else {
532 asprintf(&warn_freespace_percent, "@%s", optarg);
533 }
534 } else {
535 if (*optarg == '@') {
536 warn_freespace_units = optarg;
537 } else {
538 asprintf(&warn_freespace_units, "@%s", optarg);
539 }
540 }
541 break;
543 /* Awful mistake where the range values do not make sense. Normally,
544 you alert if the value is within the range, but since we are using
545 freespace, we have to alert if outside the range. Thus we artifically
546 force @ at the beginning of the range, so that it is backwards compatible
547 */
548 case 'c': /* critical threshold */
549 if (strstr(optarg, "%")) {
550 if (*optarg == '@') {
551 crit_freespace_percent = optarg;
552 } else {
553 asprintf(&crit_freespace_percent, "@%s", optarg);
554 }
555 } else {
556 if (*optarg == '@') {
557 crit_freespace_units = optarg;
558 } else {
559 asprintf(&crit_freespace_units, "@%s", optarg);
560 }
561 }
562 break;
564 case 'W': /* warning inode threshold */
565 if (*optarg == '@') {
566 warn_freeinodes_percent = optarg;
567 } else {
568 asprintf(&warn_freeinodes_percent, "@%s", optarg);
569 }
570 break;
571 case 'K': /* critical inode threshold */
572 if (*optarg == '@') {
573 crit_freeinodes_percent = optarg;
574 } else {
575 asprintf(&crit_freeinodes_percent, "@%s", optarg);
576 }
577 break;
578 case 'u':
579 if (units)
580 free(units);
581 if (! strcmp (optarg, "bytes")) {
582 mult = (uintmax_t)1;
583 units = strdup ("B");
584 } else if (! strcmp (optarg, "kB")) {
585 mult = (uintmax_t)1024;
586 units = strdup ("kB");
587 } else if (! strcmp (optarg, "MB")) {
588 mult = (uintmax_t)1024 * 1024;
589 units = strdup ("MB");
590 } else if (! strcmp (optarg, "GB")) {
591 mult = (uintmax_t)1024 * 1024 * 1024;
592 units = strdup ("GB");
593 } else if (! strcmp (optarg, "TB")) {
594 mult = (uintmax_t)1024 * 1024 * 1024 * 1024;
595 units = strdup ("TB");
596 } else {
597 die (STATE_UNKNOWN, _("unit type %s not known\n"), optarg);
598 }
599 if (units == NULL)
600 die (STATE_UNKNOWN, _("failed allocating storage for '%s'\n"), "units");
601 break;
602 case 'k': /* display mountpoint */
603 mult = 1024;
604 if (units)
605 free(units);
606 units = strdup ("kB");
607 break;
608 case 'm': /* display mountpoint */
609 mult = 1024 * 1024;
610 if (units)
611 free(units);
612 units = strdup ("MB");
613 break;
614 case 'L':
615 stat_remote_fs = 1;
616 case 'l':
617 show_local_fs = 1;
618 break;
619 case 'p': /* select path */
620 if (! (warn_freespace_units || crit_freespace_units || warn_freespace_percent ||
621 crit_freespace_percent || warn_usedspace_units || crit_usedspace_units ||
622 warn_usedspace_percent || crit_usedspace_percent || warn_usedinodes_percent ||
623 crit_usedinodes_percent || warn_freeinodes_percent || crit_freeinodes_percent )) {
624 die (STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set a threshold value before using -p\n"));
625 }
627 /* add parameter if not found. overwrite thresholds if path has already been added */
628 if (! (se = np_find_parameter(path_select_list, optarg))) {
629 se = np_add_parameter(&path_select_list, optarg);
630 }
631 se->group = group;
632 set_all_thresholds(se);
633 np_set_best_match(se, mount_list, exact_match);
634 stat_path(se);
635 path_selected = TRUE;
636 break;
637 case 'x': /* exclude path or partition */
638 np_add_name(&dp_exclude_list, optarg);
639 break;
640 case 'X': /* exclude file system type */
641 np_add_name(&fs_exclude_list, optarg);
642 break;
643 case 'v': /* verbose */
644 verbose++;
645 break;
646 case 'q': /* TODO: this function should eventually go away (removed 2007-09-20) */
647 /* verbose--; **replaced by line below**. -q was only a broken way of implementing -e */
648 erronly = TRUE;
649 break;
650 case 'e':
651 erronly = TRUE;
652 break;
653 case 'E':
654 if (path_selected)
655 die (STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set -E before selecting pathes\n"));
656 exact_match = TRUE;
657 break;
658 case 'g':
659 if (path_selected)
660 die (STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set group value before selecting pathes \n"));
661 group = optarg;
662 break;
663 case 'I':
664 cflags |= REG_ICASE;
665 case 'i':
666 if (!path_selected)
667 die (STATE_UNKNOWN, "DISK %s: %s\n", _("UNKNOWN"), _("Pathes need to be selected before using -i/-I. Use -A to select all pathes explicitly"));
668 err = regcomp(&re, optarg, cflags);
669 if (err != 0) {
670 regerror (err, &re, errbuf, MAX_INPUT_BUFFER);
671 die (STATE_UNKNOWN, "DISK %s: %s - %s\n",_("UNKNOWN"), _("Could not compile regular expression"), errbuf);
672 }
674 temp_list = path_select_list;
676 previous = NULL;
677 while (temp_list) {
678 if (temp_list->best_match) {
679 if (np_regex_match_mount_entry(temp_list->best_match, &re)) {
681 if (verbose >=3)
682 printf("ignoring %s matching regex\n", temp_list->name);
684 temp_list = np_del_parameter(temp_list, previous);
685 /* pointer to first element needs to be uĆ¼dated if first item gets deleted */
686 if (previous == NULL)
687 path_select_list = temp_list;
688 } else {
689 previous = temp_list;
690 temp_list = temp_list->name_next;
691 }
692 } else {
693 previous = temp_list;
694 temp_list = temp_list->name_next;
695 }
696 }
699 cflags = default_cflags;
700 break;
702 case 'A':
703 optarg = strdup(".*");
704 case 'R':
705 cflags |= REG_ICASE;
706 case 'r':
707 if (! (warn_freespace_units || crit_freespace_units || warn_freespace_percent ||
708 crit_freespace_percent || warn_usedspace_units || crit_usedspace_units ||
709 warn_usedspace_percent || crit_usedspace_percent || warn_usedinodes_percent ||
710 crit_usedinodes_percent || warn_freeinodes_percent || crit_freeinodes_percent )) {
711 die (STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set a threshold value before using -r/-R\n"));
712 }
714 err = regcomp(&re, optarg, cflags);
715 if (err != 0) {
716 regerror (err, &re, errbuf, MAX_INPUT_BUFFER);
717 die (STATE_UNKNOWN, "DISK %s: %s - %s\n",_("UNKNOWN"), _("Could not compile regular expression"), errbuf);
718 }
720 for (me = mount_list; me; me = me->me_next) {
721 if (np_regex_match_mount_entry(me, &re)) {
722 fnd = TRUE;
723 if (verbose > 3)
724 printf("%s %s matching expression %s\n", me->me_devname, me->me_mountdir, optarg);
726 /* add parameter if not found. overwrite thresholds if path has already been added */
727 if (! (se = np_find_parameter(path_select_list, me->me_mountdir))) {
728 se = np_add_parameter(&path_select_list, me->me_mountdir);
729 }
730 se->group = group;
731 set_all_thresholds(se);
732 }
733 }
735 if (!fnd)
736 die (STATE_UNKNOWN, "DISK %s: %s - %s\n",_("UNKNOWN"),
737 _("Regular expression did not match any path or disk"), optarg);
739 fnd = FALSE;
740 path_selected = TRUE;
741 np_set_best_match(path_select_list, mount_list, exact_match);
742 cflags = default_cflags;
744 break;
745 case 'M': /* display mountpoint */
746 display_mntp = TRUE;
747 break;
748 case 'C':
749 /* add all mount entries to path_select list if no partitions have been explicitly defined using -p */
750 if (path_selected == FALSE) {
751 struct mount_entry *me;
752 struct parameter_list *path;
753 for (me = mount_list; me; me = me->me_next) {
754 if (! (path = np_find_parameter(path_select_list, me->me_mountdir)))
755 path = np_add_parameter(&path_select_list, me->me_mountdir);
756 path->best_match = me;
757 path->group = group;
758 set_all_thresholds(path);
759 }
760 }
761 warn_freespace_units = NULL;
762 crit_freespace_units = NULL;
763 warn_usedspace_units = NULL;
764 crit_usedspace_units = NULL;
765 warn_freespace_percent = NULL;
766 crit_freespace_percent = NULL;
767 warn_usedspace_percent = NULL;
768 crit_usedspace_percent = NULL;
769 warn_usedinodes_percent = NULL;
770 crit_usedinodes_percent = NULL;
771 warn_freeinodes_percent = NULL;
772 crit_freeinodes_percent = NULL;
774 path_selected = FALSE;
775 group = NULL;
776 break;
777 case 'V': /* version */
778 print_revision (progname, revision);
779 exit (STATE_OK);
780 case 'h': /* help */
781 print_help ();
782 exit (STATE_OK);
783 case '?': /* help */
784 usage (_("Unknown argument"));
785 }
786 }
788 /* Support for "check_disk warn crit [fs]" with thresholds at used% level */
789 c = optind;
790 if (warn_usedspace_percent == NULL && argc > c && is_intnonneg (argv[c]))
791 warn_usedspace_percent = argv[c++];
793 if (crit_usedspace_percent == NULL && argc > c && is_intnonneg (argv[c]))
794 crit_usedspace_percent = argv[c++];
796 if (argc > c && path == NULL) {
797 se = np_add_parameter(&path_select_list, strdup(argv[c++]));
798 path_selected = TRUE;
799 set_all_thresholds(se);
800 }
802 if (units == NULL) {
803 units = strdup ("MB");
804 mult = (uintmax_t)1024 * 1024;
805 }
807 return TRUE;
808 }
812 void
813 print_path (const char *mypath)
814 {
815 if (mypath == NULL)
816 printf ("\n");
817 else
818 printf (_(" for %s\n"), mypath);
819 }
822 void
823 set_all_thresholds (struct parameter_list *path)
824 {
825 set_thresholds(&path->freespace_units, warn_freespace_units, crit_freespace_units);
826 set_thresholds(&path->freespace_percent, warn_freespace_percent, crit_freespace_percent);
827 set_thresholds(&path->usedspace_units, warn_usedspace_units, crit_usedspace_units);
828 set_thresholds(&path->usedspace_percent, warn_usedspace_percent, crit_usedspace_percent);
829 set_thresholds(&path->usedinodes_percent, warn_usedinodes_percent, crit_usedinodes_percent);
830 set_thresholds(&path->freeinodes_percent, warn_freeinodes_percent, crit_freeinodes_percent);
831 }
833 /* TODO: Remove?
835 int
836 validate_arguments (uintmax_t w, uintmax_t c, double wp, double cp, double iwp, double icp, char *mypath)
837 {
838 if (w < 0 && c < 0 && wp < 0.0 && cp < 0.0) {
839 printf (_("INPUT ERROR: No thresholds specified"));
840 print_path (mypath);
841 return ERROR;
842 }
843 else if ((wp >= 0.0 || cp >= 0.0) &&
844 (wp < 0.0 || cp < 0.0 || wp > 100.0 || cp > 100.0 || cp > wp)) {
845 printf (_("\
846 INPUT ERROR: C_DFP (%f) should be less than W_DFP (%.1f) and both should be between zero and 100 percent, inclusive"),
847 cp, wp);
848 print_path (mypath);
849 return ERROR;
850 }
851 else if ((iwp >= 0.0 || icp >= 0.0) &&
852 (iwp < 0.0 || icp < 0.0 || iwp > 100.0 || icp > 100.0 || icp > iwp)) {
853 printf (_("\
854 INPUT ERROR: C_IDFP (%f) should be less than W_IDFP (%.1f) and both should be between zero and 100 percent, inclusive"),
855 icp, iwp);
856 print_path (mypath);
857 return ERROR;
858 }
859 else if ((w > 0 || c > 0) && (w == 0 || c == 0 || c > w)) {
860 printf (_("\
861 INPUT ERROR: C_DF (%lu) should be less than W_DF (%lu) and both should be greater than zero"),
862 (unsigned long)c, (unsigned long)w);
863 print_path (mypath);
864 return ERROR;
865 }
867 return OK;
868 }
870 */
878 void
879 print_help (void)
880 {
881 print_revision (progname, revision);
883 printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
884 printf (COPYRIGHT, copyright, email);
886 printf ("%s\n", _("This plugin checks the amount of used disk space on a mounted file system"));
887 printf ("%s\n", _("and generates an alert if free space is less than one of the threshold values"));
889 printf ("\n\n");
891 print_usage ();
893 printf (_(UT_HELP_VRSN));
895 printf (" %s\n", "-w, --warning=INTEGER");
896 printf (" %s\n", _("Exit with WARNING status if less than INTEGER units of disk are free"));
897 printf (" %s\n", "-w, --warning=PERCENT%");
898 printf (" %s\n", _("Exit with WARNING status if less than PERCENT of disk space is free"));
899 printf (" %s\n", "-c, --critical=INTEGER");
900 printf (" %s\n", _("Exit with CRITICAL status if less than INTEGER units of disk are free"));
901 printf (" %s\n", "-c, --critical=PERCENT%");
902 printf (" %s\n", _("Exit with CRITCAL status if less than PERCENT of disk space is free"));
903 printf (" %s\n", "-W, --iwarning=PERCENT%");
904 printf (" %s\n", _("Exit with WARNING status if less than PERCENT of inode space is free"));
905 printf (" %s\n", "-K, --icritical=PERCENT%");
906 printf (" %s\n", _("Exit with CRITICAL status if less than PERCENT of inode space is free"));
907 printf (" %s\n", "-p, --path=PATH, --partition=PARTITION");
908 printf (" %s\n", _("Path or partition (may be repeated)"));
909 printf (" %s\n", "-x, --exclude_device=PATH <STRING>");
910 printf (" %s\n", _("Ignore device (only works if -p unspecified)"));
911 printf (" %s\n", "-C, --clear");
912 printf (" %s\n", _("Clear thresholds"));
913 printf (" %s\n", "-E, --exact-match");
914 printf (" %s\n", _("For paths or partitions specified with -p, only check for exact paths"));
915 printf (" %s\n", "-e, --errors-only");
916 printf (" %s\n", _("Display only devices/mountpoints with errors"));
917 printf (" %s\n", "-g, --group=NAME");
918 printf (" %s\n", _("Group pathes. Thresholds apply to (free-)space of all partitions together"));
919 printf (" %s\n", "-k, --kilobytes");
920 printf (" %s\n", _("Same as '--units kB'"));
921 printf (" %s\n", "-l, --local");
922 printf (" %s\n", _("Only check local filesystems"));
923 printf (" %s\n", "-L, --stat-remote-fs");
924 printf (" %s\n", _("Only check local filesystems against thresholds. Yet call stat on remote filesystems"));
925 printf (" %s\n", _("to test if they are accessible (e.g. to detect Stale NFS Handles)"));
926 printf (" %s\n", "-M, --mountpoint");
927 printf (" %s\n", _("Display the mountpoint instead of the partition"));
928 printf (" %s\n", "-m, --megabytes");
929 printf (" %s\n", _("Same as '--units MB'"));
930 printf (" %s\n", "-A, --all");
931 printf (" %s\n", _("Explicitly select all pathes. This is equivalent to -R '.*'"));
932 printf (" %s\n", "-R, --eregi-path=PATH, --eregi-partition=PARTITION");
933 printf (" %s\n", _("Case insensitive regular expression for path/partition (may be repeated)"));
934 printf (" %s\n", "-r, --ereg-path=PATH, --ereg-partition=PARTITION");
935 printf (" %s\n", _("Regular expression for path or partition (may be repeated)"));
936 printf (" %s\n", "-I, --ignore-eregi-path=PATH, --ignore-eregi-partition=PARTITION");
937 printf (" %s\n", _("Regular expression to ignore selected path/partition (case insensitive) (may be repeated)"));
938 printf (" %s\n", "-i, --ignore-ereg-path=PATH, --ignore-ereg-partition=PARTITION");
939 printf (" %s\n", _("Regular expression to ignore selected path or partition (may be repeated)"));
940 printf (_(UT_TIMEOUT), DEFAULT_SOCKET_TIMEOUT);
941 printf (" %s\n", "-u, --units=STRING");
942 printf (" %s\n", _("Choose bytes, kB, MB, GB, TB (default: MB)"));
943 printf (_(UT_VERBOSE));
944 printf (" %s\n", "-X, --exclude-type=TYPE");
945 printf (" %s\n", _("Ignore all filesystems of indicated type (may be repeated)"));
946 printf ("\n");
947 printf ("%s\n", _("Examples:"));
948 printf (" %s\n", "check_disk -w 10% -c 5% -p /tmp -p /var -C -w 100000 -c 50000 -p /");
949 printf (" %s\n", _("Checks /tmp and /var at 10% and 5%, and / at 100MB and 50MB"));
950 printf (" %s\n", "check_disk -w 100M -c 50M -C -w 1000M -c 500M -g sidDATA -r '^/oracle/SID/data.*$'");
951 printf (" %s\n", _("Checks all filesystems not matching -r at 100M and 50M. The fs matching the -r regex"));
952 printf (" %s\n", _("are grouped which means the freespace thresholds are applied to all disks together"));
953 printf (" %s\n", "check_disk -w 100M -c 50M -C -w 1000M -c 500M -p /foo -C -w 5% -c 3% -p /bar");
954 printf (" %s\n", _("Checks /foo for 1000M/500M and /bar for 5/3%. All remaining volumes use 100M/50M"));
955 printf (_(UT_SUPPORT));
956 }
960 void
961 print_usage (void)
962 {
963 printf (_("Usage:"));
964 printf (" %s -w limit -c limit [-W limit] [-K limit] {-p path | -x device}\n", progname);
965 printf ("[-C] [-E] [-e] [-g group ] [-k] [-l] [-M] [-m] [-R path ] [-r path ]\n");
966 printf ("[-t timeout] [-u unit] [-v] [-X type]\n");
967 }
969 void
970 stat_path (struct parameter_list *p)
971 {
972 /* Stat entry to check that dir exists and is accessible */
973 if (verbose > 3)
974 printf("calling stat on %s\n", p->name);
975 if (stat (p->name, &stat_buf[0])) {
976 if (verbose > 3)
977 printf("stat failed on %s\n", p->name);
978 printf("DISK %s - ", _("CRITICAL"));
979 die (STATE_CRITICAL, _("%s %s: %s\n"), p->name, _("is not accessible"), strerror(errno));
980 }
981 }