Code

Bulk EOL cleanup
[nagiosplug.git] / plugins / check_disk.c
1 /*****************************************************************************
2
3 * Nagios check_disk plugin
4
5 * License: GPL
6 * Copyright (c) 1999-2008 Nagios Plugins Development Team
7
8 * Last Modified: $Date$
9
10 * Description:
11
12 * This file contains the check_disk plugin
13
14
15 * This program is free software: you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation, either version 3 of the License, or
18 * (at your option) any later version.
19
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23 * GNU General Public License for more details.
24
25 * You should have received a copy of the GNU General Public License
26 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
27
28 * $Id$
29
30 *****************************************************************************/
32 const char *progname = "check_disk";
33 const char *program_name = "check_disk";  /* Required for coreutils libs */
34 const char *revision = "$Revision$";
35 const char *copyright = "1999-2008";
36 const char *email = "nagiosplug-devel@lists.sourceforge.net";
39 #include "common.h"
40 #ifdef HAVE_SYS_STAT_H
41 # include <sys/stat.h>
42 #endif
43 #if HAVE_INTTYPES_H
44 # include <inttypes.h>
45 #endif
46 #include <assert.h>
47 #include "popen.h"
48 #include "utils.h"
49 #include "utils_disk.h"
50 #include <stdarg.h>
51 #include "fsusage.h"
52 #include "mountlist.h"
53 #include "intprops.h"   /* necessary for TYPE_MAXIMUM */
54 #if HAVE_LIMITS_H
55 # include <limits.h>
56 #endif
57 #include "regex.h"
60 /* If nonzero, show inode information. */
61 static int inode_format = 1;
63 /* If nonzero, show even filesystems with zero size or
64    uninteresting types. */
65 static int show_all_fs = 1;
67 /* If nonzero, show only local filesystems.  */
68 static int show_local_fs = 0;
70 /* If nonzero, show only local filesystems but call stat() on remote ones. */
71 static int stat_remote_fs = 0;
73 /* If positive, the units to use when printing sizes;
74    if negative, the human-readable base.  */
75 /* static int output_block_size; */
77 /* If nonzero, invoke the `sync' system call before getting any usage data.
78    Using this option can make df very slow, especially with many or very
79    busy disks.  Note that this may make a difference on some systems --
80    SunOs4.1.3, for one.  It is *not* necessary on Linux.  */
81 /* static int require_sync = 0; */
83 /* Linked list of filesystem types to display.
84    If `fs_select_list' is NULL, list all types.
85    This table is generated dynamically from command-line options,
86    rather than hardcoding into the program what it thinks are the
87    valid filesystem types; let the user specify any filesystem type
88    they want to, and if there are any filesystems of that type, they
89    will be shown.
91    Some filesystem types:
92    4.2 4.3 ufs nfs swap ignore io vm efs dbg */
94 /* static struct parameter_list *fs_select_list; */
96 /* Linked list of filesystem types to omit.
97    If the list is empty, don't exclude any types.  */
99 static struct name_list *fs_exclude_list;
101 static struct name_list *dp_exclude_list;
103 static struct parameter_list *path_select_list = NULL;
105 /* Linked list of mounted filesystems. */
106 static struct mount_entry *mount_list;
108 /* For long options that have no equivalent short option, use a
109    non-character as a pseudo short option, starting with CHAR_MAX + 1.  */
110 enum
112   SYNC_OPTION = CHAR_MAX + 1,
113   NO_SYNC_OPTION,
114   BLOCK_SIZE_OPTION
115 };
117 #ifdef _AIX
118  #pragma alloca
119 #endif
121 int process_arguments (int, char **);
122 void print_path (const char *mypath);
123 void set_all_thresholds (struct parameter_list *path);
124 int validate_arguments (uintmax_t, uintmax_t, double, double, double, double, char *);
125 void print_help (void);
126 void print_usage (void);
127 double calculate_percent(uintmax_t, uintmax_t);
128 void stat_path (struct parameter_list *p);
130 double w_dfp = -1.0;
131 double c_dfp = -1.0;
132 char *path;
133 char *exclude_device;
134 char *units;
135 uintmax_t mult = 1024 * 1024;
136 int verbose = 0;
137 int erronly = FALSE;
138 int display_mntp = FALSE;
139 int exact_match = FALSE;
140 char *warn_freespace_units = NULL;
141 char *crit_freespace_units = NULL;
142 char *warn_freespace_percent = NULL;
143 char *crit_freespace_percent = NULL;
144 char *warn_usedspace_units = NULL;
145 char *crit_usedspace_units = NULL;
146 char *warn_usedspace_percent = NULL;
147 char *crit_usedspace_percent = NULL;
148 char *warn_usedinodes_percent = NULL;
149 char *crit_usedinodes_percent = NULL;
150 char *warn_freeinodes_percent = NULL;
151 char *crit_freeinodes_percent = NULL;
152 int path_selected = FALSE;
153 char *group = NULL;
154 struct stat *stat_buf;
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 ("");
184   stat_buf = malloc(sizeof *stat_buf);
186   setlocale (LC_ALL, "");
187   bindtextdomain (PACKAGE, LOCALEDIR);
188   textdomain (PACKAGE);
190   mount_list = read_file_system_list (0);
192   /* Parse extra opts if any */
193   argv = np_extra_opts (&argc, argv, progname);
195   if (process_arguments (argc, argv) == ERROR)
196     usage4 (_("Could not parse arguments"));
198   /* If a list of paths has not been selected, find entire
199      mount list and create list of paths
200    */
201   if (path_selected == FALSE) {
202     for (me = mount_list; me; me = me->me_next) {
203       if (! (path = np_find_parameter(path_select_list, me->me_mountdir))) {
204         path = np_add_parameter(&path_select_list, me->me_mountdir);
205       }
206       path->best_match = me;
207       path->group = group;
208       set_all_thresholds(path);
209     }
210   }
211   np_set_best_match(path_select_list, mount_list, exact_match);
213   /* Error if no match found for specified paths */
214   temp_list = path_select_list;
216   while (temp_list) {
217     if (! temp_list->best_match) {
218       die (STATE_CRITICAL, _("DISK %s: %s not found\n"), _("CRITICAL"), temp_list->name);
219     }
221     temp_list = temp_list->name_next;
222   }
224   /* Process for every path in list */
225   for (path = path_select_list; path; path=path->name_next) {
227     if (verbose >= 3 && path->freespace_percent->warning != NULL && path->freespace_percent->critical != NULL)
228       printf("Thresholds(pct) for %s warn: %f crit %f\n",path->name, path->freespace_percent->warning->end,
229                                                          path->freespace_percent->critical->end);
231     if (verbose >= 3 && path->group != NULL)
232       printf("Group of %s: %s\n",path->name,path->group);
234     /* reset disk result */
235     disk_result = STATE_UNKNOWN;
237     me = path->best_match;
239     /* Filters */
241     /* Remove filesystems already seen */
242     if (np_seen_name(seen, me->me_mountdir)) {
243       continue;
244     } else {
245       if (path->group != NULL) {
246         /* find all group members */
247         fsp.fsu_blocksize = 0;
248         fsp.fsu_blocks    = 0;
249         fsp.fsu_bfree     = 0;
250         fsp.fsu_bavail    = 0;
251         fsp.fsu_files     = 0;
252         fsp.fsu_ffree     = 0;
255         for (temp_list = path_select_list; temp_list; temp_list=temp_list->name_next) {
256           if (temp_list->group && ! (strcmp(temp_list->group, path->group))) {
258             stat_path(path);
259             get_fs_usage (temp_list->best_match->me_mountdir, temp_list->best_match->me_devname, &tmpfsp);
261             /* possibly differing blocksizes if disks are grouped. Calculating average */
262             fsp.fsu_blocksize = (fsp.fsu_blocksize * fsp.fsu_blocks + tmpfsp.fsu_blocksize * tmpfsp.fsu_blocks) / \
263                                 (fsp.fsu_blocks + tmpfsp.fsu_blocks);  /* Size of a block.  */
264             fsp.fsu_blocks    += tmpfsp.fsu_blocks;     /* Total blocks. */
265             fsp.fsu_bfree     += tmpfsp.fsu_bfree;      /* Free blocks available to superuser. */
266             /* Gnulib workaround - see comment about it a few lines below */
267             fsp.fsu_bavail    += (tmpfsp.fsu_bavail > tmpfsp.fsu_bfree ? 0 : tmpfsp.fsu_bavail); /* Free blocks available to non-superuser. */
268             fsp.fsu_files     += tmpfsp.fsu_files;      /* Total file nodes. */
269             fsp.fsu_ffree     += tmpfsp.fsu_ffree;      /* Free file nodes. */
271             if (verbose >= 3)
272               printf("Group %s: add %llu blocks (%s) \n", path->group, tmpfsp.fsu_bavail, temp_list->name);
273              /* printf("Group %s: add %u blocks (%s)\n", temp_list->name); *//* path->group, tmpfsp.fsu_bavail, temp_list->name); */
275             np_add_name(&seen, temp_list->best_match->me_mountdir);
276           }
277         }
278         /* modify devname and mountdir for output */
279         me->me_mountdir = me->me_devname = path->group;
280       } else
281         np_add_name(&seen, me->me_mountdir);
282     }
284     if (path->group == NULL) {
285       /* Skip remote filesystems if we're not interested in them */
286       if (me->me_remote && show_local_fs) {
287         if (stat_remote_fs)
288           stat_path(path);
289         continue;
290       /* Skip pseudo fs's if we haven't asked for all fs's */
291       } else if (me->me_dummy && !show_all_fs) {
292         continue;
293       /* Skip excluded fstypes */
294       } else if (fs_exclude_list && np_find_name (fs_exclude_list, me->me_type)) {
295         continue;
296       /* Skip excluded fs's */
297       } else if (dp_exclude_list &&
298                (np_find_name (dp_exclude_list, me->me_devname) ||
299                 np_find_name (dp_exclude_list, me->me_mountdir))) {
300         continue;
301       }
303       stat_path(path);
304       get_fs_usage (me->me_mountdir, me->me_devname, &fsp);
305     }
307     if (fsp.fsu_blocks && strcmp ("none", me->me_mountdir)) {
308       total = fsp.fsu_blocks;
309       /* 2007-12-08 - Workaround for Gnulib reporting insanely high available
310        * space on BSD (the actual value should be negative but fsp.fsu_bavail
311        * is unsigned) */
312       available = fsp.fsu_bavail > fsp.fsu_bfree ? 0 : fsp.fsu_bavail;
313       available_to_root = fsp.fsu_bfree;
314       used = total - available_to_root;
316       if (verbose >= 3)
317         printf ("For %s, total=%llu, available=%llu, available_to_root=%llu, used=%llu, fsp.fsu_files=%llu, fsp.fsu_ffree=%llu\n",
318         me->me_mountdir, total, available, available_to_root, used, fsp.fsu_files, fsp.fsu_ffree);
320       dused_pct = calculate_percent( used, used + available );  /* used + available can never be > uintmax */
322       dfree_pct = 100 - dused_pct;
323       dused_units = used*fsp.fsu_blocksize/mult;
324       dfree_units = available*fsp.fsu_blocksize/mult;
325       dtotal_units = total*fsp.fsu_blocksize/mult;
326       dused_inodes_percent = calculate_percent(fsp.fsu_files - fsp.fsu_ffree, fsp.fsu_files);
327       dfree_inodes_percent = 100 - dused_inodes_percent;
329       if (verbose >= 3) {
330         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",
331           me->me_mountdir, dused_pct, dfree_pct, dused_units, dfree_units, dtotal_units, dused_inodes_percent, dfree_inodes_percent, fsp.fsu_blocksize, mult);
332       }
334       /* Threshold comparisons */
336       temp_result = get_status(dfree_units, path->freespace_units);
337       if (verbose >=3) printf("Freespace_units result=%d\n", temp_result);
338       disk_result = max_state( disk_result, temp_result );
340       temp_result = get_status(dfree_pct, path->freespace_percent);
341       if (verbose >=3) printf("Freespace%% result=%d\n", temp_result);
342       disk_result = max_state( disk_result, temp_result );
344       temp_result = get_status(dused_units, path->usedspace_units);
345       if (verbose >=3) printf("Usedspace_units result=%d\n", temp_result);
346       disk_result = max_state( disk_result, temp_result );
348       temp_result = get_status(dused_pct, path->usedspace_percent);
349       if (verbose >=3) printf("Usedspace_percent result=%d\n", temp_result);
350       disk_result = max_state( disk_result, temp_result );
352       temp_result = get_status(dused_inodes_percent, path->usedinodes_percent);
353       if (verbose >=3) printf("Usedinodes_percent result=%d\n", temp_result);
354       disk_result = max_state( disk_result, temp_result );
356       temp_result = get_status(dfree_inodes_percent, path->freeinodes_percent);
357       if (verbose >=3) printf("Freeinodes_percent result=%d\n", temp_result);
358       disk_result = max_state( disk_result, temp_result );
360       result = max_state(result, disk_result);
362       /* What a mess of units. The output shows free space, the perf data shows used space. Yikes!
363          Hack here. Trying to get warn/crit levels from freespace_(units|percent) for perf
364          data. Assumption that start=0. Roll on new syntax...
365       */
367       /* *_high_tide must be reinitialized at each run */
368       warning_high_tide = UINT_MAX;
369       critical_high_tide = UINT_MAX;
371       if (path->freespace_units->warning != NULL) {
372         warning_high_tide = dtotal_units - path->freespace_units->warning->end;
373       }
374       if (path->freespace_percent->warning != NULL) {
375         warning_high_tide = abs( min( (double) warning_high_tide, (double) (1.0 - path->freespace_percent->warning->end/100)*dtotal_units ));
376       }
377       if (path->freespace_units->critical != NULL) {
378         critical_high_tide = dtotal_units - path->freespace_units->critical->end;
379       }
380       if (path->freespace_percent->critical != NULL) {
381         critical_high_tide = abs( min( (double) critical_high_tide, (double) (1.0 - path->freespace_percent->critical->end/100)*dtotal_units ));
382       }
384       /* Nb: *_high_tide are unset when == UINT_MAX */
385       asprintf (&perf, "%s %s", perf,
386                 perfdata ((!strcmp(me->me_mountdir, "none") || display_mntp) ? me->me_devname : me->me_mountdir,
387                           dused_units, units,
388                           (warning_high_tide != UINT_MAX ? TRUE : FALSE), warning_high_tide,
389                           (critical_high_tide != UINT_MAX ? TRUE : FALSE), critical_high_tide,
390                           TRUE, 0,
391                           TRUE, dtotal_units));
393       if (disk_result==STATE_OK && erronly && !verbose)
394         continue;
396       asprintf (&output, "%s %s %.0f %s (%.0f%%",
397                 output,
398                 (!strcmp(me->me_mountdir, "none") || display_mntp) ? me->me_devname : me->me_mountdir,
399                 dfree_units,
400                 units,
401                 dfree_pct);
402       if (dused_inodes_percent < 0) {
403         asprintf(&output, "%s inode=-);", output);
404       } else {
405         asprintf(&output, "%s inode=%.0f%%);", output, dfree_inodes_percent );
406       }
408       /* TODO: Need to do a similar debug line
409       asprintf (&details, _("%s\n\
410 %.0f of %.0f %s (%.0f%% inode=%.0f%%) free on %s (type %s mounted on %s) warn:%lu crit:%lu warn%%:%.0f%% crit%%:%.0f%%"),
411                 details, dfree_units, dtotal_units, units, dfree_pct, inode_space_pct,
412                 me->me_devname, me->me_type, me->me_mountdir,
413                 (unsigned long)w_df, (unsigned long)c_df, w_dfp, c_dfp);
414       */
416     }
418   }
420   if (verbose >= 2)
421     asprintf (&output, "%s%s", output, details);
424   printf ("DISK %s%s%s|%s\n", state_text (result), (erronly && result==STATE_OK) ? "" : preamble, output, perf);
425   return result;
429 double calculate_percent(uintmax_t value, uintmax_t total) {
430   double pct = -1;
431   /* I don't understand the below, but it is taken from coreutils' df */
432   /* Seems to be calculating pct, in the best possible way */
433   if (value <= TYPE_MAXIMUM(uintmax_t) / 100
434     && total != 0) {
435     uintmax_t u100 = value * 100;
436     pct = u100 / total + (u100 % total != 0);
437   } else {
438     /* Possible rounding errors - see coreutils' df for more explanation */
439     double u = value;
440     double t = total;
441     if (t) {
442       long int lipct = pct = u * 100 / t;
443       double ipct = lipct;
445       /* Like 'pct = ceil (dpct);', but without ceil - from coreutils again */
446       if (ipct - 1 < pct && pct <= ipct + 1)
447         pct = ipct + (ipct < pct);
448     }
449   }
450   return pct;
453 /* process command-line arguments */
454 int
455 process_arguments (int argc, char **argv)
457   int c, err;
458   struct parameter_list *se;
459   struct parameter_list *temp_list = NULL, *previous = NULL;
460   struct parameter_list *temp_path_select_list = NULL;
461   struct mount_entry *me, *temp_me;
462   int result = OK;
463   regex_t re;
464   int cflags = REG_NOSUB | REG_EXTENDED;
465   int default_cflags = cflags;
466   char errbuf[MAX_INPUT_BUFFER];
467   int fnd = 0;
469   int option = 0;
470   static struct option longopts[] = {
471     {"timeout", required_argument, 0, 't'},
472     {"warning", required_argument, 0, 'w'},
473     {"critical", required_argument, 0, 'c'},
474     {"iwarning", required_argument, 0, 'W'},
475     /* Dang, -C is taken. We might want to reshuffle this. */
476     {"icritical", required_argument, 0, 'K'},
477     {"kilobytes", no_argument, 0, 'k'},
478     {"megabytes", no_argument, 0, 'm'},
479     {"units", required_argument, 0, 'u'},
480     {"path", required_argument, 0, 'p'},
481     {"partition", required_argument, 0, 'p'},
482     {"exclude_device", required_argument, 0, 'x'},
483     {"exclude-type", required_argument, 0, 'X'},
484     {"group", required_argument, 0, 'g'},
485     {"eregi-path", required_argument, 0, 'R'},
486     {"eregi-partition", required_argument, 0, 'R'},
487     {"ereg-path", required_argument, 0, 'r'},
488     {"ereg-partition", required_argument, 0, 'r'},
489     {"ignore-ereg-path", required_argument, 0, 'i'},
490     {"ignore-ereg-partition", required_argument, 0, 'i'},
491     {"ignore-eregi-path", required_argument, 0, 'I'},
492     {"ignore-eregi-partition", required_argument, 0, 'I'},
493     {"local", no_argument, 0, 'l'},
494     {"stat-remote-fs", no_argument, 0, 'L'},
495     {"mountpoint", no_argument, 0, 'M'},
496     {"errors-only", no_argument, 0, 'e'},
497     {"exact-match", no_argument, 0, 'E'},
498     {"all", no_argument, 0, 'A'},
499     {"verbose", no_argument, 0, 'v'},
500     {"quiet", no_argument, 0, 'q'},
501     {"clear", no_argument, 0, 'C'},
502     {"version", no_argument, 0, 'V'},
503     {"help", no_argument, 0, 'h'},
504     {0, 0, 0, 0}
505   };
507   if (argc < 2)
508     return ERROR;
510   np_add_name(&fs_exclude_list, "iso9660");
512   for (c = 1; c < argc; c++)
513     if (strcmp ("-to", argv[c]) == 0)
514       strcpy (argv[c], "-t");
516   while (1) {
517     c = getopt_long (argc, argv, "+?VqhveCt:c:w:K:W:u:p:x:X:mklLg:R:r:i:I:MEA", longopts, &option);
519     if (c == -1 || c == EOF)
520       break;
522     switch (c) {
523     case 't':                 /* timeout period */
524       if (is_integer (optarg)) {
525         timeout_interval = atoi (optarg);
526         break;
527       }
528       else {
529         usage2 (_("Timeout interval must be a positive integer"), optarg);
530       }
532     /* See comments for 'c' */
533     case 'w':                 /* warning threshold */
534       if (strstr(optarg, "%")) {
535         if (*optarg == '@') {
536           warn_freespace_percent = optarg;
537         } else {
538           asprintf(&warn_freespace_percent, "@%s", optarg);
539         }
540       } else {
541         if (*optarg == '@') {
542           warn_freespace_units = optarg;
543         } else {
544           asprintf(&warn_freespace_units, "@%s", optarg);
545         }
546       }
547       break;
549     /* Awful mistake where the range values do not make sense. Normally,
550        you alert if the value is within the range, but since we are using
551        freespace, we have to alert if outside the range. Thus we artifically
552        force @ at the beginning of the range, so that it is backwards compatible
553     */
554     case 'c':                 /* critical threshold */
555       if (strstr(optarg, "%")) {
556         if (*optarg == '@') {
557           crit_freespace_percent = optarg;
558         } else {
559           asprintf(&crit_freespace_percent, "@%s", optarg);
560         }
561       } else {
562         if (*optarg == '@') {
563           crit_freespace_units = optarg;
564         } else {
565           asprintf(&crit_freespace_units, "@%s", optarg);
566         }
567       }
568       break;
570     case 'W':                   /* warning inode threshold */
571       if (*optarg == '@') {
572         warn_freeinodes_percent = optarg;
573       } else {
574         asprintf(&warn_freeinodes_percent, "@%s", optarg);
575       }
576       break;
577     case 'K':                   /* critical inode threshold */
578       if (*optarg == '@') {
579         crit_freeinodes_percent = optarg;
580       } else {
581         asprintf(&crit_freeinodes_percent, "@%s", optarg);
582       }
583       break;
584     case 'u':
585       if (units)
586         free(units);
587       if (! strcmp (optarg, "bytes")) {
588         mult = (uintmax_t)1;
589         units = strdup ("B");
590       } else if (! strcmp (optarg, "kB")) {
591         mult = (uintmax_t)1024;
592         units = strdup ("kB");
593       } else if (! strcmp (optarg, "MB")) {
594         mult = (uintmax_t)1024 * 1024;
595         units = strdup ("MB");
596       } else if (! strcmp (optarg, "GB")) {
597         mult = (uintmax_t)1024 * 1024 * 1024;
598         units = strdup ("GB");
599       } else if (! strcmp (optarg, "TB")) {
600         mult = (uintmax_t)1024 * 1024 * 1024 * 1024;
601         units = strdup ("TB");
602       } else {
603         die (STATE_UNKNOWN, _("unit type %s not known\n"), optarg);
604       }
605       if (units == NULL)
606         die (STATE_UNKNOWN, _("failed allocating storage for '%s'\n"), "units");
607       break;
608     case 'k': /* display mountpoint */
609       mult = 1024;
610       if (units)
611         free(units);
612       units = strdup ("kB");
613       break;
614     case 'm': /* display mountpoint */
615       mult = 1024 * 1024;
616       if (units)
617         free(units);
618       units = strdup ("MB");
619       break;
620     case 'L':
621       stat_remote_fs = 1;
622     case 'l':
623       show_local_fs = 1;
624       break;
625     case 'p':                 /* select path */
626       if (! (warn_freespace_units || crit_freespace_units || warn_freespace_percent ||
627              crit_freespace_percent || warn_usedspace_units || crit_usedspace_units ||
628              warn_usedspace_percent || crit_usedspace_percent || warn_usedinodes_percent ||
629              crit_usedinodes_percent || warn_freeinodes_percent || crit_freeinodes_percent )) {
630         die (STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set a threshold value before using -p\n"));
631       }
633       /* add parameter if not found. overwrite thresholds if path has already been added  */
634       if (! (se = np_find_parameter(path_select_list, optarg))) {
635           se = np_add_parameter(&path_select_list, optarg);
636       }
637       se->group = group;
638       set_all_thresholds(se);
640       /* With autofs, it is required to stat() the path before populating the mount_list */
641       stat_path(se);
642       mount_list = read_file_system_list (0);
643       np_set_best_match(se, mount_list, exact_match);
645       path_selected = TRUE;
646       break;
647     case 'x':                 /* exclude path or partition */
648       np_add_name(&dp_exclude_list, optarg);
649       break;
650     case 'X':                 /* exclude file system type */
651       np_add_name(&fs_exclude_list, optarg);
652       break;
653     case 'v':                 /* verbose */
654       verbose++;
655       break;
656     case 'q':                 /* TODO: this function should eventually go away (removed 2007-09-20) */
657       /* verbose--; **replaced by line below**. -q was only a broken way of implementing -e */
658       erronly = TRUE;
659       break;
660     case 'e':
661       erronly = TRUE;
662       break;
663     case 'E':
664       if (path_selected)
665         die (STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set -E before selecting pathes\n"));
666       exact_match = TRUE;
667       break;
668     case 'g':
669       if (path_selected)
670         die (STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set group value before selecting pathes \n"));
671       group = optarg;
672       break;
673     case 'I':
674       cflags |= REG_ICASE;
675     case 'i':
676       if (!path_selected)
677         die (STATE_UNKNOWN, "DISK %s: %s\n", _("UNKNOWN"), _("Pathes need to be selected before using -i/-I. Use -A to select all pathes explicitly"));
678       err = regcomp(&re, optarg, cflags);
679       if (err != 0) {
680         regerror (err, &re, errbuf, MAX_INPUT_BUFFER);
681         die (STATE_UNKNOWN, "DISK %s: %s - %s\n",_("UNKNOWN"), _("Could not compile regular expression"), errbuf);
682       }
684       temp_list = path_select_list;
686       previous = NULL;
687       while (temp_list) {
688         if (temp_list->best_match) {
689           if (np_regex_match_mount_entry(temp_list->best_match, &re)) {
691               if (verbose >=3)
692                 printf("ignoring %s matching regex\n", temp_list->name);
694               temp_list = np_del_parameter(temp_list, previous);
695               /* pointer to first element needs to be updated if first item gets deleted */
696               if (previous == NULL)
697                 path_select_list = temp_list;
698           } else {
699             previous = temp_list;
700             temp_list = temp_list->name_next;
701           }
702         } else {
703           previous = temp_list;
704           temp_list = temp_list->name_next;
705         }
706       }
709       cflags = default_cflags;
710       break;
712     case 'A':
713       optarg = strdup(".*");
714     case 'R':
715       cflags |= REG_ICASE;
716     case 'r':
717       if (! (warn_freespace_units || crit_freespace_units || warn_freespace_percent ||
718              crit_freespace_percent || warn_usedspace_units || crit_usedspace_units ||
719              warn_usedspace_percent || crit_usedspace_percent || warn_usedinodes_percent ||
720              crit_usedinodes_percent || warn_freeinodes_percent || crit_freeinodes_percent )) {
721         die (STATE_UNKNOWN, "DISK %s: %s", _("UNKNOWN"), _("Must set a threshold value before using -r/-R\n"));
722       }
724       err = regcomp(&re, optarg, cflags);
725       if (err != 0) {
726         regerror (err, &re, errbuf, MAX_INPUT_BUFFER);
727         die (STATE_UNKNOWN, "DISK %s: %s - %s\n",_("UNKNOWN"), _("Could not compile regular expression"), errbuf);
728       }
730       for (me = mount_list; me; me = me->me_next) {
731         if (np_regex_match_mount_entry(me, &re)) {
732           fnd = TRUE;
733           if (verbose >= 3)
734             printf("%s %s matching expression %s\n", me->me_devname, me->me_mountdir, optarg);
736           /* add parameter if not found. overwrite thresholds if path has already been added  */
737           if (! (se = np_find_parameter(path_select_list, me->me_mountdir))) {
738             se = np_add_parameter(&path_select_list, me->me_mountdir);
739           }
740           se->group = group;
741           set_all_thresholds(se);
742         }
743       }
745       if (!fnd)
746         die (STATE_UNKNOWN, "DISK %s: %s - %s\n",_("UNKNOWN"),
747             _("Regular expression did not match any path or disk"), optarg);
749       fnd = FALSE;
750       path_selected = TRUE;
751       np_set_best_match(path_select_list, mount_list, exact_match);
752       cflags = default_cflags;
754       break;
755     case 'M': /* display mountpoint */
756       display_mntp = TRUE;
757       break;
758     case 'C':
759        /* add all mount entries to path_select list if no partitions have been explicitly defined using -p */
760        if (path_selected == FALSE) {
761          struct parameter_list *path;
762          for (me = mount_list; me; me = me->me_next) {
763            if (! (path = np_find_parameter(path_select_list, me->me_mountdir)))
764              path = np_add_parameter(&path_select_list, me->me_mountdir);
765            path->best_match = me;
766            path->group = group;
767            set_all_thresholds(path);
768          }
769       }
770       warn_freespace_units = NULL;
771       crit_freespace_units = NULL;
772       warn_usedspace_units = NULL;
773       crit_usedspace_units = NULL;
774       warn_freespace_percent = NULL;
775       crit_freespace_percent = NULL;
776       warn_usedspace_percent = NULL;
777       crit_usedspace_percent = NULL;
778       warn_usedinodes_percent = NULL;
779       crit_usedinodes_percent = NULL;
780       warn_freeinodes_percent = NULL;
781       crit_freeinodes_percent = NULL;
783       path_selected = FALSE;
784       group = NULL;
785       break;
786     case 'V':                 /* version */
787       print_revision (progname, revision);
788       exit (STATE_OK);
789     case 'h':                 /* help */
790       print_help ();
791       exit (STATE_OK);
792     case '?':                 /* help */
793       usage (_("Unknown argument"));
794     }
795   }
797   /* Support for "check_disk warn crit [fs]" with thresholds at used% level */
798   c = optind;
799   if (warn_usedspace_percent == NULL && argc > c && is_intnonneg (argv[c]))
800     warn_usedspace_percent = argv[c++];
802   if (crit_usedspace_percent == NULL && argc > c && is_intnonneg (argv[c]))
803     crit_usedspace_percent = argv[c++];
805   if (argc > c && path == NULL) {
806     se = np_add_parameter(&path_select_list, strdup(argv[c++]));
807     path_selected = TRUE;
808     set_all_thresholds(se);
809   }
811   if (units == NULL) {
812     units = strdup ("MB");
813     mult = (uintmax_t)1024 * 1024;
814   }
816   return TRUE;
821 void
822 print_path (const char *mypath)
824   if (mypath == NULL)
825     printf ("\n");
826   else
827     printf (_(" for %s\n"), mypath);
831 void
832 set_all_thresholds (struct parameter_list *path)
834     if (path->freespace_units != NULL) free(path->freespace_units);
835     set_thresholds(&path->freespace_units, warn_freespace_units, crit_freespace_units);
836     if (path->freespace_percent != NULL) free (path->freespace_percent);
837     set_thresholds(&path->freespace_percent, warn_freespace_percent, crit_freespace_percent);
838     if (path->usedspace_units != NULL) free (path->usedspace_units);
839     set_thresholds(&path->usedspace_units, warn_usedspace_units, crit_usedspace_units);
840     if (path->usedspace_percent != NULL) free (path->usedspace_percent);
841     set_thresholds(&path->usedspace_percent, warn_usedspace_percent, crit_usedspace_percent);
842     if (path->usedinodes_percent != NULL) free (path->usedinodes_percent);
843     set_thresholds(&path->usedinodes_percent, warn_usedinodes_percent, crit_usedinodes_percent);
844     if (path->freeinodes_percent != NULL) free (path->freeinodes_percent);
845     set_thresholds(&path->freeinodes_percent, warn_freeinodes_percent, crit_freeinodes_percent);
848 /* TODO: Remove?
850 int
851 validate_arguments (uintmax_t w, uintmax_t c, double wp, double cp, double iwp, double icp, char *mypath)
853   if (w < 0 && c < 0 && wp < 0.0 && cp < 0.0) {
854     printf (_("INPUT ERROR: No thresholds specified"));
855     print_path (mypath);
856     return ERROR;
857   }
858   else if ((wp >= 0.0 || cp >= 0.0) &&
859            (wp < 0.0 || cp < 0.0 || wp > 100.0 || cp > 100.0 || cp > wp)) {
860     printf (_("\
861 INPUT ERROR: C_DFP (%f) should be less than W_DFP (%.1f) and both should be between zero and 100 percent, inclusive"),
862             cp, wp);
863     print_path (mypath);
864     return ERROR;
865   }
866   else if ((iwp >= 0.0 || icp >= 0.0) &&
867            (iwp < 0.0 || icp < 0.0 || iwp > 100.0 || icp > 100.0 || icp > iwp)) {
868     printf (_("\
869 INPUT ERROR: C_IDFP (%f) should be less than W_IDFP (%.1f) and both should be between zero and 100 percent, inclusive"),
870             icp, iwp);
871     print_path (mypath);
872     return ERROR;
873   }
874   else if ((w > 0 || c > 0) && (w == 0 || c == 0 || c > w)) {
875     printf (_("\
876 INPUT ERROR: C_DF (%lu) should be less than W_DF (%lu) and both should be greater than zero"),
877             (unsigned long)c, (unsigned long)w);
878     print_path (mypath);
879     return ERROR;
880   }
882   return OK;
885 */
893 void
894 print_help (void)
896   print_revision (progname, revision);
898   printf ("Copyright (c) 1999 Ethan Galstad <nagios@nagios.org>\n");
899   printf (COPYRIGHT, copyright, email);
901   printf ("%s\n", _("This plugin checks the amount of used disk space on a mounted file system"));
902   printf ("%s\n", _("and generates an alert if free space is less than one of the threshold values"));
904   printf ("\n\n");
906   print_usage ();
908   printf (_(UT_HELP_VRSN));
909   printf (_(UT_EXTRA_OPTS));
911   printf (" %s\n", "-w, --warning=INTEGER");
912   printf ("    %s\n", _("Exit with WARNING status if less than INTEGER units of disk are free"));
913   printf (" %s\n", "-w, --warning=PERCENT%");
914   printf ("    %s\n", _("Exit with WARNING status if less than PERCENT of disk space is free"));
915   printf (" %s\n", "-c, --critical=INTEGER");
916   printf ("    %s\n", _("Exit with CRITICAL status if less than INTEGER units of disk are free"));
917   printf (" %s\n", "-c, --critical=PERCENT%");
918   printf ("    %s\n", _("Exit with CRITCAL status if less than PERCENT of disk space is free"));
919   printf (" %s\n", "-W, --iwarning=PERCENT%");
920   printf ("    %s\n", _("Exit with WARNING status if less than PERCENT of inode space is free"));
921   printf (" %s\n", "-K, --icritical=PERCENT%");
922   printf ("    %s\n", _("Exit with CRITICAL status if less than PERCENT of inode space is free"));
923   printf (" %s\n", "-p, --path=PATH, --partition=PARTITION");
924   printf ("    %s\n", _("Path or partition (may be repeated)"));
925   printf (" %s\n", "-x, --exclude_device=PATH <STRING>");
926   printf ("    %s\n", _("Ignore device (only works if -p unspecified)"));
927   printf (" %s\n", "-C, --clear");
928   printf ("    %s\n", _("Clear thresholds"));
929   printf (" %s\n", "-E, --exact-match");
930   printf ("    %s\n", _("For paths or partitions specified with -p, only check for exact paths"));
931   printf (" %s\n", "-e, --errors-only");
932   printf ("    %s\n", _("Display only devices/mountpoints with errors"));
933   printf (" %s\n", "-g, --group=NAME");
934   printf ("    %s\n", _("Group pathes. Thresholds apply to (free-)space of all partitions together"));
935   printf (" %s\n", "-k, --kilobytes");
936   printf ("    %s\n", _("Same as '--units kB'"));
937   printf (" %s\n", "-l, --local");
938   printf ("    %s\n", _("Only check local filesystems"));
939   printf (" %s\n", "-L, --stat-remote-fs");
940   printf ("    %s\n", _("Only check local filesystems against thresholds. Yet call stat on remote filesystems"));
941   printf ("    %s\n", _("to test if they are accessible (e.g. to detect Stale NFS Handles)"));
942   printf (" %s\n", "-M, --mountpoint");
943   printf ("    %s\n", _("Display the mountpoint instead of the partition"));
944   printf (" %s\n", "-m, --megabytes");
945   printf ("    %s\n", _("Same as '--units MB'"));
946   printf (" %s\n", "-A, --all");
947   printf ("    %s\n", _("Explicitly select all pathes. This is equivalent to -R '.*'"));
948   printf (" %s\n", "-R, --eregi-path=PATH, --eregi-partition=PARTITION");
949   printf ("    %s\n", _("Case insensitive regular expression for path/partition (may be repeated)"));
950   printf (" %s\n", "-r, --ereg-path=PATH, --ereg-partition=PARTITION");
951   printf ("    %s\n", _("Regular expression for path or partition (may be repeated)"));
952   printf (" %s\n", "-I, --ignore-eregi-path=PATH, --ignore-eregi-partition=PARTITION");
953   printf ("    %s\n", _("Regular expression to ignore selected path/partition (case insensitive) (may be repeated)"));
954   printf (" %s\n", "-i, --ignore-ereg-path=PATH, --ignore-ereg-partition=PARTITION");
955   printf ("    %s\n", _("Regular expression to ignore selected path or partition (may be repeated)"));
956   printf (_(UT_TIMEOUT), DEFAULT_SOCKET_TIMEOUT);
957   printf (" %s\n", "-u, --units=STRING");
958   printf ("    %s\n", _("Choose bytes, kB, MB, GB, TB (default: MB)"));
959   printf (_(UT_VERBOSE));
960   printf (" %s\n", "-X, --exclude-type=TYPE");
961   printf ("    %s\n", _("Ignore all filesystems of indicated type (may be repeated)"));
963 #ifdef NP_EXTRA_OPTS
964   printf ("\n");
965   printf ("%s\n", _("Notes:"));
966   printf (_(UT_EXTRA_OPTS_NOTES));
967 #endif
969   printf ("\n");
970   printf ("%s\n", _("Examples:"));
971   printf (" %s\n", "check_disk -w 10% -c 5% -p /tmp -p /var -C -w 100000 -c 50000 -p /");
972   printf ("    %s\n", _("Checks /tmp and /var at 10% and 5%, and / at 100MB and 50MB"));
973   printf (" %s\n", "check_disk -w 100M -c 50M -C -w 1000M -c 500M -g sidDATA -r '^/oracle/SID/data.*$'");
974   printf ("    %s\n", _("Checks all filesystems not matching -r at 100M and 50M. The fs matching the -r regex"));
975   printf ("    %s\n", _("are grouped which means the freespace thresholds are applied to all disks together"));
976   printf (" %s\n", "check_disk -w 100M -c 50M -C -w 1000M -c 500M -p /foo -C -w 5% -c 3% -p /bar");
977   printf ("    %s\n", _("Checks /foo for 1000M/500M and /bar for 5/3%. All remaining volumes use 100M/50M"));
979   printf (_(UT_SUPPORT));
984 void
985 print_usage (void)
987   printf (_("Usage:"));
988   printf (" %s -w limit -c limit [-W limit] [-K limit] {-p path | -x device}\n", progname);
989   printf ("[-C] [-E] [-e] [-g group ] [-k] [-l] [-M] [-m] [-R path ] [-r path ]\n");
990   printf ("[-t timeout] [-u unit] [-v] [-X type]\n");
993 void
994 stat_path (struct parameter_list *p)
996   /* Stat entry to check that dir exists and is accessible */
997   if (verbose >= 3)
998     printf("calling stat on %s\n", p->name);
999   if (stat (p->name, &stat_buf[0])) {
1000     if (verbose >= 3)
1001       printf("stat failed on %s\n", p->name);
1002     printf("DISK %s - ", _("CRITICAL"));
1003     die (STATE_CRITICAL, _("%s %s: %s\n"), p->name, _("is not accessible"), strerror(errno));
1004   }