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 * speicified 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 #define PROGNAME "check_disk"
40 #define REVISION "$Revision$"
41 #define COPYRIGHT "2000-2002"
43 int process_arguments (int, char **);
44 int validate_arguments (void);
45 int check_disk (int usp, int free_disk);
46 void print_help (void);
47 void print_usage (void);
49 int w_df = -1;
50 int c_df = -1;
51 float w_dfp = -1.0;
52 float c_dfp = -1.0;
53 char *path = "";
54 int verbose = FALSE;
55 int display_mntp = FALSE;
57 int
58 main (int argc, char **argv)
59 {
60 int len;
61 int usp = -1;
62 int total_disk = -1;
63 int used_disk = -1;
64 int free_disk = -1;
65 int result = STATE_UNKNOWN;
66 int temp_result = STATE_UNKNOWN;
67 char *command_line = NULL;
68 char input_buffer[MAX_INPUT_BUFFER] = "";
69 char file_system[MAX_INPUT_BUFFER] = "";
70 char mntp[MAX_INPUT_BUFFER] = "";
71 char outbuf[MAX_INPUT_BUFFER] = "";
72 char *output = "";
74 if (process_arguments (argc, argv) != OK)
75 usage ("Could not parse arguments\n");
77 asprintf (&command_line, "%s %s", DF_COMMAND, path);
79 if (verbose)
80 printf ("%s ==> ", command_line);
82 child_process = spopen (command_line);
83 if (child_process == NULL) {
84 printf ("Could not open pipe: %s\n", command_line);
85 return STATE_UNKNOWN;
86 }
88 child_stderr = fdopen (child_stderr_array[fileno (child_process)], "r");
89 if (child_stderr == NULL) {
90 printf ("Could not open stderr for %s\n", command_line);
91 }
93 while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process)) {
95 if (!index (input_buffer, '/'))
96 continue;
98 if (sscanf
99 (input_buffer, "%s %d %d %d %d%% %s", file_system, &total_disk,
100 &used_disk, &free_disk, &usp, &mntp) == 6
101 || sscanf (input_buffer, "%s %*s %d %d %d %d%% %s", file_system,
102 &total_disk, &used_disk, &free_disk, &usp, &mntp) == 6) {
103 asprintf (&output, "%s [%d kB (%d%%) free on %s]", output, free_disk,
104 100 - usp, display_mntp ? mntp : file_system);
105 result = max_state (result, check_disk (usp, free_disk));
106 }
107 else {
108 printf ("Unable to read output:\n%s\n%s\n", command_line, input_buffer);
109 return result;
110 }
112 }
114 /* If we get anything on stderr, at least set warning */
115 while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_stderr))
116 /*result = max (result, STATE_WARNING); */
117 if( !( result == STATE_CRITICAL) ) {
118 result = STATE_WARNING;
119 }
121 /* close stderr */
122 (void) fclose (child_stderr);
124 /* close the pipe */
125 if (spclose (child_process))
126 /*result = max (result, STATE_WARNING); */
127 if( !( result == STATE_CRITICAL) ) {
128 result = STATE_WARNING;
129 }
130 if (usp < 0)
131 printf ("Disk \"%s\" not mounted or nonexistant\n", path);
132 else if (result == STATE_UNKNOWN)
133 printf ("Unable to read output\n%s\n%s\n", command_line, input_buffer);
134 else
135 printf ("DISK %s -%s\n", state_text (result), output);
137 return result;
138 }
140 /* process command-line arguments */
141 int
142 process_arguments (int argc, char **argv)
143 {
144 int c;
146 #ifdef HAVE_GETOPT_H
147 int option_index = 0;
148 static struct option long_options[] = {
149 {"warning", required_argument, 0, 'w'},
150 {"critical", required_argument, 0, 'c'},
151 {"timeout", required_argument, 0, 't'},
152 {"path", required_argument, 0, 'p'},
153 {"partition", required_argument, 0, 'p'},
154 {"verbose", no_argument, 0, 'v'},
155 {"version", no_argument, 0, 'V'},
156 {"help", no_argument, 0, 'h'},
157 {"mountpoint", no_argument, 0, 'm'},
158 {0, 0, 0, 0}
159 };
160 #endif
162 if (argc < 2)
163 return ERROR;
165 for (c = 1; c < argc; c++)
166 if (strcmp ("-to", argv[c]) == 0)
167 strcpy (argv[c], "-t");
169 while (1) {
170 #ifdef HAVE_GETOPT_H
171 c =
172 getopt_long (argc, argv, "Vhvt:c:w:p:m", long_options, &option_index);
173 #else
174 c = getopt (argc, argv, "Vhvt:c:w:p:m");
175 #endif
177 if (c == -1 || c == EOF)
178 break;
180 switch (c) {
181 case 'w': /* warning time threshold */
182 if (is_intnonneg (optarg)) {
183 w_df = atoi (optarg);
184 break;
185 }
186 else if (strpbrk (optarg, ",:") &&
187 strstr (optarg, "%") &&
188 sscanf (optarg, "%d%*[:,]%f%%", &w_df, &w_dfp) == 2) {
189 break;
190 }
191 else if (strstr (optarg, "%") && sscanf (optarg, "%f%%", &w_dfp) == 1) {
192 break;
193 }
194 else {
195 usage ("Warning threshold must be integer or percentage!\n");
196 }
197 case 'c': /* critical time threshold */
198 if (is_intnonneg (optarg)) {
199 c_df = atoi (optarg);
200 break;
201 }
202 else if (strpbrk (optarg, ",:") &&
203 strstr (optarg, "%") &&
204 sscanf (optarg, "%d%*[,:]%f%%", &c_df, &c_dfp) == 2) {
205 break;
206 }
207 else if (strstr (optarg, "%") && sscanf (optarg, "%f%%", &c_dfp) == 1) {
208 break;
209 }
210 else {
211 usage ("Critical threshold must be integer or percentage!\n");
212 }
213 case 't': /* timeout period */
214 if (is_integer (optarg)) {
215 timeout_interval = atoi (optarg);
216 break;
217 }
218 else {
219 usage ("Timeout Interval must be an integer!\n");
220 }
221 case 'p': /* path or partition */
222 path = optarg;
223 break;
224 case 'v': /* verbose */
225 verbose = TRUE;
226 break;
227 case 'm': /* display mountpoint */
228 display_mntp = TRUE;
229 break;
230 case 'V': /* version */
231 print_revision (PROGNAME, REVISION);
232 exit (STATE_OK);
233 case 'h': /* help */
234 print_help ();
235 exit (STATE_OK);
236 case '?': /* help */
237 usage ("check_disk: unrecognized option\n");
238 break;
239 }
240 }
242 c = optind;
243 if (w_dfp == -1 && argc > c && is_intnonneg (argv[c]))
244 w_dfp = (100.0 - atof (argv[c++]));
246 if (c_dfp == -1 && argc > c && is_intnonneg (argv[c]))
247 c_dfp = (100.0 - atof (argv[c++]));
249 if (argc > c && strlen (path) == 0)
250 path = argv[c++];
252 return validate_arguments ();
253 }
255 int
256 validate_arguments ()
257 {
258 if (w_df < 0 && c_df < 0 && w_dfp < 0 && c_dfp < 0) {
259 printf ("INPUT ERROR: Unable to parse command line\n");
260 return ERROR;
261 }
262 else if ((w_dfp >= 0 || c_dfp >= 0)
263 && (w_dfp < 0 || c_dfp < 0 || w_dfp > 100 || c_dfp > 100
264 || c_dfp > w_dfp)) {
265 printf
266 ("INPUT ERROR: C_DFP (%f) should be less than W_DFP (%f) and both should be between zero and 100 percent, inclusive\n",
267 c_dfp, w_dfp);
268 return ERROR;
269 }
270 else if ((w_df > 0 || c_df > 0) && (w_df < 0 || c_df < 0 || c_df > w_df)) {
271 printf
272 ("INPUT ERROR: C_DF (%d) should be less than W_DF (%d) and both should be greater than zero\n",
273 c_df, w_df);
274 return ERROR;
275 }
276 else {
277 return OK;
278 }
279 }
281 int
282 check_disk (usp, free_disk)
283 {
284 int result = STATE_UNKNOWN;
285 /* check the percent used space against thresholds */
286 if (usp >= 0 && usp >= (100.0 - c_dfp))
287 result = STATE_CRITICAL;
288 else if (c_df >= 0 && free_disk <= c_df)
289 result = STATE_CRITICAL;
290 else if (usp >= 0 && usp >= (100.0 - w_dfp))
291 result = STATE_WARNING;
292 else if (w_df >= 0 && free_disk <= w_df)
293 result = STATE_WARNING;
294 else if (usp >= 0.0)
295 result = STATE_OK;
296 return result;
297 }
299 void
300 print_help (void)
301 {
302 print_revision (PROGNAME, REVISION);
303 printf
304 ("Copyright (c) 2000 Ethan Galstad/Karl DeBisschop\n\n"
305 "This plugin will check the percent of used disk space on a mounted\n"
306 "file system and generate an alert if percentage is above one of the\n"
307 "threshold values.\n\n");
308 print_usage ();
309 printf
310 ("\nOptions:\n"
311 " -w, --warning=INTEGER\n"
312 " Exit with WARNING status if less than INTEGER kilobytes of disk are free\n"
313 " -w, --warning=PERCENT%%\n"
314 " Exit with WARNING status if more than PERCENT of disk space is free\n"
315 " -c, --critical=INTEGER\n"
316 " Exit with CRITICAL status if less than INTEGER kilobytes of disk are free\n"
317 " -c, --critical=PERCENT%%\n"
318 " Exit with CRITCAL status if more than PERCENT of disk space is free\n"
319 " -p, --path=PATH, --partition=PARTTION\n"
320 " Path or partition (checks all mounted partitions if unspecified)\n"
321 " -m, --mountpoint\n"
322 " Display the mountpoint instead of the partition\n"
323 " -v, --verbose\n"
324 " Show details for command-line debugging (do not use with nagios server)\n"
325 " -h, --help\n"
326 " Print detailed help screen\n"
327 " -V, --version\n" " Print version information\n\n");
328 support ();
329 }
331 void
332 print_usage (void)
333 {
334 printf
335 ("Usage: %s -w limit -c limit [-p path] [-t timeout] [-m] [--verbose]\n"
336 " %s (-h|--help)\n"
337 " %s (-V|--version)\n", PROGNAME, PROGNAME, PROGNAME);
338 }