Code

Fix translations when extra-opts aren't enabled
[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 * Description:
10
11 * This file contains the check_disk plugin
12
13
14 * This program is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation, either version 3 of the License, or
17 * (at your option) any later version.
18
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22 * GNU General Public License for more details.
23
24 * You should have received a copy of the GNU General Public License
25 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
26
27
28 *****************************************************************************/
30 const char *progname = "check_swap";
31 const char *copyright = "2000-2007";
32 const char *email = "nagiosplug-devel@lists.sourceforge.net";
34 #include "common.h"
35 #include "popen.h"
36 #include "utils.h"
38 #ifdef HAVE_DECL_SWAPCTL
39 # ifdef HAVE_SYS_PARAM_H
40 #  include <sys/param.h>
41 # endif
42 # ifdef HAVE_SYS_SWAP_H
43 #  include <sys/swap.h>
44 # endif
45 # ifdef HAVE_SYS_STAT_H
46 #  include <sys/stat.h>
47 # endif
48 #endif
50 #ifndef SWAP_CONVERSION
51 # define SWAP_CONVERSION 1
52 #endif
54 int check_swap (int usp, float free_swap_mb);
55 int process_arguments (int argc, char **argv);
56 int validate_arguments (void);
57 void print_usage (void);
58 void print_help (void);
60 int warn_percent = 0;
61 int crit_percent = 0;
62 float warn_size_bytes = 0;
63 float crit_size_bytes= 0;
64 int verbose;
65 int allswaps;
67 int
68 main (int argc, char **argv)
69 {
70         int percent_used, percent;
71         float total_swap_mb = 0, used_swap_mb = 0, free_swap_mb = 0;
72         float dsktotal_mb = 0, dskused_mb = 0, dskfree_mb = 0, tmp_mb = 0;
73         int result = STATE_UNKNOWN;
74         char input_buffer[MAX_INPUT_BUFFER];
75 #ifdef HAVE_PROC_MEMINFO
76         FILE *fp;
77 #else
78         int conv_factor = SWAP_CONVERSION;
79 # ifdef HAVE_SWAP
80         char *temp_buffer;
81         char *swap_command;
82         char *swap_format;
83 # else
84 #  ifdef HAVE_DECL_SWAPCTL
85         int i=0, nswaps=0, swapctl_res=0;
86 #   ifdef CHECK_SWAP_SWAPCTL_SVR4
87         swaptbl_t *tbl=NULL;
88         swapent_t *ent=NULL;
89 #   else
90 #    ifdef CHECK_SWAP_SWAPCTL_BSD
91         struct swapent *ent;
92 #    endif /* CHECK_SWAP_SWAPCTL_BSD */
93 #   endif /* CHECK_SWAP_SWAPCTL_SVR4 */
94 #  endif /* HAVE_DECL_SWAPCTL */
95 # endif
96 #endif
97         char str[32];
98         char *status;
100         setlocale (LC_ALL, "");
101         bindtextdomain (PACKAGE, LOCALEDIR);
102         textdomain (PACKAGE);
104         status = strdup ("");
106         /* Parse extra opts if any */
107         argv=np_extra_opts (&argc, argv, progname);
109         if (process_arguments (argc, argv) == ERROR)
110                 usage4 (_("Could not parse arguments"));
112 #ifdef HAVE_PROC_MEMINFO
113         if (verbose >= 3) {
114                 printf("Reading PROC_MEMINFO at %s\n", PROC_MEMINFO);
115         }
116         fp = fopen (PROC_MEMINFO, "r");
117         while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, fp)) {
118                 if (sscanf (input_buffer, "%*[S]%*[w]%*[a]%*[p]%*[:] %f %f %f", &dsktotal_mb, &dskused_mb, &dskfree_mb) == 3) {
119                         dsktotal_mb = dsktotal_mb / 1048576;    /* Apply conversion */
120                         dskused_mb = dskused_mb / 1048576;
121                         dskfree_mb = dskfree_mb / 1048576;
122                         total_swap_mb += dsktotal_mb;
123                         used_swap_mb += dskused_mb;
124                         free_swap_mb += dskfree_mb;
125                         if (allswaps) {
126                                 if (dsktotal_mb == 0)
127                                         percent=100.0;
128                                 else
129                                         percent = 100 * (((double) dskused_mb) / ((double) dsktotal_mb));
130                                 result = max_state (result, check_swap (percent, dskfree_mb));
131                                 if (verbose)
132                                         asprintf (&status, "%s [%.0f (%d%%)]", status, dskfree_mb, 100 - percent);
133                         }
134                 }
135                 else if (sscanf (input_buffer, "%*[S]%*[w]%*[a]%*[p]%[TotalFre]%*[:] %f %*[k]%*[B]", str, &tmp_mb)) {
136                         if (verbose >= 3) {
137                                 printf("Got %s with %f\n", str, tmp_mb);
138                         }
139                         /* I think this part is always in Kb, so convert to mb */
140                         if (strcmp ("Total", str) == 0) {
141                                 dsktotal_mb = tmp_mb / 1024;
142                         }
143                         else if (strcmp ("Free", str) == 0) {
144                                 dskfree_mb = tmp_mb / 1024;
145                         }
146                 }
147         }
148         fclose(fp);
149         dskused_mb = dsktotal_mb - dskfree_mb;
150         total_swap_mb = dsktotal_mb;
151         used_swap_mb = dskused_mb;
152         free_swap_mb = dskfree_mb;
153 #else
154 # ifdef HAVE_SWAP
155         asprintf(&swap_command, "%s", SWAP_COMMAND);
156         asprintf(&swap_format, "%s", SWAP_FORMAT);
158 /* These override the command used if a summary (and thus ! allswaps) is required */
159 /* The summary flag returns more accurate information about swap usage on these OSes */
160 #  ifdef _AIX
161         if (!allswaps) {
162                 asprintf(&swap_command, "%s", "/usr/sbin/lsps -s");
163                 asprintf(&swap_format, "%s", "%f%*s %f");
164                 conv_factor = 1;
165         }
166 #  endif
168         if (verbose >= 2)
169                 printf (_("Command: %s\n"), swap_command);
170         if (verbose >= 3)
171                 printf (_("Format: %s\n"), swap_format);
173         child_process = spopen (swap_command);
174         if (child_process == NULL) {
175                 printf (_("Could not open pipe: %s\n"), swap_command);
176                 return STATE_UNKNOWN;
177         }
179         child_stderr = fdopen (child_stderr_array[fileno (child_process)], "r");
180         if (child_stderr == NULL)
181                 printf (_("Could not open stderr for %s\n"), swap_command);
183         sprintf (str, "%s", "");
184         /* read 1st line */
185         fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process);
186         if (strcmp (swap_format, "") == 0) {
187                 temp_buffer = strtok (input_buffer, " \n");
188                 while (temp_buffer) {
189                         if (strstr (temp_buffer, "blocks"))
190                                 sprintf (str, "%s %s", str, "%f");
191                         else if (strstr (temp_buffer, "dskfree"))
192                                 sprintf (str, "%s %s", str, "%f");
193                         else
194                                 sprintf (str, "%s %s", str, "%*s");
195                         temp_buffer = strtok (NULL, " \n");
196                 }
197         }
199 /* If different swap command is used for summary switch, need to read format differently */
200 #  ifdef _AIX
201         if (!allswaps) {
202                 fgets(input_buffer, MAX_INPUT_BUFFER - 1, child_process);       /* Ignore first line */
203                 sscanf (input_buffer, swap_format, &total_swap_mb, &used_swap_mb);
204                 free_swap_mb = total_swap_mb * (100 - used_swap_mb) /100;
205                 used_swap_mb = total_swap_mb - free_swap_mb;
206                 if (verbose >= 3)
207                         printf (_("total=%.0f, used=%.0f, free=%.0f\n"), total_swap_mb, used_swap_mb, free_swap_mb);
208         } else {
209 #  endif
210                 while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process)) {
211                         sscanf (input_buffer, swap_format, &dsktotal_mb, &dskfree_mb);
213                         dsktotal_mb = dsktotal_mb / conv_factor;
214                         /* AIX lists percent used, so this converts to dskfree in MBs */
215 #  ifdef _AIX
216                         dskfree_mb = dsktotal_mb * (100 - dskfree_mb) / 100;
217 #  else
218                         dskfree_mb = dskfree_mb / conv_factor;
219 #  endif
220                         if (verbose >= 3)
221                                 printf (_("total=%.0f, free=%.0f\n"), dsktotal_mb, dskfree_mb);
223                         dskused_mb = dsktotal_mb - dskfree_mb;
224                         total_swap_mb += dsktotal_mb;
225                         used_swap_mb += dskused_mb;
226                         free_swap_mb += dskfree_mb;
227                         if (allswaps) {
228                                 percent = 100 * (((double) dskused_mb) / ((double) dsktotal_mb));
229                                 result = max_state (result, check_swap (percent, dskfree_mb));
230                                 if (verbose)
231                                         asprintf (&status, "%s [%.0f (%d%%)]", status, dskfree_mb, 100 - percent);
232                         }
233                 }
234 #  ifdef _AIX
235         }
236 #  endif
238         /* If we get anything on STDERR, at least set warning */
239         while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_stderr))
240                 result = max_state (result, STATE_WARNING);
242         /* close stderr */
243         (void) fclose (child_stderr);
245         /* close the pipe */
246         if (spclose (child_process))
247                 result = max_state (result, STATE_WARNING);
248 # else
249 #  ifdef CHECK_SWAP_SWAPCTL_SVR4
251         /* get the number of active swap devices */
252         if((nswaps=swapctl(SC_GETNSWP, NULL))== -1)
253                 die(STATE_UNKNOWN, _("Error getting swap devices\n") );
255         if(nswaps == 0)
256                 die(STATE_OK, _("SWAP OK: No swap devices defined\n"));
258         if(verbose >= 3)
259                 printf("Found %d swap device(s)\n", nswaps);
261         /* initialize swap table + entries */
262         tbl=(swaptbl_t*)malloc(sizeof(swaptbl_t)+(sizeof(swapent_t)*nswaps));
264         if(tbl==NULL)
265                 die(STATE_UNKNOWN, _("malloc() failed!\n"));
267         memset(tbl, 0, sizeof(swaptbl_t)+(sizeof(swapent_t)*nswaps));
268         tbl->swt_n=nswaps;
269         for(i=0;i<nswaps;i++){
270                 if((tbl->swt_ent[i].ste_path=(char*)malloc(sizeof(char)*MAXPATHLEN)) == NULL)
271                         die(STATE_UNKNOWN, _("malloc() failed!\n"));
272         }
274         /* and now, tally 'em up */
275         swapctl_res=swapctl(SC_LIST, tbl);
276         if(swapctl_res < 0){
277                 perror(_("swapctl failed: "));
278                 die(STATE_UNKNOWN, _("Error in swapctl call\n"));
279         }
281         for(i=0;i<nswaps;i++){
282                 dsktotal_mb = (float) tbl->swt_ent[i].ste_pages / SWAP_CONVERSION;
283                 dskfree_mb = (float) tbl->swt_ent[i].ste_free /  SWAP_CONVERSION;
284                 dskused_mb = ( dsktotal_mb - dskfree_mb );
286                 if (verbose >= 3)
287                         printf ("dsktotal_mb=%.0f dskfree_mb=%.0f dskused_mb=%.0f\n", dsktotal_mb, dskfree_mb, dskused_mb);
289                 if(allswaps && dsktotal_mb > 0){
290                         percent = 100 * (((double) dskused_mb) / ((double) dsktotal_mb));
291                         result = max_state (result, check_swap (percent, dskfree_mb));
292                         if (verbose) {
293                                 asprintf (&status, "%s [%.0f (%d%%)]", status, dskfree_mb, 100 - percent);
294                         }
295                 }
297                 total_swap_mb += dsktotal_mb;
298                 free_swap_mb += dskfree_mb;
299                 used_swap_mb += dskused_mb;
300         }
302         /* and clean up after ourselves */
303         for(i=0;i<nswaps;i++){
304                 free(tbl->swt_ent[i].ste_path);
305         }
306         free(tbl);
307 #  else
308 #   ifdef CHECK_SWAP_SWAPCTL_BSD
310         /* get the number of active swap devices */
311         nswaps=swapctl(SWAP_NSWAP, NULL, 0);
313         /* initialize swap table + entries */
314         ent=(struct swapent*)malloc(sizeof(struct swapent)*nswaps);
316         /* and now, tally 'em up */
317         swapctl_res=swapctl(SWAP_STATS, ent, nswaps);
318         if(swapctl_res < 0){
319                 perror(_("swapctl failed: "));
320                 die(STATE_UNKNOWN, _("Error in swapctl call\n"));
321         }
323         for(i=0;i<nswaps;i++){
324                 dsktotal_mb = (float) ent[i].se_nblks / conv_factor;
325                 dskused_mb = (float) ent[i].se_inuse / conv_factor;
326                 dskfree_mb = ( dsktotal_mb - dskused_mb );
328                 if(allswaps && dsktotal_mb > 0){
329                         percent = 100 * (((double) dskused_mb) / ((double) dsktotal_mb));
330                         result = max_state (result, check_swap (percent, dskfree_mb));
331                         if (verbose) {
332                                 asprintf (&status, "%s [%.0f (%d%%)]", status, dskfree_mb, 100 - percent);
333                         }
334                 }
336                 total_swap_mb += dsktotal_mb;
337                 free_swap_mb += dskfree_mb;
338                 used_swap_mb += dskused_mb;
339         }
341         /* and clean up after ourselves */
342         free(ent);
344 #   endif /* CHECK_SWAP_SWAPCTL_BSD */
345 #  endif /* CHECK_SWAP_SWAPCTL_SVR4 */
346 # endif /* HAVE_SWAP */
347 #endif /* HAVE_PROC_MEMINFO */
349         /* if total_swap_mb == 0, let's not divide by 0 */
350         if(total_swap_mb) {
351                 percent_used = 100 * ((double) used_swap_mb) / ((double) total_swap_mb);
352         } else {
353                 percent_used = 0;
354         }
356         result = max_state (result, check_swap (percent_used, free_swap_mb));
357         printf (_("SWAP %s - %d%% free (%d MB out of %d MB) %s|"),
358                         state_text (result),
359                         (100 - percent_used), (int) free_swap_mb, (int) total_swap_mb, status);
361         puts (perfdata ("swap", (long) free_swap_mb, "MB",
362                         TRUE, (long) max (warn_size_bytes/(1024 * 1024), warn_percent/100.0*total_swap_mb),
363                         TRUE, (long) max (crit_size_bytes/(1024 * 1024), crit_percent/100.0*total_swap_mb),
364                         TRUE, 0,
365                         TRUE, (long) total_swap_mb));
367         return result;
372 int
373 check_swap (int usp, float free_swap_mb)
375         int result = STATE_UNKNOWN;
376         float free_swap = free_swap_mb * (1024 * 1024);         /* Convert back to bytes as warn and crit specified in bytes */
377         if (usp >= 0 && crit_percent != 0 && usp >= (100.0 - crit_percent))
378                 result = STATE_CRITICAL;
379         else if (crit_size_bytes > 0 && free_swap <= crit_size_bytes)
380                 result = STATE_CRITICAL;
381         else if (usp >= 0 && warn_percent != 0 && usp >= (100.0 - warn_percent))
382                 result = STATE_WARNING;
383         else if (warn_size_bytes > 0 && free_swap <= warn_size_bytes)
384                 result = STATE_WARNING;
385         else if (usp >= 0.0)
386                 result = STATE_OK;
387         return result;
392 /* process command-line arguments */
393 int
394 process_arguments (int argc, char **argv)
396         int c = 0;  /* option character */
398         int option = 0;
399         static struct option longopts[] = {
400                 {"warning", required_argument, 0, 'w'},
401                 {"critical", required_argument, 0, 'c'},
402                 {"allswaps", no_argument, 0, 'a'},
403                 {"verbose", no_argument, 0, 'v'},
404                 {"version", no_argument, 0, 'V'},
405                 {"help", no_argument, 0, 'h'},
406                 {0, 0, 0, 0}
407         };
409         if (argc < 2)
410                 return ERROR;
412         while (1) {
413                 c = getopt_long (argc, argv, "+?Vvhac:w:", longopts, &option);
415                 if (c == -1 || c == EOF)
416                         break;
418                 switch (c) {
419                 case 'w':                                                                       /* warning size threshold */
420                         if (is_intnonneg (optarg)) {
421                                 warn_size_bytes = (float) atoi (optarg);
422                                 break;
423                         }
424                         else if (strstr (optarg, ",") &&
425                                                          strstr (optarg, "%") &&
426                                                          sscanf (optarg, "%f,%d%%", &warn_size_bytes, &warn_percent) == 2) {
427                                 warn_size_bytes = floorf(warn_size_bytes);
428                                 break;
429                         }
430                         else if (strstr (optarg, "%") &&
431                                                          sscanf (optarg, "%d%%", &warn_percent) == 1) {
432                                 break;
433                         }
434                         else {
435                                 usage4 (_("Warning threshold must be integer or percentage!"));
436                         }
437                 case 'c':                                                                       /* critical size threshold */
438                         if (is_intnonneg (optarg)) {
439                                 crit_size_bytes = (float) atoi (optarg);
440                                 break;
441                         }
442                         else if (strstr (optarg, ",") &&
443                                                          strstr (optarg, "%") &&
444                                                          sscanf (optarg, "%f,%d%%", &crit_size_bytes, &crit_percent) == 2) {
445                                 crit_size_bytes = floorf(crit_size_bytes);
446                                 break;
447                         }
448                         else if (strstr (optarg, "%") &&
449                                                          sscanf (optarg, "%d%%", &crit_percent) == 1) {
450                                 break;
451                         }
452                         else {
453                                 usage4 (_("Critical threshold must be integer or percentage!"));
454                         }
455                 case 'a':                                                                       /* all swap */
456                         allswaps = TRUE;
457                         break;
458                 case 'v':                                                                       /* verbose */
459                         verbose++;
460                         break;
461                 case 'V':                                                                       /* version */
462                         print_revision (progname, NP_VERSION);
463                         exit (STATE_OK);
464                 case 'h':                                                                       /* help */
465                         print_help ();
466                         exit (STATE_OK);
467                 case '?':                                                                       /* error */
468                         usage5 ();
469                 }
470         }
472         c = optind;
473         if (c == argc)
474                 return validate_arguments ();
475         if (warn_percent == 0 && is_intnonneg (argv[c]))
476                 warn_percent = atoi (argv[c++]);
478         if (c == argc)
479                 return validate_arguments ();
480         if (crit_percent == 0 && is_intnonneg (argv[c]))
481                 crit_percent = atoi (argv[c++]);
483         if (c == argc)
484                 return validate_arguments ();
485         if (warn_size_bytes == 0 && is_intnonneg (argv[c]))
486                 warn_size_bytes = (float) atoi (argv[c++]);
488         if (c == argc)
489                 return validate_arguments ();
490         if (crit_size_bytes == 0 && is_intnonneg (argv[c]))
491                 crit_size_bytes = (float) atoi (argv[c++]);
493         return validate_arguments ();
498 int
499 validate_arguments (void)
501         if (warn_percent == 0 && crit_percent == 0 && warn_size_bytes == 0
502                         && crit_size_bytes == 0) {
503                 return ERROR;
504         }
505         else if (warn_percent < crit_percent) {
506                 usage4
507                         (_("Warning percentage should be more than critical percentage"));
508         }
509         else if (warn_size_bytes < crit_size_bytes) {
510                 usage4
511                         (_("Warning free space should be more than critical free space"));
512         }
513         return OK;
518 void
519 print_help (void)
521         print_revision (progname, NP_VERSION);
523         printf (_(COPYRIGHT), copyright, email);
525         printf ("%s\n", _("Check swap space on local machine."));
527   printf ("\n\n");
529         print_usage ();
531         printf (UT_HELP_VRSN);
532         printf (UT_EXTRA_OPTS);
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);
546         printf ("\n");
547   printf ("%s\n", _("Notes:"));
548   printf (" %s\n", _("On AIX, if -a is specified, uses lsps -a, otherwise uses lsps -s."));
549 #ifdef NP_EXTRA_OPTS
550   printf ("\n");
551   printf (UT_EXTRA_OPTS_NOTES);
552 #endif
555         printf (UT_SUPPORT);
560 void
561 print_usage (void)
563         printf (_("Usage:"));
564   printf ("%s [-av] -w <percent_free>%% -c <percent_free>%%\n",progname);
565   printf ("%s [-av] -w <bytes_free> -c <bytes_free>\n", progname);