Code

Code cleanup
[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                         case ENOTDIR:
103                                 terminate (STATE_UNKNOWN, "A component of the path prefix is not a directory.\n");
104                         case ENAMETOOLONG:
105                                 terminate (STATE_UNKNOWN, "path is too long.\n");
106                         case ENOENT:
107                                 terminate (STATE_UNKNOWN, "The file referred to by path does not exist.\n");
108                         case EACCES:
109                                 terminate (STATE_UNKNOWN, "Search permission is denied for a component of the path prefix of path.\n");
110                         case ELOOP:
111                                 terminate (STATE_UNKNOWN, "Too many symbolic links were encountered in translating path.\n");
112                         case EFAULT:
113                                 terminate (STATE_UNKNOWN, "Buf or path points to an invalid address.\n");
114                         case EIO:
115                                 terminate (STATE_UNKNOWN, "An I/O error occurred while reading from or writing to the file system.\n");
116                         case ENOMEM:
117                                 terminate (STATE_UNKNOWN, "Insufficient kernel memory was available.\n");
118                         case ENOSYS:
119                                 terminate (STATE_UNKNOWN, "The  filesystem path is on does not support statfs.\n");
120                         }
121         }
122         usp = (buf.f_blocks - buf.f_bavail) / buf.f_blocks;
123         disk_result = check_disk (usp, buf.f_bavail);
124         result = disk_result;
125         asprintf (&output, "%ld of %ld kB free (%ld-byte blocks)",
126                   buf.f_bavail*buf.f_bsize/1024, buf.f_blocks*buf.f_bsize/1024, buf.f_bsize);
128 #else
130         asprintf (&command_line, "%s %s", DF_COMMAND, path);
132         if (verbose>0)
133                 printf ("%s ==> ", command_line);
135         child_process = spopen (command_line);
136         if (child_process == NULL) {
137                 printf ("Could not open pipe: %s\n", command_line);
138                 return STATE_UNKNOWN;
139         }
141         child_stderr = fdopen (child_stderr_array[fileno (child_process)], "r");
142         if (child_stderr == NULL) {
143                 printf ("Could not open stderr for %s\n", command_line);
144         }
146         while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process)) {
148                 if (!index (input_buffer, '/'))
149                         continue;
151                 /* Fixes AIX /proc fs which lists - for size values */
152                 if (strstr (input_buffer, "/proc ") == input_buffer)
153                         continue;
155                 if (sscanf (input_buffer, "%s %d %d %d %d%% %s", file_system,
156                      &total_disk, &used_disk, &free_disk, &usp, mntp) == 6 ||
157                     sscanf (input_buffer, "%s %*s %d %d %d %d%% %s", file_system,
158                                  &total_disk, &used_disk, &free_disk, &usp, mntp) == 6) {
160                         if (strcmp(exclude_device,file_system) == 0 ||
161                             strcmp(exclude_device,mntp) == 0) {
162                                 if (verbose>0)
163                                         printf ("ignoring %s.", file_system);
164                                 continue;
165                         }
167                         disk_result = check_disk (usp, free_disk);
169                         if (strcmp (file_system, "none") == 0)
170                                 strncpy (file_system, mntp, MAX_INPUT_BUFFER-1);
172                         if (disk_result==STATE_OK && erronly && !verbose)
173                                 continue;
175                         if (disk_result!=STATE_OK || verbose>=0) 
176                                 asprintf (&output, "%s [%d kB (%d%%) free on %s]", output,
177                                           free_disk, 100 - usp, display_mntp ? mntp : file_system);
179                         result = max_state (result, disk_result);
180                 }
182                 else {
183                         printf ("Unable to read output:\n%s\n%s\n", command_line, input_buffer);
184                         return result;
185                 }
187         }
189         /* If we get anything on stderr, at least set warning */
190         while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_stderr)) {
191                 if (result != STATE_CRITICAL) {
192                         result = STATE_WARNING;
193                 }
194         }
196         /* close stderr */
197         if (child_stderr) 
198                 (void) fclose (child_stderr);
200         /* close the pipe */
201         if (spclose(child_process)!=0 && result!=STATE_CRITICAL)
202                         result = STATE_WARNING;
204         if (usp < 0)
205                 terminate (result, "Disk \"%s\" not mounted or nonexistant\n", path);
206         else if (result == STATE_UNKNOWN)
207                 terminate (result, "Unable to read output\n%s\n%s\n", command_line, input_buffer);
209 #endif
211         terminate (result, "DISK %s %s\n", state_text (result), output);
214 /* process command-line arguments */
215 int
216 process_arguments (int argc, char **argv)
218         int c;
220         int option_index = 0;
221         static struct option long_options[] = {
222                 {"warning", required_argument, 0, 'w'},
223                 {"critical", required_argument, 0, 'c'},
224                 {"timeout", required_argument, 0, 't'},
225                 {"path", required_argument, 0, 'p'},
226                 {"partition", required_argument, 0, 'p'},
227                 {"verbose", no_argument, 0, 'v'},
228                 {"version", no_argument, 0, 'V'},
229                 {"errors-only", no_argument, 0, 'e'},
230                 {"help", no_argument, 0, 'h'},
231                 {"mountpoint", no_argument, 0, 'm'},
232                 {"exclude_device", required_argument, 0, 'x'},
233                 {"quiet", no_argument, 0, 'q'},
235                 {0, 0, 0, 0}
236         };
238         if (argc < 2)
239                 return ERROR;
241         for (c = 1; c < argc; c++)
242                 if (strcmp ("-to", argv[c]) == 0)
243                         strcpy (argv[c], "-t");
245         while (1) {
246                 c = getopt_long (argc, argv, "+?Vqhvet:c:w:p:x:m", long_options, &option_index);
248                 if (c == -1 || c == EOF)
249                         break;
251                 switch (c) {
252                 case 'w':                                                                       /* warning time threshold */
253                         if (is_intnonneg (optarg)) {
254                                 w_df = atoi (optarg);
255                                 break;
256                         }
257                         else if (strpbrk (optarg, ",:") &&
258                                                          strstr (optarg, "%") &&
259                                                          sscanf (optarg, "%d%*[:,]%f%%", &w_df, &w_dfp) == 2) {
260                                 break;
261                         }
262                         else if (strstr (optarg, "%") && sscanf (optarg, "%f%%", &w_dfp) == 1) {
263                                 break;
264                         }
265                         else {
266                                 usage ("Warning threshold must be integer or percentage!\n");
267                         }
268                 case 'c':                                                                       /* critical time threshold */
269                         if (is_intnonneg (optarg)) {
270                                 c_df = atoi (optarg);
271                                 break;
272                         }
273                         else if (strpbrk (optarg, ",:") &&
274                                                          strstr (optarg, "%") &&
275                                                          sscanf (optarg, "%d%*[,:]%f%%", &c_df, &c_dfp) == 2) {
276                                 break;
277                         }
278                         else if (strstr (optarg, "%") && sscanf (optarg, "%f%%", &c_dfp) == 1) {
279                                 break;
280                         }
281                         else {
282                                 usage ("Critical threshold must be integer or percentage!\n");
283                         }
284                 case 't':                                                                       /* timeout period */
285                         if (is_integer (optarg)) {
286                                 timeout_interval = atoi (optarg);
287                                 break;
288                         }
289                         else {
290                                 usage ("Timeout Interval must be an integer!\n");
291                         }
292                 case 'p':                                                                       /* path or partition */
293                         path = optarg;
294                         break;
295                 case 'v':                                                                       /* verbose */
296                         verbose++;
297                         break;
298                 case 'q':                                                                       /* verbose */
299                         verbose--;
300                         break;
301                 case 'e':
302                         erronly = TRUE;
303                         break;
304                 case 'm': /* display mountpoint */
305                         display_mntp = TRUE;
306                         break;
307                 case 'x':                                                                       /* exclude path or partition */
308                         exclude_device = optarg;
309                         break;
310                 case 'V':                                                                       /* version */
311                         print_revision (progname, REVISION);
312                         exit (STATE_OK);
313                 case 'h':                                                                       /* help */
314                         print_help ();
315                         exit (STATE_OK);
316                 case '?':                                                                       /* help */
317                         usage ("check_disk: unrecognized option\n");
318                         break;
319                 }
320         }
322         c = optind;
323         if (w_dfp == -1 && argc > c && is_intnonneg (argv[c]))
324                 w_dfp = (100.0 - atof (argv[c++]));
326         if (c_dfp == -1 && argc > c && is_intnonneg (argv[c]))
327                 c_dfp = (100.0 - atof (argv[c++]));
329         if (argc > c && strlen (path) == 0)
330                 path = argv[c++];
332         return validate_arguments ();
335 int
336 validate_arguments ()
338         if (w_df < 0 && c_df < 0 && w_dfp < 0 && c_dfp < 0) {
339                 printf ("INPUT ERROR: Unable to parse command line\n");
340                 return ERROR;
341         }
342         else if ((w_dfp >= 0 || c_dfp >= 0)
343                                          && (w_dfp < 0 || c_dfp < 0 || w_dfp > 100 || c_dfp > 100
344                                                          || c_dfp > w_dfp)) {
345                 printf
346                         ("INPUT ERROR: C_DFP (%f) should be less than W_DFP (%f) and both should be between zero and 100 percent, inclusive\n",
347                          c_dfp, w_dfp);
348                 return ERROR;
349         }
350         else if ((w_df > 0 || c_df > 0) && (w_df < 0 || c_df < 0 || c_df > w_df)) {
351                 printf
352                         ("INPUT ERROR: C_DF (%d) should be less than W_DF (%d) and both should be greater than zero\n",
353                          c_df, w_df);
354                 return ERROR;
355         }
356         else {
357                 return OK;
358         }
361 int
362 check_disk (usp, free_disk)
364         int result = STATE_UNKNOWN;
365         /* check the percent used space against thresholds */
366         if (usp >= 0 && usp >= (100.0 - c_dfp))
367                 result = STATE_CRITICAL;
368         else if (c_df >= 0 && free_disk <= c_df)
369                 result = STATE_CRITICAL;
370         else if (usp >= 0 && usp >= (100.0 - w_dfp))
371                 result = STATE_WARNING;
372         else if (w_df >= 0 && free_disk <= w_df)
373                 result = STATE_WARNING;
374         else if (usp >= 0.0)
375                 result = STATE_OK;
376         return result;
379 void
380 print_help (void)
382         print_revision (progname, REVISION);
383         printf
384                 ("Copyright (c) 2000 Ethan Galstad/Karl DeBisschop\n\n"
385                  "This plugin will check the percent of used disk space on a mounted\n"
386                  "file system and generate an alert if percentage is above one of the\n"
387                  "threshold values.\n\n");
388         print_usage ();
389         printf
390                 ("\nOptions:\n"
391                  " -w, --warning=INTEGER\n"
392                  "   Exit with WARNING status if less than INTEGER kilobytes of disk are free\n"
393                  " -w, --warning=PERCENT%%\n"
394                  "   Exit with WARNING status if less than PERCENT of disk space is free\n"
395                  " -c, --critical=INTEGER\n"
396                  "   Exit with CRITICAL status if less than INTEGER kilobytes of disk are free\n"
397                  " -c, --critical=PERCENT%%\n"
398                  "   Exit with CRITCAL status if less than PERCENT of disk space is free\n"
399                  " -p, --path=PATH, --partition=PARTTION\n"
400                  "    Path or partition (checks all mounted partitions if unspecified)\n"
401                  " -m, --mountpoint\n"
402                  "    Display the mountpoint instead of the partition\n"
403                  " -x, --exclude_device=PATH\n"
404                  "    Ignore device (only works if -p unspecified)\n"
405                  " -e, --errors-only\n"
406                  "    Display only devices/mountpoints with errors\n"
407                  " -v, --verbose\n"
408                  "    Show details for command-line debugging (do not use with nagios server)\n"
409                  " -h, --help\n"
410                  "    Print detailed help screen\n"
411                  " -V, --version\n" "    Print version information\n\n");
412         support ();
415 void
416 print_usage (void)
418         printf
419                 ("Usage: %s -w limit -c limit [-p path | -x device] [-t timeout] [-m] [-e] [--verbose]\n"
420                  "       %s (-h|--help)\n"
421                  "       %s (-V|--version)\n", progname, progname, progname);