Code

- Added some variables at verbose==3
[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 fsp.fsu_blocksize=%lu mult=%lu\n", 
323           me->me_mountdir, dused_pct, dfree_pct, dused_units, dfree_units, dtotal_units, dused_inodes_percent, dfree_inodes_percent, fsp.fsu_blocksize, mult);
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       /* Nb: *_high_tide are unset when == UINT_MAX */
377       asprintf (&perf, "%s %s", perf,
378                 perfdata ((!strcmp(me->me_mountdir, "none") || display_mntp) ? me->me_devname : me->me_mountdir,
379                           dused_units, units,
380                           (warning_high_tide != UINT_MAX ? TRUE : FALSE), warning_high_tide,
381                           (critical_high_tide != UINT_MAX ? TRUE : FALSE), critical_high_tide,
382                           TRUE, 0,
383                           TRUE, dtotal_units));
385       if (disk_result==STATE_OK && erronly && !verbose)
386         continue;
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       }
400       /* TODO: Need to do a similar debug line
401       asprintf (&details, _("%s\n\
402 %.0f of %.0f %s (%.0f%% inode=%.0f%%) free on %s (type %s mounted on %s) warn:%lu crit:%lu warn%%:%.0f%% crit%%:%.0f%%"),
403                 details, dfree_units, dtotal_units, units, dfree_pct, inode_space_pct,
404                 me->me_devname, me->me_type, me->me_mountdir,
405                 (unsigned long)w_df, (unsigned long)c_df, w_dfp, c_dfp);
406       */
408     }
410   }
412   if (verbose > 2)
413     asprintf (&output, "%s%s", output, details);
416   printf ("DISK %s%s%s|%s\n", state_text (result), (erronly && result==STATE_OK) ? "" : preamble, output, perf);
417   return result;
421 double calculate_percent(uintmax_t value, uintmax_t total) {
422   double pct = -1;
423   /* I don't understand the below, but it is taken from coreutils' df */
424   /* Seems to be calculating pct, in the best possible way */
425   if (value <= TYPE_MAXIMUM(uintmax_t) / 100 
426     && total != 0) {
427     uintmax_t u100 = value * 100;
428     pct = u100 / total + (u100 % total != 0);
429   } else {
430     /* Possible rounding errors - see coreutils' df for more explanation */
431     double u = value;
432     double t = total;
433     if (t) {
434       long int lipct = pct = u * 100 / t;
435       double ipct = lipct;
437       /* Like 'pct = ceil (dpct);', but without ceil - from coreutils again */
438       if (ipct - 1 < pct && pct <= ipct + 1)
439         pct = ipct + (ipct < pct);
440     }
441   }
442   return pct;
445 /* process command-line arguments */
446 int
447 process_arguments (int argc, char **argv)
449   int c, err;
450   struct parameter_list *se, *se2;
451   struct parameter_list *temp_list;
452   struct parameter_list *temp_path_select_list = NULL;
453   struct mount_entry *me;
454   int result = OK;
455   regex_t re;
456   int cflags = REG_NOSUB | REG_EXTENDED;
457   char errbuf[MAX_INPUT_BUFFER];
458   bool fnd = false;
460   int option = 0;
461   static struct option longopts[] = {
462     {"timeout", required_argument, 0, 't'},
463     {"warning", required_argument, 0, 'w'},
464     {"critical", required_argument, 0, 'c'},
465     {"iwarning", required_argument, 0, 'W'},
466     /* Dang, -C is taken. We might want to reshuffle this. */
467     {"icritical", required_argument, 0, 'K'},
468     {"local", required_argument, 0, 'l'},
469     {"kilobytes", required_argument, 0, 'k'},
470     {"megabytes", required_argument, 0, 'm'},
471     {"units", required_argument, 0, 'u'},
472     {"path", required_argument, 0, 'p'},
473     {"partition", required_argument, 0, 'p'},
474     {"exclude_device", required_argument, 0, 'x'},
475     {"exclude-type", required_argument, 0, 'X'},
476     {"group", required_argument, 0, 'g'},
477     {"eregi-path", required_argument, 0, 'R'},
478     {"eregi-partition", required_argument, 0, 'R'},
479     {"ereg-path", required_argument, 0, 'r'},
480     {"ereg-partition", required_argument, 0, 'r'},
481     {"mountpoint", no_argument, 0, 'M'},
482     {"errors-only", no_argument, 0, 'e'},
483     {"exact-match", no_argument, 0, 'E'},
484     {"verbose", no_argument, 0, 'v'},
485     {"quiet", no_argument, 0, 'q'},
486     {"clear", no_argument, 0, 'C'},
487     {"version", no_argument, 0, 'V'},
488     {"help", no_argument, 0, 'h'},
489     {0, 0, 0, 0}
490   };
492   if (argc < 2)
493     return ERROR;
495   np_add_name(&fs_exclude_list, "iso9660");
497   for (c = 1; c < argc; c++)
498     if (strcmp ("-to", argv[c]) == 0)
499       strcpy (argv[c], "-t");
501   while (1) {
502     c = getopt_long (argc, argv, "+?VqhveCt:c:w:K:W:u:p:x:X:mklg:R:r:ME", longopts, &option);
504     if (c == -1 || c == EOF)
505       break;
507     switch (c) {
508     case 't':                 /* timeout period */
509       if (is_integer (optarg)) {
510         timeout_interval = atoi (optarg);
511         break;
512       }
513       else {
514         usage2 (_("Timeout interval must be a positive integer"), optarg);
515       }
517     /* See comments for 'c' */
518     case 'w':                 /* warning threshold */
519       if (strstr(optarg, "%")) {
520         if (*optarg == '@') {
521           warn_freespace_percent = optarg;
522         } else {
523           asprintf(&warn_freespace_percent, "@%s", optarg);
524         }
525       } else {
526         if (*optarg == '@') {
527           warn_freespace_units = optarg;
528         } else {
529           asprintf(&warn_freespace_units, "@%s", optarg);
530         }
531       }
532       break;
534     /* Awful mistake where the range values do not make sense. Normally, 
535        you alert if the value is within the range, but since we are using
536        freespace, we have to alert if outside the range. Thus we artifically
537        force @ at the beginning of the range, so that it is backwards compatible
538     */
539     case 'c':                 /* critical threshold */
540       if (strstr(optarg, "%")) {
541         if (*optarg == '@') {
542           crit_freespace_percent = optarg;
543         } else {
544           asprintf(&crit_freespace_percent, "@%s", optarg);
545         }
546       } else {
547         if (*optarg == '@') {
548           crit_freespace_units = optarg;
549         } else {
550           asprintf(&crit_freespace_units, "@%s", optarg);
551         }
552       }
553       break;
555     case 'W':                   /* warning inode threshold */
556       if (*optarg == '@') {
557         warn_freeinodes_percent = optarg;
558       } else {
559         asprintf(&warn_freeinodes_percent, "@%s", optarg);
560       }
561       break;
562     case 'K':                   /* critical inode threshold */
563       if (*optarg == '@') {
564         crit_freeinodes_percent = optarg;
565       } else {
566         asprintf(&crit_freeinodes_percent, "@%s", optarg);
567       }
568       break;
569     case 'u':
570       if (units)
571         free(units);
572       if (! strcmp (optarg, "bytes")) {
573         mult = (uintmax_t)1;
574         units = strdup ("B");
575       } else if (! strcmp (optarg, "kB")) {
576         mult = (uintmax_t)1024;
577         units = strdup ("kB");
578       } else if (! strcmp (optarg, "MB")) {
579         mult = (uintmax_t)1024 * 1024;
580         units = strdup ("MB");
581       } else if (! strcmp (optarg, "GB")) {
582         mult = (uintmax_t)1024 * 1024 * 1024;
583         units = strdup ("GB");
584       } else if (! strcmp (optarg, "TB")) {
585         mult = (uintmax_t)1024 * 1024 * 1024 * 1024;
586         units = strdup ("TB");
587       } else {
588         die (STATE_UNKNOWN, _("unit type %s not known\n"), optarg);
589       }
590       if (units == NULL)
591         die (STATE_UNKNOWN, _("failed allocating storage for '%s'\n"), "units");
592       break;
593     case 'k': /* display mountpoint */
594       mult = 1024;
595       if (units)
596         free(units);
597       units = strdup ("kB");
598       break;
599     case 'm': /* display mountpoint */
600       mult = 1024 * 1024;
601       if (units)
602         free(units);
603       units = strdup ("MB");
604       break;
605     case 'l':
606       show_local_fs = 1;      
607       break;
608     case 'p':                 /* select path */
609       if (! (warn_freespace_units || crit_freespace_units || warn_freespace_percent || 
610              crit_freespace_percent || warn_usedspace_units || crit_usedspace_units ||
611              warn_usedspace_percent || crit_usedspace_percent || warn_usedinodes_percent ||
612              crit_usedinodes_percent || warn_freeinodes_percent || crit_freeinodes_percent )) {
613         die (STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set a threshold value before using -p\n"));
614       }
616       /* get the real mountdir of the specified path. np_find_parameter won't find an entry if -p is not
617        * exactly the same string as the mountdir */
618       se2 = np_add_parameter(&temp_path_select_list, optarg);
619       np_set_best_match(se2, mount_list, FALSE);
622       /* add parameter if not found. overwrite thresholds if path has already been added  */
623       if (! (se = np_find_parameter(path_select_list, optarg))) {
624           se = np_add_parameter(&path_select_list, optarg);
625       }
626       se->group = group;
627       set_all_thresholds(se);
628       path_selected = true;
629       break;
630     case 'x':                 /* exclude path or partition */
631       np_add_name(&dp_exclude_list, optarg);
632       break;
633     case 'X':                 /* exclude file system type */
634       np_add_name(&fs_exclude_list, optarg);
635       break;
636     case 'v':                 /* verbose */
637       verbose++;
638       break;
639     case 'q':                 /* TODO: this function should eventually go away (removed 2007-09-20) */
640       /* verbose--; **replaced by line below**. -q was only a broken way of implementing -e */
641       erronly = TRUE;
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", "-c, --critical=INTEGER");
847   printf ("    %s\n", _("Exit with CRITICAL status if less than INTEGER units of disk are free"));
848   printf (" %s\n", "-c, --critical=PERCENT%");
849   printf ("    %s\n", _("Exit with CRITCAL status if less than PERCENT of disk space is free"));
850   printf (" %s\n", "-W, --iwarning=PERCENT%");
851   printf ("    %s\n", _("Exit with WARNING status if less than PERCENT of inode space is free"));
852   printf (" %s\n", "-K, --icritical=PERCENT%");
853   printf ("    %s\n", _("Exit with CRITICAL status if less than PERCENT of inode space is free"));
854   printf (" %s\n", "-p, --path=PATH, --partition=PARTITION");
855   printf ("    %s\n", _("Path or partition (may be repeated)"));
856   printf (" %s\n", "-x, --exclude_device=PATH <STRING>");
857   printf ("    %s\n", _("Ignore device (only works if -p unspecified)"));
858   printf (" %s\n", "-C, --clear");
859   printf ("    %s\n", _("Clear thresholds"));
860   printf (" %s\n", "-E, --exact-match");
861   printf ("    %s\n", _("For paths or partitions specified with -p, only check for exact paths"));
862   printf (" %s\n", "-e, --errors-only");
863   printf ("    %s\n", _("Display only devices/mountpoints with errors"));
864   printf (" %s\n", "-g, --group=NAME");
865   printf ("    %s\n", _("Group pathes. Thresholds apply to (free-)space of all partitions together"));
866   printf (" %s\n", "-k, --kilobytes");
867   printf ("    %s\n", _("Same as '--units kB'"));
868   printf (" %s\n", "-l, --local");
869   printf ("    %s\n", _("Only check local filesystems"));
870   printf (" %s\n", "-M, --mountpoint");
871   printf ("    %s\n", _("Display the mountpoint instead of the partition"));
872   printf (" %s\n", "-m, --megabytes");
873   printf ("    %s\n", _("Same as '--units MB'"));
874   printf (" %s\n", "-R, --eregi-path=PATH, --eregi-partition=PARTITION");
875   printf ("    %s\n", _("Case insensitive regular expression for path/partition (may be repeated)"));
876   printf (" %s\n", "-r, --ereg-path=PATH, --ereg-partition=PARTITION");
877   printf ("    %s\n", _("Regular expression for path or partition (may be repeated)"));
878   printf (_(UT_TIMEOUT), DEFAULT_SOCKET_TIMEOUT);
879   printf (" %s\n", "-u, --units=STRING");
880   printf ("    %s\n", _("Choose bytes, kB, MB, GB, TB (default: MB)"));
881   printf (_(UT_VERBOSE));
882   printf (" %s\n", "-X, --exclude-type=TYPE");
883   printf ("    %s\n", _("Ignore all filesystems of indicated type (may be repeated)"));
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 (" %s\n", "check_disk -w 100M -c 50M -C -w 1000M -c 500M -g sidDATA -r '^/oracle/SID/data.*$'");
889   printf ("    %s\n", _("Checks all filesystems not matching -r at 100M and 50M. The fs matching the -r regex"));
890   printf ("    %s\n", _("are grouped which means the freespace thresholds are applied to all disks together"));
891   printf (" %s\n", "check_disk -w 100M -c 50M -C -w 1000M -c 500M -p /foo -C -w 5% -c 3% -p /bar");
892   printf ("    %s\n", _("Checks /foo for 1000M/500M and /bar for 5/3%. All remaining volumes use 100M/50M"));
893   printf (_(UT_SUPPORT));
898 void
899 print_usage (void)
901   printf (_("Usage:"));
902   printf (" %s -w limit -c limit [-W limit] [-K limit] {-p path | -x device}\n", progname);
903   printf ("[-C] [-E] [-e] [-g group ] [-k] [-l] [-M] [-m] [-R path ] [-r path ]\n");
904   printf ("[-t timeout] [-u unit] [-v] [-X type]\n");