summaryrefslogtreecommitdiffstats
path: root/plugins/check_load.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/check_load.c')
-rw-r--r--plugins/check_load.c662
1 files changed, 379 insertions, 283 deletions
diff --git a/plugins/check_load.c b/plugins/check_load.c
index 1431d130..644cd604 100644
--- a/plugins/check_load.c
+++ b/plugins/check_load.c
@@ -1,350 +1,430 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_load plugin 3 * Monitoring check_load plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 1999-2007 Monitoring Plugins Development Team 6 * Copyright (c) 1999-2007 Monitoring Plugins Development Team
7* 7 *
8* Description: 8 * Description:
9* 9 *
10* This file contains the check_load plugin 10 * This file contains the check_load plugin
11* 11 *
12* This plugin tests the current system load average. 12 * This plugin tests the current system load average.
13* 13 *
14* 14 *
15* This program is free software: you can redistribute it and/or modify 15 * This program is free software: you can redistribute it and/or modify
16* it under the terms of the GNU General Public License as published by 16 * it under the terms of the GNU General Public License as published by
17* the Free Software Foundation, either version 3 of the License, or 17 * the Free Software Foundation, either version 3 of the License, or
18* (at your option) any later version. 18 * (at your option) any later version.
19* 19 *
20* This program is distributed in the hope that it will be useful, 20 * This program is distributed in the hope that it will be useful,
21* but WITHOUT ANY WARRANTY; without even the implied warranty of 21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23* GNU General Public License for more details. 23 * GNU General Public License for more details.
24* 24 *
25* You should have received a copy of the GNU General Public License 25 * You should have received a copy of the GNU General Public License
26* along with this program. If not, see <http://www.gnu.org/licenses/>. 26 * along with this program. If not, see <http://www.gnu.org/licenses/>.
27* 27 *
28* 28 *
29*****************************************************************************/ 29 *****************************************************************************/
30 30
31const char *progname = "check_load"; 31const char *progname = "check_load";
32const char *copyright = "1999-2022"; 32const char *copyright = "1999-2022";
33const char *email = "devel@monitoring-plugins.org"; 33const char *email = "devel@monitoring-plugins.org";
34 34
35#include "./common.h" 35#include "./common.h"
36#include <string.h>
36#include "./runcmd.h" 37#include "./runcmd.h"
37#include "./utils.h" 38#include "./utils.h"
38#include "./popen.h" 39#include "./popen.h"
40#include "../lib/states.h"
41#include "../lib/output.h"
42#include "../lib/perfdata.h"
43#include "../lib/thresholds.h"
44#include "check_load.d/config.h"
39 45
40#include <string.h> 46// getloadavg comes from gnulib
41 47#include "../gl/stdlib.h"
42#ifdef HAVE_SYS_LOADAVG_H
43#include <sys/loadavg.h>
44#endif
45 48
46/* needed for compilation under NetBSD, as suggested by Andy Doran */ 49/* needed for compilation under NetBSD, as suggested by Andy Doran */
47#ifndef LOADAVG_1MIN 50#ifndef LOADAVG_1MIN
48#define LOADAVG_1MIN 0 51# define LOADAVG_1MIN 0
49#define LOADAVG_5MIN 1 52# define LOADAVG_5MIN 1
50#define LOADAVG_15MIN 2 53# define LOADAVG_15MIN 2
51#endif /* !defined LOADAVG_1MIN */ 54#endif /* !defined LOADAVG_1MIN */
52 55
56typedef struct {
57 int errorcode;
58 check_load_config config;
59} check_load_config_wrapper;
60static check_load_config_wrapper process_arguments(int argc, char **argv);
61
62void print_help(void);
63void print_usage(void);
64typedef struct {
65 int errorcode;
66 char **top_processes;
67} top_processes_result;
68static top_processes_result print_top_consuming_processes(unsigned long n_procs_to_show);
69
70typedef struct {
71 mp_range load[3];
72} parsed_thresholds;
73static parsed_thresholds get_threshold(char *arg) {
74 size_t index;
75 char *str = arg;
76 char *tmp_pointer;
77 bool valid = false;
78
79 parsed_thresholds result = {
80 .load =
81 {
82 mp_range_init(),
83 mp_range_init(),
84 mp_range_init(),
85 },
86 };
53 87
54static int process_arguments (int argc, char **argv); 88 size_t arg_length = strlen(arg);
55static int validate_arguments (void); 89 for (index = 0; index < 3; index++) {
56void print_help (void); 90 double tmp = strtod(str, &tmp_pointer);
57void print_usage (void); 91 if (tmp_pointer == str) {
58static int print_top_consuming_processes(); 92 break;
59 93 }
60static int n_procs_to_show = 0;
61
62/* strictly for pretty-print usage in loops */
63static const int nums[3] = { 1, 5, 15 };
64
65/* provide some fairly sane defaults */
66double wload[3] = { 0.0, 0.0, 0.0 };
67double cload[3] = { 0.0, 0.0, 0.0 };
68#define la1 la[0]
69#define la5 la[1]
70#define la15 la[2]
71
72char *status_line;
73bool take_into_account_cpus = false;
74
75static void
76get_threshold(char *arg, double *th)
77{
78 size_t i, n;
79 int valid = 0;
80 char *str = arg, *p;
81 94
82 n = strlen(arg); 95 result.load[index] = mp_range_set_end(result.load[index], mp_create_pd_value(tmp));
83 for(i = 0; i < 3; i++) {
84 th[i] = strtod(str, &p);
85 if(p == str) break;
86 96
87 valid = 1; 97 valid = true;
88 str = p + 1; 98 str = tmp_pointer + 1;
89 if(n <= (size_t)(str - arg)) break; 99 if (arg_length <= (size_t)(str - arg)) {
100 break;
101 }
90 } 102 }
91 103
92 /* empty argument or non-floatish, so warn about it and die */ 104 /* empty argument or non-floatish, so warn about it and die */
93 if(!i && !valid) usage (_("Warning threshold must be float or float triplet!\n")); 105 if (!index && !valid) {
106 usage(_("Warning threshold must be float or float triplet!\n"));
107 }
94 108
95 if(i != 2) { 109 if (index != 2) {
96 /* one or more numbers were given, so fill array with last 110 /* one or more numbers were given, so fill array with last
97 * we got (most likely to NOT produce the least expected result) */ 111 * we got (most likely to NOT produce the least expected result) */
98 for(n = i; n < 3; n++) th[n] = th[i]; 112 for (size_t tmp_index = index; tmp_index < 3; tmp_index++) {
113 result.load[tmp_index] = result.load[index];
114 }
99 } 115 }
116 return result;
100} 117}
101 118
102 119int main(int argc, char **argv) {
103int 120 setlocale(LC_ALL, "");
104main (int argc, char **argv) 121 bindtextdomain(PACKAGE, LOCALEDIR);
105{ 122 textdomain(PACKAGE);
106 int result = -1;
107 int i;
108 long numcpus;
109
110 double la[3] = { 0.0, 0.0, 0.0 }; /* NetBSD complains about uninitialized arrays */
111#ifndef HAVE_GETLOADAVG
112 char input_buffer[MAX_INPUT_BUFFER];
113#endif
114
115 setlocale (LC_ALL, "");
116 bindtextdomain (PACKAGE, LOCALEDIR);
117 textdomain (PACKAGE);
118 setlocale(LC_NUMERIC, "POSIX"); 123 setlocale(LC_NUMERIC, "POSIX");
119 124
120 /* Parse extra opts if any */ 125 /* Parse extra opts if any */
121 argv = np_extra_opts (&argc, argv, progname); 126 argv = np_extra_opts(&argc, argv, progname);
122 127
123 if (process_arguments (argc, argv) == ERROR) 128 check_load_config_wrapper tmp_config = process_arguments(argc, argv);
124 usage4 (_("Could not parse arguments")); 129 if (tmp_config.errorcode == ERROR) {
125 130 usage4(_("Could not parse arguments"));
126#ifdef HAVE_GETLOADAVG
127 result = getloadavg (la, 3);
128 if (result != 3)
129 return STATE_UNKNOWN;
130#else
131 child_process = spopen (PATH_TO_UPTIME);
132 if (child_process == NULL) {
133 printf (_("Error opening %s\n"), PATH_TO_UPTIME);
134 return STATE_UNKNOWN;
135 }
136 child_stderr = fdopen (child_stderr_array[fileno (child_process)], "r");
137 if (child_stderr == NULL) {
138 printf (_("Could not open stderr for %s\n"), PATH_TO_UPTIME);
139 }
140 fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process);
141 if(strstr(input_buffer, "load average:")) {
142 sscanf (input_buffer, "%*[^l]load average: %lf, %lf, %lf", &la1, &la5, &la15);
143 }
144 else if(strstr(input_buffer, "load averages:")) {
145 sscanf (input_buffer, "%*[^l]load averages: %lf, %lf, %lf", &la1, &la5, &la15);
146 }
147 else {
148 printf (_("could not parse load from uptime %s: %d\n"), PATH_TO_UPTIME, result);
149 return STATE_UNKNOWN;
150 }
151
152 result = spclose (child_process);
153 if (result) {
154 printf (_("Error code %d returned in %s\n"), result, PATH_TO_UPTIME);
155 return STATE_UNKNOWN;
156 }
157#endif
158
159 if ((la[0] < 0.0) || (la[1] < 0.0) || (la[2] < 0.0)) {
160#ifdef HAVE_GETLOADAVG
161 printf (_("Error in getloadavg()\n"));
162#else
163 printf (_("Error processing %s\n"), PATH_TO_UPTIME);
164#endif
165 return STATE_UNKNOWN;
166 } 131 }
167 132
168 /* we got this far, so assume OK until we've measured */ 133 const check_load_config config = tmp_config.config;
169 result = STATE_OK; 134
135 double load_values[3] = {0, 0, 0};
170 136
171 xasprintf(&status_line, _("load average: %.2f, %.2f, %.2f"), la1, la5, la15); 137 // this should be getloadavg from gnulib, should work everywhereâ„¢
172 xasprintf(&status_line, ("total %s"), status_line); 138 int error = getloadavg(load_values, 3);
139 if (error != 3) {
140 die(STATE_UNKNOWN, _("Failed to retrieve load values"));
141 }
173 142
143 mp_check overall = mp_check_init();
144 if (config.output_format_set) {
145 mp_set_format(config.output_format);
146 }
174 147
175 double scaled_la[3] = { 0.0, 0.0, 0.0 };
176 bool is_using_scaled_load_values = false; 148 bool is_using_scaled_load_values = false;
177 149 long numcpus;
178 if (take_into_account_cpus == true && (numcpus = GET_NUMBER_OF_CPUS()) > 0) { 150 if (config.take_into_account_cpus && ((numcpus = GET_NUMBER_OF_CPUS()) > 0)) {
179 is_using_scaled_load_values = true; 151 is_using_scaled_load_values = true;
180 152
181 scaled_la[0] = la[0] / numcpus; 153 double scaled_la[3] = {
182 scaled_la[1] = la[1] / numcpus; 154 load_values[0] / numcpus,
183 scaled_la[2] = la[2] / numcpus; 155 load_values[1] / numcpus,
156 load_values[2] / numcpus,
157 };
158
159 mp_subcheck scaled_load_sc = mp_subcheck_init();
160 scaled_load_sc = mp_set_subcheck_default_state(scaled_load_sc, STATE_OK);
161 scaled_load_sc.output = "Scaled Load (divided by number of CPUs";
162
163 mp_perfdata pd_scaled_load1 = perfdata_init();
164 pd_scaled_load1.label = "scaled_load1";
165 pd_scaled_load1 = mp_set_pd_value(pd_scaled_load1, scaled_la[0]);
166 pd_scaled_load1 = mp_pd_set_thresholds(pd_scaled_load1, config.th_load[0]);
167
168 mp_subcheck scaled_load_sc1 = mp_subcheck_init();
169 scaled_load_sc1 = mp_set_subcheck_state(scaled_load_sc1, mp_get_pd_status(pd_scaled_load1));
170 mp_add_perfdata_to_subcheck(&scaled_load_sc1, pd_scaled_load1);
171 xasprintf(&scaled_load_sc1.output, "1 Minute: %s",
172 pd_value_to_string(pd_scaled_load1.value));
173 mp_add_subcheck_to_subcheck(&scaled_load_sc, scaled_load_sc1);
174
175 mp_perfdata pd_scaled_load5 = perfdata_init();
176 pd_scaled_load5.label = "scaled_load5";
177 pd_scaled_load5 = mp_set_pd_value(pd_scaled_load5, scaled_la[1]);
178 pd_scaled_load5 = mp_pd_set_thresholds(pd_scaled_load5, config.th_load[1]);
179
180 mp_subcheck scaled_load_sc5 = mp_subcheck_init();
181 scaled_load_sc5 = mp_set_subcheck_state(scaled_load_sc5, mp_get_pd_status(pd_scaled_load5));
182 mp_add_perfdata_to_subcheck(&scaled_load_sc5, pd_scaled_load5);
183 xasprintf(&scaled_load_sc5.output, "5 Minutes: %s",
184 pd_value_to_string(pd_scaled_load5.value));
185 mp_add_subcheck_to_subcheck(&scaled_load_sc, scaled_load_sc5);
186
187 mp_perfdata pd_scaled_load15 = perfdata_init();
188 pd_scaled_load15.label = "scaled_load15";
189 pd_scaled_load15 = mp_set_pd_value(pd_scaled_load15, scaled_la[2]);
190 pd_scaled_load15 = mp_pd_set_thresholds(pd_scaled_load15, config.th_load[2]);
191
192 mp_subcheck scaled_load_sc15 = mp_subcheck_init();
193 scaled_load_sc15 =
194 mp_set_subcheck_state(scaled_load_sc15, mp_get_pd_status(pd_scaled_load15));
195 mp_add_perfdata_to_subcheck(&scaled_load_sc15, pd_scaled_load15);
196 xasprintf(&scaled_load_sc15.output, "15 Minutes: %s",
197 pd_value_to_string(pd_scaled_load15.value));
198 mp_add_subcheck_to_subcheck(&scaled_load_sc, scaled_load_sc15);
199
200 mp_add_subcheck_to_check(&overall, scaled_load_sc);
201 }
202
203 mp_subcheck load_sc = mp_subcheck_init();
204 load_sc = mp_set_subcheck_default_state(load_sc, STATE_OK);
205 load_sc.output = "Total Load";
184 206
185 char *tmp = NULL; 207 mp_perfdata pd_load1 = perfdata_init();
186 xasprintf(&tmp, _("load average: %.2f, %.2f, %.2f"), scaled_la[0], scaled_la[1], scaled_la[2]); 208 pd_load1.label = "load1";
187 xasprintf(&status_line, "scaled %s - %s", tmp, status_line); 209 pd_load1 = mp_set_pd_value(pd_load1, load_values[0]);
210 if (!is_using_scaled_load_values) {
211 pd_load1 = mp_pd_set_thresholds(pd_load1, config.th_load[0]);
188 } 212 }
189 213
190 for(i = 0; i < 3; i++) { 214 mp_subcheck load_sc1 = mp_subcheck_init();
191 if (is_using_scaled_load_values) { 215 load_sc1 = mp_set_subcheck_state(load_sc1, mp_get_pd_status(pd_load1));
192 if(scaled_la[i] > cload[i]) { 216 mp_add_perfdata_to_subcheck(&load_sc1, pd_load1);
193 result = STATE_CRITICAL; 217 xasprintf(&load_sc1.output, "1 Minute: %s", pd_value_to_string(pd_load1.value));
194 break; 218 mp_add_subcheck_to_subcheck(&load_sc, load_sc1);
195 } 219
196 else if(scaled_la[i] > wload[i]) result = STATE_WARNING; 220 mp_perfdata pd_load5 = perfdata_init();
197 } else { 221 pd_load5.label = "load5";
198 if(la[i] > cload[i]) { 222 pd_load5 = mp_set_pd_value(pd_load5, load_values[1]);
199 result = STATE_CRITICAL; 223 if (!is_using_scaled_load_values) {
200 break; 224 pd_load5 = mp_pd_set_thresholds(pd_load5, config.th_load[1]);
201 }
202 else if(la[i] > wload[i]) result = STATE_WARNING;
203 }
204 } 225 }
205 226
206 printf("LOAD %s - %s|", state_text(result), status_line); 227 mp_subcheck load_sc5 = mp_subcheck_init();
207 for(i = 0; i < 3; i++) { 228 load_sc5 = mp_set_subcheck_state(load_sc5, mp_get_pd_status(pd_load5));
208 if (is_using_scaled_load_values) { 229 mp_add_perfdata_to_subcheck(&load_sc5, pd_load5);
209 printf("load%d=%.3f;;;0; ", nums[i], la[i]); 230 xasprintf(&load_sc5.output, "5 Minutes: %s", pd_value_to_string(pd_load5.value));
210 printf("scaled_load%d=%.3f;%.3f;%.3f;0; ", nums[i], scaled_la[i], wload[i], cload[i]); 231 mp_add_subcheck_to_subcheck(&load_sc, load_sc5);
211 } else { 232
212 printf("load%d=%.3f;%.3f;%.3f;0; ", nums[i], la[i], wload[i], cload[i]); 233 mp_perfdata pd_load15 = perfdata_init();
213 } 234 pd_load15.label = "load15";
235 pd_load15 = mp_set_pd_value(pd_load15, load_values[2]);
236 if (!is_using_scaled_load_values) {
237 pd_load15 = mp_pd_set_thresholds(pd_load15, config.th_load[2]);
214 } 238 }
215 239
216 putchar('\n'); 240 mp_subcheck load_sc15 = mp_subcheck_init();
217 if (n_procs_to_show > 0) { 241 load_sc15 = mp_set_subcheck_state(load_sc15, mp_get_pd_status(pd_load15));
218 print_top_consuming_processes(); 242 mp_add_perfdata_to_subcheck(&load_sc15, pd_load15);
243 xasprintf(&load_sc15.output, "15 Minutes: %s", pd_value_to_string(pd_load15.value));
244 mp_add_subcheck_to_subcheck(&load_sc, load_sc15);
245
246 mp_add_subcheck_to_check(&overall, load_sc);
247
248 if (config.n_procs_to_show > 0) {
249 mp_subcheck top_proc_sc = mp_subcheck_init();
250 top_proc_sc = mp_set_subcheck_state(top_proc_sc, STATE_OK);
251 top_processes_result top_proc = print_top_consuming_processes(config.n_procs_to_show);
252 xasprintf(&top_proc_sc.output, "Top %lu CPU time consuming processes",
253 config.n_procs_to_show);
254
255 if (top_proc.errorcode == OK) {
256 for (unsigned long i = 0; i < config.n_procs_to_show; i++) {
257 xasprintf(&top_proc_sc.output, "%s\n%s", top_proc_sc.output,
258 top_proc.top_processes[i]);
259 }
260 }
261
262 mp_add_subcheck_to_check(&overall, top_proc_sc);
219 } 263 }
220 return result;
221}
222 264
265 mp_exit(overall);
266}
223 267
224/* process command-line arguments */ 268/* process command-line arguments */
225static int 269static check_load_config_wrapper process_arguments(int argc, char **argv) {
226process_arguments (int argc, char **argv) 270
227{ 271 enum {
228 int c = 0; 272 output_format_index = CHAR_MAX + 1,
229
230 int option = 0;
231 static struct option longopts[] = {
232 {"warning", required_argument, 0, 'w'},
233 {"critical", required_argument, 0, 'c'},
234 {"percpu", no_argument, 0, 'r'},
235 {"version", no_argument, 0, 'V'},
236 {"help", no_argument, 0, 'h'},
237 {"procs-to-show", required_argument, 0, 'n'},
238 {0, 0, 0, 0}
239 }; 273 };
240 274
241 if (argc < 2) 275 static struct option longopts[] = {{"warning", required_argument, 0, 'w'},
242 return ERROR; 276 {"critical", required_argument, 0, 'c'},
277 {"percpu", no_argument, 0, 'r'},
278 {"version", no_argument, 0, 'V'},
279 {"help", no_argument, 0, 'h'},
280 {"procs-to-show", required_argument, 0, 'n'},
281 {"output-format", required_argument, 0, output_format_index},
282 {0, 0, 0, 0}};
283
284 check_load_config_wrapper result = {
285 .errorcode = OK,
286 .config = check_load_config_init(),
287 };
243 288
244 while (1) { 289 if (argc < 2) {
245 c = getopt_long (argc, argv, "Vhrc:w:n:", longopts, &option); 290 result.errorcode = ERROR;
291 return result;
292 }
246 293
247 if (c == -1 || c == EOF) 294 while (true) {
248 break; 295 int option = 0;
296 int option_index = getopt_long(argc, argv, "Vhrc:w:n:", longopts, &option);
249 297
250 switch (c) { 298 if (option_index == -1 || option_index == EOF) {
251 case 'w': /* warning time threshold */
252 get_threshold(optarg, wload);
253 break; 299 break;
254 case 'c': /* critical time threshold */ 300 }
255 get_threshold(optarg, cload); 301
302 switch (option_index) {
303 case output_format_index: {
304 parsed_output_format parser = mp_parse_output_format(optarg);
305 if (!parser.parsing_success) {
306 printf("Invalid output format: %s\n", optarg);
307 exit(STATE_UNKNOWN);
308 }
309
310 result.config.output_format_set = true;
311 result.config.output_format = parser.output_format;
256 break; 312 break;
313 }
314 case 'w': /* warning time threshold */ {
315 parsed_thresholds warning_range = get_threshold(optarg);
316 result.config.th_load[0].warning = warning_range.load[0];
317 result.config.th_load[0].warning_is_set = true;
318
319 result.config.th_load[1].warning = warning_range.load[1];
320 result.config.th_load[1].warning_is_set = true;
321
322 result.config.th_load[2].warning = warning_range.load[2];
323 result.config.th_load[2].warning_is_set = true;
324 } break;
325 case 'c': /* critical time threshold */ {
326 parsed_thresholds critical_range = get_threshold(optarg);
327 result.config.th_load[0].critical = critical_range.load[0];
328 result.config.th_load[0].critical_is_set = true;
329
330 result.config.th_load[1].critical = critical_range.load[1];
331 result.config.th_load[1].critical_is_set = true;
332
333 result.config.th_load[2].critical = critical_range.load[2];
334 result.config.th_load[2].critical_is_set = true;
335 } break;
257 case 'r': /* Divide load average by number of CPUs */ 336 case 'r': /* Divide load average by number of CPUs */
258 take_into_account_cpus = true; 337 result.config.take_into_account_cpus = true;
259 break; 338 break;
260 case 'V': /* version */ 339 case 'V': /* version */
261 print_revision (progname, NP_VERSION); 340 print_revision(progname, NP_VERSION);
262 exit (STATE_UNKNOWN); 341 exit(STATE_UNKNOWN);
263 case 'h': /* help */ 342 case 'h': /* help */
264 print_help (); 343 print_help();
265 exit (STATE_UNKNOWN); 344 exit(STATE_UNKNOWN);
266 case 'n': 345 case 'n':
267 n_procs_to_show = atoi(optarg); 346 result.config.n_procs_to_show = (unsigned long)atol(optarg);
268 break; 347 break;
269 case '?': /* help */ 348 case '?': /* help */
270 usage5 (); 349 usage5();
271 } 350 }
272 } 351 }
273 352
274 c = optind; 353 int index = optind;
275 if (c == argc) 354 if (index == argc) {
276 return validate_arguments (); 355 return result;
356 }
277 357
278 /* handle the case if both arguments are missing, 358 /* handle the case if both arguments are missing,
279 * but not if only one is given without -c or -w flag */ 359 * but not if only one is given without -c or -w flag */
280 if(c - argc == 2) { 360 if (index - argc == 2) {
281 get_threshold(argv[c++], wload); 361 parsed_thresholds warning_range = get_threshold(argv[index++]);
282 get_threshold(argv[c++], cload); 362 result.config.th_load[0].warning = warning_range.load[0];
283 } 363 result.config.th_load[0].warning_is_set = true;
284 else if(c - argc == 1) { 364
285 get_threshold(argv[c++], cload); 365 result.config.th_load[1].warning = warning_range.load[1];
286 } 366 result.config.th_load[1].warning_is_set = true;
287 367
288 return validate_arguments (); 368 result.config.th_load[2].warning = warning_range.load[2];
289} 369 result.config.th_load[2].warning_is_set = true;
290 370 parsed_thresholds critical_range = get_threshold(argv[index++]);
291 371 result.config.th_load[0].critical = critical_range.load[0];
292static int 372 result.config.th_load[0].critical_is_set = true;
293validate_arguments (void) 373
294{ 374 result.config.th_load[1].critical = critical_range.load[1];
295 int i = 0; 375 result.config.th_load[1].critical_is_set = true;
296 376
297 /* match cload first, as it will give the most friendly error message 377 result.config.th_load[2].critical = critical_range.load[2];
298 * if user hasn't given the -c switch properly */ 378 result.config.th_load[2].critical_is_set = true;
299 for(i = 0; i < 3; i++) { 379 } else if (index - argc == 1) {
300 if(cload[i] < 0) 380 parsed_thresholds critical_range = get_threshold(argv[index++]);
301 die (STATE_UNKNOWN, _("Critical threshold for %d-minute load average is not specified\n"), nums[i]); 381 result.config.th_load[0].critical = critical_range.load[0];
302 if(wload[i] < 0) 382 result.config.th_load[0].critical_is_set = true;
303 die (STATE_UNKNOWN, _("Warning threshold for %d-minute load average is not specified\n"), nums[i]); 383
304 if(wload[i] > cload[i]) 384 result.config.th_load[1].critical = critical_range.load[1];
305 die (STATE_UNKNOWN, _("Parameter inconsistency: %d-minute \"warning load\" is greater than \"critical load\"\n"), nums[i]); 385 result.config.th_load[1].critical_is_set = true;
386
387 result.config.th_load[2].critical = critical_range.load[2];
388 result.config.th_load[2].critical_is_set = true;
306 } 389 }
307 390
308 return OK; 391 return result;
309} 392}
310 393
394void print_help(void) {
395 print_revision(progname, NP_VERSION);
311 396
312void 397 printf("Copyright (c) 1999 Felipe Gustavo de Almeida <galmeida@linux.ime.usp.br>\n");
313print_help (void) 398 printf(COPYRIGHT, copyright, email);
314{
315 print_revision (progname, NP_VERSION);
316 399
317 printf ("Copyright (c) 1999 Felipe Gustavo de Almeida <galmeida@linux.ime.usp.br>\n"); 400 printf(_("This plugin tests the current system load average."));
318 printf (COPYRIGHT, copyright, email);
319 401
320 printf (_("This plugin tests the current system load average.")); 402 printf("\n\n");
321 403
322 printf ("\n\n"); 404 print_usage();
323 405
324 print_usage (); 406 printf(UT_HELP_VRSN);
407 printf(UT_EXTRA_OPTS);
325 408
326 printf (UT_HELP_VRSN); 409 printf(" %s\n", "-w, --warning=WLOAD1,WLOAD5,WLOAD15");
327 printf (UT_EXTRA_OPTS); 410 printf(" %s\n", _("Exit with WARNING status if load average exceeds WLOADn"));
411 printf(" %s\n", "-c, --critical=CLOAD1,CLOAD5,CLOAD15");
412 printf(" %s\n", _("Exit with CRITICAL status if load average exceed CLOADn"));
413 printf(" %s\n", _("the load average format is the same used by \"uptime\" and \"w\""));
414 printf(" %s\n", "-r, --percpu");
415 printf(" %s\n", _("Divide the load averages by the number of CPUs (when possible)"));
416 printf(" %s\n", "-n, --procs-to-show=NUMBER_OF_PROCS");
417 printf(" %s\n", _("Number of processes to show when printing the top consuming processes."));
418 printf(" %s\n", _("NUMBER_OF_PROCS=0 disables this feature. Default value is 0"));
328 419
329 printf (" %s\n", "-w, --warning=WLOAD1,WLOAD5,WLOAD15"); 420 printf(UT_OUTPUT_FORMAT);
330 printf (" %s\n", _("Exit with WARNING status if load average exceeds WLOADn")); 421 printf(UT_SUPPORT);
331 printf (" %s\n", "-c, --critical=CLOAD1,CLOAD5,CLOAD15");
332 printf (" %s\n", _("Exit with CRITICAL status if load average exceed CLOADn"));
333 printf (" %s\n", _("the load average format is the same used by \"uptime\" and \"w\""));
334 printf (" %s\n", "-r, --percpu");
335 printf (" %s\n", _("Divide the load averages by the number of CPUs (when possible)"));
336 printf (" %s\n", "-n, --procs-to-show=NUMBER_OF_PROCS");
337 printf (" %s\n", _("Number of processes to show when printing the top consuming processes."));
338 printf (" %s\n", _("NUMBER_OF_PROCS=0 disables this feature. Default value is 0"));
339
340 printf (UT_SUPPORT);
341} 422}
342 423
343void 424void print_usage(void) {
344print_usage (void) 425 printf("%s\n", _("Usage:"));
345{ 426 printf("%s [-r] -w WLOAD1,WLOAD5,WLOAD15 -c CLOAD1,CLOAD5,CLOAD15 [-n NUMBER_OF_PROCS]\n",
346 printf ("%s\n", _("Usage:")); 427 progname);
347 printf ("%s [-r] -w WLOAD1,WLOAD5,WLOAD15 -c CLOAD1,CLOAD5,CLOAD15 [-n NUMBER_OF_PROCS]\n", progname);
348} 428}
349 429
350#ifdef PS_USES_PROCPCPU 430#ifdef PS_USES_PROCPCPU
@@ -356,36 +436,52 @@ int cmpstringp(const void *p1, const void *p2) {
356 int procrss = 0; 436 int procrss = 0;
357 float procpcpu = 0; 437 float procpcpu = 0;
358 char procstat[8]; 438 char procstat[8];
359#ifdef PS_USES_PROCETIME 439# ifdef PS_USES_PROCETIME
360 char procetime[MAX_INPUT_BUFFER]; 440 char procetime[MAX_INPUT_BUFFER];
361#endif /* PS_USES_PROCETIME */ 441# endif /* PS_USES_PROCETIME */
362 char procprog[MAX_INPUT_BUFFER]; 442 char procprog[MAX_INPUT_BUFFER];
363 int pos; 443 int pos;
364 sscanf (* (char * const *) p1, PS_FORMAT, PS_VARLIST); 444 sscanf(*(char *const *)p1, PS_FORMAT, PS_VARLIST);
365 float procpcpu1 = procpcpu; 445 float procpcpu1 = procpcpu;
366 sscanf (* (char * const *) p2, PS_FORMAT, PS_VARLIST); 446 sscanf(*(char *const *)p2, PS_FORMAT, PS_VARLIST);
367 return procpcpu1 < procpcpu; 447 return procpcpu1 < procpcpu;
368} 448}
369#endif /* PS_USES_PROCPCPU */ 449#endif /* PS_USES_PROCPCPU */
370 450
371static int print_top_consuming_processes() { 451static top_processes_result print_top_consuming_processes(unsigned long n_procs_to_show) {
372 int i = 0; 452 top_processes_result result = {
373 struct output chld_out, chld_err; 453 .errorcode = OK,
374 if(np_runcmd(PS_COMMAND, &chld_out, &chld_err, 0) != 0){ 454 };
455 output chld_out;
456 output chld_err;
457 if (np_runcmd(PS_COMMAND, &chld_out, &chld_err, 0) != 0) {
375 fprintf(stderr, _("'%s' exited with non-zero status.\n"), PS_COMMAND); 458 fprintf(stderr, _("'%s' exited with non-zero status.\n"), PS_COMMAND);
376 return STATE_UNKNOWN; 459 result.errorcode = ERROR;
460 return result;
377 } 461 }
462
378 if (chld_out.lines < 2) { 463 if (chld_out.lines < 2) {
379 fprintf(stderr, _("some error occurred getting procs list.\n")); 464 fprintf(stderr, _("some error occurred getting procs list.\n"));
380 return STATE_UNKNOWN; 465 result.errorcode = ERROR;
466 return result;
381 } 467 }
468
382#ifdef PS_USES_PROCPCPU 469#ifdef PS_USES_PROCPCPU
383 qsort(chld_out.line + 1, chld_out.lines - 1, sizeof(char*), cmpstringp); 470 qsort(chld_out.line + 1, chld_out.lines - 1, sizeof(char *), cmpstringp);
384#endif /* PS_USES_PROCPCPU */ 471#endif /* PS_USES_PROCPCPU */
385 int lines_to_show = chld_out.lines < (size_t)(n_procs_to_show + 1) 472 unsigned long lines_to_show =
386 ? (int)chld_out.lines : n_procs_to_show + 1; 473 chld_out.lines < (size_t)(n_procs_to_show + 1) ? chld_out.lines : n_procs_to_show + 1;
387 for (i = 0; i < lines_to_show; i += 1) { 474
388 printf("%s\n", chld_out.line[i]); 475 result.top_processes = calloc(lines_to_show, sizeof(char *));
476 if (result.top_processes == NULL) {
477 // Failed allocation
478 result.errorcode = ERROR;
479 return result;
389 } 480 }
390 return OK; 481
482 for (unsigned long i = 0; i < lines_to_show; i += 1) {
483 xasprintf(&result.top_processes[i], "%s", chld_out.line[i]);
484 }
485
486 return result;
391} 487}