Code

errors for statfs
[nagiosplug.git] / plugins / check_disk.c
1 /******************************************************************************
2  *
3  * CHECK_DISK.C
4  *
5  * Program: Disk space plugin for Nagios
6  * License: GPL
7  * Copyright (c) 1999 Ethan Galstad (nagios@nagios.org)
8  * Copyright (c) 2000 Karl DeBisschop (kdebisschop@users.sourceforge.net)
9  *
10  * $Id$
11  *
12  * Description:
13  *
14  * This plugin will use the /bin/df command to check the free space on
15  * currently mounted filesystems.  If the percent used disk space is
16  * above <c_dfp>, a STATE_CRITICAL is returned.  If the percent used
17  * disk space is above <w_dfp>, a STATE_WARNING is returned.  If the
18  * specified filesystem cannot be read, a STATE_CRITICAL is returned,
19  * other errors with reading the output result in a STATE_UNKNOWN
20  * error.
21  *
22  * Notes:
23  *  - IRIX support added by Charlie Cook 4-16-1999
24  *  - Modifications by Karl DeBisschop 1999-11-24
25  *     reformat code to 80 char screen width
26  *     set STATE_WARNING if stderr is written or spclose status set
27  *     set default result to STAT_UNKNOWN
28  *     initailize usp to -1, eliminate 'found' variable
29  *     accept any filename/filesystem
30  *     use sscanf, drop while loop
31  *
32  *****************************************************************************/
34 #include "common.h"
35 #include "popen.h"
36 #include "utils.h"
37 #include <stdarg.h>
39 #ifdef _AIX
40  #pragma alloca
41 #endif
43 #if HAVE_INTTYPES_H
44 # include <inttypes.h>
45 #endif
47 #define REVISION "$Revision$"
48 #define COPYRIGHT "2000-2002"
50 int process_arguments (int, char **);
51 int validate_arguments (void);
52 int check_disk (int usp, int free_disk);
53 void print_help (void);
54 void print_usage (void);
56 const char *progname = "check_disk";
58 int w_df = -1;
59 int c_df = -1;
60 float w_dfp = -1.0;
61 float c_dfp = -1.0;
62 char *path = "";
63 char *exclude_device = "";
64 int verbose = 0;
65 int erronly = FALSE;
66 int display_mntp = FALSE;
69 int
70 main (int argc, char **argv)
71 {
72         int usp = -1;
73         int total_disk = -1;
74         int used_disk = -1;
75         int free_disk = -1;
76         int result = STATE_UNKNOWN;
77         int disk_result = STATE_UNKNOWN;
78         char *command_line = "";
79         char input_buffer[MAX_INPUT_BUFFER];
80         char file_system[MAX_INPUT_BUFFER];
81         char mntp[MAX_INPUT_BUFFER];
82         char *output = "";
84 #ifdef HAVE_STRUCT_STATFS
85 #ifdef HAVE_SYS_VFS_H
86 #include <sys/vfs.h>
87 #else
88 #include <sys/param.h>
89 #include <sys/mount.h>
90 #endif
91         struct statfs buf;
92 #endif
94         if (process_arguments (argc, argv) != OK)
95                 usage ("Could not parse arguments\n");
97 #ifdef HAVE_STRUCT_STATFS
99         if (statfs (path, &buf) == -1) {
100                 switch (errno)
101                         {
102 #ifdef ENOTDIR
103                         case ENOTDIR:
104                                 terminate (STATE_UNKNOWN, "A component of the path prefix is not a directory.\n");
105 #endif
106 #ifdef ENAMETOOLONG
107                         case ENAMETOOLONG:
108                                 terminate (STATE_UNKNOWN, "path is too long.\n");
109 #endif
110 #ifdef ENOENT
111                         case ENOENT:
112                                 terminate (STATE_UNKNOWN, "The file referred to by path does not exist.\n");
113 #endif
114 #ifdef EACCES
115                         case EACCES:
116                                 terminate (STATE_UNKNOWN, "Search permission is denied for a component of the path prefix of path.\n");
117 #endif
118 #ifdef ELOOP
119                         case ELOOP:
120                                 terminate (STATE_UNKNOWN, "Too many symbolic links were encountered in translating path.\n");
121 #endif
122 #ifdef EFAULT
123                         case EFAULT:
124                                 terminate (STATE_UNKNOWN, "Buf or path points to an invalid address.\n");
125 #endif
126 #ifdef EIO
127                         case EIO:
128                                 terminate (STATE_UNKNOWN, "An I/O error occurred while reading from or writing to the file system.\n");
129 #endif
130 #ifdef ENOMEM
131                         case ENOMEM:
132                                 terminate (STATE_UNKNOWN, "Insufficient kernel memory was available.\n");
133 #endif
134 #ifdef ENOSYS
135                         case ENOSYS:
136                                 terminate (STATE_UNKNOWN, "The  filesystem path is on does not support statfs.\n");
137 #endif
138                         }
139         }
141         usp = (buf.f_blocks - buf.f_bavail) / buf.f_blocks;
142         disk_result = check_disk (usp, buf.f_bavail);
143         result = disk_result;
144         asprintf (&output, "%ld of %ld kB free (%ld-byte blocks)",
145                   buf.f_bavail*buf.f_bsize/1024, buf.f_blocks*buf.f_bsize/1024, buf.f_bsize);
147 #else
149         asprintf (&command_line, "%s %s", DF_COMMAND, path);
151         if (verbose>0)
152                 printf ("%s ==> ", command_line);
154         child_process = spopen (command_line);
155         if (child_process == NULL) {
156                 printf ("Could not open pipe: %s\n", command_line);
157                 return STATE_UNKNOWN;
158         }
160         child_stderr = fdopen (child_stderr_array[fileno (child_process)], "r");
161         if (child_stderr == NULL) {
162                 printf ("Could not open stderr for %s\n", command_line);
163         }
165         while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process)) {
167                 if (!index (input_buffer, '/'))
168                         continue;
170                 /* Fixes AIX /proc fs which lists - for size values */
171                 if (strstr (input_buffer, "/proc ") == input_buffer)
172                         continue;
174                 if (sscanf (input_buffer, "%s %d %d %d %d%% %s", file_system,
175                      &total_disk, &used_disk, &free_disk, &usp, mntp) == 6 ||
176                     sscanf (input_buffer, "%s %*s %d %d %d %d%% %s", file_system,
177                                  &total_disk, &used_disk, &free_disk, &usp, mntp) == 6) {
179                         if (strcmp(exclude_device,file_system) == 0 ||
180                             strcmp(exclude_device,mntp) == 0) {
181                                 if (verbose>0)
182                                         printf ("ignoring %s.", file_system);
183                                 continue;
184                         }
186                         disk_result = check_disk (usp, free_disk);
188                         if (strcmp (file_system, "none") == 0)
189                                 strncpy (file_system, mntp, MAX_INPUT_BUFFER-1);
191                         if (disk_result==STATE_OK && erronly && !verbose)
192                                 continue;
194                         if (disk_result!=STATE_OK || verbose>=0) 
195                                 asprintf (&output, "%s [%d kB (%d%%) free on %s]", output,
196                                           free_disk, 100 - usp, display_mntp ? mntp : file_system);
198                         result = max_state (result, disk_result);
199                 }
201                 else {
202                         printf ("Unable to read output:\n%s\n%s\n", command_line, input_buffer);
203                         return result;
204                 }
206         }
208         /* If we get anything on stderr, at least set warning */
209         while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_stderr)) {
210                 if (result != STATE_CRITICAL) {
211                         result = STATE_WARNING;
212                 }
213         }
215         /* close stderr */
216         if (child_stderr) 
217                 (void) fclose (child_stderr);
219         /* close the pipe */
220         if (spclose(child_process)!=0 && result!=STATE_CRITICAL)
221                         result = STATE_WARNING;
223         if (usp < 0)
224                 terminate (result, "Disk \"%s\" not mounted or nonexistant\n", path);
225         else if (result == STATE_UNKNOWN)
226                 terminate (result, "Unable to read output\n%s\n%s\n", command_line, input_buffer);
228 #endif
230         terminate (result, "DISK %s %s\n", state_text (result), output);
233 /* process command-line arguments */
234 int
235 process_arguments (int argc, char **argv)
237         int c;
239         int option_index = 0;
240         static struct option long_options[] = {
241                 {"warning", required_argument, 0, 'w'},
242                 {"critical", required_argument, 0, 'c'},
243                 {"timeout", required_argument, 0, 't'},
244                 {"path", required_argument, 0, 'p'},
245                 {"partition", required_argument, 0, 'p'},
246                 {"verbose", no_argument, 0, 'v'},
247                 {"version", no_argument, 0, 'V'},
248                 {"errors-only", no_argument, 0, 'e'},
249                 {"help", no_argument, 0, 'h'},
250                 {"mountpoint", no_argument, 0, 'm'},
251                 {"exclude_device", required_argument, 0, 'x'},
252                 {"quiet", no_argument, 0, 'q'},
254                 {0, 0, 0, 0}
255         };
257         if (argc < 2)
258                 return ERROR;
260         for (c = 1; c < argc; c++)
261                 if (strcmp ("-to", argv[c]) == 0)
262                         strcpy (argv[c], "-t");
264         while (1) {
265                 c = getopt_long (argc, argv, "+?Vqhvet:c:w:p:x:m", long_options, &option_index);
267                 if (c == -1 || c == EOF)
268                         break;
270                 switch (c) {
271                 case 'w':                                                                       /* warning time threshold */
272                         if (is_intnonneg (optarg)) {
273                                 w_df = atoi (optarg);
274                                 break;
275                         }
276                         else if (strpbrk (optarg, ",:") &&
277                                                          strstr (optarg, "%") &&
278                                                          sscanf (optarg, "%d%*[:,]%f%%", &w_df, &w_dfp) == 2) {
279                                 break;
280                         }
281                         else if (strstr (optarg, "%") && sscanf (optarg, "%f%%", &w_dfp) == 1) {
282                                 break;
283                         }
284                         else {
285                                 usage ("Warning threshold must be integer or percentage!\n");
286                         }
287                 case 'c':                                                                       /* critical time threshold */
288                         if (is_intnonneg (optarg)) {
289                                 c_df = atoi (optarg);
290                                 break;
291                         }
292                         else if (strpbrk (optarg, ",:") &&
293                                                          strstr (optarg, "%") &&
294                                                          sscanf (optarg, "%d%*[,:]%f%%", &c_df, &c_dfp) == 2) {
295                                 break;
296                         }
297                         else if (strstr (optarg, "%") && sscanf (optarg, "%f%%", &c_dfp) == 1) {
298                                 break;
299                         }
300                         else {
301                                 usage ("Critical threshold must be integer or percentage!\n");
302                         }
303                 case 't':                                                                       /* timeout period */
304                         if (is_integer (optarg)) {
305                                 timeout_interval = atoi (optarg);
306                                 break;
307                         }
308                         else {
309                                 usage ("Timeout Interval must be an integer!\n");
310                         }
311                 case 'p':                                                                       /* path or partition */
312                         path = optarg;
313                         break;
314                 case 'v':                                                                       /* verbose */
315                         verbose++;
316                         break;
317                 case 'q':                                                                       /* verbose */
318                         verbose--;
319                         break;
320                 case 'e':
321                         erronly = TRUE;
322                         break;
323                 case 'm': /* display mountpoint */
324                         display_mntp = TRUE;
325                         break;
326                 case 'x':                                                                       /* exclude path or partition */
327                         exclude_device = optarg;
328                         break;
329                 case 'V':                                                                       /* version */
330                         print_revision (progname, REVISION);
331                         exit (STATE_OK);
332                 case 'h':                                                                       /* help */
333                         print_help ();
334                         exit (STATE_OK);
335                 case '?':                                                                       /* help */
336                         usage ("check_disk: unrecognized option\n");
337                         break;
338                 }
339         }
341         c = optind;
342         if (w_dfp == -1 && argc > c && is_intnonneg (argv[c]))
343                 w_dfp = (100.0 - atof (argv[c++]));
345         if (c_dfp == -1 && argc > c && is_intnonneg (argv[c]))
346                 c_dfp = (100.0 - atof (argv[c++]));
348         if (argc > c && strlen (path) == 0)
349                 path = argv[c++];
351         return validate_arguments ();
354 int
355 validate_arguments ()
357         if (w_df < 0 && c_df < 0 && w_dfp < 0 && c_dfp < 0) {
358                 printf ("INPUT ERROR: Unable to parse command line\n");
359                 return ERROR;
360         }
361         else if ((w_dfp >= 0 || c_dfp >= 0)
362                                          && (w_dfp < 0 || c_dfp < 0 || w_dfp > 100 || c_dfp > 100
363                                                          || c_dfp > w_dfp)) {
364                 printf
365                         ("INPUT ERROR: C_DFP (%f) should be less than W_DFP (%f) and both should be between zero and 100 percent, inclusive\n",
366                          c_dfp, w_dfp);
367                 return ERROR;
368         }
369         else if ((w_df > 0 || c_df > 0) && (w_df < 0 || c_df < 0 || c_df > w_df)) {
370                 printf
371                         ("INPUT ERROR: C_DF (%d) should be less than W_DF (%d) and both should be greater than zero\n",
372                          c_df, w_df);
373                 return ERROR;
374         }
375         else {
376                 return OK;
377         }
380 int
381 check_disk (usp, free_disk)
383         int result = STATE_UNKNOWN;
384         /* check the percent used space against thresholds */
385         if (usp >= 0 && usp >= (100.0 - c_dfp))
386                 result = STATE_CRITICAL;
387         else if (c_df >= 0 && free_disk <= c_df)
388                 result = STATE_CRITICAL;
389         else if (usp >= 0 && usp >= (100.0 - w_dfp))
390                 result = STATE_WARNING;
391         else if (w_df >= 0 && free_disk <= w_df)
392                 result = STATE_WARNING;
393         else if (usp >= 0.0)
394                 result = STATE_OK;
395         return result;
398 void
399 print_help (void)
401         print_revision (progname, REVISION);
402         printf
403                 ("Copyright (c) 2000 Ethan Galstad/Karl DeBisschop\n\n"
404                  "This plugin will check the percent of used disk space on a mounted\n"
405                  "file system and generate an alert if percentage is above one of the\n"
406                  "threshold values.\n\n");
407         print_usage ();
408         printf
409                 ("\nOptions:\n"
410                  " -w, --warning=INTEGER\n"
411                  "   Exit with WARNING status if less than INTEGER kilobytes of disk are free\n"
412                  " -w, --warning=PERCENT%%\n"
413                  "   Exit with WARNING status if less than PERCENT of disk space is free\n"
414                  " -c, --critical=INTEGER\n"
415                  "   Exit with CRITICAL status if less than INTEGER kilobytes of disk are free\n"
416                  " -c, --critical=PERCENT%%\n"
417                  "   Exit with CRITCAL status if less than PERCENT of disk space is free\n"
418                  " -p, --path=PATH, --partition=PARTTION\n"
419                  "    Path or partition (checks all mounted partitions if unspecified)\n"
420                  " -m, --mountpoint\n"
421                  "    Display the mountpoint instead of the partition\n"
422                  " -x, --exclude_device=PATH\n"
423                  "    Ignore device (only works if -p unspecified)\n"
424                  " -e, --errors-only\n"
425                  "    Display only devices/mountpoints with errors\n"
426                  " -v, --verbose\n"
427                  "    Show details for command-line debugging (do not use with nagios server)\n"
428                  " -h, --help\n"
429                  "    Print detailed help screen\n"
430                  " -V, --version\n" "    Print version information\n\n");
431         support ();
434 void
435 print_usage (void)
437         printf
438                 ("Usage: %s -w limit -c limit [-p path | -x device] [-t timeout] [-m] [-e] [--verbose]\n"
439                  "       %s (-h|--help)\n"
440                  "       %s (-V|--version)\n", progname, progname, progname);