Code

check_disk: minor fix for -C if bestmatch != -p
[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, *se2;
443   struct parameter_list *temp_list;
444   struct parameter_list *temp_path_select_list = NULL;
445   struct mount_entry *me;
446   int result = OK;
447   struct stat *stat_buf;
448   regex_t re;
449   int cflags = REG_NOSUB | REG_EXTENDED;
450   char errbuf[MAX_INPUT_BUFFER];
451   bool fnd = false;
453   int option = 0;
454   static struct option longopts[] = {
455     {"timeout", required_argument, 0, 't'},
456     {"warning", required_argument, 0, 'w'},
457     {"critical", required_argument, 0, 'c'},
458     {"iwarning", required_argument, 0, 'W'},
459     /* Dang, -C is taken. We might want to reshuffle this. */
460     {"icritical", required_argument, 0, 'K'},
461     {"local", required_argument, 0, 'l'},
462     {"kilobytes", required_argument, 0, 'k'},
463     {"megabytes", required_argument, 0, 'm'},
464     {"units", required_argument, 0, 'u'},
465     {"path", required_argument, 0, 'p'},
466     {"partition", required_argument, 0, 'p'},
467     {"exclude_device", required_argument, 0, 'x'},
468     {"exclude-type", required_argument, 0, 'X'},
469     {"group", required_argument, 0, 'g'},
470     {"eregi-path", required_argument, 0, 'R'},
471     {"eregi-partition", required_argument, 0, 'R'},
472     {"ereg-path", required_argument, 0, 'r'},
473     {"ereg-partition", required_argument, 0, 'r'},
474     {"mountpoint", no_argument, 0, 'M'},
475     {"errors-only", no_argument, 0, 'e'},
476     {"exact-match", no_argument, 0, 'E'},
477     {"verbose", no_argument, 0, 'v'},
478     {"quiet", no_argument, 0, 'q'},
479     {"clear", no_argument, 0, 'C'},
480     {"version", no_argument, 0, 'V'},
481     {"help", no_argument, 0, 'h'},
482     {0, 0, 0, 0}
483   };
485   if (argc < 2)
486     return ERROR;
488   np_add_name(&fs_exclude_list, "iso9660");
490   for (c = 1; c < argc; c++)
491     if (strcmp ("-to", argv[c]) == 0)
492       strcpy (argv[c], "-t");
494   while (1) {
495     c = getopt_long (argc, argv, "+?VqhveCt:c:w:K:W:u:p:x:X:mklg:R:r:ME", longopts, &option);
497     if (c == -1 || c == EOF)
498       break;
500     switch (c) {
501     case 't':                 /* timeout period */
502       if (is_integer (optarg)) {
503         timeout_interval = atoi (optarg);
504         break;
505       }
506       else {
507         usage2 (_("Timeout interval must be a positive integer"), optarg);
508       }
510     /* See comments for 'c' */
511     case 'w':                 /* warning threshold */
512       if (strstr(optarg, "%")) {
513         if (*optarg == '@') {
514           warn_freespace_percent = optarg;
515         } else {
516           asprintf(&warn_freespace_percent, "@%s", optarg);
517         }
518       } else {
519         if (*optarg == '@') {
520           warn_freespace_units = optarg;
521         } else {
522           asprintf(&warn_freespace_units, "@%s", optarg);
523         }
524       }
525       break;
527     /* Awful mistake where the range values do not make sense. Normally, 
528        you alert if the value is within the range, but since we are using
529        freespace, we have to alert if outside the range. Thus we artifically
530        force @ at the beginning of the range, so that it is backwards compatible
531     */
532     case 'c':                 /* critical threshold */
533       if (strstr(optarg, "%")) {
534         if (*optarg == '@') {
535           crit_freespace_percent = optarg;
536         } else {
537           asprintf(&crit_freespace_percent, "@%s", optarg);
538         }
539       } else {
540         if (*optarg == '@') {
541           crit_freespace_units = optarg;
542         } else {
543           asprintf(&crit_freespace_units, "@%s", optarg);
544         }
545       }
546       break;
548     case 'W':                   /* warning inode threshold */
549       if (*optarg == '@') {
550         warn_freeinodes_percent = optarg;
551       } else {
552         asprintf(&warn_freeinodes_percent, "@%s", optarg);
553       }
554       break;
555     case 'K':                   /* critical inode threshold */
556       if (*optarg == '@') {
557         crit_freeinodes_percent = optarg;
558       } else {
559         asprintf(&crit_freeinodes_percent, "@%s", optarg);
560       }
561       break;
562     case 'u':
563       if (units)
564         free(units);
565       if (! strcmp (optarg, "bytes")) {
566         mult = (uintmax_t)1;
567         units = strdup ("B");
568       } else if (! strcmp (optarg, "kB")) {
569         mult = (uintmax_t)1024;
570         units = strdup ("kB");
571       } else if (! strcmp (optarg, "MB")) {
572         mult = (uintmax_t)1024 * 1024;
573         units = strdup ("MB");
574       } else if (! strcmp (optarg, "GB")) {
575         mult = (uintmax_t)1024 * 1024 * 1024;
576         units = strdup ("GB");
577       } else if (! strcmp (optarg, "TB")) {
578         mult = (uintmax_t)1024 * 1024 * 1024 * 1024;
579         units = strdup ("TB");
580       } else {
581         die (STATE_UNKNOWN, _("unit type %s not known\n"), optarg);
582       }
583       if (units == NULL)
584         die (STATE_UNKNOWN, _("failed allocating storage for '%s'\n"), "units");
585       break;
586     case 'k': /* display mountpoint */
587       mult = 1024;
588       if (units)
589         free(units);
590       units = strdup ("kB");
591       break;
592     case 'm': /* display mountpoint */
593       mult = 1024 * 1024;
594       if (units)
595         free(units);
596       units = strdup ("MB");
597       break;
598     case 'l':
599       show_local_fs = 1;      
600       break;
601     case 'p':                 /* select path */
602       if (! (warn_freespace_units || crit_freespace_units || warn_freespace_percent || 
603              crit_freespace_percent || warn_usedspace_units || crit_usedspace_units ||
604              warn_usedspace_percent || crit_usedspace_percent || warn_usedinodes_percent ||
605              crit_usedinodes_percent || warn_freeinodes_percent || crit_freeinodes_percent )) {
606         die (STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set a threshold value before using -p\n"));
607       }
609       /* get the real mountdir of the specified path. np_find_parameter won't find an entry if -p is not
610        * exactly the same string as the mountdir */
611       se2 = np_add_parameter(&temp_path_select_list, optarg);
612       np_set_best_match(se2, mount_list, FALSE);
615       /* add parameter if not found. overwrite thresholds if path has already been added  */
616       if (! (se = np_find_parameter(path_select_list, optarg))) {
617           se = np_add_parameter(&path_select_list, optarg);
618       }
619       se->group = group;
620       set_all_thresholds(se);
621       path_selected = true;
622       break;
623     case 'x':                 /* exclude path or partition */
624       np_add_name(&dp_exclude_list, optarg);
625       break;
626     case 'X':                 /* exclude file system type */
627       np_add_name(&fs_exclude_list, optarg);
628       break;
629     case 'v':                 /* verbose */
630       verbose++;
631       break;
632     case 'q':                 /* verbose */
633       verbose--;
634       break;
635     case 'e':
636       erronly = TRUE;
637       break;
638     case 'E':
639       exact_match = TRUE;
640       break;
641     case 'g':
642       if (path_selected)
643         die (STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set group value before using -p\n"));
644       group = optarg;
645       break;
646     case 'R':
647       cflags |= REG_ICASE;
648     case 'r':
649       if (! (warn_freespace_units || crit_freespace_units || warn_freespace_percent || 
650              crit_freespace_percent || warn_usedspace_units || crit_usedspace_units ||
651              warn_usedspace_percent || crit_usedspace_percent || warn_usedinodes_percent ||
652              crit_usedinodes_percent || warn_freeinodes_percent || crit_freeinodes_percent )) {
653         die (STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set a threshold value before using -r/-R\n"));
654       }
656       err = regcomp(&re, optarg, cflags);
657       if (err != 0) {
658         regerror (err, &re, errbuf, MAX_INPUT_BUFFER);
659         die (STATE_UNKNOWN, "DISK %s: %s - %s\n",_("UNKNOWN"), _("Could not compile regular expression"), errbuf);
660       }
661           
662       for (me = mount_list; me; me = me->me_next) {
663         if (np_regex_match_mount_entry(me, &re)) {
664           fnd = true;
665           if (verbose > 3)
666             printf("%s %s matching expression %s\n", me->me_devname, me->me_mountdir, optarg);
668           /* add parameter if not found. overwrite thresholds if path has already been added  */
669           if (! (se = np_find_parameter(path_select_list, me->me_mountdir))) {
670             se = np_add_parameter(&path_select_list, me->me_mountdir);
671           }
672           se->group = group;
673           set_all_thresholds(se);
674         }
675       }
677       if (!fnd)
678         die (STATE_UNKNOWN, "DISK %s: %s - %s\n",_("UNKNOWN"),
679             _("Regular expression did not match any path or disk"), optarg);
681       fnd = false;
682       path_selected = true;
683       break;
684     case 'M': /* display mountpoint */
685       display_mntp = TRUE;
686       break;
687     case 'C':
688        /* add all mount entries to path_select list if no partitions have been explicitly defined using -p */
689        if (path_selected == false) {
690          struct mount_entry *me;
691          struct parameter_list *path;
692          for (me = mount_list; me; me = me->me_next) {
693            if (! (path = np_find_parameter(path_select_list, me->me_mountdir))) 
694              path = np_add_parameter(&path_select_list, me->me_mountdir);
695            path->best_match = me;
696            path->group = group;
697            set_all_thresholds(path);
698          }
699       }
700       warn_freespace_units = NULL;
701       crit_freespace_units = NULL;
702       warn_usedspace_units = NULL;
703       crit_usedspace_units = NULL;
704       warn_freespace_percent = NULL;
705       crit_freespace_percent = NULL;
706       warn_usedspace_percent = NULL;
707       crit_usedspace_percent = NULL;
708       warn_usedinodes_percent = NULL;
709       crit_usedinodes_percent = NULL;
710       warn_freeinodes_percent = NULL;
711       crit_freeinodes_percent = NULL;
712     
713       path_selected = false;
714       group = NULL;
715       break;
716     case 'V':                 /* version */
717       print_revision (progname, revision);
718       exit (STATE_OK);
719     case 'h':                 /* help */
720       print_help ();
721       exit (STATE_OK);
722     case '?':                 /* help */
723       usage (_("Unknown argument"));
724     }
725   }
727   /* Support for "check_disk warn crit [fs]" with thresholds at used% level */
728   c = optind;
729   if (warn_usedspace_percent == NULL && argc > c && is_intnonneg (argv[c]))
730     warn_usedspace_percent = argv[c++];
732   if (crit_usedspace_percent == NULL && argc > c && is_intnonneg (argv[c]))
733     crit_usedspace_percent = argv[c++];
735   if (argc > c && path == NULL) {
736     se = np_add_parameter(&path_select_list, strdup(argv[c++]));
737     set_all_thresholds(se);
738   }
740   if (units == NULL) {
741     units = strdup ("MB");
742     mult = (uintmax_t)1024 * 1024;
743   }
745   if (path_select_list) {
746     temp_list = path_select_list;
747     stat_buf = malloc(sizeof *stat_buf);
748     while (temp_list) {
749       /* Stat each entry to check that dir exists */
750       if (stat (temp_list->name, &stat_buf[0])) {
751         printf("DISK %s - ", _("CRITICAL"));
752         die (STATE_CRITICAL, _("%s does not exist\n"), temp_list->name);
753       }
754       /* if (validate_arguments (temp_list->w_df,
755                               temp_list->c_df,
756                               temp_list->w_dfp,
757                               temp_list->c_dfp,
758                               temp_list->w_idfp,
759                               temp_list->c_idfp,
760                               temp_list->name) == ERROR)
761         result = ERROR;
762       */
763       temp_list = temp_list->name_next;
764     }
765     free(stat_buf);
766     return result;
767   } else {
768     return TRUE;
769     /* return validate_arguments (w_df, c_df, w_dfp, c_dfp, w_idfp, c_idfp, NULL); */
770   }
775 void
776 print_path (const char *mypath) 
778   if (mypath == NULL)
779     printf ("\n");
780   else
781     printf (_(" for %s\n"), mypath);
785 void
786 set_all_thresholds (struct parameter_list *path) 
788     set_thresholds(&path->freespace_units, warn_freespace_units, crit_freespace_units);
789     set_thresholds(&path->freespace_percent, warn_freespace_percent, crit_freespace_percent);
790     set_thresholds(&path->usedspace_units, warn_usedspace_units, crit_usedspace_units);
791     set_thresholds(&path->usedspace_percent, warn_usedspace_percent, crit_usedspace_percent);
792     set_thresholds(&path->usedinodes_percent, warn_usedinodes_percent, crit_usedinodes_percent);
793     set_thresholds(&path->freeinodes_percent, warn_freeinodes_percent, crit_freeinodes_percent);
796 /* TODO: Remove?
798 int
799 validate_arguments (uintmax_t w, uintmax_t c, double wp, double cp, double iwp, double icp, char *mypath)
801   if (w < 0 && c < 0 && wp < 0.0 && cp < 0.0) {
802     printf (_("INPUT ERROR: No thresholds specified"));
803     print_path (mypath);
804     return ERROR;
805   }
806   else if ((wp >= 0.0 || cp >= 0.0) &&
807            (wp < 0.0 || cp < 0.0 || wp > 100.0 || cp > 100.0 || cp > wp)) {
808     printf (_("\
809 INPUT ERROR: C_DFP (%f) should be less than W_DFP (%.1f) and both should be between zero and 100 percent, inclusive"),
810             cp, wp);
811     print_path (mypath);
812     return ERROR;
813   }
814   else if ((iwp >= 0.0 || icp >= 0.0) &&
815            (iwp < 0.0 || icp < 0.0 || iwp > 100.0 || icp > 100.0 || icp > iwp)) {
816     printf (_("\
817 INPUT ERROR: C_IDFP (%f) should be less than W_IDFP (%.1f) and both should be between zero and 100 percent, inclusive"),
818             icp, iwp);
819     print_path (mypath);
820     return ERROR;
821   }
822   else if ((w > 0 || c > 0) && (w == 0 || c == 0 || c > w)) {
823     printf (_("\
824 INPUT ERROR: C_DF (%lu) should be less than W_DF (%lu) and both should be greater than zero"),
825             (unsigned long)c, (unsigned long)w);
826     print_path (mypath);
827     return ERROR;
828   }
829   
830   return OK;
833 */
841 void
842 print_help (void)
844   print_revision (progname, revision);
846   printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
847   printf (COPYRIGHT, copyright, email);
849   printf ("%s\n", _("This plugin checks the amount of used disk space on a mounted file system"));
850   printf ("%s\n", _("and generates an alert if free space is less than one of the threshold values"));
852   printf ("\n\n");
854   print_usage ();
856   printf (_(UT_HELP_VRSN));
858   printf (" %s\n", "-w, --warning=INTEGER");
859   printf ("    %s\n", _("Exit with WARNING status if less than INTEGER units of disk are free"));
860   printf (" %s\n", "-w, --warning=PERCENT%");
861   printf ("    %s\n", _("Exit with WARNING status if less than PERCENT of disk space is free"));
862   printf (" %s\n", "-W, --iwarning=PERCENT%");
863   printf ("    %s\n", _("Exit with WARNING status if less than PERCENT of inode space is free"));
864   printf (" %s\n", "-K, --icritical=PERCENT%");
865   printf ("    %s\n", _("Exit with CRITICAL status if less than PERCENT of inode space is free"));
866   printf (" %s\n", "-c, --critical=INTEGER");
867   printf ("    %s\n", _("Exit with CRITICAL status if less than INTEGER units of disk are free"));
868   printf (" %s\n", "-c, --critical=PERCENT%");
869   printf ("    %s\n", _("Exit with CRITCAL status if less than PERCENT of disk space is free"));
870   printf (" %s\n", "-C, --clear");
871   printf ("    %s\n", _("Clear thresholds"));
872   printf (" %s\n", "-u, --units=STRING");
873   printf ("    %s\n", _("Choose bytes, kB, MB, GB, TB (default: MB)"));
874   printf (" %s\n", "-k, --kilobytes");
875   printf ("    %s\n", _("Same as '--units kB'"));
876   printf (" %s\n", "-m, --megabytes");
877   printf ("    %s\n", _("Same as '--units MB'"));
878   printf (" %s\n", "-l, --local");
879   printf ("    %s\n", _("Only check local filesystems"));
880   printf (" %s\n", "-p, --path=PATH, --partition=PARTITION");
881   printf ("    %s\n", _("Path or partition (may be repeated)"));
882   printf (" %s\n", "-r, --ereg-path=PATH, --ereg-partition=PARTITION");
883   printf ("    %s\n", _("Regular expression for path or partition (may be repeated)"));
884   printf (" %s\n", "-R, --eregi-path=PATH, --eregi-partition=PARTITION");
885   printf ("    %s\n", _("Case insensitive regular expression for path/partition (may be repeated)"));
886   printf (" %s\n", "-g, --group=NAME");
887   printf ("    %s\n", _("Group pathes. Thresholds apply to (free-)space of all partitions together"));
888   printf (" %s\n", "-x, --exclude_device=PATH <STRING>");
889   printf ("    %s\n", _("Ignore device (only works if -p unspecified)"));
890   printf (" %s\n", "-X, --exclude-type=TYPE <STRING>");
891   printf ("    %s\n", _("Ignore all filesystems of indicated type (may be repeated)"));
892   printf (" %s\n", "-M, --mountpoint");
893   printf ("    %s\n", _("Display the mountpoint instead of the partition"));
894   printf (" %s\n", "-E, --exact-match");
895   printf ("    %s\n", _("For paths or partitions specified with -p, only check for exact paths"));
896   printf (" %s\n", "-e, --errors-only");
897   printf ("    %s\n", _("Display only devices/mountpoints with errors"));
898   printf (_(UT_TIMEOUT), DEFAULT_SOCKET_TIMEOUT);
899   printf (_(UT_VERBOSE));
900   printf ("\n");
901   printf ("%s\n", _("Examples:"));
902   printf (" %s\n", "check_disk -w 10% -c 5% -p /tmp -p /var -C -w 100000 -c 50000 -p /");
903   printf ("    %s\n", _("Checks /tmp and /var at 10% and 5%, and / at 100MB and 50MB"));
904   printf (_(UT_SUPPORT));
909 void
910 print_usage (void)
912   printf (_("Usage:"));
913   printf (" %s -w limit -c limit [-p path | -x device] [-t timeout]", progname);
914   printf ("[-m] [-e] [-W limit] [-K limit] [-v] [-q] [-E]\n");