Code

check_disk: added regex functionality -r and -R. see np-devel mail (2007-02-10)
[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;
180   preamble = strdup (" - free space:");
181   output = strdup ("");
182   details = strdup ("");
183   perf = strdup ("");
185   setlocale (LC_ALL, "");
186   bindtextdomain (PACKAGE, LOCALEDIR);
187   textdomain (PACKAGE);
189   mount_list = read_file_system_list (0);
191   if (process_arguments (argc, argv) == ERROR)
192     usage4 (_("Could not parse arguments"));
194   /* If a list of paths has not been selected, find entire
195      mount list and create list of paths
196    */
197   if (path_selected == false) { 
198     for (me = mount_list; me; me = me->me_next) {
199       if (! (path = np_find_parameter(path_select_list, me->me_mountdir))) {
200         path = np_add_parameter(&path_select_list, me->me_mountdir);
201       }
202       path->best_match = me;
203       path->group = group;
204       set_all_thresholds(path);
205     }
206   }
207   np_set_best_match(path_select_list, mount_list, exact_match);
209   /* Error if no match found for specified paths */
210   temp_list = path_select_list;
211   while (temp_list) {
212     if (! temp_list->best_match) {
213       die (STATE_CRITICAL, _("DISK %s: %s not found\n"), _("CRITICAL"), temp_list->name);
214     }
215     temp_list = temp_list->name_next;
216   }
217   
219   /* Process for every path in list */
220   for (path = path_select_list; path; path=path->name_next) {
222     if (verbose > 3 && path->freespace_percent->warning != NULL && path->freespace_percent->critical != NULL)
223       printf("Thresholds(pct) for %s warn: %f crit %f\n",path->name, path->freespace_percent->warning->end,
224                                                          path->freespace_percent->critical->end);
226     if (verbose > 3 && path->group != NULL)
227       printf("Group of %s: %s\n",path->name,path->group);
229     /* reset disk result */
230     disk_result = STATE_UNKNOWN;
232     me = path->best_match;
234     /* Filters */
236     /* Remove filesystems already seen */
237     if (np_seen_name(seen, me->me_mountdir)) {
238       continue;
239     } else {
240       if (path->group != NULL) {
241         /* find all group members */
242         fsp.fsu_blocksize = 0;
243         fsp.fsu_blocks    = 0;
244         fsp.fsu_bfree     = 0;
245         fsp.fsu_bavail    = 0;
246         fsp.fsu_files     = 0;
247         fsp.fsu_ffree     = 0;
250         for (temp_list = path_select_list; temp_list; temp_list=temp_list->name_next) {
251           if (temp_list->group && ! (strcmp(temp_list->group, path->group))) {
252             
253             get_fs_usage (temp_list->best_match->me_mountdir, temp_list->best_match->me_devname, &tmpfsp);
255             /* possibly differing blocksizes if disks are grouped. Calculating average */
256             fsp.fsu_blocksize = (fsp.fsu_blocksize * fsp.fsu_blocks + tmpfsp.fsu_blocksize * tmpfsp.fsu_blocks) / \
257                                 (fsp.fsu_blocks + tmpfsp.fsu_blocks);  /* Size of a block.  */
258             fsp.fsu_blocks    += tmpfsp.fsu_blocks;     /* Total blocks. */
259             fsp.fsu_bfree     += tmpfsp.fsu_bfree;      /* Free blocks available to superuser. */
260             fsp.fsu_bavail    += tmpfsp.fsu_bavail;     /* Free blocks available to non-superuser. */
261             fsp.fsu_files     += tmpfsp.fsu_files;      /* Total file nodes. */
262             fsp.fsu_ffree     += tmpfsp.fsu_ffree;      /* Free file nodes. */
263             
264             if (verbose > 3)
265               printf("Group %s: add %llu blocks (%s) \n", path->group, tmpfsp.fsu_bavail, temp_list->name);
266              // printf("Group %s: add %u blocks (%s)\n", temp_list->name); // path->group, tmpfsp.fsu_bavail, temp_list->name);
268             np_add_name(&seen, temp_list->best_match->me_mountdir);
269           }
270         }
271         /* modify devname and mountdir for output */
272         me->me_mountdir = me->me_devname = path->group;
273       } else
274         np_add_name(&seen, me->me_mountdir);
275     }
277     if (path->group == NULL) {
278       /* Skip remote filesystems if we're not interested in them */
279       if (me->me_remote && show_local_fs) {
280         continue;
281       /* Skip pseudo fs's if we haven't asked for all fs's */
282       } else if (me->me_dummy && !show_all_fs) {
283         continue;
284       /* Skip excluded fstypes */
285       } else if (fs_exclude_list && np_find_name (fs_exclude_list, me->me_type)) {
286         continue;
287       /* Skip excluded fs's */  
288       } else if (dp_exclude_list && 
289                (np_find_name (dp_exclude_list, me->me_devname) ||
290                 np_find_name (dp_exclude_list, me->me_mountdir))) {
291         continue;
292       }
294       get_fs_usage (me->me_mountdir, me->me_devname, &fsp);
295     }
297     if (fsp.fsu_blocks && strcmp ("none", me->me_mountdir)) {
298       total = fsp.fsu_blocks;
299       available = fsp.fsu_bavail;
300       available_to_root = fsp.fsu_bfree;
301       used = total - available_to_root;
303       dused_pct = calculate_percent( used, used + available );  /* used + available can never be > uintmax */
304      
305       dfree_pct = 100 - dused_pct;
306       dused_units = used*fsp.fsu_blocksize/mult;
307       dfree_units = available*fsp.fsu_blocksize/mult;
308       dtotal_units = total*fsp.fsu_blocksize/mult;
309       dused_inodes_percent = calculate_percent(fsp.fsu_files - fsp.fsu_ffree, fsp.fsu_files);
310       dfree_inodes_percent = 100 - dused_inodes_percent;
312       if (verbose >= 3) {
313         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", 
314           me->me_mountdir, dused_pct, dfree_pct, dused_units, dfree_units, dtotal_units, dused_inodes_percent, dfree_inodes_percent);
315       }
317       /* Threshold comparisons */
319       temp_result = get_status(dfree_units, path->freespace_units);
320       if (verbose >=3) printf("Freespace_units result=%d\n", temp_result);
321       disk_result = max_state( disk_result, temp_result );
323       temp_result = get_status(dfree_pct, path->freespace_percent);
324       if (verbose >=3) printf("Freespace%% result=%d\n", temp_result);
325       disk_result = max_state( disk_result, temp_result );
327       temp_result = get_status(dused_units, path->usedspace_units);
328       if (verbose >=3) printf("Usedspace_units result=%d\n", temp_result);
329       disk_result = max_state( disk_result, temp_result );
331       temp_result = get_status(dused_pct, path->usedspace_percent);
332       if (verbose >=3) printf("Usedspace_percent result=%d\n", temp_result);
333       disk_result = max_state( disk_result, temp_result );
335       temp_result = get_status(dused_inodes_percent, path->usedinodes_percent);
336       if (verbose >=3) printf("Usedinodes_percent result=%d\n", temp_result);
337       disk_result = max_state( disk_result, temp_result );
339       temp_result = get_status(dfree_inodes_percent, path->freeinodes_percent);
340       if (verbose >=3) printf("Freeinodes_percent result=%d\n", temp_result);
341       disk_result = max_state( disk_result, temp_result );
343       result = max_state(result, disk_result);
345       /* What a mess of units. The output shows free space, the perf data shows used space. Yikes!
346          Hack here. Trying to get warn/crit levels from freespace_(units|percent) for perf
347          data. Assumption that start=0. Roll on new syntax...
348       */
350       /* *_high_tide must be reinitialized at each run */
351       warning_high_tide = UINT_MAX;
352       critical_high_tide = UINT_MAX;
354       if (path->freespace_units->warning != NULL) {
355         warning_high_tide = dtotal_units - path->freespace_units->warning->end;
356       }
357       if (path->freespace_percent->warning != NULL) {
358         warning_high_tide = abs( min( (double) warning_high_tide, (double) (1.0 - path->freespace_percent->warning->end/100)*dtotal_units ));
359       }
360       if (path->freespace_units->critical != NULL) {
361         critical_high_tide = dtotal_units - path->freespace_units->critical->end;
362       }
363       if (path->freespace_percent->critical != NULL) {
364         critical_high_tide = abs( min( (double) critical_high_tide, (double) (1.0 - path->freespace_percent->critical->end/100)*dtotal_units ));
365       }
367       asprintf (&perf, "%s %s", perf,
368                 perfdata ((!strcmp(me->me_mountdir, "none") || display_mntp) ? me->me_devname : me->me_mountdir,
369                           dused_units, units,
370                           (warning_high_tide != UINT_MAX ? TRUE : FALSE), warning_high_tide,
371                           (critical_high_tide != UINT_MAX ? TRUE : FALSE), critical_high_tide,
372                           TRUE, 0,
373                           TRUE, dtotal_units));
375       if (disk_result==STATE_OK && erronly && !verbose)
376         continue;
378       if (disk_result!=STATE_OK || verbose>=0) {
379         asprintf (&output, "%s %s %.0f %s (%.0f%%",
380                   output,
381                   (!strcmp(me->me_mountdir, "none") || display_mntp) ? me->me_devname : me->me_mountdir,
382                   dfree_units,
383                   units,
384                   dfree_pct);
385         if (dused_inodes_percent < 0) {
386           asprintf(&output, "%s inode=-);", output);
387         } else {
388           asprintf(&output, "%s inode=%.0f%%);", output, dfree_inodes_percent );
389         }
390       }
392       /* TODO: Need to do a similar debug line
393       asprintf (&details, _("%s\n\
394 %.0f of %.0f %s (%.0f%% inode=%.0f%%) free on %s (type %s mounted on %s) warn:%lu crit:%lu warn%%:%.0f%% crit%%:%.0f%%"),
395                 details, dfree_units, dtotal_units, units, dfree_pct, inode_space_pct,
396                 me->me_devname, me->me_type, me->me_mountdir,
397                 (unsigned long)w_df, (unsigned long)c_df, w_dfp, c_dfp);
398       */
400     }
402   }
404   if (verbose > 2)
405     asprintf (&output, "%s%s", output, details);
408   printf ("DISK %s%s%s|%s\n", state_text (result), (erronly && result==STATE_OK) ? "" : preamble, output, perf);
409   return result;
413 double calculate_percent(uintmax_t value, uintmax_t total) {
414   double pct = -1;
415   /* I don't understand the below, but it is taken from coreutils' df */
416   /* Seems to be calculating pct, in the best possible way */
417   if (value <= TYPE_MAXIMUM(uintmax_t) / 100 
418     && total != 0) {
419     uintmax_t u100 = value * 100;
420     pct = u100 / total + (u100 % total != 0);
421   } else {
422     /* Possible rounding errors - see coreutils' df for more explanation */
423     double u = value;
424     double t = total;
425     if (t) {
426       long int lipct = pct = u * 100 / t;
427       double ipct = lipct;
429       /* Like 'pct = ceil (dpct);', but without ceil - from coreutils again */
430       if (ipct - 1 < pct && pct <= ipct + 1)
431         pct = ipct + (ipct < pct);
432     }
433   }
434   return pct;
437 /* process command-line arguments */
438 int
439 process_arguments (int argc, char **argv)
441   int c, err;
442   struct parameter_list *se;
443   struct parameter_list *temp_list;
444   struct mount_entry *me;
445   int result = OK;
446   struct stat *stat_buf;
447   regex_t re;
448   int cflags = REG_NOSUB | REG_EXTENDED;
449   char errbuf[MAX_INPUT_BUFFER];
450   bool fnd = false;
452   int option = 0;
453   static struct option longopts[] = {
454     {"timeout", required_argument, 0, 't'},
455     {"warning", required_argument, 0, 'w'},
456     {"critical", required_argument, 0, 'c'},
457     {"iwarning", required_argument, 0, 'W'},
458     /* Dang, -C is taken. We might want to reshuffle this. */
459     {"icritical", required_argument, 0, 'K'},
460     {"local", required_argument, 0, 'l'},
461     {"kilobytes", required_argument, 0, 'k'},
462     {"megabytes", required_argument, 0, 'm'},
463     {"units", required_argument, 0, 'u'},
464     {"path", required_argument, 0, 'p'},
465     {"partition", required_argument, 0, 'p'},
466     {"exclude_device", required_argument, 0, 'x'},
467     {"exclude-type", required_argument, 0, 'X'},
468     {"group", required_argument, 0, 'g'},
469     {"eregi-path", required_argument, 0, 'R'},
470     {"eregi-partition", required_argument, 0, 'R'},
471     {"ereg-path", required_argument, 0, 'r'},
472     {"ereg-partition", required_argument, 0, 'r'},
473     {"mountpoint", no_argument, 0, 'M'},
474     {"errors-only", no_argument, 0, 'e'},
475     {"exact-match", no_argument, 0, 'E'},
476     {"verbose", no_argument, 0, 'v'},
477     {"quiet", no_argument, 0, 'q'},
478     {"clear", no_argument, 0, 'C'},
479     {"version", no_argument, 0, 'V'},
480     {"help", no_argument, 0, 'h'},
481     {0, 0, 0, 0}
482   };
484   if (argc < 2)
485     return ERROR;
487   np_add_name(&fs_exclude_list, "iso9660");
489   for (c = 1; c < argc; c++)
490     if (strcmp ("-to", argv[c]) == 0)
491       strcpy (argv[c], "-t");
493   while (1) {
494     c = getopt_long (argc, argv, "+?VqhveCt:c:w:K:W:u:p:x:X:mklg:R:r:ME", longopts, &option);
496     if (c == -1 || c == EOF)
497       break;
499     switch (c) {
500     case 't':                 /* timeout period */
501       if (is_integer (optarg)) {
502         timeout_interval = atoi (optarg);
503         break;
504       }
505       else {
506         usage2 (_("Timeout interval must be a positive integer"), optarg);
507       }
509     /* See comments for 'c' */
510     case 'w':                 /* warning threshold */
511       if (strstr(optarg, "%")) {
512         if (*optarg == '@') {
513           warn_freespace_percent = optarg;
514         } else {
515           asprintf(&warn_freespace_percent, "@%s", optarg);
516         }
517       } else {
518         if (*optarg == '@') {
519           warn_freespace_units = optarg;
520         } else {
521           asprintf(&warn_freespace_units, "@%s", optarg);
522         }
523       }
524       break;
526     /* Awful mistake where the range values do not make sense. Normally, 
527        you alert if the value is within the range, but since we are using
528        freespace, we have to alert if outside the range. Thus we artifically
529        force @ at the beginning of the range, so that it is backwards compatible
530     */
531     case 'c':                 /* critical threshold */
532       if (strstr(optarg, "%")) {
533         if (*optarg == '@') {
534           crit_freespace_percent = optarg;
535         } else {
536           asprintf(&crit_freespace_percent, "@%s", optarg);
537         }
538       } else {
539         if (*optarg == '@') {
540           crit_freespace_units = optarg;
541         } else {
542           asprintf(&crit_freespace_units, "@%s", optarg);
543         }
544       }
545       break;
547     case 'W':                   /* warning inode threshold */
548       if (*optarg == '@') {
549         warn_freeinodes_percent = optarg;
550       } else {
551         asprintf(&warn_freeinodes_percent, "@%s", optarg);
552       }
553       break;
554     case 'K':                   /* critical inode threshold */
555       if (*optarg == '@') {
556         crit_freeinodes_percent = optarg;
557       } else {
558         asprintf(&crit_freeinodes_percent, "@%s", optarg);
559       }
560       break;
561     case 'u':
562       if (units)
563         free(units);
564       if (! strcmp (optarg, "bytes")) {
565         mult = (uintmax_t)1;
566         units = strdup ("B");
567       } else if (! strcmp (optarg, "kB")) {
568         mult = (uintmax_t)1024;
569         units = strdup ("kB");
570       } else if (! strcmp (optarg, "MB")) {
571         mult = (uintmax_t)1024 * 1024;
572         units = strdup ("MB");
573       } else if (! strcmp (optarg, "GB")) {
574         mult = (uintmax_t)1024 * 1024 * 1024;
575         units = strdup ("GB");
576       } else if (! strcmp (optarg, "TB")) {
577         mult = (uintmax_t)1024 * 1024 * 1024 * 1024;
578         units = strdup ("TB");
579       } else {
580         die (STATE_UNKNOWN, _("unit type %s not known\n"), optarg);
581       }
582       if (units == NULL)
583         die (STATE_UNKNOWN, _("failed allocating storage for '%s'\n"), "units");
584       break;
585     case 'k': /* display mountpoint */
586       mult = 1024;
587       if (units)
588         free(units);
589       units = strdup ("kB");
590       break;
591     case 'm': /* display mountpoint */
592       mult = 1024 * 1024;
593       if (units)
594         free(units);
595       units = strdup ("MB");
596       break;
597     case 'l':
598       show_local_fs = 1;      
599       break;
600     case 'p':                 /* select path */
601       if (! (warn_freespace_units || crit_freespace_units || warn_freespace_percent || 
602              crit_freespace_percent || warn_usedspace_units || crit_usedspace_units ||
603              warn_usedspace_percent || crit_usedspace_percent || warn_usedinodes_percent ||
604              crit_usedinodes_percent || warn_freeinodes_percent || crit_freeinodes_percent )) {
605         die (STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set a threshold value before using -p\n"));
606       }
608       /* add parameter if not found. overwrite thresholds if path has already been added  */
609       if (! (se = np_find_parameter(path_select_list, optarg))) {
610           se = np_add_parameter(&path_select_list, optarg);
611       }
612       se->group = group;
613       set_all_thresholds(se);
614       path_selected = true;
615       break;
616     case 'x':                 /* exclude path or partition */
617       np_add_name(&dp_exclude_list, optarg);
618       break;
619     case 'X':                 /* exclude file system type */
620       np_add_name(&fs_exclude_list, optarg);
621       break;
622     case 'v':                 /* verbose */
623       verbose++;
624       break;
625     case 'q':                 /* verbose */
626       verbose--;
627       break;
628     case 'e':
629       erronly = TRUE;
630       break;
631     case 'E':
632       exact_match = TRUE;
633       break;
634     case 'g':
635       if (path_selected)
636         die (STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set group value before using -p\n"));
637       group = optarg;
638       break;
639     case 'R':
640       cflags |= REG_ICASE;
641     case 'r':
642       if (! (warn_freespace_units || crit_freespace_units || warn_freespace_percent || 
643              crit_freespace_percent || warn_usedspace_units || crit_usedspace_units ||
644              warn_usedspace_percent || crit_usedspace_percent || warn_usedinodes_percent ||
645              crit_usedinodes_percent || warn_freeinodes_percent || crit_freeinodes_percent )) {
646         die (STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set a threshold value before using -r/-R\n"));
647       }
649       err = regcomp(&re, optarg, cflags);
650       if (err != 0) {
651         regerror (err, &re, errbuf, MAX_INPUT_BUFFER);
652         die (STATE_UNKNOWN, "DISK %s: %s - %s\n",_("UNKNOWN"), _("Could not compile regular expression"), errbuf);
653       }
654           
655       for (me = mount_list; me; me = me->me_next) {
656         if (np_regex_match_mount_entry(me, &re)) {
657           fnd = true;
658           if (verbose > 3)
659             printf("%s %s matching expression %s\n", me->me_devname, me->me_mountdir, optarg);
661           /* add parameter if not found. overwrite thresholds if path has already been added  */
662           if (! (se = np_find_parameter(path_select_list, me->me_mountdir))) {
663             se = np_add_parameter(&path_select_list, me->me_mountdir);
664           }
665           se->group = group;
666           set_all_thresholds(se);
667         }
668       }
670       if (!fnd)
671         die (STATE_UNKNOWN, "DISK %s: %s - %s\n",_("UNKNOWN"),
672             _("Regular expression did not match any path or disk"), optarg);
674       fnd = false;
675       path_selected = true;
676       break;
677     case 'M': /* display mountpoint */
678       display_mntp = TRUE;
679       break;
680     case 'C':
681        /* add all mount entries to path_select list if no partitions have been explicitly defined using -p */
682        if (path_selected == false) {
683          struct mount_entry *me;
684          struct parameter_list *path;
685          for (me = mount_list; me; me = me->me_next) {
686            if (! (path = np_find_parameter(path_select_list, me->me_mountdir))) 
687              path = np_add_parameter(&path_select_list, me->me_mountdir);
688            path->best_match = me;
689            path->group = group;
690            set_all_thresholds(path);
691          }
692       }
693       warn_freespace_units = NULL;
694       crit_freespace_units = NULL;
695       warn_usedspace_units = NULL;
696       crit_usedspace_units = NULL;
697       warn_freespace_percent = NULL;
698       crit_freespace_percent = NULL;
699       warn_usedspace_percent = NULL;
700       crit_usedspace_percent = NULL;
701       warn_usedinodes_percent = NULL;
702       crit_usedinodes_percent = NULL;
703       warn_freeinodes_percent = NULL;
704       crit_freeinodes_percent = NULL;
705     
706       path_selected = false;
707       group = NULL;
708       break;
709     case 'V':                 /* version */
710       print_revision (progname, revision);
711       exit (STATE_OK);
712     case 'h':                 /* help */
713       print_help ();
714       exit (STATE_OK);
715     case '?':                 /* help */
716       usage (_("Unknown argument"));
717     }
718   }
720   /* Support for "check_disk warn crit [fs]" with thresholds at used% level */
721   c = optind;
722   if (warn_usedspace_percent == NULL && argc > c && is_intnonneg (argv[c]))
723     warn_usedspace_percent = argv[c++];
725   if (crit_usedspace_percent == NULL && argc > c && is_intnonneg (argv[c]))
726     crit_usedspace_percent = argv[c++];
728   if (argc > c && path == NULL) {
729     se = np_add_parameter(&path_select_list, strdup(argv[c++]));
730     set_all_thresholds(se);
731   }
733   if (units == NULL) {
734     units = strdup ("MB");
735     mult = (uintmax_t)1024 * 1024;
736   }
738   if (path_select_list) {
739     temp_list = path_select_list;
740     stat_buf = malloc(sizeof *stat_buf);
741     while (temp_list) {
742       /* Stat each entry to check that dir exists */
743       if (stat (temp_list->name, &stat_buf[0])) {
744         printf("DISK %s - ", _("CRITICAL"));
745         die (STATE_CRITICAL, _("%s does not exist\n"), temp_list->name);
746       }
747       /* if (validate_arguments (temp_list->w_df,
748                               temp_list->c_df,
749                               temp_list->w_dfp,
750                               temp_list->c_dfp,
751                               temp_list->w_idfp,
752                               temp_list->c_idfp,
753                               temp_list->name) == ERROR)
754         result = ERROR;
755       */
756       temp_list = temp_list->name_next;
757     }
758     free(stat_buf);
759     return result;
760   } else {
761     return TRUE;
762     /* return validate_arguments (w_df, c_df, w_dfp, c_dfp, w_idfp, c_idfp, NULL); */
763   }
768 void
769 print_path (const char *mypath) 
771   if (mypath == NULL)
772     printf ("\n");
773   else
774     printf (_(" for %s\n"), mypath);
778 void
779 set_all_thresholds (struct parameter_list *path) 
781     set_thresholds(&path->freespace_units, warn_freespace_units, crit_freespace_units);
782     set_thresholds(&path->freespace_percent, warn_freespace_percent, crit_freespace_percent);
783     set_thresholds(&path->usedspace_units, warn_usedspace_units, crit_usedspace_units);
784     set_thresholds(&path->usedspace_percent, warn_usedspace_percent, crit_usedspace_percent);
785     set_thresholds(&path->usedinodes_percent, warn_usedinodes_percent, crit_usedinodes_percent);
786     set_thresholds(&path->freeinodes_percent, warn_freeinodes_percent, crit_freeinodes_percent);
789 /* TODO: Remove?
791 int
792 validate_arguments (uintmax_t w, uintmax_t c, double wp, double cp, double iwp, double icp, char *mypath)
794   if (w < 0 && c < 0 && wp < 0.0 && cp < 0.0) {
795     printf (_("INPUT ERROR: No thresholds specified"));
796     print_path (mypath);
797     return ERROR;
798   }
799   else if ((wp >= 0.0 || cp >= 0.0) &&
800            (wp < 0.0 || cp < 0.0 || wp > 100.0 || cp > 100.0 || cp > wp)) {
801     printf (_("\
802 INPUT ERROR: C_DFP (%f) should be less than W_DFP (%.1f) and both should be between zero and 100 percent, inclusive"),
803             cp, wp);
804     print_path (mypath);
805     return ERROR;
806   }
807   else if ((iwp >= 0.0 || icp >= 0.0) &&
808            (iwp < 0.0 || icp < 0.0 || iwp > 100.0 || icp > 100.0 || icp > iwp)) {
809     printf (_("\
810 INPUT ERROR: C_IDFP (%f) should be less than W_IDFP (%.1f) and both should be between zero and 100 percent, inclusive"),
811             icp, iwp);
812     print_path (mypath);
813     return ERROR;
814   }
815   else if ((w > 0 || c > 0) && (w == 0 || c == 0 || c > w)) {
816     printf (_("\
817 INPUT ERROR: C_DF (%lu) should be less than W_DF (%lu) and both should be greater than zero"),
818             (unsigned long)c, (unsigned long)w);
819     print_path (mypath);
820     return ERROR;
821   }
822   
823   return OK;
826 */
834 void
835 print_help (void)
837   print_revision (progname, revision);
839   printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
840   printf (COPYRIGHT, copyright, email);
842   printf ("%s\n", _("This plugin checks the amount of used disk space on a mounted file system"));
843   printf ("%s\n", _("and generates an alert if free space is less than one of the threshold values"));
845   printf ("\n\n");
847   print_usage ();
849   printf (_(UT_HELP_VRSN));
851   printf (" %s\n", "-w, --warning=INTEGER");
852   printf ("    %s\n", _("Exit with WARNING status if less than INTEGER units of disk are free"));
853   printf (" %s\n", "-w, --warning=PERCENT%");
854   printf ("    %s\n", _("Exit with WARNING status if less than PERCENT of disk space is free"));
855   printf (" %s\n", "-W, --iwarning=PERCENT%");
856   printf ("    %s\n", _("Exit with WARNING status if less than PERCENT of inode space is free"));
857   printf (" %s\n", "-K, --icritical=PERCENT%");
858   printf ("    %s\n", _("Exit with CRITICAL status if less than PERCENT of inode space is free"));
859   printf (" %s\n", "-c, --critical=INTEGER");
860   printf ("    %s\n", _("Exit with CRITICAL status if less than INTEGER units of disk are free"));
861   printf (" %s\n", "-c, --critical=PERCENT%");
862   printf ("    %s\n", _("Exit with CRITCAL status if less than PERCENT of disk space is free"));
863   printf (" %s\n", "-C, --clear");
864   printf ("    %s\n", _("Clear thresholds"));
865   printf (" %s\n", "-u, --units=STRING");
866   printf ("    %s\n", _("Choose bytes, kB, MB, GB, TB (default: MB)"));
867   printf (" %s\n", "-k, --kilobytes");
868   printf ("    %s\n", _("Same as '--units kB'"));
869   printf (" %s\n", "-m, --megabytes");
870   printf ("    %s\n", _("Same as '--units MB'"));
871   printf (" %s\n", "-l, --local");
872   printf ("    %s\n", _("Only check local filesystems"));
873   printf (" %s\n", "-p, --path=PATH, --partition=PARTITION");
874   printf ("    %s\n", _("Path or partition (may be repeated)"));
875   printf (" %s\n", "-r, --ereg-path=PATH, --ereg-partition=PARTITION");
876   printf ("    %s\n", _("Regular expression for path or partition (may be repeated)"));
877   printf (" %s\n", "-R, --eregi-path=PATH, --eregi-partition=PARTITION");
878   printf ("    %s\n", _("Case insensitive regular expression for path/partition (may be repeated)"));
879   printf (" %s\n", "-g, --group=NAME");
880   printf ("    %s\n", _("Group pathes. Thresholds apply to (free-)space of all partitions together"));
881   printf (" %s\n", "-x, --exclude_device=PATH <STRING>");
882   printf ("    %s\n", _("Ignore device (only works if -p unspecified)"));
883   printf (" %s\n", "-X, --exclude-type=TYPE <STRING>");
884   printf ("    %s\n", _("Ignore all filesystems of indicated type (may be repeated)"));
885   printf (" %s\n", "-M, --mountpoint");
886   printf ("    %s\n", _("Display the mountpoint instead of the partition"));
887   printf (" %s\n", "-E, --exact-match");
888   printf ("    %s\n", _("For paths or partitions specified with -p, only check for exact paths"));
889   printf (" %s\n", "-e, --errors-only");
890   printf ("    %s\n", _("Display only devices/mountpoints with errors"));
891   printf (_(UT_TIMEOUT), DEFAULT_SOCKET_TIMEOUT);
892   printf (_(UT_VERBOSE));
893   printf ("\n");
894   printf ("%s\n", _("Examples:"));
895   printf (" %s\n", "check_disk -w 10% -c 5% -p /tmp -p /var -C -w 100000 -c 50000 -p /");
896   printf ("    %s\n", _("Checks /tmp and /var at 10% and 5%, and / at 100MB and 50MB"));
897   printf (_(UT_SUPPORT));
902 void
903 print_usage (void)
905   printf (_("Usage:"));
906   printf (" %s -w limit -c limit [-p path | -x device] [-t timeout]", progname);
907   printf ("[-m] [-e] [-W limit] [-K limit] [-v] [-q] [-E]\n");