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