summaryrefslogtreecommitdiffstats
path: root/lib/perfdata.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/perfdata.c')
-rw-r--r--lib/perfdata.c516
1 files changed, 516 insertions, 0 deletions
diff --git a/lib/perfdata.c b/lib/perfdata.c
new file mode 100644
index 00000000..661756c5
--- /dev/null
+++ b/lib/perfdata.c
@@ -0,0 +1,516 @@
1#include "./perfdata.h"
2#include "../plugins/common.h"
3#include "../plugins/utils.h"
4#include "utils_base.h"
5
6#include <assert.h>
7#include <limits.h>
8#include <stdlib.h>
9
10char *pd_value_to_string(const mp_perfdata_value pd) {
11 char *result = NULL;
12
13 assert(pd.type != PD_TYPE_NONE);
14
15 switch (pd.type) {
16 case PD_TYPE_INT:
17 asprintf(&result, "%lli", pd.pd_int);
18 break;
19 case PD_TYPE_UINT:
20 asprintf(&result, "%llu", pd.pd_int);
21 break;
22 case PD_TYPE_DOUBLE:
23 asprintf(&result, "%f", pd.pd_double);
24 break;
25 default:
26 // die here
27 die(STATE_UNKNOWN, "Invalid mp_perfdata mode\n");
28 }
29
30 return result;
31}
32
33char *pd_to_string(mp_perfdata pd) {
34 assert(pd.label != NULL);
35 char *result = NULL;
36 asprintf(&result, "%s=", pd.label);
37
38 asprintf(&result, "%s%s", result, pd_value_to_string(pd.value));
39
40 if (pd.uom != NULL) {
41 asprintf(&result, "%s%s", result, pd.uom);
42 }
43
44 if (pd.warn_present) {
45 asprintf(&result, "%s;%s", result, mp_range_to_string(pd.warn));
46 } else {
47 asprintf(&result, "%s;", result);
48 }
49
50 if (pd.crit_present) {
51 asprintf(&result, "%s;%s", result, mp_range_to_string(pd.crit));
52 } else {
53 asprintf(&result, "%s;", result);
54 }
55 if (pd.min_present) {
56 asprintf(&result, "%s;%s", result, pd_value_to_string(pd.min));
57 } else {
58 asprintf(&result, "%s;", result);
59 }
60
61 if (pd.max_present) {
62 asprintf(&result, "%s;%s", result, pd_value_to_string(pd.max));
63 }
64
65 /*printf("pd_to_string: %s\n", result); */
66
67 return result;
68}
69
70char *pd_list_to_string(const pd_list pd) {
71 char *result = pd_to_string(pd.data);
72
73 for (pd_list *elem = pd.next; elem != NULL; elem = elem->next) {
74 asprintf(&result, "%s %s", result, pd_to_string(elem->data));
75 }
76
77 return result;
78}
79
80mp_perfdata perfdata_init() {
81 mp_perfdata pd = {};
82 return pd;
83}
84
85pd_list *pd_list_init() {
86 pd_list *tmp = (pd_list *)calloc(1, sizeof(pd_list));
87 if (tmp == NULL) {
88 die(STATE_UNKNOWN, "calloc failed\n");
89 }
90 tmp->next = NULL;
91 return tmp;
92}
93
94mp_range mp_range_init() {
95 mp_range result = {
96 .alert_on_inside_range = OUTSIDE,
97 .start = {},
98 .start_infinity = true,
99 .end = {},
100 .end_infinity = true,
101 };
102
103 return result;
104}
105
106mp_range mp_range_set_start(mp_range input, mp_perfdata_value perf_val) {
107 input.start = perf_val;
108 input.start_infinity = false;
109 return input;
110}
111
112mp_range mp_range_set_end(mp_range input, mp_perfdata_value perf_val) {
113 input.end = perf_val;
114 input.end_infinity = false;
115 return input;
116}
117
118void pd_list_append(pd_list pdl[1], const mp_perfdata pd) {
119 assert(pdl != NULL);
120
121 if (pdl->data.value.type == PD_TYPE_NONE) {
122 // first entry is still empty
123 pdl->data = pd;
124 } else {
125 // find last element in the list
126 pd_list *curr = pdl;
127 pd_list *next = pdl->next;
128
129 while (next != NULL) {
130 curr = next;
131 next = next->next;
132 }
133
134 if (curr->data.value.type == PD_TYPE_NONE) {
135 // still empty
136 curr->data = pd;
137 } else {
138 // new a new one
139 curr->next = pd_list_init();
140 curr->next->data = pd;
141 }
142 }
143}
144
145void pd_list_free(pd_list pdl[1]) {
146 while (pdl != NULL) {
147 pd_list *old = pdl;
148 pdl = pdl->next;
149 free(old);
150 }
151}
152
153/*
154 * returns -1 if a < b, 0 if a == b, 1 if a > b
155 */
156int cmp_perfdata_value(const mp_perfdata_value a, const mp_perfdata_value b) {
157 // Test if types are different
158 if (a.type == b.type) {
159
160 switch (a.type) {
161 case PD_TYPE_UINT:
162 if (a.pd_uint < b.pd_uint) {
163 return -1;
164 } else if (a.pd_uint == b.pd_uint) {
165 return 0;
166 } else {
167 return 1;
168 }
169 break;
170 case PD_TYPE_INT:
171 if (a.pd_int < b.pd_int) {
172 return -1;
173 } else if (a.pd_int == b.pd_int) {
174 return 0;
175 } else {
176 return 1;
177 }
178 break;
179 case PD_TYPE_DOUBLE:
180 if (a.pd_int < b.pd_int) {
181 return -1;
182 } else if (a.pd_int == b.pd_int) {
183 return 0;
184 } else {
185 return 1;
186 }
187 break;
188 default:
189 die(STATE_UNKNOWN, "Error in %s line: %d!", __FILE__, __LINE__);
190 }
191 }
192
193 // Get dirty here
194 long double floating_a = 0;
195
196 switch (a.type) {
197 case PD_TYPE_UINT:
198 floating_a = a.pd_uint;
199 break;
200 case PD_TYPE_INT:
201 floating_a = a.pd_int;
202 break;
203 case PD_TYPE_DOUBLE:
204 floating_a = a.pd_double;
205 break;
206 default:
207 die(STATE_UNKNOWN, "Error in %s line: %d!", __FILE__, __LINE__);
208 }
209
210 long double floating_b = 0;
211 switch (b.type) {
212 case PD_TYPE_UINT:
213 floating_b = b.pd_uint;
214 break;
215 case PD_TYPE_INT:
216 floating_b = b.pd_int;
217 break;
218 case PD_TYPE_DOUBLE:
219 floating_b = b.pd_double;
220 break;
221 default:
222 die(STATE_UNKNOWN, "Error in %s line: %d!", __FILE__, __LINE__);
223 }
224
225 if (floating_a < floating_b) {
226 return -1;
227 }
228 if (floating_a == floating_b) {
229 return 0;
230 }
231 return 1;
232}
233
234char *mp_range_to_string(const mp_range input) {
235 char *result = "";
236 if (input.alert_on_inside_range == INSIDE) {
237 asprintf(&result, "@");
238 }
239
240 if (input.start_infinity) {
241 asprintf(&result, "%s~:", result);
242 } else {
243 asprintf(&result, "%s%s:", result, pd_value_to_string(input.start));
244 }
245
246 if (!input.end_infinity) {
247 asprintf(&result, "%s%s", result, pd_value_to_string(input.end));
248 }
249 return result;
250}
251
252mp_perfdata mp_set_pd_value_float(mp_perfdata pd, float value) { return mp_set_pd_value_double(pd, value); }
253
254mp_perfdata mp_set_pd_value_double(mp_perfdata pd, double value) {
255 pd.value.pd_double = value;
256 pd.value.type = PD_TYPE_DOUBLE;
257 return pd;
258}
259
260mp_perfdata mp_set_pd_value_int(mp_perfdata pd, int value) { return mp_set_pd_value_long_long(pd, (long long)value); }
261
262mp_perfdata mp_set_pd_value_u_int(mp_perfdata pd, unsigned int value) { return mp_set_pd_value_u_long_long(pd, (unsigned long long)value); }
263
264mp_perfdata mp_set_pd_value_long(mp_perfdata pd, long value) { return mp_set_pd_value_long_long(pd, (long long)value); }
265
266mp_perfdata mp_set_pd_value_u_long(mp_perfdata pd, unsigned long value) {
267 return mp_set_pd_value_u_long_long(pd, (unsigned long long)value);
268}
269
270mp_perfdata mp_set_pd_value_long_long(mp_perfdata pd, long long value) {
271 pd.value.pd_int = value;
272 pd.value.type = PD_TYPE_INT;
273 return pd;
274}
275
276mp_perfdata mp_set_pd_value_u_long_long(mp_perfdata pd, unsigned long long value) {
277 pd.value.pd_uint = value;
278 pd.value.type = PD_TYPE_UINT;
279 return pd;
280}
281
282mp_perfdata_value mp_create_pd_value_double(double value) {
283 mp_perfdata_value res = {0};
284 res.type = PD_TYPE_DOUBLE;
285 res.pd_double = value;
286 return res;
287}
288
289mp_perfdata_value mp_create_pd_value_float(float value) { return mp_create_pd_value_double((double)value); }
290
291mp_perfdata_value mp_create_pd_value_int(int value) { return mp_create_pd_value_long_long((long long)value); }
292
293mp_perfdata_value mp_create_pd_value_u_int(unsigned int value) { return mp_create_pd_value_u_long_long((unsigned long long)value); }
294
295mp_perfdata_value mp_create_pd_value_long(long value) { return mp_create_pd_value_long_long((long long)value); }
296
297mp_perfdata_value mp_create_pd_value_u_long(unsigned long value) { return mp_create_pd_value_u_long_long((unsigned long long)value); }
298
299mp_perfdata_value mp_create_pd_value_long_long(long long value) {
300 mp_perfdata_value res = {0};
301 res.type = PD_TYPE_INT;
302 res.pd_int = value;
303 return res;
304}
305
306mp_perfdata_value mp_create_pd_value_u_long_long(unsigned long long value) {
307 mp_perfdata_value res = {0};
308 res.type = PD_TYPE_UINT;
309 res.pd_uint = value;
310 return res;
311}
312
313char *fmt_range(range foo) { return foo.text; }
314
315typedef struct integer_parser_wrapper {
316 int error;
317 mp_perfdata_value value;
318} integer_parser_wrapper;
319
320typedef struct double_parser_wrapper {
321 int error;
322 mp_perfdata_value value;
323} double_parser_wrapper;
324
325typedef struct perfdata_value_parser_wrapper {
326 int error;
327 mp_perfdata_value value;
328} perfdata_value_parser_wrapper;
329
330double_parser_wrapper parse_double(const char *input);
331integer_parser_wrapper parse_integer(const char *input);
332perfdata_value_parser_wrapper parse_pd_value(const char *input);
333
334mp_range_parsed mp_parse_range_string(const char *input) {
335 if (input == NULL) {
336 mp_range_parsed result = {
337 .error = MP_RANGE_PARSING_FAILURE,
338 };
339 return result;
340 }
341
342 if (strlen(input) == 0) {
343 mp_range_parsed result = {
344 .error = MP_RANGE_PARSING_FAILURE,
345 };
346 return result;
347 }
348
349 mp_range_parsed result = {
350 .range = mp_range_init(),
351 .error = MP_PARSING_SUCCES,
352 };
353
354 if (input[0] == '@') {
355 // found an '@' at beginning, so invert the range logic
356 result.range.alert_on_inside_range = INSIDE;
357
358 // advance the pointer one symbol
359 input++;
360 }
361
362 char *working_copy = strdup(input);
363 input = working_copy;
364
365 char *separator = index(working_copy, ':');
366 if (separator != NULL) {
367 // Found a separator
368 // set the separator to 0, so we have two different strings
369 *separator = '\0';
370
371 if (input[0] == '~') {
372 // the beginning starts with '~', so it might be infinity
373 if (&input[1] != separator) {
374 // the next symbol after '~' is not the separator!
375 // so input is probably wrong
376 result.error = MP_RANGE_PARSING_FAILURE;
377 free(working_copy);
378 return result;
379 }
380
381 result.range.start_infinity = true;
382 } else {
383 // No '~' at the beginning, so this should be a number
384 result.range.start_infinity = false;
385 perfdata_value_parser_wrapper parsed_pd = parse_pd_value(input);
386
387 if (parsed_pd.error != MP_PARSING_SUCCES) {
388 result.error = parsed_pd.error;
389 free(working_copy);
390 return result;
391 }
392
393 result.range.start = parsed_pd.value;
394 result.range.start_infinity = false;
395 }
396 // got the first part now
397 // advance the pointer
398 input = separator + 1;
399 }
400
401 // End part or no separator
402 if (input[0] == '\0') {
403 // the end is infinite
404 result.range.end_infinity = true;
405 } else {
406 perfdata_value_parser_wrapper parsed_pd = parse_pd_value(input);
407
408 if (parsed_pd.error != MP_PARSING_SUCCES) {
409 result.error = parsed_pd.error;
410 return result;
411 }
412 result.range.end = parsed_pd.value;
413 result.range.end_infinity = false;
414 }
415 free(working_copy);
416 return result;
417}
418
419double_parser_wrapper parse_double(const char *input) {
420 double_parser_wrapper result = {
421 .error = MP_PARSING_SUCCES,
422 };
423
424 if (input == NULL) {
425 result.error = MP_PARSING_FAILURE;
426 return result;
427 }
428
429 char *endptr = NULL;
430 errno = 0;
431 double tmp = strtod(input, &endptr);
432
433 if (input == endptr) {
434 // man 3 strtod says, no conversion performed
435 result.error = MP_PARSING_FAILURE;
436 return result;
437 }
438
439 if (errno) {
440 // some other error
441 // TODO maybe differentiate a little bit
442 result.error = MP_PARSING_FAILURE;
443 return result;
444 }
445
446 result.value = mp_create_pd_value(tmp);
447 return result;
448}
449
450integer_parser_wrapper parse_integer(const char *input) {
451 integer_parser_wrapper result = {
452 .error = MP_PARSING_SUCCES,
453 };
454
455 if (input == NULL) {
456 result.error = MP_PARSING_FAILURE;
457 return result;
458 }
459
460 char *endptr = NULL;
461 errno = 0;
462 long long tmp = strtoll(input, &endptr, 0);
463
464 // validating *sigh*
465 if (*endptr != '\0') {
466 // something went wrong in strtoll
467 if (tmp == LLONG_MIN) {
468 // underflow
469 result.error = MP_RANGE_PARSING_UNDERFLOW;
470 return result;
471 }
472
473 if (tmp == LLONG_MAX) {
474 // overflow
475 result.error = MP_RANGE_PARSING_OVERFLOW;
476 return result;
477 }
478
479 // still wrong, but not sure why, probably invalid characters
480 if (errno == EINVAL) {
481 result.error = MP_RANGE_PARSING_INVALID_CHAR;
482 return result;
483 }
484
485 // some other error, do catch all here
486 result.error = MP_RANGE_PARSING_FAILURE;
487 return result;
488 }
489
490 // no error, should be fine
491 result.value = mp_create_pd_value(tmp);
492 return result;
493}
494
495perfdata_value_parser_wrapper parse_pd_value(const char *input) {
496 // try integer first
497 integer_parser_wrapper tmp_int = parse_integer(input);
498
499 if (tmp_int.error == MP_PARSING_SUCCES) {
500 perfdata_value_parser_wrapper result = {
501 .error = tmp_int.error,
502 .value = tmp_int.value,
503 };
504 return result;
505 }
506
507 double_parser_wrapper tmp_double = parse_double(input);
508 perfdata_value_parser_wrapper result = {};
509 if (tmp_double.error == MP_PARSING_SUCCES) {
510 result.error = tmp_double.error;
511 result.value = tmp_double.value;
512 } else {
513 result.error = tmp_double.error;
514 }
515 return result;
516}