diff options
Diffstat (limited to 'plugins/check_swap.d')
| -rw-r--r-- | plugins/check_swap.d/check_swap.h | 49 | ||||
| -rw-r--r-- | plugins/check_swap.d/swap.c | 471 |
2 files changed, 520 insertions, 0 deletions
diff --git a/plugins/check_swap.d/check_swap.h b/plugins/check_swap.d/check_swap.h new file mode 100644 index 00000000..8d3c7fcf --- /dev/null +++ b/plugins/check_swap.d/check_swap.h | |||
| @@ -0,0 +1,49 @@ | |||
| 1 | #pragma once | ||
| 2 | |||
| 3 | #include "../common.h" | ||
| 4 | #include "../../lib/output.h" | ||
| 5 | #include "../../lib/states.h" | ||
| 6 | |||
| 7 | #ifndef SWAP_CONVERSION | ||
| 8 | # define SWAP_CONVERSION 1 | ||
| 9 | #endif | ||
| 10 | |||
| 11 | typedef struct { | ||
| 12 | bool is_percentage; | ||
| 13 | uint64_t value; | ||
| 14 | } check_swap_threshold; | ||
| 15 | |||
| 16 | typedef struct { | ||
| 17 | unsigned long long free; // Free swap in Bytes! | ||
| 18 | unsigned long long used; // Used swap in Bytes! | ||
| 19 | unsigned long long total; // Total swap size, you guessed it, in Bytes! | ||
| 20 | } swap_metrics; | ||
| 21 | |||
| 22 | typedef struct { | ||
| 23 | int errorcode; | ||
| 24 | int statusCode; | ||
| 25 | swap_metrics metrics; | ||
| 26 | } swap_result; | ||
| 27 | |||
| 28 | typedef struct { | ||
| 29 | bool allswaps; | ||
| 30 | mp_state_enum no_swap_state; | ||
| 31 | bool warn_is_set; | ||
| 32 | check_swap_threshold warn; | ||
| 33 | bool crit_is_set; | ||
| 34 | check_swap_threshold crit; | ||
| 35 | bool on_aix; | ||
| 36 | int conversion_factor; | ||
| 37 | |||
| 38 | bool output_format_is_set; | ||
| 39 | mp_output_format output_format; | ||
| 40 | } swap_config; | ||
| 41 | |||
| 42 | swap_config swap_config_init(void); | ||
| 43 | |||
| 44 | swap_result get_swap_data(swap_config config); | ||
| 45 | swap_result getSwapFromProcMeminfo(char path_to_proc_meminfo[]); | ||
| 46 | swap_result getSwapFromSwapCommand(swap_config config, const char swap_command[], | ||
| 47 | const char swap_format[]); | ||
| 48 | swap_result getSwapFromSwapctl_BSD(swap_config config); | ||
| 49 | swap_result getSwapFromSwap_SRV4(swap_config config); | ||
diff --git a/plugins/check_swap.d/swap.c b/plugins/check_swap.d/swap.c new file mode 100644 index 00000000..58213a3c --- /dev/null +++ b/plugins/check_swap.d/swap.c | |||
| @@ -0,0 +1,471 @@ | |||
| 1 | #include "./check_swap.d/check_swap.h" | ||
| 2 | #include "../popen.h" | ||
| 3 | #include "../utils.h" | ||
| 4 | #include "common.h" | ||
| 5 | |||
| 6 | extern int verbose; | ||
| 7 | |||
| 8 | swap_config swap_config_init(void) { | ||
| 9 | swap_config tmp = {0}; | ||
| 10 | tmp.allswaps = false; | ||
| 11 | tmp.no_swap_state = STATE_CRITICAL; | ||
| 12 | tmp.conversion_factor = SWAP_CONVERSION; | ||
| 13 | |||
| 14 | tmp.warn_is_set = false; | ||
| 15 | tmp.crit_is_set = false; | ||
| 16 | |||
| 17 | tmp.output_format_is_set = false; | ||
| 18 | |||
| 19 | #ifdef _AIX | ||
| 20 | tmp.on_aix = true; | ||
| 21 | #else | ||
| 22 | tmp.on_aix = false; | ||
| 23 | #endif | ||
| 24 | |||
| 25 | return tmp; | ||
| 26 | } | ||
| 27 | |||
| 28 | swap_result get_swap_data(swap_config config) { | ||
| 29 | #ifdef HAVE_PROC_MEMINFO | ||
| 30 | if (verbose >= 3) { | ||
| 31 | printf("Reading PROC_MEMINFO at %s\n", PROC_MEMINFO); | ||
| 32 | } | ||
| 33 | |||
| 34 | return getSwapFromProcMeminfo(PROC_MEMINFO); | ||
| 35 | #else // HAVE_PROC_MEMINFO | ||
| 36 | # ifdef HAVE_SWAP | ||
| 37 | if (verbose >= 3) { | ||
| 38 | printf("Using swap command %s with format: %s\n", SWAP_COMMAND, SWAP_FORMAT); | ||
| 39 | } | ||
| 40 | |||
| 41 | /* These override the command used if a summary (and thus ! allswaps) is | ||
| 42 | * required | ||
| 43 | * The summary flag returns more accurate information about swap usage on these | ||
| 44 | * OSes */ | ||
| 45 | if (config.on_aix && !config.allswaps) { | ||
| 46 | |||
| 47 | config.conversion_factor = 1; | ||
| 48 | |||
| 49 | return getSwapFromSwapCommand(config, "/usr/sbin/lsps -s", "%lu%*s %lu"); | ||
| 50 | } else { | ||
| 51 | return getSwapFromSwapCommand(config, SWAP_COMMAND, SWAP_FORMAT); | ||
| 52 | } | ||
| 53 | # else // HAVE_SWAP | ||
| 54 | # ifdef CHECK_SWAP_SWAPCTL_SVR4 | ||
| 55 | return getSwapFromSwapctl_SRV4(config); | ||
| 56 | # else // CHECK_SWAP_SWAPCTL_SVR4 | ||
| 57 | # ifdef CHECK_SWAP_SWAPCTL_BSD | ||
| 58 | return getSwapFromSwapctl_BSD(config); | ||
| 59 | # else // CHECK_SWAP_SWAPCTL_BSD | ||
| 60 | # error No way found to retrieve swap | ||
| 61 | # endif /* CHECK_SWAP_SWAPCTL_BSD */ | ||
| 62 | # endif /* CHECK_SWAP_SWAPCTL_SVR4 */ | ||
| 63 | # endif /* HAVE_SWAP */ | ||
| 64 | #endif /* HAVE_PROC_MEMINFO */ | ||
| 65 | } | ||
| 66 | |||
| 67 | swap_result getSwapFromProcMeminfo(char proc_meminfo[]) { | ||
| 68 | FILE *meminfo_file_ptr; | ||
| 69 | meminfo_file_ptr = fopen(proc_meminfo, "r"); | ||
| 70 | |||
| 71 | swap_result result = {}; | ||
| 72 | result.errorcode = STATE_UNKNOWN; | ||
| 73 | |||
| 74 | if (meminfo_file_ptr == NULL) { | ||
| 75 | // failed to open meminfo file | ||
| 76 | // errno should contain an error | ||
| 77 | result.errorcode = STATE_UNKNOWN; | ||
| 78 | return result; | ||
| 79 | } | ||
| 80 | |||
| 81 | unsigned long swap_total = 0; | ||
| 82 | unsigned long swap_used = 0; | ||
| 83 | unsigned long swap_free = 0; | ||
| 84 | |||
| 85 | bool found_total = false; | ||
| 86 | bool found_free = false; | ||
| 87 | |||
| 88 | char input_buffer[MAX_INPUT_BUFFER]; | ||
| 89 | char str[32]; | ||
| 90 | |||
| 91 | while (fgets(input_buffer, MAX_INPUT_BUFFER - 1, meminfo_file_ptr)) { | ||
| 92 | |||
| 93 | /* | ||
| 94 | * The following sscanf call looks for a line looking like: "Swap: 123 | ||
| 95 | * 123 123" which exists on NetBSD (at least), | ||
| 96 | * The unit should be Bytes | ||
| 97 | */ | ||
| 98 | if (sscanf(input_buffer, "%*[S]%*[w]%*[a]%*[p]%*[:] %lu %lu %lu", &swap_total, &swap_used, | ||
| 99 | &swap_free) == 3) { | ||
| 100 | found_total = true; | ||
| 101 | found_free = true; | ||
| 102 | // Set error | ||
| 103 | result.errorcode = STATE_OK; | ||
| 104 | // Break out of fgets here, since both scanf expressions might match (NetBSD for | ||
| 105 | // example) | ||
| 106 | break; | ||
| 107 | } | ||
| 108 | |||
| 109 | /* | ||
| 110 | * The following sscanf call looks for lines looking like: | ||
| 111 | * "SwapTotal: 123" and "SwapFree: 123" This format exists at least | ||
| 112 | * on Debian Linux with a 5.* kernel | ||
| 113 | */ | ||
| 114 | unsigned long tmp_KB = 0; | ||
| 115 | int sscanf_result = sscanf(input_buffer, | ||
| 116 | "%*[S]%*[w]%*[a]%*[p]%[TotalFreCchd]%*[:] %lu " | ||
| 117 | "%*[k]%*[B]", | ||
| 118 | str, &tmp_KB); | ||
| 119 | |||
| 120 | if (sscanf_result == 2) { | ||
| 121 | |||
| 122 | if (verbose >= 3) { | ||
| 123 | printf("Got %s with %lu\n", str, tmp_KB); | ||
| 124 | } | ||
| 125 | |||
| 126 | /* I think this part is always in Kb, so convert to bytes */ | ||
| 127 | if (strcmp("Total", str) == 0) { | ||
| 128 | swap_total = tmp_KB * 1000; | ||
| 129 | found_total = true; | ||
| 130 | } else if (strcmp("Free", str) == 0) { | ||
| 131 | swap_free += tmp_KB * 1000; | ||
| 132 | found_free = true; | ||
| 133 | } else if (strcmp("Cached", str) == 0) { | ||
| 134 | swap_free += tmp_KB * 1000; | ||
| 135 | } | ||
| 136 | |||
| 137 | result.errorcode = STATE_OK; | ||
| 138 | } | ||
| 139 | } | ||
| 140 | |||
| 141 | fclose(meminfo_file_ptr); | ||
| 142 | |||
| 143 | result.metrics.total = swap_total; | ||
| 144 | result.metrics.free = swap_free; | ||
| 145 | result.metrics.used = swap_total - swap_free; | ||
| 146 | |||
| 147 | if (!found_free || !found_total) { | ||
| 148 | result.errorcode = STATE_UNKNOWN; | ||
| 149 | } | ||
| 150 | |||
| 151 | return result; | ||
| 152 | } | ||
| 153 | |||
| 154 | swap_result getSwapFromSwapCommand(swap_config config, const char swap_command[], | ||
| 155 | const char swap_format[]) { | ||
| 156 | swap_result result = {0}; | ||
| 157 | |||
| 158 | char *temp_buffer; | ||
| 159 | |||
| 160 | if (verbose >= 2) { | ||
| 161 | printf(_("Command: %s\n"), swap_command); | ||
| 162 | } | ||
| 163 | if (verbose >= 3) { | ||
| 164 | printf(_("Format: %s\n"), swap_format); | ||
| 165 | } | ||
| 166 | |||
| 167 | child_process = spopen(swap_command); | ||
| 168 | if (child_process == NULL) { | ||
| 169 | printf(_("Could not open pipe: %s\n"), swap_command); | ||
| 170 | swap_result tmp = { | ||
| 171 | .errorcode = STATE_UNKNOWN, | ||
| 172 | }; | ||
| 173 | return tmp; | ||
| 174 | } | ||
| 175 | |||
| 176 | child_stderr = fdopen(child_stderr_array[fileno(child_process)], "r"); | ||
| 177 | if (child_stderr == NULL) { | ||
| 178 | printf(_("Could not open stderr for %s\n"), swap_command); | ||
| 179 | } | ||
| 180 | |||
| 181 | char str[32] = {0}; | ||
| 182 | char input_buffer[MAX_INPUT_BUFFER]; | ||
| 183 | |||
| 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, "%lu"); | ||
| 191 | } else if (strstr(temp_buffer, "dskfree")) { | ||
| 192 | sprintf(str, "%s %s", str, "%lu"); | ||
| 193 | } else { | ||
| 194 | sprintf(str, "%s %s", str, "%*s"); | ||
| 195 | } | ||
| 196 | temp_buffer = strtok(NULL, " \n"); | ||
| 197 | } | ||
| 198 | } | ||
| 199 | |||
| 200 | double total_swap_mb = 0; | ||
| 201 | double free_swap_mb = 0; | ||
| 202 | double used_swap_mb = 0; | ||
| 203 | double dsktotal_mb = 0; | ||
| 204 | double dskused_mb = 0; | ||
| 205 | double dskfree_mb = 0; | ||
| 206 | |||
| 207 | /* | ||
| 208 | * If different swap command is used for summary switch, need to read format | ||
| 209 | * differently | ||
| 210 | */ | ||
| 211 | if (config.on_aix && !config.allswaps) { | ||
| 212 | fgets(input_buffer, MAX_INPUT_BUFFER - 1, child_process); /* Ignore first line */ | ||
| 213 | sscanf(input_buffer, swap_format, &total_swap_mb, &used_swap_mb); | ||
| 214 | free_swap_mb = total_swap_mb * (100 - used_swap_mb) / 100; | ||
| 215 | used_swap_mb = total_swap_mb - free_swap_mb; | ||
| 216 | |||
| 217 | if (verbose >= 3) { | ||
| 218 | printf(_("total=%.0f, used=%.0f, free=%.0f\n"), total_swap_mb, used_swap_mb, | ||
| 219 | free_swap_mb); | ||
| 220 | } | ||
| 221 | } else { | ||
| 222 | while (fgets(input_buffer, MAX_INPUT_BUFFER - 1, child_process)) { | ||
| 223 | sscanf(input_buffer, swap_format, &dsktotal_mb, &dskfree_mb); | ||
| 224 | |||
| 225 | dsktotal_mb = dsktotal_mb / config.conversion_factor; | ||
| 226 | /* AIX lists percent used, so this converts to dskfree in MBs */ | ||
| 227 | |||
| 228 | if (config.on_aix) { | ||
| 229 | dskfree_mb = dsktotal_mb * (100 - dskfree_mb) / 100; | ||
| 230 | } else { | ||
| 231 | dskfree_mb = dskfree_mb / config.conversion_factor; | ||
| 232 | } | ||
| 233 | |||
| 234 | if (verbose >= 3) { | ||
| 235 | printf(_("total=%.0f, free=%.0f\n"), dsktotal_mb, dskfree_mb); | ||
| 236 | } | ||
| 237 | |||
| 238 | dskused_mb = dsktotal_mb - dskfree_mb; | ||
| 239 | total_swap_mb += dsktotal_mb; | ||
| 240 | used_swap_mb += dskused_mb; | ||
| 241 | free_swap_mb += dskfree_mb; | ||
| 242 | } | ||
| 243 | } | ||
| 244 | |||
| 245 | result.metrics.free = free_swap_mb * 1024 * 1024; | ||
| 246 | result.metrics.used = used_swap_mb * 1024 * 1024; | ||
| 247 | result.metrics.total = free_swap_mb * 1024 * 1024; | ||
| 248 | |||
| 249 | /* If we get anything on STDERR, at least set warning */ | ||
| 250 | while (fgets(input_buffer, MAX_INPUT_BUFFER - 1, child_stderr)) { | ||
| 251 | result.statusCode = max_state(result.statusCode, STATE_WARNING); | ||
| 252 | // TODO Set error here | ||
| 253 | } | ||
| 254 | |||
| 255 | /* close stderr */ | ||
| 256 | (void)fclose(child_stderr); | ||
| 257 | |||
| 258 | /* close the pipe */ | ||
| 259 | if (spclose(child_process)) { | ||
| 260 | result.statusCode = max_state(result.statusCode, STATE_WARNING); | ||
| 261 | // TODO set error here | ||
| 262 | } | ||
| 263 | |||
| 264 | return result; | ||
| 265 | } | ||
| 266 | |||
| 267 | #ifndef CHECK_SWAP_SWAPCTL_BSD | ||
| 268 | # define CHECK_SWAP_SWAPCTL_BSD | ||
| 269 | |||
| 270 | // Stub functionality for BSD stuff, so the compiler always sees the following BSD code | ||
| 271 | |||
| 272 | # define SWAP_NSWAP 0 | ||
| 273 | # define SWAP_STATS 1 | ||
| 274 | |||
| 275 | int bsd_swapctl(int cmd, const void *arg, int misc) { | ||
| 276 | (void)cmd; | ||
| 277 | (void)arg; | ||
| 278 | (void)misc; | ||
| 279 | return 512; | ||
| 280 | } | ||
| 281 | |||
| 282 | struct swapent { | ||
| 283 | dev_t se_dev; /* device id */ | ||
| 284 | int se_flags; /* entry flags */ | ||
| 285 | int se_nblks; /* total blocks */ | ||
| 286 | int se_inuse; /* blocks in use */ | ||
| 287 | int se_priority; /* priority */ | ||
| 288 | char se_path[PATH_MAX]; /* path to entry */ | ||
| 289 | }; | ||
| 290 | |||
| 291 | #else | ||
| 292 | |||
| 293 | // Includes for NetBSD | ||
| 294 | # include <unistd.h> | ||
| 295 | # include <sys/swap.h> | ||
| 296 | |||
| 297 | # define bsd_swapctl swapctl | ||
| 298 | |||
| 299 | #endif // CHECK_SWAP_SWAPCTL_BSD | ||
| 300 | |||
| 301 | swap_result getSwapFromSwapctl_BSD(swap_config config) { | ||
| 302 | /* get the number of active swap devices */ | ||
| 303 | int nswaps = bsd_swapctl(SWAP_NSWAP, NULL, 0); | ||
| 304 | |||
| 305 | /* initialize swap table + entries */ | ||
| 306 | struct swapent *ent = (struct swapent *)malloc(sizeof(struct swapent) * (unsigned long)nswaps); | ||
| 307 | |||
| 308 | /* and now, tally 'em up */ | ||
| 309 | int swapctl_res = bsd_swapctl(SWAP_STATS, ent, nswaps); | ||
| 310 | if (swapctl_res < 0) { | ||
| 311 | perror(_("swapctl failed: ")); | ||
| 312 | die(STATE_UNKNOWN, _("Error in swapctl call\n")); | ||
| 313 | } | ||
| 314 | |||
| 315 | double dsktotal_mb = 0.0; | ||
| 316 | double dskfree_mb = 0.0; | ||
| 317 | double dskused_mb = 0.0; | ||
| 318 | unsigned long long total_swap_mb = 0; | ||
| 319 | unsigned long long free_swap_mb = 0; | ||
| 320 | unsigned long long used_swap_mb = 0; | ||
| 321 | |||
| 322 | for (int i = 0; i < nswaps; i++) { | ||
| 323 | dsktotal_mb = (double)ent[i].se_nblks / (double)config.conversion_factor; | ||
| 324 | dskused_mb = (double)ent[i].se_inuse / (double)config.conversion_factor; | ||
| 325 | dskfree_mb = (dsktotal_mb - dskused_mb); | ||
| 326 | |||
| 327 | if (config.allswaps && dsktotal_mb > 0) { | ||
| 328 | double percent = 100 * (((double)dskused_mb) / ((double)dsktotal_mb)); | ||
| 329 | |||
| 330 | if (verbose) { | ||
| 331 | printf("[%.0f (%g%%)]", dskfree_mb, 100 - percent); | ||
| 332 | } | ||
| 333 | } | ||
| 334 | |||
| 335 | total_swap_mb += (unsigned long long)dsktotal_mb; | ||
| 336 | free_swap_mb += (unsigned long long)dskfree_mb; | ||
| 337 | used_swap_mb += (unsigned long long)dskused_mb; | ||
| 338 | } | ||
| 339 | |||
| 340 | /* and clean up after ourselves */ | ||
| 341 | free(ent); | ||
| 342 | |||
| 343 | swap_result result = {0}; | ||
| 344 | |||
| 345 | result.statusCode = OK; | ||
| 346 | result.errorcode = OK; | ||
| 347 | |||
| 348 | result.metrics.total = total_swap_mb * 1024 * 1024; | ||
| 349 | result.metrics.free = free_swap_mb * 1024 * 1024; | ||
| 350 | result.metrics.used = used_swap_mb * 1024 * 1024; | ||
| 351 | |||
| 352 | return result; | ||
| 353 | } | ||
| 354 | |||
| 355 | #ifndef CHECK_SWAP_SWAPCTL_SVR4 | ||
| 356 | int srv4_swapctl(int cmd, void *arg) { | ||
| 357 | (void)cmd; | ||
| 358 | (void)arg; | ||
| 359 | return 512; | ||
| 360 | } | ||
| 361 | |||
| 362 | typedef struct srv4_swapent { | ||
| 363 | char *ste_path; /* name of the swap file */ | ||
| 364 | off_t ste_start; /* starting block for swapping */ | ||
| 365 | off_t ste_length; /* length of swap area */ | ||
| 366 | long ste_pages; /* number of pages for swapping */ | ||
| 367 | long ste_free; /* number of ste_pages free */ | ||
| 368 | long ste_flags; /* ST_INDEL bit set if swap file */ | ||
| 369 | /* is now being deleted */ | ||
| 370 | } swapent_t; | ||
| 371 | |||
| 372 | typedef struct swaptbl { | ||
| 373 | int swt_n; /* number of swapents following */ | ||
| 374 | struct srv4_swapent swt_ent[]; /* array of swt_n swapents */ | ||
| 375 | } swaptbl_t; | ||
| 376 | |||
| 377 | # define SC_LIST 2 | ||
| 378 | # define SC_GETNSWP 3 | ||
| 379 | |||
| 380 | # ifndef MAXPATHLEN | ||
| 381 | # define MAXPATHLEN 2048 | ||
| 382 | # endif | ||
| 383 | |||
| 384 | #else | ||
| 385 | # define srv4_swapctl swapctl | ||
| 386 | #endif | ||
| 387 | |||
| 388 | swap_result getSwapFromSwap_SRV4(swap_config config) { | ||
| 389 | int nswaps = 0; | ||
| 390 | |||
| 391 | /* get the number of active swap devices */ | ||
| 392 | if ((nswaps = srv4_swapctl(SC_GETNSWP, NULL)) == -1) { | ||
| 393 | die(STATE_UNKNOWN, _("Error getting swap devices\n")); | ||
| 394 | } | ||
| 395 | |||
| 396 | if (nswaps == 0) { | ||
| 397 | die(STATE_OK, _("SWAP OK: No swap devices defined\n")); | ||
| 398 | } | ||
| 399 | |||
| 400 | if (verbose >= 3) { | ||
| 401 | printf("Found %d swap device(s)\n", nswaps); | ||
| 402 | } | ||
| 403 | |||
| 404 | /* initialize swap table + entries */ | ||
| 405 | swaptbl_t *tbl = | ||
| 406 | (swaptbl_t *)malloc(sizeof(swaptbl_t) + (sizeof(swapent_t) * (unsigned long)nswaps)); | ||
| 407 | |||
| 408 | if (tbl == NULL) { | ||
| 409 | die(STATE_UNKNOWN, _("malloc() failed!\n")); | ||
| 410 | } | ||
| 411 | |||
| 412 | memset(tbl, 0, sizeof(swaptbl_t) + (sizeof(swapent_t) * (unsigned long)nswaps)); | ||
| 413 | tbl->swt_n = nswaps; | ||
| 414 | |||
| 415 | for (int i = 0; i < nswaps; i++) { | ||
| 416 | if ((tbl->swt_ent[i].ste_path = (char *)malloc(sizeof(char) * MAXPATHLEN)) == NULL) { | ||
| 417 | die(STATE_UNKNOWN, _("malloc() failed!\n")); | ||
| 418 | } | ||
| 419 | } | ||
| 420 | |||
| 421 | /* and now, tally 'em up */ | ||
| 422 | int swapctl_res = srv4_swapctl(SC_LIST, tbl); | ||
| 423 | if (swapctl_res < 0) { | ||
| 424 | perror(_("swapctl failed: ")); | ||
| 425 | die(STATE_UNKNOWN, _("Error in swapctl call\n")); | ||
| 426 | } | ||
| 427 | |||
| 428 | double dsktotal_mb = 0.0; | ||
| 429 | double dskfree_mb = 0.0; | ||
| 430 | double dskused_mb = 0.0; | ||
| 431 | unsigned long long total_swap_mb = 0; | ||
| 432 | unsigned long long free_swap_mb = 0; | ||
| 433 | unsigned long long used_swap_mb = 0; | ||
| 434 | |||
| 435 | for (int i = 0; i < nswaps; i++) { | ||
| 436 | dsktotal_mb = (float)tbl->swt_ent[i].ste_pages / SWAP_CONVERSION; | ||
| 437 | dskfree_mb = (float)tbl->swt_ent[i].ste_free / SWAP_CONVERSION; | ||
| 438 | dskused_mb = (dsktotal_mb - dskfree_mb); | ||
| 439 | |||
| 440 | if (verbose >= 3) { | ||
| 441 | printf("dsktotal_mb=%.0f dskfree_mb=%.0f dskused_mb=%.0f\n", dsktotal_mb, dskfree_mb, | ||
| 442 | dskused_mb); | ||
| 443 | } | ||
| 444 | |||
| 445 | if (config.allswaps && dsktotal_mb > 0) { | ||
| 446 | double percent = 100 * (((double)dskused_mb) / ((double)dsktotal_mb)); | ||
| 447 | |||
| 448 | if (verbose) { | ||
| 449 | printf("[%.0f (%g%%)]", dskfree_mb, 100 - percent); | ||
| 450 | } | ||
| 451 | } | ||
| 452 | |||
| 453 | total_swap_mb += (unsigned long long)dsktotal_mb; | ||
| 454 | free_swap_mb += (unsigned long long)dskfree_mb; | ||
| 455 | used_swap_mb += (unsigned long long)dskused_mb; | ||
| 456 | } | ||
| 457 | |||
| 458 | /* and clean up after ourselves */ | ||
| 459 | for (int i = 0; i < nswaps; i++) { | ||
| 460 | free(tbl->swt_ent[i].ste_path); | ||
| 461 | } | ||
| 462 | free(tbl); | ||
| 463 | |||
| 464 | swap_result result = {0}; | ||
| 465 | result.errorcode = OK; | ||
| 466 | result.metrics.total = total_swap_mb * 1024 * 1024; | ||
| 467 | result.metrics.free = free_swap_mb * 1024 * 1024; | ||
| 468 | result.metrics.used = used_swap_mb * 1024 * 1024; | ||
| 469 | |||
| 470 | return result; | ||
| 471 | } | ||
