summaryrefslogtreecommitdiffstats
path: root/plugins/check_swap.c
diff options
context:
space:
mode:
authorRincewindsHat <12514511+RincewindsHat@users.noreply.github.com>2023-12-13 16:17:47 +0100
committerRincewindsHat <12514511+RincewindsHat@users.noreply.github.com>2023-12-20 10:02:47 +0100
commit3a10773c0918a190c43d1508f9f572709fba25a8 (patch)
treed9535ad46f7b4c514cd469ec97b1ec4a31eaf6cc /plugins/check_swap.c
parentb32d7421ee81faaadb2729ee8b19cec4fd1b1899 (diff)
downloadmonitoring-plugins-3a10773c0918a190c43d1508f9f572709fba25a8.tar.gz
check_swap: Heavily refactored linux part
Diffstat (limited to 'plugins/check_swap.c')
-rw-r--r--plugins/check_swap.c758
1 files changed, 395 insertions, 363 deletions
diff --git a/plugins/check_swap.c b/plugins/check_swap.c
index 9630071a..60309a76 100644
--- a/plugins/check_swap.c
+++ b/plugins/check_swap.c
@@ -56,70 +56,335 @@ typedef struct {
56 uint64_t value; 56 uint64_t value;
57} threshold; 57} threshold;
58 58
59int check_swap (float free_swap_mb, float total_swap_mb); 59typedef struct {
60int process_arguments (int argc, char **argv); 60 unsigned long long free; // Free swap in Bytes!
61int validate_arguments (void); 61 unsigned long long used; // Used swap in Bytes!
62void print_usage (void); 62 unsigned long long total; // Total swap size, you guessed it, in Bytes!
63void print_help (void); 63} swap_metrics;
64 64
65threshold warn; 65typedef struct {
66threshold crit; 66 int errorcode;
67int verbose; 67 int statusCode;
68bool allswaps = false; 68 swap_metrics metrics;
69int no_swap_state = STATE_CRITICAL; 69} swap_result;
70 70
71int 71typedef struct {
72main (int argc, char **argv) 72 int verbose;
73{ 73 bool allswaps;
74 unsigned int percent_used, percent; 74 int no_swap_state;
75 uint64_t total_swap_mb = 0, used_swap_mb = 0, free_swap_mb = 0; 75 threshold warn;
76 uint64_t dsktotal_mb = 0, dskused_mb = 0, dskfree_mb = 0; 76 threshold crit;
77 uint64_t tmp_KB = 0; 77} swap_config;
78 int result = STATE_UNKNOWN; 78
79 char input_buffer[MAX_INPUT_BUFFER]; 79typedef struct {
80#ifdef HAVE_PROC_MEMINFO 80 int errorcode;
81 FILE *fp; 81 swap_config config;
82#else 82} swap_config_wrapper;
83 int conv_factor = SWAP_CONVERSION; 83
84# ifdef HAVE_SWAP 84swap_config_wrapper process_arguments (swap_config_wrapper config, int argc, char **argv);
85 char *temp_buffer; 85void print_usage ();
86 char *swap_command; 86void print_help (swap_config);
87 char *swap_format; 87
88# else 88swap_result getSwapFromProcMeminfo(swap_config config);
89# ifdef HAVE_DECL_SWAPCTL 89swap_result getSwapFromSwapCommand(swap_config config);
90 int i=0, nswaps=0, swapctl_res=0; 90swap_result getSwapFromSwapctl_BSD(swap_config config);
91# ifdef CHECK_SWAP_SWAPCTL_SVR4 91swap_result getSwapFromSwap_SRV4(swap_config config);
92 swaptbl_t *tbl=NULL; 92
93 swapent_t *ent=NULL; 93swap_config swap_config_init() {
94# else 94 swap_config tmp = { 0 };
95# ifdef CHECK_SWAP_SWAPCTL_BSD 95 tmp.allswaps = false;
96 struct swapent *ent; 96 tmp.no_swap_state = STATE_CRITICAL;
97# endif /* CHECK_SWAP_SWAPCTL_BSD */ 97 tmp.verbose = 0;
98# endif /* CHECK_SWAP_SWAPCTL_SVR4 */ 98
99# endif /* HAVE_DECL_SWAPCTL */ 99 return tmp;
100# endif 100}
101#endif
102 char str[32];
103 char *status;
104 101
102
103int main (int argc, char **argv) {
105 setlocale (LC_ALL, ""); 104 setlocale (LC_ALL, "");
106 bindtextdomain (PACKAGE, LOCALEDIR); 105 bindtextdomain (PACKAGE, LOCALEDIR);
107 textdomain (PACKAGE); 106 textdomain (PACKAGE);
108 107
108 char *status;
109 status = strdup (""); 109 status = strdup ("");
110 110
111 /* Parse extra opts if any */ 111 /* Parse extra opts if any */
112 argv=np_extra_opts (&argc, argv, progname); 112 argv=np_extra_opts (&argc, argv, progname);
113 113
114 if (process_arguments (argc, argv) == ERROR) 114 swap_config_wrapper tmp = {
115 .errorcode = OK
116 };
117
118 tmp.config = swap_config_init();
119
120 tmp = process_arguments (tmp, argc, argv);
121
122 if (tmp.errorcode != OK) {
115 usage4 (_("Could not parse arguments")); 123 usage4 (_("Could not parse arguments"));
124 }
125
126 swap_config config = tmp.config;
127
128#ifdef HAVE_PROC_MEMINFO
129 swap_result data = getSwapFromProcMeminfo(config);
130#else
131# ifdef HAVE_SWAP
132 swap_result data = getSwapFromSwapCommand();
133# else
134# ifdef CHECK_SWAP_SWAPCTL_SVR4
135 swap_result data = getSwapFromSwapctl_SRV4();
136# else
137# ifdef CHECK_SWAP_SWAPCTL_BSD
138 swap_result data = getSwapFromSwapctl_BSD();
139# else
140 #error No now found to retrieve swap
141# endif /* CHECK_SWAP_SWAPCTL_BSD */
142# endif /* CHECK_SWAP_SWAPCTL_SVR4 */
143# endif /* HAVE_SWAP */
144#endif /* HAVE_PROC_MEMINFO */
145
146 double percent_used;
147
148 /* if total_swap_mb == 0, let's not divide by 0 */
149 if(data.metrics.total != 0) {
150 percent_used = 100 * ((double) data.metrics.used) / ((double) data.metrics.total);
151 } else {
152 printf (_("SWAP %s - Swap is either disabled, not present, or of zero size."),
153 state_text (data.statusCode));
154 exit(config.no_swap_state);
155 }
156
157 uint64_t warn_print = config.warn.value;
158 if (config.warn.is_percentage) {
159 warn_print = config.warn.value * (data.metrics.total*1024 *1024/100);
160 }
161
162 uint64_t crit_print = config.crit.value;
163 if (config.crit.is_percentage) {
164 crit_print = config.crit.value * (data.metrics.total*1024 *1024/100);
165 }
166
167 char *perfdata = perfdata_uint64 ("swap", data.metrics.free *1024 *1024, "B",
168 true, warn_print,
169 true, crit_print,
170 true, 0,
171 true, (long) data.metrics.total* 1024 * 1024);
172
173 if ((config.warn.is_percentage && (percent_used >= (100 - config.warn.value))) ||
174 config.warn.value >= data.metrics.free) {
175 data.statusCode = max_state (data.statusCode, STATE_WARNING);
176 }
177
178 if ((config.crit.is_percentage && (percent_used >= (100 - config.crit.value))) ||
179 config.crit.value >= data.metrics.free) {
180 data.statusCode = max_state (data.statusCode, STATE_CRITICAL);
181 }
182
183 printf (_("SWAP %s - %g%% free (%lluMB out of %lluMB) %s|%s\n"),
184 state_text (data.statusCode),
185 (100 - percent_used), data.metrics.free, data.metrics.total, status,
186 perfdata);
187
188 exit(data.statusCode);
189}
190
191
192/* process command-line arguments */
193swap_config_wrapper process_arguments (swap_config_wrapper conf_wrapper, int argc, char **argv) {
194 if (argc < 2) {
195 conf_wrapper.errorcode = ERROR;
196 return conf_wrapper;
197 }
198
199 int option = 0;
200 static struct option longopts[] = {
201 {"warning", required_argument, 0, 'w'},
202 {"critical", required_argument, 0, 'c'},
203 {"allswaps", no_argument, 0, 'a'},
204 {"no-swap", required_argument, 0, 'n'},
205 {"verbose", no_argument, 0, 'v'},
206 {"version", no_argument, 0, 'V'},
207 {"help", no_argument, 0, 'h'},
208 {0, 0, 0, 0}
209 };
210
211 int c = 0; /* option character */
212 while (true) {
213 c = getopt_long (argc, argv, "+?Vvhac:w:n:", longopts, &option);
214
215 if (c == -1 || c == EOF)
216 break;
217
218 switch (c) {
219 case 'w': /* warning size threshold */
220 {
221 /*
222 * We expect either a positive integer value without a unit, which means
223 * the unit is Bytes or a positive integer value and a percentage sign (%),
224 * which means the value must be with 0 and 100 and is relative to the total swap
225 */
226 size_t length;
227 length = strlen(optarg);
228
229 if (optarg[length - 1] == '%') {
230 /* It's percentage */
231 conf_wrapper.config.warn.is_percentage = true;
232 optarg[length - 1] = '\0';
233 if (is_uint64(optarg, &conf_wrapper.config.warn.value)) {
234 if (conf_wrapper.config.warn.value > 100) {
235 usage4 (_("Warning threshold percentage must be <= 100!"));
236 }
237 }
238 break;
239 } else {
240 /* It's Bytes */
241 conf_wrapper.config.warn.is_percentage = false;
242 if (is_uint64(optarg, &conf_wrapper.config.warn.value)) {
243 break;
244 } else {
245 usage4 (_("Warning threshold be positive integer or percentage!"));
246 }
247 }
248 }
249 case 'c': /* critical size threshold */
250 {
251 /*
252 * We expect either a positive integer value without a unit, which means
253 * the unit is Bytes or a positive integer value and a percentage sign (%),
254 * which means the value must be with 0 and 100 and is relative to the total swap
255 */
256 size_t length;
257 length = strlen(optarg);
258
259 if (optarg[length - 1] == '%') {
260 /* It's percentage */
261 conf_wrapper.config.crit.is_percentage = true;
262 optarg[length - 1] = '\0';
263 if (is_uint64(optarg, &conf_wrapper.config.crit.value)) {
264 if (conf_wrapper.config.crit.value> 100) {
265 usage4 (_("Critical threshold percentage must be <= 100!"));
266 }
267 }
268 break;
269 } else {
270 /* It's Bytes */
271 conf_wrapper.config.crit.is_percentage = false;
272 if (is_uint64(optarg, &conf_wrapper.config.crit.value)) {
273 break;
274 } else {
275 usage4 (_("Critical threshold be positive integer or percentage!"));
276 }
277 }
278 }
279 case 'a': /* all swap */
280 conf_wrapper.config.allswaps = true;
281 break;
282 case 'n':
283 if ((conf_wrapper.config.no_swap_state = mp_translate_state(optarg)) == ERROR) {
284 usage4 (_("no-swap result must be a valid state name (OK, WARNING, CRITICAL, UNKNOWN) or integer (0-3)."));
285 }
286 break;
287 case 'v': /* verbose */
288 conf_wrapper.config.verbose++;
289 break;
290 case 'V': /* version */
291 print_revision (progname, NP_VERSION);
292 exit (STATE_UNKNOWN);
293 case 'h': /* help */
294 print_help (conf_wrapper.config);
295 exit (STATE_UNKNOWN);
296 case '?': /* error */
297 usage5 ();
298 }
299 }
300
301 c = optind;
302
303 if (conf_wrapper.config.warn.value == 0 && conf_wrapper.config.crit.value == 0) {
304 conf_wrapper.errorcode = ERROR;
305 return conf_wrapper;
306 } else if ((conf_wrapper.config.warn.is_percentage == conf_wrapper.config.crit.is_percentage) &&
307 (conf_wrapper.config.warn.value < conf_wrapper.config.crit.value)) {
308 /* This is NOT triggered if warn and crit are different units, e.g warn is percentage
309 * and crit is absolute. We cannot determine the condition at this point since we
310 * dont know the value of total swap yet
311 */
312 usage4(_("Warning should be more than critical"));
313 }
314
315 return conf_wrapper;
316}
317
318
319void
320print_help (swap_config config)
321{
322 print_revision (progname, NP_VERSION);
323
324 printf (_(COPYRIGHT), copyright, email);
325
326 printf ("%s\n", _("Check swap space on local machine."));
327
328 printf ("\n\n");
329
330 print_usage();
331
332 printf (UT_HELP_VRSN);
333 printf (UT_EXTRA_OPTS);
334
335 printf (" %s\n", "-w, --warning=INTEGER");
336 printf (" %s\n", _("Exit with WARNING status if less than INTEGER bytes of swap space are free"));
337 printf (" %s\n", "-w, --warning=PERCENT%");
338 printf (" %s\n", _("Exit with WARNING status if less than PERCENT of swap space is free"));
339 printf (" %s\n", "-c, --critical=INTEGER");
340 printf (" %s\n", _("Exit with CRITICAL status if less than INTEGER bytes of swap space are free"));
341 printf (" %s\n", "-c, --critical=PERCENT%");
342 printf (" %s\n", _("Exit with CRITICAL status if less than PERCENT of swap space is free"));
343 printf (" %s\n", "-a, --allswaps");
344 printf (" %s\n", _("Conduct comparisons for all swap partitions, one by one"));
345 printf (" %s\n", "-n, --no-swap=<ok|warning|critical|unknown>");
346 printf (" %s %s\n", _("Resulting state when there is no swap regardless of thresholds. Default:"), state_text(config.no_swap_state));
347 printf (UT_VERBOSE);
348
349 printf ("\n");
350 printf ("%s\n", _("Notes:"));
351 printf (" %s\n", _("Both INTEGER and PERCENT thresholds can be specified, they are all checked."));
352 printf (" %s\n", _("On AIX, if -a is specified, uses lsps -a, otherwise uses lsps -s."));
353
354 printf (UT_SUPPORT);
355}
356
357
358void
359print_usage ()
360{
361 printf ("%s\n", _("Usage:"));
362 printf (" %s [-av] -w <percent_free>%% -c <percent_free>%%\n",progname);
363 printf (" -w <bytes_free> -c <bytes_free> [-n <state>]\n");
364}
116 365
117#ifdef HAVE_PROC_MEMINFO 366#ifdef HAVE_PROC_MEMINFO
118 if (verbose >= 3) { 367swap_result getSwapFromProcMeminfo(swap_config config) {
368
369 if (config.verbose >= 3) {
119 printf("Reading PROC_MEMINFO at %s\n", PROC_MEMINFO); 370 printf("Reading PROC_MEMINFO at %s\n", PROC_MEMINFO);
120 } 371 }
372
373 FILE *fp;
121 fp = fopen (PROC_MEMINFO, "r"); 374 fp = fopen (PROC_MEMINFO, "r");
375
376
377 swap_result result = { 0 };
378 result.statusCode = STATE_OK;
379
380 uint64_t dsktotal_mb = 0, dskused_mb = 0, dskfree_mb = 0;
381
382 char input_buffer[MAX_INPUT_BUFFER];
383 char str[32];
384
122 while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, fp)) { 385 while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, fp)) {
386 uint64_t tmp_KB = 0;
387
123 /* 388 /*
124 * The following sscanf call looks for a line looking like: "Swap: 123 123 123" 389 * The following sscanf call looks for a line looking like: "Swap: 123 123 123"
125 * On which kind of system this format exists, I can not say, but I wanted to 390 * On which kind of system this format exists, I can not say, but I wanted to
@@ -129,59 +394,63 @@ main (int argc, char **argv)
129 dsktotal_mb = dsktotal_mb / (1024 * 1024); /* Apply conversion */ 394 dsktotal_mb = dsktotal_mb / (1024 * 1024); /* Apply conversion */
130 dskused_mb = dskused_mb / (1024 * 1024); 395 dskused_mb = dskused_mb / (1024 * 1024);
131 dskfree_mb = dskfree_mb / (1024 * 1024); 396 dskfree_mb = dskfree_mb / (1024 * 1024);
132 total_swap_mb += dsktotal_mb; 397
133 used_swap_mb += dskused_mb; 398 result.metrics.total += dsktotal_mb;
134 free_swap_mb += dskfree_mb; 399 result.metrics.used+= dskused_mb;
135 if (allswaps) { 400 result.metrics.free += dskfree_mb;
136 if (dsktotal_mb == 0) 401
137 percent=100.0; 402
138 else
139 percent = 100 * (((double) dskused_mb) / ((double) dsktotal_mb));
140 result = max_state (result, check_swap (dskfree_mb, dsktotal_mb));
141 if (verbose)
142 xasprintf (&status, "%s [%lu (%d%%)]", status, dskfree_mb, 100 - percent);
143 }
144 }
145 403
146 /* 404 /*
147 * The following sscanf call looks for lines looking like: "SwapTotal: 123" and "SwapFree: 123" 405 * The following sscanf call looks for lines looking like: "SwapTotal: 123" and "SwapFree: 123"
148 * This format exists at least on Debian Linux with a 5.* kernel 406 * This format exists at least on Debian Linux with a 5.* kernel
149 */ 407 */
150 else if (sscanf (input_buffer, "%*[S]%*[w]%*[a]%*[p]%[TotalFreCchd]%*[:] %lu %*[k]%*[B]", str, &tmp_KB)) { 408 } else if (sscanf (input_buffer, "%*[S]%*[w]%*[a]%*[p]%[TotalFreCchd]%*[:] %lu %*[k]%*[B]", str, &tmp_KB)) {
151 if (verbose >= 3) { 409 if (config.verbose >= 3) {
152 printf("Got %s with %lu\n", str, tmp_KB); 410 printf("Got %s with %lu\n", str, tmp_KB);
153 } 411 }
154 /* I think this part is always in Kb, so convert to mb */ 412 /* I think this part is always in Kb, so convert to mb */
155 if (strcmp ("Total", str) == 0) { 413 if (strcmp ("Total", str) == 0) {
156 dsktotal_mb = tmp_KB / 1024; 414 dsktotal_mb = tmp_KB / 1024;
157 } 415 } else if (strcmp ("Free", str) == 0) {
158 else if (strcmp ("Free", str) == 0) {
159 dskfree_mb = dskfree_mb + tmp_KB / 1024; 416 dskfree_mb = dskfree_mb + tmp_KB / 1024;
160 } 417 } else if (strcmp ("Cached", str) == 0) {
161 else if (strcmp ("Cached", str) == 0) {
162 dskfree_mb = dskfree_mb + tmp_KB / 1024; 418 dskfree_mb = dskfree_mb + tmp_KB / 1024;
163 } 419 }
164 } 420 }
165 } 421 }
422
166 fclose(fp); 423 fclose(fp);
167 dskused_mb = dsktotal_mb - dskfree_mb; 424
168 total_swap_mb = dsktotal_mb; 425 result.metrics.total = dsktotal_mb;
169 used_swap_mb = dskused_mb; 426 result.metrics.used = dsktotal_mb - dskfree_mb;
170 free_swap_mb = dskfree_mb; 427 result.metrics.free = dskfree_mb;
171#else 428
172# ifdef HAVE_SWAP 429 return result;
430}
431#endif
432
433#ifdef HAVE_SWAP
434swap_result getSwapFromSwapCommand() {
435 swap_result result = { 0 };
436
437 char *temp_buffer;
438 char *swap_command;
439 char *swap_format;
440 int conv_factor = SWAP_CONVERSION;
441
173 xasprintf(&swap_command, "%s", SWAP_COMMAND); 442 xasprintf(&swap_command, "%s", SWAP_COMMAND);
174 xasprintf(&swap_format, "%s", SWAP_FORMAT); 443 xasprintf(&swap_format, "%s", SWAP_FORMAT);
175 444
176/* These override the command used if a summary (and thus ! allswaps) is required */ 445/* These override the command used if a summary (and thus ! allswaps) is required */
177/* The summary flag returns more accurate information about swap usage on these OSes */ 446/* The summary flag returns more accurate information about swap usage on these OSes */
178# ifdef _AIX 447# ifdef _AIX
179 if (!allswaps) { 448 if (!allswaps) {
180 xasprintf(&swap_command, "%s", "/usr/sbin/lsps -s"); 449 xasprintf(&swap_command, "%s", "/usr/sbin/lsps -s");
181 xasprintf(&swap_format, "%s", "%lu%*s %lu"); 450 xasprintf(&swap_format, "%s", "%lu%*s %lu");
182 conv_factor = 1; 451 conv_factor = 1;
183 } 452 }
184# endif 453# endif
185 454
186 if (verbose >= 2) 455 if (verbose >= 2)
187 printf (_("Command: %s\n"), swap_command); 456 printf (_("Command: %s\n"), swap_command);
@@ -215,7 +484,7 @@ main (int argc, char **argv)
215 } 484 }
216 485
217/* If different swap command is used for summary switch, need to read format differently */ 486/* If different swap command is used for summary switch, need to read format differently */
218# ifdef _AIX 487# ifdef _AIX
219 if (!allswaps) { 488 if (!allswaps) {
220 fgets(input_buffer, MAX_INPUT_BUFFER - 1, child_process); /* Ignore first line */ 489 fgets(input_buffer, MAX_INPUT_BUFFER - 1, child_process); /* Ignore first line */
221 sscanf (input_buffer, swap_format, &total_swap_mb, &used_swap_mb); 490 sscanf (input_buffer, swap_format, &total_swap_mb, &used_swap_mb);
@@ -224,7 +493,7 @@ main (int argc, char **argv)
224 if (verbose >= 3) 493 if (verbose >= 3)
225 printf (_("total=%.0f, used=%.0f, free=%.0f\n"), total_swap_mb, used_swap_mb, free_swap_mb); 494 printf (_("total=%.0f, used=%.0f, free=%.0f\n"), total_swap_mb, used_swap_mb, free_swap_mb);
226 } else { 495 } else {
227# endif 496# endif
228 while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process)) { 497 while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process)) {
229 sscanf (input_buffer, swap_format, &dsktotal_mb, &dskfree_mb); 498 sscanf (input_buffer, swap_format, &dsktotal_mb, &dskfree_mb);
230 499
@@ -263,9 +532,56 @@ main (int argc, char **argv)
263 /* close the pipe */ 532 /* close the pipe */
264 if (spclose (child_process)) 533 if (spclose (child_process))
265 result = max_state (result, STATE_WARNING); 534 result = max_state (result, STATE_WARNING);
266# else 535}
267# ifdef CHECK_SWAP_SWAPCTL_SVR4 536#endif // HAVE_SWAP
537
538#ifdef CHECK_SWAP_SWAPCTL_BSD
539swap_result getSwapFromSwapctl_BSD() {
540 int i=0, nswaps=0, swapctl_res=0;
541 struct swapent *ent;
542 int conv_factor = SWAP_CONVERSION;
543
544 /* get the number of active swap devices */
545 nswaps=swapctl(SWAP_NSWAP, NULL, 0);
546
547 /* initialize swap table + entries */
548 ent=(struct swapent*)malloc(sizeof(struct swapent)*nswaps);
549
550 /* and now, tally 'em up */
551 swapctl_res=swapctl(SWAP_STATS, ent, nswaps);
552 if(swapctl_res < 0){
553 perror(_("swapctl failed: "));
554 die(STATE_UNKNOWN, _("Error in swapctl call\n"));
555 }
556
557 for(i=0;i<nswaps;i++){
558 dsktotal_mb = (float) ent[i].se_nblks / conv_factor;
559 dskused_mb = (float) ent[i].se_inuse / conv_factor;
560 dskfree_mb = ( dsktotal_mb - dskused_mb );
561
562 if(allswaps && dsktotal_mb > 0){
563 percent = 100 * (((double) dskused_mb) / ((double) dsktotal_mb));
564 result = max_state (result, check_swap(dskfree_mb, dsktotal_mb));
565 if (verbose) {
566 xasprintf (&status, "%s [%.0f (%d%%)]", status, dskfree_mb, 100 - percent);
567 }
568 }
569
570 total_swap_mb += dsktotal_mb;
571 free_swap_mb += dskfree_mb;
572 used_swap_mb += dskused_mb;
573 }
268 574
575 /* and clean up after ourselves */
576 free(ent);
577}
578#endif // CHECK_SWAP_SWAPCTL_BSD
579
580#ifdef CHECK_SWAP_SWAPCTL_SVR4
581swap_result getSwapFromSwap_SRV4() {
582 int i=0, nswaps=0, swapctl_res=0;
583 swaptbl_t *tbl=NULL;
584 swapent_t *ent=NULL;
269 /* get the number of active swap devices */ 585 /* get the number of active swap devices */
270 if((nswaps=swapctl(SC_GETNSWP, NULL))== -1) 586 if((nswaps=swapctl(SC_GETNSWP, NULL))== -1)
271 die(STATE_UNKNOWN, _("Error getting swap devices\n") ); 587 die(STATE_UNKNOWN, _("Error getting swap devices\n") );
@@ -322,289 +638,5 @@ main (int argc, char **argv)
322 free(tbl->swt_ent[i].ste_path); 638 free(tbl->swt_ent[i].ste_path);
323 } 639 }
324 free(tbl); 640 free(tbl);
325# else
326# ifdef CHECK_SWAP_SWAPCTL_BSD
327
328 /* get the number of active swap devices */
329 nswaps=swapctl(SWAP_NSWAP, NULL, 0);
330
331 /* initialize swap table + entries */
332 ent=(struct swapent*)malloc(sizeof(struct swapent)*nswaps);
333
334 /* and now, tally 'em up */
335 swapctl_res=swapctl(SWAP_STATS, ent, nswaps);
336 if(swapctl_res < 0){
337 perror(_("swapctl failed: "));
338 die(STATE_UNKNOWN, _("Error in swapctl call\n"));
339 }
340
341 for(i=0;i<nswaps;i++){
342 dsktotal_mb = (float) ent[i].se_nblks / conv_factor;
343 dskused_mb = (float) ent[i].se_inuse / conv_factor;
344 dskfree_mb = ( dsktotal_mb - dskused_mb );
345
346 if(allswaps && dsktotal_mb > 0){
347 percent = 100 * (((double) dskused_mb) / ((double) dsktotal_mb));
348 result = max_state (result, check_swap(dskfree_mb, dsktotal_mb));
349 if (verbose) {
350 xasprintf (&status, "%s [%.0f (%d%%)]", status, dskfree_mb, 100 - percent);
351 }
352 }
353
354 total_swap_mb += dsktotal_mb;
355 free_swap_mb += dskfree_mb;
356 used_swap_mb += dskused_mb;
357 }
358
359 /* and clean up after ourselves */
360 free(ent);
361
362# endif /* CHECK_SWAP_SWAPCTL_BSD */
363# endif /* CHECK_SWAP_SWAPCTL_SVR4 */
364# endif /* HAVE_SWAP */
365#endif /* HAVE_PROC_MEMINFO */
366
367 /* if total_swap_mb == 0, let's not divide by 0 */
368 if(total_swap_mb) {
369 percent_used = 100 * ((double) used_swap_mb) / ((double) total_swap_mb);
370 } else {
371 percent_used = 100;
372 status = "- Swap is either disabled, not present, or of zero size. ";
373 }
374
375 result = max_state (result, check_swap(free_swap_mb, total_swap_mb));
376 printf (_("SWAP %s - %d%% free (%dMB out of %dMB) %s|"),
377 state_text (result),
378 (100 - percent_used), (int) free_swap_mb, (int) total_swap_mb, status);
379
380 uint64_t warn_print = warn.value;
381 if (warn.is_percentage) warn_print = warn.value * (total_swap_mb *1024 *1024/100);
382 uint64_t crit_print = crit.value;
383 if (crit.is_percentage) crit_print = crit.value * (total_swap_mb *1024 *1024/100);
384
385 puts (perfdata_uint64 ("swap", free_swap_mb *1024 *1024, "B",
386 true, warn_print,
387 true, crit_print,
388 true, 0,
389 true, (long) total_swap_mb * 1024 * 1024));
390
391 return result;
392}
393
394
395int
396check_swap(float free_swap_mb, float total_swap_mb)
397{
398
399 if (!total_swap_mb) return no_swap_state;
400
401 uint64_t free_swap = free_swap_mb * (1024 * 1024); /* Convert back to bytes as warn and crit specified in bytes */
402
403 if (!crit.is_percentage && crit.value >= free_swap) return STATE_CRITICAL;
404 if (!warn.is_percentage && warn.value >= free_swap) return STATE_WARNING;
405
406
407 uint64_t usage_percentage = ((total_swap_mb - free_swap_mb) / total_swap_mb) * 100;
408
409 if (crit.is_percentage &&
410 crit.value != 0 &&
411 usage_percentage >= (100 - crit.value))
412 {
413 return STATE_CRITICAL;
414 }
415
416 if (warn.is_percentage &&
417 warn.value != 0 &&
418 usage_percentage >= (100 - warn.value))
419 {
420 return STATE_WARNING;
421 }
422
423 return STATE_OK;
424}
425
426
427
428/* process command-line arguments */
429int
430process_arguments (int argc, char **argv)
431{
432 int c = 0; /* option character */
433
434 int option = 0;
435 static struct option longopts[] = {
436 {"warning", required_argument, 0, 'w'},
437 {"critical", required_argument, 0, 'c'},
438 {"allswaps", no_argument, 0, 'a'},
439 {"no-swap", required_argument, 0, 'n'},
440 {"verbose", no_argument, 0, 'v'},
441 {"version", no_argument, 0, 'V'},
442 {"help", no_argument, 0, 'h'},
443 {0, 0, 0, 0}
444 };
445
446 if (argc < 2)
447 return ERROR;
448
449 while (1) {
450 c = getopt_long (argc, argv, "+?Vvhac:w:n:", longopts, &option);
451
452 if (c == -1 || c == EOF)
453 break;
454
455 switch (c) {
456 case 'w': /* warning size threshold */
457 {
458 /*
459 * We expect either a positive integer value without a unit, which means
460 * the unit is Bytes or a positive integer value and a percentage sign (%),
461 * which means the value must be with 0 and 100 and is relative to the total swap
462 */
463 size_t length;
464 length = strlen(optarg);
465
466 if (optarg[length - 1] == '%') {
467 /* It's percentage */
468 warn.is_percentage = true;
469 optarg[length - 1] = '\0';
470 if (is_uint64(optarg, &warn.value)) {
471 if (warn.value > 100) {
472 usage4 (_("Warning threshold percentage must be <= 100!"));
473 }
474 }
475 break;
476 } else {
477 /* It's Bytes */
478 warn.is_percentage = false;
479 if (is_uint64(optarg, &warn.value)) {
480 break;
481 } else {
482 usage4 (_("Warning threshold be positive integer or percentage!"));
483 }
484 }
485 }
486 case 'c': /* critical size threshold */
487 {
488 /*
489 * We expect either a positive integer value without a unit, which means
490 * the unit is Bytes or a positive integer value and a percentage sign (%),
491 * which means the value must be with 0 and 100 and is relative to the total swap
492 */
493 size_t length;
494 length = strlen(optarg);
495
496 if (optarg[length - 1] == '%') {
497 /* It's percentage */
498 crit.is_percentage = true;
499 optarg[length - 1] = '\0';
500 if (is_uint64(optarg, &crit.value)) {
501 if (crit.value> 100) {
502 usage4 (_("Critical threshold percentage must be <= 100!"));
503 }
504 }
505 break;
506 } else {
507 /* It's Bytes */
508 crit.is_percentage = false;
509 if (is_uint64(optarg, &crit.value)) {
510 break;
511 } else {
512 usage4 (_("Critical threshold be positive integer or percentage!"));
513 }
514 }
515 }
516 case 'a': /* all swap */
517 allswaps = true;
518 break;
519 case 'n':
520 if ((no_swap_state = mp_translate_state(optarg)) == ERROR) {
521 usage4 (_("no-swap result must be a valid state name (OK, WARNING, CRITICAL, UNKNOWN) or integer (0-3)."));
522 }
523 break;
524 case 'v': /* verbose */
525 verbose++;
526 break;
527 case 'V': /* version */
528 print_revision (progname, NP_VERSION);
529 exit (STATE_UNKNOWN);
530 case 'h': /* help */
531 print_help ();
532 exit (STATE_UNKNOWN);
533 case '?': /* error */
534 usage5 ();
535 }
536 }
537
538 c = optind;
539 if (c == argc)
540 return validate_arguments ();
541
542 return validate_arguments ();
543}
544
545
546
547int
548validate_arguments (void)
549{
550 if (warn.value == 0 && crit.value == 0) {
551 return ERROR;
552 }
553 else if ((warn.is_percentage == crit.is_percentage) && (warn.value < crit.value)) {
554 /* This is NOT triggered if warn and crit are different units, e.g warn is percentage
555 * and crit is absolute. We cannot determine the condition at this point since we
556 * dont know the value of total swap yet
557 */
558 usage4(_("Warning should be more than critical"));
559 }
560 return OK;
561}
562
563
564
565void
566print_help (void)
567{
568 print_revision (progname, NP_VERSION);
569
570 printf (_(COPYRIGHT), copyright, email);
571
572 printf ("%s\n", _("Check swap space on local machine."));
573
574 printf ("\n\n");
575
576 print_usage ();
577
578 printf (UT_HELP_VRSN);
579 printf (UT_EXTRA_OPTS);
580
581 printf (" %s\n", "-w, --warning=INTEGER");
582 printf (" %s\n", _("Exit with WARNING status if less than INTEGER bytes of swap space are free"));
583 printf (" %s\n", "-w, --warning=PERCENT%");
584 printf (" %s\n", _("Exit with WARNING status if less than PERCENT of swap space is free"));
585 printf (" %s\n", "-c, --critical=INTEGER");
586 printf (" %s\n", _("Exit with CRITICAL status if less than INTEGER bytes of swap space are free"));
587 printf (" %s\n", "-c, --critical=PERCENT%");
588 printf (" %s\n", _("Exit with CRITICAL status if less than PERCENT of swap space is free"));
589 printf (" %s\n", "-a, --allswaps");
590 printf (" %s\n", _("Conduct comparisons for all swap partitions, one by one"));
591 printf (" %s\n", "-n, --no-swap=<ok|warning|critical|unknown>");
592 printf (" %s %s\n", _("Resulting state when there is no swap regardless of thresholds. Default:"), state_text(no_swap_state));
593 printf (UT_VERBOSE);
594
595 printf ("\n");
596 printf ("%s\n", _("Notes:"));
597 printf (" %s\n", _("Both INTEGER and PERCENT thresholds can be specified, they are all checked."));
598 printf (" %s\n", _("On AIX, if -a is specified, uses lsps -a, otherwise uses lsps -s."));
599
600 printf (UT_SUPPORT);
601}
602
603
604void
605print_usage (void)
606{
607 printf ("%s\n", _("Usage:"));
608 printf (" %s [-av] -w <percent_free>%% -c <percent_free>%%\n",progname);
609 printf (" -w <bytes_free> -c <bytes_free> [-n <state>]\n");
610} 641}
642#endif // CHECK_SWAP_SWAPCTL_SVR4