Code

Added support for --extra-opts in all C plugins (disabled by default, see configure...
[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         /* Parse extra opts if any */
111         argv=np_extra_opts (&argc, argv, progname);
113         if (process_arguments (argc, argv) == ERROR)
114                 usage4 (_("Could not parse arguments"));
116 #ifdef HAVE_PROC_MEMINFO
117         if (verbose >= 3) {
118                 printf("Reading PROC_MEMINFO at %s\n", PROC_MEMINFO);
119         }
120         fp = fopen (PROC_MEMINFO, "r");
121         while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, fp)) {
122                 if (sscanf (input_buffer, "%*[S]%*[w]%*[a]%*[p]%*[:] %f %f %f", &dsktotal_mb, &dskused_mb, &dskfree_mb) == 3) {
123                         dsktotal_mb = dsktotal_mb / 1048576;    /* Apply conversion */
124                         dskused_mb = dskused_mb / 1048576;
125                         dskfree_mb = dskfree_mb / 1048576;
126                         total_swap_mb += dsktotal_mb;
127                         used_swap_mb += dskused_mb;
128                         free_swap_mb += dskfree_mb;
129                         if (allswaps) {
130                                 if (dsktotal_mb == 0)
131                                         percent=100.0;
132                                 else
133                                         percent = 100 * (((double) dskused_mb) / ((double) dsktotal_mb));
134                                 result = max_state (result, check_swap (percent, dskfree_mb));
135                                 if (verbose)
136                                         asprintf (&status, "%s [%.0f (%d%%)]", status, dskfree_mb, 100 - percent);
137                         }
138                 }
139                 else if (sscanf (input_buffer, "%*[S]%*[w]%*[a]%*[p]%[TotalFre]%*[:] %f %*[k]%*[B]", str, &tmp_mb)) {
140                         if (verbose >= 3) {
141                                 printf("Got %s with %f\n", str, tmp_mb);
142                         }
143                         /* I think this part is always in Kb, so convert to mb */
144                         if (strcmp ("Total", str) == 0) {
145                                 dsktotal_mb = tmp_mb / 1024;
146                         }
147                         else if (strcmp ("Free", str) == 0) {
148                                 dskfree_mb = tmp_mb / 1024;
149                         }
150                 }
151         }
152         fclose(fp);
153         dskused_mb = dsktotal_mb - dskfree_mb;
154         total_swap_mb = dsktotal_mb;
155         used_swap_mb = dskused_mb;
156         free_swap_mb = dskfree_mb;
157 #else
158 # ifdef HAVE_SWAP
159         asprintf(&swap_command, "%s", SWAP_COMMAND);
160         asprintf(&swap_format, "%s", SWAP_FORMAT);
162 /* These override the command used if a summary (and thus ! allswaps) is required */
163 /* The summary flag returns more accurate information about swap usage on these OSes */
164 #  ifdef _AIX
165         if (!allswaps) {
166                 asprintf(&swap_command, "%s", "/usr/sbin/lsps -s");
167                 asprintf(&swap_format, "%s", "%f%*s %f");
168                 conv_factor = 1;
169         }
170 #  endif
172         if (verbose >= 2)
173                 printf (_("Command: %s\n"), swap_command);
174         if (verbose >= 3)
175                 printf (_("Format: %s\n"), swap_format);
177         child_process = spopen (swap_command);
178         if (child_process == NULL) {
179                 printf (_("Could not open pipe: %s\n"), swap_command);
180                 return STATE_UNKNOWN;
181         }
183         child_stderr = fdopen (child_stderr_array[fileno (child_process)], "r");
184         if (child_stderr == NULL)
185                 printf (_("Could not open stderr for %s\n"), swap_command);
187         sprintf (str, "%s", "");
188         /* read 1st line */
189         fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process);
190         if (strcmp (swap_format, "") == 0) {
191                 temp_buffer = strtok (input_buffer, " \n");
192                 while (temp_buffer) {
193                         if (strstr (temp_buffer, "blocks"))
194                                 sprintf (str, "%s %s", str, "%f");
195                         else if (strstr (temp_buffer, "dskfree"))
196                                 sprintf (str, "%s %s", str, "%f");
197                         else
198                                 sprintf (str, "%s %s", str, "%*s");
199                         temp_buffer = strtok (NULL, " \n");
200                 }
201         }
203 /* If different swap command is used for summary switch, need to read format differently */
204 #  ifdef _AIX
205         if (!allswaps) {
206                 fgets(input_buffer, MAX_INPUT_BUFFER - 1, child_process);       /* Ignore first line */
207                 sscanf (input_buffer, swap_format, &total_swap_mb, &used_swap_mb);
208                 free_swap_mb = total_swap_mb * (100 - used_swap_mb) /100;
209                 used_swap_mb = total_swap_mb - free_swap_mb;
210                 if (verbose >= 3)
211                         printf (_("total=%.0f, used=%.0f, free=%.0f\n"), total_swap_mb, used_swap_mb, free_swap_mb);
212         } else {
213 #  endif
214                 while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process)) {
215                         sscanf (input_buffer, swap_format, &dsktotal_mb, &dskfree_mb);
217                         dsktotal_mb = dsktotal_mb / conv_factor;
218                         /* AIX lists percent used, so this converts to dskfree in MBs */
219 #  ifdef _AIX
220                         dskfree_mb = dsktotal_mb * (100 - dskfree_mb) / 100;
221 #  else
222                         dskfree_mb = dskfree_mb / conv_factor;
223 #  endif
224                         if (verbose >= 3)
225                                 printf (_("total=%.0f, free=%.0f\n"), dsktotal_mb, dskfree_mb);
227                         dskused_mb = dsktotal_mb - dskfree_mb;
228                         total_swap_mb += dsktotal_mb;
229                         used_swap_mb += dskused_mb;
230                         free_swap_mb += dskfree_mb;
231                         if (allswaps) {
232                                 percent = 100 * (((double) dskused_mb) / ((double) dsktotal_mb));
233                                 result = max_state (result, check_swap (percent, dskfree_mb));
234                                 if (verbose)
235                                         asprintf (&status, "%s [%.0f (%d%%)]", status, dskfree_mb, 100 - percent);
236                         }
237                 }
238 #  ifdef _AIX
239         }
240 #  endif
242         /* If we get anything on STDERR, at least set warning */
243         while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_stderr))
244                 result = max_state (result, STATE_WARNING);
246         /* close stderr */
247         (void) fclose (child_stderr);
249         /* close the pipe */
250         if (spclose (child_process))
251                 result = max_state (result, STATE_WARNING);
252 # else
253 #  ifdef CHECK_SWAP_SWAPCTL_SVR4
255         /* get the number of active swap devices */
256         if((nswaps=swapctl(SC_GETNSWP, NULL))== -1)
257                 die(STATE_UNKNOWN, _("Error getting swap devices\n") );
259         if(nswaps == 0)
260                 die(STATE_OK, _("SWAP OK: No swap devices defined\n"));
262         if(verbose >= 3)
263                 printf("Found %d swap device(s)\n", nswaps);
265         /* initialize swap table + entries */
266         tbl=(swaptbl_t*)malloc(sizeof(swaptbl_t)+(sizeof(swapent_t)*nswaps));
268         if(tbl==NULL)
269                 die(STATE_UNKNOWN, _("malloc() failed!\n"));
271         memset(tbl, 0, sizeof(swaptbl_t)+(sizeof(swapent_t)*nswaps));
272         tbl->swt_n=nswaps;
273         for(i=0;i<nswaps;i++){
274                 if((tbl->swt_ent[i].ste_path=(char*)malloc(sizeof(char)*MAXPATHLEN)) == NULL)
275                         die(STATE_UNKNOWN, _("malloc() failed!\n"));
276         }
278         /* and now, tally 'em up */
279         swapctl_res=swapctl(SC_LIST, tbl);
280         if(swapctl_res < 0){
281                 perror(_("swapctl failed: "));
282                 die(STATE_UNKNOWN, _("Error in swapctl call\n"));
283         }
285         for(i=0;i<nswaps;i++){
286                 dsktotal_mb = (float) tbl->swt_ent[i].ste_pages / SWAP_CONVERSION;
287                 dskfree_mb = (float) tbl->swt_ent[i].ste_free /  SWAP_CONVERSION;
288                 dskused_mb = ( dsktotal_mb - dskfree_mb );
290                 if (verbose >= 3)
291                         printf ("dsktotal_mb=%.0f dskfree_mb=%.0f dskused_mb=%.0f\n", dsktotal_mb, dskfree_mb, dskused_mb);
293                 if(allswaps && dsktotal_mb > 0){
294                         percent = 100 * (((double) dskused_mb) / ((double) dsktotal_mb));
295                         result = max_state (result, check_swap (percent, dskfree_mb));
296                         if (verbose) {
297                                 asprintf (&status, "%s [%.0f (%d%%)]", status, dskfree_mb, 100 - percent);
298                         }
299                 }
301                 total_swap_mb += dsktotal_mb;
302                 free_swap_mb += dskfree_mb;
303                 used_swap_mb += dskused_mb;
304         }
306         /* and clean up after ourselves */
307         for(i=0;i<nswaps;i++){
308                 free(tbl->swt_ent[i].ste_path);
309         }
310         free(tbl);
311 #  else
312 #   ifdef CHECK_SWAP_SWAPCTL_BSD
314         /* get the number of active swap devices */
315         nswaps=swapctl(SWAP_NSWAP, NULL, 0);
317         /* initialize swap table + entries */
318         ent=(struct swapent*)malloc(sizeof(struct swapent)*nswaps);
320         /* and now, tally 'em up */
321         swapctl_res=swapctl(SWAP_STATS, ent, nswaps);
322         if(swapctl_res < 0){
323                 perror(_("swapctl failed: "));
324                 die(STATE_UNKNOWN, _("Error in swapctl call\n"));
325         }
327         for(i=0;i<nswaps;i++){
328                 dsktotal_mb = (float) ent[i].se_nblks / conv_factor;
329                 dskused_mb = (float) ent[i].se_inuse / conv_factor;
330                 dskfree_mb = ( dsktotal_mb - dskused_mb );
332                 if(allswaps && dsktotal_mb > 0){
333                         percent = 100 * (((double) dskused_mb) / ((double) dsktotal_mb));
334                         result = max_state (result, check_swap (percent, dskfree_mb));
335                         if (verbose) {
336                                 asprintf (&status, "%s [%.0f (%d%%)]", status, dskfree_mb, 100 - percent);
337                         }
338                 }
340                 total_swap_mb += dsktotal_mb;
341                 free_swap_mb += dskfree_mb;
342                 used_swap_mb += dskused_mb;
343         }
345         /* and clean up after ourselves */
346         free(ent);
348 #   endif /* CHECK_SWAP_SWAPCTL_BSD */
349 #  endif /* CHECK_SWAP_SWAPCTL_SVR4 */
350 # endif /* HAVE_SWAP */
351 #endif /* HAVE_PROC_MEMINFO */
353         /* if total_swap_mb == 0, let's not divide by 0 */
354         if(total_swap_mb) {
355                 percent_used = 100 * ((double) used_swap_mb) / ((double) total_swap_mb);
356         } else {
357                 percent_used = 0;
358         }
360         result = max_state (result, check_swap (percent_used, free_swap_mb));
361         printf (_("SWAP %s - %d%% free (%d MB out of %d MB) %s|"),
362                         state_text (result),
363                         (100 - percent_used), (int) free_swap_mb, (int) total_swap_mb, status);
365         puts (perfdata ("swap", (long) free_swap_mb, "MB",
366                         TRUE, (long) max (warn_size_bytes/(1024 * 1024), warn_percent/100.0*total_swap_mb),
367                         TRUE, (long) max (crit_size_bytes/(1024 * 1024), crit_percent/100.0*total_swap_mb),
368                         TRUE, 0,
369                         TRUE, (long) total_swap_mb));
371         return result;
376 int
377 check_swap (int usp, float free_swap_mb)
379         int result = STATE_UNKNOWN;
380         float free_swap = free_swap_mb * (1024 * 1024);         /* Convert back to bytes as warn and crit specified in bytes */
381         if (usp >= 0 && crit_percent != 0 && usp >= (100.0 - crit_percent))
382                 result = STATE_CRITICAL;
383         else if (crit_size_bytes > 0 && free_swap <= crit_size_bytes)
384                 result = STATE_CRITICAL;
385         else if (usp >= 0 && warn_percent != 0 && usp >= (100.0 - warn_percent))
386                 result = STATE_WARNING;
387         else if (warn_size_bytes > 0 && free_swap <= warn_size_bytes)
388                 result = STATE_WARNING;
389         else if (usp >= 0.0)
390                 result = STATE_OK;
391         return result;
396 /* process command-line arguments */
397 int
398 process_arguments (int argc, char **argv)
400         int c = 0;  /* option character */
402         int option = 0;
403         static struct option longopts[] = {
404                 {"warning", required_argument, 0, 'w'},
405                 {"critical", required_argument, 0, 'c'},
406                 {"allswaps", no_argument, 0, 'a'},
407                 {"verbose", no_argument, 0, 'v'},
408                 {"version", no_argument, 0, 'V'},
409                 {"help", no_argument, 0, 'h'},
410                 {0, 0, 0, 0}
411         };
413         if (argc < 2)
414                 return ERROR;
416         while (1) {
417                 c = getopt_long (argc, argv, "+?Vvhac:w:", longopts, &option);
419                 if (c == -1 || c == EOF)
420                         break;
422                 switch (c) {
423                 case 'w':                                                                       /* warning size threshold */
424                         if (is_intnonneg (optarg)) {
425                                 warn_size_bytes = (float) atoi (optarg);
426                                 break;
427                         }
428                         else if (strstr (optarg, ",") &&
429                                                          strstr (optarg, "%") &&
430                                                          sscanf (optarg, "%f,%d%%", &warn_size_bytes, &warn_percent) == 2) {
431                                 warn_size_bytes = floorf(warn_size_bytes);
432                                 break;
433                         }
434                         else if (strstr (optarg, "%") &&
435                                                          sscanf (optarg, "%d%%", &warn_percent) == 1) {
436                                 break;
437                         }
438                         else {
439                                 usage4 (_("Warning threshold must be integer or percentage!"));
440                         }
441                 case 'c':                                                                       /* critical size threshold */
442                         if (is_intnonneg (optarg)) {
443                                 crit_size_bytes = (float) atoi (optarg);
444                                 break;
445                         }
446                         else if (strstr (optarg, ",") &&
447                                                          strstr (optarg, "%") &&
448                                                          sscanf (optarg, "%f,%d%%", &crit_size_bytes, &crit_percent) == 2) {
449                                 crit_size_bytes = floorf(crit_size_bytes);
450                                 break;
451                         }
452                         else if (strstr (optarg, "%") &&
453                                                          sscanf (optarg, "%d%%", &crit_percent) == 1) {
454                                 break;
455                         }
456                         else {
457                                 usage4 (_("Critical threshold must be integer or percentage!"));
458                         }
459                 case 'a':                                                                       /* all swap */
460                         allswaps = TRUE;
461                         break;
462                 case 'v':                                                                       /* verbose */
463                         verbose++;
464                         break;
465                 case 'V':                                                                       /* version */
466                         print_revision (progname, revision);
467                         exit (STATE_OK);
468                 case 'h':                                                                       /* help */
469                         print_help ();
470                         exit (STATE_OK);
471                 case '?':                                                                       /* error */
472                         usage5 ();
473                 }
474         }
476         c = optind;
477         if (c == argc)
478                 return validate_arguments ();
479         if (warn_percent == 0 && is_intnonneg (argv[c]))
480                 warn_percent = atoi (argv[c++]);
482         if (c == argc)
483                 return validate_arguments ();
484         if (crit_percent == 0 && is_intnonneg (argv[c]))
485                 crit_percent = atoi (argv[c++]);
487         if (c == argc)
488                 return validate_arguments ();
489         if (warn_size_bytes == 0 && is_intnonneg (argv[c]))
490                 warn_size_bytes = (float) atoi (argv[c++]);
492         if (c == argc)
493                 return validate_arguments ();
494         if (crit_size_bytes == 0 && is_intnonneg (argv[c]))
495                 crit_size_bytes = (float) atoi (argv[c++]);
497         return validate_arguments ();
502 int
503 validate_arguments (void)
505         if (warn_percent == 0 && crit_percent == 0 && warn_size_bytes == 0
506                         && crit_size_bytes == 0) {
507                 return ERROR;
508         }
509         else if (warn_percent < crit_percent) {
510                 usage4 
511                         (_("Warning percentage should be more than critical percentage"));
512         }
513         else if (warn_size_bytes < crit_size_bytes) {
514                 usage4
515                         (_("Warning free space should be more than critical free space"));
516         }
517         return OK;
522 void
523 print_help (void)
525         print_revision (progname, revision);
527         printf (_(COPYRIGHT), copyright, email);
529         printf ("%s\n", _("Check swap space on local machine."));
531   printf ("\n\n");
533         print_usage ();
535         printf (_(UT_HELP_VRSN));
536         printf (_(UT_EXTRA_OPTS));
538         printf (" %s\n", "-w, --warning=INTEGER");
539   printf ("    %s\n", _("Exit with WARNING status if less than INTEGER bytes of swap space are free"));
540   printf (" %s\n", "-w, --warning=PERCENT%%");
541   printf ("    %s\n", _("Exit with WARNING status if less than PERCENT of swap space is free"));
542   printf (" %s\n", "-c, --critical=INTEGER");
543   printf ("    %s\n", _("Exit with CRITICAL status if less than INTEGER bytes of swap space are free"));
544   printf (" %s\n", "-c, --critical=PERCENT%%");
545   printf ("    %s\n", _("Exit with CRITCAL status if less than PERCENT of swap space is free"));
546   printf (" %s\n", "-a, --allswaps");
547   printf ("    %s\n", _("Conduct comparisons for all swap partitions, one by one"));
548         printf (_(UT_VERBOSE));
550         printf ("\n");
551   printf ("%s\n", _("Notes:"));
552   printf (" %s\n", _("On AIX, if -a is specified, uses lsps -a, otherwise uses lsps -s."));
553 #ifdef NP_EXTRA_OPTS
554   printf ("\n");
555   printf (_(UT_EXTRA_OPTS_NOTES));
556 #endif
559         printf (_(UT_SUPPORT));
564 void
565 print_usage (void)
567         printf (_("Usage:"));
568   printf ("%s [-av] -w <percent_free>%% -c <percent_free>%%\n",progname);
569   printf ("%s [-av] -w <bytes_free> -c <bytes_free>\n", progname);