1 /*
2 ** Zabbix
3 ** Copyright (C) 2001-2021 Zabbix SIA
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation; either version 2 of the License, or
8 ** (at your option) any later version.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ** GNU General Public License for more details.
14 **
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 **/
19
20 #include "common.h"
21 #include "db.h"
22 #include "log.h"
23 #include "zbxserver.h"
24 #include "valuecache.h"
25 #include "evalfunc.h"
26 #include "zbxregexp.h"
27 #include "zbxtrends.h"
28 #include "../zbxalgo/vectorimpl.h"
29
30 typedef enum
31 {
32 ZBX_PARAM_OPTIONAL,
33 ZBX_PARAM_MANDATORY
34 }
35 zbx_param_type_t;
36
37 typedef enum
38 {
39 ZBX_VALUE_SECONDS,
40 ZBX_VALUE_NVALUES
41 }
42 zbx_value_type_t;
43
44 #define ZBX_VALUEMAP_STRING_LEN 64
45
46 #define ZBX_VALUEMAP_TYPE_MATCH 0
47 #define ZBX_VALUEMAP_TYPE_GREATER_OR_EQUAL 1
48 #define ZBX_VALUEMAP_TYPE_LESS_OR_EQUAL 2
49 #define ZBX_VALUEMAP_TYPE_RANGE 3
50 #define ZBX_VALUEMAP_TYPE_REGEX 4
51 #define ZBX_VALUEMAP_TYPE_DEFAULT 5
52
53 typedef struct
54 {
55 char value[ZBX_VALUEMAP_STRING_LEN];
56 char newvalue[ZBX_VALUEMAP_STRING_LEN];
57 int type;
58 }
59 zbx_valuemaps_t;
60
ZBX_PTR_VECTOR_DECL(valuemaps_ptr,zbx_valuemaps_t *)61 ZBX_PTR_VECTOR_DECL(valuemaps_ptr, zbx_valuemaps_t *)
62 ZBX_PTR_VECTOR_IMPL(valuemaps_ptr, zbx_valuemaps_t *)
63
64 static const char *zbx_type_string(zbx_value_type_t type)
65 {
66 switch (type)
67 {
68 case ZBX_VALUE_SECONDS:
69 return "sec";
70 case ZBX_VALUE_NVALUES:
71 return "num";
72 default:
73 THIS_SHOULD_NEVER_HAPPEN;
74 return "unknown";
75 }
76 }
77
78 /******************************************************************************
79 * *
80 * Function: get_function_parameter_int *
81 * *
82 * Purpose: get the value of sec|#num trigger function parameter *
83 * *
84 * Parameters: parameters - [IN] trigger function parameters *
85 * Nparam - [IN] specifies which parameter to extract *
86 * parameter_type - [IN] specifies whether parameter is mandatory *
87 * or optional *
88 * value - [OUT] parameter value (preserved as is if the *
89 * parameter is optional and empty) *
90 * type - [OUT] parameter value type (number of seconds *
91 * or number of values) *
92 * *
93 * Return value: SUCCEED - parameter is valid *
94 * FAIL - otherwise *
95 * *
96 ******************************************************************************/
get_function_parameter_int(const char * parameters,int Nparam,zbx_param_type_t parameter_type,int * value,zbx_value_type_t * type)97 static int get_function_parameter_int(const char *parameters, int Nparam, zbx_param_type_t parameter_type,
98 int *value, zbx_value_type_t *type)
99 {
100 char *parameter;
101 int ret = FAIL;
102
103 zabbix_log(LOG_LEVEL_DEBUG, "In %s() parameters:'%s' Nparam:%d", __func__, parameters, Nparam);
104
105 if (NULL == (parameter = zbx_function_get_param_dyn(parameters, Nparam)))
106 goto out;
107
108 if ('\0' == *parameter)
109 {
110 switch (parameter_type)
111 {
112 case ZBX_PARAM_OPTIONAL:
113 ret = SUCCEED;
114 break;
115 case ZBX_PARAM_MANDATORY:
116 break;
117 default:
118 THIS_SHOULD_NEVER_HAPPEN;
119 }
120 }
121 else if ('#' == *parameter)
122 {
123 *type = ZBX_VALUE_NVALUES;
124 if (SUCCEED == is_uint31(parameter + 1, value) && 0 < *value)
125 ret = SUCCEED;
126 }
127 else if ('-' == *parameter)
128 {
129 if (SUCCEED == is_time_suffix(parameter + 1, value, ZBX_LENGTH_UNLIMITED))
130 {
131 *value = -(*value);
132 *type = ZBX_VALUE_SECONDS;
133 ret = SUCCEED;
134 }
135 }
136 else if (SUCCEED == is_time_suffix(parameter, value, ZBX_LENGTH_UNLIMITED))
137 {
138 *type = ZBX_VALUE_SECONDS;
139 ret = SUCCEED;
140 }
141
142 if (SUCCEED == ret)
143 zabbix_log(LOG_LEVEL_DEBUG, "%s() type:%s value:%d", __func__, zbx_type_string(*type), *value);
144
145 zbx_free(parameter);
146 out:
147 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
148
149 return ret;
150 }
151
get_function_parameter_uint64(const char * parameters,int Nparam,zbx_uint64_t * value)152 static int get_function_parameter_uint64(const char *parameters, int Nparam, zbx_uint64_t *value)
153 {
154 char *parameter;
155 int ret = FAIL;
156
157 zabbix_log(LOG_LEVEL_DEBUG, "In %s() parameters:'%s' Nparam:%d", __func__, parameters, Nparam);
158
159 if (NULL == (parameter = zbx_function_get_param_dyn(parameters, Nparam)))
160 goto out;
161
162 if (SUCCEED == (ret = is_uint64(parameter, value)))
163 zabbix_log(LOG_LEVEL_DEBUG, "%s() value:" ZBX_FS_UI64, __func__, *value);
164
165 zbx_free(parameter);
166 out:
167 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
168
169 return ret;
170 }
171
get_function_parameter_float(const char * parameters,int Nparam,unsigned char flags,double * value)172 static int get_function_parameter_float(const char *parameters, int Nparam, unsigned char flags, double *value)
173 {
174 char *parameter;
175 int ret = FAIL;
176
177 zabbix_log(LOG_LEVEL_DEBUG, "In %s() parameters:'%s' Nparam:%d", __func__, parameters, Nparam);
178
179 if (NULL == (parameter = zbx_function_get_param_dyn(parameters, Nparam)))
180 goto out;
181
182 if (SUCCEED == (ret = is_double_suffix(parameter, flags)))
183 {
184 *value = str2double(parameter);
185 zabbix_log(LOG_LEVEL_DEBUG, "%s() value:" ZBX_FS_DBL, __func__, *value);
186 }
187
188 zbx_free(parameter);
189 out:
190 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
191
192 return ret;
193 }
194
get_function_parameter_str(const char * parameters,int Nparam,char ** value)195 static int get_function_parameter_str(const char *parameters, int Nparam, char **value)
196 {
197 int ret = FAIL;
198
199 zabbix_log(LOG_LEVEL_DEBUG, "In %s() parameters:'%s' Nparam:%d", __func__, parameters, Nparam);
200
201 if (NULL == (*value = zbx_function_get_param_dyn(parameters, Nparam)))
202 goto out;
203
204 zabbix_log(LOG_LEVEL_DEBUG, "%s() value:'%s'", __func__, *value);
205 ret = SUCCEED;
206 out:
207 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
208
209 return ret;
210 }
211
212 /******************************************************************************
213 * *
214 * Function: evaluate_LOGEVENTID *
215 * *
216 * Purpose: evaluate function 'logeventid' for the item *
217 * *
218 * Parameters: item - item (performance metric) *
219 * parameter - regex string for event id matching *
220 * *
221 * Return value: SUCCEED - evaluated successfully, result is stored in 'value'*
222 * FAIL - failed to evaluate function *
223 * *
224 ******************************************************************************/
evaluate_LOGEVENTID(char ** value,DC_ITEM * item,const char * parameters,const zbx_timespec_t * ts,char ** error)225 static int evaluate_LOGEVENTID(char **value, DC_ITEM *item, const char *parameters,
226 const zbx_timespec_t *ts, char **error)
227 {
228 char *arg1 = NULL;
229 int ret = FAIL;
230 zbx_vector_ptr_t regexps;
231 zbx_history_record_t vc_value;
232
233 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
234
235 zbx_vector_ptr_create(®exps);
236
237 if (ITEM_VALUE_TYPE_LOG != item->value_type)
238 {
239 *error = zbx_strdup(*error, "invalid value type");
240 goto out;
241 }
242
243 if (1 < num_param(parameters))
244 {
245 *error = zbx_strdup(*error, "invalid number of parameters");
246 goto out;
247 }
248
249 if (SUCCEED != get_function_parameter_str(parameters, 1, &arg1))
250 {
251 *error = zbx_strdup(*error, "invalid first parameter");
252 goto out;
253 }
254
255 if ('@' == *arg1)
256 {
257 DCget_expressions_by_name(®exps, arg1 + 1);
258
259 if (0 == regexps.values_num)
260 {
261 *error = zbx_dsprintf(*error, "global regular expression \"%s\" does not exist", arg1 + 1);
262 goto out;
263 }
264 }
265
266 if (SUCCEED == zbx_vc_get_value(item->itemid, item->value_type, ts, &vc_value))
267 {
268 char logeventid[16];
269 int regexp_ret;
270
271 zbx_snprintf(logeventid, sizeof(logeventid), "%d", vc_value.value.log->logeventid);
272
273 if (FAIL == (regexp_ret = regexp_match_ex(®exps, logeventid, arg1, ZBX_CASE_SENSITIVE)))
274 {
275 *error = zbx_dsprintf(*error, "invalid regular expression \"%s\"", arg1);
276 }
277 else
278 {
279 if (ZBX_REGEXP_MATCH == regexp_ret)
280 *value = zbx_strdup(*value, "1");
281 else if (ZBX_REGEXP_NO_MATCH == regexp_ret)
282 *value = zbx_strdup(*value, "0");
283
284 ret = SUCCEED;
285 }
286
287 zbx_history_record_clear(&vc_value, item->value_type);
288 }
289 else
290 {
291 zabbix_log(LOG_LEVEL_DEBUG, "result for LOGEVENTID is empty");
292 *error = zbx_strdup(*error, "cannot get values from value cache");
293 }
294 out:
295 zbx_free(arg1);
296
297 zbx_regexp_clean_expressions(®exps);
298 zbx_vector_ptr_destroy(®exps);
299
300 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
301
302 return ret;
303 }
304
305 /******************************************************************************
306 * *
307 * Function: evaluate_LOGSOURCE *
308 * *
309 * Purpose: evaluate function 'logsource' for the item *
310 * *
311 * Parameters: item - item (performance metric) *
312 * parameter - ignored *
313 * *
314 * Return value: SUCCEED - evaluated successfully, result is stored in 'value'*
315 * FAIL - failed to evaluate function *
316 * *
317 ******************************************************************************/
evaluate_LOGSOURCE(char ** value,DC_ITEM * item,const char * parameters,const zbx_timespec_t * ts,char ** error)318 static int evaluate_LOGSOURCE(char **value, DC_ITEM *item, const char *parameters, const zbx_timespec_t *ts,
319 char **error)
320 {
321 char *arg1 = NULL;
322 int ret = FAIL;
323 zbx_vector_ptr_t regexps;
324 zbx_history_record_t vc_value;
325
326 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
327
328 zbx_vector_ptr_create(®exps);
329
330 if (ITEM_VALUE_TYPE_LOG != item->value_type)
331 {
332 *error = zbx_strdup(*error, "invalid value type");
333 goto out;
334 }
335
336 if (1 < num_param(parameters))
337 {
338 *error = zbx_strdup(*error, "invalid number of parameters");
339 goto out;
340 }
341
342 if (SUCCEED != get_function_parameter_str(parameters, 1, &arg1))
343 {
344 *error = zbx_strdup(*error, "invalid first parameter");
345 goto out;
346 }
347
348 if ('@' == *arg1)
349 {
350 DCget_expressions_by_name(®exps, arg1 + 1);
351
352 if (0 == regexps.values_num)
353 {
354 *error = zbx_dsprintf(*error, "global regular expression \"%s\" does not exist", arg1 + 1);
355 goto out;
356 }
357 }
358
359 if (SUCCEED == zbx_vc_get_value(item->itemid, item->value_type, ts, &vc_value))
360 {
361 switch (regexp_match_ex(®exps, ZBX_NULL2EMPTY_STR(vc_value.value.log->source), arg1, ZBX_CASE_SENSITIVE))
362 {
363 case ZBX_REGEXP_MATCH:
364 *value = zbx_strdup(*value, "1");
365 ret = SUCCEED;
366 break;
367 case ZBX_REGEXP_NO_MATCH:
368 *value = zbx_strdup(*value, "0");
369 ret = SUCCEED;
370 break;
371 case FAIL:
372 *error = zbx_dsprintf(*error, "invalid regular expression");
373 }
374
375 zbx_history_record_clear(&vc_value, item->value_type);
376 }
377 else
378 {
379 zabbix_log(LOG_LEVEL_DEBUG, "result for LOGSOURCE is empty");
380 *error = zbx_strdup(*error, "cannot get values from value cache");
381 }
382 out:
383 zbx_free(arg1);
384
385 zbx_regexp_clean_expressions(®exps);
386 zbx_vector_ptr_destroy(®exps);
387
388 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
389
390 return ret;
391 }
392
393 /******************************************************************************
394 * *
395 * Function: evaluate_LOGSEVERITY *
396 * *
397 * Purpose: evaluate function 'logseverity' for the item *
398 * *
399 * Parameters: item - item (performance metric) *
400 * *
401 * Return value: SUCCEED - evaluated successfully, result is stored in 'value'*
402 * FAIL - failed to evaluate function *
403 * *
404 ******************************************************************************/
evaluate_LOGSEVERITY(char ** value,DC_ITEM * item,const zbx_timespec_t * ts,char ** error)405 static int evaluate_LOGSEVERITY(char **value, DC_ITEM *item, const zbx_timespec_t *ts, char **error)
406 {
407 int ret = FAIL;
408 zbx_history_record_t vc_value;
409
410 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
411
412 if (ITEM_VALUE_TYPE_LOG != item->value_type)
413 {
414 *error = zbx_strdup(*error, "invalid value type");
415 goto out;
416 }
417
418 if (SUCCEED == zbx_vc_get_value(item->itemid, item->value_type, ts, &vc_value))
419 {
420 size_t value_alloc = 0, value_offset = 0;
421
422 zbx_snprintf_alloc(value, &value_alloc, &value_offset, "%d", vc_value.value.log->severity);
423 zbx_history_record_clear(&vc_value, item->value_type);
424
425 ret = SUCCEED;
426 }
427 else
428 {
429 zabbix_log(LOG_LEVEL_DEBUG, "result for LOGSEVERITY is empty");
430 *error = zbx_strdup(*error, "cannot get value from value cache");
431 }
432 out:
433 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
434
435 return ret;
436 }
437
438 #define OP_UNKNOWN -1
439 #define OP_EQ 0
440 #define OP_NE 1
441 #define OP_GT 2
442 #define OP_GE 3
443 #define OP_LT 4
444 #define OP_LE 5
445 #define OP_LIKE 6
446 #define OP_REGEXP 7
447 #define OP_IREGEXP 8
448 #define OP_BITAND 9
449 #define OP_MAX 10
450
count_one_ui64(int * count,int op,zbx_uint64_t value,zbx_uint64_t pattern,zbx_uint64_t mask)451 static void count_one_ui64(int *count, int op, zbx_uint64_t value, zbx_uint64_t pattern, zbx_uint64_t mask)
452 {
453 switch (op)
454 {
455 case OP_EQ:
456 if (value == pattern)
457 (*count)++;
458 break;
459 case OP_NE:
460 if (value != pattern)
461 (*count)++;
462 break;
463 case OP_GT:
464 if (value > pattern)
465 (*count)++;
466 break;
467 case OP_GE:
468 if (value >= pattern)
469 (*count)++;
470 break;
471 case OP_LT:
472 if (value < pattern)
473 (*count)++;
474 break;
475 case OP_LE:
476 if (value <= pattern)
477 (*count)++;
478 break;
479 case OP_BITAND:
480 if ((value & mask) == pattern)
481 (*count)++;
482 }
483 }
484
count_one_dbl(int * count,int op,double value,double pattern)485 static void count_one_dbl(int *count, int op, double value, double pattern)
486 {
487 switch (op)
488 {
489 case OP_EQ:
490 if (SUCCEED == zbx_double_compare(value, pattern))
491 (*count)++;
492 break;
493 case OP_NE:
494 if (FAIL == zbx_double_compare(value, pattern))
495 (*count)++;
496 break;
497 case OP_GT:
498 if (value - pattern > ZBX_DOUBLE_EPSILON)
499 (*count)++;
500 break;
501 case OP_GE:
502 if (value - pattern >= -ZBX_DOUBLE_EPSILON)
503 (*count)++;
504 break;
505 case OP_LT:
506 if (pattern - value > ZBX_DOUBLE_EPSILON)
507 (*count)++;
508 break;
509 case OP_LE:
510 if (pattern - value >= -ZBX_DOUBLE_EPSILON)
511 (*count)++;
512 }
513 }
514
count_one_str(int * count,int op,const char * value,const char * pattern,zbx_vector_ptr_t * regexps)515 static void count_one_str(int *count, int op, const char *value, const char *pattern, zbx_vector_ptr_t *regexps)
516 {
517 int res;
518
519 switch (op)
520 {
521 case OP_EQ:
522 if (0 == strcmp(value, pattern))
523 (*count)++;
524 break;
525 case OP_NE:
526 if (0 != strcmp(value, pattern))
527 (*count)++;
528 break;
529 case OP_LIKE:
530 if (NULL != strstr(value, pattern))
531 (*count)++;
532 break;
533 case OP_REGEXP:
534 if (ZBX_REGEXP_MATCH == (res = regexp_match_ex(regexps, value, pattern, ZBX_CASE_SENSITIVE)))
535 (*count)++;
536 else if (FAIL == res)
537 *count = FAIL;
538 break;
539 case OP_IREGEXP:
540 if (ZBX_REGEXP_MATCH == (res = regexp_match_ex(regexps, value, pattern, ZBX_IGNORE_CASE)))
541 (*count)++;
542 else if (FAIL == res)
543 *count = FAIL;
544 }
545 }
546
547 /******************************************************************************
548 * *
549 * Function: evaluate_COUNT *
550 * *
551 * Purpose: evaluate function 'count' for the item *
552 * *
553 * Parameters: item - item (performance metric) *
554 * parameters - up to four comma-separated fields: *
555 * (1) number of seconds/values *
556 * (2) value to compare with (optional) *
557 * Becomes mandatory for numeric items if 3rd *
558 * parameter is specified and is not "regexp" *
559 * or "iregexp". With "band" can take one of *
560 * 2 forms: *
561 * - value_to_compare_with/mask *
562 * - mask *
563 * (3) comparison operator (optional) *
564 * (4) time shift (optional) *
565 * *
566 * Return value: SUCCEED - evaluated successfully, result is stored in 'value'*
567 * FAIL - failed to evaluate function *
568 * *
569 ******************************************************************************/
evaluate_COUNT(char ** value,DC_ITEM * item,const char * parameters,const zbx_timespec_t * ts,char ** error)570 static int evaluate_COUNT(char **value, DC_ITEM *item, const char *parameters, const zbx_timespec_t *ts,
571 char **error)
572 {
573 int arg1, op = OP_UNKNOWN, numeric_search, nparams, count = 0, i, ret = FAIL;
574 int seconds = 0, nvalues = 0;
575 char *arg2 = NULL, *arg2_2 = NULL, *arg3 = NULL, buf[ZBX_MAX_UINT64_LEN];
576 double arg2_dbl;
577 zbx_uint64_t arg2_ui64, arg2_2_ui64;
578 zbx_value_type_t arg1_type;
579 zbx_vector_ptr_t regexps;
580 zbx_vector_history_record_t values;
581 zbx_timespec_t ts_end = *ts;
582 size_t value_alloc = 0, value_offset = 0;
583
584 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
585
586 zbx_vector_ptr_create(®exps);
587 zbx_history_record_vector_create(&values);
588
589 numeric_search = (ITEM_VALUE_TYPE_UINT64 == item->value_type || ITEM_VALUE_TYPE_FLOAT == item->value_type);
590
591 if (4 < (nparams = num_param(parameters)))
592 {
593 *error = zbx_strdup(*error, "invalid number of parameters");
594 goto out;
595 }
596
597 if (SUCCEED != get_function_parameter_int(parameters, 1, ZBX_PARAM_MANDATORY, &arg1, &arg1_type) || 0 >= arg1)
598 {
599 *error = zbx_strdup(*error, "invalid first parameter");
600 goto out;
601 }
602
603 if (2 <= nparams && SUCCEED != get_function_parameter_str(parameters, 2, &arg2))
604 {
605 *error = zbx_strdup(*error, "invalid second parameter");
606 goto out;
607 }
608
609 if (3 <= nparams && SUCCEED != get_function_parameter_str(parameters, 3, &arg3))
610 {
611 *error = zbx_strdup(*error, "invalid third parameter");
612 goto out;
613 }
614
615 if (4 <= nparams)
616 {
617 int time_shift = 0;
618 zbx_value_type_t time_shift_type = ZBX_VALUE_SECONDS;
619
620 if (SUCCEED != get_function_parameter_int(parameters, 4, ZBX_PARAM_OPTIONAL, &time_shift,
621 &time_shift_type) || ZBX_VALUE_SECONDS != time_shift_type || 0 > time_shift)
622 {
623 *error = zbx_strdup(*error, "invalid fourth parameter");
624 goto out;
625 }
626
627 ts_end.sec -= time_shift;
628 }
629
630 if (NULL == arg3 || '\0' == *arg3)
631 op = (0 != numeric_search ? OP_EQ : OP_LIKE);
632 else if (0 == strcmp(arg3, "eq"))
633 op = OP_EQ;
634 else if (0 == strcmp(arg3, "ne"))
635 op = OP_NE;
636 else if (0 == strcmp(arg3, "gt"))
637 op = OP_GT;
638 else if (0 == strcmp(arg3, "ge"))
639 op = OP_GE;
640 else if (0 == strcmp(arg3, "lt"))
641 op = OP_LT;
642 else if (0 == strcmp(arg3, "le"))
643 op = OP_LE;
644 else if (0 == strcmp(arg3, "like"))
645 op = OP_LIKE;
646 else if (0 == strcmp(arg3, "regexp"))
647 op = OP_REGEXP;
648 else if (0 == strcmp(arg3, "iregexp"))
649 op = OP_IREGEXP;
650 else if (0 == strcmp(arg3, "band"))
651 op = OP_BITAND;
652
653 if (OP_UNKNOWN == op)
654 {
655 *error = zbx_dsprintf(*error, "operator \"%s\" is not supported for function COUNT", arg3);
656 goto out;
657 }
658
659 numeric_search = (0 != numeric_search && OP_REGEXP != op && OP_IREGEXP != op);
660
661 if (0 != numeric_search)
662 {
663 if (NULL != arg3 && '\0' != *arg3 && '\0' == *arg2)
664 {
665 *error = zbx_strdup(*error, "pattern must be provided along with operator for numeric values");
666 goto out;
667 }
668
669 if (OP_LIKE == op)
670 {
671 *error = zbx_dsprintf(*error, "operator \"%s\" is not supported for counting numeric values",
672 arg3);
673 goto out;
674 }
675
676 if (OP_BITAND == op && ITEM_VALUE_TYPE_FLOAT == item->value_type)
677 {
678 *error = zbx_dsprintf(*error, "operator \"%s\" is not supported for counting float values",
679 arg3);
680 goto out;
681 }
682
683 if (OP_BITAND == op && NULL != (arg2_2 = strchr(arg2, '/')))
684 {
685 *arg2_2 = '\0'; /* end of the 1st part of the 2nd parameter (number to compare with) */
686 arg2_2++; /* start of the 2nd part of the 2nd parameter (mask) */
687 }
688
689 if (NULL != arg2 && '\0' != *arg2)
690 {
691 if (ITEM_VALUE_TYPE_UINT64 == item->value_type)
692 {
693 if (OP_BITAND != op)
694 {
695 if (SUCCEED != str2uint64(arg2, ZBX_UNIT_SYMBOLS, &arg2_ui64))
696 {
697 *error = zbx_dsprintf(*error, "\"%s\" is not a valid numeric unsigned"
698 " value", arg2);
699 goto out;
700 }
701 }
702 else
703 {
704 if (SUCCEED != is_uint64(arg2, &arg2_ui64))
705 {
706 *error = zbx_dsprintf(*error, "\"%s\" is not a valid numeric unsigned"
707 " value", arg2);
708 goto out;
709 }
710
711 if (NULL != arg2_2)
712 {
713 if (SUCCEED != is_uint64(arg2_2, &arg2_2_ui64))
714 {
715 *error = zbx_dsprintf(*error, "\"%s\" is not a valid numeric"
716 " unsigned value", arg2_2);
717 goto out;
718 }
719 }
720 else
721 arg2_2_ui64 = arg2_ui64;
722 }
723 }
724 else
725 {
726 if (SUCCEED != is_double_suffix(arg2, ZBX_FLAG_DOUBLE_SUFFIX))
727 {
728 *error = zbx_dsprintf(*error, "\"%s\" is not a valid numeric float value",
729 arg2);
730 goto out;
731 }
732
733 arg2_dbl = str2double(arg2);
734 }
735 }
736 }
737 else if (OP_LIKE != op && OP_REGEXP != op && OP_IREGEXP != op && OP_EQ != op && OP_NE != op)
738 {
739 *error = zbx_dsprintf(*error, "operator \"%s\" is not supported for counting textual values", arg3);
740 goto out;
741 }
742
743 if ((OP_REGEXP == op || OP_IREGEXP == op) && '@' == *arg2)
744 {
745 DCget_expressions_by_name(®exps, arg2 + 1);
746
747 if (0 == regexps.values_num)
748 {
749 *error = zbx_dsprintf(*error, "global regular expression \"%s\" does not exist", arg2 + 1);
750 goto out;
751 }
752 }
753
754 switch (arg1_type)
755 {
756 case ZBX_VALUE_SECONDS:
757 seconds = arg1;
758 break;
759 case ZBX_VALUE_NVALUES:
760 nvalues = arg1;
761 break;
762 default:
763 THIS_SHOULD_NEVER_HAPPEN;
764 }
765
766 if (FAIL == zbx_vc_get_values(item->itemid, item->value_type, &values, seconds, nvalues, &ts_end))
767 {
768 *error = zbx_strdup(*error, "cannot get values from value cache");
769 goto out;
770 }
771
772 /* skip counting values one by one if both pattern and operator are empty or "" is searched in text values */
773 if ((NULL != arg2 && '\0' != *arg2) || (NULL != arg3 && '\0' != *arg3 &&
774 OP_LIKE != op && OP_REGEXP != op && OP_IREGEXP != op))
775 {
776 switch (item->value_type)
777 {
778 case ITEM_VALUE_TYPE_UINT64:
779 if (0 != numeric_search)
780 {
781 for (i = 0; i < values.values_num; i++)
782 {
783 count_one_ui64(&count, op, values.values[i].value.ui64, arg2_ui64,
784 arg2_2_ui64);
785 }
786 }
787 else
788 {
789 for (i = 0; i < values.values_num && FAIL != count; i++)
790 {
791 zbx_snprintf(buf, sizeof(buf), ZBX_FS_UI64,
792 values.values[i].value.ui64);
793 count_one_str(&count, op, buf, arg2, ®exps);
794 }
795 }
796 break;
797 case ITEM_VALUE_TYPE_FLOAT:
798 if (0 != numeric_search)
799 {
800 for (i = 0; i < values.values_num; i++)
801 count_one_dbl(&count, op, values.values[i].value.dbl, arg2_dbl);
802 }
803 else
804 {
805 for (i = 0; i < values.values_num && FAIL != count; i++)
806 {
807 zbx_snprintf(buf, sizeof(buf), ZBX_FS_DBL_EXT(4),
808 values.values[i].value.dbl);
809 count_one_str(&count, op, buf, arg2, ®exps);
810 }
811 }
812 break;
813 case ITEM_VALUE_TYPE_LOG:
814 for (i = 0; i < values.values_num && FAIL != count; i++)
815 count_one_str(&count, op, values.values[i].value.log->value, arg2, ®exps);
816 break;
817 default:
818 for (i = 0; i < values.values_num && FAIL != count; i++)
819 count_one_str(&count, op, values.values[i].value.str, arg2, ®exps);
820 }
821
822 if (FAIL == count)
823 {
824 *error = zbx_strdup(*error, "invalid regular expression");
825 goto out;
826 }
827 }
828 else
829 count = values.values_num;
830
831 zbx_snprintf_alloc(value, &value_alloc, &value_offset, "%d", count);
832
833 ret = SUCCEED;
834 out:
835 zbx_free(arg2);
836 zbx_free(arg3);
837
838 zbx_regexp_clean_expressions(®exps);
839 zbx_vector_ptr_destroy(®exps);
840
841 zbx_history_record_vector_destroy(&values, item->value_type);
842
843 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
844
845 return ret;
846 }
847
848 #undef OP_UNKNOWN
849 #undef OP_EQ
850 #undef OP_NE
851 #undef OP_GT
852 #undef OP_GE
853 #undef OP_LT
854 #undef OP_LE
855 #undef OP_LIKE
856 #undef OP_REGEXP
857 #undef OP_IREGEXP
858 #undef OP_BITAND
859 #undef OP_MAX
860
861 /******************************************************************************
862 * *
863 * Function: evaluate_SUM *
864 * *
865 * Purpose: evaluate function 'sum' for the item *
866 * *
867 * Parameters: item - item (performance metric) *
868 * parameters - number of seconds/values and time shift (optional)*
869 * *
870 * Return value: SUCCEED - evaluated successfully, result is stored in 'value'*
871 * FAIL - failed to evaluate function *
872 * *
873 ******************************************************************************/
evaluate_SUM(char ** value,DC_ITEM * item,const char * parameters,const zbx_timespec_t * ts,char ** error)874 static int evaluate_SUM(char **value, DC_ITEM *item, const char *parameters, const zbx_timespec_t *ts, char **error)
875 {
876 int nparams, arg1, i, ret = FAIL, seconds = 0, nvalues = 0;
877 zbx_value_type_t arg1_type;
878 zbx_vector_history_record_t values;
879 history_value_t result;
880 zbx_timespec_t ts_end = *ts;
881
882 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
883
884 zbx_history_record_vector_create(&values);
885
886 if (ITEM_VALUE_TYPE_FLOAT != item->value_type && ITEM_VALUE_TYPE_UINT64 != item->value_type)
887 {
888 *error = zbx_strdup(*error, "invalid value type");
889 goto out;
890 }
891
892 if (2 < (nparams = num_param(parameters)))
893 {
894 *error = zbx_strdup(*error, "invalid number of parameters");
895 goto out;
896 }
897
898 if (SUCCEED != get_function_parameter_int(parameters, 1, ZBX_PARAM_MANDATORY, &arg1, &arg1_type) || 0 >= arg1)
899 {
900 *error = zbx_strdup(*error, "invalid first parameter");
901 goto out;
902 }
903
904 if (2 == nparams)
905 {
906 int time_shift = 0;
907 zbx_value_type_t time_shift_type = ZBX_VALUE_SECONDS;
908
909 if (SUCCEED != get_function_parameter_int(parameters, 2, ZBX_PARAM_OPTIONAL, &time_shift,
910 &time_shift_type) || ZBX_VALUE_SECONDS != time_shift_type || 0 > time_shift)
911 {
912 *error = zbx_strdup(*error, "invalid second parameter");
913 goto out;
914 }
915
916 ts_end.sec -= time_shift;
917 }
918
919 switch (arg1_type)
920 {
921 case ZBX_VALUE_SECONDS:
922 seconds = arg1;
923 break;
924 case ZBX_VALUE_NVALUES:
925 nvalues = arg1;
926 break;
927 default:
928 THIS_SHOULD_NEVER_HAPPEN;
929 }
930
931 if (FAIL == zbx_vc_get_values(item->itemid, item->value_type, &values, seconds, nvalues, &ts_end))
932 {
933 *error = zbx_strdup(*error, "cannot get values from value cache");
934 goto out;
935 }
936
937 if (ITEM_VALUE_TYPE_FLOAT == item->value_type)
938 {
939 result.dbl = 0;
940
941 for (i = 0; i < values.values_num; i++)
942 result.dbl += values.values[i].value.dbl;
943 }
944 else
945 {
946 result.ui64 = 0;
947
948 for (i = 0; i < values.values_num; i++)
949 result.ui64 += values.values[i].value.ui64;
950 }
951
952 *value = zbx_history_value2str_dyn(&result, item->value_type);
953 ret = SUCCEED;
954 out:
955 zbx_history_record_vector_destroy(&values, item->value_type);
956
957 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
958
959 return ret;
960 }
961
962 /******************************************************************************
963 * *
964 * Function: evaluate_AVG *
965 * *
966 * Purpose: evaluate function 'avg' for the item *
967 * *
968 * Parameters: item - item (performance metric) *
969 * parameters - number of seconds/values and time shift (optional)*
970 * *
971 * Return value: SUCCEED - evaluated successfully, result is stored in 'value'*
972 * FAIL - failed to evaluate function *
973 * *
974 ******************************************************************************/
evaluate_AVG(char ** value,DC_ITEM * item,const char * parameters,const zbx_timespec_t * ts,char ** error)975 static int evaluate_AVG(char **value, DC_ITEM *item, const char *parameters, const zbx_timespec_t *ts, char **error)
976 {
977 int nparams, arg1, ret = FAIL, i, seconds = 0, nvalues = 0;
978 zbx_value_type_t arg1_type;
979 zbx_vector_history_record_t values;
980 zbx_timespec_t ts_end = *ts;
981
982 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
983
984 zbx_history_record_vector_create(&values);
985
986 if (ITEM_VALUE_TYPE_FLOAT != item->value_type && ITEM_VALUE_TYPE_UINT64 != item->value_type)
987 {
988 *error = zbx_strdup(*error, "invalid value type");
989 goto out;
990 }
991
992 if (2 < (nparams = num_param(parameters)))
993 {
994 *error = zbx_strdup(*error, "invalid number of parameters");
995 goto out;
996 }
997
998 if (SUCCEED != get_function_parameter_int(parameters, 1, ZBX_PARAM_MANDATORY, &arg1, &arg1_type) || 0 >= arg1)
999 {
1000 *error = zbx_strdup(*error, "invalid first parameter");
1001 goto out;
1002 }
1003
1004 if (2 == nparams)
1005 {
1006 int time_shift = 0;
1007 zbx_value_type_t time_shift_type = ZBX_VALUE_SECONDS;
1008
1009 if (SUCCEED != get_function_parameter_int(parameters, 2, ZBX_PARAM_OPTIONAL, &time_shift,
1010 &time_shift_type) || ZBX_VALUE_SECONDS != time_shift_type || 0 > time_shift)
1011 {
1012 *error = zbx_strdup(*error, "invalid second parameter");
1013 goto out;
1014 }
1015
1016 ts_end.sec -= time_shift;
1017 }
1018
1019 switch (arg1_type)
1020 {
1021 case ZBX_VALUE_SECONDS:
1022 seconds = arg1;
1023 break;
1024 case ZBX_VALUE_NVALUES:
1025 nvalues = arg1;
1026 break;
1027 default:
1028 THIS_SHOULD_NEVER_HAPPEN;
1029 }
1030
1031 if (FAIL == zbx_vc_get_values(item->itemid, item->value_type, &values, seconds, nvalues, &ts_end))
1032 {
1033 *error = zbx_strdup(*error, "cannot get values from value cache");
1034 goto out;
1035 }
1036
1037 if (0 < values.values_num)
1038 {
1039 double avg = 0;
1040 size_t value_alloc = 0, value_offset = 0;
1041
1042 if (ITEM_VALUE_TYPE_FLOAT == item->value_type)
1043 {
1044 for (i = 0; i < values.values_num; i++)
1045 avg += values.values[i].value.dbl / (i + 1) - avg / (i + 1);
1046 }
1047 else
1048 {
1049 for (i = 0; i < values.values_num; i++)
1050 avg += values.values[i].value.ui64;
1051
1052 avg = avg / values.values_num;
1053 }
1054 zbx_snprintf_alloc(value, &value_alloc, &value_offset, ZBX_FS_DBL64, avg);
1055
1056 ret = SUCCEED;
1057 }
1058 else
1059 {
1060 zabbix_log(LOG_LEVEL_DEBUG, "result for AVG is empty");
1061 *error = zbx_strdup(*error, "not enough data");
1062 }
1063 out:
1064 zbx_history_record_vector_destroy(&values, item->value_type);
1065
1066 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
1067
1068 return ret;
1069 }
1070
1071 /******************************************************************************
1072 * *
1073 * Function: evaluate_LAST *
1074 * *
1075 * Purpose: evaluate functions 'last' and 'prev' for the item *
1076 * *
1077 * Parameters: value - dynamic buffer *
1078 * item - item (performance metric) *
1079 * parameters - Nth last value and time shift (optional) *
1080 * *
1081 * Return value: SUCCEED - evaluated successfully, result is stored in 'value'*
1082 * FAIL - failed to evaluate function *
1083 * *
1084 ******************************************************************************/
evaluate_LAST(char ** value,DC_ITEM * item,const char * parameters,const zbx_timespec_t * ts,char ** error)1085 static int evaluate_LAST(char **value, DC_ITEM *item, const char *parameters, const zbx_timespec_t *ts,
1086 char **error)
1087 {
1088 int arg1 = 1, ret = FAIL;
1089 zbx_value_type_t arg1_type = ZBX_VALUE_NVALUES;
1090 zbx_vector_history_record_t values;
1091 zbx_timespec_t ts_end = *ts;
1092
1093 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1094
1095 zbx_history_record_vector_create(&values);
1096
1097 if (SUCCEED != get_function_parameter_int(parameters, 1, ZBX_PARAM_OPTIONAL, &arg1, &arg1_type))
1098 {
1099 *error = zbx_strdup(*error, "invalid first parameter");
1100 goto out;
1101 }
1102
1103 if (ZBX_VALUE_NVALUES != arg1_type)
1104 arg1 = 1; /* non-# first parameter is ignored to support older syntax "last(0)" */
1105
1106 if (2 == num_param(parameters))
1107 {
1108 int time_shift = 0;
1109 zbx_value_type_t time_shift_type = ZBX_VALUE_SECONDS;
1110
1111 if (SUCCEED != get_function_parameter_int(parameters, 2, ZBX_PARAM_OPTIONAL, &time_shift,
1112 &time_shift_type) || ZBX_VALUE_SECONDS != time_shift_type || 0 > time_shift)
1113 {
1114 *error = zbx_strdup(*error, "invalid second parameter");
1115 goto out;
1116 }
1117
1118 ts_end.sec -= time_shift;
1119 }
1120
1121 if (SUCCEED == zbx_vc_get_values(item->itemid, item->value_type, &values, 0, arg1, &ts_end))
1122 {
1123 if (arg1 <= values.values_num)
1124 {
1125 char *tmp;
1126
1127 tmp = zbx_history_value2str_dyn(&values.values[arg1 - 1].value, item->value_type);
1128
1129 if (ITEM_VALUE_TYPE_STR == item->value_type ||
1130 ITEM_VALUE_TYPE_TEXT == item->value_type ||
1131 ITEM_VALUE_TYPE_LOG == item->value_type)
1132 {
1133 size_t len;
1134 char *ptr;
1135
1136 len = zbx_get_escape_string_len(tmp, "\"\\");
1137 ptr = *value = zbx_malloc(NULL, len + 3);
1138 *ptr++ = '"';
1139 zbx_escape_string(ptr, len + 1, tmp, "\"\\");
1140 ptr += len;
1141 *ptr++ = '"';
1142 *ptr = '\0';
1143 zbx_free(tmp);
1144 }
1145 else
1146 *value = tmp;
1147
1148 ret = SUCCEED;
1149 }
1150 else
1151 {
1152 *error = zbx_strdup(*error, "not enough data");
1153 goto out;
1154 }
1155 }
1156 else
1157 {
1158 *error = zbx_strdup(*error, "cannot get values from value cache");
1159 }
1160 out:
1161 zbx_history_record_vector_destroy(&values, item->value_type);
1162
1163 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
1164
1165 return ret;
1166 }
1167
1168 /******************************************************************************
1169 * *
1170 * Function: evaluate_MIN *
1171 * *
1172 * Purpose: evaluate function 'min' for the item *
1173 * *
1174 * Parameters: item - item (performance metric) *
1175 * parameters - number of seconds/values and time shift (optional)*
1176 * *
1177 * Return value: SUCCEED - evaluated successfully, result is stored in 'value'*
1178 * FAIL - failed to evaluate function *
1179 * *
1180 ******************************************************************************/
evaluate_MIN(char ** value,DC_ITEM * item,const char * parameters,const zbx_timespec_t * ts,char ** error)1181 static int evaluate_MIN(char **value, DC_ITEM *item, const char *parameters, const zbx_timespec_t *ts, char **error)
1182 {
1183 int nparams, arg1, i, ret = FAIL, seconds = 0, nvalues = 0;
1184 zbx_value_type_t arg1_type;
1185 zbx_vector_history_record_t values;
1186 zbx_timespec_t ts_end = *ts;
1187
1188 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1189
1190 zbx_history_record_vector_create(&values);
1191
1192 if (ITEM_VALUE_TYPE_FLOAT != item->value_type && ITEM_VALUE_TYPE_UINT64 != item->value_type)
1193 {
1194 *error = zbx_strdup(*error, "invalid value type");
1195 goto out;
1196 }
1197
1198 if (2 < (nparams = num_param(parameters)))
1199 {
1200 *error = zbx_strdup(*error, "invalid number of parameters");
1201 goto out;
1202 }
1203
1204 if (SUCCEED != get_function_parameter_int(parameters, 1, ZBX_PARAM_MANDATORY, &arg1, &arg1_type) || 0 >= arg1)
1205 {
1206 *error = zbx_strdup(*error, "invalid first parameter");
1207 goto out;
1208 }
1209
1210 if (2 == nparams)
1211 {
1212 int time_shift = 0;
1213 zbx_value_type_t time_shift_type = ZBX_VALUE_SECONDS;
1214
1215 if (SUCCEED != get_function_parameter_int(parameters, 2, ZBX_PARAM_OPTIONAL, &time_shift,
1216 &time_shift_type) || ZBX_VALUE_SECONDS != time_shift_type || 0 > time_shift)
1217 {
1218 *error = zbx_strdup(*error, "invalid second parameter");
1219 goto out;
1220 }
1221
1222 ts_end.sec -= time_shift;
1223 }
1224
1225 switch (arg1_type)
1226 {
1227 case ZBX_VALUE_SECONDS:
1228 seconds = arg1;
1229 break;
1230 case ZBX_VALUE_NVALUES:
1231 nvalues = arg1;
1232 break;
1233 default:
1234 THIS_SHOULD_NEVER_HAPPEN;
1235 }
1236
1237 if (FAIL == zbx_vc_get_values(item->itemid, item->value_type, &values, seconds, nvalues, &ts_end))
1238 {
1239 *error = zbx_strdup(*error, "cannot get values from value cache");
1240 goto out;
1241 }
1242
1243 if (0 < values.values_num)
1244 {
1245 int index = 0;
1246
1247 if (ITEM_VALUE_TYPE_UINT64 == item->value_type)
1248 {
1249 for (i = 1; i < values.values_num; i++)
1250 {
1251 if (values.values[i].value.ui64 < values.values[index].value.ui64)
1252 index = i;
1253 }
1254 }
1255 else
1256 {
1257 for (i = 1; i < values.values_num; i++)
1258 {
1259 if (values.values[i].value.dbl < values.values[index].value.dbl)
1260 index = i;
1261 }
1262 }
1263
1264 *value = zbx_history_value2str_dyn(&values.values[index].value, item->value_type);
1265 ret = SUCCEED;
1266 }
1267 else
1268 {
1269 zabbix_log(LOG_LEVEL_DEBUG, "result for MIN is empty");
1270 *error = zbx_strdup(*error, "not enough data");
1271 }
1272 out:
1273 zbx_history_record_vector_destroy(&values, item->value_type);
1274
1275 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
1276
1277 return ret;
1278 }
1279
1280 /******************************************************************************
1281 * *
1282 * Function: evaluate_MAX *
1283 * *
1284 * Purpose: evaluate function 'max' for the item *
1285 * *
1286 * Parameters: item - item (performance metric) *
1287 * parameters - number of seconds/values and time shift (optional)*
1288 * *
1289 * Return value: SUCCEED - evaluated successfully, result is stored in 'value'*
1290 * FAIL - failed to evaluate function *
1291 * *
1292 ******************************************************************************/
evaluate_MAX(char ** value,DC_ITEM * item,const char * parameters,const zbx_timespec_t * ts,char ** error)1293 static int evaluate_MAX(char **value, DC_ITEM *item, const char *parameters, const zbx_timespec_t *ts, char **error)
1294 {
1295 int nparams, arg1, ret = FAIL, i, seconds = 0, nvalues = 0;
1296 zbx_value_type_t arg1_type;
1297 zbx_vector_history_record_t values;
1298 zbx_timespec_t ts_end = *ts;
1299
1300 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1301
1302 zbx_history_record_vector_create(&values);
1303
1304 if (ITEM_VALUE_TYPE_FLOAT != item->value_type && ITEM_VALUE_TYPE_UINT64 != item->value_type)
1305 {
1306 *error = zbx_strdup(*error, "invalid value type");
1307 goto out;
1308 }
1309
1310 if (2 < (nparams = num_param(parameters)))
1311 {
1312 *error = zbx_strdup(*error, "invalid number of parameters");
1313 goto out;
1314 }
1315
1316 if (SUCCEED != get_function_parameter_int(parameters, 1, ZBX_PARAM_MANDATORY, &arg1, &arg1_type) || 0 >= arg1)
1317 {
1318 *error = zbx_strdup(*error, "invalid first parameter");
1319 goto out;
1320 }
1321
1322 if (2 == nparams)
1323 {
1324 int time_shift = 0;
1325 zbx_value_type_t time_shift_type = ZBX_VALUE_SECONDS;
1326
1327 if (SUCCEED != get_function_parameter_int(parameters, 2, ZBX_PARAM_OPTIONAL, &time_shift,
1328 &time_shift_type) || ZBX_VALUE_SECONDS != time_shift_type || 0 > time_shift)
1329 {
1330 *error = zbx_strdup(*error, "invalid second parameter");
1331 goto out;
1332 }
1333
1334 ts_end.sec -= time_shift;
1335 }
1336
1337 switch (arg1_type)
1338 {
1339 case ZBX_VALUE_SECONDS:
1340 seconds = arg1;
1341 break;
1342 case ZBX_VALUE_NVALUES:
1343 nvalues = arg1;
1344 break;
1345 default:
1346 THIS_SHOULD_NEVER_HAPPEN;
1347 }
1348
1349 if (FAIL == zbx_vc_get_values(item->itemid, item->value_type, &values, seconds, nvalues, &ts_end))
1350 {
1351 *error = zbx_strdup(*error, "cannot get values from value cache");
1352 goto out;
1353 }
1354
1355 if (0 < values.values_num)
1356 {
1357 int index = 0;
1358
1359 if (ITEM_VALUE_TYPE_UINT64 == item->value_type)
1360 {
1361 for (i = 1; i < values.values_num; i++)
1362 {
1363 if (values.values[i].value.ui64 > values.values[index].value.ui64)
1364 index = i;
1365 }
1366 }
1367 else
1368 {
1369 for (i = 1; i < values.values_num; i++)
1370 {
1371 if (values.values[i].value.dbl > values.values[index].value.dbl)
1372 index = i;
1373 }
1374 }
1375
1376 *value = zbx_history_value2str_dyn(&values.values[index].value, item->value_type);
1377
1378 ret = SUCCEED;
1379 }
1380 else
1381 {
1382 zabbix_log(LOG_LEVEL_DEBUG, "result for MAX is empty");
1383 *error = zbx_strdup(*error, "not enough data");
1384 }
1385 out:
1386 zbx_history_record_vector_destroy(&values, item->value_type);
1387
1388 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
1389
1390 return ret;
1391 }
1392
__history_record_float_compare(const zbx_history_record_t * d1,const zbx_history_record_t * d2)1393 static int __history_record_float_compare(const zbx_history_record_t *d1, const zbx_history_record_t *d2)
1394 {
1395 ZBX_RETURN_IF_NOT_EQUAL(d1->value.dbl, d2->value.dbl);
1396
1397 return 0;
1398 }
1399
__history_record_uint64_compare(const zbx_history_record_t * d1,const zbx_history_record_t * d2)1400 static int __history_record_uint64_compare(const zbx_history_record_t *d1, const zbx_history_record_t *d2)
1401 {
1402 ZBX_RETURN_IF_NOT_EQUAL(d1->value.ui64, d2->value.ui64);
1403
1404 return 0;
1405 }
1406
1407 /******************************************************************************
1408 * *
1409 * Function: evaluate_PERCENTILE *
1410 * *
1411 * Purpose: evaluate function 'percentile' for the item *
1412 * *
1413 * Parameters: item - [IN] item (performance metric) *
1414 * parameters - [IN] seconds/values, time shift (optional), *
1415 * percentage *
1416 * *
1417 * Return value: SUCCEED - evaluated successfully, result is stored in *
1418 * 'value' *
1419 * FAIL - failed to evaluate function *
1420 * *
1421 ******************************************************************************/
evaluate_PERCENTILE(char ** value,DC_ITEM * item,const char * parameters,const zbx_timespec_t * ts,char ** error)1422 static int evaluate_PERCENTILE(char **value, DC_ITEM *item, const char *parameters,
1423 const zbx_timespec_t *ts, char **error)
1424 {
1425 int nparams, arg1, time_shift = 0, ret = FAIL, seconds = 0, nvalues = 0;
1426 zbx_value_type_t arg1_type, time_shift_type = ZBX_VALUE_SECONDS;
1427 double percentage;
1428 zbx_vector_history_record_t values;
1429 zbx_timespec_t ts_end = *ts;
1430
1431 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1432
1433 zbx_history_record_vector_create(&values);
1434
1435 if (ITEM_VALUE_TYPE_FLOAT != item->value_type && ITEM_VALUE_TYPE_UINT64 != item->value_type)
1436 {
1437 *error = zbx_strdup(*error, "invalid value type");
1438 goto out;
1439 }
1440
1441 if (3 != (nparams = num_param(parameters)))
1442 {
1443 *error = zbx_strdup(*error, "invalid number of parameters");
1444 goto out;
1445 }
1446
1447 if (SUCCEED != get_function_parameter_int(parameters, 1, ZBX_PARAM_MANDATORY, &arg1, &arg1_type) || 0 >= arg1)
1448 {
1449 *error = zbx_strdup(*error, "invalid first parameter");
1450 goto out;
1451 }
1452
1453 switch (arg1_type)
1454 {
1455 case ZBX_VALUE_SECONDS:
1456 seconds = arg1;
1457 break;
1458 case ZBX_VALUE_NVALUES:
1459 nvalues = arg1;
1460 break;
1461 default:
1462 THIS_SHOULD_NEVER_HAPPEN;
1463 }
1464
1465 if (SUCCEED != get_function_parameter_int(parameters, 2, ZBX_PARAM_OPTIONAL, &time_shift, &time_shift_type) ||
1466 ZBX_VALUE_SECONDS != time_shift_type || 0 > time_shift)
1467 {
1468 *error = zbx_strdup(*error, "invalid second parameter");
1469 goto out;
1470 }
1471
1472 ts_end.sec -= time_shift;
1473
1474 if (SUCCEED != get_function_parameter_float(parameters, 3, ZBX_FLAG_DOUBLE_PLAIN, &percentage) ||
1475 0.0 > percentage || 100.0 < percentage)
1476 {
1477 *error = zbx_strdup(*error, "invalid third parameter");
1478 goto out;
1479 }
1480
1481 if (FAIL == zbx_vc_get_values(item->itemid, item->value_type, &values, seconds, nvalues, &ts_end))
1482 {
1483 *error = zbx_strdup(*error, "cannot get values from value cache");
1484 goto out;
1485 }
1486
1487 if (0 < values.values_num)
1488 {
1489 int index;
1490
1491 if (ITEM_VALUE_TYPE_FLOAT == item->value_type)
1492 zbx_vector_history_record_sort(&values, (zbx_compare_func_t)__history_record_float_compare);
1493 else
1494 zbx_vector_history_record_sort(&values, (zbx_compare_func_t)__history_record_uint64_compare);
1495
1496 if (0 == percentage)
1497 index = 1;
1498 else
1499 index = (int)ceil(values.values_num * (percentage / 100));
1500
1501 *value = zbx_history_value2str_dyn(&values.values[index - 1].value, item->value_type);
1502
1503 ret = SUCCEED;
1504 }
1505 else
1506 {
1507 zabbix_log(LOG_LEVEL_DEBUG, "result for PERCENTILE is empty");
1508 *error = zbx_strdup(*error, "not enough data");
1509 }
1510 out:
1511 zbx_history_record_vector_destroy(&values, item->value_type);
1512
1513 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
1514
1515 return ret;
1516 }
1517
1518 /******************************************************************************
1519 * *
1520 * Function: evaluate_DELTA *
1521 * *
1522 * Purpose: evaluate function 'delta' for the item *
1523 * *
1524 * Parameters: item - item (performance metric) *
1525 * parameters - number of seconds/values and time shift (optional)*
1526 * *
1527 * Return value: SUCCEED - evaluated successfully, result is stored in 'value'*
1528 * FAIL - failed to evaluate function *
1529 * *
1530 ******************************************************************************/
evaluate_DELTA(char ** value,DC_ITEM * item,const char * parameters,const zbx_timespec_t * ts,char ** error)1531 static int evaluate_DELTA(char **value, DC_ITEM *item, const char *parameters, const zbx_timespec_t *ts,
1532 char **error)
1533 {
1534 int nparams, arg1, ret = FAIL, i, seconds = 0, nvalues = 0;
1535 zbx_value_type_t arg1_type;
1536 zbx_vector_history_record_t values;
1537 zbx_timespec_t ts_end = *ts;
1538
1539 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1540
1541 zbx_history_record_vector_create(&values);
1542
1543 if (ITEM_VALUE_TYPE_FLOAT != item->value_type && ITEM_VALUE_TYPE_UINT64 != item->value_type)
1544 {
1545 *error = zbx_strdup(*error, "invalid value type");
1546 goto out;
1547 }
1548
1549 if (2 < (nparams = num_param(parameters)))
1550 {
1551 *error = zbx_strdup(*error, "invalid number of parameters");
1552 goto out;
1553 }
1554
1555 if (SUCCEED != get_function_parameter_int(parameters, 1, ZBX_PARAM_MANDATORY, &arg1, &arg1_type) || 0 >= arg1)
1556 {
1557 *error = zbx_strdup(*error, "invalid first parameter");
1558 goto out;
1559 }
1560
1561 if (2 == nparams)
1562 {
1563 int time_shift = 0;
1564 zbx_value_type_t time_shift_type = ZBX_VALUE_SECONDS;
1565
1566 if (SUCCEED != get_function_parameter_int(parameters, 2, ZBX_PARAM_OPTIONAL, &time_shift,
1567 &time_shift_type) || ZBX_VALUE_SECONDS != time_shift_type || 0 > time_shift)
1568 {
1569 *error = zbx_strdup(*error, "invalid second parameter");
1570 goto out;
1571 }
1572
1573 ts_end.sec -= time_shift;
1574 }
1575
1576 switch (arg1_type)
1577 {
1578 case ZBX_VALUE_SECONDS:
1579 seconds = arg1;
1580 break;
1581 case ZBX_VALUE_NVALUES:
1582 nvalues = arg1;
1583 break;
1584 default:
1585 THIS_SHOULD_NEVER_HAPPEN;
1586 }
1587
1588 if (FAIL == zbx_vc_get_values(item->itemid, item->value_type, &values, seconds, nvalues, &ts_end))
1589 {
1590 *error = zbx_strdup(*error, "cannot get values from value cache");
1591 goto out;
1592 }
1593
1594 if (0 < values.values_num)
1595 {
1596 history_value_t result;
1597 int index_min = 0, index_max = 0;
1598
1599 if (ITEM_VALUE_TYPE_UINT64 == item->value_type)
1600 {
1601 for (i = 1; i < values.values_num; i++)
1602 {
1603 if (values.values[i].value.ui64 > values.values[index_max].value.ui64)
1604 index_max = i;
1605
1606 if (values.values[i].value.ui64 < values.values[index_min].value.ui64)
1607 index_min = i;
1608 }
1609
1610 result.ui64 = values.values[index_max].value.ui64 - values.values[index_min].value.ui64;
1611 }
1612 else
1613 {
1614 for (i = 1; i < values.values_num; i++)
1615 {
1616 if (values.values[i].value.dbl > values.values[index_max].value.dbl)
1617 index_max = i;
1618
1619 if (values.values[i].value.dbl < values.values[index_min].value.dbl)
1620 index_min = i;
1621 }
1622
1623 result.dbl = values.values[index_max].value.dbl - values.values[index_min].value.dbl;
1624 }
1625
1626 *value = zbx_history_value2str_dyn(&result, item->value_type);
1627
1628 ret = SUCCEED;
1629 }
1630 else
1631 {
1632 zabbix_log(LOG_LEVEL_DEBUG, "result for DELTA is empty");
1633 *error = zbx_strdup(*error, "not enough data");
1634 }
1635 out:
1636 zbx_history_record_vector_destroy(&values, item->value_type);
1637
1638 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
1639
1640 return ret;
1641 }
1642
1643 /******************************************************************************
1644 * *
1645 * Function: evaluate_NODATA *
1646 * *
1647 * Purpose: evaluate function 'nodata' for the item *
1648 * *
1649 * Parameters: item - item (performance metric) *
1650 * parameter - number of seconds *
1651 * *
1652 * Return value: SUCCEED - evaluated successfully, result is stored in 'value'*
1653 * FAIL - failed to evaluate function *
1654 * *
1655 ******************************************************************************/
evaluate_NODATA(char ** value,DC_ITEM * item,const char * parameters,char ** error)1656 static int evaluate_NODATA(char **value, DC_ITEM *item, const char *parameters, char **error)
1657 {
1658 int arg1, num, period, lazy = 1, ret = FAIL;
1659 zbx_value_type_t arg1_type;
1660 zbx_vector_history_record_t values;
1661 zbx_timespec_t ts;
1662 char *arg2 = NULL;
1663 zbx_proxy_suppress_t nodata_win;
1664
1665 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1666
1667 zbx_history_record_vector_create(&values);
1668
1669 if (2 < (num = num_param(parameters)))
1670 {
1671 *error = zbx_strdup(*error, "invalid number of parameters");
1672 goto out;
1673 }
1674
1675 if (SUCCEED != get_function_parameter_int(parameters, 1, ZBX_PARAM_MANDATORY, &arg1, &arg1_type) ||
1676 ZBX_VALUE_SECONDS != arg1_type || 0 >= arg1)
1677 {
1678 *error = zbx_strdup(*error, "invalid first parameter");
1679 goto out;
1680 }
1681
1682 if (1 < num && (SUCCEED != get_function_parameter_str(parameters, 2, &arg2) ||
1683 ('\0' != *arg2 && 0 != (lazy = strcmp("strict", arg2)))))
1684 {
1685 *error = zbx_strdup(*error, "invalid second parameter");
1686 goto out;
1687 }
1688
1689 zbx_timespec(&ts);
1690 nodata_win.flags = ZBX_PROXY_SUPPRESS_DISABLE;
1691
1692 if (0 != item->host.proxy_hostid && 0 != lazy)
1693 {
1694 int lastaccess;
1695
1696 if (SUCCEED != DCget_proxy_nodata_win(item->host.proxy_hostid, &nodata_win, &lastaccess))
1697 {
1698 *error = zbx_strdup(*error, "cannot retrieve proxy last access");
1699 goto out;
1700 }
1701
1702 period = arg1 + (ts.sec - lastaccess);
1703 }
1704 else
1705 period = arg1;
1706
1707 if (SUCCEED == zbx_vc_get_values(item->itemid, item->value_type, &values, period, 1, &ts) &&
1708 1 == values.values_num)
1709 {
1710 *value = zbx_strdup(*value, "0");
1711 }
1712 else
1713 {
1714 int seconds;
1715
1716 if (SUCCEED != DCget_data_expected_from(item->itemid, &seconds))
1717 {
1718 *error = zbx_strdup(*error, "item does not exist, is disabled or belongs to a disabled host");
1719 goto out;
1720 }
1721
1722 if (seconds + arg1 > ts.sec)
1723 {
1724 *error = zbx_strdup(*error,
1725 "item does not have enough data after server start or item creation");
1726 goto out;
1727 }
1728
1729 if (0 != (nodata_win.flags & ZBX_PROXY_SUPPRESS_ACTIVE))
1730 {
1731 *error = zbx_strdup(*error, "historical data transfer from proxy is still in progress");
1732 goto out;
1733 }
1734
1735 *value = zbx_strdup(*value, "1");
1736
1737 if (0 != item->host.proxy_hostid && 0 != lazy)
1738 {
1739 zabbix_log(LOG_LEVEL_TRACE, "Nodata in %s() flag:%d values_num:%d start_time:%d period:%d",
1740 __func__, nodata_win.flags, nodata_win.values_num, ts.sec - period, period);
1741 }
1742 }
1743
1744 ret = SUCCEED;
1745 out:
1746 zbx_history_record_vector_destroy(&values, item->value_type);
1747 zbx_free(arg2);
1748
1749 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
1750
1751 return ret;
1752 }
1753
1754 /******************************************************************************
1755 * *
1756 * Function: evaluate_ABSCHANGE *
1757 * *
1758 * Purpose: evaluate function 'abschange' for the item *
1759 * *
1760 * Parameters: item - item (performance metric) *
1761 * parameter - number of seconds *
1762 * *
1763 * Return value: SUCCEED - evaluated successfully, result is stored in 'value'*
1764 * FAIL - failed to evaluate function *
1765 * *
1766 ******************************************************************************/
evaluate_ABSCHANGE(char ** value,DC_ITEM * item,const zbx_timespec_t * ts,char ** error)1767 static int evaluate_ABSCHANGE(char **value, DC_ITEM *item, const zbx_timespec_t *ts, char **error)
1768 {
1769 int ret = FAIL;
1770 size_t value_alloc = 0, value_offset = 0;
1771 zbx_vector_history_record_t values;
1772
1773 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1774
1775 zbx_history_record_vector_create(&values);
1776
1777 if (SUCCEED != zbx_vc_get_values(item->itemid, item->value_type, &values, 0, 2, ts) ||
1778 2 > values.values_num)
1779 {
1780 *error = zbx_strdup(*error, "cannot get values from value cache");
1781 goto out;
1782 }
1783
1784 switch (item->value_type)
1785 {
1786 case ITEM_VALUE_TYPE_FLOAT:
1787 zbx_snprintf_alloc(value, &value_alloc, &value_offset, ZBX_FS_DBL64,
1788 fabs(values.values[0].value.dbl - values.values[1].value.dbl));
1789 break;
1790 case ITEM_VALUE_TYPE_UINT64:
1791 /* to avoid overflow */
1792 if (values.values[0].value.ui64 >= values.values[1].value.ui64)
1793 {
1794 zbx_snprintf_alloc(value, &value_alloc, &value_offset, ZBX_FS_UI64,
1795 values.values[0].value.ui64 - values.values[1].value.ui64);
1796 }
1797 else
1798 {
1799 zbx_snprintf_alloc(value, &value_alloc, &value_offset, ZBX_FS_UI64,
1800 values.values[1].value.ui64 - values.values[0].value.ui64);
1801 }
1802 break;
1803 case ITEM_VALUE_TYPE_LOG:
1804 if (0 == strcmp(values.values[0].value.log->value, values.values[1].value.log->value))
1805 *value = zbx_strdup(*value, "0");
1806 else
1807 *value = zbx_strdup(*value, "1");
1808 break;
1809
1810 case ITEM_VALUE_TYPE_STR:
1811 case ITEM_VALUE_TYPE_TEXT:
1812 if (0 == strcmp(values.values[0].value.str, values.values[1].value.str))
1813 *value = zbx_strdup(*value, "0");
1814 else
1815 *value = zbx_strdup(*value, "1");
1816 break;
1817 default:
1818 *error = zbx_strdup(*error, "invalid value type");
1819 goto out;
1820 }
1821 ret = SUCCEED;
1822 out:
1823 zbx_history_record_vector_destroy(&values, item->value_type);
1824
1825 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
1826
1827 return ret;
1828 }
1829
1830 /******************************************************************************
1831 * *
1832 * Function: evaluate_CHANGE *
1833 * *
1834 * Purpose: evaluate function 'change' for the item *
1835 * *
1836 * Parameters: item - item (performance metric) *
1837 * parameter - number of seconds *
1838 * *
1839 * Return value: SUCCEED - evaluated successfully, result is stored in 'value'*
1840 * FAIL - failed to evaluate function *
1841 * *
1842 ******************************************************************************/
evaluate_CHANGE(char ** value,DC_ITEM * item,const zbx_timespec_t * ts,char ** error)1843 static int evaluate_CHANGE(char **value, DC_ITEM *item, const zbx_timespec_t *ts, char **error)
1844 {
1845 int ret = FAIL;
1846 size_t value_alloc = 0, value_offset = 0;
1847 zbx_vector_history_record_t values;
1848
1849 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1850
1851 zbx_history_record_vector_create(&values);
1852
1853 if (SUCCEED != zbx_vc_get_values(item->itemid, item->value_type, &values, 0, 2, ts) ||
1854 2 > values.values_num)
1855 {
1856 *error = zbx_strdup(*error, "cannot get values from value cache");
1857 goto out;
1858 }
1859
1860 switch (item->value_type)
1861 {
1862 case ITEM_VALUE_TYPE_FLOAT:
1863 zbx_snprintf_alloc(value, &value_alloc, &value_offset, ZBX_FS_DBL64,
1864 values.values[0].value.dbl - values.values[1].value.dbl);
1865 break;
1866 case ITEM_VALUE_TYPE_UINT64:
1867 /* to avoid overflow */
1868 if (values.values[0].value.ui64 >= values.values[1].value.ui64)
1869 zbx_snprintf_alloc(value, &value_alloc, &value_offset, ZBX_FS_UI64,
1870 values.values[0].value.ui64 - values.values[1].value.ui64);
1871 else
1872 zbx_snprintf_alloc(value, &value_alloc, &value_offset, "-" ZBX_FS_UI64,
1873 values.values[1].value.ui64 - values.values[0].value.ui64);
1874 break;
1875 case ITEM_VALUE_TYPE_LOG:
1876 if (0 == strcmp(values.values[0].value.log->value, values.values[1].value.log->value))
1877 *value = zbx_strdup(*value, "0");
1878 else
1879 *value = zbx_strdup(*value, "1");
1880 break;
1881
1882 case ITEM_VALUE_TYPE_STR:
1883 case ITEM_VALUE_TYPE_TEXT:
1884 if (0 == strcmp(values.values[0].value.str, values.values[1].value.str))
1885 *value = zbx_strdup(*value, "0");
1886 else
1887 *value = zbx_strdup(*value, "1");
1888 break;
1889 default:
1890 *error = zbx_strdup(*error, "invalid value type");
1891 goto out;
1892 }
1893
1894 ret = SUCCEED;
1895 out:
1896 zbx_history_record_vector_destroy(&values, item->value_type);
1897
1898 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
1899
1900 return ret;
1901 }
1902
1903 /******************************************************************************
1904 * *
1905 * Function: evaluate_DIFF *
1906 * *
1907 * Purpose: evaluate function 'diff' for the item *
1908 * *
1909 * Parameters: item - item (performance metric) *
1910 * parameter - number of seconds *
1911 * *
1912 * Return value: SUCCEED - evaluated successfully, result is stored in 'value'*
1913 * FAIL - failed to evaluate function *
1914 * *
1915 ******************************************************************************/
evaluate_DIFF(char ** value,DC_ITEM * item,const zbx_timespec_t * ts,char ** error)1916 static int evaluate_DIFF(char **value, DC_ITEM *item, const zbx_timespec_t *ts, char **error)
1917 {
1918 int ret = FAIL;
1919 zbx_vector_history_record_t values;
1920
1921 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
1922
1923 zbx_history_record_vector_create(&values);
1924
1925 if (SUCCEED != zbx_vc_get_values(item->itemid, item->value_type, &values, 0, 2, ts) || 2 > values.values_num)
1926 {
1927 *error = zbx_strdup(*error, "cannot get values from value cache");
1928 goto out;
1929 }
1930
1931 switch (item->value_type)
1932 {
1933 case ITEM_VALUE_TYPE_FLOAT:
1934 if (SUCCEED == zbx_double_compare(values.values[0].value.dbl, values.values[1].value.dbl))
1935 *value = zbx_strdup(*value, "0");
1936 else
1937 *value = zbx_strdup(*value, "1");
1938 break;
1939 case ITEM_VALUE_TYPE_UINT64:
1940 if (values.values[0].value.ui64 == values.values[1].value.ui64)
1941 *value = zbx_strdup(*value, "0");
1942 else
1943 *value = zbx_strdup(*value, "1");
1944 break;
1945 case ITEM_VALUE_TYPE_LOG:
1946 if (0 == strcmp(values.values[0].value.log->value, values.values[1].value.log->value))
1947 *value = zbx_strdup(*value, "0");
1948 else
1949 *value = zbx_strdup(*value, "1");
1950 break;
1951 case ITEM_VALUE_TYPE_STR:
1952 case ITEM_VALUE_TYPE_TEXT:
1953 if (0 == strcmp(values.values[0].value.str, values.values[1].value.str))
1954 *value = zbx_strdup(*value, "0");
1955 else
1956 *value = zbx_strdup(*value, "1");
1957 break;
1958 default:
1959 *error = zbx_strdup(*error, "invalid value type");
1960 goto out;
1961 }
1962
1963 ret = SUCCEED;
1964 out:
1965 zbx_history_record_vector_destroy(&values, item->value_type);
1966
1967 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
1968
1969 return ret;
1970 }
1971
1972 /******************************************************************************
1973 * *
1974 * Function: evaluate_STR *
1975 * *
1976 * Purpose: evaluate function 'str' for the item *
1977 * *
1978 * Parameters: item - item (performance metric) *
1979 * parameters - <string>[,seconds] *
1980 * *
1981 * Return value: SUCCEED - evaluated successfully, result stored in 'value' *
1982 * FAIL - failed to match the regular expression *
1983 * NOTSUPPORTED - invalid regular expression *
1984 * *
1985 ******************************************************************************/
1986
1987 #define ZBX_FUNC_STR 1
1988 #define ZBX_FUNC_REGEXP 2
1989 #define ZBX_FUNC_IREGEXP 3
1990
evaluate_STR_one(int func,zbx_vector_ptr_t * regexps,const char * value,const char * arg1)1991 static int evaluate_STR_one(int func, zbx_vector_ptr_t *regexps, const char *value, const char *arg1)
1992 {
1993 switch (func)
1994 {
1995 case ZBX_FUNC_STR:
1996 if (NULL != strstr(value, arg1))
1997 return SUCCEED;
1998 break;
1999 case ZBX_FUNC_REGEXP:
2000 switch (regexp_match_ex(regexps, value, arg1, ZBX_CASE_SENSITIVE))
2001 {
2002 case ZBX_REGEXP_MATCH:
2003 return SUCCEED;
2004 case FAIL:
2005 return NOTSUPPORTED;
2006 }
2007 break;
2008 case ZBX_FUNC_IREGEXP:
2009 switch (regexp_match_ex(regexps, value, arg1, ZBX_IGNORE_CASE))
2010 {
2011 case ZBX_REGEXP_MATCH:
2012 return SUCCEED;
2013 case FAIL:
2014 return NOTSUPPORTED;
2015 }
2016 break;
2017 }
2018
2019 return FAIL;
2020 }
2021
evaluate_STR(char ** value,DC_ITEM * item,const char * function,const char * parameters,const zbx_timespec_t * ts,char ** error)2022 static int evaluate_STR(char **value, DC_ITEM *item, const char *function, const char *parameters,
2023 const zbx_timespec_t *ts, char **error)
2024 {
2025 char *arg1 = NULL;
2026 int arg2 = 1, func, found = 0, i, ret = FAIL, seconds = 0, nvalues = 0, nparams;
2027 int str_one_ret;
2028 zbx_value_type_t arg2_type = ZBX_VALUE_NVALUES;
2029 zbx_vector_ptr_t regexps;
2030 zbx_vector_history_record_t values;
2031 size_t value_alloc = 0, value_offset = 0;
2032
2033 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
2034
2035 zbx_vector_ptr_create(®exps);
2036 zbx_history_record_vector_create(&values);
2037
2038 if (ITEM_VALUE_TYPE_STR != item->value_type && ITEM_VALUE_TYPE_TEXT != item->value_type &&
2039 ITEM_VALUE_TYPE_LOG != item->value_type)
2040 {
2041 *error = zbx_strdup(*error, "invalid value type");
2042 goto out;
2043 }
2044
2045 if (0 == strcmp(function, "str"))
2046 func = ZBX_FUNC_STR;
2047 else if (0 == strcmp(function, "regexp"))
2048 func = ZBX_FUNC_REGEXP;
2049 else if (0 == strcmp(function, "iregexp"))
2050 func = ZBX_FUNC_IREGEXP;
2051 else
2052 goto out;
2053
2054 if (2 < (nparams = num_param(parameters)))
2055 {
2056 *error = zbx_strdup(*error, "invalid number of parameters");
2057 goto out;
2058 }
2059
2060 if (SUCCEED != get_function_parameter_str(parameters, 1, &arg1))
2061 {
2062 *error = zbx_strdup(*error, "invalid first parameter");
2063 goto out;
2064 }
2065
2066 if (2 == nparams)
2067 {
2068 if (SUCCEED != get_function_parameter_int(parameters, 2, ZBX_PARAM_OPTIONAL, &arg2, &arg2_type) ||
2069 0 >= arg2)
2070 {
2071 *error = zbx_strdup(*error, "invalid second parameter");
2072 goto out;
2073 }
2074 }
2075
2076 if ((ZBX_FUNC_REGEXP == func || ZBX_FUNC_IREGEXP == func) && '@' == *arg1)
2077 {
2078 DCget_expressions_by_name(®exps, arg1 + 1);
2079
2080 if (0 == regexps.values_num)
2081 {
2082 *error = zbx_dsprintf(*error, "global regular expression \"%s\" does not exist", arg1 + 1);
2083 goto out;
2084 }
2085 }
2086
2087 switch (arg2_type)
2088 {
2089 case ZBX_VALUE_SECONDS:
2090 seconds = arg2;
2091 break;
2092 case ZBX_VALUE_NVALUES:
2093 nvalues = arg2;
2094 break;
2095 default:
2096 THIS_SHOULD_NEVER_HAPPEN;
2097 }
2098
2099 if (FAIL == zbx_vc_get_values(item->itemid, item->value_type, &values, seconds, nvalues, ts))
2100 {
2101 *error = zbx_strdup(*error, "cannot get values from value cache");
2102 goto out;
2103 }
2104
2105 if (0 != values.values_num)
2106 {
2107 /* at this point the value type can be only str, text or log */
2108 if (ITEM_VALUE_TYPE_LOG == item->value_type)
2109 {
2110 for (i = 0; i < values.values_num; i++)
2111 {
2112 if (SUCCEED == (str_one_ret = evaluate_STR_one(func, ®exps,
2113 values.values[i].value.log->value, arg1)))
2114 {
2115 found = 1;
2116 break;
2117 }
2118
2119 if (NOTSUPPORTED == str_one_ret)
2120 {
2121 *error = zbx_dsprintf(*error, "invalid regular expression \"%s\"", arg1);
2122 goto out;
2123 }
2124 }
2125 }
2126 else
2127 {
2128 for (i = 0; i < values.values_num; i++)
2129 {
2130 if (SUCCEED == (str_one_ret = evaluate_STR_one(func, ®exps,
2131 values.values[i].value.str, arg1)))
2132 {
2133 found = 1;
2134 break;
2135 }
2136
2137 if (NOTSUPPORTED == str_one_ret)
2138 {
2139 *error = zbx_dsprintf(*error, "invalid regular expression \"%s\"", arg1);
2140 goto out;
2141 }
2142 }
2143 }
2144 }
2145
2146 zbx_snprintf_alloc(value, &value_alloc, &value_offset, "%d", found);
2147 ret = SUCCEED;
2148 out:
2149 zbx_regexp_clean_expressions(®exps);
2150 zbx_vector_ptr_destroy(®exps);
2151
2152 zbx_history_record_vector_destroy(&values, item->value_type);
2153
2154 zbx_free(arg1);
2155
2156 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
2157
2158 return ret;
2159 }
2160
2161 #undef ZBX_FUNC_STR
2162 #undef ZBX_FUNC_REGEXP
2163 #undef ZBX_FUNC_IREGEXP
2164
2165 /******************************************************************************
2166 * *
2167 * Function: evaluate_STRLEN *
2168 * *
2169 * Purpose: evaluate function 'strlen' for the item *
2170 * *
2171 * Parameters: value - dynamic buffer *
2172 * item - item (performance metric) *
2173 * parameters - Nth last value and time shift (optional) *
2174 * *
2175 * Return value: SUCCEED - evaluated successfully, result is stored in 'value'*
2176 * FAIL - failed to evaluate function *
2177 * *
2178 ******************************************************************************/
evaluate_STRLEN(char ** value,DC_ITEM * item,const char * parameters,const zbx_timespec_t * ts,char ** error)2179 static int evaluate_STRLEN(char **value, DC_ITEM *item, const char *parameters, const zbx_timespec_t *ts,
2180 char **error)
2181 {
2182 int arg1 = 1, ret = FAIL;
2183 zbx_value_type_t arg1_type = ZBX_VALUE_NVALUES;
2184 zbx_vector_history_record_t values;
2185 zbx_timespec_t ts_end = *ts;
2186
2187 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
2188
2189 zbx_history_record_vector_create(&values);
2190
2191 if (ITEM_VALUE_TYPE_STR != item->value_type && ITEM_VALUE_TYPE_TEXT != item->value_type &&
2192 ITEM_VALUE_TYPE_LOG != item->value_type)
2193 {
2194 *error = zbx_strdup(*error, "invalid value type");
2195 goto out;
2196 }
2197
2198 if (SUCCEED != get_function_parameter_int(parameters, 1, ZBX_PARAM_OPTIONAL, &arg1, &arg1_type))
2199 {
2200 *error = zbx_strdup(*error, "invalid first parameter");
2201 goto out;
2202 }
2203
2204 if (ZBX_VALUE_NVALUES != arg1_type)
2205 arg1 = 1; /* non-# first parameter is ignored to support older syntax "strlen(0)" */
2206
2207 if (2 == num_param(parameters))
2208 {
2209 int time_shift = 0;
2210 zbx_value_type_t time_shift_type = ZBX_VALUE_SECONDS;
2211
2212 if (SUCCEED != get_function_parameter_int(parameters, 2, ZBX_PARAM_OPTIONAL, &time_shift,
2213 &time_shift_type) || ZBX_VALUE_SECONDS != time_shift_type || 0 > time_shift)
2214 {
2215 *error = zbx_strdup(*error, "invalid second parameter");
2216 goto out;
2217 }
2218
2219 ts_end.sec -= time_shift;
2220 }
2221
2222 if (SUCCEED == zbx_vc_get_values(item->itemid, item->value_type, &values, 0, arg1, &ts_end))
2223 {
2224 if (arg1 <= values.values_num)
2225 {
2226 size_t sz, value_alloc = 0, value_offset = 0;
2227 char *hist_val;
2228
2229 hist_val = zbx_history_value2str_dyn(&values.values[arg1 - 1].value, item->value_type);
2230 sz = zbx_strlen_utf8(hist_val);
2231 zbx_free(hist_val);
2232
2233 zbx_snprintf_alloc(value, &value_alloc, &value_offset, ZBX_FS_SIZE_T, sz);
2234 ret = SUCCEED;
2235 }
2236 else
2237 {
2238 *error = zbx_strdup(*error, "not enough data");
2239 goto out;
2240 }
2241 }
2242 else
2243 {
2244 *error = zbx_strdup(*error, "cannot get values from value cache");
2245 }
2246
2247 zbx_history_record_vector_destroy(&values, item->value_type);
2248 out:
2249 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
2250
2251 return ret;
2252 }
2253
2254 /******************************************************************************
2255 * *
2256 * Function: evaluate_FUZZYTIME *
2257 * *
2258 * Purpose: evaluate function 'fuzzytime' for the item *
2259 * *
2260 * Parameters: item - item (performance metric) *
2261 * parameter - number of seconds *
2262 * *
2263 * Return value: SUCCEED - evaluated successfully, result is stored in 'value'*
2264 * FAIL - failed to evaluate function *
2265 * *
2266 ******************************************************************************/
evaluate_FUZZYTIME(char ** value,DC_ITEM * item,const char * parameters,const zbx_timespec_t * ts,char ** error)2267 static int evaluate_FUZZYTIME(char **value, DC_ITEM *item, const char *parameters, const zbx_timespec_t *ts,
2268 char **error)
2269 {
2270 int arg1, ret = FAIL;
2271 zbx_value_type_t arg1_type;
2272 zbx_history_record_t vc_value;
2273 zbx_uint64_t fuzlow, fuzhig;
2274
2275 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
2276
2277 if (ITEM_VALUE_TYPE_FLOAT != item->value_type && ITEM_VALUE_TYPE_UINT64 != item->value_type)
2278 {
2279 *error = zbx_strdup(*error, "invalid value type");
2280 goto out;
2281 }
2282
2283 if (1 < num_param(parameters))
2284 {
2285 *error = zbx_strdup(*error, "invalid number of parameters");
2286 goto out;
2287 }
2288
2289 if (SUCCEED != get_function_parameter_int(parameters, 1, ZBX_PARAM_MANDATORY, &arg1, &arg1_type) || 0 >= arg1)
2290 {
2291 *error = zbx_strdup(*error, "invalid first parameter");
2292 goto out;
2293 }
2294
2295 if (ZBX_VALUE_SECONDS != arg1_type || ts->sec <= arg1)
2296 {
2297 *error = zbx_strdup(*error, "invalid argument type or value");
2298 goto out;
2299 }
2300
2301 if (SUCCEED != zbx_vc_get_value(item->itemid, item->value_type, ts, &vc_value))
2302 {
2303 *error = zbx_strdup(*error, "cannot get value from value cache");
2304 goto out;
2305 }
2306
2307 fuzlow = (int)(ts->sec - arg1);
2308 fuzhig = (int)(ts->sec + arg1);
2309
2310 if (ITEM_VALUE_TYPE_UINT64 == item->value_type)
2311 {
2312 if (vc_value.value.ui64 >= fuzlow && vc_value.value.ui64 <= fuzhig)
2313 *value = zbx_strdup(*value, "1");
2314 else
2315 *value = zbx_strdup(*value, "0");
2316 }
2317 else
2318 {
2319 if (vc_value.value.dbl >= fuzlow && vc_value.value.dbl <= fuzhig)
2320 *value = zbx_strdup(*value, "1");
2321 else
2322 *value = zbx_strdup(*value, "0");
2323 }
2324
2325 zbx_history_record_clear(&vc_value, item->value_type);
2326
2327 ret = SUCCEED;
2328 out:
2329 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
2330
2331 return ret;
2332 }
2333
2334 /******************************************************************************
2335 * *
2336 * Function: evaluate_BAND *
2337 * *
2338 * Purpose: evaluate logical bitwise function 'and' for the item *
2339 * *
2340 * Parameters: value - dynamic buffer *
2341 * item - item (performance metric) *
2342 * parameters - up to 3 comma-separated fields: *
2343 * (1) same as the 1st parameter for function *
2344 * evaluate_LAST() (see documentation of *
2345 * trigger function last()), *
2346 * (2) mask to bitwise AND with (mandatory), *
2347 * (3) same as the 2nd parameter for function *
2348 * evaluate_LAST() (see documentation of *
2349 * trigger function last()). *
2350 * *
2351 * Return value: SUCCEED - evaluated successfully, result is stored in 'value'*
2352 * FAIL - failed to evaluate function *
2353 * *
2354 ******************************************************************************/
evaluate_BAND(char ** value,DC_ITEM * item,const char * parameters,const zbx_timespec_t * ts,char ** error)2355 static int evaluate_BAND(char **value, DC_ITEM *item, const char *parameters, const zbx_timespec_t *ts,
2356 char **error)
2357 {
2358 char *last_parameters = NULL;
2359 int nparams, ret = FAIL;
2360 zbx_uint64_t last_uint64, mask;
2361
2362 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
2363
2364 if (ITEM_VALUE_TYPE_UINT64 != item->value_type)
2365 {
2366 *error = zbx_strdup(*error, "invalid value type");
2367 goto clean;
2368 }
2369
2370 if (3 < (nparams = num_param(parameters)))
2371 {
2372 *error = zbx_strdup(*error, "invalid number of parameters");
2373 goto clean;
2374 }
2375
2376 if (SUCCEED != get_function_parameter_uint64(parameters, 2, &mask))
2377 {
2378 *error = zbx_strdup(*error, "invalid second parameter");
2379 goto clean;
2380 }
2381
2382 /* prepare the 1st and the 3rd parameter for passing to evaluate_LAST() */
2383 last_parameters = zbx_strdup(NULL, parameters);
2384 remove_param(last_parameters, 2);
2385
2386 if (SUCCEED == evaluate_LAST(value, item, last_parameters, ts, error))
2387 {
2388 ZBX_STR2UINT64(last_uint64, *value);
2389 /* 'and' bit operation cannot be larger than the source value, */
2390 /* so the result can just be copied in value buffer */
2391 zbx_snprintf(*value, strlen(*value) + 1, ZBX_FS_UI64, last_uint64 & (zbx_uint64_t)mask);
2392 ret = SUCCEED;
2393 }
2394
2395 zbx_free(last_parameters);
2396 clean:
2397 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
2398
2399 return ret;
2400 }
2401
2402 /******************************************************************************
2403 * *
2404 * Function: evaluate_FORECAST *
2405 * *
2406 * Purpose: evaluate function 'forecast' for the item *
2407 * *
2408 * Parameters: item - item (performance metric) *
2409 * parameters - number of seconds/values and time shift (optional)*
2410 * *
2411 * Return value: SUCCEED - evaluated successfully, result is stored in 'value'*
2412 * FAIL - failed to evaluate function *
2413 * *
2414 ******************************************************************************/
evaluate_FORECAST(char ** value,DC_ITEM * item,const char * parameters,const zbx_timespec_t * ts,char ** error)2415 static int evaluate_FORECAST(char **value, DC_ITEM *item, const char *parameters, const zbx_timespec_t *ts,
2416 char **error)
2417 {
2418 char *fit_str = NULL, *mode_str = NULL;
2419 double *t = NULL, *x = NULL;
2420 int nparams, time, arg1, i, ret = FAIL, seconds = 0, nvalues = 0, time_shift = 0;
2421 zbx_value_type_t time_type, time_shift_type = ZBX_VALUE_SECONDS, arg1_type;
2422 unsigned int k = 0;
2423 zbx_vector_history_record_t values;
2424 zbx_timespec_t zero_time;
2425 zbx_fit_t fit;
2426 zbx_mode_t mode;
2427 zbx_timespec_t ts_end = *ts;
2428 size_t value_alloc = 0, value_offset = 0;
2429
2430 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
2431
2432 zbx_history_record_vector_create(&values);
2433
2434 if (ITEM_VALUE_TYPE_FLOAT != item->value_type && ITEM_VALUE_TYPE_UINT64 != item->value_type)
2435 {
2436 *error = zbx_strdup(*error, "invalid value type");
2437 goto out;
2438 }
2439
2440 if (3 > (nparams = num_param(parameters)) || nparams > 5)
2441 {
2442 *error = zbx_strdup(*error, "invalid number of parameters");
2443 goto out;
2444 }
2445
2446 if (SUCCEED != get_function_parameter_int(parameters, 1, ZBX_PARAM_MANDATORY, &arg1, &arg1_type) || 0 >= arg1)
2447 {
2448 *error = zbx_strdup(*error, "invalid first parameter");
2449 goto out;
2450 }
2451
2452 if (SUCCEED != get_function_parameter_int(parameters, 2, ZBX_PARAM_OPTIONAL, &time_shift, &time_shift_type) ||
2453 ZBX_VALUE_SECONDS != time_shift_type || 0 > time_shift)
2454 {
2455 *error = zbx_strdup(*error, "invalid second parameter");
2456 goto out;
2457 }
2458
2459 if (SUCCEED != get_function_parameter_int(parameters, 3, ZBX_PARAM_MANDATORY, &time, &time_type) ||
2460 ZBX_VALUE_SECONDS != time_type)
2461 {
2462 *error = zbx_strdup(*error, "invalid third parameter");
2463 goto out;
2464 }
2465
2466 if (4 <= nparams)
2467 {
2468 if (SUCCEED != get_function_parameter_str(parameters, 4, &fit_str) ||
2469 SUCCEED != zbx_fit_code(fit_str, &fit, &k, error))
2470 {
2471 *error = zbx_strdup(*error, "invalid fourth parameter");
2472 goto out;
2473 }
2474 }
2475 else
2476 {
2477 fit = FIT_LINEAR;
2478 }
2479
2480 if (5 == nparams)
2481 {
2482 if (SUCCEED != get_function_parameter_str(parameters, 5, &mode_str) ||
2483 SUCCEED != zbx_mode_code(mode_str, &mode, error))
2484 {
2485 *error = zbx_strdup(*error, "invalid fifth parameter");
2486 goto out;
2487 }
2488 }
2489 else
2490 {
2491 mode = MODE_VALUE;
2492 }
2493
2494 switch (arg1_type)
2495 {
2496 case ZBX_VALUE_SECONDS:
2497 seconds = arg1;
2498 break;
2499 case ZBX_VALUE_NVALUES:
2500 nvalues = arg1;
2501 break;
2502 default:
2503 THIS_SHOULD_NEVER_HAPPEN;
2504 }
2505
2506 ts_end.sec -= time_shift;
2507
2508 if (FAIL == zbx_vc_get_values(item->itemid, item->value_type, &values, seconds, nvalues, &ts_end))
2509 {
2510 *error = zbx_strdup(*error, "cannot get values from value cache");
2511 goto out;
2512 }
2513
2514 if (0 < values.values_num)
2515 {
2516 t = (double *)zbx_malloc(t, values.values_num * sizeof(double));
2517 x = (double *)zbx_malloc(x, values.values_num * sizeof(double));
2518
2519 zero_time.sec = values.values[values.values_num - 1].timestamp.sec;
2520 zero_time.ns = values.values[values.values_num - 1].timestamp.ns;
2521
2522 if (ITEM_VALUE_TYPE_FLOAT == item->value_type)
2523 {
2524 for (i = 0; i < values.values_num; i++)
2525 {
2526 t[i] = values.values[i].timestamp.sec - zero_time.sec + 1.0e-9 *
2527 (values.values[i].timestamp.ns - zero_time.ns + 1);
2528 x[i] = values.values[i].value.dbl;
2529 }
2530 }
2531 else
2532 {
2533 for (i = 0; i < values.values_num; i++)
2534 {
2535 t[i] = values.values[i].timestamp.sec - zero_time.sec + 1.0e-9 *
2536 (values.values[i].timestamp.ns - zero_time.ns + 1);
2537 x[i] = values.values[i].value.ui64;
2538 }
2539 }
2540
2541 zbx_snprintf_alloc(value, &value_alloc, &value_offset, ZBX_FS_DBL64, zbx_forecast(t, x,
2542 values.values_num, ts->sec - zero_time.sec - 1.0e-9 * (zero_time.ns + 1), time, fit, k,
2543 mode));
2544 }
2545 else
2546 {
2547 zabbix_log(LOG_LEVEL_DEBUG, "no data available");
2548 zbx_snprintf_alloc(value, &value_alloc, &value_offset, ZBX_FS_DBL64, ZBX_MATH_ERROR);
2549 }
2550
2551 ret = SUCCEED;
2552 out:
2553 zbx_history_record_vector_destroy(&values, item->value_type);
2554
2555 zbx_free(fit_str);
2556 zbx_free(mode_str);
2557
2558 zbx_free(t);
2559 zbx_free(x);
2560
2561 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
2562
2563 return ret;
2564 }
2565
2566 /******************************************************************************
2567 * *
2568 * Function: evaluate_TIMELEFT *
2569 * *
2570 * Purpose: evaluate function 'timeleft' for the item *
2571 * *
2572 * Parameters: item - item (performance metric) *
2573 * parameters - number of seconds/values and time shift (optional)*
2574 * *
2575 * Return value: SUCCEED - evaluated successfully, result is stored in 'value'*
2576 * FAIL - failed to evaluate function *
2577 * *
2578 ******************************************************************************/
evaluate_TIMELEFT(char ** value,DC_ITEM * item,const char * parameters,const zbx_timespec_t * ts,char ** error)2579 static int evaluate_TIMELEFT(char **value, DC_ITEM *item, const char *parameters, const zbx_timespec_t *ts,
2580 char **error)
2581 {
2582 char *fit_str = NULL;
2583 double *t = NULL, *x = NULL, threshold;
2584 int nparams, arg1, i, ret = FAIL, seconds = 0, nvalues = 0, time_shift = 0;
2585 zbx_value_type_t arg1_type, time_shift_type = ZBX_VALUE_SECONDS;
2586 unsigned k = 0;
2587 zbx_vector_history_record_t values;
2588 zbx_timespec_t zero_time;
2589 zbx_fit_t fit;
2590 zbx_timespec_t ts_end = *ts;
2591 size_t value_alloc = 0, value_offset = 0;
2592
2593 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
2594
2595 zbx_history_record_vector_create(&values);
2596
2597 if (ITEM_VALUE_TYPE_FLOAT != item->value_type && ITEM_VALUE_TYPE_UINT64 != item->value_type)
2598 {
2599 *error = zbx_strdup(*error, "invalid value type");
2600 goto out;
2601 }
2602
2603 if (3 > (nparams = num_param(parameters)) || nparams > 4)
2604 {
2605 *error = zbx_strdup(*error, "invalid number of parameters");
2606 goto out;
2607 }
2608
2609 if (SUCCEED != get_function_parameter_int(parameters, 1, ZBX_PARAM_MANDATORY, &arg1, &arg1_type) || 0 >= arg1)
2610 {
2611 *error = zbx_strdup(*error, "invalid first parameter");
2612 goto out;
2613 }
2614
2615 if (SUCCEED != get_function_parameter_int(parameters, 2, ZBX_PARAM_OPTIONAL, &time_shift, &time_shift_type) ||
2616 ZBX_VALUE_SECONDS != time_shift_type || 0 > time_shift)
2617 {
2618 *error = zbx_strdup(*error, "invalid second parameter");
2619 goto out;
2620 }
2621
2622 if (SUCCEED != get_function_parameter_float( parameters, 3, ZBX_FLAG_DOUBLE_SUFFIX, &threshold))
2623 {
2624 *error = zbx_strdup(*error, "invalid third parameter");
2625 goto out;
2626 }
2627
2628 if (4 == nparams)
2629 {
2630 if (SUCCEED != get_function_parameter_str(parameters, 4, &fit_str) ||
2631 SUCCEED != zbx_fit_code(fit_str, &fit, &k, error))
2632 {
2633 *error = zbx_strdup(*error, "invalid fourth parameter");
2634 goto out;
2635 }
2636 }
2637 else
2638 {
2639 fit = FIT_LINEAR;
2640 }
2641
2642 if ((FIT_EXPONENTIAL == fit || FIT_POWER == fit) && 0.0 >= threshold)
2643 {
2644 *error = zbx_strdup(*error, "exponential and power functions are always positive");
2645 goto out;
2646 }
2647
2648 switch (arg1_type)
2649 {
2650 case ZBX_VALUE_SECONDS:
2651 seconds = arg1;
2652 break;
2653 case ZBX_VALUE_NVALUES:
2654 nvalues = arg1;
2655 break;
2656 default:
2657 THIS_SHOULD_NEVER_HAPPEN;
2658 }
2659
2660 ts_end.sec -= time_shift;
2661
2662 if (FAIL == zbx_vc_get_values(item->itemid, item->value_type, &values, seconds, nvalues, &ts_end))
2663 {
2664 *error = zbx_strdup(*error, "cannot get values from value cache");
2665 goto out;
2666 }
2667
2668 if (0 < values.values_num)
2669 {
2670 t = (double *)zbx_malloc(t, values.values_num * sizeof(double));
2671 x = (double *)zbx_malloc(x, values.values_num * sizeof(double));
2672
2673 zero_time.sec = values.values[values.values_num - 1].timestamp.sec;
2674 zero_time.ns = values.values[values.values_num - 1].timestamp.ns;
2675
2676 if (ITEM_VALUE_TYPE_FLOAT == item->value_type)
2677 {
2678 for (i = 0; i < values.values_num; i++)
2679 {
2680 t[i] = values.values[i].timestamp.sec - zero_time.sec + 1.0e-9 *
2681 (values.values[i].timestamp.ns - zero_time.ns + 1);
2682 x[i] = values.values[i].value.dbl;
2683 }
2684 }
2685 else
2686 {
2687 for (i = 0; i < values.values_num; i++)
2688 {
2689 t[i] = values.values[i].timestamp.sec - zero_time.sec + 1.0e-9 *
2690 (values.values[i].timestamp.ns - zero_time.ns + 1);
2691 x[i] = values.values[i].value.ui64;
2692 }
2693 }
2694
2695 zbx_snprintf_alloc(value, &value_alloc, &value_offset, ZBX_FS_DBL64, zbx_timeleft(t, x,
2696 values.values_num, ts->sec - zero_time.sec - 1.0e-9 * (zero_time.ns + 1), threshold,
2697 fit, k));
2698 }
2699 else
2700 {
2701 zabbix_log(LOG_LEVEL_DEBUG, "no data available");
2702 zbx_snprintf_alloc(value, &value_alloc, &value_offset, ZBX_FS_DBL64, ZBX_MATH_ERROR);
2703 }
2704
2705 ret = SUCCEED;
2706 out:
2707 zbx_history_record_vector_destroy(&values, item->value_type);
2708
2709 zbx_free(fit_str);
2710
2711 zbx_free(t);
2712 zbx_free(x);
2713
2714 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
2715
2716 return ret;
2717 }
2718
2719 /******************************************************************************
2720 * *
2721 * Function: trends_parse_range *
2722 * *
2723 * Purpose: parse trend function period arguments into time range using old *
2724 * parameter format *
2725 * *
2726 * Parameters: from - [IN] the time the period shift is calculated *
2727 * from *
2728 * period - [IN] the history period *
2729 * period_shift - [IN] the history period shift *
2730 * start - [OUT] the period start time in seconds since *
2731 * Epoch *
2732 * end - [OUT] the period end time in seconds since *
2733 * Epoch *
2734 * error - [OUT] the error message if parsing failed *
2735 * *
2736 * Return value: SUCCEED - period was parsed successfully *
2737 * FAIL - invalid time period was specified *
2738 * *
2739 * Comments: Daylight saving changes are applied when parsing ranges with *
2740 * day+ used as period base (now/?). *
2741 * *
2742 * Example period_shift values: *
2743 * now/d *
2744 * now/d-1h *
2745 * now/d+1h *
2746 * now/d+1h/w *
2747 * now/d/w/h+1h+2h *
2748 * now-1d/h *
2749 * *
2750 * Comments: This is temporary solution to keep calculated checks working *
2751 * until they are updated. *
2752 * *
2753 ******************************************************************************/
trends_parse_range(time_t from,const char * period,const char * period_shift,int * start,int * end,char ** error)2754 static int trends_parse_range(time_t from, const char *period, const char *period_shift, int *start, int *end,
2755 char **error)
2756 {
2757 int period_num, period_hours[ZBX_TIME_UNIT_COUNT] = {0, 1, 24, 24 * 7, 24 * 30, 24 * 365};
2758 zbx_time_unit_t period_unit;
2759 size_t len;
2760 struct tm tm_end, tm_start;
2761 const char *p;
2762
2763 zabbix_log(LOG_LEVEL_DEBUG, "In %s() period:%s shift:%s", __func__, period, period_shift);
2764
2765 /* parse period */
2766
2767 if (SUCCEED != zbx_tm_parse_period(period, &len, &period_num, &period_unit, error))
2768 return FAIL;
2769
2770 if ('\0' != period[len])
2771 {
2772 *error = zbx_dsprintf(*error, "unexpected character[s] in period \"%s\"", period + len);
2773 return FAIL;
2774 }
2775
2776 if (period_hours[period_unit] * period_num > 24 * 366)
2777 {
2778 *error = zbx_strdup(*error, "period is too large");
2779 return FAIL;
2780 }
2781
2782 /* parse period shift */
2783
2784 p = period_shift;
2785
2786 if (0 != strncmp(p, "now", ZBX_CONST_STRLEN("now")))
2787 {
2788 *error = zbx_strdup(*error, "period shift must begin with \"now\"");
2789 return FAIL;
2790 }
2791
2792 p += ZBX_CONST_STRLEN("now");
2793
2794 localtime_r(&from, &tm_end);
2795
2796 while ('\0' != *p)
2797 {
2798 zbx_time_unit_t unit;
2799
2800 if ('/' == *p)
2801 {
2802 if (ZBX_TIME_UNIT_UNKNOWN == (unit = zbx_tm_str_to_unit(++p)))
2803 {
2804 *error = zbx_dsprintf(*error, "unexpected character starting with \"%s\"", p);
2805 return FAIL;
2806 }
2807
2808 if (unit < period_unit)
2809 {
2810 *error = zbx_dsprintf(*error, "time units in period shift must be greater or equal"
2811 " to period time unit");
2812 return FAIL;
2813 }
2814
2815 zbx_tm_round_down(&tm_end, unit);
2816
2817 /* unit is single character */
2818 p++;
2819 }
2820 else if ('+' == *p || '-' == *p)
2821 {
2822 int num;
2823 char op = *(p++);
2824
2825 if (FAIL == zbx_tm_parse_period(p, &len, &num, &unit, error))
2826 return FAIL;
2827
2828 if (unit < period_unit)
2829 {
2830 *error = zbx_dsprintf(*error, "time units in period shift must be greater or equal"
2831 " to period time unit");
2832 return FAIL;
2833 }
2834
2835 if ('+' == op)
2836 zbx_tm_add(&tm_end, num, unit);
2837 else
2838 zbx_tm_sub(&tm_end, num, unit);
2839
2840 p += len;
2841 }
2842 else
2843 {
2844 *error = zbx_dsprintf(*error, "unexpected character starting with \"%s\"", p);
2845 return FAIL;
2846 }
2847 }
2848
2849 tm_start = tm_end;
2850
2851 /* trends clock refers to the beginning of the hourly interval - subtract */
2852 /* one hour to get the trends clock for the last hourly interval */
2853 zbx_tm_sub(&tm_end, 1, ZBX_TIME_UNIT_HOUR);
2854
2855 if (-1 == (*end = mktime(&tm_end)))
2856 {
2857 *error = zbx_dsprintf(*error, "cannot calculate the period end time: %s", zbx_strerror(errno));
2858 return FAIL;
2859 }
2860
2861 if (abs((int)from - *end) > SEC_PER_YEAR * 26)
2862 {
2863 *error = zbx_strdup(*error, "period shift is too large");
2864 return FAIL;
2865 }
2866
2867 zbx_tm_sub(&tm_start, period_num, period_unit);
2868 if (-1 == (*start = mktime(&tm_start)))
2869 {
2870 *error = zbx_dsprintf(*error, "cannot calculate the period start time: %s", zbx_strerror(errno));
2871 return FAIL;
2872 }
2873
2874 zabbix_log(LOG_LEVEL_DEBUG, "End of %s() start:%d end:%d", __func__, *start, *end);
2875
2876 return SUCCEED;
2877 }
2878
2879
2880 /******************************************************************************
2881 * *
2882 * Function: evaluate_TREND *
2883 * *
2884 * Purpose: evaluate trend* functions for the item *
2885 * *
2886 * Parameters: value - [OUT] the function result *
2887 * item - [IN] item (performance metric) *
2888 * func - [IN] the trend function to evaluate *
2889 * (avg, sum, count, delta, max, min) *
2890 * parameters - [IN] function parameters *
2891 * ts - [IN] the historical time when function must be *
2892 * evaluated *
2893 * *
2894 * Return value: SUCCEED - evaluated successfully, result is stored in 'value'*
2895 * FAIL - failed to evaluate function *
2896 * *
2897 ******************************************************************************/
evaluate_TREND(char ** value,DC_ITEM * item,const char * func,const char * parameters,const zbx_timespec_t * ts,char ** error)2898 static int evaluate_TREND(char **value, DC_ITEM *item, const char *func, const char *parameters,
2899 const zbx_timespec_t *ts, char **error)
2900 {
2901 int ret = FAIL, start, end;
2902 char *period = NULL, *period_shift = NULL;
2903 const char *table;
2904 double value_dbl;
2905
2906 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
2907
2908 if (SUCCEED != get_function_parameter_str(parameters, 1, &period))
2909 {
2910 *error = zbx_strdup(*error, "invalid first parameter");
2911 goto out;
2912 }
2913
2914 if (SUCCEED != get_function_parameter_str(parameters, 2, &period_shift))
2915 {
2916 *error = zbx_strdup(*error, "invalid second parameter");
2917 goto out;
2918 }
2919
2920 if (SUCCEED != trends_parse_range(ts->sec, period, period_shift, &start, &end, error))
2921 goto out;
2922
2923 switch (item->value_type)
2924 {
2925 case ITEM_VALUE_TYPE_FLOAT:
2926 table = "trends";
2927 break;
2928 case ITEM_VALUE_TYPE_UINT64:
2929 table = "trends_uint";
2930 break;
2931 default:
2932 *error = zbx_strdup(*error, "unsupported value type");
2933 goto out;
2934 }
2935
2936 if (0 == strcmp(func, "avg"))
2937 {
2938 ret = zbx_trends_eval_avg(table, item->itemid, start, end, &value_dbl, error);
2939 }
2940 else if (0 == strcmp(func, "count"))
2941 {
2942 ret = zbx_trends_eval_count(table, item->itemid, start, end, &value_dbl, error);
2943 }
2944 else if (0 == strcmp(func, "delta"))
2945 {
2946 ret = zbx_trends_eval_delta(table, item->itemid, start, end, &value_dbl, error);
2947 }
2948 else if (0 == strcmp(func, "max"))
2949 {
2950 ret = zbx_trends_eval_max(table, item->itemid, start, end, &value_dbl, error);
2951 }
2952 else if (0 == strcmp(func, "min"))
2953 {
2954 ret = zbx_trends_eval_min(table, item->itemid, start, end, &value_dbl, error);
2955 }
2956 else if (0 == strcmp(func, "sum"))
2957 {
2958 ret = zbx_trends_eval_sum(table, item->itemid, start, end, &value_dbl, error);
2959 }
2960 else
2961 {
2962 *error = zbx_strdup(*error, "unknown trend function");
2963 goto out;
2964 }
2965
2966 if (SUCCEED == ret)
2967 *value = zbx_dsprintf(*value, ZBX_FS_DBL64, value_dbl);
2968 out:
2969 zbx_free(period);
2970 zbx_free(period_shift);
2971
2972 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
2973
2974 return ret;
2975 }
2976
2977 /******************************************************************************
2978 * *
2979 * Function: evaluate_function *
2980 * *
2981 * Purpose: evaluate function *
2982 * *
2983 * Parameters: item - item to calculate function for *
2984 * function - function (for example, 'max') *
2985 * parameter - parameter of the function *
2986 * *
2987 * Return value: SUCCEED - evaluated successfully, value contains its value *
2988 * FAIL - evaluation failed *
2989 * *
2990 ******************************************************************************/
evaluate_function(char ** value,DC_ITEM * item,const char * function,const char * parameter,const zbx_timespec_t * ts,char ** error)2991 int evaluate_function(char **value, DC_ITEM *item, const char *function, const char *parameter,
2992 const zbx_timespec_t *ts, char **error)
2993 {
2994 int ret;
2995 struct tm *tm = NULL;
2996
2997 zabbix_log(LOG_LEVEL_DEBUG, "In %s() function:'%s:%s.%s(%s)' ts:'%s\'", __func__,
2998 item->host.host, item->key_orig, function, parameter, zbx_timespec_str(ts));
2999
3000 if (0 == strcmp(function, "last"))
3001 {
3002 ret = evaluate_LAST(value, item, parameter, ts, error);
3003 }
3004 else if (0 == strcmp(function, "prev"))
3005 {
3006 ret = evaluate_LAST(value, item, "#2", ts, error);
3007 }
3008 else if (0 == strcmp(function, "min"))
3009 {
3010 ret = evaluate_MIN(value, item, parameter, ts, error);
3011 }
3012 else if (0 == strcmp(function, "max"))
3013 {
3014 ret = evaluate_MAX(value, item, parameter, ts, error);
3015 }
3016 else if (0 == strcmp(function, "avg"))
3017 {
3018 ret = evaluate_AVG(value, item, parameter, ts, error);
3019 }
3020 else if (0 == strcmp(function, "sum"))
3021 {
3022 ret = evaluate_SUM(value, item, parameter, ts, error);
3023 }
3024 else if (0 == strcmp(function, "percentile"))
3025 {
3026 ret = evaluate_PERCENTILE(value, item, parameter, ts, error);
3027 }
3028 else if (0 == strcmp(function, "count"))
3029 {
3030 ret = evaluate_COUNT(value, item, parameter, ts, error);
3031 }
3032 else if (0 == strcmp(function, "delta"))
3033 {
3034 ret = evaluate_DELTA(value, item, parameter, ts, error);
3035 }
3036 else if (0 == strcmp(function, "nodata"))
3037 {
3038 ret = evaluate_NODATA(value, item, parameter, error);
3039 }
3040 else if (0 == strcmp(function, "date"))
3041 {
3042 size_t value_alloc = 0, value_offset = 0;
3043 time_t now = ts->sec;
3044
3045 tm = localtime(&now);
3046 zbx_snprintf_alloc(value, &value_alloc, &value_offset, "%.4d%.2d%.2d",
3047 tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday);
3048 ret = SUCCEED;
3049 }
3050 else if (0 == strcmp(function, "dayofweek"))
3051 {
3052 size_t value_alloc = 0, value_offset = 0;
3053 time_t now = ts->sec;
3054
3055 tm = localtime(&now);
3056 zbx_snprintf_alloc(value, &value_alloc, &value_offset, "%d", 0 == tm->tm_wday ? 7 : tm->tm_wday);
3057 ret = SUCCEED;
3058 }
3059 else if (0 == strcmp(function, "dayofmonth"))
3060 {
3061 size_t value_alloc = 0, value_offset = 0;
3062 time_t now = ts->sec;
3063
3064 tm = localtime(&now);
3065 zbx_snprintf_alloc(value, &value_alloc, &value_offset, "%d", tm->tm_mday);
3066 ret = SUCCEED;
3067 }
3068 else if (0 == strcmp(function, "time"))
3069 {
3070 size_t value_alloc = 0, value_offset = 0;
3071 time_t now = ts->sec;
3072
3073 tm = localtime(&now);
3074 zbx_snprintf_alloc(value, &value_alloc, &value_offset, "%.2d%.2d%.2d", tm->tm_hour, tm->tm_min,
3075 tm->tm_sec);
3076 ret = SUCCEED;
3077 }
3078 else if (0 == strcmp(function, "abschange"))
3079 {
3080 ret = evaluate_ABSCHANGE(value, item, ts, error);
3081 }
3082 else if (0 == strcmp(function, "change"))
3083 {
3084 ret = evaluate_CHANGE(value, item, ts, error);
3085 }
3086 else if (0 == strcmp(function, "diff"))
3087 {
3088 ret = evaluate_DIFF(value, item, ts, error);
3089 }
3090 else if (0 == strcmp(function, "str") || 0 == strcmp(function, "regexp") || 0 == strcmp(function, "iregexp"))
3091 {
3092 ret = evaluate_STR(value, item, function, parameter, ts, error);
3093 }
3094 else if (0 == strcmp(function, "strlen"))
3095 {
3096 ret = evaluate_STRLEN(value, item, parameter, ts, error);
3097 }
3098 else if (0 == strcmp(function, "now"))
3099 {
3100 size_t value_alloc = 0, value_offset = 0;
3101
3102 zbx_snprintf_alloc(value, &value_alloc, &value_offset, "%d", ts->sec);
3103 ret = SUCCEED;
3104 }
3105 else if (0 == strcmp(function, "fuzzytime"))
3106 {
3107 ret = evaluate_FUZZYTIME(value, item, parameter, ts, error);
3108 }
3109 else if (0 == strcmp(function, "logeventid"))
3110 {
3111 ret = evaluate_LOGEVENTID(value, item, parameter, ts, error);
3112 }
3113 else if (0 == strcmp(function, "logseverity"))
3114 {
3115 ret = evaluate_LOGSEVERITY(value, item, ts, error);
3116 }
3117 else if (0 == strcmp(function, "logsource"))
3118 {
3119 ret = evaluate_LOGSOURCE(value, item, parameter, ts, error);
3120 }
3121 else if (0 == strcmp(function, "band"))
3122 {
3123 ret = evaluate_BAND(value, item, parameter, ts, error);
3124 }
3125 else if (0 == strcmp(function, "forecast"))
3126 {
3127 ret = evaluate_FORECAST(value, item, parameter, ts, error);
3128 }
3129 else if (0 == strcmp(function, "timeleft"))
3130 {
3131 ret = evaluate_TIMELEFT(value, item, parameter, ts, error);
3132 }
3133 else if (0 == strncmp(function, "trend", 5))
3134 {
3135 ret = evaluate_TREND(value, item, function + 5, parameter, ts, error);
3136 }
3137 else
3138 {
3139 *value = zbx_malloc(*value, 1);
3140 (*value)[0] = '\0';
3141 *error = zbx_strdup(*error, "function is not supported");
3142 ret = FAIL;
3143 }
3144
3145 if (SUCCEED == ret)
3146 del_zeros(*value);
3147
3148 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s value:'%s'", __func__, zbx_result_string(ret), ZBX_NULL2STR(*value));
3149
3150 return ret;
3151 }
3152
3153 /******************************************************************************
3154 * *
3155 * Function: add_value_suffix_uptime *
3156 * *
3157 * Purpose: Process suffix 'uptime' *
3158 * *
3159 * Parameters: value - value for adjusting *
3160 * max_len - max len of the value *
3161 * *
3162 ******************************************************************************/
add_value_suffix_uptime(char * value,size_t max_len)3163 static void add_value_suffix_uptime(char *value, size_t max_len)
3164 {
3165 double secs, days;
3166 size_t offset = 0;
3167 int hours, mins;
3168
3169 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
3170
3171 if (0 > (secs = round(atof(value))))
3172 {
3173 offset += zbx_snprintf(value, max_len, "-");
3174 secs = -secs;
3175 }
3176
3177 days = floor(secs / SEC_PER_DAY);
3178 secs -= days * SEC_PER_DAY;
3179
3180 hours = (int)(secs / SEC_PER_HOUR);
3181 secs -= (double)hours * SEC_PER_HOUR;
3182
3183 mins = (int)(secs / SEC_PER_MIN);
3184 secs -= (double)mins * SEC_PER_MIN;
3185
3186 if (0 != days)
3187 {
3188 if (1 == days)
3189 offset += zbx_snprintf(value + offset, max_len - offset, ZBX_FS_DBL_EXT(0) " day, ", days);
3190 else
3191 offset += zbx_snprintf(value + offset, max_len - offset, ZBX_FS_DBL_EXT(0) " days, ", days);
3192 }
3193
3194 zbx_snprintf(value + offset, max_len - offset, "%02d:%02d:%02d", hours, mins, (int)secs);
3195
3196 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
3197 }
3198
3199 /******************************************************************************
3200 * *
3201 * Function: add_value_suffix_s *
3202 * *
3203 * Purpose: Process suffix 's' *
3204 * *
3205 * Parameters: value - value for adjusting *
3206 * max_len - max len of the value *
3207 * *
3208 ******************************************************************************/
add_value_suffix_s(char * value,size_t max_len)3209 static void add_value_suffix_s(char *value, size_t max_len)
3210 {
3211 double secs, n;
3212 size_t offset = 0;
3213 int n_unit = 0;
3214
3215 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
3216
3217 secs = atof(value);
3218
3219 if (0 == floor(fabs(secs) * 1000))
3220 {
3221 zbx_snprintf(value, max_len, "%s", (0 == secs ? "0s" : "< 1ms"));
3222 goto clean;
3223 }
3224
3225 if (0 > (secs = round(secs * 1000) / 1000))
3226 {
3227 offset += zbx_snprintf(value, max_len, "-");
3228 secs = -secs;
3229 }
3230 else
3231 *value = '\0';
3232
3233 if (0 != (n = floor(secs / SEC_PER_YEAR)))
3234 {
3235 offset += zbx_snprintf(value + offset, max_len - offset, ZBX_FS_DBL_EXT(0) "y ", n);
3236 secs -= n * SEC_PER_YEAR;
3237 if (0 == n_unit)
3238 n_unit = 4;
3239 }
3240
3241 if (0 != (n = floor(secs / SEC_PER_MONTH)))
3242 {
3243 offset += zbx_snprintf(value + offset, max_len - offset, "%dm ", (int)n);
3244 secs -= n * SEC_PER_MONTH;
3245 if (0 == n_unit)
3246 n_unit = 3;
3247 }
3248
3249 if (0 != (n = floor(secs / SEC_PER_DAY)))
3250 {
3251 offset += zbx_snprintf(value + offset, max_len - offset, "%dd ", (int)n);
3252 secs -= n * SEC_PER_DAY;
3253 if (0 == n_unit)
3254 n_unit = 2;
3255 }
3256
3257 if (4 > n_unit && 0 != (n = floor(secs / SEC_PER_HOUR)))
3258 {
3259 offset += zbx_snprintf(value + offset, max_len - offset, "%dh ", (int)n);
3260 secs -= n * SEC_PER_HOUR;
3261 if (0 == n_unit)
3262 n_unit = 1;
3263 }
3264
3265 if (3 > n_unit && 0 != (n = floor(secs / SEC_PER_MIN)))
3266 {
3267 offset += zbx_snprintf(value + offset, max_len - offset, "%dm ", (int)n);
3268 secs -= n * SEC_PER_MIN;
3269 }
3270
3271 if (2 > n_unit && 0 != (n = floor(secs)))
3272 {
3273 offset += zbx_snprintf(value + offset, max_len - offset, "%ds ", (int)n);
3274 secs -= n;
3275 }
3276
3277 if (1 > n_unit && 0 != (n = round(secs * 1000)))
3278 offset += zbx_snprintf(value + offset, max_len - offset, "%dms", (int)n);
3279
3280 if (0 != offset && ' ' == value[--offset])
3281 value[offset] = '\0';
3282 clean:
3283 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
3284 }
3285
3286 /******************************************************************************
3287 * *
3288 * Function: is_blacklisted_unit *
3289 * *
3290 * Purpose: check if unit is blacklisted or not *
3291 * *
3292 * Parameters: unit - unit to check *
3293 * *
3294 * Return value: SUCCEED - unit blacklisted *
3295 * FAIL - unit is not blacklisted *
3296 * *
3297 ******************************************************************************/
is_blacklisted_unit(const char * unit)3298 static int is_blacklisted_unit(const char *unit)
3299 {
3300 int ret;
3301
3302 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
3303
3304 ret = str_in_list("%,ms,rpm,RPM", unit, ',');
3305
3306 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
3307
3308 return ret;
3309 }
3310
3311 /******************************************************************************
3312 * *
3313 * Function: add_value_units_no_kmgt *
3314 * *
3315 * Purpose: add only units to the value *
3316 * *
3317 * Parameters: value - value for adjusting *
3318 * max_len - max len of the value *
3319 * units - units (bps, b, B, etc) *
3320 * *
3321 ******************************************************************************/
add_value_units_no_kmgt(char * value,size_t max_len,const char * units)3322 static void add_value_units_no_kmgt(char *value, size_t max_len, const char *units)
3323 {
3324 const char *minus = "";
3325 char tmp[64];
3326 double value_double;
3327
3328 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
3329
3330 if (0 > (value_double = atof(value)))
3331 {
3332 minus = "-";
3333 value_double = -value_double;
3334 }
3335
3336 if (SUCCEED != zbx_double_compare(round(value_double), value_double))
3337 {
3338 zbx_snprintf(tmp, sizeof(tmp), ZBX_FS_DBL_EXT(2), value_double);
3339 del_zeros(tmp);
3340 }
3341 else
3342 zbx_snprintf(tmp, sizeof(tmp), ZBX_FS_DBL_EXT(0), value_double);
3343
3344 zbx_snprintf(value, max_len, "%s%s %s", minus, tmp, units);
3345
3346 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
3347 }
3348
3349 /******************************************************************************
3350 * *
3351 * Function: add_value_units_with_kmgt *
3352 * *
3353 * Purpose: add units with K,M,G,T prefix to the value *
3354 * *
3355 * Parameters: value - value for adjusting *
3356 * max_len - max len of the value *
3357 * units - units (bps, b, B, etc) *
3358 * *
3359 ******************************************************************************/
add_value_units_with_kmgt(char * value,size_t max_len,const char * units)3360 static void add_value_units_with_kmgt(char *value, size_t max_len, const char *units)
3361 {
3362 const char *minus = "";
3363 char kmgt[8];
3364 char tmp[64];
3365 double base;
3366 double value_double;
3367
3368 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
3369
3370 if (0 > (value_double = atof(value)))
3371 {
3372 minus = "-";
3373 value_double = -value_double;
3374 }
3375
3376 base = (0 == strcmp(units, "B") || 0 == strcmp(units, "Bps") ? 1024 : 1000);
3377
3378 if (value_double < base)
3379 {
3380 strscpy(kmgt, "");
3381 }
3382 else if (value_double < base * base)
3383 {
3384 strscpy(kmgt, "K");
3385 value_double /= base;
3386 }
3387 else if (value_double < base * base * base)
3388 {
3389 strscpy(kmgt, "M");
3390 value_double /= base * base;
3391 }
3392 else if (value_double < base * base * base * base)
3393 {
3394 strscpy(kmgt, "G");
3395 value_double /= base * base * base;
3396 }
3397 else
3398 {
3399 strscpy(kmgt, "T");
3400 value_double /= base * base * base * base;
3401 }
3402
3403 if (SUCCEED != zbx_double_compare(round(value_double), value_double))
3404 {
3405 zbx_snprintf(tmp, sizeof(tmp), ZBX_FS_DBL_EXT(2), value_double);
3406 del_zeros(tmp);
3407 }
3408 else
3409 zbx_snprintf(tmp, sizeof(tmp), ZBX_FS_DBL_EXT(0), value_double);
3410
3411 zbx_snprintf(value, max_len, "%s%s %s%s", minus, tmp, kmgt, units);
3412
3413 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
3414 }
3415
3416 /******************************************************************************
3417 * *
3418 * Function: add_value_suffix *
3419 * *
3420 * Purpose: Add suffix for value *
3421 * *
3422 * Parameters: value - value for replacing *
3423 * *
3424 * Return value: SUCCEED - suffix added successfully, value contains new value*
3425 * FAIL - adding failed, value contains old value *
3426 * *
3427 ******************************************************************************/
add_value_suffix(char * value,size_t max_len,const char * units,unsigned char value_type)3428 static void add_value_suffix(char *value, size_t max_len, const char *units, unsigned char value_type)
3429 {
3430 struct tm *local_time;
3431 time_t time;
3432
3433 zabbix_log(LOG_LEVEL_DEBUG, "In %s() value:'%s' units:'%s' value_type:%d",
3434 __func__, value, units, (int)value_type);
3435
3436 switch (value_type)
3437 {
3438 case ITEM_VALUE_TYPE_UINT64:
3439 if (0 == strcmp(units, "unixtime"))
3440 {
3441 time = (time_t)atoi(value);
3442 local_time = localtime(&time);
3443 strftime(value, max_len, "%Y.%m.%d %H:%M:%S", local_time);
3444 break;
3445 }
3446 ZBX_FALLTHROUGH;
3447 case ITEM_VALUE_TYPE_FLOAT:
3448 if (0 == strcmp(units, "s"))
3449 add_value_suffix_s(value, max_len);
3450 else if (0 == strcmp(units, "uptime"))
3451 add_value_suffix_uptime(value, max_len);
3452 else if ('!' == *units)
3453 add_value_units_no_kmgt(value, max_len, (const char *)(units + 1));
3454 else if (SUCCEED == is_blacklisted_unit(units))
3455 add_value_units_no_kmgt(value, max_len, units);
3456 else if ('\0' != *units)
3457 add_value_units_with_kmgt(value, max_len, units);
3458 break;
3459 default:
3460 ;
3461 }
3462
3463 zabbix_log(LOG_LEVEL_DEBUG, "End of %s() value:'%s'", __func__, value);
3464 }
3465
zbx_valuemaps_free(zbx_valuemaps_t * valuemap)3466 static void zbx_valuemaps_free(zbx_valuemaps_t *valuemap)
3467 {
3468 zbx_free(valuemap);
3469 }
3470
3471 /******************************************************************************
3472 * *
3473 * Function: evaluate_value_by_map *
3474 * *
3475 * Purpose: replace value by mapping value *
3476 * *
3477 * Parameters: value - value for replacing *
3478 * max_len - maximal length of output value *
3479 * valuemaps - vector of values mapped *
3480 * value_type - type of input value *
3481 * *
3482 * Return value: SUCCEED - evaluated successfully, value contains new value *
3483 * FAIL - evaluation failed, value contains old value *
3484 * *
3485 ******************************************************************************/
evaluate_value_by_map(char * value,size_t max_len,zbx_vector_valuemaps_ptr_t * valuemaps,unsigned char value_type)3486 static int evaluate_value_by_map(char *value, size_t max_len, zbx_vector_valuemaps_ptr_t *valuemaps,
3487 unsigned char value_type)
3488 {
3489 char *value_tmp;
3490 int i, ret = FAIL;
3491 double input_value;
3492 zbx_valuemaps_t *valuemap;
3493
3494 for (i = 0; i < valuemaps->values_num; i++)
3495 {
3496 char *pattern;
3497 int match;
3498 zbx_vector_ptr_t regexps;
3499
3500 valuemap = (zbx_valuemaps_t *)valuemaps->values[i];
3501
3502 if (ZBX_VALUEMAP_TYPE_MATCH == valuemap->type)
3503 {
3504 if (ITEM_VALUE_TYPE_STR != value_type)
3505 {
3506 double num1, num2;
3507
3508 if (ZBX_INFINITY != (num1 = evaluate_string_to_double(value)) &&
3509 ZBX_INFINITY != (num2 = evaluate_string_to_double(valuemap->value)) &&
3510 SUCCEED == zbx_double_compare(num1, num2))
3511 {
3512 goto map_value;
3513 }
3514 }
3515 else if (0 == strcmp(valuemap->value, value))
3516 goto map_value;
3517 }
3518
3519 if (ITEM_VALUE_TYPE_STR == value_type && ZBX_VALUEMAP_TYPE_REGEX == valuemap->type)
3520 {
3521 zbx_vector_ptr_create(®exps);
3522
3523 pattern = valuemap->value;
3524
3525 match = regexp_match_ex(®exps, value, pattern, ZBX_CASE_SENSITIVE);
3526
3527 zbx_regexp_clean_expressions(®exps);
3528 zbx_vector_ptr_destroy(®exps);
3529
3530 if (ZBX_REGEXP_MATCH == match)
3531 goto map_value;
3532 }
3533
3534 if (ITEM_VALUE_TYPE_STR != value_type &&
3535 ZBX_INFINITY != (input_value = evaluate_string_to_double(value)))
3536 {
3537 double min, max;
3538
3539 if (ZBX_VALUEMAP_TYPE_LESS_OR_EQUAL == valuemap->type &&
3540 ZBX_INFINITY != (max = evaluate_string_to_double(valuemap->value)))
3541 {
3542 if (input_value <= max)
3543 goto map_value;
3544 }
3545 else if (ZBX_VALUEMAP_TYPE_GREATER_OR_EQUAL == valuemap->type &&
3546 ZBX_INFINITY != (min = evaluate_string_to_double(valuemap->value)))
3547 {
3548 if (input_value >= min)
3549 goto map_value;
3550 }
3551 else if (ZBX_VALUEMAP_TYPE_RANGE == valuemap->type)
3552 {
3553 int num, j;
3554 char *input_ptr;
3555
3556 input_ptr = valuemap->value;
3557
3558 zbx_trim_str_list(input_ptr, ',');
3559 zbx_trim_str_list(input_ptr, '-');
3560 num = num_param(input_ptr);
3561
3562 for (j = 0; j < num; j++)
3563 {
3564 int found = 0;
3565 char *ptr, *range_str;
3566
3567 range_str = ptr = get_param_dyn(input_ptr, j + 1, NULL);
3568
3569 if (1 < strlen(ptr) && '-' == *ptr)
3570 ptr++;
3571
3572 while (NULL != (ptr = strchr(ptr, '-')))
3573 {
3574 if (ptr > range_str && 'e' != ptr[-1] && 'E' != ptr[-1])
3575 break;
3576 ptr++;
3577 }
3578
3579 if (NULL == ptr)
3580 {
3581 min = evaluate_string_to_double(range_str);
3582 found = ZBX_INFINITY != min && SUCCEED == zbx_double_compare(input_value, min);
3583 }
3584 else
3585 {
3586 *ptr = '\0';
3587 min = evaluate_string_to_double(range_str);
3588 max = evaluate_string_to_double(ptr + 1);
3589 if (ZBX_INFINITY != min && ZBX_INFINITY != max &&
3590 input_value >= min && input_value <= max)
3591 {
3592 found = 1;
3593 }
3594 }
3595
3596 zbx_free(range_str);
3597
3598 if (0 != found)
3599 goto map_value;
3600 }
3601 }
3602 }
3603 }
3604
3605 for (i = 0; i < valuemaps->values_num; i++)
3606 {
3607 valuemap = (zbx_valuemaps_t *)valuemaps->values[i];
3608
3609 if (ZBX_VALUEMAP_TYPE_DEFAULT == valuemap->type)
3610 goto map_value;
3611 }
3612 map_value:
3613 if (i < valuemaps->values_num)
3614 {
3615 value_tmp = zbx_dsprintf(NULL, "%s (%s)", valuemap->newvalue, value);
3616 zbx_strlcpy_utf8(value, value_tmp, max_len);
3617 zbx_free(value_tmp);
3618
3619 ret = SUCCEED;
3620 }
3621
3622 return ret;
3623 }
3624
3625 /******************************************************************************
3626 * *
3627 * Function: replace_value_by_map *
3628 * *
3629 * Purpose: replace value by mapping value *
3630 * *
3631 * Parameters: value - value for replacing *
3632 * max_len - maximal length of output value *
3633 * valuemapid - index of value map *
3634 * value_type - type of input value *
3635 * *
3636 * Return value: SUCCEED - evaluated successfully, value contains new value *
3637 * FAIL - evaluation failed, value contains old value *
3638 * *
3639 ******************************************************************************/
replace_value_by_map(char * value,size_t max_len,zbx_uint64_t valuemapid,unsigned char value_type)3640 static int replace_value_by_map(char *value, size_t max_len, zbx_uint64_t valuemapid, unsigned char value_type)
3641 {
3642 int ret = FAIL;
3643 DB_RESULT result;
3644 DB_ROW row;
3645 zbx_valuemaps_t *valuemap;
3646 zbx_vector_valuemaps_ptr_t valuemaps;
3647
3648 zabbix_log(LOG_LEVEL_DEBUG, "In %s() value:'%s' valuemapid:" ZBX_FS_UI64, __func__, value, valuemapid);
3649
3650 if (0 == valuemapid)
3651 goto clean;
3652
3653 zbx_vector_valuemaps_ptr_create(&valuemaps);
3654
3655 result = DBselect(
3656 "select value,newvalue,type"
3657 " from valuemap_mapping"
3658 " where valuemapid=" ZBX_FS_UI64
3659 " order by sortorder asc",
3660 valuemapid);
3661
3662 while (NULL != (row = DBfetch(result)))
3663 {
3664 del_zeros(row[1]);
3665
3666 valuemap = (zbx_valuemaps_t *)zbx_malloc(NULL, sizeof(zbx_valuemaps_t));
3667 zbx_strlcpy_utf8(valuemap->value, row[0], ZBX_VALUEMAP_STRING_LEN);
3668 zbx_strlcpy_utf8(valuemap->newvalue, row[1], ZBX_VALUEMAP_STRING_LEN);
3669 valuemap->type = atoi(row[2]);
3670 zbx_vector_valuemaps_ptr_append(&valuemaps, valuemap);
3671 }
3672
3673 DBfree_result(result);
3674
3675 ret = evaluate_value_by_map(value, max_len, &valuemaps, value_type);
3676
3677 zbx_vector_valuemaps_ptr_clear_ext(&valuemaps, zbx_valuemaps_free);
3678 zbx_vector_valuemaps_ptr_destroy(&valuemaps);
3679 clean:
3680 zabbix_log(LOG_LEVEL_DEBUG, "End of %s() value:'%s'", __func__, value);
3681
3682 return ret;
3683 }
3684
3685 /******************************************************************************
3686 * *
3687 * Function: zbx_format_value *
3688 * *
3689 * Purpose: replace value by value mapping or by units *
3690 * *
3691 * Parameters: value - [IN/OUT] value for replacing *
3692 * valuemapid - [IN] identificator of value map *
3693 * units - [IN] units *
3694 * value_type - [IN] value type; ITEM_VALUE_TYPE_* *
3695 * *
3696 ******************************************************************************/
zbx_format_value(char * value,size_t max_len,zbx_uint64_t valuemapid,const char * units,unsigned char value_type)3697 void zbx_format_value(char *value, size_t max_len, zbx_uint64_t valuemapid,
3698 const char *units, unsigned char value_type)
3699 {
3700 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
3701
3702 switch (value_type)
3703 {
3704 case ITEM_VALUE_TYPE_STR:
3705 replace_value_by_map(value, max_len, valuemapid, value_type);
3706 break;
3707 case ITEM_VALUE_TYPE_FLOAT:
3708 del_zeros(value);
3709 ZBX_FALLTHROUGH;
3710 case ITEM_VALUE_TYPE_UINT64:
3711 if (SUCCEED != replace_value_by_map(value, max_len, valuemapid, value_type))
3712 add_value_suffix(value, max_len, units, value_type);
3713 break;
3714 default:
3715 ;
3716 }
3717
3718 zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__);
3719 }
3720
3721 /******************************************************************************
3722 * *
3723 * Function: evaluate_macro_function *
3724 * *
3725 * Purpose: evaluate function used in simple macro *
3726 * *
3727 * Parameters: result - [OUT] evaluation result (if it's successful) *
3728 * host - [IN] host the key belongs to *
3729 * key - [IN] item's key *
3730 * (for example, 'system.cpu.load[,avg1]') *
3731 * function - [IN] function name (for example, 'max') *
3732 * parameter - [IN] function parameter list *
3733 * *
3734 * Return value: SUCCEED - evaluated successfully, value contains its value *
3735 * FAIL - evaluation failed *
3736 * *
3737 * Comments: used for evaluation of notification macros *
3738 * *
3739 ******************************************************************************/
evaluate_macro_function(char ** result,const char * host,const char * key,const char * function,const char * parameter,zbx_output_format_t format)3740 int evaluate_macro_function(char **result, const char *host, const char *key, const char *function,
3741 const char *parameter, zbx_output_format_t format)
3742 {
3743 zbx_host_key_t host_key = {(char *)host, (char *)key};
3744 DC_ITEM item;
3745 char *value = NULL, *error = NULL, *resolved_params = NULL;
3746 int ret, errcode;
3747 zbx_timespec_t ts;
3748
3749 zabbix_log(LOG_LEVEL_DEBUG, "In %s() function:'%s:%s.%s(%s)'", __func__, host, key, function, parameter);
3750
3751 DCconfig_get_items_by_keys(&item, &host_key, &errcode, 1);
3752
3753 zbx_timespec(&ts);
3754
3755 /* User macros in trigger and calculated function parameters are resolved during configuration sync. */
3756 /* However simple macro user parameters are not expanded, do it now. */
3757
3758 if (SUCCEED != errcode || SUCCEED != evaluate_function(&value, &item, function,
3759 (resolved_params = zbx_dc_expand_user_macros_in_func_params(parameter, item.host.hostid)),
3760 &ts, &error))
3761 {
3762 char *msg;
3763
3764 msg = zbx_eval_format_function_error(function, host, key, parameter,
3765 (NULL == error ? "item does not exist" : error));
3766 zabbix_log(LOG_LEVEL_DEBUG, "%s", msg);
3767 zbx_free(msg);
3768 ret = FAIL;
3769 }
3770 else
3771 {
3772 if (ZBX_FORMAT_HUMAN == format)
3773 {
3774 size_t len;
3775
3776 len = strlen(value) + 1 + MAX_BUFFER_LEN;
3777 value = (char *)zbx_realloc(value, len);
3778
3779 if (SUCCEED == str_in_list("last,prev", function, ','))
3780 {
3781 /* last, prev functions can return quoted and escaped string values */
3782 /* which must be unquoted and unescaped before further processing */
3783 if ('"' == *value)
3784 {
3785 char *src, *dst;
3786
3787 for (dst = value, src = dst + 1; '"' != *src; )
3788 {
3789 if ('\\' == *src)
3790 src++;
3791 if ('\0' == *src)
3792 break;
3793 *dst++ = *src++;
3794 }
3795 *dst = '\0';
3796 }
3797 zbx_format_value(value, len, item.valuemapid, item.units, item.value_type);
3798 }
3799 else if (SUCCEED == str_in_list("abschange,avg,change,delta,max,min,percentile,sum,forecast", function,
3800 ','))
3801 {
3802 switch (item.value_type)
3803 {
3804 case ITEM_VALUE_TYPE_FLOAT:
3805 case ITEM_VALUE_TYPE_UINT64:
3806 add_value_suffix(value, len, item.units, item.value_type);
3807 break;
3808 default:
3809 ;
3810 }
3811 }
3812 else if (SUCCEED == str_in_list("timeleft", function, ','))
3813 {
3814 add_value_suffix(value, len, "s", ITEM_VALUE_TYPE_FLOAT);
3815 }
3816 }
3817
3818 *result = zbx_strdup(NULL, value);
3819 ret = SUCCEED;
3820 }
3821
3822 DCconfig_clean_items(&item, &errcode, 1);
3823 zbx_free(error);
3824
3825 zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s value:'%s'", __func__, zbx_result_string(ret), value);
3826 zbx_free(value);
3827 zbx_free(resolved_params);
3828
3829 return ret;
3830 }
3831
3832 /******************************************************************************
3833 * *
3834 * Function: evaluatable_for_notsupported *
3835 * *
3836 * Purpose: check is function to be evaluated for NOTSUPPORTED items *
3837 * *
3838 * Parameters: fn - [IN] function name *
3839 * *
3840 * Return value: SUCCEED - do evaluate the function for NOTSUPPORTED items *
3841 * FAIL - don't evaluate the function for NOTSUPPORTED items *
3842 * *
3843 ******************************************************************************/
zbx_evaluatable_for_notsupported(const char * fn)3844 int zbx_evaluatable_for_notsupported(const char *fn)
3845 {
3846 /* function nodata() are exceptions, */
3847 /* and should be evaluated for NOTSUPPORTED items, too */
3848
3849 if (0 == strcmp(fn, "nodata"))
3850 return SUCCEED;
3851
3852 return FAIL;
3853 }
3854
3855 #ifdef HAVE_TESTS
3856 # include "../../../tests/libs/zbxserver/valuemaps_test.c"
3857 #endif
3858