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 /* 2007-12-08 - Workaround for Gnulib reporting insanely high available
311 * space on BSD (the actual value should be negative but fsp.fsu_bavail
312 * is unsigned) */
313 available = fsp.fsu_bavail > fsp.fsu_bfree ? 0 : fsp.fsu_bavail;
314 available_to_root = fsp.fsu_bfree;
315 used = total - available_to_root;
317 if (verbose >= 3)
318 printf ("For %s, total=%llu, available=%llu, available_to_root=%llu, used=%llu, fsp.fsu_files=%llu, fsp.fsu_ffree=%llu\n",
319 me->me_mountdir, total, available, available_to_root, used, fsp.fsu_files, fsp.fsu_ffree);
321 dused_pct = calculate_percent( used, used + available ); /* used + available can never be > uintmax */
323 dfree_pct = 100 - dused_pct;
324 dused_units = used*fsp.fsu_blocksize/mult;
325 dfree_units = available*fsp.fsu_blocksize/mult;
326 dtotal_units = total*fsp.fsu_blocksize/mult;
327 dused_inodes_percent = calculate_percent(fsp.fsu_files - fsp.fsu_ffree, fsp.fsu_files);
328 dfree_inodes_percent = 100 - dused_inodes_percent;
330 if (verbose >= 3) {
331 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",
332 me->me_mountdir, dused_pct, dfree_pct, dused_units, dfree_units, dtotal_units, dused_inodes_percent, dfree_inodes_percent, fsp.fsu_blocksize, mult);
333 }
335 /* Threshold comparisons */
337 temp_result = get_status(dfree_units, path->freespace_units);
338 if (verbose >=3) printf("Freespace_units result=%d\n", temp_result);
339 disk_result = max_state( disk_result, temp_result );
341 temp_result = get_status(dfree_pct, path->freespace_percent);
342 if (verbose >=3) printf("Freespace%% result=%d\n", temp_result);
343 disk_result = max_state( disk_result, temp_result );
345 temp_result = get_status(dused_units, path->usedspace_units);
346 if (verbose >=3) printf("Usedspace_units result=%d\n", temp_result);
347 disk_result = max_state( disk_result, temp_result );
349 temp_result = get_status(dused_pct, path->usedspace_percent);
350 if (verbose >=3) printf("Usedspace_percent result=%d\n", temp_result);
351 disk_result = max_state( disk_result, temp_result );
353 temp_result = get_status(dused_inodes_percent, path->usedinodes_percent);
354 if (verbose >=3) printf("Usedinodes_percent result=%d\n", temp_result);
355 disk_result = max_state( disk_result, temp_result );
357 temp_result = get_status(dfree_inodes_percent, path->freeinodes_percent);
358 if (verbose >=3) printf("Freeinodes_percent result=%d\n", temp_result);
359 disk_result = max_state( disk_result, temp_result );
361 result = max_state(result, disk_result);
363 /* What a mess of units. The output shows free space, the perf data shows used space. Yikes!
364 Hack here. Trying to get warn/crit levels from freespace_(units|percent) for perf
365 data. Assumption that start=0. Roll on new syntax...
366 */
368 /* *_high_tide must be reinitialized at each run */
369 warning_high_tide = UINT_MAX;
370 critical_high_tide = UINT_MAX;
372 if (path->freespace_units->warning != NULL) {
373 warning_high_tide = dtotal_units - path->freespace_units->warning->end;
374 }
375 if (path->freespace_percent->warning != NULL) {
376 warning_high_tide = abs( min( (double) warning_high_tide, (double) (1.0 - path->freespace_percent->warning->end/100)*dtotal_units ));
377 }
378 if (path->freespace_units->critical != NULL) {
379 critical_high_tide = dtotal_units - path->freespace_units->critical->end;
380 }
381 if (path->freespace_percent->critical != NULL) {
382 critical_high_tide = abs( min( (double) critical_high_tide, (double) (1.0 - path->freespace_percent->critical->end/100)*dtotal_units ));
383 }
385 /* Nb: *_high_tide are unset when == UINT_MAX */
386 asprintf (&perf, "%s %s", perf,
387 perfdata ((!strcmp(me->me_mountdir, "none") || display_mntp) ? me->me_devname : me->me_mountdir,
388 dused_units, units,
389 (warning_high_tide != UINT_MAX ? TRUE : FALSE), warning_high_tide,
390 (critical_high_tide != UINT_MAX ? TRUE : FALSE), critical_high_tide,
391 TRUE, 0,
392 TRUE, dtotal_units));
394 if (disk_result==STATE_OK && erronly && !verbose)
395 continue;
397 asprintf (&output, "%s %s %.0f %s (%.0f%%",
398 output,
399 (!strcmp(me->me_mountdir, "none") || display_mntp) ? me->me_devname : me->me_mountdir,
400 dfree_units,
401 units,
402 dfree_pct);
403 if (dused_inodes_percent < 0) {
404 asprintf(&output, "%s inode=-);", output);
405 } else {
406 asprintf(&output, "%s inode=%.0f%%);", output, dfree_inodes_percent );
407 }
409 /* TODO: Need to do a similar debug line
410 asprintf (&details, _("%s\n\
411 %.0f of %.0f %s (%.0f%% inode=%.0f%%) free on %s (type %s mounted on %s) warn:%lu crit:%lu warn%%:%.0f%% crit%%:%.0f%%"),
412 details, dfree_units, dtotal_units, units, dfree_pct, inode_space_pct,
413 me->me_devname, me->me_type, me->me_mountdir,
414 (unsigned long)w_df, (unsigned long)c_df, w_dfp, c_dfp);
415 */
417 }
419 }
421 if (verbose > 2)
422 asprintf (&output, "%s%s", output, details);
425 printf ("DISK %s%s%s|%s\n", state_text (result), (erronly && result==STATE_OK) ? "" : preamble, output, perf);
426 return result;
427 }
430 double calculate_percent(uintmax_t value, uintmax_t total) {
431 double pct = -1;
432 /* I don't understand the below, but it is taken from coreutils' df */
433 /* Seems to be calculating pct, in the best possible way */
434 if (value <= TYPE_MAXIMUM(uintmax_t) / 100
435 && total != 0) {
436 uintmax_t u100 = value * 100;
437 pct = u100 / total + (u100 % total != 0);
438 } else {
439 /* Possible rounding errors - see coreutils' df for more explanation */
440 double u = value;
441 double t = total;
442 if (t) {
443 long int lipct = pct = u * 100 / t;
444 double ipct = lipct;
446 /* Like 'pct = ceil (dpct);', but without ceil - from coreutils again */
447 if (ipct - 1 < pct && pct <= ipct + 1)
448 pct = ipct + (ipct < pct);
449 }
450 }
451 return pct;
452 }
454 /* process command-line arguments */
455 int
456 process_arguments (int argc, char **argv)
457 {
458 int c, err;
459 struct parameter_list *se;
460 struct parameter_list *temp_list = NULL, *previous = NULL;
461 struct parameter_list *temp_path_select_list = NULL;
462 struct mount_entry *me, *temp_me;
463 int result = OK;
464 regex_t re;
465 int cflags = REG_NOSUB | REG_EXTENDED;
466 int default_cflags = cflags;
467 char errbuf[MAX_INPUT_BUFFER];
468 int fnd = 0;
470 int option = 0;
471 static struct option longopts[] = {
472 {"timeout", required_argument, 0, 't'},
473 {"warning", required_argument, 0, 'w'},
474 {"critical", required_argument, 0, 'c'},
475 {"iwarning", required_argument, 0, 'W'},
476 /* Dang, -C is taken. We might want to reshuffle this. */
477 {"icritical", required_argument, 0, 'K'},
478 {"local", required_argument, 0, 'l'},
479 {"stat-remote-fs", required_argument, 0, 'L'},
480 {"kilobytes", required_argument, 0, 'k'},
481 {"megabytes", required_argument, 0, 'm'},
482 {"units", required_argument, 0, 'u'},
483 {"path", required_argument, 0, 'p'},
484 {"partition", required_argument, 0, 'p'},
485 {"exclude_device", required_argument, 0, 'x'},
486 {"exclude-type", required_argument, 0, 'X'},
487 {"group", required_argument, 0, 'g'},
488 {"eregi-path", required_argument, 0, 'R'},
489 {"eregi-partition", required_argument, 0, 'R'},
490 {"ereg-path", required_argument, 0, 'r'},
491 {"ereg-partition", required_argument, 0, 'r'},
492 {"ignore-ereg-path", required_argument, 0, 'i'},
493 {"ignore-ereg-partition", required_argument, 0, 'i'},
494 {"ignore-eregi-path", required_argument, 0, 'I'},
495 {"ignore-eregi-partition", required_argument, 0, 'I'},
496 {"mountpoint", no_argument, 0, 'M'},
497 {"errors-only", no_argument, 0, 'e'},
498 {"exact-match", no_argument, 0, 'E'},
499 {"all", no_argument, 0, 'A'},
500 {"verbose", no_argument, 0, 'v'},
501 {"quiet", no_argument, 0, 'q'},
502 {"clear", no_argument, 0, 'C'},
503 {"version", no_argument, 0, 'V'},
504 {"help", no_argument, 0, 'h'},
505 {0, 0, 0, 0}
506 };
508 if (argc < 2)
509 return ERROR;
511 np_add_name(&fs_exclude_list, "iso9660");
513 for (c = 1; c < argc; c++)
514 if (strcmp ("-to", argv[c]) == 0)
515 strcpy (argv[c], "-t");
517 while (1) {
518 c = getopt_long (argc, argv, "+?VqhveCt:c:w:K:W:u:p:x:X:mklLg:R:r:i:I:MEA", longopts, &option);
520 if (c == -1 || c == EOF)
521 break;
523 switch (c) {
524 case 't': /* timeout period */
525 if (is_integer (optarg)) {
526 timeout_interval = atoi (optarg);
527 break;
528 }
529 else {
530 usage2 (_("Timeout interval must be a positive integer"), optarg);
531 }
533 /* See comments for 'c' */
534 case 'w': /* warning threshold */
535 if (strstr(optarg, "%")) {
536 if (*optarg == '@') {
537 warn_freespace_percent = optarg;
538 } else {
539 asprintf(&warn_freespace_percent, "@%s", optarg);
540 }
541 } else {
542 if (*optarg == '@') {
543 warn_freespace_units = optarg;
544 } else {
545 asprintf(&warn_freespace_units, "@%s", optarg);
546 }
547 }
548 break;
550 /* Awful mistake where the range values do not make sense. Normally,
551 you alert if the value is within the range, but since we are using
552 freespace, we have to alert if outside the range. Thus we artifically
553 force @ at the beginning of the range, so that it is backwards compatible
554 */
555 case 'c': /* critical threshold */
556 if (strstr(optarg, "%")) {
557 if (*optarg == '@') {
558 crit_freespace_percent = optarg;
559 } else {
560 asprintf(&crit_freespace_percent, "@%s", optarg);
561 }
562 } else {
563 if (*optarg == '@') {
564 crit_freespace_units = optarg;
565 } else {
566 asprintf(&crit_freespace_units, "@%s", optarg);
567 }
568 }
569 break;
571 case 'W': /* warning inode threshold */
572 if (*optarg == '@') {
573 warn_freeinodes_percent = optarg;
574 } else {
575 asprintf(&warn_freeinodes_percent, "@%s", optarg);
576 }
577 break;
578 case 'K': /* critical inode threshold */
579 if (*optarg == '@') {
580 crit_freeinodes_percent = optarg;
581 } else {
582 asprintf(&crit_freeinodes_percent, "@%s", optarg);
583 }
584 break;
585 case 'u':
586 if (units)
587 free(units);
588 if (! strcmp (optarg, "bytes")) {
589 mult = (uintmax_t)1;
590 units = strdup ("B");
591 } else if (! strcmp (optarg, "kB")) {
592 mult = (uintmax_t)1024;
593 units = strdup ("kB");
594 } else if (! strcmp (optarg, "MB")) {
595 mult = (uintmax_t)1024 * 1024;
596 units = strdup ("MB");
597 } else if (! strcmp (optarg, "GB")) {
598 mult = (uintmax_t)1024 * 1024 * 1024;
599 units = strdup ("GB");
600 } else if (! strcmp (optarg, "TB")) {
601 mult = (uintmax_t)1024 * 1024 * 1024 * 1024;
602 units = strdup ("TB");
603 } else {
604 die (STATE_UNKNOWN, _("unit type %s not known\n"), optarg);
605 }
606 if (units == NULL)
607 die (STATE_UNKNOWN, _("failed allocating storage for '%s'\n"), "units");
608 break;
609 case 'k': /* display mountpoint */
610 mult = 1024;
611 if (units)
612 free(units);
613 units = strdup ("kB");
614 break;
615 case 'm': /* display mountpoint */
616 mult = 1024 * 1024;
617 if (units)
618 free(units);
619 units = strdup ("MB");
620 break;
621 case 'L':
622 stat_remote_fs = 1;
623 case 'l':
624 show_local_fs = 1;
625 break;
626 case 'p': /* select path */
627 if (! (warn_freespace_units || crit_freespace_units || warn_freespace_percent ||
628 crit_freespace_percent || warn_usedspace_units || crit_usedspace_units ||
629 warn_usedspace_percent || crit_usedspace_percent || warn_usedinodes_percent ||
630 crit_usedinodes_percent || warn_freeinodes_percent || crit_freeinodes_percent )) {
631 die (STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set a threshold value before using -p\n"));
632 }
634 /* add parameter if not found. overwrite thresholds if path has already been added */
635 if (! (se = np_find_parameter(path_select_list, optarg))) {
636 se = np_add_parameter(&path_select_list, optarg);
637 }
638 se->group = group;
639 set_all_thresholds(se);
640 np_set_best_match(se, mount_list, exact_match);
641 stat_path(se);
642 path_selected = TRUE;
643 break;
644 case 'x': /* exclude path or partition */
645 np_add_name(&dp_exclude_list, optarg);
646 break;
647 case 'X': /* exclude file system type */
648 np_add_name(&fs_exclude_list, optarg);
649 break;
650 case 'v': /* verbose */
651 verbose++;
652 break;
653 case 'q': /* TODO: this function should eventually go away (removed 2007-09-20) */
654 /* verbose--; **replaced by line below**. -q was only a broken way of implementing -e */
655 erronly = TRUE;
656 break;
657 case 'e':
658 erronly = TRUE;
659 break;
660 case 'E':
661 if (path_selected)
662 die (STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set -E before selecting pathes\n"));
663 exact_match = TRUE;
664 break;
665 case 'g':
666 if (path_selected)
667 die (STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set group value before selecting pathes \n"));
668 group = optarg;
669 break;
670 case 'I':
671 cflags |= REG_ICASE;
672 case 'i':
673 if (!path_selected)
674 die (STATE_UNKNOWN, "DISK %s: %s\n", _("UNKNOWN"), _("Pathes need to be selected before using -i/-I. Use -A to select all pathes explicitly"));
675 err = regcomp(&re, optarg, cflags);
676 if (err != 0) {
677 regerror (err, &re, errbuf, MAX_INPUT_BUFFER);
678 die (STATE_UNKNOWN, "DISK %s: %s - %s\n",_("UNKNOWN"), _("Could not compile regular expression"), errbuf);
679 }
681 temp_list = path_select_list;
683 previous = NULL;
684 while (temp_list) {
685 if (temp_list->best_match) {
686 if (np_regex_match_mount_entry(temp_list->best_match, &re)) {
688 if (verbose >=3)
689 printf("ignoring %s matching regex\n", temp_list->name);
691 temp_list = np_del_parameter(temp_list, previous);
692 /* pointer to first element needs to be uĆ¼dated if first item gets deleted */
693 if (previous == NULL)
694 path_select_list = temp_list;
695 } else {
696 previous = temp_list;
697 temp_list = temp_list->name_next;
698 }
699 } else {
700 previous = temp_list;
701 temp_list = temp_list->name_next;
702 }
703 }
706 cflags = default_cflags;
707 break;
709 case 'A':
710 optarg = strdup(".*");
711 case 'R':
712 cflags |= REG_ICASE;
713 case 'r':
714 if (! (warn_freespace_units || crit_freespace_units || warn_freespace_percent ||
715 crit_freespace_percent || warn_usedspace_units || crit_usedspace_units ||
716 warn_usedspace_percent || crit_usedspace_percent || warn_usedinodes_percent ||
717 crit_usedinodes_percent || warn_freeinodes_percent || crit_freeinodes_percent )) {
718 die (STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set a threshold value before using -r/-R\n"));
719 }
721 err = regcomp(&re, optarg, cflags);
722 if (err != 0) {
723 regerror (err, &re, errbuf, MAX_INPUT_BUFFER);
724 die (STATE_UNKNOWN, "DISK %s: %s - %s\n",_("UNKNOWN"), _("Could not compile regular expression"), errbuf);
725 }
727 for (me = mount_list; me; me = me->me_next) {
728 if (np_regex_match_mount_entry(me, &re)) {
729 fnd = TRUE;
730 if (verbose > 3)
731 printf("%s %s matching expression %s\n", me->me_devname, me->me_mountdir, optarg);
733 /* add parameter if not found. overwrite thresholds if path has already been added */
734 if (! (se = np_find_parameter(path_select_list, me->me_mountdir))) {
735 se = np_add_parameter(&path_select_list, me->me_mountdir);
736 }
737 se->group = group;
738 set_all_thresholds(se);
739 }
740 }
742 if (!fnd)
743 die (STATE_UNKNOWN, "DISK %s: %s - %s\n",_("UNKNOWN"),
744 _("Regular expression did not match any path or disk"), optarg);
746 fnd = FALSE;
747 path_selected = TRUE;
748 np_set_best_match(path_select_list, mount_list, exact_match);
749 cflags = default_cflags;
751 break;
752 case 'M': /* display mountpoint */
753 display_mntp = TRUE;
754 break;
755 case 'C':
756 /* add all mount entries to path_select list if no partitions have been explicitly defined using -p */
757 if (path_selected == FALSE) {
758 struct mount_entry *me;
759 struct parameter_list *path;
760 for (me = mount_list; me; me = me->me_next) {
761 if (! (path = np_find_parameter(path_select_list, me->me_mountdir)))
762 path = np_add_parameter(&path_select_list, me->me_mountdir);
763 path->best_match = me;
764 path->group = group;
765 set_all_thresholds(path);
766 }
767 }
768 warn_freespace_units = NULL;
769 crit_freespace_units = NULL;
770 warn_usedspace_units = NULL;
771 crit_usedspace_units = NULL;
772 warn_freespace_percent = NULL;
773 crit_freespace_percent = NULL;
774 warn_usedspace_percent = NULL;
775 crit_usedspace_percent = NULL;
776 warn_usedinodes_percent = NULL;
777 crit_usedinodes_percent = NULL;
778 warn_freeinodes_percent = NULL;
779 crit_freeinodes_percent = NULL;
781 path_selected = FALSE;
782 group = NULL;
783 break;
784 case 'V': /* version */
785 print_revision (progname, revision);
786 exit (STATE_OK);
787 case 'h': /* help */
788 print_help ();
789 exit (STATE_OK);
790 case '?': /* help */
791 usage (_("Unknown argument"));
792 }
793 }
795 /* Support for "check_disk warn crit [fs]" with thresholds at used% level */
796 c = optind;
797 if (warn_usedspace_percent == NULL && argc > c && is_intnonneg (argv[c]))
798 warn_usedspace_percent = argv[c++];
800 if (crit_usedspace_percent == NULL && argc > c && is_intnonneg (argv[c]))
801 crit_usedspace_percent = argv[c++];
803 if (argc > c && path == NULL) {
804 se = np_add_parameter(&path_select_list, strdup(argv[c++]));
805 path_selected = TRUE;
806 set_all_thresholds(se);
807 }
809 if (units == NULL) {
810 units = strdup ("MB");
811 mult = (uintmax_t)1024 * 1024;
812 }
814 return TRUE;
815 }
819 void
820 print_path (const char *mypath)
821 {
822 if (mypath == NULL)
823 printf ("\n");
824 else
825 printf (_(" for %s\n"), mypath);
826 }
829 void
830 set_all_thresholds (struct parameter_list *path)
831 {
832 set_thresholds(&path->freespace_units, warn_freespace_units, crit_freespace_units);
833 set_thresholds(&path->freespace_percent, warn_freespace_percent, crit_freespace_percent);
834 set_thresholds(&path->usedspace_units, warn_usedspace_units, crit_usedspace_units);
835 set_thresholds(&path->usedspace_percent, warn_usedspace_percent, crit_usedspace_percent);
836 set_thresholds(&path->usedinodes_percent, warn_usedinodes_percent, crit_usedinodes_percent);
837 set_thresholds(&path->freeinodes_percent, warn_freeinodes_percent, crit_freeinodes_percent);
838 }
840 /* TODO: Remove?
842 int
843 validate_arguments (uintmax_t w, uintmax_t c, double wp, double cp, double iwp, double icp, char *mypath)
844 {
845 if (w < 0 && c < 0 && wp < 0.0 && cp < 0.0) {
846 printf (_("INPUT ERROR: No thresholds specified"));
847 print_path (mypath);
848 return ERROR;
849 }
850 else if ((wp >= 0.0 || cp >= 0.0) &&
851 (wp < 0.0 || cp < 0.0 || wp > 100.0 || cp > 100.0 || cp > wp)) {
852 printf (_("\
853 INPUT ERROR: C_DFP (%f) should be less than W_DFP (%.1f) and both should be between zero and 100 percent, inclusive"),
854 cp, wp);
855 print_path (mypath);
856 return ERROR;
857 }
858 else if ((iwp >= 0.0 || icp >= 0.0) &&
859 (iwp < 0.0 || icp < 0.0 || iwp > 100.0 || icp > 100.0 || icp > iwp)) {
860 printf (_("\
861 INPUT ERROR: C_IDFP (%f) should be less than W_IDFP (%.1f) and both should be between zero and 100 percent, inclusive"),
862 icp, iwp);
863 print_path (mypath);
864 return ERROR;
865 }
866 else if ((w > 0 || c > 0) && (w == 0 || c == 0 || c > w)) {
867 printf (_("\
868 INPUT ERROR: C_DF (%lu) should be less than W_DF (%lu) and both should be greater than zero"),
869 (unsigned long)c, (unsigned long)w);
870 print_path (mypath);
871 return ERROR;
872 }
874 return OK;
875 }
877 */
885 void
886 print_help (void)
887 {
888 print_revision (progname, revision);
890 printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
891 printf (COPYRIGHT, copyright, email);
893 printf ("%s\n", _("This plugin checks the amount of used disk space on a mounted file system"));
894 printf ("%s\n", _("and generates an alert if free space is less than one of the threshold values"));
896 printf ("\n\n");
898 print_usage ();
900 printf (_(UT_HELP_VRSN));
902 printf (" %s\n", "-w, --warning=INTEGER");
903 printf (" %s\n", _("Exit with WARNING status if less than INTEGER units of disk are free"));
904 printf (" %s\n", "-w, --warning=PERCENT%");
905 printf (" %s\n", _("Exit with WARNING status if less than PERCENT of disk space is free"));
906 printf (" %s\n", "-c, --critical=INTEGER");
907 printf (" %s\n", _("Exit with CRITICAL status if less than INTEGER units of disk are free"));
908 printf (" %s\n", "-c, --critical=PERCENT%");
909 printf (" %s\n", _("Exit with CRITCAL status if less than PERCENT of disk space is free"));
910 printf (" %s\n", "-W, --iwarning=PERCENT%");
911 printf (" %s\n", _("Exit with WARNING status if less than PERCENT of inode space is free"));
912 printf (" %s\n", "-K, --icritical=PERCENT%");
913 printf (" %s\n", _("Exit with CRITICAL status if less than PERCENT of inode space is free"));
914 printf (" %s\n", "-p, --path=PATH, --partition=PARTITION");
915 printf (" %s\n", _("Path or partition (may be repeated)"));
916 printf (" %s\n", "-x, --exclude_device=PATH <STRING>");
917 printf (" %s\n", _("Ignore device (only works if -p unspecified)"));
918 printf (" %s\n", "-C, --clear");
919 printf (" %s\n", _("Clear thresholds"));
920 printf (" %s\n", "-E, --exact-match");
921 printf (" %s\n", _("For paths or partitions specified with -p, only check for exact paths"));
922 printf (" %s\n", "-e, --errors-only");
923 printf (" %s\n", _("Display only devices/mountpoints with errors"));
924 printf (" %s\n", "-g, --group=NAME");
925 printf (" %s\n", _("Group pathes. Thresholds apply to (free-)space of all partitions together"));
926 printf (" %s\n", "-k, --kilobytes");
927 printf (" %s\n", _("Same as '--units kB'"));
928 printf (" %s\n", "-l, --local");
929 printf (" %s\n", _("Only check local filesystems"));
930 printf (" %s\n", "-L, --stat-remote-fs");
931 printf (" %s\n", _("Only check local filesystems against thresholds. Yet call stat on remote filesystems"));
932 printf (" %s\n", _("to test if they are accessible (e.g. to detect Stale NFS Handles)"));
933 printf (" %s\n", "-M, --mountpoint");
934 printf (" %s\n", _("Display the mountpoint instead of the partition"));
935 printf (" %s\n", "-m, --megabytes");
936 printf (" %s\n", _("Same as '--units MB'"));
937 printf (" %s\n", "-A, --all");
938 printf (" %s\n", _("Explicitly select all pathes. This is equivalent to -R '.*'"));
939 printf (" %s\n", "-R, --eregi-path=PATH, --eregi-partition=PARTITION");
940 printf (" %s\n", _("Case insensitive regular expression for path/partition (may be repeated)"));
941 printf (" %s\n", "-r, --ereg-path=PATH, --ereg-partition=PARTITION");
942 printf (" %s\n", _("Regular expression for path or partition (may be repeated)"));
943 printf (" %s\n", "-I, --ignore-eregi-path=PATH, --ignore-eregi-partition=PARTITION");
944 printf (" %s\n", _("Regular expression to ignore selected path/partition (case insensitive) (may be repeated)"));
945 printf (" %s\n", "-i, --ignore-ereg-path=PATH, --ignore-ereg-partition=PARTITION");
946 printf (" %s\n", _("Regular expression to ignore selected path or partition (may be repeated)"));
947 printf (_(UT_TIMEOUT), DEFAULT_SOCKET_TIMEOUT);
948 printf (" %s\n", "-u, --units=STRING");
949 printf (" %s\n", _("Choose bytes, kB, MB, GB, TB (default: MB)"));
950 printf (_(UT_VERBOSE));
951 printf (" %s\n", "-X, --exclude-type=TYPE");
952 printf (" %s\n", _("Ignore all filesystems of indicated type (may be repeated)"));
953 printf ("\n");
954 printf ("%s\n", _("Examples:"));
955 printf (" %s\n", "check_disk -w 10% -c 5% -p /tmp -p /var -C -w 100000 -c 50000 -p /");
956 printf (" %s\n", _("Checks /tmp and /var at 10% and 5%, and / at 100MB and 50MB"));
957 printf (" %s\n", "check_disk -w 100M -c 50M -C -w 1000M -c 500M -g sidDATA -r '^/oracle/SID/data.*$'");
958 printf (" %s\n", _("Checks all filesystems not matching -r at 100M and 50M. The fs matching the -r regex"));
959 printf (" %s\n", _("are grouped which means the freespace thresholds are applied to all disks together"));
960 printf (" %s\n", "check_disk -w 100M -c 50M -C -w 1000M -c 500M -p /foo -C -w 5% -c 3% -p /bar");
961 printf (" %s\n", _("Checks /foo for 1000M/500M and /bar for 5/3%. All remaining volumes use 100M/50M"));
962 printf (_(UT_SUPPORT));
963 }
967 void
968 print_usage (void)
969 {
970 printf (_("Usage:"));
971 printf (" %s -w limit -c limit [-W limit] [-K limit] {-p path | -x device}\n", progname);
972 printf ("[-C] [-E] [-e] [-g group ] [-k] [-l] [-M] [-m] [-R path ] [-r path ]\n");
973 printf ("[-t timeout] [-u unit] [-v] [-X type]\n");
974 }
976 void
977 stat_path (struct parameter_list *p)
978 {
979 /* Stat entry to check that dir exists and is accessible */
980 if (verbose > 3)
981 printf("calling stat on %s\n", p->name);
982 if (stat (p->name, &stat_buf[0])) {
983 if (verbose > 3)
984 printf("stat failed on %s\n", p->name);
985 printf("DISK %s - ", _("CRITICAL"));
986 die (STATE_CRITICAL, _("%s %s: %s\n"), p->name, _("is not accessible"), strerror(errno));
987 }
988 }