diff options
| author | RincewindsHat <12514511+RincewindsHat@users.noreply.github.com> | 2023-12-13 16:17:47 +0100 |
|---|---|---|
| committer | RincewindsHat <12514511+RincewindsHat@users.noreply.github.com> | 2023-12-20 10:02:47 +0100 |
| commit | 3a10773c0918a190c43d1508f9f572709fba25a8 (patch) | |
| tree | d9535ad46f7b4c514cd469ec97b1ec4a31eaf6cc /plugins | |
| parent | b32d7421ee81faaadb2729ee8b19cec4fd1b1899 (diff) | |
| download | monitoring-plugins-3a10773c0918a190c43d1508f9f572709fba25a8.tar.gz | |
check_swap: Heavily refactored linux part
Diffstat (limited to 'plugins')
| -rw-r--r-- | plugins/check_swap.c | 758 |
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 | ||
| 59 | int check_swap (float free_swap_mb, float total_swap_mb); | 59 | typedef struct { |
| 60 | int process_arguments (int argc, char **argv); | 60 | unsigned long long free; // Free swap in Bytes! |
| 61 | int validate_arguments (void); | 61 | unsigned long long used; // Used swap in Bytes! |
| 62 | void print_usage (void); | 62 | unsigned long long total; // Total swap size, you guessed it, in Bytes! |
| 63 | void print_help (void); | 63 | } swap_metrics; |
| 64 | 64 | ||
| 65 | threshold warn; | 65 | typedef struct { |
| 66 | threshold crit; | 66 | int errorcode; |
| 67 | int verbose; | 67 | int statusCode; |
| 68 | bool allswaps = false; | 68 | swap_metrics metrics; |
| 69 | int no_swap_state = STATE_CRITICAL; | 69 | } swap_result; |
| 70 | 70 | ||
| 71 | int | 71 | typedef struct { |
| 72 | main (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]; | 79 | typedef 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 | 84 | swap_config_wrapper process_arguments (swap_config_wrapper config, int argc, char **argv); |
| 85 | char *temp_buffer; | 85 | void print_usage (); |
| 86 | char *swap_command; | 86 | void print_help (swap_config); |
| 87 | char *swap_format; | 87 | |
| 88 | # else | 88 | swap_result getSwapFromProcMeminfo(swap_config config); |
| 89 | # ifdef HAVE_DECL_SWAPCTL | 89 | swap_result getSwapFromSwapCommand(swap_config config); |
| 90 | int i=0, nswaps=0, swapctl_res=0; | 90 | swap_result getSwapFromSwapctl_BSD(swap_config config); |
| 91 | # ifdef CHECK_SWAP_SWAPCTL_SVR4 | 91 | swap_result getSwapFromSwap_SRV4(swap_config config); |
| 92 | swaptbl_t *tbl=NULL; | 92 | |
| 93 | swapent_t *ent=NULL; | 93 | swap_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 | |||
| 103 | int 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 */ | ||
| 193 | swap_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 | |||
| 319 | void | ||
| 320 | print_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 | |||
| 358 | void | ||
| 359 | print_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) { | 367 | swap_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 | ||
| 434 | swap_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 | ||
| 539 | swap_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 | ||
| 581 | swap_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 | |||
| 395 | int | ||
| 396 | check_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 */ | ||
| 429 | int | ||
| 430 | process_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 | |||
| 547 | int | ||
| 548 | validate_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 | |||
| 565 | void | ||
| 566 | print_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 | |||
| 604 | void | ||
| 605 | print_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 | ||
