Code

d2674097c46c60d58017d890aef9647fcc33fc84
[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=%llu mult=%llu\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;
451   struct parameter_list *temp_list = NULL, *previous = NULL;
452   struct parameter_list *temp_path_select_list = NULL;
453   struct mount_entry *me, *temp_me;
454   int result = OK;
455   regex_t re;
456   int cflags = REG_NOSUB | REG_EXTENDED;
457   int default_cflags = cflags;
458   char errbuf[MAX_INPUT_BUFFER];
459   int fnd = 0;
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     {"ignore-ereg-path", required_argument, 0, 'i'},
483     {"ignore-ereg-partition", required_argument, 0, 'i'},
484     {"ignore-eregi-path", required_argument, 0, 'I'},
485     {"ignore-eregi-partition", required_argument, 0, 'I'},
486     {"mountpoint", no_argument, 0, 'M'},
487     {"errors-only", no_argument, 0, 'e'},
488     {"exact-match", no_argument, 0, 'E'},
489     {"all", no_argument, 0, 'A'},
490     {"verbose", no_argument, 0, 'v'},
491     {"quiet", no_argument, 0, 'q'},
492     {"clear", no_argument, 0, 'C'},
493     {"version", no_argument, 0, 'V'},
494     {"help", no_argument, 0, 'h'},
495     {0, 0, 0, 0}
496   };
498   if (argc < 2)
499     return ERROR;
501   np_add_name(&fs_exclude_list, "iso9660");
503   for (c = 1; c < argc; c++)
504     if (strcmp ("-to", argv[c]) == 0)
505       strcpy (argv[c], "-t");
507   while (1) {
508     c = getopt_long (argc, argv, "+?VqhveCt:c:w:K:W:u:p:x:X:mklg:R:r:i:I:MEA", longopts, &option);
510     if (c == -1 || c == EOF)
511       break;
513     switch (c) {
514     case 't':                 /* timeout period */
515       if (is_integer (optarg)) {
516         timeout_interval = atoi (optarg);
517         break;
518       }
519       else {
520         usage2 (_("Timeout interval must be a positive integer"), optarg);
521       }
523     /* See comments for 'c' */
524     case 'w':                 /* warning threshold */
525       if (strstr(optarg, "%")) {
526         if (*optarg == '@') {
527           warn_freespace_percent = optarg;
528         } else {
529           asprintf(&warn_freespace_percent, "@%s", optarg);
530         }
531       } else {
532         if (*optarg == '@') {
533           warn_freespace_units = optarg;
534         } else {
535           asprintf(&warn_freespace_units, "@%s", optarg);
536         }
537       }
538       break;
540     /* Awful mistake where the range values do not make sense. Normally, 
541        you alert if the value is within the range, but since we are using
542        freespace, we have to alert if outside the range. Thus we artifically
543        force @ at the beginning of the range, so that it is backwards compatible
544     */
545     case 'c':                 /* critical threshold */
546       if (strstr(optarg, "%")) {
547         if (*optarg == '@') {
548           crit_freespace_percent = optarg;
549         } else {
550           asprintf(&crit_freespace_percent, "@%s", optarg);
551         }
552       } else {
553         if (*optarg == '@') {
554           crit_freespace_units = optarg;
555         } else {
556           asprintf(&crit_freespace_units, "@%s", optarg);
557         }
558       }
559       break;
561     case 'W':                   /* warning inode threshold */
562       if (*optarg == '@') {
563         warn_freeinodes_percent = optarg;
564       } else {
565         asprintf(&warn_freeinodes_percent, "@%s", optarg);
566       }
567       break;
568     case 'K':                   /* critical inode threshold */
569       if (*optarg == '@') {
570         crit_freeinodes_percent = optarg;
571       } else {
572         asprintf(&crit_freeinodes_percent, "@%s", optarg);
573       }
574       break;
575     case 'u':
576       if (units)
577         free(units);
578       if (! strcmp (optarg, "bytes")) {
579         mult = (uintmax_t)1;
580         units = strdup ("B");
581       } else if (! strcmp (optarg, "kB")) {
582         mult = (uintmax_t)1024;
583         units = strdup ("kB");
584       } else if (! strcmp (optarg, "MB")) {
585         mult = (uintmax_t)1024 * 1024;
586         units = strdup ("MB");
587       } else if (! strcmp (optarg, "GB")) {
588         mult = (uintmax_t)1024 * 1024 * 1024;
589         units = strdup ("GB");
590       } else if (! strcmp (optarg, "TB")) {
591         mult = (uintmax_t)1024 * 1024 * 1024 * 1024;
592         units = strdup ("TB");
593       } else {
594         die (STATE_UNKNOWN, _("unit type %s not known\n"), optarg);
595       }
596       if (units == NULL)
597         die (STATE_UNKNOWN, _("failed allocating storage for '%s'\n"), "units");
598       break;
599     case 'k': /* display mountpoint */
600       mult = 1024;
601       if (units)
602         free(units);
603       units = strdup ("kB");
604       break;
605     case 'm': /* display mountpoint */
606       mult = 1024 * 1024;
607       if (units)
608         free(units);
609       units = strdup ("MB");
610       break;
611     case 'l':
612       show_local_fs = 1;      
613       break;
614     case 'p':                 /* select path */
615       if (! (warn_freespace_units || crit_freespace_units || warn_freespace_percent || 
616              crit_freespace_percent || warn_usedspace_units || crit_usedspace_units ||
617              warn_usedspace_percent || crit_usedspace_percent || warn_usedinodes_percent ||
618              crit_usedinodes_percent || warn_freeinodes_percent || crit_freeinodes_percent )) {
619         die (STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set a threshold value before using -p\n"));
620       }
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       np_set_best_match(se, mount_list, exact_match);
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':                 /* TODO: this function should eventually go away (removed 2007-09-20) */
641       /* verbose--; **replaced by line below**. -q was only a broken way of implementing -e */
642       erronly = TRUE;
643       break;
644     case 'e':
645       erronly = TRUE;
646       break;
647     case 'E':
648       if (path_selected)
649         die (STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set -E before selecting pathes\n"));
650       exact_match = TRUE;
651       break;
652     case 'g':
653       if (path_selected)
654         die (STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set group value before selecting pathes \n"));
655       group = optarg;
656       break;
657     case 'I':
658       cflags |= REG_ICASE;
659     case 'i':
660       if (!path_selected)
661         die (STATE_UNKNOWN, "DISK %s: %s\n", _("UNKNOWN"), _("Pathes need to be selected before using -i/-I. Use -A to select all pathes explicitly"));
662       err = regcomp(&re, optarg, cflags);
663       if (err != 0) {
664         regerror (err, &re, errbuf, MAX_INPUT_BUFFER);
665         die (STATE_UNKNOWN, "DISK %s: %s - %s\n",_("UNKNOWN"), _("Could not compile regular expression"), errbuf);
666       }
668       temp_list = path_select_list;
670       previous = NULL;
671       while (temp_list) {
672         if (temp_list->best_match) {
673           if (np_regex_match_mount_entry(temp_list->best_match, &re)) {
674         
675               if (verbose >=3)
676                 printf("ignoring %s matching regex\n", temp_list->name);
678               temp_list = np_del_parameter(temp_list, previous);
679               /* pointer to first element needs to be uĆ¼dated if first item gets deleted */
680               if (previous == NULL)
681                 path_select_list = temp_list;
682           } else {
683             previous = temp_list;
684             temp_list = temp_list->name_next;
685           }
686         } else {
687           previous = temp_list;
688           temp_list = temp_list->name_next;
689         }
690       }
693       cflags = default_cflags;
694       break;
696     case 'A':
697       optarg = strdup(".*");
698     case 'R':
699       cflags |= REG_ICASE;
700     case 'r':
701       if (! (warn_freespace_units || crit_freespace_units || warn_freespace_percent || 
702              crit_freespace_percent || warn_usedspace_units || crit_usedspace_units ||
703              warn_usedspace_percent || crit_usedspace_percent || warn_usedinodes_percent ||
704              crit_usedinodes_percent || warn_freeinodes_percent || crit_freeinodes_percent )) {
705         die (STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set a threshold value before using -r/-R\n"));
706       }
708       err = regcomp(&re, optarg, cflags);
709       if (err != 0) {
710         regerror (err, &re, errbuf, MAX_INPUT_BUFFER);
711         die (STATE_UNKNOWN, "DISK %s: %s - %s\n",_("UNKNOWN"), _("Could not compile regular expression"), errbuf);
712       }
713           
714       for (me = mount_list; me; me = me->me_next) {
715         if (np_regex_match_mount_entry(me, &re)) {
716           fnd = true;
717           if (verbose > 3)
718             printf("%s %s matching expression %s\n", me->me_devname, me->me_mountdir, optarg);
720           /* add parameter if not found. overwrite thresholds if path has already been added  */
721           if (! (se = np_find_parameter(path_select_list, me->me_mountdir))) {
722             se = np_add_parameter(&path_select_list, me->me_mountdir);
723           }
724           se->group = group;
725           set_all_thresholds(se);
726         }
727       }
729       if (!fnd)
730         die (STATE_UNKNOWN, "DISK %s: %s - %s\n",_("UNKNOWN"),
731             _("Regular expression did not match any path or disk"), optarg);
733       fnd = false;
734       path_selected = true;
735       np_set_best_match(path_select_list, mount_list, exact_match);
736       cflags = default_cflags;
738       break;
739     case 'M': /* display mountpoint */
740       display_mntp = TRUE;
741       break;
742     case 'C':
743        /* add all mount entries to path_select list if no partitions have been explicitly defined using -p */
744        if (path_selected == false) {
745          struct mount_entry *me;
746          struct parameter_list *path;
747          for (me = mount_list; me; me = me->me_next) {
748            if (! (path = np_find_parameter(path_select_list, me->me_mountdir))) 
749              path = np_add_parameter(&path_select_list, me->me_mountdir);
750            path->best_match = me;
751            path->group = group;
752            set_all_thresholds(path);
753          }
754       }
755       warn_freespace_units = NULL;
756       crit_freespace_units = NULL;
757       warn_usedspace_units = NULL;
758       crit_usedspace_units = NULL;
759       warn_freespace_percent = NULL;
760       crit_freespace_percent = NULL;
761       warn_usedspace_percent = NULL;
762       crit_usedspace_percent = NULL;
763       warn_usedinodes_percent = NULL;
764       crit_usedinodes_percent = NULL;
765       warn_freeinodes_percent = NULL;
766       crit_freeinodes_percent = NULL;
767     
768       path_selected = false;
769       group = NULL;
770       break;
771     case 'V':                 /* version */
772       print_revision (progname, revision);
773       exit (STATE_OK);
774     case 'h':                 /* help */
775       print_help ();
776       exit (STATE_OK);
777     case '?':                 /* help */
778       usage (_("Unknown argument"));
779     }
780   }
782   /* Support for "check_disk warn crit [fs]" with thresholds at used% level */
783   c = optind;
784   if (warn_usedspace_percent == NULL && argc > c && is_intnonneg (argv[c]))
785     warn_usedspace_percent = argv[c++];
787   if (crit_usedspace_percent == NULL && argc > c && is_intnonneg (argv[c]))
788     crit_usedspace_percent = argv[c++];
790   if (argc > c && path == NULL) {
791     se = np_add_parameter(&path_select_list, strdup(argv[c++]));
792     path_selected = true;
793     set_all_thresholds(se);
794   }
796   if (units == NULL) {
797     units = strdup ("MB");
798     mult = (uintmax_t)1024 * 1024;
799   }
801   return TRUE;
806 void
807 print_path (const char *mypath) 
809   if (mypath == NULL)
810     printf ("\n");
811   else
812     printf (_(" for %s\n"), mypath);
816 void
817 set_all_thresholds (struct parameter_list *path) 
819     set_thresholds(&path->freespace_units, warn_freespace_units, crit_freespace_units);
820     set_thresholds(&path->freespace_percent, warn_freespace_percent, crit_freespace_percent);
821     set_thresholds(&path->usedspace_units, warn_usedspace_units, crit_usedspace_units);
822     set_thresholds(&path->usedspace_percent, warn_usedspace_percent, crit_usedspace_percent);
823     set_thresholds(&path->usedinodes_percent, warn_usedinodes_percent, crit_usedinodes_percent);
824     set_thresholds(&path->freeinodes_percent, warn_freeinodes_percent, crit_freeinodes_percent);
827 /* TODO: Remove?
829 int
830 validate_arguments (uintmax_t w, uintmax_t c, double wp, double cp, double iwp, double icp, char *mypath)
832   if (w < 0 && c < 0 && wp < 0.0 && cp < 0.0) {
833     printf (_("INPUT ERROR: No thresholds specified"));
834     print_path (mypath);
835     return ERROR;
836   }
837   else if ((wp >= 0.0 || cp >= 0.0) &&
838            (wp < 0.0 || cp < 0.0 || wp > 100.0 || cp > 100.0 || cp > wp)) {
839     printf (_("\
840 INPUT ERROR: C_DFP (%f) should be less than W_DFP (%.1f) and both should be between zero and 100 percent, inclusive"),
841             cp, wp);
842     print_path (mypath);
843     return ERROR;
844   }
845   else if ((iwp >= 0.0 || icp >= 0.0) &&
846            (iwp < 0.0 || icp < 0.0 || iwp > 100.0 || icp > 100.0 || icp > iwp)) {
847     printf (_("\
848 INPUT ERROR: C_IDFP (%f) should be less than W_IDFP (%.1f) and both should be between zero and 100 percent, inclusive"),
849             icp, iwp);
850     print_path (mypath);
851     return ERROR;
852   }
853   else if ((w > 0 || c > 0) && (w == 0 || c == 0 || c > w)) {
854     printf (_("\
855 INPUT ERROR: C_DF (%lu) should be less than W_DF (%lu) and both should be greater than zero"),
856             (unsigned long)c, (unsigned long)w);
857     print_path (mypath);
858     return ERROR;
859   }
860   
861   return OK;
864 */
872 void
873 print_help (void)
875   print_revision (progname, revision);
877   printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
878   printf (COPYRIGHT, copyright, email);
880   printf ("%s\n", _("This plugin checks the amount of used disk space on a mounted file system"));
881   printf ("%s\n", _("and generates an alert if free space is less than one of the threshold values"));
883   printf ("\n\n");
885   print_usage ();
887   printf (_(UT_HELP_VRSN));
889   printf (" %s\n", "-w, --warning=INTEGER");
890   printf ("    %s\n", _("Exit with WARNING status if less than INTEGER units of disk are free"));
891   printf (" %s\n", "-w, --warning=PERCENT%");
892   printf ("    %s\n", _("Exit with WARNING status if less than PERCENT of disk space is free"));
893   printf (" %s\n", "-c, --critical=INTEGER");
894   printf ("    %s\n", _("Exit with CRITICAL status if less than INTEGER units of disk are free"));
895   printf (" %s\n", "-c, --critical=PERCENT%");
896   printf ("    %s\n", _("Exit with CRITCAL status if less than PERCENT of disk space is free"));
897   printf (" %s\n", "-W, --iwarning=PERCENT%");
898   printf ("    %s\n", _("Exit with WARNING status if less than PERCENT of inode space is free"));
899   printf (" %s\n", "-K, --icritical=PERCENT%");
900   printf ("    %s\n", _("Exit with CRITICAL status if less than PERCENT of inode space is free"));
901   printf (" %s\n", "-p, --path=PATH, --partition=PARTITION");
902   printf ("    %s\n", _("Path or partition (may be repeated)"));
903   printf (" %s\n", "-x, --exclude_device=PATH <STRING>");
904   printf ("    %s\n", _("Ignore device (only works if -p unspecified)"));
905   printf (" %s\n", "-C, --clear");
906   printf ("    %s\n", _("Clear thresholds"));
907   printf (" %s\n", "-E, --exact-match");
908   printf ("    %s\n", _("For paths or partitions specified with -p, only check for exact paths"));
909   printf (" %s\n", "-e, --errors-only");
910   printf ("    %s\n", _("Display only devices/mountpoints with errors"));
911   printf (" %s\n", "-g, --group=NAME");
912   printf ("    %s\n", _("Group pathes. Thresholds apply to (free-)space of all partitions together"));
913   printf (" %s\n", "-k, --kilobytes");
914   printf ("    %s\n", _("Same as '--units kB'"));
915   printf (" %s\n", "-l, --local");
916   printf ("    %s\n", _("Only check local filesystems"));
917   printf (" %s\n", "-M, --mountpoint");
918   printf ("    %s\n", _("Display the mountpoint instead of the partition"));
919   printf (" %s\n", "-m, --megabytes");
920   printf ("    %s\n", _("Same as '--units MB'"));
921   printf (" %s\n", "-A, --all");
922   printf ("    %s\n", _("Explicitly select all pathes. This is equivalent to -R '.*'"));
923   printf (" %s\n", "-R, --eregi-path=PATH, --eregi-partition=PARTITION");
924   printf ("    %s\n", _("Case insensitive regular expression for path/partition (may be repeated)"));
925   printf (" %s\n", "-r, --ereg-path=PATH, --ereg-partition=PARTITION");
926   printf ("    %s\n", _("Regular expression for path or partition (may be repeated)"));
927   printf (" %s\n", "-I, --ignore-eregi-path=PATH, --ignore-eregi-partition=PARTITION");
928   printf ("    %s\n", _("Regular expression to ignore selected path/partition (case insensitive) (may be repeated)"));
929   printf (" %s\n", "-i, --ignore-ereg-path=PATH, --ignore-ereg-partition=PARTITION");
930   printf ("    %s\n", _("Regular expression to ignore selected path or partition (may be repeated)"));
931   printf (_(UT_TIMEOUT), DEFAULT_SOCKET_TIMEOUT);
932   printf (" %s\n", "-u, --units=STRING");
933   printf ("    %s\n", _("Choose bytes, kB, MB, GB, TB (default: MB)"));
934   printf (_(UT_VERBOSE));
935   printf (" %s\n", "-X, --exclude-type=TYPE");
936   printf ("    %s\n", _("Ignore all filesystems of indicated type (may be repeated)"));
937   printf ("\n");
938   printf ("%s\n", _("Examples:"));
939   printf (" %s\n", "check_disk -w 10% -c 5% -p /tmp -p /var -C -w 100000 -c 50000 -p /");
940   printf ("    %s\n", _("Checks /tmp and /var at 10% and 5%, and / at 100MB and 50MB"));
941   printf (" %s\n", "check_disk -w 100M -c 50M -C -w 1000M -c 500M -g sidDATA -r '^/oracle/SID/data.*$'");
942   printf ("    %s\n", _("Checks all filesystems not matching -r at 100M and 50M. The fs matching the -r regex"));
943   printf ("    %s\n", _("are grouped which means the freespace thresholds are applied to all disks together"));
944   printf (" %s\n", "check_disk -w 100M -c 50M -C -w 1000M -c 500M -p /foo -C -w 5% -c 3% -p /bar");
945   printf ("    %s\n", _("Checks /foo for 1000M/500M and /bar for 5/3%. All remaining volumes use 100M/50M"));
946   printf (_(UT_SUPPORT));
951 void
952 print_usage (void)
954   printf (_("Usage:"));
955   printf (" %s -w limit -c limit [-W limit] [-K limit] {-p path | -x device}\n", progname);
956   printf ("[-C] [-E] [-e] [-g group ] [-k] [-l] [-M] [-m] [-R path ] [-r path ]\n");
957   printf ("[-t timeout] [-u unit] [-v] [-X type]\n");