Code

If unspecified set LDAP_OPT_SUCCESS to LDAP_SUCCESS (Sergei Haramundanis - #1498923)
[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 nonzero, show only local filesystems but call stat() on remote ones. */
73 static int stat_remote_fs = 0;
75 /* If positive, the units to use when printing sizes;
76    if negative, the human-readable base.  */
77 /* static int output_block_size; */
79 /* If nonzero, invoke the `sync' system call before getting any usage data.
80    Using this option can make df very slow, especially with many or very
81    busy disks.  Note that this may make a difference on some systems --
82    SunOs4.1.3, for one.  It is *not* necessary on Linux.  */
83 /* static int require_sync = 0; */
85 /* Linked list of filesystem types to display.
86    If `fs_select_list' is NULL, list all types.
87    This table is generated dynamically from command-line options,
88    rather than hardcoding into the program what it thinks are the
89    valid filesystem types; let the user specify any filesystem type
90    they want to, and if there are any filesystems of that type, they
91    will be shown.
93    Some filesystem types:
94    4.2 4.3 ufs nfs swap ignore io vm efs dbg */
96 /* static struct parameter_list *fs_select_list; */
98 /* Linked list of filesystem types to omit.
99    If the list is empty, don't exclude any types.  */
101 static struct name_list *fs_exclude_list;
103 static struct name_list *dp_exclude_list;
105 static struct parameter_list *path_select_list = NULL;
107 /* Linked list of mounted filesystems. */
108 static struct mount_entry *mount_list;
110 /* For long options that have no equivalent short option, use a
111    non-character as a pseudo short option, starting with CHAR_MAX + 1.  */
112 enum
114   SYNC_OPTION = CHAR_MAX + 1,
115   NO_SYNC_OPTION,
116   BLOCK_SIZE_OPTION
117 };
119 #ifdef _AIX
120  #pragma alloca
121 #endif
123 /* Linked list of mounted filesystems. */
124 static struct mount_entry *mount_list;
126 int process_arguments (int, char **);
127 void print_path (const char *mypath);
128 void set_all_thresholds (struct parameter_list *path);
129 int validate_arguments (uintmax_t, uintmax_t, double, double, double, double, char *);
130 void print_help (void);
131 void print_usage (void);
132 double calculate_percent(uintmax_t, uintmax_t);
133 void stat_path (struct parameter_list *p);
135 double w_dfp = -1.0;
136 double c_dfp = -1.0;
137 char *path;
138 char *exclude_device;
139 char *units;
140 uintmax_t mult = 1024 * 1024;
141 int verbose = 0;
142 int erronly = FALSE;
143 int display_mntp = FALSE;
144 int exact_match = FALSE;
145 char *warn_freespace_units = NULL;
146 char *crit_freespace_units = NULL;
147 char *warn_freespace_percent = NULL;
148 char *crit_freespace_percent = NULL;
149 char *warn_usedspace_units = NULL;
150 char *crit_usedspace_units = NULL;
151 char *warn_usedspace_percent = NULL;
152 char *crit_usedspace_percent = NULL;
153 char *warn_usedinodes_percent = NULL;
154 char *crit_usedinodes_percent = NULL;
155 char *warn_freeinodes_percent = NULL;
156 char *crit_freeinodes_percent = NULL;
157 int path_selected = FALSE;
158 char *group = NULL;
159 struct stat *stat_buf;
162 int
163 main (int argc, char **argv)
165   int result = STATE_UNKNOWN;
166   int disk_result = STATE_UNKNOWN;
167   char *output;
168   char *details;
169   char *perf;
170   char *preamble;
171   double inode_space_pct;
172   uintmax_t total, available, available_to_root, used;
173   double dfree_pct = -1, dused_pct = -1;
174   double dused_units, dfree_units, dtotal_units;
175   double dused_inodes_percent, dfree_inodes_percent;
176   double warning_high_tide;
177   double critical_high_tide;
178   int temp_result;
180   struct mount_entry *me;
181   struct fs_usage fsp, tmpfsp;
182   struct parameter_list *temp_list, *path;
183   struct name_list *seen = NULL;
185   preamble = strdup (" - free space:");
186   output = strdup ("");
187   details = strdup ("");
188   perf = strdup ("");
189   stat_buf = malloc(sizeof *stat_buf);
191   setlocale (LC_ALL, "");
192   bindtextdomain (PACKAGE, LOCALEDIR);
193   textdomain (PACKAGE);
195   mount_list = read_file_system_list (0);
197   if (process_arguments (argc, argv) == ERROR)
198     usage4 (_("Could not parse arguments"));
200   /* If a list of paths has not been selected, find entire
201      mount list and create list of paths
202    */
203   if (path_selected == FALSE) { 
204     for (me = mount_list; me; me = me->me_next) {
205       if (! (path = np_find_parameter(path_select_list, me->me_mountdir))) {
206         path = np_add_parameter(&path_select_list, me->me_mountdir);
207       }
208       path->best_match = me;
209       path->group = group;
210       set_all_thresholds(path);
211     }
212   }
213   np_set_best_match(path_select_list, mount_list, exact_match);
215   /* Error if no match found for specified paths */
216   temp_list = path_select_list;
218   while (temp_list) {
219     if (! temp_list->best_match) {
220       die (STATE_CRITICAL, _("DISK %s: %s not found\n"), _("CRITICAL"), temp_list->name);
221     }
223     temp_list = temp_list->name_next;
224   }
225   
226   /* Process for every path in list */
227   for (path = path_select_list; path; path=path->name_next) {
229     if (verbose > 3 && path->freespace_percent->warning != NULL && path->freespace_percent->critical != NULL)
230       printf("Thresholds(pct) for %s warn: %f crit %f\n",path->name, path->freespace_percent->warning->end,
231                                                          path->freespace_percent->critical->end);
233     if (verbose > 3 && path->group != NULL)
234       printf("Group of %s: %s\n",path->name,path->group);
236     /* reset disk result */
237     disk_result = STATE_UNKNOWN;
239     me = path->best_match;
241     /* Filters */
243     /* Remove filesystems already seen */
244     if (np_seen_name(seen, me->me_mountdir)) {
245       continue;
246     } else {
247       if (path->group != NULL) {
248         /* find all group members */
249         fsp.fsu_blocksize = 0;
250         fsp.fsu_blocks    = 0;
251         fsp.fsu_bfree     = 0;
252         fsp.fsu_bavail    = 0;
253         fsp.fsu_files     = 0;
254         fsp.fsu_ffree     = 0;
257         for (temp_list = path_select_list; temp_list; temp_list=temp_list->name_next) {
258           if (temp_list->group && ! (strcmp(temp_list->group, path->group))) {
259             
260             stat_path(path);
261             get_fs_usage (temp_list->best_match->me_mountdir, temp_list->best_match->me_devname, &tmpfsp);
263             /* possibly differing blocksizes if disks are grouped. Calculating average */
264             fsp.fsu_blocksize = (fsp.fsu_blocksize * fsp.fsu_blocks + tmpfsp.fsu_blocksize * tmpfsp.fsu_blocks) / \
265                                 (fsp.fsu_blocks + tmpfsp.fsu_blocks);  /* Size of a block.  */
266             fsp.fsu_blocks    += tmpfsp.fsu_blocks;     /* Total blocks. */
267             fsp.fsu_bfree     += tmpfsp.fsu_bfree;      /* Free blocks available to superuser. */
268             fsp.fsu_bavail    += tmpfsp.fsu_bavail;     /* Free blocks available to non-superuser. */
269             fsp.fsu_files     += tmpfsp.fsu_files;      /* Total file nodes. */
270             fsp.fsu_ffree     += tmpfsp.fsu_ffree;      /* Free file nodes. */
271             
272             if (verbose > 3)
273               printf("Group %s: add %llu blocks (%s) \n", path->group, tmpfsp.fsu_bavail, temp_list->name);
274              /* printf("Group %s: add %u blocks (%s)\n", temp_list->name); *//* path->group, tmpfsp.fsu_bavail, temp_list->name); */
276             np_add_name(&seen, temp_list->best_match->me_mountdir);
277           }
278         }
279         /* modify devname and mountdir for output */
280         me->me_mountdir = me->me_devname = path->group;
281       } else
282         np_add_name(&seen, me->me_mountdir);
283     }
285     if (path->group == NULL) {
286       /* Skip remote filesystems if we're not interested in them */
287       if (me->me_remote && show_local_fs) {
288         if (stat_remote_fs)
289           stat_path(path);
290         continue;
291       /* Skip pseudo fs's if we haven't asked for all fs's */
292       } else if (me->me_dummy && !show_all_fs) {
293         continue;
294       /* Skip excluded fstypes */
295       } else if (fs_exclude_list && np_find_name (fs_exclude_list, me->me_type)) {
296         continue;
297       /* Skip excluded fs's */  
298       } else if (dp_exclude_list && 
299                (np_find_name (dp_exclude_list, me->me_devname) ||
300                 np_find_name (dp_exclude_list, me->me_mountdir))) {
301         continue;
302       }
304       stat_path(path);
305       get_fs_usage (me->me_mountdir, me->me_devname, &fsp);
306     }
308     if (fsp.fsu_blocks && strcmp ("none", me->me_mountdir)) {
309       total = fsp.fsu_blocks;
310       /* 2007-12-08 - Workaround for Gnulib reporting insanely high available
311        * space on BSD (the actual value should be negative but fsp.fsu_bavail
312        * is unsigned) */
313       available = fsp.fsu_bavail > fsp.fsu_bfree ? 0 : fsp.fsu_bavail;
314       available_to_root = fsp.fsu_bfree;
315       used = total - available_to_root;
317       if (verbose >= 3)
318         printf ("For %s, total=%llu, available=%llu, available_to_root=%llu, used=%llu, fsp.fsu_files=%llu, fsp.fsu_ffree=%llu\n",
319         me->me_mountdir, total, available, available_to_root, used, fsp.fsu_files, fsp.fsu_ffree);
321       dused_pct = calculate_percent( used, used + available );  /* used + available can never be > uintmax */
322      
323       dfree_pct = 100 - dused_pct;
324       dused_units = used*fsp.fsu_blocksize/mult;
325       dfree_units = available*fsp.fsu_blocksize/mult;
326       dtotal_units = total*fsp.fsu_blocksize/mult;
327       dused_inodes_percent = calculate_percent(fsp.fsu_files - fsp.fsu_ffree, fsp.fsu_files);
328       dfree_inodes_percent = 100 - dused_inodes_percent;
330       if (verbose >= 3) {
331         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", 
332           me->me_mountdir, dused_pct, dfree_pct, dused_units, dfree_units, dtotal_units, dused_inodes_percent, dfree_inodes_percent, fsp.fsu_blocksize, mult);
333       }
335       /* Threshold comparisons */
337       temp_result = get_status(dfree_units, path->freespace_units);
338       if (verbose >=3) printf("Freespace_units result=%d\n", temp_result);
339       disk_result = max_state( disk_result, temp_result );
341       temp_result = get_status(dfree_pct, path->freespace_percent);
342       if (verbose >=3) printf("Freespace%% result=%d\n", temp_result);
343       disk_result = max_state( disk_result, temp_result );
345       temp_result = get_status(dused_units, path->usedspace_units);
346       if (verbose >=3) printf("Usedspace_units result=%d\n", temp_result);
347       disk_result = max_state( disk_result, temp_result );
349       temp_result = get_status(dused_pct, path->usedspace_percent);
350       if (verbose >=3) printf("Usedspace_percent result=%d\n", temp_result);
351       disk_result = max_state( disk_result, temp_result );
353       temp_result = get_status(dused_inodes_percent, path->usedinodes_percent);
354       if (verbose >=3) printf("Usedinodes_percent result=%d\n", temp_result);
355       disk_result = max_state( disk_result, temp_result );
357       temp_result = get_status(dfree_inodes_percent, path->freeinodes_percent);
358       if (verbose >=3) printf("Freeinodes_percent result=%d\n", temp_result);
359       disk_result = max_state( disk_result, temp_result );
361       result = max_state(result, disk_result);
363       /* What a mess of units. The output shows free space, the perf data shows used space. Yikes!
364          Hack here. Trying to get warn/crit levels from freespace_(units|percent) for perf
365          data. Assumption that start=0. Roll on new syntax...
366       */
368       /* *_high_tide must be reinitialized at each run */
369       warning_high_tide = UINT_MAX;
370       critical_high_tide = UINT_MAX;
372       if (path->freespace_units->warning != NULL) {
373         warning_high_tide = dtotal_units - path->freespace_units->warning->end;
374       }
375       if (path->freespace_percent->warning != NULL) {
376         warning_high_tide = abs( min( (double) warning_high_tide, (double) (1.0 - path->freespace_percent->warning->end/100)*dtotal_units ));
377       }
378       if (path->freespace_units->critical != NULL) {
379         critical_high_tide = dtotal_units - path->freespace_units->critical->end;
380       }
381       if (path->freespace_percent->critical != NULL) {
382         critical_high_tide = abs( min( (double) critical_high_tide, (double) (1.0 - path->freespace_percent->critical->end/100)*dtotal_units ));
383       }
385       /* Nb: *_high_tide are unset when == UINT_MAX */
386       asprintf (&perf, "%s %s", perf,
387                 perfdata ((!strcmp(me->me_mountdir, "none") || display_mntp) ? me->me_devname : me->me_mountdir,
388                           dused_units, units,
389                           (warning_high_tide != UINT_MAX ? TRUE : FALSE), warning_high_tide,
390                           (critical_high_tide != UINT_MAX ? TRUE : FALSE), critical_high_tide,
391                           TRUE, 0,
392                           TRUE, dtotal_units));
394       if (disk_result==STATE_OK && erronly && !verbose)
395         continue;
397       asprintf (&output, "%s %s %.0f %s (%.0f%%",
398                 output,
399                 (!strcmp(me->me_mountdir, "none") || display_mntp) ? me->me_devname : me->me_mountdir,
400                 dfree_units,
401                 units,
402                 dfree_pct);
403       if (dused_inodes_percent < 0) {
404         asprintf(&output, "%s inode=-);", output);
405       } else {
406         asprintf(&output, "%s inode=%.0f%%);", output, dfree_inodes_percent );
407       }
409       /* TODO: Need to do a similar debug line
410       asprintf (&details, _("%s\n\
411 %.0f of %.0f %s (%.0f%% inode=%.0f%%) free on %s (type %s mounted on %s) warn:%lu crit:%lu warn%%:%.0f%% crit%%:%.0f%%"),
412                 details, dfree_units, dtotal_units, units, dfree_pct, inode_space_pct,
413                 me->me_devname, me->me_type, me->me_mountdir,
414                 (unsigned long)w_df, (unsigned long)c_df, w_dfp, c_dfp);
415       */
417     }
419   }
421   if (verbose > 2)
422     asprintf (&output, "%s%s", output, details);
425   printf ("DISK %s%s%s|%s\n", state_text (result), (erronly && result==STATE_OK) ? "" : preamble, output, perf);
426   return result;
430 double calculate_percent(uintmax_t value, uintmax_t total) {
431   double pct = -1;
432   /* I don't understand the below, but it is taken from coreutils' df */
433   /* Seems to be calculating pct, in the best possible way */
434   if (value <= TYPE_MAXIMUM(uintmax_t) / 100 
435     && total != 0) {
436     uintmax_t u100 = value * 100;
437     pct = u100 / total + (u100 % total != 0);
438   } else {
439     /* Possible rounding errors - see coreutils' df for more explanation */
440     double u = value;
441     double t = total;
442     if (t) {
443       long int lipct = pct = u * 100 / t;
444       double ipct = lipct;
446       /* Like 'pct = ceil (dpct);', but without ceil - from coreutils again */
447       if (ipct - 1 < pct && pct <= ipct + 1)
448         pct = ipct + (ipct < pct);
449     }
450   }
451   return pct;
454 /* process command-line arguments */
455 int
456 process_arguments (int argc, char **argv)
458   int c, err;
459   struct parameter_list *se;
460   struct parameter_list *temp_list = NULL, *previous = NULL;
461   struct parameter_list *temp_path_select_list = NULL;
462   struct mount_entry *me, *temp_me;
463   int result = OK;
464   regex_t re;
465   int cflags = REG_NOSUB | REG_EXTENDED;
466   int default_cflags = cflags;
467   char errbuf[MAX_INPUT_BUFFER];
468   int fnd = 0;
470   int option = 0;
471   static struct option longopts[] = {
472     {"timeout", required_argument, 0, 't'},
473     {"warning", required_argument, 0, 'w'},
474     {"critical", required_argument, 0, 'c'},
475     {"iwarning", required_argument, 0, 'W'},
476     /* Dang, -C is taken. We might want to reshuffle this. */
477     {"icritical", required_argument, 0, 'K'},
478     {"local", required_argument, 0, 'l'},
479     {"stat-remote-fs", required_argument, 0, 'L'},
480     {"kilobytes", required_argument, 0, 'k'},
481     {"megabytes", required_argument, 0, 'm'},
482     {"units", required_argument, 0, 'u'},
483     {"path", required_argument, 0, 'p'},
484     {"partition", required_argument, 0, 'p'},
485     {"exclude_device", required_argument, 0, 'x'},
486     {"exclude-type", required_argument, 0, 'X'},
487     {"group", required_argument, 0, 'g'},
488     {"eregi-path", required_argument, 0, 'R'},
489     {"eregi-partition", required_argument, 0, 'R'},
490     {"ereg-path", required_argument, 0, 'r'},
491     {"ereg-partition", required_argument, 0, 'r'},
492     {"ignore-ereg-path", required_argument, 0, 'i'},
493     {"ignore-ereg-partition", required_argument, 0, 'i'},
494     {"ignore-eregi-path", required_argument, 0, 'I'},
495     {"ignore-eregi-partition", required_argument, 0, 'I'},
496     {"mountpoint", no_argument, 0, 'M'},
497     {"errors-only", no_argument, 0, 'e'},
498     {"exact-match", no_argument, 0, 'E'},
499     {"all", no_argument, 0, 'A'},
500     {"verbose", no_argument, 0, 'v'},
501     {"quiet", no_argument, 0, 'q'},
502     {"clear", no_argument, 0, 'C'},
503     {"version", no_argument, 0, 'V'},
504     {"help", no_argument, 0, 'h'},
505     {0, 0, 0, 0}
506   };
508   if (argc < 2)
509     return ERROR;
511   np_add_name(&fs_exclude_list, "iso9660");
513   for (c = 1; c < argc; c++)
514     if (strcmp ("-to", argv[c]) == 0)
515       strcpy (argv[c], "-t");
517   while (1) {
518     c = getopt_long (argc, argv, "+?VqhveCt:c:w:K:W:u:p:x:X:mklLg:R:r:i:I:MEA", longopts, &option);
520     if (c == -1 || c == EOF)
521       break;
523     switch (c) {
524     case 't':                 /* timeout period */
525       if (is_integer (optarg)) {
526         timeout_interval = atoi (optarg);
527         break;
528       }
529       else {
530         usage2 (_("Timeout interval must be a positive integer"), optarg);
531       }
533     /* See comments for 'c' */
534     case 'w':                 /* warning threshold */
535       if (strstr(optarg, "%")) {
536         if (*optarg == '@') {
537           warn_freespace_percent = optarg;
538         } else {
539           asprintf(&warn_freespace_percent, "@%s", optarg);
540         }
541       } else {
542         if (*optarg == '@') {
543           warn_freespace_units = optarg;
544         } else {
545           asprintf(&warn_freespace_units, "@%s", optarg);
546         }
547       }
548       break;
550     /* Awful mistake where the range values do not make sense. Normally, 
551        you alert if the value is within the range, but since we are using
552        freespace, we have to alert if outside the range. Thus we artifically
553        force @ at the beginning of the range, so that it is backwards compatible
554     */
555     case 'c':                 /* critical threshold */
556       if (strstr(optarg, "%")) {
557         if (*optarg == '@') {
558           crit_freespace_percent = optarg;
559         } else {
560           asprintf(&crit_freespace_percent, "@%s", optarg);
561         }
562       } else {
563         if (*optarg == '@') {
564           crit_freespace_units = optarg;
565         } else {
566           asprintf(&crit_freespace_units, "@%s", optarg);
567         }
568       }
569       break;
571     case 'W':                   /* warning inode threshold */
572       if (*optarg == '@') {
573         warn_freeinodes_percent = optarg;
574       } else {
575         asprintf(&warn_freeinodes_percent, "@%s", optarg);
576       }
577       break;
578     case 'K':                   /* critical inode threshold */
579       if (*optarg == '@') {
580         crit_freeinodes_percent = optarg;
581       } else {
582         asprintf(&crit_freeinodes_percent, "@%s", optarg);
583       }
584       break;
585     case 'u':
586       if (units)
587         free(units);
588       if (! strcmp (optarg, "bytes")) {
589         mult = (uintmax_t)1;
590         units = strdup ("B");
591       } else if (! strcmp (optarg, "kB")) {
592         mult = (uintmax_t)1024;
593         units = strdup ("kB");
594       } else if (! strcmp (optarg, "MB")) {
595         mult = (uintmax_t)1024 * 1024;
596         units = strdup ("MB");
597       } else if (! strcmp (optarg, "GB")) {
598         mult = (uintmax_t)1024 * 1024 * 1024;
599         units = strdup ("GB");
600       } else if (! strcmp (optarg, "TB")) {
601         mult = (uintmax_t)1024 * 1024 * 1024 * 1024;
602         units = strdup ("TB");
603       } else {
604         die (STATE_UNKNOWN, _("unit type %s not known\n"), optarg);
605       }
606       if (units == NULL)
607         die (STATE_UNKNOWN, _("failed allocating storage for '%s'\n"), "units");
608       break;
609     case 'k': /* display mountpoint */
610       mult = 1024;
611       if (units)
612         free(units);
613       units = strdup ("kB");
614       break;
615     case 'm': /* display mountpoint */
616       mult = 1024 * 1024;
617       if (units)
618         free(units);
619       units = strdup ("MB");
620       break;
621     case 'L':
622       stat_remote_fs = 1;
623     case 'l':
624       show_local_fs = 1;      
625       break;
626     case 'p':                 /* select path */
627       if (! (warn_freespace_units || crit_freespace_units || warn_freespace_percent || 
628              crit_freespace_percent || warn_usedspace_units || crit_usedspace_units ||
629              warn_usedspace_percent || crit_usedspace_percent || warn_usedinodes_percent ||
630              crit_usedinodes_percent || warn_freeinodes_percent || crit_freeinodes_percent )) {
631         die (STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set a threshold value before using -p\n"));
632       }
634       /* add parameter if not found. overwrite thresholds if path has already been added  */
635       if (! (se = np_find_parameter(path_select_list, optarg))) {
636           se = np_add_parameter(&path_select_list, optarg);
637       }
638       se->group = group;
639       set_all_thresholds(se);
640       np_set_best_match(se, mount_list, exact_match);
641       stat_path(se);
642       path_selected = TRUE;
643       break;
644     case 'x':                 /* exclude path or partition */
645       np_add_name(&dp_exclude_list, optarg);
646       break;
647     case 'X':                 /* exclude file system type */
648       np_add_name(&fs_exclude_list, optarg);
649       break;
650     case 'v':                 /* verbose */
651       verbose++;
652       break;
653     case 'q':                 /* TODO: this function should eventually go away (removed 2007-09-20) */
654       /* verbose--; **replaced by line below**. -q was only a broken way of implementing -e */
655       erronly = TRUE;
656       break;
657     case 'e':
658       erronly = TRUE;
659       break;
660     case 'E':
661       if (path_selected)
662         die (STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set -E before selecting pathes\n"));
663       exact_match = TRUE;
664       break;
665     case 'g':
666       if (path_selected)
667         die (STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set group value before selecting pathes \n"));
668       group = optarg;
669       break;
670     case 'I':
671       cflags |= REG_ICASE;
672     case 'i':
673       if (!path_selected)
674         die (STATE_UNKNOWN, "DISK %s: %s\n", _("UNKNOWN"), _("Pathes need to be selected before using -i/-I. Use -A to select all pathes explicitly"));
675       err = regcomp(&re, optarg, cflags);
676       if (err != 0) {
677         regerror (err, &re, errbuf, MAX_INPUT_BUFFER);
678         die (STATE_UNKNOWN, "DISK %s: %s - %s\n",_("UNKNOWN"), _("Could not compile regular expression"), errbuf);
679       }
681       temp_list = path_select_list;
683       previous = NULL;
684       while (temp_list) {
685         if (temp_list->best_match) {
686           if (np_regex_match_mount_entry(temp_list->best_match, &re)) {
687         
688               if (verbose >=3)
689                 printf("ignoring %s matching regex\n", temp_list->name);
691               temp_list = np_del_parameter(temp_list, previous);
692               /* pointer to first element needs to be uĆ¼dated if first item gets deleted */
693               if (previous == NULL)
694                 path_select_list = temp_list;
695           } else {
696             previous = temp_list;
697             temp_list = temp_list->name_next;
698           }
699         } else {
700           previous = temp_list;
701           temp_list = temp_list->name_next;
702         }
703       }
706       cflags = default_cflags;
707       break;
709     case 'A':
710       optarg = strdup(".*");
711     case 'R':
712       cflags |= REG_ICASE;
713     case 'r':
714       if (! (warn_freespace_units || crit_freespace_units || warn_freespace_percent || 
715              crit_freespace_percent || warn_usedspace_units || crit_usedspace_units ||
716              warn_usedspace_percent || crit_usedspace_percent || warn_usedinodes_percent ||
717              crit_usedinodes_percent || warn_freeinodes_percent || crit_freeinodes_percent )) {
718         die (STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set a threshold value before using -r/-R\n"));
719       }
721       err = regcomp(&re, optarg, cflags);
722       if (err != 0) {
723         regerror (err, &re, errbuf, MAX_INPUT_BUFFER);
724         die (STATE_UNKNOWN, "DISK %s: %s - %s\n",_("UNKNOWN"), _("Could not compile regular expression"), errbuf);
725       }
726           
727       for (me = mount_list; me; me = me->me_next) {
728         if (np_regex_match_mount_entry(me, &re)) {
729           fnd = TRUE;
730           if (verbose > 3)
731             printf("%s %s matching expression %s\n", me->me_devname, me->me_mountdir, optarg);
733           /* add parameter if not found. overwrite thresholds if path has already been added  */
734           if (! (se = np_find_parameter(path_select_list, me->me_mountdir))) {
735             se = np_add_parameter(&path_select_list, me->me_mountdir);
736           }
737           se->group = group;
738           set_all_thresholds(se);
739         }
740       }
742       if (!fnd)
743         die (STATE_UNKNOWN, "DISK %s: %s - %s\n",_("UNKNOWN"),
744             _("Regular expression did not match any path or disk"), optarg);
746       fnd = FALSE;
747       path_selected = TRUE;
748       np_set_best_match(path_select_list, mount_list, exact_match);
749       cflags = default_cflags;
751       break;
752     case 'M': /* display mountpoint */
753       display_mntp = TRUE;
754       break;
755     case 'C':
756        /* add all mount entries to path_select list if no partitions have been explicitly defined using -p */
757        if (path_selected == FALSE) {
758          struct mount_entry *me;
759          struct parameter_list *path;
760          for (me = mount_list; me; me = me->me_next) {
761            if (! (path = np_find_parameter(path_select_list, me->me_mountdir))) 
762              path = np_add_parameter(&path_select_list, me->me_mountdir);
763            path->best_match = me;
764            path->group = group;
765            set_all_thresholds(path);
766          }
767       }
768       warn_freespace_units = NULL;
769       crit_freespace_units = NULL;
770       warn_usedspace_units = NULL;
771       crit_usedspace_units = NULL;
772       warn_freespace_percent = NULL;
773       crit_freespace_percent = NULL;
774       warn_usedspace_percent = NULL;
775       crit_usedspace_percent = NULL;
776       warn_usedinodes_percent = NULL;
777       crit_usedinodes_percent = NULL;
778       warn_freeinodes_percent = NULL;
779       crit_freeinodes_percent = NULL;
780     
781       path_selected = FALSE;
782       group = NULL;
783       break;
784     case 'V':                 /* version */
785       print_revision (progname, revision);
786       exit (STATE_OK);
787     case 'h':                 /* help */
788       print_help ();
789       exit (STATE_OK);
790     case '?':                 /* help */
791       usage (_("Unknown argument"));
792     }
793   }
795   /* Support for "check_disk warn crit [fs]" with thresholds at used% level */
796   c = optind;
797   if (warn_usedspace_percent == NULL && argc > c && is_intnonneg (argv[c]))
798     warn_usedspace_percent = argv[c++];
800   if (crit_usedspace_percent == NULL && argc > c && is_intnonneg (argv[c]))
801     crit_usedspace_percent = argv[c++];
803   if (argc > c && path == NULL) {
804     se = np_add_parameter(&path_select_list, strdup(argv[c++]));
805     path_selected = TRUE;
806     set_all_thresholds(se);
807   }
809   if (units == NULL) {
810     units = strdup ("MB");
811     mult = (uintmax_t)1024 * 1024;
812   }
814   return TRUE;
819 void
820 print_path (const char *mypath) 
822   if (mypath == NULL)
823     printf ("\n");
824   else
825     printf (_(" for %s\n"), mypath);
829 void
830 set_all_thresholds (struct parameter_list *path) 
832     set_thresholds(&path->freespace_units, warn_freespace_units, crit_freespace_units);
833     set_thresholds(&path->freespace_percent, warn_freespace_percent, crit_freespace_percent);
834     set_thresholds(&path->usedspace_units, warn_usedspace_units, crit_usedspace_units);
835     set_thresholds(&path->usedspace_percent, warn_usedspace_percent, crit_usedspace_percent);
836     set_thresholds(&path->usedinodes_percent, warn_usedinodes_percent, crit_usedinodes_percent);
837     set_thresholds(&path->freeinodes_percent, warn_freeinodes_percent, crit_freeinodes_percent);
840 /* TODO: Remove?
842 int
843 validate_arguments (uintmax_t w, uintmax_t c, double wp, double cp, double iwp, double icp, char *mypath)
845   if (w < 0 && c < 0 && wp < 0.0 && cp < 0.0) {
846     printf (_("INPUT ERROR: No thresholds specified"));
847     print_path (mypath);
848     return ERROR;
849   }
850   else if ((wp >= 0.0 || cp >= 0.0) &&
851            (wp < 0.0 || cp < 0.0 || wp > 100.0 || cp > 100.0 || cp > wp)) {
852     printf (_("\
853 INPUT ERROR: C_DFP (%f) should be less than W_DFP (%.1f) and both should be between zero and 100 percent, inclusive"),
854             cp, wp);
855     print_path (mypath);
856     return ERROR;
857   }
858   else if ((iwp >= 0.0 || icp >= 0.0) &&
859            (iwp < 0.0 || icp < 0.0 || iwp > 100.0 || icp > 100.0 || icp > iwp)) {
860     printf (_("\
861 INPUT ERROR: C_IDFP (%f) should be less than W_IDFP (%.1f) and both should be between zero and 100 percent, inclusive"),
862             icp, iwp);
863     print_path (mypath);
864     return ERROR;
865   }
866   else if ((w > 0 || c > 0) && (w == 0 || c == 0 || c > w)) {
867     printf (_("\
868 INPUT ERROR: C_DF (%lu) should be less than W_DF (%lu) and both should be greater than zero"),
869             (unsigned long)c, (unsigned long)w);
870     print_path (mypath);
871     return ERROR;
872   }
873   
874   return OK;
877 */
885 void
886 print_help (void)
888   print_revision (progname, revision);
890   printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
891   printf (COPYRIGHT, copyright, email);
893   printf ("%s\n", _("This plugin checks the amount of used disk space on a mounted file system"));
894   printf ("%s\n", _("and generates an alert if free space is less than one of the threshold values"));
896   printf ("\n\n");
898   print_usage ();
900   printf (_(UT_HELP_VRSN));
902   printf (" %s\n", "-w, --warning=INTEGER");
903   printf ("    %s\n", _("Exit with WARNING status if less than INTEGER units of disk are free"));
904   printf (" %s\n", "-w, --warning=PERCENT%");
905   printf ("    %s\n", _("Exit with WARNING status if less than PERCENT of disk space is free"));
906   printf (" %s\n", "-c, --critical=INTEGER");
907   printf ("    %s\n", _("Exit with CRITICAL status if less than INTEGER units of disk are free"));
908   printf (" %s\n", "-c, --critical=PERCENT%");
909   printf ("    %s\n", _("Exit with CRITCAL status if less than PERCENT of disk space is free"));
910   printf (" %s\n", "-W, --iwarning=PERCENT%");
911   printf ("    %s\n", _("Exit with WARNING status if less than PERCENT of inode space is free"));
912   printf (" %s\n", "-K, --icritical=PERCENT%");
913   printf ("    %s\n", _("Exit with CRITICAL status if less than PERCENT of inode space is free"));
914   printf (" %s\n", "-p, --path=PATH, --partition=PARTITION");
915   printf ("    %s\n", _("Path or partition (may be repeated)"));
916   printf (" %s\n", "-x, --exclude_device=PATH <STRING>");
917   printf ("    %s\n", _("Ignore device (only works if -p unspecified)"));
918   printf (" %s\n", "-C, --clear");
919   printf ("    %s\n", _("Clear thresholds"));
920   printf (" %s\n", "-E, --exact-match");
921   printf ("    %s\n", _("For paths or partitions specified with -p, only check for exact paths"));
922   printf (" %s\n", "-e, --errors-only");
923   printf ("    %s\n", _("Display only devices/mountpoints with errors"));
924   printf (" %s\n", "-g, --group=NAME");
925   printf ("    %s\n", _("Group pathes. Thresholds apply to (free-)space of all partitions together"));
926   printf (" %s\n", "-k, --kilobytes");
927   printf ("    %s\n", _("Same as '--units kB'"));
928   printf (" %s\n", "-l, --local");
929   printf ("    %s\n", _("Only check local filesystems"));
930   printf (" %s\n", "-L, --stat-remote-fs");
931   printf ("    %s\n", _("Only check local filesystems against thresholds. Yet call stat on remote filesystems"));
932   printf ("    %s\n", _("to test if they are accessible (e.g. to detect Stale NFS Handles)"));
933   printf (" %s\n", "-M, --mountpoint");
934   printf ("    %s\n", _("Display the mountpoint instead of the partition"));
935   printf (" %s\n", "-m, --megabytes");
936   printf ("    %s\n", _("Same as '--units MB'"));
937   printf (" %s\n", "-A, --all");
938   printf ("    %s\n", _("Explicitly select all pathes. This is equivalent to -R '.*'"));
939   printf (" %s\n", "-R, --eregi-path=PATH, --eregi-partition=PARTITION");
940   printf ("    %s\n", _("Case insensitive regular expression for path/partition (may be repeated)"));
941   printf (" %s\n", "-r, --ereg-path=PATH, --ereg-partition=PARTITION");
942   printf ("    %s\n", _("Regular expression for path or partition (may be repeated)"));
943   printf (" %s\n", "-I, --ignore-eregi-path=PATH, --ignore-eregi-partition=PARTITION");
944   printf ("    %s\n", _("Regular expression to ignore selected path/partition (case insensitive) (may be repeated)"));
945   printf (" %s\n", "-i, --ignore-ereg-path=PATH, --ignore-ereg-partition=PARTITION");
946   printf ("    %s\n", _("Regular expression to ignore selected path or partition (may be repeated)"));
947   printf (_(UT_TIMEOUT), DEFAULT_SOCKET_TIMEOUT);
948   printf (" %s\n", "-u, --units=STRING");
949   printf ("    %s\n", _("Choose bytes, kB, MB, GB, TB (default: MB)"));
950   printf (_(UT_VERBOSE));
951   printf (" %s\n", "-X, --exclude-type=TYPE");
952   printf ("    %s\n", _("Ignore all filesystems of indicated type (may be repeated)"));
953   printf ("\n");
954   printf ("%s\n", _("Examples:"));
955   printf (" %s\n", "check_disk -w 10% -c 5% -p /tmp -p /var -C -w 100000 -c 50000 -p /");
956   printf ("    %s\n", _("Checks /tmp and /var at 10% and 5%, and / at 100MB and 50MB"));
957   printf (" %s\n", "check_disk -w 100M -c 50M -C -w 1000M -c 500M -g sidDATA -r '^/oracle/SID/data.*$'");
958   printf ("    %s\n", _("Checks all filesystems not matching -r at 100M and 50M. The fs matching the -r regex"));
959   printf ("    %s\n", _("are grouped which means the freespace thresholds are applied to all disks together"));
960   printf (" %s\n", "check_disk -w 100M -c 50M -C -w 1000M -c 500M -p /foo -C -w 5% -c 3% -p /bar");
961   printf ("    %s\n", _("Checks /foo for 1000M/500M and /bar for 5/3%. All remaining volumes use 100M/50M"));
962   printf (_(UT_SUPPORT));
967 void
968 print_usage (void)
970   printf (_("Usage:"));
971   printf (" %s -w limit -c limit [-W limit] [-K limit] {-p path | -x device}\n", progname);
972   printf ("[-C] [-E] [-e] [-g group ] [-k] [-l] [-M] [-m] [-R path ] [-r path ]\n");
973   printf ("[-t timeout] [-u unit] [-v] [-X type]\n");
976 void
977 stat_path (struct parameter_list *p)
979   /* Stat entry to check that dir exists and is accessible */
980   if (verbose > 3)
981     printf("calling stat on %s\n", p->name);
982   if (stat (p->name, &stat_buf[0])) {
983     if (verbose > 3)
984       printf("stat failed on %s\n", p->name);
985     printf("DISK %s - ", _("CRITICAL"));
986     die (STATE_CRITICAL, _("%s %s: %s\n"), p->name, _("is not accessible"), strerror(errno));
987   }