Code

cceb5be8c8d326b224eaeb6686399eb7a69a3ac9
[nagiosplug.git] / plugins / check_disk.c
1 /******************************************************************************
2 *
3 * Nagios check_disk plugin
4 *
5 * License: GPL
6 * Copyright (c) 1999-2006 nagios-plugins team
7 *
8 * Last Modified: $Date$
9 *
10 * Description:
11 *
12 * This file contains the check_disk plugin
13 *
14 * License Information:
15 *
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
20 *
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24 * GNU General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29 *
30 * $Id$
31
32 *****************************************************************************/
34 const char *progname = "check_disk";
35 const char *program_name = "check_disk";  /* Required for coreutils libs */
36 const char *revision = "$Revision$";
37 const char *copyright = "1999-2006";
38 const char *email = "nagiosplug-devel@lists.sourceforge.net";
41 #include "common.h"
42 #ifdef HAVE_SYS_STAT_H
43 # include <sys/stat.h>
44 #endif
45 #if HAVE_INTTYPES_H
46 # include <inttypes.h>
47 #endif
48 #include <assert.h>
49 #include "popen.h"
50 #include "utils.h"
51 #include "utils_disk.h"
52 #include <stdarg.h>
53 #include "fsusage.h"
54 #include "mountlist.h"
55 #include "intprops.h"   /* necessary for TYPE_MAXIMUM */
56 #if HAVE_LIMITS_H
57 # include <limits.h>
58 #endif
59 #include "regex.h"
62 /* If nonzero, show inode information. */
63 static int inode_format = 1;
65 /* If nonzero, show even filesystems with zero size or
66    uninteresting types. */
67 static int show_all_fs = 1;
69 /* If nonzero, show only local filesystems.  */
70 static int show_local_fs = 0;
72 /* If positive, the units to use when printing sizes;
73    if negative, the human-readable base.  */
74 /* static int output_block_size; */
76 /* If nonzero, invoke the `sync' system call before getting any usage data.
77    Using this option can make df very slow, especially with many or very
78    busy disks.  Note that this may make a difference on some systems --
79    SunOs4.1.3, for one.  It is *not* necessary on Linux.  */
80 /* static int require_sync = 0; */
82 /* Linked list of filesystem types to display.
83    If `fs_select_list' is NULL, list all types.
84    This table is generated dynamically from command-line options,
85    rather than hardcoding into the program what it thinks are the
86    valid filesystem types; let the user specify any filesystem type
87    they want to, and if there are any filesystems of that type, they
88    will be shown.
90    Some filesystem types:
91    4.2 4.3 ufs nfs swap ignore io vm efs dbg */
93 /* static struct parameter_list *fs_select_list; */
95 /* Linked list of filesystem types to omit.
96    If the list is empty, don't exclude any types.  */
98 static struct name_list *fs_exclude_list;
100 static struct name_list *dp_exclude_list;
102 static struct parameter_list *path_select_list = NULL;
104 /* Linked list of mounted filesystems. */
105 static struct mount_entry *mount_list;
107 /* For long options that have no equivalent short option, use a
108    non-character as a pseudo short option, starting with CHAR_MAX + 1.  */
109 enum
111   SYNC_OPTION = CHAR_MAX + 1,
112   NO_SYNC_OPTION,
113   BLOCK_SIZE_OPTION
114 };
116 #ifdef _AIX
117  #pragma alloca
118 #endif
120 /* Linked list of mounted filesystems. */
121 static struct mount_entry *mount_list;
123 int process_arguments (int, char **);
124 void print_path (const char *mypath);
125 void set_all_thresholds (struct parameter_list *path);
126 int validate_arguments (uintmax_t, uintmax_t, double, double, double, double, char *);
127 void print_help (void);
128 void print_usage (void);
129 double calculate_percent(uintmax_t, uintmax_t);
131 double w_dfp = -1.0;
132 double c_dfp = -1.0;
133 char *path;
134 char *exclude_device;
135 char *units;
136 uintmax_t mult = 1024 * 1024;
137 int verbose = 0;
138 int erronly = FALSE;
139 int display_mntp = FALSE;
140 int exact_match = FALSE;
141 char *warn_freespace_units = NULL;
142 char *crit_freespace_units = NULL;
143 char *warn_freespace_percent = NULL;
144 char *crit_freespace_percent = NULL;
145 char *warn_usedspace_units = NULL;
146 char *crit_usedspace_units = NULL;
147 char *warn_usedspace_percent = NULL;
148 char *crit_usedspace_percent = NULL;
149 char *warn_usedinodes_percent = NULL;
150 char *crit_usedinodes_percent = NULL;
151 char *warn_freeinodes_percent = NULL;
152 char *crit_freeinodes_percent = NULL;
153 bool path_selected = false;
154 char *group = NULL;
157 int
158 main (int argc, char **argv)
160   int result = STATE_UNKNOWN;
161   int disk_result = STATE_UNKNOWN;
162   char *output;
163   char *details;
164   char *perf;
165   char *preamble;
166   double inode_space_pct;
167   uintmax_t total, available, available_to_root, used;
168   double dfree_pct = -1, dused_pct = -1;
169   double dused_units, dfree_units, dtotal_units;
170   double dused_inodes_percent, dfree_inodes_percent;
171   double warning_high_tide;
172   double critical_high_tide;
173   int temp_result;
175   struct mount_entry *me;
176   struct fs_usage fsp, tmpfsp;
177   struct parameter_list *temp_list, *path;
178   struct name_list *seen = NULL;
179   struct stat *stat_buf;
181   preamble = strdup (" - free space:");
182   output = strdup ("");
183   details = strdup ("");
184   perf = strdup ("");
186   setlocale (LC_ALL, "");
187   bindtextdomain (PACKAGE, LOCALEDIR);
188   textdomain (PACKAGE);
190   mount_list = read_file_system_list (0);
192   if (process_arguments (argc, argv) == ERROR)
193     usage4 (_("Could not parse arguments"));
195   /* If a list of paths has not been selected, find entire
196      mount list and create list of paths
197    */
198   if (path_selected == false) { 
199     for (me = mount_list; me; me = me->me_next) {
200       if (! (path = np_find_parameter(path_select_list, me->me_mountdir))) {
201         path = np_add_parameter(&path_select_list, me->me_mountdir);
202       }
203       path->best_match = me;
204       path->group = group;
205       set_all_thresholds(path);
206     }
207   }
208   np_set_best_match(path_select_list, mount_list, exact_match);
210   /* Error if no match found for specified paths */
211   temp_list = path_select_list;
213   stat_buf = malloc(sizeof *stat_buf);
214   while (temp_list) {
215     if (! temp_list->best_match) {
216       die (STATE_CRITICAL, _("DISK %s: %s not found\n"), _("CRITICAL"), temp_list->name);
217     }
219     /* Stat each entry to check that dir exists */
220     if (stat (temp_list->name, &stat_buf[0])) {
221       printf("DISK %s - ", _("CRITICAL"));
222       die (STATE_CRITICAL, _("%s %s: %s\n"), temp_list->name, _("is not accessible"), strerror(errno));
223     }
224     temp_list = temp_list->name_next;
225   }
226   free(stat_buf);
227   
228   /* Process for every path in list */
229   for (path = path_select_list; path; path=path->name_next) {
231     if (verbose > 3 && path->freespace_percent->warning != NULL && path->freespace_percent->critical != NULL)
232       printf("Thresholds(pct) for %s warn: %f crit %f\n",path->name, path->freespace_percent->warning->end,
233                                                          path->freespace_percent->critical->end);
235     if (verbose > 3 && path->group != NULL)
236       printf("Group of %s: %s\n",path->name,path->group);
238     /* reset disk result */
239     disk_result = STATE_UNKNOWN;
241     me = path->best_match;
243     /* Filters */
245     /* Remove filesystems already seen */
246     if (np_seen_name(seen, me->me_mountdir)) {
247       continue;
248     } else {
249       if (path->group != NULL) {
250         /* find all group members */
251         fsp.fsu_blocksize = 0;
252         fsp.fsu_blocks    = 0;
253         fsp.fsu_bfree     = 0;
254         fsp.fsu_bavail    = 0;
255         fsp.fsu_files     = 0;
256         fsp.fsu_ffree     = 0;
259         for (temp_list = path_select_list; temp_list; temp_list=temp_list->name_next) {
260           if (temp_list->group && ! (strcmp(temp_list->group, path->group))) {
261             
262             get_fs_usage (temp_list->best_match->me_mountdir, temp_list->best_match->me_devname, &tmpfsp);
264             /* possibly differing blocksizes if disks are grouped. Calculating average */
265             fsp.fsu_blocksize = (fsp.fsu_blocksize * fsp.fsu_blocks + tmpfsp.fsu_blocksize * tmpfsp.fsu_blocks) / \
266                                 (fsp.fsu_blocks + tmpfsp.fsu_blocks);  /* Size of a block.  */
267             fsp.fsu_blocks    += tmpfsp.fsu_blocks;     /* Total blocks. */
268             fsp.fsu_bfree     += tmpfsp.fsu_bfree;      /* Free blocks available to superuser. */
269             fsp.fsu_bavail    += tmpfsp.fsu_bavail;     /* Free blocks available to non-superuser. */
270             fsp.fsu_files     += tmpfsp.fsu_files;      /* Total file nodes. */
271             fsp.fsu_ffree     += tmpfsp.fsu_ffree;      /* Free file nodes. */
272             
273             if (verbose > 3)
274               printf("Group %s: add %llu blocks (%s) \n", path->group, tmpfsp.fsu_bavail, temp_list->name);
275              // printf("Group %s: add %u blocks (%s)\n", temp_list->name); // path->group, tmpfsp.fsu_bavail, temp_list->name);
277             np_add_name(&seen, temp_list->best_match->me_mountdir);
278           }
279         }
280         /* modify devname and mountdir for output */
281         me->me_mountdir = me->me_devname = path->group;
282       } else
283         np_add_name(&seen, me->me_mountdir);
284     }
286     if (path->group == NULL) {
287       /* Skip remote filesystems if we're not interested in them */
288       if (me->me_remote && show_local_fs) {
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       get_fs_usage (me->me_mountdir, me->me_devname, &fsp);
304     }
306     if (fsp.fsu_blocks && strcmp ("none", me->me_mountdir)) {
307       total = fsp.fsu_blocks;
308       available = fsp.fsu_bavail;
309       available_to_root = fsp.fsu_bfree;
310       used = total - available_to_root;
312       dused_pct = calculate_percent( used, used + available );  /* used + available can never be > uintmax */
313      
314       dfree_pct = 100 - dused_pct;
315       dused_units = used*fsp.fsu_blocksize/mult;
316       dfree_units = available*fsp.fsu_blocksize/mult;
317       dtotal_units = total*fsp.fsu_blocksize/mult;
318       dused_inodes_percent = calculate_percent(fsp.fsu_files - fsp.fsu_ffree, fsp.fsu_files);
319       dfree_inodes_percent = 100 - dused_inodes_percent;
321       if (verbose >= 3) {
322         printf ("For %s, used_pct=%g free_pct=%g used_units=%g free_units=%g total_units=%g used_inodes_pct=%g free_inodes_pct=%g\n", 
323           me->me_mountdir, dused_pct, dfree_pct, dused_units, dfree_units, dtotal_units, dused_inodes_percent, dfree_inodes_percent);
324       }
326       /* Threshold comparisons */
328       temp_result = get_status(dfree_units, path->freespace_units);
329       if (verbose >=3) printf("Freespace_units result=%d\n", temp_result);
330       disk_result = max_state( disk_result, temp_result );
332       temp_result = get_status(dfree_pct, path->freespace_percent);
333       if (verbose >=3) printf("Freespace%% result=%d\n", temp_result);
334       disk_result = max_state( disk_result, temp_result );
336       temp_result = get_status(dused_units, path->usedspace_units);
337       if (verbose >=3) printf("Usedspace_units result=%d\n", temp_result);
338       disk_result = max_state( disk_result, temp_result );
340       temp_result = get_status(dused_pct, path->usedspace_percent);
341       if (verbose >=3) printf("Usedspace_percent result=%d\n", temp_result);
342       disk_result = max_state( disk_result, temp_result );
344       temp_result = get_status(dused_inodes_percent, path->usedinodes_percent);
345       if (verbose >=3) printf("Usedinodes_percent result=%d\n", temp_result);
346       disk_result = max_state( disk_result, temp_result );
348       temp_result = get_status(dfree_inodes_percent, path->freeinodes_percent);
349       if (verbose >=3) printf("Freeinodes_percent result=%d\n", temp_result);
350       disk_result = max_state( disk_result, temp_result );
352       result = max_state(result, disk_result);
354       /* What a mess of units. The output shows free space, the perf data shows used space. Yikes!
355          Hack here. Trying to get warn/crit levels from freespace_(units|percent) for perf
356          data. Assumption that start=0. Roll on new syntax...
357       */
359       /* *_high_tide must be reinitialized at each run */
360       warning_high_tide = UINT_MAX;
361       critical_high_tide = UINT_MAX;
363       if (path->freespace_units->warning != NULL) {
364         warning_high_tide = dtotal_units - path->freespace_units->warning->end;
365       }
366       if (path->freespace_percent->warning != NULL) {
367         warning_high_tide = abs( min( (double) warning_high_tide, (double) (1.0 - path->freespace_percent->warning->end/100)*dtotal_units ));
368       }
369       if (path->freespace_units->critical != NULL) {
370         critical_high_tide = dtotal_units - path->freespace_units->critical->end;
371       }
372       if (path->freespace_percent->critical != NULL) {
373         critical_high_tide = abs( min( (double) critical_high_tide, (double) (1.0 - path->freespace_percent->critical->end/100)*dtotal_units ));
374       }
376       asprintf (&perf, "%s %s", perf,
377                 perfdata ((!strcmp(me->me_mountdir, "none") || display_mntp) ? me->me_devname : me->me_mountdir,
378                           dused_units, units,
379                           (warning_high_tide != UINT_MAX ? TRUE : FALSE), warning_high_tide,
380                           (critical_high_tide != UINT_MAX ? TRUE : FALSE), critical_high_tide,
381                           TRUE, 0,
382                           TRUE, dtotal_units));
384       if (disk_result==STATE_OK && erronly && !verbose)
385         continue;
387       if (disk_result!=STATE_OK || verbose>=0) {
388         asprintf (&output, "%s %s %.0f %s (%.0f%%",
389                   output,
390                   (!strcmp(me->me_mountdir, "none") || display_mntp) ? me->me_devname : me->me_mountdir,
391                   dfree_units,
392                   units,
393                   dfree_pct);
394         if (dused_inodes_percent < 0) {
395           asprintf(&output, "%s inode=-);", output);
396         } else {
397           asprintf(&output, "%s inode=%.0f%%);", output, dfree_inodes_percent );
398         }
399       }
401       /* TODO: Need to do a similar debug line
402       asprintf (&details, _("%s\n\
403 %.0f of %.0f %s (%.0f%% inode=%.0f%%) free on %s (type %s mounted on %s) warn:%lu crit:%lu warn%%:%.0f%% crit%%:%.0f%%"),
404                 details, dfree_units, dtotal_units, units, dfree_pct, inode_space_pct,
405                 me->me_devname, me->me_type, me->me_mountdir,
406                 (unsigned long)w_df, (unsigned long)c_df, w_dfp, c_dfp);
407       */
409     }
411   }
413   if (verbose > 2)
414     asprintf (&output, "%s%s", output, details);
417   printf ("DISK %s%s%s|%s\n", state_text (result), (erronly && result==STATE_OK) ? "" : preamble, output, perf);
418   return result;
422 double calculate_percent(uintmax_t value, uintmax_t total) {
423   double pct = -1;
424   /* I don't understand the below, but it is taken from coreutils' df */
425   /* Seems to be calculating pct, in the best possible way */
426   if (value <= TYPE_MAXIMUM(uintmax_t) / 100 
427     && total != 0) {
428     uintmax_t u100 = value * 100;
429     pct = u100 / total + (u100 % total != 0);
430   } else {
431     /* Possible rounding errors - see coreutils' df for more explanation */
432     double u = value;
433     double t = total;
434     if (t) {
435       long int lipct = pct = u * 100 / t;
436       double ipct = lipct;
438       /* Like 'pct = ceil (dpct);', but without ceil - from coreutils again */
439       if (ipct - 1 < pct && pct <= ipct + 1)
440         pct = ipct + (ipct < pct);
441     }
442   }
443   return pct;
446 /* process command-line arguments */
447 int
448 process_arguments (int argc, char **argv)
450   int c, err;
451   struct parameter_list *se, *se2;
452   struct parameter_list *temp_list;
453   struct parameter_list *temp_path_select_list = NULL;
454   struct mount_entry *me;
455   int result = OK;
456   regex_t re;
457   int cflags = REG_NOSUB | REG_EXTENDED;
458   char errbuf[MAX_INPUT_BUFFER];
459   bool fnd = false;
461   int option = 0;
462   static struct option longopts[] = {
463     {"timeout", required_argument, 0, 't'},
464     {"warning", required_argument, 0, 'w'},
465     {"critical", required_argument, 0, 'c'},
466     {"iwarning", required_argument, 0, 'W'},
467     /* Dang, -C is taken. We might want to reshuffle this. */
468     {"icritical", required_argument, 0, 'K'},
469     {"local", required_argument, 0, 'l'},
470     {"kilobytes", required_argument, 0, 'k'},
471     {"megabytes", required_argument, 0, 'm'},
472     {"units", required_argument, 0, 'u'},
473     {"path", required_argument, 0, 'p'},
474     {"partition", required_argument, 0, 'p'},
475     {"exclude_device", required_argument, 0, 'x'},
476     {"exclude-type", required_argument, 0, 'X'},
477     {"group", required_argument, 0, 'g'},
478     {"eregi-path", required_argument, 0, 'R'},
479     {"eregi-partition", required_argument, 0, 'R'},
480     {"ereg-path", required_argument, 0, 'r'},
481     {"ereg-partition", required_argument, 0, 'r'},
482     {"mountpoint", no_argument, 0, 'M'},
483     {"errors-only", no_argument, 0, 'e'},
484     {"exact-match", no_argument, 0, 'E'},
485     {"verbose", no_argument, 0, 'v'},
486     {"quiet", no_argument, 0, 'q'},
487     {"clear", no_argument, 0, 'C'},
488     {"version", no_argument, 0, 'V'},
489     {"help", no_argument, 0, 'h'},
490     {0, 0, 0, 0}
491   };
493   if (argc < 2)
494     return ERROR;
496   np_add_name(&fs_exclude_list, "iso9660");
498   for (c = 1; c < argc; c++)
499     if (strcmp ("-to", argv[c]) == 0)
500       strcpy (argv[c], "-t");
502   while (1) {
503     c = getopt_long (argc, argv, "+?VqhveCt:c:w:K:W:u:p:x:X:mklg:R:r:ME", longopts, &option);
505     if (c == -1 || c == EOF)
506       break;
508     switch (c) {
509     case 't':                 /* timeout period */
510       if (is_integer (optarg)) {
511         timeout_interval = atoi (optarg);
512         break;
513       }
514       else {
515         usage2 (_("Timeout interval must be a positive integer"), optarg);
516       }
518     /* See comments for 'c' */
519     case 'w':                 /* warning threshold */
520       if (strstr(optarg, "%")) {
521         if (*optarg == '@') {
522           warn_freespace_percent = optarg;
523         } else {
524           asprintf(&warn_freespace_percent, "@%s", optarg);
525         }
526       } else {
527         if (*optarg == '@') {
528           warn_freespace_units = optarg;
529         } else {
530           asprintf(&warn_freespace_units, "@%s", optarg);
531         }
532       }
533       break;
535     /* Awful mistake where the range values do not make sense. Normally, 
536        you alert if the value is within the range, but since we are using
537        freespace, we have to alert if outside the range. Thus we artifically
538        force @ at the beginning of the range, so that it is backwards compatible
539     */
540     case 'c':                 /* critical threshold */
541       if (strstr(optarg, "%")) {
542         if (*optarg == '@') {
543           crit_freespace_percent = optarg;
544         } else {
545           asprintf(&crit_freespace_percent, "@%s", optarg);
546         }
547       } else {
548         if (*optarg == '@') {
549           crit_freespace_units = optarg;
550         } else {
551           asprintf(&crit_freespace_units, "@%s", optarg);
552         }
553       }
554       break;
556     case 'W':                   /* warning inode threshold */
557       if (*optarg == '@') {
558         warn_freeinodes_percent = optarg;
559       } else {
560         asprintf(&warn_freeinodes_percent, "@%s", optarg);
561       }
562       break;
563     case 'K':                   /* critical inode threshold */
564       if (*optarg == '@') {
565         crit_freeinodes_percent = optarg;
566       } else {
567         asprintf(&crit_freeinodes_percent, "@%s", optarg);
568       }
569       break;
570     case 'u':
571       if (units)
572         free(units);
573       if (! strcmp (optarg, "bytes")) {
574         mult = (uintmax_t)1;
575         units = strdup ("B");
576       } else if (! strcmp (optarg, "kB")) {
577         mult = (uintmax_t)1024;
578         units = strdup ("kB");
579       } else if (! strcmp (optarg, "MB")) {
580         mult = (uintmax_t)1024 * 1024;
581         units = strdup ("MB");
582       } else if (! strcmp (optarg, "GB")) {
583         mult = (uintmax_t)1024 * 1024 * 1024;
584         units = strdup ("GB");
585       } else if (! strcmp (optarg, "TB")) {
586         mult = (uintmax_t)1024 * 1024 * 1024 * 1024;
587         units = strdup ("TB");
588       } else {
589         die (STATE_UNKNOWN, _("unit type %s not known\n"), optarg);
590       }
591       if (units == NULL)
592         die (STATE_UNKNOWN, _("failed allocating storage for '%s'\n"), "units");
593       break;
594     case 'k': /* display mountpoint */
595       mult = 1024;
596       if (units)
597         free(units);
598       units = strdup ("kB");
599       break;
600     case 'm': /* display mountpoint */
601       mult = 1024 * 1024;
602       if (units)
603         free(units);
604       units = strdup ("MB");
605       break;
606     case 'l':
607       show_local_fs = 1;      
608       break;
609     case 'p':                 /* select path */
610       if (! (warn_freespace_units || crit_freespace_units || warn_freespace_percent || 
611              crit_freespace_percent || warn_usedspace_units || crit_usedspace_units ||
612              warn_usedspace_percent || crit_usedspace_percent || warn_usedinodes_percent ||
613              crit_usedinodes_percent || warn_freeinodes_percent || crit_freeinodes_percent )) {
614         die (STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set a threshold value before using -p\n"));
615       }
617       /* get the real mountdir of the specified path. np_find_parameter won't find an entry if -p is not
618        * exactly the same string as the mountdir */
619       se2 = np_add_parameter(&temp_path_select_list, optarg);
620       np_set_best_match(se2, mount_list, FALSE);
623       /* add parameter if not found. overwrite thresholds if path has already been added  */
624       if (! (se = np_find_parameter(path_select_list, optarg))) {
625           se = np_add_parameter(&path_select_list, optarg);
626       }
627       se->group = group;
628       set_all_thresholds(se);
629       path_selected = true;
630       break;
631     case 'x':                 /* exclude path or partition */
632       np_add_name(&dp_exclude_list, optarg);
633       break;
634     case 'X':                 /* exclude file system type */
635       np_add_name(&fs_exclude_list, optarg);
636       break;
637     case 'v':                 /* verbose */
638       verbose++;
639       break;
640     case 'q':                 /* verbose */
641       verbose--;
642       break;
643     case 'e':
644       erronly = TRUE;
645       break;
646     case 'E':
647       exact_match = TRUE;
648       break;
649     case 'g':
650       if (path_selected)
651         die (STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set group value before using -p\n"));
652       group = optarg;
653       break;
654     case 'R':
655       cflags |= REG_ICASE;
656     case 'r':
657       if (! (warn_freespace_units || crit_freespace_units || warn_freespace_percent || 
658              crit_freespace_percent || warn_usedspace_units || crit_usedspace_units ||
659              warn_usedspace_percent || crit_usedspace_percent || warn_usedinodes_percent ||
660              crit_usedinodes_percent || warn_freeinodes_percent || crit_freeinodes_percent )) {
661         die (STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set a threshold value before using -r/-R\n"));
662       }
664       err = regcomp(&re, optarg, cflags);
665       if (err != 0) {
666         regerror (err, &re, errbuf, MAX_INPUT_BUFFER);
667         die (STATE_UNKNOWN, "DISK %s: %s - %s\n",_("UNKNOWN"), _("Could not compile regular expression"), errbuf);
668       }
669           
670       for (me = mount_list; me; me = me->me_next) {
671         if (np_regex_match_mount_entry(me, &re)) {
672           fnd = true;
673           if (verbose > 3)
674             printf("%s %s matching expression %s\n", me->me_devname, me->me_mountdir, optarg);
676           /* add parameter if not found. overwrite thresholds if path has already been added  */
677           if (! (se = np_find_parameter(path_select_list, me->me_mountdir))) {
678             se = np_add_parameter(&path_select_list, me->me_mountdir);
679           }
680           se->group = group;
681           set_all_thresholds(se);
682         }
683       }
685       if (!fnd)
686         die (STATE_UNKNOWN, "DISK %s: %s - %s\n",_("UNKNOWN"),
687             _("Regular expression did not match any path or disk"), optarg);
689       fnd = false;
690       path_selected = true;
691       break;
692     case 'M': /* display mountpoint */
693       display_mntp = TRUE;
694       break;
695     case 'C':
696        /* add all mount entries to path_select list if no partitions have been explicitly defined using -p */
697        if (path_selected == false) {
698          struct mount_entry *me;
699          struct parameter_list *path;
700          for (me = mount_list; me; me = me->me_next) {
701            if (! (path = np_find_parameter(path_select_list, me->me_mountdir))) 
702              path = np_add_parameter(&path_select_list, me->me_mountdir);
703            path->best_match = me;
704            path->group = group;
705            set_all_thresholds(path);
706          }
707       }
708       warn_freespace_units = NULL;
709       crit_freespace_units = NULL;
710       warn_usedspace_units = NULL;
711       crit_usedspace_units = NULL;
712       warn_freespace_percent = NULL;
713       crit_freespace_percent = NULL;
714       warn_usedspace_percent = NULL;
715       crit_usedspace_percent = NULL;
716       warn_usedinodes_percent = NULL;
717       crit_usedinodes_percent = NULL;
718       warn_freeinodes_percent = NULL;
719       crit_freeinodes_percent = NULL;
720     
721       path_selected = false;
722       group = NULL;
723       break;
724     case 'V':                 /* version */
725       print_revision (progname, revision);
726       exit (STATE_OK);
727     case 'h':                 /* help */
728       print_help ();
729       exit (STATE_OK);
730     case '?':                 /* help */
731       usage (_("Unknown argument"));
732     }
733   }
735   /* Support for "check_disk warn crit [fs]" with thresholds at used% level */
736   c = optind;
737   if (warn_usedspace_percent == NULL && argc > c && is_intnonneg (argv[c]))
738     warn_usedspace_percent = argv[c++];
740   if (crit_usedspace_percent == NULL && argc > c && is_intnonneg (argv[c]))
741     crit_usedspace_percent = argv[c++];
743   if (argc > c && path == NULL) {
744     se = np_add_parameter(&path_select_list, strdup(argv[c++]));
745     path_selected = true;
746     set_all_thresholds(se);
747   }
749   if (units == NULL) {
750     units = strdup ("MB");
751     mult = (uintmax_t)1024 * 1024;
752   }
754   return TRUE;
759 void
760 print_path (const char *mypath) 
762   if (mypath == NULL)
763     printf ("\n");
764   else
765     printf (_(" for %s\n"), mypath);
769 void
770 set_all_thresholds (struct parameter_list *path) 
772     set_thresholds(&path->freespace_units, warn_freespace_units, crit_freespace_units);
773     set_thresholds(&path->freespace_percent, warn_freespace_percent, crit_freespace_percent);
774     set_thresholds(&path->usedspace_units, warn_usedspace_units, crit_usedspace_units);
775     set_thresholds(&path->usedspace_percent, warn_usedspace_percent, crit_usedspace_percent);
776     set_thresholds(&path->usedinodes_percent, warn_usedinodes_percent, crit_usedinodes_percent);
777     set_thresholds(&path->freeinodes_percent, warn_freeinodes_percent, crit_freeinodes_percent);
780 /* TODO: Remove?
782 int
783 validate_arguments (uintmax_t w, uintmax_t c, double wp, double cp, double iwp, double icp, char *mypath)
785   if (w < 0 && c < 0 && wp < 0.0 && cp < 0.0) {
786     printf (_("INPUT ERROR: No thresholds specified"));
787     print_path (mypath);
788     return ERROR;
789   }
790   else if ((wp >= 0.0 || cp >= 0.0) &&
791            (wp < 0.0 || cp < 0.0 || wp > 100.0 || cp > 100.0 || cp > wp)) {
792     printf (_("\
793 INPUT ERROR: C_DFP (%f) should be less than W_DFP (%.1f) and both should be between zero and 100 percent, inclusive"),
794             cp, wp);
795     print_path (mypath);
796     return ERROR;
797   }
798   else if ((iwp >= 0.0 || icp >= 0.0) &&
799            (iwp < 0.0 || icp < 0.0 || iwp > 100.0 || icp > 100.0 || icp > iwp)) {
800     printf (_("\
801 INPUT ERROR: C_IDFP (%f) should be less than W_IDFP (%.1f) and both should be between zero and 100 percent, inclusive"),
802             icp, iwp);
803     print_path (mypath);
804     return ERROR;
805   }
806   else if ((w > 0 || c > 0) && (w == 0 || c == 0 || c > w)) {
807     printf (_("\
808 INPUT ERROR: C_DF (%lu) should be less than W_DF (%lu) and both should be greater than zero"),
809             (unsigned long)c, (unsigned long)w);
810     print_path (mypath);
811     return ERROR;
812   }
813   
814   return OK;
817 */
825 void
826 print_help (void)
828   print_revision (progname, revision);
830   printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
831   printf (COPYRIGHT, copyright, email);
833   printf ("%s\n", _("This plugin checks the amount of used disk space on a mounted file system"));
834   printf ("%s\n", _("and generates an alert if free space is less than one of the threshold values"));
836   printf ("\n\n");
838   print_usage ();
840   printf (_(UT_HELP_VRSN));
842   printf (" %s\n", "-w, --warning=INTEGER");
843   printf ("    %s\n", _("Exit with WARNING status if less than INTEGER units of disk are free"));
844   printf (" %s\n", "-w, --warning=PERCENT%");
845   printf ("    %s\n", _("Exit with WARNING status if less than PERCENT of disk space is free"));
846   printf (" %s\n", "-W, --iwarning=PERCENT%");
847   printf ("    %s\n", _("Exit with WARNING status if less than PERCENT of inode space is free"));
848   printf (" %s\n", "-K, --icritical=PERCENT%");
849   printf ("    %s\n", _("Exit with CRITICAL status if less than PERCENT of inode space is free"));
850   printf (" %s\n", "-c, --critical=INTEGER");
851   printf ("    %s\n", _("Exit with CRITICAL status if less than INTEGER units of disk are free"));
852   printf (" %s\n", "-c, --critical=PERCENT%");
853   printf ("    %s\n", _("Exit with CRITCAL status if less than PERCENT of disk space is free"));
854   printf (" %s\n", "-C, --clear");
855   printf ("    %s\n", _("Clear thresholds"));
856   printf (" %s\n", "-u, --units=STRING");
857   printf ("    %s\n", _("Choose bytes, kB, MB, GB, TB (default: MB)"));
858   printf (" %s\n", "-k, --kilobytes");
859   printf ("    %s\n", _("Same as '--units kB'"));
860   printf (" %s\n", "-m, --megabytes");
861   printf ("    %s\n", _("Same as '--units MB'"));
862   printf (" %s\n", "-l, --local");
863   printf ("    %s\n", _("Only check local filesystems"));
864   printf (" %s\n", "-p, --path=PATH, --partition=PARTITION");
865   printf ("    %s\n", _("Path or partition (may be repeated)"));
866   printf (" %s\n", "-r, --ereg-path=PATH, --ereg-partition=PARTITION");
867   printf ("    %s\n", _("Regular expression for path or partition (may be repeated)"));
868   printf (" %s\n", "-R, --eregi-path=PATH, --eregi-partition=PARTITION");
869   printf ("    %s\n", _("Case insensitive regular expression for path/partition (may be repeated)"));
870   printf (" %s\n", "-g, --group=NAME");
871   printf ("    %s\n", _("Group pathes. Thresholds apply to (free-)space of all partitions together"));
872   printf (" %s\n", "-x, --exclude_device=PATH <STRING>");
873   printf ("    %s\n", _("Ignore device (only works if -p unspecified)"));
874   printf (" %s\n", "-X, --exclude-type=TYPE <STRING>");
875   printf ("    %s\n", _("Ignore all filesystems of indicated type (may be repeated)"));
876   printf (" %s\n", "-M, --mountpoint");
877   printf ("    %s\n", _("Display the mountpoint instead of the partition"));
878   printf (" %s\n", "-E, --exact-match");
879   printf ("    %s\n", _("For paths or partitions specified with -p, only check for exact paths"));
880   printf (" %s\n", "-e, --errors-only");
881   printf ("    %s\n", _("Display only devices/mountpoints with errors"));
882   printf (_(UT_TIMEOUT), DEFAULT_SOCKET_TIMEOUT);
883   printf (_(UT_VERBOSE));
884   printf ("\n");
885   printf ("%s\n", _("Examples:"));
886   printf (" %s\n", "check_disk -w 10% -c 5% -p /tmp -p /var -C -w 100000 -c 50000 -p /");
887   printf ("    %s\n", _("Checks /tmp and /var at 10% and 5%, and / at 100MB and 50MB"));
888   printf (_(UT_SUPPORT));
893 void
894 print_usage (void)
896   printf (_("Usage:"));
897   printf (" %s -w limit -c limit [-p path | -x device] [-t timeout]", progname);
898   printf ("[-m] [-e] [-W limit] [-K limit] [-v] [-q] [-E]\n");