Code

This floorf workaround is Nnot needed anymore since floorf is part of Gnulib
[nagiosplug.git] / plugins / check_swap.c
1 /*****************************************************************************
2
3 * Nagios check_disk plugin
4
5 * License: GPL
6 * Copyright (c) 2000 Karl DeBisschop (kdebisschop@users.sourceforge.net)
7 * Copyright (c) 2000-2007 Nagios Plugins Development Team
8
9 * Last Modified: $Date$
10
11 * Description:
12
13 * This file contains the check_disk plugin
14
15
16 * This program is free software: you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation, either version 3 of the License, or
19 * (at your option) any later version.
20
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24 * GNU General Public License for more details.
25
26 * You should have received a copy of the GNU General Public License
27 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
28
29 * $Id$
30
31 *****************************************************************************/
33 const char *progname = "check_swap";
34 const char *revision = "$Revision$";
35 const char *copyright = "2000-2007";
36 const char *email = "nagiosplug-devel@lists.sourceforge.net";
38 #include "common.h"
39 #include "popen.h"
40 #include "utils.h"
42 #ifdef HAVE_DECL_SWAPCTL
43 # ifdef HAVE_SYS_PARAM_H
44 #  include <sys/param.h>
45 # endif
46 # ifdef HAVE_SYS_SWAP_H
47 #  include <sys/swap.h>
48 # endif
49 # ifdef HAVE_SYS_STAT_H
50 #  include <sys/stat.h>
51 # endif
52 #endif
54 #ifndef SWAP_CONVERSION
55 # define SWAP_CONVERSION 1
56 #endif
58 int check_swap (int usp, float free_swap_mb);
59 int process_arguments (int argc, char **argv);
60 int validate_arguments (void);
61 void print_usage (void);
62 void print_help (void);
64 int warn_percent = 0;
65 int crit_percent = 0;
66 float warn_size_bytes = 0;
67 float crit_size_bytes= 0;
68 int verbose;
69 int allswaps;
71 int
72 main (int argc, char **argv)
73 {
74         int percent_used, percent;
75         float total_swap_mb = 0, used_swap_mb = 0, free_swap_mb = 0;
76         float dsktotal_mb = 0, dskused_mb = 0, dskfree_mb = 0, tmp_mb = 0;
77         int result = STATE_UNKNOWN;
78         char input_buffer[MAX_INPUT_BUFFER];
79 #ifdef HAVE_PROC_MEMINFO
80         FILE *fp;
81 #else
82         int conv_factor = SWAP_CONVERSION;
83 # ifdef HAVE_SWAP
84         char *temp_buffer;
85         char *swap_command;
86         char *swap_format;
87 # else
88 #  ifdef HAVE_DECL_SWAPCTL
89         int i=0, nswaps=0, swapctl_res=0;
90 #   ifdef CHECK_SWAP_SWAPCTL_SVR4
91         swaptbl_t *tbl=NULL;
92         swapent_t *ent=NULL;
93 #   else
94 #    ifdef CHECK_SWAP_SWAPCTL_BSD
95         struct swapent *ent;
96 #    endif /* CHECK_SWAP_SWAPCTL_BSD */
97 #   endif /* CHECK_SWAP_SWAPCTL_SVR4 */
98 #  endif /* HAVE_DECL_SWAPCTL */
99 # endif
100 #endif
101         char str[32];
102         char *status;
104         setlocale (LC_ALL, "");
105         bindtextdomain (PACKAGE, LOCALEDIR);
106         textdomain (PACKAGE);
108         status = strdup ("");
110         if (process_arguments (argc, argv) == ERROR)
111                 usage4 (_("Could not parse arguments"));
113 #ifdef HAVE_PROC_MEMINFO
114         if (verbose >= 3) {
115                 printf("Reading PROC_MEMINFO at %s\n", PROC_MEMINFO);
116         }
117         fp = fopen (PROC_MEMINFO, "r");
118         while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, fp)) {
119                 if (sscanf (input_buffer, "%*[S]%*[w]%*[a]%*[p]%*[:] %f %f %f", &dsktotal_mb, &dskused_mb, &dskfree_mb) == 3) {
120                         dsktotal_mb = dsktotal_mb / 1048576;    /* Apply conversion */
121                         dskused_mb = dskused_mb / 1048576;
122                         dskfree_mb = dskfree_mb / 1048576;
123                         total_swap_mb += dsktotal_mb;
124                         used_swap_mb += dskused_mb;
125                         free_swap_mb += dskfree_mb;
126                         if (allswaps) {
127                                 if (dsktotal_mb == 0)
128                                         percent=100.0;
129                                 else
130                                         percent = 100 * (((double) dskused_mb) / ((double) dsktotal_mb));
131                                 result = max_state (result, check_swap (percent, dskfree_mb));
132                                 if (verbose)
133                                         asprintf (&status, "%s [%.0f (%d%%)]", status, dskfree_mb, 100 - percent);
134                         }
135                 }
136                 else if (sscanf (input_buffer, "%*[S]%*[w]%*[a]%*[p]%[TotalFre]%*[:] %f %*[k]%*[B]", str, &tmp_mb)) {
137                         if (verbose >= 3) {
138                                 printf("Got %s with %f\n", str, tmp_mb);
139                         }
140                         /* I think this part is always in Kb, so convert to mb */
141                         if (strcmp ("Total", str) == 0) {
142                                 dsktotal_mb = tmp_mb / 1024;
143                         }
144                         else if (strcmp ("Free", str) == 0) {
145                                 dskfree_mb = tmp_mb / 1024;
146                         }
147                 }
148         }
149         fclose(fp);
150         dskused_mb = dsktotal_mb - dskfree_mb;
151         total_swap_mb = dsktotal_mb;
152         used_swap_mb = dskused_mb;
153         free_swap_mb = dskfree_mb;
154 #else
155 # ifdef HAVE_SWAP
156         asprintf(&swap_command, "%s", SWAP_COMMAND);
157         asprintf(&swap_format, "%s", SWAP_FORMAT);
159 /* These override the command used if a summary (and thus ! allswaps) is required */
160 /* The summary flag returns more accurate information about swap usage on these OSes */
161 #  ifdef _AIX
162         if (!allswaps) {
163                 asprintf(&swap_command, "%s", "/usr/sbin/lsps -s");
164                 asprintf(&swap_format, "%s", "%f%*s %f");
165                 conv_factor = 1;
166         }
167 #  endif
169         if (verbose >= 2)
170                 printf (_("Command: %s\n"), swap_command);
171         if (verbose >= 3)
172                 printf (_("Format: %s\n"), swap_format);
174         child_process = spopen (swap_command);
175         if (child_process == NULL) {
176                 printf (_("Could not open pipe: %s\n"), swap_command);
177                 return STATE_UNKNOWN;
178         }
180         child_stderr = fdopen (child_stderr_array[fileno (child_process)], "r");
181         if (child_stderr == NULL)
182                 printf (_("Could not open stderr for %s\n"), swap_command);
184         sprintf (str, "%s", "");
185         /* read 1st line */
186         fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process);
187         if (strcmp (swap_format, "") == 0) {
188                 temp_buffer = strtok (input_buffer, " \n");
189                 while (temp_buffer) {
190                         if (strstr (temp_buffer, "blocks"))
191                                 sprintf (str, "%s %s", str, "%f");
192                         else if (strstr (temp_buffer, "dskfree"))
193                                 sprintf (str, "%s %s", str, "%f");
194                         else
195                                 sprintf (str, "%s %s", str, "%*s");
196                         temp_buffer = strtok (NULL, " \n");
197                 }
198         }
200 /* If different swap command is used for summary switch, need to read format differently */
201 #  ifdef _AIX
202         if (!allswaps) {
203                 fgets(input_buffer, MAX_INPUT_BUFFER - 1, child_process);       /* Ignore first line */
204                 sscanf (input_buffer, swap_format, &total_swap_mb, &used_swap_mb);
205                 free_swap_mb = total_swap_mb * (100 - used_swap_mb) /100;
206                 used_swap_mb = total_swap_mb - free_swap_mb;
207                 if (verbose >= 3)
208                         printf (_("total=%.0f, used=%.0f, free=%.0f\n"), total_swap_mb, used_swap_mb, free_swap_mb);
209         } else {
210 #  endif
211                 while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process)) {
212                         sscanf (input_buffer, swap_format, &dsktotal_mb, &dskfree_mb);
214                         dsktotal_mb = dsktotal_mb / conv_factor;
215                         /* AIX lists percent used, so this converts to dskfree in MBs */
216 #  ifdef _AIX
217                         dskfree_mb = dsktotal_mb * (100 - dskfree_mb) / 100;
218 #  else
219                         dskfree_mb = dskfree_mb / conv_factor;
220 #  endif
221                         if (verbose >= 3)
222                                 printf (_("total=%.0f, free=%.0f\n"), dsktotal_mb, dskfree_mb);
224                         dskused_mb = dsktotal_mb - dskfree_mb;
225                         total_swap_mb += dsktotal_mb;
226                         used_swap_mb += dskused_mb;
227                         free_swap_mb += dskfree_mb;
228                         if (allswaps) {
229                                 percent = 100 * (((double) dskused_mb) / ((double) dsktotal_mb));
230                                 result = max_state (result, check_swap (percent, dskfree_mb));
231                                 if (verbose)
232                                         asprintf (&status, "%s [%.0f (%d%%)]", status, dskfree_mb, 100 - percent);
233                         }
234                 }
235 #  ifdef _AIX
236         }
237 #  endif
239         /* If we get anything on STDERR, at least set warning */
240         while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_stderr))
241                 result = max_state (result, STATE_WARNING);
243         /* close stderr */
244         (void) fclose (child_stderr);
246         /* close the pipe */
247         if (spclose (child_process))
248                 result = max_state (result, STATE_WARNING);
249 # else
250 #  ifdef CHECK_SWAP_SWAPCTL_SVR4
252         /* get the number of active swap devices */
253         if((nswaps=swapctl(SC_GETNSWP, NULL))== -1)
254                 die(STATE_UNKNOWN, _("Error getting swap devices\n") );
256         if(nswaps == 0)
257                 die(STATE_OK, _("SWAP OK: No swap devices defined\n"));
259         if(verbose >= 3)
260                 printf("Found %d swap device(s)\n", nswaps);
262         /* initialize swap table + entries */
263         tbl=(swaptbl_t*)malloc(sizeof(swaptbl_t)+(sizeof(swapent_t)*nswaps));
265         if(tbl==NULL)
266                 die(STATE_UNKNOWN, _("malloc() failed!\n"));
268         memset(tbl, 0, sizeof(swaptbl_t)+(sizeof(swapent_t)*nswaps));
269         tbl->swt_n=nswaps;
270         for(i=0;i<nswaps;i++){
271                 if((tbl->swt_ent[i].ste_path=(char*)malloc(sizeof(char)*MAXPATHLEN)) == NULL)
272                         die(STATE_UNKNOWN, _("malloc() failed!\n"));
273         }
275         /* and now, tally 'em up */
276         swapctl_res=swapctl(SC_LIST, tbl);
277         if(swapctl_res < 0){
278                 perror(_("swapctl failed: "));
279                 die(STATE_UNKNOWN, _("Error in swapctl call\n"));
280         }
282         for(i=0;i<nswaps;i++){
283                 dsktotal_mb = (float) tbl->swt_ent[i].ste_pages / SWAP_CONVERSION;
284                 dskfree_mb = (float) tbl->swt_ent[i].ste_free /  SWAP_CONVERSION;
285                 dskused_mb = ( dsktotal_mb - dskfree_mb );
287                 if (verbose >= 3)
288                         printf ("dsktotal_mb=%.0f dskfree_mb=%.0f dskused_mb=%.0f\n", dsktotal_mb, dskfree_mb, dskused_mb);
290                 if(allswaps && dsktotal_mb > 0){
291                         percent = 100 * (((double) dskused_mb) / ((double) dsktotal_mb));
292                         result = max_state (result, check_swap (percent, dskfree_mb));
293                         if (verbose) {
294                                 asprintf (&status, "%s [%.0f (%d%%)]", status, dskfree_mb, 100 - percent);
295                         }
296                 }
298                 total_swap_mb += dsktotal_mb;
299                 free_swap_mb += dskfree_mb;
300                 used_swap_mb += dskused_mb;
301         }
303         /* and clean up after ourselves */
304         for(i=0;i<nswaps;i++){
305                 free(tbl->swt_ent[i].ste_path);
306         }
307         free(tbl);
308 #  else
309 #   ifdef CHECK_SWAP_SWAPCTL_BSD
311         /* get the number of active swap devices */
312         nswaps=swapctl(SWAP_NSWAP, NULL, 0);
314         /* initialize swap table + entries */
315         ent=(struct swapent*)malloc(sizeof(struct swapent)*nswaps);
317         /* and now, tally 'em up */
318         swapctl_res=swapctl(SWAP_STATS, ent, nswaps);
319         if(swapctl_res < 0){
320                 perror(_("swapctl failed: "));
321                 die(STATE_UNKNOWN, _("Error in swapctl call\n"));
322         }
324         for(i=0;i<nswaps;i++){
325                 dsktotal_mb = (float) ent[i].se_nblks / conv_factor;
326                 dskused_mb = (float) ent[i].se_inuse / conv_factor;
327                 dskfree_mb = ( dsktotal_mb - dskused_mb );
329                 if(allswaps && dsktotal_mb > 0){
330                         percent = 100 * (((double) dskused_mb) / ((double) dsktotal_mb));
331                         result = max_state (result, check_swap (percent, dskfree_mb));
332                         if (verbose) {
333                                 asprintf (&status, "%s [%.0f (%d%%)]", status, dskfree_mb, 100 - percent);
334                         }
335                 }
337                 total_swap_mb += dsktotal_mb;
338                 free_swap_mb += dskfree_mb;
339                 used_swap_mb += dskused_mb;
340         }
342         /* and clean up after ourselves */
343         free(ent);
345 #   endif /* CHECK_SWAP_SWAPCTL_BSD */
346 #  endif /* CHECK_SWAP_SWAPCTL_SVR4 */
347 # endif /* HAVE_SWAP */
348 #endif /* HAVE_PROC_MEMINFO */
350         /* if total_swap_mb == 0, let's not divide by 0 */
351         if(total_swap_mb) {
352                 percent_used = 100 * ((double) used_swap_mb) / ((double) total_swap_mb);
353         } else {
354                 percent_used = 0;
355         }
357         result = max_state (result, check_swap (percent_used, free_swap_mb));
358         printf (_("SWAP %s - %d%% free (%d MB out of %d MB) %s|"),
359                         state_text (result),
360                         (100 - percent_used), (int) free_swap_mb, (int) total_swap_mb, status);
362         puts (perfdata ("swap", (long) free_swap_mb, "MB",
363                         TRUE, (long) max (warn_size_bytes/(1024 * 1024), warn_percent/100.0*total_swap_mb),
364                         TRUE, (long) max (crit_size_bytes/(1024 * 1024), crit_percent/100.0*total_swap_mb),
365                         TRUE, 0,
366                         TRUE, (long) total_swap_mb));
368         return result;
373 int
374 check_swap (int usp, float free_swap_mb)
376         int result = STATE_UNKNOWN;
377         float free_swap = free_swap_mb * (1024 * 1024);         /* Convert back to bytes as warn and crit specified in bytes */
378         if (usp >= 0 && crit_percent != 0 && usp >= (100.0 - crit_percent))
379                 result = STATE_CRITICAL;
380         else if (crit_size_bytes > 0 && free_swap <= crit_size_bytes)
381                 result = STATE_CRITICAL;
382         else if (usp >= 0 && warn_percent != 0 && usp >= (100.0 - warn_percent))
383                 result = STATE_WARNING;
384         else if (warn_size_bytes > 0 && free_swap <= warn_size_bytes)
385                 result = STATE_WARNING;
386         else if (usp >= 0.0)
387                 result = STATE_OK;
388         return result;
393 /* process command-line arguments */
394 int
395 process_arguments (int argc, char **argv)
397         int c = 0;  /* option character */
399         int option = 0;
400         static struct option longopts[] = {
401                 {"warning", required_argument, 0, 'w'},
402                 {"critical", required_argument, 0, 'c'},
403                 {"allswaps", no_argument, 0, 'a'},
404                 {"verbose", no_argument, 0, 'v'},
405                 {"version", no_argument, 0, 'V'},
406                 {"help", no_argument, 0, 'h'},
407                 {0, 0, 0, 0}
408         };
410         if (argc < 2)
411                 return ERROR;
413         while (1) {
414                 c = getopt_long (argc, argv, "+?Vvhac:w:", longopts, &option);
416                 if (c == -1 || c == EOF)
417                         break;
419                 switch (c) {
420                 case 'w':                                                                       /* warning size threshold */
421                         if (is_intnonneg (optarg)) {
422                                 warn_size_bytes = (float) atoi (optarg);
423                                 break;
424                         }
425                         else if (strstr (optarg, ",") &&
426                                                          strstr (optarg, "%") &&
427                                                          sscanf (optarg, "%f,%d%%", &warn_size_bytes, &warn_percent) == 2) {
428                                 warn_size_bytes = floorf(warn_size_bytes);
429                                 break;
430                         }
431                         else if (strstr (optarg, "%") &&
432                                                          sscanf (optarg, "%d%%", &warn_percent) == 1) {
433                                 break;
434                         }
435                         else {
436                                 usage4 (_("Warning threshold must be integer or percentage!"));
437                         }
438                 case 'c':                                                                       /* critical size threshold */
439                         if (is_intnonneg (optarg)) {
440                                 crit_size_bytes = (float) atoi (optarg);
441                                 break;
442                         }
443                         else if (strstr (optarg, ",") &&
444                                                          strstr (optarg, "%") &&
445                                                          sscanf (optarg, "%f,%d%%", &crit_size_bytes, &crit_percent) == 2) {
446                                 crit_size_bytes = floorf(crit_size_bytes);
447                                 break;
448                         }
449                         else if (strstr (optarg, "%") &&
450                                                          sscanf (optarg, "%d%%", &crit_percent) == 1) {
451                                 break;
452                         }
453                         else {
454                                 usage4 (_("Critical threshold must be integer or percentage!"));
455                         }
456                 case 'a':                                                                       /* all swap */
457                         allswaps = TRUE;
458                         break;
459                 case 'v':                                                                       /* verbose */
460                         verbose++;
461                         break;
462                 case 'V':                                                                       /* version */
463                         print_revision (progname, revision);
464                         exit (STATE_OK);
465                 case 'h':                                                                       /* help */
466                         print_help ();
467                         exit (STATE_OK);
468                 case '?':                                                                       /* error */
469                         usage5 ();
470                 }
471         }
473         c = optind;
474         if (c == argc)
475                 return validate_arguments ();
476         if (warn_percent == 0 && is_intnonneg (argv[c]))
477                 warn_percent = atoi (argv[c++]);
479         if (c == argc)
480                 return validate_arguments ();
481         if (crit_percent == 0 && is_intnonneg (argv[c]))
482                 crit_percent = atoi (argv[c++]);
484         if (c == argc)
485                 return validate_arguments ();
486         if (warn_size_bytes == 0 && is_intnonneg (argv[c]))
487                 warn_size_bytes = (float) atoi (argv[c++]);
489         if (c == argc)
490                 return validate_arguments ();
491         if (crit_size_bytes == 0 && is_intnonneg (argv[c]))
492                 crit_size_bytes = (float) atoi (argv[c++]);
494         return validate_arguments ();
499 int
500 validate_arguments (void)
502         if (warn_percent == 0 && crit_percent == 0 && warn_size_bytes == 0
503                         && crit_size_bytes == 0) {
504                 return ERROR;
505         }
506         else if (warn_percent < crit_percent) {
507                 usage4 
508                         (_("Warning percentage should be more than critical percentage"));
509         }
510         else if (warn_size_bytes < crit_size_bytes) {
511                 usage4
512                         (_("Warning free space should be more than critical free space"));
513         }
514         return OK;
519 void
520 print_help (void)
522         print_revision (progname, revision);
524         printf (_(COPYRIGHT), copyright, email);
526         printf ("%s\n", _("Check swap space on local machine."));
528   printf ("\n\n");
529   
530         print_usage ();
532         printf (_(UT_HELP_VRSN));
534         printf (" %s\n", "-w, --warning=INTEGER");
535   printf ("    %s\n", _("Exit with WARNING status if less than INTEGER bytes of swap space are free"));
536   printf (" %s\n", "-w, --warning=PERCENT%%");
537   printf ("    %s\n", _("Exit with WARNING status if less than PERCENT of swap space is free"));
538   printf (" %s\n", "-c, --critical=INTEGER");
539   printf ("    %s\n", _("Exit with CRITICAL status if less than INTEGER bytes of swap space are free"));
540   printf (" %s\n", "-c, --critical=PERCENT%%");
541   printf ("    %s\n", _("Exit with CRITCAL status if less than PERCENT of swap space is free"));
542   printf (" %s\n", "-a, --allswaps");
543   printf ("    %s\n", _("Conduct comparisons for all swap partitions, one by one"));
544         printf (_(UT_VERBOSE));
545         printf ("\n");
546   printf ("%s\n", _("Notes:"));
547   printf (" %s\n", _("On AIX, if -a is specified, uses lsps -a, otherwise uses lsps -s.\n"));
549         printf (_(UT_SUPPORT));
554 void
555 print_usage (void)
557         printf (_("Usage:"));
558   printf ("%s [-av] -w <percent_free>%% -c <percent_free>%%\n",progname);
559   printf ("%s [-av] -w <bytes_free> -c <bytes_free>\n", progname);