/****************************************************************************** * * * Purpose: evaluate "and" * * * * 0.0 and Unknown -> 0.0 * * Unknown and 0.0 -> 0.0 * * 1.0 and Unknown -> Unknown * * Unknown and 1.0 -> Unknown * * Unknown and Unknown -> Unknown * * * ******************************************************************************/ static double evaluate_term2(int *unknown_idx) { double result, operand; int res_idx = -9, oper_idx = -10; /* set invalid values to catch errors */ if (ZBX_INFINITY == (result = evaluate_term3(&res_idx))) return ZBX_INFINITY; if (ZBX_UNKNOWN == result) *unknown_idx = res_idx; /* if evaluate_term3() returns ZBX_UNKNOWN then continue as with regular number */ while ('a' == ptr[0] && 'n' == ptr[1] && 'd' == ptr[2] && SUCCEED == is_operator_delimiter(ptr[3])) { ptr += 3; if (ZBX_INFINITY == (operand = evaluate_term3(&oper_idx))) return ZBX_INFINITY; if (ZBX_UNKNOWN == result) { if (ZBX_UNKNOWN == operand) /* Unknown and Unknown */ { *unknown_idx = oper_idx; res_idx = oper_idx; result = ZBX_UNKNOWN; } else if (SUCCEED == zbx_double_compare(operand, 0.0)) /* Unknown and 0 */ { result = 0.0; } else /* Unknown and 1 */ *unknown_idx = res_idx; } else if (ZBX_UNKNOWN == operand) { if (SUCCEED == zbx_double_compare(result, 0.0)) /* 0 and Unknown */ { result = 0.0; } else /* 1 and Unknown */ { *unknown_idx = oper_idx; res_idx = oper_idx; result = ZBX_UNKNOWN; } } else { result = (SUCCEED != zbx_double_compare(result, 0.0) && SUCCEED != zbx_double_compare(operand, 0.0)); } } return result; }
/****************************************************************************** * * * Purpose: evaluate "=" and "<>" * * * * 0.0 = Unknown -> Unknown * * 1.2 = Unknown -> Unknown * * Unknown = Unknown -> Unknown * * 0.0 <> Unknown -> Unknown * * 1.2 <> Unknown -> Unknown * * Unknown <> Unknown -> Unknown * * * ******************************************************************************/ static double evaluate_term3(int *unknown_idx) { char op; double result, operand; int res_idx = -7, oper_idx = -8; /* set invalid values to catch errors */ if (ZBX_INFINITY == (result = evaluate_term4(&res_idx))) return ZBX_INFINITY; if (ZBX_UNKNOWN == result) *unknown_idx = res_idx; /* if evaluate_term4() returns ZBX_UNKNOWN then continue as with regular number */ while (1) { if ('=' == *ptr) { op = *ptr++; } else if ('<' == ptr[0] && '>' == ptr[1]) { op = '#'; ptr += 2; } else break; /* even if 1st operand is Unknown we evaluate 2nd operand to catch fatal error if any occurrs */ if (ZBX_INFINITY == (operand = evaluate_term4(&oper_idx))) return ZBX_INFINITY; if (ZBX_UNKNOWN == operand) /* (anything) = Unknown, (anything) <> Unknown */ { *unknown_idx = oper_idx; res_idx = oper_idx; result = ZBX_UNKNOWN; } else if (ZBX_UNKNOWN == result) /* Unknown = known, Unknown <> known */ { *unknown_idx = res_idx; } else if ('=' == op) { result = (SUCCEED == zbx_double_compare(result, operand)); } else result = (SUCCEED != zbx_double_compare(result, operand)); } return result; }
/****************************************************************************** * * * Function: filter_evaluate_expression * * * * Purpose: check if the lld data passes filter evaluation by custom * * expression * * * * Parameters: filter - [IN] the lld filter * * jp_row - [IN] the lld data row * * * * Return value: SUCCEED - the lld data passed filter evaluation * * FAIL - otherwise * * * * Comments: 1) replace {item_condition} references with action condition * * evaluation results (1 or 0) * * 2) call evaluate() to calculate the final result * * * ******************************************************************************/ static int filter_evaluate_expression(lld_filter_t *filter, struct zbx_json_parse *jp_row) { const char *__function_name = "filter_evaluate_expression"; int i, ret = FAIL, id_len; char *expression, id[ZBX_MAX_UINT64_LEN + 2], *p, error[256]; double result; zabbix_log(LOG_LEVEL_DEBUG, "In %s() expression:%s", __function_name, filter->expression); expression = zbx_strdup(NULL, filter->expression); for (i = 0; i < filter->conditions.values_num; i++) { char *value = NULL; size_t value_alloc = 0; lld_condition_t *condition = (lld_condition_t *)filter->conditions.values[i]; if (SUCCEED == (ret = zbx_json_value_by_name_dyn(jp_row, condition->macro, &value, &value_alloc))) { ret = (ZBX_REGEXP_MATCH == regexp_match_ex(&condition->regexps, value, condition->regexp, ZBX_CASE_SENSITIVE) ? SUCCEED : FAIL); } zbx_free(value); zbx_snprintf(id, sizeof(id), "{" ZBX_FS_UI64 "}", condition->id); id_len = strlen(id); p = expression; while (NULL != (p = strstr(p, id))) { *p = (SUCCEED == ret ? '1' : '0'); memset(p + 1, ' ', id_len - 1); p += id_len; } } if (SUCCEED == evaluate(&result, expression, error, sizeof(error))) ret = (SUCCEED != zbx_double_compare(result, 0) ? SUCCEED : FAIL); zbx_free(expression); zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __function_name, zbx_result_string(ret)); return ret; }
/****************************************************************************** * * * Purpose: evaluate "not" * * * * not 0.0 -> 1.0 * * not 1.2 -> 0.0 * * not Unknown -> Unknown * * * ******************************************************************************/ static double evaluate_term7(int *unknown_idx) { double result; while (' ' == *ptr || '\r' == *ptr || '\n' == *ptr || '\t' == *ptr) ptr++; if ('n' == ptr[0] && 'o' == ptr[1] && 't' == ptr[2] && SUCCEED == is_operator_delimiter(ptr[3])) { ptr += 3; if (ZBX_UNKNOWN == (result = evaluate_term8(unknown_idx)) || ZBX_INFINITY == result) return result; result = (SUCCEED == zbx_double_compare(result, 0.0) ? 1.0 : 0.0); } else result = evaluate_term8(unknown_idx); return result; }
/****************************************************************************** * * * Function: variant_compare_dbl * * * * Purpose: compares two variant values when at least one is double and the * * other is double or uint64 * * * ******************************************************************************/ static int variant_compare_dbl(const zbx_variant_t *value1, const zbx_variant_t *value2) { double value1_dbl, value2_dbl; switch (value1->type) { case ZBX_VARIANT_DBL: value1_dbl = value1->data.dbl; break; case ZBX_VARIANT_UI64: value1_dbl = value1->data.ui64; break; default: THIS_SHOULD_NEVER_HAPPEN; exit(EXIT_FAILURE); } switch (value2->type) { case ZBX_VARIANT_DBL: value2_dbl = value2->data.dbl; break; case ZBX_VARIANT_UI64: value2_dbl = value2->data.ui64; break; default: THIS_SHOULD_NEVER_HAPPEN; exit(EXIT_FAILURE); } if (SUCCEED == zbx_double_compare(value1_dbl, value2_dbl)) return 0; ZBX_RETURN_IF_NOT_EQUAL(value1_dbl, value2_dbl); THIS_SHOULD_NEVER_HAPPEN; exit(EXIT_FAILURE); }
/****************************************************************************** * * * Purpose: evaluate "or" * * * * 1.0 or Unknown -> 1.0 * * Unknown or 1.0 -> 1.0 * * 0.0 or Unknown -> Unknown * * Unknown or 0.0 -> Unknown * * Unknown or Unknown -> Unknown * * * ******************************************************************************/ static double evaluate_term1(int *unknown_idx) { double result, operand; int res_idx = -11, oper_idx = -12; /* set invalid values to catch errors */ level++; if (32 < level) { zbx_strlcpy(buffer, "Cannot evaluate expression: nesting level is too deep.", max_buffer_len); return ZBX_INFINITY; } if (ZBX_INFINITY == (result = evaluate_term2(&res_idx))) return ZBX_INFINITY; if (ZBX_UNKNOWN == result) *unknown_idx = res_idx; /* if evaluate_term2() returns ZBX_UNKNOWN then continue as with regular number */ while ('o' == ptr[0] && 'r' == ptr[1] && SUCCEED == is_operator_delimiter(ptr[2])) { ptr += 2; if (ZBX_INFINITY == (operand = evaluate_term2(&oper_idx))) return ZBX_INFINITY; if (ZBX_UNKNOWN == result) { if (ZBX_UNKNOWN == operand) /* Unknown or Unknown */ { *unknown_idx = oper_idx; res_idx = oper_idx; result = ZBX_UNKNOWN; } else if (SUCCEED != zbx_double_compare(operand, 0.0)) /* Unknown or 1 */ { result = 1; } else /* Unknown or 0 */ *unknown_idx = res_idx; } else if (ZBX_UNKNOWN == operand) { if (SUCCEED != zbx_double_compare(result, 0.0)) /* 1 or Unknown */ { result = 1; } else /* 0 or Unknown */ { *unknown_idx = oper_idx; res_idx = oper_idx; result = ZBX_UNKNOWN; } } else { result = (SUCCEED != zbx_double_compare(result, 0.0) || SUCCEED != zbx_double_compare(operand, 0.0)); } } level--; return result; }
/****************************************************************************** * * * Purpose: evaluate "*" and "/" * * * * 0.0 * Unknown -> Unknown (yes, not 0 as we don't want to lose * * Unknown in arithmetic operations) * * 1.2 * Unknown -> Unknown * * 0.0 / 1.2 -> 0.0 * * 1.2 / 0.0 -> error (ZBX_INFINITY) * * Unknown / 0.0 -> error (ZBX_INFINITY) * * Unknown / 1.2 -> Unknown * * Unknown / Unknown -> Unknown * * 0.0 / Unknown -> Unknown * * 1.2 / Unknown -> Unknown * * * ******************************************************************************/ static double evaluate_term6(int *unknown_idx) { char op; double result, operand; int res_idx = -1, oper_idx = -2; /* set invalid values to catch errors */ if (ZBX_INFINITY == (result = evaluate_term7(&res_idx))) return ZBX_INFINITY; if (ZBX_UNKNOWN == result) *unknown_idx = res_idx; /* if evaluate_term7() returns ZBX_UNKNOWN then continue as with regular number */ while ('*' == *ptr || '/' == *ptr) { op = *ptr++; /* 'ZBX_UNKNOWN' in multiplication and division produces 'ZBX_UNKNOWN'. */ /* Even if 1st operand is Unknown we evaluate 2nd operand too to catch fatal errors in it. */ if (ZBX_INFINITY == (operand = evaluate_term7(&oper_idx))) return ZBX_INFINITY; if ('*' == op) { if (ZBX_UNKNOWN == operand) /* (anything) * Unknown */ { *unknown_idx = oper_idx; res_idx = oper_idx; result = ZBX_UNKNOWN; } else if (ZBX_UNKNOWN == result) /* Unknown * known */ { *unknown_idx = res_idx; } else result *= operand; } else { /* catch division by 0 even if 1st operand is Unknown */ if (ZBX_UNKNOWN != operand && SUCCEED == zbx_double_compare(operand, 0.0)) { zbx_strlcpy(buffer, "Cannot evaluate expression: division by zero.", max_buffer_len); return ZBX_INFINITY; } if (ZBX_UNKNOWN == operand) /* (anything) / Unknown */ { *unknown_idx = oper_idx; res_idx = oper_idx; result = ZBX_UNKNOWN; } else if (ZBX_UNKNOWN == result) /* Unknown / known */ { *unknown_idx = res_idx; } else result /= operand; } } return result; }