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