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