485ae82260701bdccaa2b8db73d82fa50241f65d
1 /******************************************************************************
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
16 *
17 *****************************************************************************/
19 const char *progname = "check_disk";
20 const char *revision = "$Revision$";
21 const char *copyright = "1999-2003";
22 const char *authors = "Nagios Plugin Development Team";
23 const char *email = "nagiosplug-devel@lists.sourceforge.net";
25 const char *summary = "\
26 This plugin checks the amount of used disk space on a mounted file system\n\
27 and generates an alert if free space is less than one of the threshold values.";
29 const char *option_summary = "\
30 -w limit -c limit [-p path | -x device] [-t timeout] [-m] [-e]\n\
31 [-v] [-q]";
33 const char *options = "\
34 -w, --warning=INTEGER\n\
35 Exit with WARNING status if less than INTEGER kilobytes of disk are free\n\
36 -w, --warning=PERCENT%%\n\
37 Exit with WARNING status if less than PERCENT of disk space is free\n\
38 -c, --critical=INTEGER\n\
39 Exit with CRITICAL status if less than INTEGER kilobytes of disk are free\n\
40 -c, --critical=PERCENT%%\n\
41 Exit with CRITCAL status if less than PERCENT of disk space is free\n\
42 -p, --path=PATH, --partition=PARTTION\n\
43 Path or partition (checks all mounted partitions if unspecified)\n\
44 -m, --mountpoint\n\
45 Display the mountpoint instead of the partition\n\
46 -x, --exclude_device=PATH\n\
47 Ignore device (only works if -p unspecified)\n\
48 -e, --errors-only\n\
49 Display only devices/mountpoints with errors\n\
50 -v, --verbose\n\
51 Show details for command-line debugging (do not use with nagios server)\n\
52 -h, --help\n\
53 Print detailed help screen\n\
54 -V, --version\n\
55 Print version information\n";
57 #include "common.h"
58 #include "popen.h"
59 #include "utils.h"
60 #include <stdarg.h>
62 #ifdef _AIX
63 #pragma alloca
64 #endif
66 #if HAVE_INTTYPES_H
67 # include <inttypes.h>
68 #endif
70 int process_arguments (int, char **);
71 int validate_arguments (void);
72 int check_disk (int usp, int free_disk);
73 void print_help (void);
74 void print_usage (void);
76 int w_df = -1;
77 int c_df = -1;
78 float w_dfp = -1.0;
79 float c_dfp = -1.0;
80 char *path = "";
81 char *exclude_device = "";
82 int verbose = 0;
83 int erronly = FALSE;
84 int display_mntp = FALSE;
87 int
88 main (int argc, char **argv)
89 {
90 int usp = -1;
91 int total_disk = -1;
92 int used_disk = -1;
93 int free_disk = -1;
94 int result = STATE_UNKNOWN;
95 int disk_result = STATE_UNKNOWN;
96 char *command_line = "";
97 char input_buffer[MAX_INPUT_BUFFER];
98 char file_system[MAX_INPUT_BUFFER];
99 char mntp[MAX_INPUT_BUFFER];
100 char *output = "";
102 #ifdef HAVE_STRUCT_STATFS
103 #ifdef HAVE_SYS_VFS_H
104 #include <sys/vfs.h>
105 #else
106 #include <sys/param.h>
107 #include <sys/mount.h>
108 #endif
109 struct statfs buf;
110 #endif
112 if (process_arguments (argc, argv) != OK)
113 usage ("Could not parse arguments\n");
115 #ifdef HAVE_STRUCT_STATFS
117 if (statfs (path, &buf) == -1) {
118 switch (errno)
119 {
120 #ifdef ENOTDIR
121 case ENOTDIR:
122 terminate (STATE_UNKNOWN, "A component of the path prefix is not a directory.\n");
123 #endif
124 #ifdef ENAMETOOLONG
125 case ENAMETOOLONG:
126 terminate (STATE_UNKNOWN, "path is too long.\n");
127 #endif
128 #ifdef ENOENT
129 case ENOENT:
130 terminate (STATE_UNKNOWN, "The file referred to by path does not exist.\n");
131 #endif
132 #ifdef EACCES
133 case EACCES:
134 terminate (STATE_UNKNOWN, "Search permission is denied for a component of the path prefix of path.\n");
135 #endif
136 #ifdef ELOOP
137 case ELOOP:
138 terminate (STATE_UNKNOWN, "Too many symbolic links were encountered in translating path.\n");
139 #endif
140 #ifdef EFAULT
141 case EFAULT:
142 terminate (STATE_UNKNOWN, "Buf or path points to an invalid address.\n");
143 #endif
144 #ifdef EIO
145 case EIO:
146 terminate (STATE_UNKNOWN, "An I/O error occurred while reading from or writing to the file system.\n");
147 #endif
148 #ifdef ENOMEM
149 case ENOMEM:
150 terminate (STATE_UNKNOWN, "Insufficient kernel memory was available.\n");
151 #endif
152 #ifdef ENOSYS
153 case ENOSYS:
154 terminate (STATE_UNKNOWN, "The filesystem path is on does not support statfs.\n");
155 #endif
156 }
157 }
159 usp = (buf.f_blocks - buf.f_bavail) / buf.f_blocks;
160 disk_result = check_disk (usp, buf.f_bavail);
161 result = disk_result;
162 asprintf (&output, "%ld of %ld kB free (%ld-byte blocks)",
163 buf.f_bavail*buf.f_bsize/1024, buf.f_blocks*buf.f_bsize/1024, buf.f_bsize);
165 #else
167 asprintf (&command_line, "%s %s", DF_COMMAND, path);
169 if (verbose>0)
170 printf ("%s ==> ", command_line);
172 child_process = spopen (command_line);
173 if (child_process == NULL) {
174 printf ("Could not open pipe: %s\n", command_line);
175 return STATE_UNKNOWN;
176 }
178 child_stderr = fdopen (child_stderr_array[fileno (child_process)], "r");
179 if (child_stderr == NULL) {
180 printf ("Could not open stderr for %s\n", command_line);
181 }
183 while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process)) {
185 if (!index (input_buffer, '/'))
186 continue;
188 /* Fixes AIX /proc fs which lists - for size values */
189 if (strstr (input_buffer, "/proc ") == input_buffer)
190 continue;
192 if (sscanf (input_buffer, "%s %d %d %d %d%% %s", file_system,
193 &total_disk, &used_disk, &free_disk, &usp, mntp) == 6 ||
194 sscanf (input_buffer, "%s %*s %d %d %d %d%% %s", file_system,
195 &total_disk, &used_disk, &free_disk, &usp, mntp) == 6) {
197 if (strcmp(exclude_device,file_system) == 0 ||
198 strcmp(exclude_device,mntp) == 0) {
199 if (verbose>0)
200 printf ("ignoring %s.", file_system);
201 continue;
202 }
204 disk_result = check_disk (usp, free_disk);
206 if (strcmp (file_system, "none") == 0)
207 strncpy (file_system, mntp, MAX_INPUT_BUFFER-1);
209 if (disk_result==STATE_OK && erronly && !verbose)
210 continue;
212 if (disk_result!=STATE_OK || verbose>=0)
213 asprintf (&output, "%s [%d kB (%d%%) free on %s]", output,
214 free_disk, 100 - usp, display_mntp ? mntp : file_system);
216 result = max_state (result, disk_result);
217 }
219 else {
220 printf ("Unable to read output:\n%s\n%s\n", command_line, input_buffer);
221 return result;
222 }
224 }
226 /* If we get anything on stderr, at least set warning */
227 while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_stderr)) {
228 if (result != STATE_CRITICAL) {
229 result = STATE_WARNING;
230 }
231 }
233 /* close stderr */
234 if (child_stderr)
235 (void) fclose (child_stderr);
237 /* close the pipe */
238 if (spclose(child_process)!=0 && result!=STATE_CRITICAL)
239 result = STATE_WARNING;
241 if (usp < 0)
242 terminate (result, "Disk \"%s\" not mounted or nonexistant\n", path);
243 else if (result == STATE_UNKNOWN)
244 terminate (result, "Unable to read output\n%s\n%s\n", command_line, input_buffer);
246 #endif
248 terminate (result, "DISK %s %s\n", state_text (result), output);
249 }
251 /* process command-line arguments */
252 int
253 process_arguments (int argc, char **argv)
254 {
255 int c;
257 int option_index = 0;
258 static struct option long_options[] = {
259 {"warning", required_argument, 0, 'w'},
260 {"critical", required_argument, 0, 'c'},
261 {"timeout", required_argument, 0, 't'},
262 {"path", required_argument, 0, 'p'},
263 {"partition", required_argument, 0, 'p'},
264 {"verbose", no_argument, 0, 'v'},
265 {"version", no_argument, 0, 'V'},
266 {"errors-only", no_argument, 0, 'e'},
267 {"help", no_argument, 0, 'h'},
268 {"mountpoint", no_argument, 0, 'm'},
269 {"exclude_device", required_argument, 0, 'x'},
270 {"quiet", no_argument, 0, 'q'},
272 {0, 0, 0, 0}
273 };
275 if (argc < 2)
276 return ERROR;
278 for (c = 1; c < argc; c++)
279 if (strcmp ("-to", argv[c]) == 0)
280 strcpy (argv[c], "-t");
282 while (1) {
283 c = getopt_long (argc, argv, "+?Vqhvet:c:w:p:x:m", long_options, &option_index);
285 if (c == -1 || c == EOF)
286 break;
288 switch (c) {
289 case 'w': /* warning time threshold */
290 if (is_intnonneg (optarg)) {
291 w_df = atoi (optarg);
292 break;
293 }
294 else if (strpbrk (optarg, ",:") &&
295 strstr (optarg, "%") &&
296 sscanf (optarg, "%d%*[:,]%f%%", &w_df, &w_dfp) == 2) {
297 break;
298 }
299 else if (strstr (optarg, "%") && sscanf (optarg, "%f%%", &w_dfp) == 1) {
300 break;
301 }
302 else {
303 usage ("Warning threshold must be integer or percentage!\n");
304 }
305 case 'c': /* critical time threshold */
306 if (is_intnonneg (optarg)) {
307 c_df = atoi (optarg);
308 break;
309 }
310 else if (strpbrk (optarg, ",:") &&
311 strstr (optarg, "%") &&
312 sscanf (optarg, "%d%*[,:]%f%%", &c_df, &c_dfp) == 2) {
313 break;
314 }
315 else if (strstr (optarg, "%") && sscanf (optarg, "%f%%", &c_dfp) == 1) {
316 break;
317 }
318 else {
319 usage ("Critical threshold must be integer or percentage!\n");
320 }
321 case 't': /* timeout period */
322 if (is_integer (optarg)) {
323 timeout_interval = atoi (optarg);
324 break;
325 }
326 else {
327 usage ("Timeout Interval must be an integer!\n");
328 }
329 case 'p': /* path or partition */
330 path = optarg;
331 break;
332 case 'v': /* verbose */
333 verbose++;
334 break;
335 case 'q': /* verbose */
336 verbose--;
337 break;
338 case 'e':
339 erronly = TRUE;
340 break;
341 case 'm': /* display mountpoint */
342 display_mntp = TRUE;
343 break;
344 case 'x': /* exclude path or partition */
345 exclude_device = optarg;
346 break;
347 case 'V': /* version */
348 print_revision (progname, revision);
349 exit (STATE_OK);
350 case 'h': /* help */
351 print_help ();
352 exit (STATE_OK);
353 case '?': /* help */
354 usage ("check_disk: unrecognized option\n");
355 break;
356 }
357 }
359 c = optind;
360 if (w_dfp == -1 && argc > c && is_intnonneg (argv[c]))
361 w_dfp = (100.0 - atof (argv[c++]));
363 if (c_dfp == -1 && argc > c && is_intnonneg (argv[c]))
364 c_dfp = (100.0 - atof (argv[c++]));
366 if (argc > c && strlen (path) == 0)
367 path = argv[c++];
369 return validate_arguments ();
370 }
372 int
373 validate_arguments ()
374 {
375 if (w_df < 0 && c_df < 0 && w_dfp < 0 && c_dfp < 0) {
376 printf ("INPUT ERROR: Unable to parse command line\n");
377 return ERROR;
378 }
379 else if ((w_dfp >= 0 || c_dfp >= 0)
380 && (w_dfp < 0 || c_dfp < 0 || w_dfp > 100 || c_dfp > 100
381 || c_dfp > w_dfp)) {
382 printf
383 ("INPUT ERROR: C_DFP (%f) should be less than W_DFP (%f) and both should be between zero and 100 percent, inclusive\n",
384 c_dfp, w_dfp);
385 return ERROR;
386 }
387 else if ((w_df > 0 || c_df > 0) && (w_df < 0 || c_df < 0 || c_df > w_df)) {
388 printf
389 ("INPUT ERROR: C_DF (%d) should be less than W_DF (%d) and both should be greater than zero\n",
390 c_df, w_df);
391 return ERROR;
392 }
393 else {
394 return OK;
395 }
396 }
398 int
399 check_disk (usp, free_disk)
400 {
401 int result = STATE_UNKNOWN;
402 /* check the percent used space against thresholds */
403 if (usp >= 0 && usp >= (100.0 - c_dfp))
404 result = STATE_CRITICAL;
405 else if (c_df >= 0 && free_disk <= c_df)
406 result = STATE_CRITICAL;
407 else if (usp >= 0 && usp >= (100.0 - w_dfp))
408 result = STATE_WARNING;
409 else if (w_df >= 0 && free_disk <= w_df)
410 result = STATE_WARNING;
411 else if (usp >= 0.0)
412 result = STATE_OK;
413 return result;
414 }
416 void
417 print_help (void)
418 {
419 print_revision (progname, revision);
420 printf ("Copyright (c) %s %s\n\t<%s>\n\n%s\n",
421 copyright, authors, email, summary);
422 print_usage ();
423 printf ("\nOptions:\n");
424 printf (options);
425 support ();
426 }
428 void
429 print_usage (void)
430 {
431 printf
432 ("Usage: %s %s\n"
433 " %s (-h|--help)\n"
434 " %s (-V|--version)\n", progname, option_summary, progname, progname);
435 }