summaryrefslogtreecommitdiffstats
path: root/lib/perfdata.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/perfdata.c')
-rw-r--r--lib/perfdata.c649
1 files changed, 649 insertions, 0 deletions
diff --git a/lib/perfdata.c b/lib/perfdata.c
new file mode 100644
index 00000000..2930a8bc
--- /dev/null
+++ b/lib/perfdata.c
@@ -0,0 +1,649 @@
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
37 if (strchr(pd.label, '\'') == NULL) {
38 asprintf(&result, "'%s'=", pd.label);
39 } else {
40 // we have a illegal single quote in the string
41 // replace it silently instead of complaining
42 for (char *ptr = pd.label; *ptr == '\0'; ptr++) {
43 if (*ptr == '\'') {
44 *ptr = '_';
45 }
46 }
47 }
48
49 asprintf(&result, "%s%s", result, pd_value_to_string(pd.value));
50
51 if (pd.uom != NULL) {
52 asprintf(&result, "%s%s", result, pd.uom);
53 }
54
55 if (pd.warn_present) {
56 asprintf(&result, "%s;%s", result, mp_range_to_string(pd.warn));
57 } else {
58 asprintf(&result, "%s;", result);
59 }
60
61 if (pd.crit_present) {
62 asprintf(&result, "%s;%s", result, mp_range_to_string(pd.crit));
63 } else {
64 asprintf(&result, "%s;", result);
65 }
66 if (pd.min_present) {
67 asprintf(&result, "%s;%s", result, pd_value_to_string(pd.min));
68 } else {
69 asprintf(&result, "%s;", result);
70 }
71
72 if (pd.max_present) {
73 asprintf(&result, "%s;%s", result, pd_value_to_string(pd.max));
74 }
75
76 /*printf("pd_to_string: %s\n", result); */
77
78 return result;
79}
80
81char *pd_list_to_string(const pd_list pd) {
82 char *result = pd_to_string(pd.data);
83
84 for (pd_list *elem = pd.next; elem != NULL; elem = elem->next) {
85 asprintf(&result, "%s %s", result, pd_to_string(elem->data));
86 }
87
88 return result;
89}
90
91mp_perfdata perfdata_init() {
92 mp_perfdata pd = {};
93 return pd;
94}
95
96pd_list *pd_list_init() {
97 pd_list *tmp = (pd_list *)calloc(1, sizeof(pd_list));
98 if (tmp == NULL) {
99 die(STATE_UNKNOWN, "calloc failed\n");
100 }
101 tmp->next = NULL;
102 return tmp;
103}
104
105mp_range mp_range_init() {
106 mp_range result = {
107 .alert_on_inside_range = OUTSIDE,
108 .start = {},
109 .start_infinity = true,
110 .end = {},
111 .end_infinity = true,
112 };
113
114 return result;
115}
116
117mp_range mp_range_set_start(mp_range input, mp_perfdata_value perf_val) {
118 input.start = perf_val;
119 input.start_infinity = false;
120 return input;
121}
122
123mp_range mp_range_set_end(mp_range input, mp_perfdata_value perf_val) {
124 input.end = perf_val;
125 input.end_infinity = false;
126 return input;
127}
128
129void pd_list_append(pd_list pdl[1], const mp_perfdata pd) {
130 assert(pdl != NULL);
131
132 if (pdl->data.value.type == PD_TYPE_NONE) {
133 // first entry is still empty
134 pdl->data = pd;
135 } else {
136 // find last element in the list
137 pd_list *curr = pdl;
138 pd_list *next = pdl->next;
139
140 while (next != NULL) {
141 curr = next;
142 next = next->next;
143 }
144
145 if (curr->data.value.type == PD_TYPE_NONE) {
146 // still empty
147 curr->data = pd;
148 } else {
149 // new a new one
150 curr->next = pd_list_init();
151 curr->next->data = pd;
152 }
153 }
154}
155
156void pd_list_free(pd_list pdl[1]) {
157 while (pdl != NULL) {
158 pd_list *old = pdl;
159 pdl = pdl->next;
160 free(old);
161 }
162}
163
164/*
165 * returns -1 if a < b, 0 if a == b, 1 if a > b
166 */
167int cmp_perfdata_value(const mp_perfdata_value a, const mp_perfdata_value b) {
168 // Test if types are different
169 if (a.type == b.type) {
170
171 switch (a.type) {
172 case PD_TYPE_UINT:
173 if (a.pd_uint < b.pd_uint) {
174 return -1;
175 } else if (a.pd_uint == b.pd_uint) {
176 return 0;
177 } else {
178 return 1;
179 }
180 break;
181 case PD_TYPE_INT:
182 if (a.pd_int < b.pd_int) {
183 return -1;
184 } else if (a.pd_int == b.pd_int) {
185 return 0;
186 } else {
187 return 1;
188 }
189 break;
190 case PD_TYPE_DOUBLE:
191 if (a.pd_int < b.pd_int) {
192 return -1;
193 } else if (a.pd_int == b.pd_int) {
194 return 0;
195 } else {
196 return 1;
197 }
198 break;
199 default:
200 die(STATE_UNKNOWN, "Error in %s line: %d!", __FILE__, __LINE__);
201 }
202 }
203
204 // Get dirty here
205 long double floating_a = 0;
206
207 switch (a.type) {
208 case PD_TYPE_UINT:
209 floating_a = a.pd_uint;
210 break;
211 case PD_TYPE_INT:
212 floating_a = a.pd_int;
213 break;
214 case PD_TYPE_DOUBLE:
215 floating_a = a.pd_double;
216 break;
217 default:
218 die(STATE_UNKNOWN, "Error in %s line: %d!", __FILE__, __LINE__);
219 }
220
221 long double floating_b = 0;
222 switch (b.type) {
223 case PD_TYPE_UINT:
224 floating_b = b.pd_uint;
225 break;
226 case PD_TYPE_INT:
227 floating_b = b.pd_int;
228 break;
229 case PD_TYPE_DOUBLE:
230 floating_b = b.pd_double;
231 break;
232 default:
233 die(STATE_UNKNOWN, "Error in %s line: %d!", __FILE__, __LINE__);
234 }
235
236 if (floating_a < floating_b) {
237 return -1;
238 }
239 if (floating_a == floating_b) {
240 return 0;
241 }
242 return 1;
243}
244
245char *mp_range_to_string(const mp_range input) {
246 char *result = "";
247 if (input.alert_on_inside_range == INSIDE) {
248 asprintf(&result, "@");
249 }
250
251 if (input.start_infinity) {
252 asprintf(&result, "%s~:", result);
253 } else {
254 asprintf(&result, "%s%s:", result, pd_value_to_string(input.start));
255 }
256
257 if (!input.end_infinity) {
258 asprintf(&result, "%s%s", result, pd_value_to_string(input.end));
259 }
260 return result;
261}
262
263mp_perfdata mp_set_pd_value_float(mp_perfdata pd, float value) {
264 return mp_set_pd_value_double(pd, value);
265}
266
267mp_perfdata mp_set_pd_value_double(mp_perfdata pd, double value) {
268 pd.value.pd_double = value;
269 pd.value.type = PD_TYPE_DOUBLE;
270 return pd;
271}
272
273mp_perfdata mp_set_pd_value_char(mp_perfdata pd, char value) {
274 return mp_set_pd_value_long_long(pd, (long long)value);
275}
276
277mp_perfdata mp_set_pd_value_u_char(mp_perfdata pd, unsigned char value) {
278 return mp_set_pd_value_u_long_long(pd, (unsigned long long)value);
279}
280
281mp_perfdata mp_set_pd_value_int(mp_perfdata pd, int value) {
282 return mp_set_pd_value_long_long(pd, (long long)value);
283}
284
285mp_perfdata mp_set_pd_value_u_int(mp_perfdata pd, unsigned int value) {
286 return mp_set_pd_value_u_long_long(pd, (unsigned long long)value);
287}
288
289mp_perfdata mp_set_pd_value_long(mp_perfdata pd, long value) {
290 return mp_set_pd_value_long_long(pd, (long long)value);
291}
292
293mp_perfdata mp_set_pd_value_u_long(mp_perfdata pd, unsigned long value) {
294 return mp_set_pd_value_u_long_long(pd, (unsigned long long)value);
295}
296
297mp_perfdata mp_set_pd_value_long_long(mp_perfdata pd, long long value) {
298 pd.value.pd_int = value;
299 pd.value.type = PD_TYPE_INT;
300 return pd;
301}
302
303mp_perfdata mp_set_pd_value_u_long_long(mp_perfdata pd, unsigned long long value) {
304 pd.value.pd_uint = value;
305 pd.value.type = PD_TYPE_UINT;
306 return pd;
307}
308
309mp_perfdata_value mp_create_pd_value_double(double value) {
310 mp_perfdata_value res = {0};
311 res.type = PD_TYPE_DOUBLE;
312 res.pd_double = value;
313 return res;
314}
315
316mp_perfdata_value mp_create_pd_value_float(float value) {
317 return mp_create_pd_value_double((double)value);
318}
319
320mp_perfdata_value mp_create_pd_value_char(char value) {
321 return mp_create_pd_value_long_long((long long)value);
322}
323
324mp_perfdata_value mp_create_pd_value_u_char(unsigned char value) {
325 return mp_create_pd_value_u_long_long((unsigned long long)value);
326}
327
328mp_perfdata_value mp_create_pd_value_int(int value) {
329 return mp_create_pd_value_long_long((long long)value);
330}
331
332mp_perfdata_value mp_create_pd_value_u_int(unsigned int value) {
333 return mp_create_pd_value_u_long_long((unsigned long long)value);
334}
335
336mp_perfdata_value mp_create_pd_value_long(long value) {
337 return mp_create_pd_value_long_long((long long)value);
338}
339
340mp_perfdata_value mp_create_pd_value_u_long(unsigned long value) {
341 return mp_create_pd_value_u_long_long((unsigned long long)value);
342}
343
344mp_perfdata_value mp_create_pd_value_long_long(long long value) {
345 mp_perfdata_value res = {0};
346 res.type = PD_TYPE_INT;
347 res.pd_int = value;
348 return res;
349}
350
351mp_perfdata_value mp_create_pd_value_u_long_long(unsigned long long value) {
352 mp_perfdata_value res = {0};
353 res.type = PD_TYPE_UINT;
354 res.pd_uint = value;
355 return res;
356}
357
358char *fmt_range(range foo) { return foo.text; }
359
360typedef struct integer_parser_wrapper {
361 int error;
362 mp_perfdata_value value;
363} integer_parser_wrapper;
364
365typedef struct double_parser_wrapper {
366 int error;
367 mp_perfdata_value value;
368} double_parser_wrapper;
369
370typedef struct perfdata_value_parser_wrapper {
371 int error;
372 mp_perfdata_value value;
373} perfdata_value_parser_wrapper;
374
375double_parser_wrapper parse_double(const char *input);
376integer_parser_wrapper parse_integer(const char *input);
377perfdata_value_parser_wrapper parse_pd_value(const char *input);
378
379mp_range_parsed mp_parse_range_string(const char *input) {
380 if (input == NULL) {
381 mp_range_parsed result = {
382 .error = MP_RANGE_PARSING_FAILURE,
383 };
384 return result;
385 }
386
387 if (strlen(input) == 0) {
388 mp_range_parsed result = {
389 .error = MP_RANGE_PARSING_FAILURE,
390 };
391 return result;
392 }
393
394 mp_range_parsed result = {
395 .range = mp_range_init(),
396 .error = MP_PARSING_SUCCES,
397 };
398
399 if (input[0] == '@') {
400 // found an '@' at beginning, so invert the range logic
401 result.range.alert_on_inside_range = INSIDE;
402
403 // advance the pointer one symbol
404 input++;
405 }
406
407 char *working_copy = strdup(input);
408 if (working_copy == NULL) {
409 // strdup error, probably
410 mp_range_parsed result = {
411 .error = MP_RANGE_PARSING_FAILURE,
412 };
413 return result;
414 }
415 input = working_copy;
416
417 char *separator = index(working_copy, ':');
418 if (separator != NULL) {
419 // Found a separator
420 // set the separator to 0, so we have two different strings
421 *separator = '\0';
422
423 if (input[0] == '~') {
424 // the beginning starts with '~', so it might be infinity
425 if (&input[1] != separator) {
426 // the next symbol after '~' is not the separator!
427 // so input is probably wrong
428 result.error = MP_RANGE_PARSING_FAILURE;
429 free(working_copy);
430 return result;
431 }
432
433 result.range.start_infinity = true;
434 } else {
435 // No '~' at the beginning, so this should be a number
436 result.range.start_infinity = false;
437 perfdata_value_parser_wrapper parsed_pd = parse_pd_value(input);
438
439 if (parsed_pd.error != MP_PARSING_SUCCES) {
440 result.error = parsed_pd.error;
441 free(working_copy);
442 return result;
443 }
444
445 result.range.start = parsed_pd.value;
446 result.range.start_infinity = false;
447 }
448 // got the first part now
449 // advance the pointer
450 input = separator + 1;
451 }
452
453 // End part or no separator
454 if (input[0] == '\0') {
455 // the end is infinite
456 result.range.end_infinity = true;
457 } else {
458 perfdata_value_parser_wrapper parsed_pd = parse_pd_value(input);
459
460 if (parsed_pd.error != MP_PARSING_SUCCES) {
461 result.error = parsed_pd.error;
462 return result;
463 }
464 result.range.end = parsed_pd.value;
465 result.range.end_infinity = false;
466 }
467 free(working_copy);
468 return result;
469}
470
471double_parser_wrapper parse_double(const char *input) {
472 double_parser_wrapper result = {
473 .error = MP_PARSING_SUCCES,
474 };
475
476 if (input == NULL) {
477 result.error = MP_PARSING_FAILURE;
478 return result;
479 }
480
481 char *endptr = NULL;
482 errno = 0;
483 double tmp = strtod(input, &endptr);
484
485 if (input == endptr) {
486 // man 3 strtod says, no conversion performed
487 result.error = MP_PARSING_FAILURE;
488 return result;
489 }
490
491 if (errno) {
492 // some other error
493 // TODO maybe differentiate a little bit
494 result.error = MP_PARSING_FAILURE;
495 return result;
496 }
497
498 result.value = mp_create_pd_value(tmp);
499 return result;
500}
501
502integer_parser_wrapper parse_integer(const char *input) {
503 integer_parser_wrapper result = {
504 .error = MP_PARSING_SUCCES,
505 };
506
507 if (input == NULL) {
508 result.error = MP_PARSING_FAILURE;
509 return result;
510 }
511
512 char *endptr = NULL;
513 errno = 0;
514 long long tmp = strtoll(input, &endptr, 0);
515
516 // validating *sigh*
517 if (*endptr != '\0') {
518 // something went wrong in strtoll
519 if (tmp == LLONG_MIN) {
520 // underflow
521 result.error = MP_RANGE_PARSING_UNDERFLOW;
522 return result;
523 }
524
525 if (tmp == LLONG_MAX) {
526 // overflow
527 result.error = MP_RANGE_PARSING_OVERFLOW;
528 return result;
529 }
530
531 // still wrong, but not sure why, probably invalid characters
532 if (errno == EINVAL) {
533 result.error = MP_RANGE_PARSING_INVALID_CHAR;
534 return result;
535 }
536
537 // some other error, do catch all here
538 result.error = MP_RANGE_PARSING_FAILURE;
539 return result;
540 }
541
542 // no error, should be fine
543 result.value = mp_create_pd_value(tmp);
544 return result;
545}
546
547perfdata_value_parser_wrapper parse_pd_value(const char *input) {
548 // try integer first
549 integer_parser_wrapper tmp_int = parse_integer(input);
550
551 if (tmp_int.error == MP_PARSING_SUCCES) {
552 perfdata_value_parser_wrapper result = {
553 .error = tmp_int.error,
554 .value = tmp_int.value,
555 };
556 return result;
557 }
558
559 double_parser_wrapper tmp_double = parse_double(input);
560 perfdata_value_parser_wrapper result = {};
561 if (tmp_double.error == MP_PARSING_SUCCES) {
562 result.error = tmp_double.error;
563 result.value = tmp_double.value;
564 } else {
565 result.error = tmp_double.error;
566 }
567 return result;
568}
569
570mp_perfdata mp_set_pd_max_value(mp_perfdata perfdata, mp_perfdata_value value) {
571 perfdata.max = value;
572 perfdata.max_present = true;
573 return perfdata;
574}
575
576mp_perfdata mp_set_pd_min_value(mp_perfdata perfdata, mp_perfdata_value value) {
577 perfdata.min = value;
578 perfdata.min_present = true;
579 return perfdata;
580}
581
582double mp_get_pd_value(mp_perfdata_value value) {
583 assert(value.type != PD_TYPE_NONE);
584 switch (value.type) {
585 case PD_TYPE_DOUBLE:
586 return value.pd_double;
587 case PD_TYPE_INT:
588 return (double)value.pd_int;
589 case PD_TYPE_UINT:
590 return (double)value.pd_uint;
591 default:
592 return 0; // just to make the compiler happy
593 }
594}
595
596mp_perfdata_value mp_pd_value_multiply(mp_perfdata_value left, mp_perfdata_value right) {
597 if (left.type == right.type) {
598 switch (left.type) {
599 case PD_TYPE_DOUBLE:
600 left.pd_double *= right.pd_double;
601 return left;
602 case PD_TYPE_INT:
603 left.pd_int *= right.pd_int;
604 return left;
605 case PD_TYPE_UINT:
606 left.pd_uint *= right.pd_uint;
607 return left;
608 default:
609 // what to here?
610 return left;
611 }
612 }
613
614 // Different types, oh boy, just do the lazy thing for now and switch to double
615 switch (left.type) {
616 case PD_TYPE_INT:
617 left.pd_double = (double)left.pd_int;
618 left.type = PD_TYPE_DOUBLE;
619 break;
620 case PD_TYPE_UINT:
621 left.pd_double = (double)left.pd_uint;
622 left.type = PD_TYPE_DOUBLE;
623 break;
624 }
625
626 switch (right.type) {
627 case PD_TYPE_INT:
628 right.pd_double = (double)right.pd_int;
629 right.type = PD_TYPE_DOUBLE;
630 break;
631 case PD_TYPE_UINT:
632 right.pd_double = (double)right.pd_uint;
633 right.type = PD_TYPE_DOUBLE;
634 break;
635 }
636
637 left.pd_double *= right.pd_double;
638 return left;
639}
640
641mp_range mp_range_multiply(mp_range range, mp_perfdata_value factor) {
642 if (!range.end_infinity) {
643 range.end = mp_pd_value_multiply(range.end, factor);
644 }
645 if (!range.start_infinity) {
646 range.start = mp_pd_value_multiply(range.start, factor);
647 }
648 return range;
649}