summaryrefslogtreecommitdiffstats
path: root/lib/perfdata.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/perfdata.c')
-rw-r--r--lib/perfdata.c605
1 files changed, 605 insertions, 0 deletions
diff --git a/lib/perfdata.c b/lib/perfdata.c
new file mode 100644
index 00000000..b87de7e0
--- /dev/null
+++ b/lib/perfdata.c
@@ -0,0 +1,605 @@
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_char(mp_perfdata pd, char value) { return mp_set_pd_value_long_long(pd, (long long)value); }
261
262mp_perfdata mp_set_pd_value_u_char(mp_perfdata pd, unsigned char value) { return mp_set_pd_value_u_long_long(pd, (unsigned long long)value); }
263
264mp_perfdata mp_set_pd_value_int(mp_perfdata pd, int value) { return mp_set_pd_value_long_long(pd, (long long)value); }
265
266mp_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); }
267
268mp_perfdata mp_set_pd_value_long(mp_perfdata pd, long value) { return mp_set_pd_value_long_long(pd, (long long)value); }
269
270mp_perfdata mp_set_pd_value_u_long(mp_perfdata pd, unsigned long value) {
271 return mp_set_pd_value_u_long_long(pd, (unsigned long long)value);
272}
273
274mp_perfdata mp_set_pd_value_long_long(mp_perfdata pd, long long value) {
275 pd.value.pd_int = value;
276 pd.value.type = PD_TYPE_INT;
277 return pd;
278}
279
280mp_perfdata mp_set_pd_value_u_long_long(mp_perfdata pd, unsigned long long value) {
281 pd.value.pd_uint = value;
282 pd.value.type = PD_TYPE_UINT;
283 return pd;
284}
285
286mp_perfdata_value mp_create_pd_value_double(double value) {
287 mp_perfdata_value res = {0};
288 res.type = PD_TYPE_DOUBLE;
289 res.pd_double = value;
290 return res;
291}
292
293mp_perfdata_value mp_create_pd_value_float(float value) { return mp_create_pd_value_double((double)value); }
294
295mp_perfdata_value mp_create_pd_value_char(char value) { return mp_create_pd_value_long_long((long long)value); }
296
297mp_perfdata_value mp_create_pd_value_u_char(unsigned char value) { return mp_create_pd_value_u_long_long((unsigned long long)value); }
298
299mp_perfdata_value mp_create_pd_value_int(int value) { return mp_create_pd_value_long_long((long long)value); }
300
301mp_perfdata_value mp_create_pd_value_u_int(unsigned int value) { return mp_create_pd_value_u_long_long((unsigned long long)value); }
302
303mp_perfdata_value mp_create_pd_value_long(long value) { return mp_create_pd_value_long_long((long long)value); }
304
305mp_perfdata_value mp_create_pd_value_u_long(unsigned long value) { return mp_create_pd_value_u_long_long((unsigned long long)value); }
306
307mp_perfdata_value mp_create_pd_value_long_long(long long value) {
308 mp_perfdata_value res = {0};
309 res.type = PD_TYPE_INT;
310 res.pd_int = value;
311 return res;
312}
313
314mp_perfdata_value mp_create_pd_value_u_long_long(unsigned long long value) {
315 mp_perfdata_value res = {0};
316 res.type = PD_TYPE_UINT;
317 res.pd_uint = value;
318 return res;
319}
320
321char *fmt_range(range foo) { return foo.text; }
322
323typedef struct integer_parser_wrapper {
324 int error;
325 mp_perfdata_value value;
326} integer_parser_wrapper;
327
328typedef struct double_parser_wrapper {
329 int error;
330 mp_perfdata_value value;
331} double_parser_wrapper;
332
333typedef struct perfdata_value_parser_wrapper {
334 int error;
335 mp_perfdata_value value;
336} perfdata_value_parser_wrapper;
337
338double_parser_wrapper parse_double(const char *input);
339integer_parser_wrapper parse_integer(const char *input);
340perfdata_value_parser_wrapper parse_pd_value(const char *input);
341
342mp_range_parsed mp_parse_range_string(const char *input) {
343 if (input == NULL) {
344 mp_range_parsed result = {
345 .error = MP_RANGE_PARSING_FAILURE,
346 };
347 return result;
348 }
349
350 if (strlen(input) == 0) {
351 mp_range_parsed result = {
352 .error = MP_RANGE_PARSING_FAILURE,
353 };
354 return result;
355 }
356
357 mp_range_parsed result = {
358 .range = mp_range_init(),
359 .error = MP_PARSING_SUCCES,
360 };
361
362 if (input[0] == '@') {
363 // found an '@' at beginning, so invert the range logic
364 result.range.alert_on_inside_range = INSIDE;
365
366 // advance the pointer one symbol
367 input++;
368 }
369
370 char *working_copy = strdup(input);
371 input = working_copy;
372
373 char *separator = index(working_copy, ':');
374 if (separator != NULL) {
375 // Found a separator
376 // set the separator to 0, so we have two different strings
377 *separator = '\0';
378
379 if (input[0] == '~') {
380 // the beginning starts with '~', so it might be infinity
381 if (&input[1] != separator) {
382 // the next symbol after '~' is not the separator!
383 // so input is probably wrong
384 result.error = MP_RANGE_PARSING_FAILURE;
385 free(working_copy);
386 return result;
387 }
388
389 result.range.start_infinity = true;
390 } else {
391 // No '~' at the beginning, so this should be a number
392 result.range.start_infinity = false;
393 perfdata_value_parser_wrapper parsed_pd = parse_pd_value(input);
394
395 if (parsed_pd.error != MP_PARSING_SUCCES) {
396 result.error = parsed_pd.error;
397 free(working_copy);
398 return result;
399 }
400
401 result.range.start = parsed_pd.value;
402 result.range.start_infinity = false;
403 }
404 // got the first part now
405 // advance the pointer
406 input = separator + 1;
407 }
408
409 // End part or no separator
410 if (input[0] == '\0') {
411 // the end is infinite
412 result.range.end_infinity = true;
413 } else {
414 perfdata_value_parser_wrapper parsed_pd = parse_pd_value(input);
415
416 if (parsed_pd.error != MP_PARSING_SUCCES) {
417 result.error = parsed_pd.error;
418 return result;
419 }
420 result.range.end = parsed_pd.value;
421 result.range.end_infinity = false;
422 }
423 free(working_copy);
424 return result;
425}
426
427double_parser_wrapper parse_double(const char *input) {
428 double_parser_wrapper result = {
429 .error = MP_PARSING_SUCCES,
430 };
431
432 if (input == NULL) {
433 result.error = MP_PARSING_FAILURE;
434 return result;
435 }
436
437 char *endptr = NULL;
438 errno = 0;
439 double tmp = strtod(input, &endptr);
440
441 if (input == endptr) {
442 // man 3 strtod says, no conversion performed
443 result.error = MP_PARSING_FAILURE;
444 return result;
445 }
446
447 if (errno) {
448 // some other error
449 // TODO maybe differentiate a little bit
450 result.error = MP_PARSING_FAILURE;
451 return result;
452 }
453
454 result.value = mp_create_pd_value(tmp);
455 return result;
456}
457
458integer_parser_wrapper parse_integer(const char *input) {
459 integer_parser_wrapper result = {
460 .error = MP_PARSING_SUCCES,
461 };
462
463 if (input == NULL) {
464 result.error = MP_PARSING_FAILURE;
465 return result;
466 }
467
468 char *endptr = NULL;
469 errno = 0;
470 long long tmp = strtoll(input, &endptr, 0);
471
472 // validating *sigh*
473 if (*endptr != '\0') {
474 // something went wrong in strtoll
475 if (tmp == LLONG_MIN) {
476 // underflow
477 result.error = MP_RANGE_PARSING_UNDERFLOW;
478 return result;
479 }
480
481 if (tmp == LLONG_MAX) {
482 // overflow
483 result.error = MP_RANGE_PARSING_OVERFLOW;
484 return result;
485 }
486
487 // still wrong, but not sure why, probably invalid characters
488 if (errno == EINVAL) {
489 result.error = MP_RANGE_PARSING_INVALID_CHAR;
490 return result;
491 }
492
493 // some other error, do catch all here
494 result.error = MP_RANGE_PARSING_FAILURE;
495 return result;
496 }
497
498 // no error, should be fine
499 result.value = mp_create_pd_value(tmp);
500 return result;
501}
502
503perfdata_value_parser_wrapper parse_pd_value(const char *input) {
504 // try integer first
505 integer_parser_wrapper tmp_int = parse_integer(input);
506
507 if (tmp_int.error == MP_PARSING_SUCCES) {
508 perfdata_value_parser_wrapper result = {
509 .error = tmp_int.error,
510 .value = tmp_int.value,
511 };
512 return result;
513 }
514
515 double_parser_wrapper tmp_double = parse_double(input);
516 perfdata_value_parser_wrapper result = {};
517 if (tmp_double.error == MP_PARSING_SUCCES) {
518 result.error = tmp_double.error;
519 result.value = tmp_double.value;
520 } else {
521 result.error = tmp_double.error;
522 }
523 return result;
524}
525
526mp_perfdata mp_set_pd_max_value(mp_perfdata perfdata, mp_perfdata_value value) {
527 perfdata.max = value;
528 perfdata.max_present = true;
529 return perfdata;
530}
531
532mp_perfdata mp_set_pd_min_value(mp_perfdata perfdata, mp_perfdata_value value) {
533 perfdata.min = value;
534 perfdata.min_present = true;
535 return perfdata;
536}
537
538double mp_get_pd_value(mp_perfdata_value value) {
539 assert(value.type != PD_TYPE_NONE);
540 switch (value.type) {
541 case PD_TYPE_DOUBLE:
542 return value.pd_double;
543 case PD_TYPE_INT:
544 return (double)value.pd_int;
545 case PD_TYPE_UINT:
546 return (double)value.pd_uint;
547 default:
548 return 0; // just to make the compiler happy
549 }
550}
551
552mp_perfdata_value mp_pd_value_multiply(mp_perfdata_value left, mp_perfdata_value right) {
553 if (left.type == right.type) {
554 switch (left.type) {
555 case PD_TYPE_DOUBLE:
556 left.pd_double *= right.pd_double;
557 return left;
558 case PD_TYPE_INT:
559 left.pd_int *= right.pd_int;
560 return left;
561 case PD_TYPE_UINT:
562 left.pd_uint *= right.pd_uint;
563 return left;
564 default:
565 // what to here?
566 return left;
567 }
568 }
569
570 // Different types, oh boy, just do the lazy thing for now and switch to double
571 switch (left.type) {
572 case PD_TYPE_INT:
573 left.pd_double = (double)left.pd_int;
574 left.type = PD_TYPE_DOUBLE;
575 break;
576 case PD_TYPE_UINT:
577 left.pd_double = (double)left.pd_uint;
578 left.type = PD_TYPE_DOUBLE;
579 break;
580 }
581
582 switch (right.type) {
583 case PD_TYPE_INT:
584 right.pd_double = (double)right.pd_int;
585 right.type = PD_TYPE_DOUBLE;
586 break;
587 case PD_TYPE_UINT:
588 right.pd_double = (double)right.pd_uint;
589 right.type = PD_TYPE_DOUBLE;
590 break;
591 }
592
593 left.pd_double *= right.pd_double;
594 return left;
595}
596
597mp_range mp_range_multiply(mp_range range, mp_perfdata_value factor) {
598 if (!range.end_infinity) {
599 range.end = mp_pd_value_multiply(range.end, factor);
600 }
601 if (!range.start_infinity) {
602 range.start = mp_pd_value_multiply(range.start, factor);
603 }
604 return range;
605}