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/check_swap.c | |
parent | b32d7421ee81faaadb2729ee8b19cec4fd1b1899 (diff) | |
download | monitoring-plugins-3a10773c0918a190c43d1508f9f572709fba25a8.tar.gz |
check_swap: Heavily refactored linux part
Diffstat (limited to 'plugins/check_swap.c')
-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 | ||