diff options
Diffstat (limited to 'plugins/check_swap.d')
| -rw-r--r-- | plugins/check_swap.d/check_swap.h | 43 | ||||
| -rw-r--r-- | plugins/check_swap.d/swap.c | 469 |
2 files changed, 512 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..99039b21 --- /dev/null +++ b/plugins/check_swap.d/check_swap.h | |||
| @@ -0,0 +1,43 @@ | |||
| 1 | #pragma once | ||
| 2 | |||
| 3 | #include "../common.h" | ||
| 4 | |||
| 5 | #ifndef SWAP_CONVERSION | ||
| 6 | # define SWAP_CONVERSION 1 | ||
| 7 | #endif | ||
| 8 | |||
| 9 | typedef struct { | ||
| 10 | bool is_percentage; | ||
| 11 | uint64_t value; | ||
| 12 | } check_swap_threshold; | ||
| 13 | |||
| 14 | typedef struct { | ||
| 15 | unsigned long long free; // Free swap in Bytes! | ||
| 16 | unsigned long long used; // Used swap in Bytes! | ||
| 17 | unsigned long long total; // Total swap size, you guessed it, in Bytes! | ||
| 18 | } swap_metrics; | ||
| 19 | |||
| 20 | typedef struct { | ||
| 21 | int errorcode; | ||
| 22 | int statusCode; | ||
| 23 | swap_metrics metrics; | ||
| 24 | } swap_result; | ||
| 25 | |||
| 26 | typedef struct { | ||
| 27 | bool allswaps; | ||
| 28 | int no_swap_state; | ||
| 29 | bool warn_is_set; | ||
| 30 | check_swap_threshold warn; | ||
| 31 | bool crit_is_set; | ||
| 32 | check_swap_threshold crit; | ||
| 33 | bool on_aix; | ||
| 34 | int conversion_factor; | ||
| 35 | } swap_config; | ||
| 36 | |||
| 37 | swap_config swap_config_init(void); | ||
| 38 | |||
| 39 | swap_result get_swap_data(swap_config config); | ||
| 40 | swap_result getSwapFromProcMeminfo(char path_to_proc_meminfo[]); | ||
| 41 | swap_result getSwapFromSwapCommand(swap_config config, const char swap_command[], const char swap_format[]); | ||
| 42 | swap_result getSwapFromSwapctl_BSD(swap_config config); | ||
| 43 | 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..2fe4544f --- /dev/null +++ b/plugins/check_swap.d/swap.c | |||
| @@ -0,0 +1,469 @@ | |||
| 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 | #ifdef _AIX | ||
| 18 | tmp.on_aix = true; | ||
| 19 | #else | ||
| 20 | tmp.on_aix = false; | ||
| 21 | #endif | ||
| 22 | |||
| 23 | return tmp; | ||
| 24 | } | ||
| 25 | |||
| 26 | swap_result get_swap_data(swap_config config) { | ||
| 27 | #ifdef HAVE_PROC_MEMINFO | ||
| 28 | if (verbose >= 3) { | ||
| 29 | printf("Reading PROC_MEMINFO at %s\n", PROC_MEMINFO); | ||
| 30 | } | ||
| 31 | |||
| 32 | return getSwapFromProcMeminfo(PROC_MEMINFO); | ||
| 33 | #else // HAVE_PROC_MEMINFO | ||
| 34 | # ifdef HAVE_SWAP | ||
| 35 | if (verbose >= 3) { | ||
| 36 | printf("Using swap command %s with format: %s\n", SWAP_COMMAND, SWAP_FORMAT); | ||
| 37 | } | ||
| 38 | |||
| 39 | /* These override the command used if a summary (and thus ! allswaps) is | ||
| 40 | * required | ||
| 41 | * The summary flag returns more accurate information about swap usage on these | ||
| 42 | * OSes */ | ||
| 43 | if (config.on_aix && !config.allswaps) { | ||
| 44 | |||
| 45 | config.conversion_factor = 1; | ||
| 46 | |||
| 47 | return getSwapFromSwapCommand(config, "/usr/sbin/lsps -s", "%lu%*s %lu"); | ||
| 48 | } else { | ||
| 49 | return getSwapFromSwapCommand(config, SWAP_COMMAND, SWAP_FORMAT); | ||
| 50 | } | ||
| 51 | # else // HAVE_SWAP | ||
| 52 | # ifdef CHECK_SWAP_SWAPCTL_SVR4 | ||
| 53 | return getSwapFromSwapctl_SRV4(); | ||
| 54 | # else // CHECK_SWAP_SWAPCTL_SVR4 | ||
| 55 | # ifdef CHECK_SWAP_SWAPCTL_BSD | ||
| 56 | return getSwapFromSwapctl_BSD(); | ||
| 57 | # else // CHECK_SWAP_SWAPCTL_BSD | ||
| 58 | # error No way found to retrieve swap | ||
| 59 | # endif /* CHECK_SWAP_SWAPCTL_BSD */ | ||
| 60 | # endif /* CHECK_SWAP_SWAPCTL_SVR4 */ | ||
| 61 | # endif /* HAVE_SWAP */ | ||
| 62 | #endif /* HAVE_PROC_MEMINFO */ | ||
| 63 | } | ||
| 64 | |||
| 65 | swap_result getSwapFromProcMeminfo(char proc_meminfo[]) { | ||
| 66 | FILE *meminfo_file_ptr; | ||
| 67 | meminfo_file_ptr = fopen(proc_meminfo, "r"); | ||
| 68 | |||
| 69 | swap_result result = {0}; | ||
| 70 | result.errorcode = STATE_UNKNOWN; | ||
| 71 | |||
| 72 | if (meminfo_file_ptr == NULL) { | ||
| 73 | // failed to open meminfo file | ||
| 74 | // errno should contain an error | ||
| 75 | result.errorcode = STATE_UNKNOWN; | ||
| 76 | return result; | ||
| 77 | } | ||
| 78 | |||
| 79 | uint64_t swap_total = 0; | ||
| 80 | uint64_t swap_used = 0; | ||
| 81 | uint64_t swap_free = 0; | ||
| 82 | |||
| 83 | bool found_total = false; | ||
| 84 | bool found_used = false; | ||
| 85 | bool found_free = false; | ||
| 86 | |||
| 87 | char input_buffer[MAX_INPUT_BUFFER]; | ||
| 88 | char str[32]; | ||
| 89 | |||
| 90 | while (fgets(input_buffer, MAX_INPUT_BUFFER - 1, meminfo_file_ptr)) { | ||
| 91 | uint64_t tmp_KB = 0; | ||
| 92 | |||
| 93 | /* | ||
| 94 | * The following sscanf call looks for a line looking like: "Swap: 123 | ||
| 95 | * 123 123" On which kind of system this format exists, I can not say, | ||
| 96 | * but I wanted to document this for people who are not adapt with | ||
| 97 | * sscanf anymore, like me | ||
| 98 | * Also the units used here are unclear and probably wrong | ||
| 99 | */ | ||
| 100 | if (sscanf(input_buffer, "%*[S]%*[w]%*[a]%*[p]%*[:] %lu %lu %lu", &swap_total, &swap_used, &swap_free) == 3) { | ||
| 101 | |||
| 102 | result.metrics.total += swap_total; | ||
| 103 | result.metrics.used += swap_used; | ||
| 104 | result.metrics.free += swap_free; | ||
| 105 | |||
| 106 | found_total = true; | ||
| 107 | found_free = true; | ||
| 108 | found_used = true; | ||
| 109 | |||
| 110 | // Set error | ||
| 111 | result.errorcode = STATE_OK; | ||
| 112 | |||
| 113 | /* | ||
| 114 | * The following sscanf call looks for lines looking like: | ||
| 115 | * "SwapTotal: 123" and "SwapFree: 123" This format exists at least | ||
| 116 | * on Debian Linux with a 5.* kernel | ||
| 117 | */ | ||
| 118 | } else { | ||
| 119 | int sscanf_result = sscanf(input_buffer, | ||
| 120 | "%*[S]%*[w]%*[a]%*[p]%[TotalFreCchd]%*[:] %lu " | ||
| 121 | "%*[k]%*[B]", | ||
| 122 | str, &tmp_KB); | ||
| 123 | |||
| 124 | if (sscanf_result == 2) { | ||
| 125 | |||
| 126 | if (verbose >= 3) { | ||
| 127 | printf("Got %s with %lu\n", str, tmp_KB); | ||
| 128 | } | ||
| 129 | |||
| 130 | /* I think this part is always in Kb, so convert to bytes */ | ||
| 131 | if (strcmp("Total", str) == 0) { | ||
| 132 | swap_total = tmp_KB * 1000; | ||
| 133 | found_total = true; | ||
| 134 | } else if (strcmp("Free", str) == 0) { | ||
| 135 | swap_free = swap_free + tmp_KB * 1000; | ||
| 136 | found_free = true; | ||
| 137 | found_used = true; // No explicit used metric available | ||
| 138 | } else if (strcmp("Cached", str) == 0) { | ||
| 139 | swap_free = swap_free + tmp_KB * 1000; | ||
| 140 | found_free = true; | ||
| 141 | found_used = true; // No explicit used metric available | ||
| 142 | } | ||
| 143 | |||
| 144 | result.errorcode = STATE_OK; | ||
| 145 | } | ||
| 146 | } | ||
| 147 | } | ||
| 148 | |||
| 149 | fclose(meminfo_file_ptr); | ||
| 150 | |||
| 151 | result.metrics.total = swap_total; | ||
| 152 | result.metrics.used = swap_total - swap_free; | ||
| 153 | result.metrics.free = swap_free; | ||
| 154 | |||
| 155 | if (!found_free || !found_total || !found_used) { | ||
| 156 | result.errorcode = STATE_UNKNOWN; | ||
| 157 | } | ||
| 158 | |||
| 159 | return result; | ||
| 160 | } | ||
| 161 | |||
| 162 | swap_result getSwapFromSwapCommand(swap_config config, const char swap_command[], const char swap_format[]) { | ||
| 163 | swap_result result = {0}; | ||
| 164 | |||
| 165 | char *temp_buffer; | ||
| 166 | |||
| 167 | if (verbose >= 2) { | ||
| 168 | printf(_("Command: %s\n"), swap_command); | ||
| 169 | } | ||
| 170 | if (verbose >= 3) { | ||
| 171 | printf(_("Format: %s\n"), swap_format); | ||
| 172 | } | ||
| 173 | |||
| 174 | child_process = spopen(swap_command); | ||
| 175 | if (child_process == NULL) { | ||
| 176 | printf(_("Could not open pipe: %s\n"), swap_command); | ||
| 177 | swap_result tmp = { | ||
| 178 | .errorcode = STATE_UNKNOWN, | ||
| 179 | }; | ||
| 180 | return tmp; | ||
| 181 | } | ||
| 182 | |||
| 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); | ||
| 186 | } | ||
| 187 | |||
| 188 | char str[32] = {0}; | ||
| 189 | char input_buffer[MAX_INPUT_BUFFER]; | ||
| 190 | |||
| 191 | /* read 1st line */ | ||
| 192 | fgets(input_buffer, MAX_INPUT_BUFFER - 1, child_process); | ||
| 193 | if (strcmp(swap_format, "") == 0) { | ||
| 194 | temp_buffer = strtok(input_buffer, " \n"); | ||
| 195 | while (temp_buffer) { | ||
| 196 | if (strstr(temp_buffer, "blocks")) { | ||
| 197 | sprintf(str, "%s %s", str, "%lu"); | ||
| 198 | } else if (strstr(temp_buffer, "dskfree")) { | ||
| 199 | sprintf(str, "%s %s", str, "%lu"); | ||
| 200 | } else { | ||
| 201 | sprintf(str, "%s %s", str, "%*s"); | ||
| 202 | } | ||
| 203 | temp_buffer = strtok(NULL, " \n"); | ||
| 204 | } | ||
| 205 | } | ||
| 206 | |||
| 207 | double total_swap_mb = 0; | ||
| 208 | double free_swap_mb = 0; | ||
| 209 | double used_swap_mb = 0; | ||
| 210 | double dsktotal_mb = 0; | ||
| 211 | double dskused_mb = 0; | ||
| 212 | double dskfree_mb = 0; | ||
| 213 | |||
| 214 | /* | ||
| 215 | * If different swap command is used for summary switch, need to read format | ||
| 216 | * differently | ||
| 217 | */ | ||
| 218 | if (config.on_aix && !config.allswaps) { | ||
| 219 | fgets(input_buffer, MAX_INPUT_BUFFER - 1, child_process); /* Ignore first line */ | ||
| 220 | sscanf(input_buffer, swap_format, &total_swap_mb, &used_swap_mb); | ||
| 221 | free_swap_mb = total_swap_mb * (100 - used_swap_mb) / 100; | ||
| 222 | used_swap_mb = total_swap_mb - free_swap_mb; | ||
| 223 | |||
| 224 | if (verbose >= 3) { | ||
| 225 | printf(_("total=%.0f, used=%.0f, free=%.0f\n"), total_swap_mb, used_swap_mb, free_swap_mb); | ||
| 226 | } | ||
| 227 | } else { | ||
| 228 | while (fgets(input_buffer, MAX_INPUT_BUFFER - 1, child_process)) { | ||
| 229 | sscanf(input_buffer, swap_format, &dsktotal_mb, &dskfree_mb); | ||
| 230 | |||
| 231 | dsktotal_mb = dsktotal_mb / config.conversion_factor; | ||
| 232 | /* AIX lists percent used, so this converts to dskfree in MBs */ | ||
| 233 | |||
| 234 | if (config.on_aix) { | ||
| 235 | dskfree_mb = dsktotal_mb * (100 - dskfree_mb) / 100; | ||
| 236 | } else { | ||
| 237 | dskfree_mb = dskfree_mb / config.conversion_factor; | ||
| 238 | } | ||
| 239 | |||
| 240 | if (verbose >= 3) { | ||
| 241 | printf(_("total=%.0f, free=%.0f\n"), dsktotal_mb, dskfree_mb); | ||
| 242 | } | ||
| 243 | |||
| 244 | dskused_mb = dsktotal_mb - dskfree_mb; | ||
| 245 | total_swap_mb += dsktotal_mb; | ||
| 246 | used_swap_mb += dskused_mb; | ||
| 247 | free_swap_mb += dskfree_mb; | ||
| 248 | } | ||
| 249 | } | ||
| 250 | |||
| 251 | result.metrics.free = free_swap_mb * 1024 * 1024; | ||
| 252 | result.metrics.used = used_swap_mb * 1024 * 1024; | ||
| 253 | result.metrics.total = free_swap_mb * 1024 * 1024; | ||
| 254 | |||
| 255 | /* If we get anything on STDERR, at least set warning */ | ||
| 256 | while (fgets(input_buffer, MAX_INPUT_BUFFER - 1, child_stderr)) { | ||
| 257 | result.statusCode = max_state(result.statusCode, STATE_WARNING); | ||
| 258 | // TODO Set error here | ||
| 259 | } | ||
| 260 | |||
| 261 | /* close stderr */ | ||
| 262 | (void)fclose(child_stderr); | ||
| 263 | |||
| 264 | /* close the pipe */ | ||
| 265 | if (spclose(child_process)) { | ||
| 266 | result.statusCode = max_state(result.statusCode, STATE_WARNING); | ||
| 267 | // TODO set error here | ||
| 268 | } | ||
| 269 | |||
| 270 | return result; | ||
| 271 | } | ||
| 272 | |||
| 273 | #ifndef CHECK_SWAP_SWAPCTL_BSD | ||
| 274 | # define CHECK_SWAP_SWAPCTL_BSD | ||
| 275 | |||
| 276 | // Stub functionality for BSD stuff, so the compiler always sees the following BSD code | ||
| 277 | |||
| 278 | # define SWAP_NSWAP 0 | ||
| 279 | # define SWAP_STATS 1 | ||
| 280 | |||
| 281 | int bsd_swapctl(int cmd, const void *arg, int misc) { | ||
| 282 | (void)cmd; | ||
| 283 | (void)arg; | ||
| 284 | (void)misc; | ||
| 285 | return 512; | ||
| 286 | } | ||
| 287 | |||
| 288 | struct swapent { | ||
| 289 | dev_t se_dev; /* device id */ | ||
| 290 | int se_flags; /* entry flags */ | ||
| 291 | int se_nblks; /* total blocks */ | ||
| 292 | int se_inuse; /* blocks in use */ | ||
| 293 | int se_priority; /* priority */ | ||
| 294 | char se_path[PATH_MAX]; /* path to entry */ | ||
| 295 | }; | ||
| 296 | |||
| 297 | #else | ||
| 298 | # define bsd_swapctl swapctl | ||
| 299 | #endif | ||
| 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 = (float)ent[i].se_nblks / (float)config.conversion_factor; | ||
| 324 | dskused_mb = (float)ent[i].se_inuse / (float)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 = (swaptbl_t *)malloc(sizeof(swaptbl_t) + (sizeof(swapent_t) * (unsigned long)nswaps)); | ||
| 406 | |||
| 407 | if (tbl == NULL) { | ||
| 408 | die(STATE_UNKNOWN, _("malloc() failed!\n")); | ||
| 409 | } | ||
| 410 | |||
| 411 | memset(tbl, 0, sizeof(swaptbl_t) + (sizeof(swapent_t) * (unsigned long)nswaps)); | ||
| 412 | tbl->swt_n = nswaps; | ||
| 413 | |||
| 414 | for (int i = 0; i < nswaps; i++) { | ||
| 415 | if ((tbl->swt_ent[i].ste_path = (char *)malloc(sizeof(char) * MAXPATHLEN)) == NULL) { | ||
| 416 | die(STATE_UNKNOWN, _("malloc() failed!\n")); | ||
| 417 | } | ||
| 418 | } | ||
| 419 | |||
| 420 | /* and now, tally 'em up */ | ||
| 421 | int swapctl_res = srv4_swapctl(SC_LIST, tbl); | ||
| 422 | if (swapctl_res < 0) { | ||
| 423 | perror(_("swapctl failed: ")); | ||
| 424 | die(STATE_UNKNOWN, _("Error in swapctl call\n")); | ||
| 425 | } | ||
| 426 | |||
| 427 | double dsktotal_mb = 0.0; | ||
| 428 | double dskfree_mb = 0.0; | ||
| 429 | double dskused_mb = 0.0; | ||
| 430 | unsigned long long total_swap_mb = 0; | ||
| 431 | unsigned long long free_swap_mb = 0; | ||
| 432 | unsigned long long used_swap_mb = 0; | ||
| 433 | |||
| 434 | for (int i = 0; i < nswaps; i++) { | ||
| 435 | dsktotal_mb = (float)tbl->swt_ent[i].ste_pages / SWAP_CONVERSION; | ||
| 436 | dskfree_mb = (float)tbl->swt_ent[i].ste_free / SWAP_CONVERSION; | ||
| 437 | dskused_mb = (dsktotal_mb - dskfree_mb); | ||
| 438 | |||
| 439 | if (verbose >= 3) { | ||
| 440 | printf("dsktotal_mb=%.0f dskfree_mb=%.0f dskused_mb=%.0f\n", dsktotal_mb, dskfree_mb, dskused_mb); | ||
| 441 | } | ||
| 442 | |||
| 443 | if (config.allswaps && dsktotal_mb > 0) { | ||
| 444 | double percent = 100 * (((double)dskused_mb) / ((double)dsktotal_mb)); | ||
| 445 | |||
| 446 | if (verbose) { | ||
| 447 | printf("[%.0f (%g%%)]", dskfree_mb, 100 - percent); | ||
| 448 | } | ||
| 449 | } | ||
| 450 | |||
| 451 | total_swap_mb += (unsigned long long)dsktotal_mb; | ||
| 452 | free_swap_mb += (unsigned long long)dskfree_mb; | ||
| 453 | used_swap_mb += (unsigned long long)dskused_mb; | ||
| 454 | } | ||
| 455 | |||
| 456 | /* and clean up after ourselves */ | ||
| 457 | for (int i = 0; i < nswaps; i++) { | ||
| 458 | free(tbl->swt_ent[i].ste_path); | ||
| 459 | } | ||
| 460 | free(tbl); | ||
| 461 | |||
| 462 | swap_result result = {0}; | ||
| 463 | result.errorcode = OK; | ||
| 464 | result.metrics.total = total_swap_mb * 1024 * 1024; | ||
| 465 | result.metrics.free = free_swap_mb * 1024 * 1024; | ||
| 466 | result.metrics.used = used_swap_mb * 1024 * 1024; | ||
| 467 | |||
| 468 | return result; | ||
| 469 | } | ||
