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