44c154fce085a9a8e326cc295d274ed375cf7d01
1 /*****************************************************************************
2 *
3 * Nagios check_disk plugin
4 *
5 * License: GPL
6 * Copyright (c) 1999-2008 Nagios Plugins Development Team
7 *
8 * Last Modified: $Date$
9 *
10 * Description:
11 *
12 * This file contains the check_disk plugin
13 *
14 *
15 * This program is free software: you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation, either version 3 of the License, or
18 * (at your option) any later version.
19 *
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this program. If not, see <http://www.gnu.org/licenses/>.
27 *
28 * $Id$
29 *
30 *****************************************************************************/
32 const char *progname = "check_disk";
33 const char *program_name = "check_disk"; /* Required for coreutils libs */
34 const char *revision = "$Revision$";
35 const char *copyright = "1999-2008";
36 const char *email = "nagiosplug-devel@lists.sourceforge.net";
39 #include "common.h"
40 #ifdef HAVE_SYS_STAT_H
41 # include <sys/stat.h>
42 #endif
43 #if HAVE_INTTYPES_H
44 # include <inttypes.h>
45 #endif
46 #include <assert.h>
47 #include "popen.h"
48 #include "utils.h"
49 #include "utils_disk.h"
50 #include <stdarg.h>
51 #include "fsusage.h"
52 #include "mountlist.h"
53 #include "intprops.h" /* necessary for TYPE_MAXIMUM */
54 #if HAVE_LIMITS_H
55 # include <limits.h>
56 #endif
57 #include "regex.h"
60 /* If nonzero, show inode information. */
61 static int inode_format = 1;
63 /* If nonzero, show even filesystems with zero size or
64 uninteresting types. */
65 static int show_all_fs = 1;
67 /* If nonzero, show only local filesystems. */
68 static int show_local_fs = 0;
70 /* If nonzero, show only local filesystems but call stat() on remote ones. */
71 static int stat_remote_fs = 0;
73 /* If positive, the units to use when printing sizes;
74 if negative, the human-readable base. */
75 /* static int output_block_size; */
77 /* If nonzero, invoke the `sync' system call before getting any usage data.
78 Using this option can make df very slow, especially with many or very
79 busy disks. Note that this may make a difference on some systems --
80 SunOs4.1.3, for one. It is *not* necessary on Linux. */
81 /* static int require_sync = 0; */
83 /* Linked list of filesystem types to display.
84 If `fs_select_list' is NULL, list all types.
85 This table is generated dynamically from command-line options,
86 rather than hardcoding into the program what it thinks are the
87 valid filesystem types; let the user specify any filesystem type
88 they want to, and if there are any filesystems of that type, they
89 will be shown.
91 Some filesystem types:
92 4.2 4.3 ufs nfs swap ignore io vm efs dbg */
94 /* static struct parameter_list *fs_select_list; */
96 /* Linked list of filesystem types to omit.
97 If the list is empty, don't exclude any types. */
99 static struct name_list *fs_exclude_list;
101 static struct name_list *dp_exclude_list;
103 static struct parameter_list *path_select_list = NULL;
105 /* Linked list of mounted filesystems. */
106 static struct mount_entry *mount_list;
108 /* For long options that have no equivalent short option, use a
109 non-character as a pseudo short option, starting with CHAR_MAX + 1. */
110 enum
111 {
112 SYNC_OPTION = CHAR_MAX + 1,
113 NO_SYNC_OPTION,
114 BLOCK_SIZE_OPTION
115 };
117 #ifdef _AIX
118 #pragma alloca
119 #endif
121 /* Linked list of mounted filesystems. */
122 static struct mount_entry *mount_list;
124 int process_arguments (int, char **);
125 void print_path (const char *mypath);
126 void set_all_thresholds (struct parameter_list *path);
127 int validate_arguments (uintmax_t, uintmax_t, double, double, double, double, char *);
128 void print_help (void);
129 void print_usage (void);
130 double calculate_percent(uintmax_t, uintmax_t);
131 void stat_path (struct parameter_list *p);
133 double w_dfp = -1.0;
134 double c_dfp = -1.0;
135 char *path;
136 char *exclude_device;
137 char *units;
138 uintmax_t mult = 1024 * 1024;
139 int verbose = 0;
140 int erronly = FALSE;
141 int display_mntp = FALSE;
142 int exact_match = FALSE;
143 char *warn_freespace_units = NULL;
144 char *crit_freespace_units = NULL;
145 char *warn_freespace_percent = NULL;
146 char *crit_freespace_percent = NULL;
147 char *warn_usedspace_units = NULL;
148 char *crit_usedspace_units = NULL;
149 char *warn_usedspace_percent = NULL;
150 char *crit_usedspace_percent = NULL;
151 char *warn_usedinodes_percent = NULL;
152 char *crit_usedinodes_percent = NULL;
153 char *warn_freeinodes_percent = NULL;
154 char *crit_freeinodes_percent = NULL;
155 int path_selected = FALSE;
156 char *group = NULL;
157 struct stat *stat_buf;
160 int
161 main (int argc, char **argv)
162 {
163 int result = STATE_UNKNOWN;
164 int disk_result = STATE_UNKNOWN;
165 char *output;
166 char *details;
167 char *perf;
168 char *preamble;
169 double inode_space_pct;
170 uintmax_t total, available, available_to_root, used;
171 double dfree_pct = -1, dused_pct = -1;
172 double dused_units, dfree_units, dtotal_units;
173 double dused_inodes_percent, dfree_inodes_percent;
174 double warning_high_tide;
175 double critical_high_tide;
176 int temp_result;
178 struct mount_entry *me;
179 struct fs_usage fsp, tmpfsp;
180 struct parameter_list *temp_list, *path;
181 struct name_list *seen = NULL;
183 preamble = strdup (" - free space:");
184 output = strdup ("");
185 details = strdup ("");
186 perf = strdup ("");
187 stat_buf = malloc(sizeof *stat_buf);
189 setlocale (LC_ALL, "");
190 bindtextdomain (PACKAGE, LOCALEDIR);
191 textdomain (PACKAGE);
193 mount_list = read_file_system_list (0);
195 if (process_arguments (argc, argv) == ERROR)
196 usage4 (_("Could not parse arguments"));
198 /* If a list of paths has not been selected, find entire
199 mount list and create list of paths
200 */
201 if (path_selected == FALSE) {
202 for (me = mount_list; me; me = me->me_next) {
203 if (! (path = np_find_parameter(path_select_list, me->me_mountdir))) {
204 path = np_add_parameter(&path_select_list, me->me_mountdir);
205 }
206 path->best_match = me;
207 path->group = group;
208 set_all_thresholds(path);
209 }
210 }
211 np_set_best_match(path_select_list, mount_list, exact_match);
213 /* Error if no match found for specified paths */
214 temp_list = path_select_list;
216 while (temp_list) {
217 if (! temp_list->best_match) {
218 die (STATE_CRITICAL, _("DISK %s: %s not found\n"), _("CRITICAL"), temp_list->name);
219 }
221 temp_list = temp_list->name_next;
222 }
224 /* Process for every path in list */
225 for (path = path_select_list; path; path=path->name_next) {
227 if (verbose > 3 && path->freespace_percent->warning != NULL && path->freespace_percent->critical != NULL)
228 printf("Thresholds(pct) for %s warn: %f crit %f\n",path->name, path->freespace_percent->warning->end,
229 path->freespace_percent->critical->end);
231 if (verbose > 3 && path->group != NULL)
232 printf("Group of %s: %s\n",path->name,path->group);
234 /* reset disk result */
235 disk_result = STATE_UNKNOWN;
237 me = path->best_match;
239 /* Filters */
241 /* Remove filesystems already seen */
242 if (np_seen_name(seen, me->me_mountdir)) {
243 continue;
244 } else {
245 if (path->group != NULL) {
246 /* find all group members */
247 fsp.fsu_blocksize = 0;
248 fsp.fsu_blocks = 0;
249 fsp.fsu_bfree = 0;
250 fsp.fsu_bavail = 0;
251 fsp.fsu_files = 0;
252 fsp.fsu_ffree = 0;
255 for (temp_list = path_select_list; temp_list; temp_list=temp_list->name_next) {
256 if (temp_list->group && ! (strcmp(temp_list->group, path->group))) {
258 stat_path(path);
259 get_fs_usage (temp_list->best_match->me_mountdir, temp_list->best_match->me_devname, &tmpfsp);
261 /* possibly differing blocksizes if disks are grouped. Calculating average */
262 fsp.fsu_blocksize = (fsp.fsu_blocksize * fsp.fsu_blocks + tmpfsp.fsu_blocksize * tmpfsp.fsu_blocks) / \
263 (fsp.fsu_blocks + tmpfsp.fsu_blocks); /* Size of a block. */
264 fsp.fsu_blocks += tmpfsp.fsu_blocks; /* Total blocks. */
265 fsp.fsu_bfree += tmpfsp.fsu_bfree; /* Free blocks available to superuser. */
266 /* Gnulib workaround - see comment about it a few lines below */
267 fsp.fsu_bavail += (tmpfsp.fsu_bavail > tmpfsp.fsu_bfree ? 0 : tmpfsp.fsu_bavail); /* Free blocks available to non-superuser. */
268 fsp.fsu_files += tmpfsp.fsu_files; /* Total file nodes. */
269 fsp.fsu_ffree += tmpfsp.fsu_ffree; /* Free file nodes. */
271 if (verbose > 3)
272 printf("Group %s: add %llu blocks (%s) \n", path->group, tmpfsp.fsu_bavail, temp_list->name);
273 /* printf("Group %s: add %u blocks (%s)\n", temp_list->name); *//* path->group, tmpfsp.fsu_bavail, temp_list->name); */
275 np_add_name(&seen, temp_list->best_match->me_mountdir);
276 }
277 }
278 /* modify devname and mountdir for output */
279 me->me_mountdir = me->me_devname = path->group;
280 } else
281 np_add_name(&seen, me->me_mountdir);
282 }
284 if (path->group == NULL) {
285 /* Skip remote filesystems if we're not interested in them */
286 if (me->me_remote && show_local_fs) {
287 if (stat_remote_fs)
288 stat_path(path);
289 continue;
290 /* Skip pseudo fs's if we haven't asked for all fs's */
291 } else if (me->me_dummy && !show_all_fs) {
292 continue;
293 /* Skip excluded fstypes */
294 } else if (fs_exclude_list && np_find_name (fs_exclude_list, me->me_type)) {
295 continue;
296 /* Skip excluded fs's */
297 } else if (dp_exclude_list &&
298 (np_find_name (dp_exclude_list, me->me_devname) ||
299 np_find_name (dp_exclude_list, me->me_mountdir))) {
300 continue;
301 }
303 stat_path(path);
304 get_fs_usage (me->me_mountdir, me->me_devname, &fsp);
305 }
307 if (fsp.fsu_blocks && strcmp ("none", me->me_mountdir)) {
308 total = fsp.fsu_blocks;
309 /* 2007-12-08 - Workaround for Gnulib reporting insanely high available
310 * space on BSD (the actual value should be negative but fsp.fsu_bavail
311 * is unsigned) */
312 available = fsp.fsu_bavail > fsp.fsu_bfree ? 0 : fsp.fsu_bavail;
313 available_to_root = fsp.fsu_bfree;
314 used = total - available_to_root;
316 if (verbose >= 3)
317 printf ("For %s, total=%llu, available=%llu, available_to_root=%llu, used=%llu, fsp.fsu_files=%llu, fsp.fsu_ffree=%llu\n",
318 me->me_mountdir, total, available, available_to_root, used, fsp.fsu_files, fsp.fsu_ffree);
320 dused_pct = calculate_percent( used, used + available ); /* used + available can never be > uintmax */
322 dfree_pct = 100 - dused_pct;
323 dused_units = used*fsp.fsu_blocksize/mult;
324 dfree_units = available*fsp.fsu_blocksize/mult;
325 dtotal_units = total*fsp.fsu_blocksize/mult;
326 dused_inodes_percent = calculate_percent(fsp.fsu_files - fsp.fsu_ffree, fsp.fsu_files);
327 dfree_inodes_percent = 100 - dused_inodes_percent;
329 if (verbose >= 3) {
330 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",
331 me->me_mountdir, dused_pct, dfree_pct, dused_units, dfree_units, dtotal_units, dused_inodes_percent, dfree_inodes_percent, fsp.fsu_blocksize, mult);
332 }
334 /* Threshold comparisons */
336 temp_result = get_status(dfree_units, path->freespace_units);
337 if (verbose >=3) printf("Freespace_units result=%d\n", temp_result);
338 disk_result = max_state( disk_result, temp_result );
340 temp_result = get_status(dfree_pct, path->freespace_percent);
341 if (verbose >=3) printf("Freespace%% result=%d\n", temp_result);
342 disk_result = max_state( disk_result, temp_result );
344 temp_result = get_status(dused_units, path->usedspace_units);
345 if (verbose >=3) printf("Usedspace_units result=%d\n", temp_result);
346 disk_result = max_state( disk_result, temp_result );
348 temp_result = get_status(dused_pct, path->usedspace_percent);
349 if (verbose >=3) printf("Usedspace_percent result=%d\n", temp_result);
350 disk_result = max_state( disk_result, temp_result );
352 temp_result = get_status(dused_inodes_percent, path->usedinodes_percent);
353 if (verbose >=3) printf("Usedinodes_percent result=%d\n", temp_result);
354 disk_result = max_state( disk_result, temp_result );
356 temp_result = get_status(dfree_inodes_percent, path->freeinodes_percent);
357 if (verbose >=3) printf("Freeinodes_percent result=%d\n", temp_result);
358 disk_result = max_state( disk_result, temp_result );
360 result = max_state(result, disk_result);
362 /* What a mess of units. The output shows free space, the perf data shows used space. Yikes!
363 Hack here. Trying to get warn/crit levels from freespace_(units|percent) for perf
364 data. Assumption that start=0. Roll on new syntax...
365 */
367 /* *_high_tide must be reinitialized at each run */
368 warning_high_tide = UINT_MAX;
369 critical_high_tide = UINT_MAX;
371 if (path->freespace_units->warning != NULL) {
372 warning_high_tide = dtotal_units - path->freespace_units->warning->end;
373 }
374 if (path->freespace_percent->warning != NULL) {
375 warning_high_tide = abs( min( (double) warning_high_tide, (double) (1.0 - path->freespace_percent->warning->end/100)*dtotal_units ));
376 }
377 if (path->freespace_units->critical != NULL) {
378 critical_high_tide = dtotal_units - path->freespace_units->critical->end;
379 }
380 if (path->freespace_percent->critical != NULL) {
381 critical_high_tide = abs( min( (double) critical_high_tide, (double) (1.0 - path->freespace_percent->critical->end/100)*dtotal_units ));
382 }
384 /* Nb: *_high_tide are unset when == UINT_MAX */
385 asprintf (&perf, "%s %s", perf,
386 perfdata ((!strcmp(me->me_mountdir, "none") || display_mntp) ? me->me_devname : me->me_mountdir,
387 dused_units, units,
388 (warning_high_tide != UINT_MAX ? TRUE : FALSE), warning_high_tide,
389 (critical_high_tide != UINT_MAX ? TRUE : FALSE), critical_high_tide,
390 TRUE, 0,
391 TRUE, dtotal_units));
393 if (disk_result==STATE_OK && erronly && !verbose)
394 continue;
396 asprintf (&output, "%s %s %.0f %s (%.0f%%",
397 output,
398 (!strcmp(me->me_mountdir, "none") || display_mntp) ? me->me_devname : me->me_mountdir,
399 dfree_units,
400 units,
401 dfree_pct);
402 if (dused_inodes_percent < 0) {
403 asprintf(&output, "%s inode=-);", output);
404 } else {
405 asprintf(&output, "%s inode=%.0f%%);", output, dfree_inodes_percent );
406 }
408 /* TODO: Need to do a similar debug line
409 asprintf (&details, _("%s\n\
410 %.0f of %.0f %s (%.0f%% inode=%.0f%%) free on %s (type %s mounted on %s) warn:%lu crit:%lu warn%%:%.0f%% crit%%:%.0f%%"),
411 details, dfree_units, dtotal_units, units, dfree_pct, inode_space_pct,
412 me->me_devname, me->me_type, me->me_mountdir,
413 (unsigned long)w_df, (unsigned long)c_df, w_dfp, c_dfp);
414 */
416 }
418 }
420 if (verbose > 2)
421 asprintf (&output, "%s%s", output, details);
424 printf ("DISK %s%s%s|%s\n", state_text (result), (erronly && result==STATE_OK) ? "" : preamble, output, perf);
425 return result;
426 }
429 double calculate_percent(uintmax_t value, uintmax_t total) {
430 double pct = -1;
431 /* I don't understand the below, but it is taken from coreutils' df */
432 /* Seems to be calculating pct, in the best possible way */
433 if (value <= TYPE_MAXIMUM(uintmax_t) / 100
434 && total != 0) {
435 uintmax_t u100 = value * 100;
436 pct = u100 / total + (u100 % total != 0);
437 } else {
438 /* Possible rounding errors - see coreutils' df for more explanation */
439 double u = value;
440 double t = total;
441 if (t) {
442 long int lipct = pct = u * 100 / t;
443 double ipct = lipct;
445 /* Like 'pct = ceil (dpct);', but without ceil - from coreutils again */
446 if (ipct - 1 < pct && pct <= ipct + 1)
447 pct = ipct + (ipct < pct);
448 }
449 }
450 return pct;
451 }
453 /* process command-line arguments */
454 int
455 process_arguments (int argc, char **argv)
456 {
457 int c, err;
458 struct parameter_list *se;
459 struct parameter_list *temp_list = NULL, *previous = NULL;
460 struct parameter_list *temp_path_select_list = NULL;
461 struct mount_entry *me, *temp_me;
462 int result = OK;
463 regex_t re;
464 int cflags = REG_NOSUB | REG_EXTENDED;
465 int default_cflags = cflags;
466 char errbuf[MAX_INPUT_BUFFER];
467 int fnd = 0;
469 int option = 0;
470 static struct option longopts[] = {
471 {"timeout", required_argument, 0, 't'},
472 {"warning", required_argument, 0, 'w'},
473 {"critical", required_argument, 0, 'c'},
474 {"iwarning", required_argument, 0, 'W'},
475 /* Dang, -C is taken. We might want to reshuffle this. */
476 {"icritical", required_argument, 0, 'K'},
477 {"kilobytes", required_argument, 0, 'k'},
478 {"megabytes", required_argument, 0, 'm'},
479 {"units", required_argument, 0, 'u'},
480 {"path", required_argument, 0, 'p'},
481 {"partition", required_argument, 0, 'p'},
482 {"exclude_device", required_argument, 0, 'x'},
483 {"exclude-type", required_argument, 0, 'X'},
484 {"group", required_argument, 0, 'g'},
485 {"eregi-path", required_argument, 0, 'R'},
486 {"eregi-partition", required_argument, 0, 'R'},
487 {"ereg-path", required_argument, 0, 'r'},
488 {"ereg-partition", required_argument, 0, 'r'},
489 {"ignore-ereg-path", required_argument, 0, 'i'},
490 {"ignore-ereg-partition", required_argument, 0, 'i'},
491 {"ignore-eregi-path", required_argument, 0, 'I'},
492 {"ignore-eregi-partition", required_argument, 0, 'I'},
493 {"local", no_argument, 0, 'l'},
494 {"stat-remote-fs", no_argument, 0, 'L'},
495 {"mountpoint", no_argument, 0, 'M'},
496 {"errors-only", no_argument, 0, 'e'},
497 {"exact-match", no_argument, 0, 'E'},
498 {"all", no_argument, 0, 'A'},
499 {"verbose", no_argument, 0, 'v'},
500 {"quiet", no_argument, 0, 'q'},
501 {"clear", no_argument, 0, 'C'},
502 {"version", no_argument, 0, 'V'},
503 {"help", no_argument, 0, 'h'},
504 {0, 0, 0, 0}
505 };
507 if (argc < 2)
508 return ERROR;
510 np_add_name(&fs_exclude_list, "iso9660");
512 for (c = 1; c < argc; c++)
513 if (strcmp ("-to", argv[c]) == 0)
514 strcpy (argv[c], "-t");
516 while (1) {
517 c = getopt_long (argc, argv, "+?VqhveCt:c:w:K:W:u:p:x:X:mklLg:R:r:i:I:MEA", longopts, &option);
519 if (c == -1 || c == EOF)
520 break;
522 switch (c) {
523 case 't': /* timeout period */
524 if (is_integer (optarg)) {
525 timeout_interval = atoi (optarg);
526 break;
527 }
528 else {
529 usage2 (_("Timeout interval must be a positive integer"), optarg);
530 }
532 /* See comments for 'c' */
533 case 'w': /* warning threshold */
534 if (strstr(optarg, "%")) {
535 if (*optarg == '@') {
536 warn_freespace_percent = optarg;
537 } else {
538 asprintf(&warn_freespace_percent, "@%s", optarg);
539 }
540 } else {
541 if (*optarg == '@') {
542 warn_freespace_units = optarg;
543 } else {
544 asprintf(&warn_freespace_units, "@%s", optarg);
545 }
546 }
547 break;
549 /* Awful mistake where the range values do not make sense. Normally,
550 you alert if the value is within the range, but since we are using
551 freespace, we have to alert if outside the range. Thus we artifically
552 force @ at the beginning of the range, so that it is backwards compatible
553 */
554 case 'c': /* critical threshold */
555 if (strstr(optarg, "%")) {
556 if (*optarg == '@') {
557 crit_freespace_percent = optarg;
558 } else {
559 asprintf(&crit_freespace_percent, "@%s", optarg);
560 }
561 } else {
562 if (*optarg == '@') {
563 crit_freespace_units = optarg;
564 } else {
565 asprintf(&crit_freespace_units, "@%s", optarg);
566 }
567 }
568 break;
570 case 'W': /* warning inode threshold */
571 if (*optarg == '@') {
572 warn_freeinodes_percent = optarg;
573 } else {
574 asprintf(&warn_freeinodes_percent, "@%s", optarg);
575 }
576 break;
577 case 'K': /* critical inode threshold */
578 if (*optarg == '@') {
579 crit_freeinodes_percent = optarg;
580 } else {
581 asprintf(&crit_freeinodes_percent, "@%s", optarg);
582 }
583 break;
584 case 'u':
585 if (units)
586 free(units);
587 if (! strcmp (optarg, "bytes")) {
588 mult = (uintmax_t)1;
589 units = strdup ("B");
590 } else if (! strcmp (optarg, "kB")) {
591 mult = (uintmax_t)1024;
592 units = strdup ("kB");
593 } else if (! strcmp (optarg, "MB")) {
594 mult = (uintmax_t)1024 * 1024;
595 units = strdup ("MB");
596 } else if (! strcmp (optarg, "GB")) {
597 mult = (uintmax_t)1024 * 1024 * 1024;
598 units = strdup ("GB");
599 } else if (! strcmp (optarg, "TB")) {
600 mult = (uintmax_t)1024 * 1024 * 1024 * 1024;
601 units = strdup ("TB");
602 } else {
603 die (STATE_UNKNOWN, _("unit type %s not known\n"), optarg);
604 }
605 if (units == NULL)
606 die (STATE_UNKNOWN, _("failed allocating storage for '%s'\n"), "units");
607 break;
608 case 'k': /* display mountpoint */
609 mult = 1024;
610 if (units)
611 free(units);
612 units = strdup ("kB");
613 break;
614 case 'm': /* display mountpoint */
615 mult = 1024 * 1024;
616 if (units)
617 free(units);
618 units = strdup ("MB");
619 break;
620 case 'L':
621 stat_remote_fs = 1;
622 case 'l':
623 show_local_fs = 1;
624 break;
625 case 'p': /* select path */
626 if (! (warn_freespace_units || crit_freespace_units || warn_freespace_percent ||
627 crit_freespace_percent || warn_usedspace_units || crit_usedspace_units ||
628 warn_usedspace_percent || crit_usedspace_percent || warn_usedinodes_percent ||
629 crit_usedinodes_percent || warn_freeinodes_percent || crit_freeinodes_percent )) {
630 die (STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set a threshold value before using -p\n"));
631 }
633 /* add parameter if not found. overwrite thresholds if path has already been added */
634 if (! (se = np_find_parameter(path_select_list, optarg))) {
635 se = np_add_parameter(&path_select_list, optarg);
636 }
637 se->group = group;
638 set_all_thresholds(se);
639 np_set_best_match(se, mount_list, exact_match);
640 stat_path(se);
641 path_selected = TRUE;
642 break;
643 case 'x': /* exclude path or partition */
644 np_add_name(&dp_exclude_list, optarg);
645 break;
646 case 'X': /* exclude file system type */
647 np_add_name(&fs_exclude_list, optarg);
648 break;
649 case 'v': /* verbose */
650 verbose++;
651 break;
652 case 'q': /* TODO: this function should eventually go away (removed 2007-09-20) */
653 /* verbose--; **replaced by line below**. -q was only a broken way of implementing -e */
654 erronly = TRUE;
655 break;
656 case 'e':
657 erronly = TRUE;
658 break;
659 case 'E':
660 if (path_selected)
661 die (STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set -E before selecting pathes\n"));
662 exact_match = TRUE;
663 break;
664 case 'g':
665 if (path_selected)
666 die (STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set group value before selecting pathes \n"));
667 group = optarg;
668 break;
669 case 'I':
670 cflags |= REG_ICASE;
671 case 'i':
672 if (!path_selected)
673 die (STATE_UNKNOWN, "DISK %s: %s\n", _("UNKNOWN"), _("Pathes need to be selected before using -i/-I. Use -A to select all pathes explicitly"));
674 err = regcomp(&re, optarg, cflags);
675 if (err != 0) {
676 regerror (err, &re, errbuf, MAX_INPUT_BUFFER);
677 die (STATE_UNKNOWN, "DISK %s: %s - %s\n",_("UNKNOWN"), _("Could not compile regular expression"), errbuf);
678 }
680 temp_list = path_select_list;
682 previous = NULL;
683 while (temp_list) {
684 if (temp_list->best_match) {
685 if (np_regex_match_mount_entry(temp_list->best_match, &re)) {
687 if (verbose >=3)
688 printf("ignoring %s matching regex\n", temp_list->name);
690 temp_list = np_del_parameter(temp_list, previous);
691 /* pointer to first element needs to be updated if first item gets deleted */
692 if (previous == NULL)
693 path_select_list = temp_list;
694 } else {
695 previous = temp_list;
696 temp_list = temp_list->name_next;
697 }
698 } else {
699 previous = temp_list;
700 temp_list = temp_list->name_next;
701 }
702 }
705 cflags = default_cflags;
706 break;
708 case 'A':
709 optarg = strdup(".*");
710 case 'R':
711 cflags |= REG_ICASE;
712 case 'r':
713 if (! (warn_freespace_units || crit_freespace_units || warn_freespace_percent ||
714 crit_freespace_percent || warn_usedspace_units || crit_usedspace_units ||
715 warn_usedspace_percent || crit_usedspace_percent || warn_usedinodes_percent ||
716 crit_usedinodes_percent || warn_freeinodes_percent || crit_freeinodes_percent )) {
717 die (STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set a threshold value before using -r/-R\n"));
718 }
720 err = regcomp(&re, optarg, cflags);
721 if (err != 0) {
722 regerror (err, &re, errbuf, MAX_INPUT_BUFFER);
723 die (STATE_UNKNOWN, "DISK %s: %s - %s\n",_("UNKNOWN"), _("Could not compile regular expression"), errbuf);
724 }
726 for (me = mount_list; me; me = me->me_next) {
727 if (np_regex_match_mount_entry(me, &re)) {
728 fnd = TRUE;
729 if (verbose > 3)
730 printf("%s %s matching expression %s\n", me->me_devname, me->me_mountdir, optarg);
732 /* add parameter if not found. overwrite thresholds if path has already been added */
733 if (! (se = np_find_parameter(path_select_list, me->me_mountdir))) {
734 se = np_add_parameter(&path_select_list, me->me_mountdir);
735 }
736 se->group = group;
737 set_all_thresholds(se);
738 }
739 }
741 if (!fnd)
742 die (STATE_UNKNOWN, "DISK %s: %s - %s\n",_("UNKNOWN"),
743 _("Regular expression did not match any path or disk"), optarg);
745 fnd = FALSE;
746 path_selected = TRUE;
747 np_set_best_match(path_select_list, mount_list, exact_match);
748 cflags = default_cflags;
750 break;
751 case 'M': /* display mountpoint */
752 display_mntp = TRUE;
753 break;
754 case 'C':
755 /* add all mount entries to path_select list if no partitions have been explicitly defined using -p */
756 if (path_selected == FALSE) {
757 struct mount_entry *me;
758 struct parameter_list *path;
759 for (me = mount_list; me; me = me->me_next) {
760 if (! (path = np_find_parameter(path_select_list, me->me_mountdir)))
761 path = np_add_parameter(&path_select_list, me->me_mountdir);
762 path->best_match = me;
763 path->group = group;
764 set_all_thresholds(path);
765 }
766 }
767 warn_freespace_units = NULL;
768 crit_freespace_units = NULL;
769 warn_usedspace_units = NULL;
770 crit_usedspace_units = NULL;
771 warn_freespace_percent = NULL;
772 crit_freespace_percent = NULL;
773 warn_usedspace_percent = NULL;
774 crit_usedspace_percent = NULL;
775 warn_usedinodes_percent = NULL;
776 crit_usedinodes_percent = NULL;
777 warn_freeinodes_percent = NULL;
778 crit_freeinodes_percent = NULL;
780 path_selected = FALSE;
781 group = NULL;
782 break;
783 case 'V': /* version */
784 print_revision (progname, revision);
785 exit (STATE_OK);
786 case 'h': /* help */
787 print_help ();
788 exit (STATE_OK);
789 case '?': /* help */
790 usage (_("Unknown argument"));
791 }
792 }
794 /* Support for "check_disk warn crit [fs]" with thresholds at used% level */
795 c = optind;
796 if (warn_usedspace_percent == NULL && argc > c && is_intnonneg (argv[c]))
797 warn_usedspace_percent = argv[c++];
799 if (crit_usedspace_percent == NULL && argc > c && is_intnonneg (argv[c]))
800 crit_usedspace_percent = argv[c++];
802 if (argc > c && path == NULL) {
803 se = np_add_parameter(&path_select_list, strdup(argv[c++]));
804 path_selected = TRUE;
805 set_all_thresholds(se);
806 }
808 if (units == NULL) {
809 units = strdup ("MB");
810 mult = (uintmax_t)1024 * 1024;
811 }
813 return TRUE;
814 }
818 void
819 print_path (const char *mypath)
820 {
821 if (mypath == NULL)
822 printf ("\n");
823 else
824 printf (_(" for %s\n"), mypath);
825 }
828 void
829 set_all_thresholds (struct parameter_list *path)
830 {
831 if (path->freespace_units != NULL) free(path->freespace_units);
832 set_thresholds(&path->freespace_units, warn_freespace_units, crit_freespace_units);
833 if (path->freespace_percent != NULL) free (path->freespace_percent);
834 set_thresholds(&path->freespace_percent, warn_freespace_percent, crit_freespace_percent);
835 if (path->usedspace_units != NULL) free (path->usedspace_units);
836 set_thresholds(&path->usedspace_units, warn_usedspace_units, crit_usedspace_units);
837 if (path->usedspace_percent != NULL) free (path->usedspace_percent);
838 set_thresholds(&path->usedspace_percent, warn_usedspace_percent, crit_usedspace_percent);
839 if (path->usedinodes_percent != NULL) free (path->usedinodes_percent);
840 set_thresholds(&path->usedinodes_percent, warn_usedinodes_percent, crit_usedinodes_percent);
841 if (path->freeinodes_percent != NULL) free (path->freeinodes_percent);
842 set_thresholds(&path->freeinodes_percent, warn_freeinodes_percent, crit_freeinodes_percent);
843 }
845 /* TODO: Remove?
847 int
848 validate_arguments (uintmax_t w, uintmax_t c, double wp, double cp, double iwp, double icp, char *mypath)
849 {
850 if (w < 0 && c < 0 && wp < 0.0 && cp < 0.0) {
851 printf (_("INPUT ERROR: No thresholds specified"));
852 print_path (mypath);
853 return ERROR;
854 }
855 else if ((wp >= 0.0 || cp >= 0.0) &&
856 (wp < 0.0 || cp < 0.0 || wp > 100.0 || cp > 100.0 || cp > wp)) {
857 printf (_("\
858 INPUT ERROR: C_DFP (%f) should be less than W_DFP (%.1f) and both should be between zero and 100 percent, inclusive"),
859 cp, wp);
860 print_path (mypath);
861 return ERROR;
862 }
863 else if ((iwp >= 0.0 || icp >= 0.0) &&
864 (iwp < 0.0 || icp < 0.0 || iwp > 100.0 || icp > 100.0 || icp > iwp)) {
865 printf (_("\
866 INPUT ERROR: C_IDFP (%f) should be less than W_IDFP (%.1f) and both should be between zero and 100 percent, inclusive"),
867 icp, iwp);
868 print_path (mypath);
869 return ERROR;
870 }
871 else if ((w > 0 || c > 0) && (w == 0 || c == 0 || c > w)) {
872 printf (_("\
873 INPUT ERROR: C_DF (%lu) should be less than W_DF (%lu) and both should be greater than zero"),
874 (unsigned long)c, (unsigned long)w);
875 print_path (mypath);
876 return ERROR;
877 }
879 return OK;
880 }
882 */
890 void
891 print_help (void)
892 {
893 print_revision (progname, revision);
895 printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
896 printf (COPYRIGHT, copyright, email);
898 printf ("%s\n", _("This plugin checks the amount of used disk space on a mounted file system"));
899 printf ("%s\n", _("and generates an alert if free space is less than one of the threshold values"));
901 printf ("\n\n");
903 print_usage ();
905 printf (_(UT_HELP_VRSN));
907 printf (" %s\n", "-w, --warning=INTEGER");
908 printf (" %s\n", _("Exit with WARNING status if less than INTEGER units of disk are free"));
909 printf (" %s\n", "-w, --warning=PERCENT%");
910 printf (" %s\n", _("Exit with WARNING status if less than PERCENT of disk space is free"));
911 printf (" %s\n", "-c, --critical=INTEGER");
912 printf (" %s\n", _("Exit with CRITICAL status if less than INTEGER units of disk are free"));
913 printf (" %s\n", "-c, --critical=PERCENT%");
914 printf (" %s\n", _("Exit with CRITCAL status if less than PERCENT of disk space is free"));
915 printf (" %s\n", "-W, --iwarning=PERCENT%");
916 printf (" %s\n", _("Exit with WARNING status if less than PERCENT of inode space is free"));
917 printf (" %s\n", "-K, --icritical=PERCENT%");
918 printf (" %s\n", _("Exit with CRITICAL status if less than PERCENT of inode space is free"));
919 printf (" %s\n", "-p, --path=PATH, --partition=PARTITION");
920 printf (" %s\n", _("Path or partition (may be repeated)"));
921 printf (" %s\n", "-x, --exclude_device=PATH <STRING>");
922 printf (" %s\n", _("Ignore device (only works if -p unspecified)"));
923 printf (" %s\n", "-C, --clear");
924 printf (" %s\n", _("Clear thresholds"));
925 printf (" %s\n", "-E, --exact-match");
926 printf (" %s\n", _("For paths or partitions specified with -p, only check for exact paths"));
927 printf (" %s\n", "-e, --errors-only");
928 printf (" %s\n", _("Display only devices/mountpoints with errors"));
929 printf (" %s\n", "-g, --group=NAME");
930 printf (" %s\n", _("Group pathes. Thresholds apply to (free-)space of all partitions together"));
931 printf (" %s\n", "-k, --kilobytes");
932 printf (" %s\n", _("Same as '--units kB'"));
933 printf (" %s\n", "-l, --local");
934 printf (" %s\n", _("Only check local filesystems"));
935 printf (" %s\n", "-L, --stat-remote-fs");
936 printf (" %s\n", _("Only check local filesystems against thresholds. Yet call stat on remote filesystems"));
937 printf (" %s\n", _("to test if they are accessible (e.g. to detect Stale NFS Handles)"));
938 printf (" %s\n", "-M, --mountpoint");
939 printf (" %s\n", _("Display the mountpoint instead of the partition"));
940 printf (" %s\n", "-m, --megabytes");
941 printf (" %s\n", _("Same as '--units MB'"));
942 printf (" %s\n", "-A, --all");
943 printf (" %s\n", _("Explicitly select all pathes. This is equivalent to -R '.*'"));
944 printf (" %s\n", "-R, --eregi-path=PATH, --eregi-partition=PARTITION");
945 printf (" %s\n", _("Case insensitive regular expression for path/partition (may be repeated)"));
946 printf (" %s\n", "-r, --ereg-path=PATH, --ereg-partition=PARTITION");
947 printf (" %s\n", _("Regular expression for path or partition (may be repeated)"));
948 printf (" %s\n", "-I, --ignore-eregi-path=PATH, --ignore-eregi-partition=PARTITION");
949 printf (" %s\n", _("Regular expression to ignore selected path/partition (case insensitive) (may be repeated)"));
950 printf (" %s\n", "-i, --ignore-ereg-path=PATH, --ignore-ereg-partition=PARTITION");
951 printf (" %s\n", _("Regular expression to ignore selected path or partition (may be repeated)"));
952 printf (_(UT_TIMEOUT), DEFAULT_SOCKET_TIMEOUT);
953 printf (" %s\n", "-u, --units=STRING");
954 printf (" %s\n", _("Choose bytes, kB, MB, GB, TB (default: MB)"));
955 printf (_(UT_VERBOSE));
956 printf (" %s\n", "-X, --exclude-type=TYPE");
957 printf (" %s\n", _("Ignore all filesystems of indicated type (may be repeated)"));
958 printf ("\n");
959 printf ("%s\n", _("Examples:"));
960 printf (" %s\n", "check_disk -w 10% -c 5% -p /tmp -p /var -C -w 100000 -c 50000 -p /");
961 printf (" %s\n", _("Checks /tmp and /var at 10% and 5%, and / at 100MB and 50MB"));
962 printf (" %s\n", "check_disk -w 100M -c 50M -C -w 1000M -c 500M -g sidDATA -r '^/oracle/SID/data.*$'");
963 printf (" %s\n", _("Checks all filesystems not matching -r at 100M and 50M. The fs matching the -r regex"));
964 printf (" %s\n", _("are grouped which means the freespace thresholds are applied to all disks together"));
965 printf (" %s\n", "check_disk -w 100M -c 50M -C -w 1000M -c 500M -p /foo -C -w 5% -c 3% -p /bar");
966 printf (" %s\n", _("Checks /foo for 1000M/500M and /bar for 5/3%. All remaining volumes use 100M/50M"));
967 printf (_(UT_SUPPORT));
968 }
972 void
973 print_usage (void)
974 {
975 printf (_("Usage:"));
976 printf (" %s -w limit -c limit [-W limit] [-K limit] {-p path | -x device}\n", progname);
977 printf ("[-C] [-E] [-e] [-g group ] [-k] [-l] [-M] [-m] [-R path ] [-r path ]\n");
978 printf ("[-t timeout] [-u unit] [-v] [-X type]\n");
979 }
981 void
982 stat_path (struct parameter_list *p)
983 {
984 /* Stat entry to check that dir exists and is accessible */
985 if (verbose > 3)
986 printf("calling stat on %s\n", p->name);
987 if (stat (p->name, &stat_buf[0])) {
988 if (verbose > 3)
989 printf("stat failed on %s\n", p->name);
990 printf("DISK %s - ", _("CRITICAL"));
991 die (STATE_CRITICAL, _("%s %s: %s\n"), p->name, _("is not accessible"), strerror(errno));
992 }
993 }