/* ** ZABBIX ** Copyright (C) 2000-2005 SIA Zabbix ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. **/ #include #include #include #include #include "functions.h" #include "evalfunc.h" #include "common.h" #include "db.h" #include "log.h" #include "zlog.h" /****************************************************************************** * * * Function: rtrim_spaces * * * * Purpose: delete all right spaces for the string * * * * Parameters: c - string to trim spaces * * * * Return value: string without right spaces * * * * Author: Alexei Vladishev * * * * Comments: * * * ******************************************************************************/ void rtrim_spaces(char *c) { int i,len; len=strlen(c); for(i=len-1;i>=0;i--) { if( c[i] == ' ') { c[i]=0; } else break; } } /****************************************************************************** * * * Function: ltrim_spaces * * * * Purpose: delete all left spaces for the string * * * * Parameters: c - string to trim spaces * * * * Return value: string without left spaces * * * * Author: Alexei Vladishev * * * * Comments: * * * ******************************************************************************/ void ltrim_spaces(char *c) { int i; /* Number of left spaces */ int spaces=0; for(i=0;c[i]!=0;i++) { if( c[i] == ' ') { spaces++; } else break; } for(i=0;c[i+spaces]!=0;i++) { c[i]=c[i+spaces]; } c[strlen(c)-spaces]=0; } /****************************************************************************** * * * Function: lrtrim_spaces * * * * Purpose: delete all left and right spaces for the string * * * * Parameters: c - string to trim spaces * * * * Return value: string without left and right spaces * * * * Author: Alexei Vladishev * * * * Comments: * * * ******************************************************************************/ void lrtrim_spaces(char *c) { ltrim_spaces(c); rtrim_spaces(c); } /****************************************************************************** * * * Function: str2double * * * * Purpose: convert string to double * * * * Parameters: str - string to convert * * * * Return value: converted double value * * * * Author: Alexei Vladishev * * * * Comments: the function automatically processes prefixes 'K','M','G' * * * ******************************************************************************/ double str2double(char *str) { if(str[strlen(str)-1] == 'K') { str[strlen(str)-1] = 0; return (double)1024*atof(str); } else if(str[strlen(str)-1] == 'M') { str[strlen(str)-1] = 0; return (double)1024*1024*atof(str); } else if(str[strlen(str)-1] == 'G') { str[strlen(str)-1] = 0; return (double)1024*1024*1024*atof(str); } return atof(str); } /****************************************************************************** * * * Function: delete_spaces * * * * Purpose: delete all spaces * * * * Parameters: c - string to delete spaces * * * * Return value: the string wtihout spaces * * * * Author: Alexei Vladishev * * * * Comments: * * * ******************************************************************************/ void delete_spaces(char *c) { int i,j; zabbix_log( LOG_LEVEL_DEBUG, "Before deleting spaces:%s", c ); j=0; for(i=0;c[i]!=0;i++) { if( c[i] != ' ') { c[j]=c[i]; j++; } } c[j]=0; zabbix_log(LOG_LEVEL_DEBUG, "After deleting spaces:%s", c ); } /****************************************************************************** * * * Function: find_char * * * * Purpose: locate a character in the string * * * * Parameters: str - string * * c - character to find * * * * Return value: position of the character * * FAIL - otherwise * * * * Author: Alexei Vladishev * * * * Comments: * * * ******************************************************************************/ int find_char(char *str,char c) { int i; zabbix_log( LOG_LEVEL_DEBUG, "Before find_char:%s[%c]", str, c ); for(i=0;str[i]!=0;i++) { if(str[i]==c) return i; } return FAIL; } /****************************************************************************** * * * Function: evaluate_simple * * * * Purpose: evaluate simple expression * * * * Parameters: exp - expression string * * * * Return value: SUCCEED - evaluated succesfully, result - value of the exp * * FAIL - otherwise * * * * Author: Alexei Vladishev * * * * Comments: format: or * * * * It is recursive function! * * * ******************************************************************************/ int evaluate_simple (double *result,char *exp,char *error,int maxerrlen) { double value1,value2; char first[MAX_STRING_LEN],second[MAX_STRING_LEN]; int i,j,l; zabbix_log( LOG_LEVEL_DEBUG, "Evaluating simple expression [%s]", exp ); /* Remove left and right spaces */ lrtrim_spaces(exp); if( is_double_prefix(exp) == SUCCEED ) { /* *result=atof(exp);*/ /* str2double support prefixes */ *result=str2double(exp); return SUCCEED; } if( find_char(exp,'|') != FAIL ) { zabbix_log( LOG_LEVEL_DEBUG, "| is found" ); l=find_char(exp,'|'); strscpy( first, exp ); first[l]=0; j=0; for(i=l+1;exp[i]!=0;i++) { second[j]=exp[i]; j++; } second[j]=0; if( evaluate_simple(&value1,first,error,maxerrlen) == FAIL ) { zabbix_log(LOG_LEVEL_DEBUG, error); zabbix_syslog(error); return FAIL; } if( value1 == 1) { *result=value1; return SUCCEED; } if( evaluate_simple(&value2,second,error,maxerrlen) == FAIL ) { zabbix_log(LOG_LEVEL_DEBUG, error); zabbix_syslog(error); return FAIL; } if( value2 == 1) { *result=value2; return SUCCEED; } *result=0; return SUCCEED; } else if( find_char(exp,'&') != FAIL ) { zabbix_log(LOG_LEVEL_DEBUG, "& is found" ); l=find_char(exp,'&'); strscpy( first, exp ); first[l]=0; j=0; for(i=l+1;exp[i]!=0;i++) { second[j]=exp[i]; j++; } second[j]=0; zabbix_log(LOG_LEVEL_DEBUG, "[%s] [%s]",first,second ); if( evaluate_simple(&value1,first,error,maxerrlen) == FAIL ) { zabbix_log(LOG_LEVEL_DEBUG, error); zabbix_syslog(error); return FAIL; } if( evaluate_simple(&value2,second,error,maxerrlen) == FAIL ) { zabbix_log(LOG_LEVEL_DEBUG, error); zabbix_syslog(error); return FAIL; } if( (value1 == 1) && (value2 == 1) ) { *result=1; } else { *result=0; } return SUCCEED; } else if( find_char(exp,'>') != FAIL ) { zabbix_log(LOG_LEVEL_DEBUG, "> is found" ); l=find_char(exp,'>'); strscpy(first, exp); first[l]=0; j=0; for(i=l+1;exp[i]!=0;i++) { second[j]=exp[i]; j++; } second[j]=0; if( evaluate_simple(&value1,first,error,maxerrlen) == FAIL ) { zabbix_log(LOG_LEVEL_DEBUG, error); zabbix_syslog(error); return FAIL; } if( evaluate_simple(&value2,second,error,maxerrlen) == FAIL ) { zabbix_log(LOG_LEVEL_DEBUG, error); zabbix_syslog(error); return FAIL; } if( value1 > value2 ) { *result=1; } else { *result=0; } return SUCCEED; } else if( find_char(exp,'<') != FAIL ) { zabbix_log(LOG_LEVEL_DEBUG, "< is found" ); l=find_char(exp,'<'); strscpy(first, exp); first[l]=0; j=0; for(i=l+1;exp[i]!=0;i++) { second[j]=exp[i]; j++; } second[j]=0; zabbix_log(LOG_LEVEL_DEBUG, "[%s] [%s]",first,second ); if( evaluate_simple(&value1,first,error,maxerrlen) == FAIL ) { zabbix_log(LOG_LEVEL_DEBUG, error); zabbix_syslog(error); return FAIL; } if( evaluate_simple(&value2,second,error,maxerrlen) == FAIL ) { zabbix_log(LOG_LEVEL_DEBUG, error); zabbix_syslog(error); return FAIL; } if( value1 < value2 ) { *result=1; } else { *result=0; } zabbix_log(LOG_LEVEL_DEBUG, "Result [%f]",*result ); return SUCCEED; } else if( find_char(exp,'*') != FAIL ) { zabbix_log(LOG_LEVEL_DEBUG, "* is found" ); l=find_char(exp,'*'); strscpy(first, exp); first[l]=0; j=0; for(i=l+1;exp[i]!=0;i++) { second[j]=exp[i]; j++; } second[j]=0; if( evaluate_simple(&value1,first,error,maxerrlen) == FAIL ) { zabbix_log(LOG_LEVEL_DEBUG, error); zabbix_syslog(error); return FAIL; } if( evaluate_simple(&value2,second,error,maxerrlen) == FAIL ) { zabbix_log(LOG_LEVEL_DEBUG, error); zabbix_syslog(error); return FAIL; } *result=value1*value2; return SUCCEED; } else if( find_char(exp,'/') != FAIL ) { zabbix_log(LOG_LEVEL_DEBUG, "/ is found" ); l=find_char(exp,'/'); strscpy(first, exp); first[l]=0; j=0; for(i=l+1;exp[i]!=0;i++) { second[j]=exp[i]; j++; } second[j]=0; if( evaluate_simple(&value1,first,error,maxerrlen) == FAIL ) { zabbix_log(LOG_LEVEL_DEBUG, error); zabbix_syslog(error); return FAIL; } if( evaluate_simple(&value2,second,error,maxerrlen) == FAIL ) { zabbix_log(LOG_LEVEL_DEBUG, error); zabbix_syslog(error); return FAIL; } if(cmp_double(value2,0) == 0) { snprintf(error,maxerrlen-1,"Division by zero. Cannot evaluate expression [%s/%s]", first,second); zabbix_log(LOG_LEVEL_WARNING, error); zabbix_syslog(error); return FAIL; } else { *result=value1/value2; } return SUCCEED; } else if( find_char(exp,'+') != FAIL ) { zabbix_log(LOG_LEVEL_DEBUG, "+ is found" ); l=find_char(exp,'+'); strscpy(first, exp); first[l]=0; j=0; for(i=l+1;exp[i]!=0;i++) { second[j]=exp[i]; j++; } second[j]=0; if( evaluate_simple(&value1,first,error,maxerrlen) == FAIL ) { zabbix_log(LOG_LEVEL_DEBUG, error); zabbix_syslog(error); return FAIL; } if( evaluate_simple(&value2,second,error,maxerrlen) == FAIL ) { zabbix_log(LOG_LEVEL_DEBUG, error); zabbix_syslog(error); return FAIL; } *result=value1+value2; return SUCCEED; } else if( find_char(exp,'-') != FAIL ) { zabbix_log(LOG_LEVEL_DEBUG, "- is found" ); l=find_char(exp,'-'); strscpy(first, exp); first[l]=0; j=0; for(i=l+1;exp[i]!=0;i++) { second[j]=exp[i]; j++; } second[j]=0; if( evaluate_simple(&value1,first,error,maxerrlen) == FAIL ) { zabbix_log(LOG_LEVEL_DEBUG, error); zabbix_syslog(error); return FAIL; } if( evaluate_simple(&value2,second,error,maxerrlen) == FAIL ) { zabbix_log(LOG_LEVEL_DEBUG, error); zabbix_syslog(error); return FAIL; } *result=value1-value2; return SUCCEED; } else if( find_char(exp,'=') != FAIL ) { zabbix_log(LOG_LEVEL_DEBUG, "= is found" ); l=find_char(exp,'='); strscpy(first, exp); first[l]=0; j=0; for(i=l+1;exp[i]!=0;i++) { second[j]=exp[i]; j++; } second[j]=0; if( evaluate_simple(&value1,first,error,maxerrlen) == FAIL ) { zabbix_log(LOG_LEVEL_DEBUG, error); zabbix_syslog(error); return FAIL; } if( evaluate_simple(&value2,second,error,maxerrlen) == FAIL ) { zabbix_log(LOG_LEVEL_DEBUG, error); zabbix_syslog(error); return FAIL; } if( cmp_double(value1,value2) ==0 ) { *result=1; } else { *result=0; } return SUCCEED; } else if( find_char(exp,'#') != FAIL ) { zabbix_log(LOG_LEVEL_DEBUG, "# is found" ); l=find_char(exp,'#'); strscpy(first, exp); first[l]=0; j=0; for(i=l+1;exp[i]!=0;i++) { second[j]=exp[i]; j++; } second[j]=0; if( evaluate_simple(&value1,first,error,maxerrlen) == FAIL ) { zabbix_log(LOG_LEVEL_DEBUG, error); zabbix_syslog(error); return FAIL; } if( evaluate_simple(&value2,second,error,maxerrlen) == FAIL ) { zabbix_log(LOG_LEVEL_DEBUG, error); zabbix_syslog(error); return FAIL; } if( cmp_double(value1,value2) != 0 ) { *result=1; } else { *result=0; } return SUCCEED; } else { snprintf(error,maxerrlen-1,"Format error or unsupported operator. Exp: [%s]", exp); zabbix_log(LOG_LEVEL_WARNING, error); zabbix_syslog(error); return FAIL; } return SUCCEED; } /****************************************************************************** * * * Function: evaluate * * * * Purpose: evaluate simplified expression * * * * Parameters: exp - expression string * * * * Return value: SUCCEED - evaluated succesfully, result - value of the exp * * FAIL - otherwise * * * * Author: Alexei Vladishev * * * * Comments: example: ({15}>10)|({123}=1) * * * ******************************************************************************/ int evaluate(int *result,char *exp, char *error, int maxerrlen) { double value; char res[MAX_STRING_LEN]; char simple[MAX_STRING_LEN]; int i,l,r; zabbix_log(LOG_LEVEL_DEBUG, "In evaluate([%s])",exp); strscpy( res,exp ); while( find_char( exp, ')' ) != FAIL ) { l=-1; r=find_char(exp,')'); for(i=r;i>=0;i--) { if( exp[i] == '(' ) { l=i; break; } } if( r == -1 ) { snprintf(error, maxerrlen-1, "Cannot find left bracket [(]. Expression:[%s]", exp); zabbix_log(LOG_LEVEL_WARNING, error); zabbix_syslog(error); return FAIL; } for(i=l+1;itriggerid);*/ snprintf(sql,sizeof(sql)-1,"select distinct h.host from triggers t, functions f,items i, hosts h where t.triggerid=%d and f.triggerid=t.triggerid and f.itemid=i.itemid and h.hostid=i.hostid", trigger->triggerid); result = DBselect(sql); if(DBnum_rows(result) == 0) { zabbix_log( LOG_LEVEL_ERR, "No hostname in substitute_simple_macros. Triggerid [%d]", trigger->triggerid); zabbix_syslog("No hostname in substitute_simple_macros. Triggerid [%d]", trigger->triggerid); strscpy(tmp, "*UNKNOWN*"); DBfree_result(result); } else { strscpy(tmp,DBget_field(result,0,0)); DBfree_result(result); } s[0]=0; strcpy(data, str); strncat(data, tmp, MAX_STRING_LEN); strncat(data, s+strlen("{HOSTNAME}"), MAX_STRING_LEN); found = SUCCEED; } else if( (s = strstr(str,"{IPADDRESS}")) != NULL ) { snprintf(sql,sizeof(sql)-1,"select distinct h.ip from triggers t, functions f,items i, hosts h where t.triggerid=%d and f.triggerid=t.triggerid and f.itemid=i.itemid and h.hostid=i.hostid and i.useip=1", trigger->triggerid); result = DBselect(sql); if(DBnum_rows(result) == 0) { zabbix_log( LOG_LEVEL_ERR, "No IP address in substitute_simple_macros. Triggerid [%d]", trigger->triggerid); zabbix_syslog("No IP address in substitute_simple_macros. Triggerid [%d]", trigger->triggerid); strscpy(tmp, "*UNKNOWN IP*"); DBfree_result(result); } else { strscpy(tmp,DBget_field(result,0,0)); DBfree_result(result); } s[0]=0; strcpy(data, str); strncat(data, tmp, MAX_STRING_LEN); strncat(data, s+strlen("{IPADDRESS}"), MAX_STRING_LEN); found = SUCCEED; } else if( (s = strstr(str,"{DATE}")) != NULL ) { now=time(NULL); tm=localtime(&now); snprintf(tmp,sizeof(tmp)-1,"%.4d.%.2d.%.2d",tm->tm_year+1900,tm->tm_mon+1,tm->tm_mday); s[0]=0; strcpy(data, str); strncat(data, tmp, MAX_STRING_LEN); strncat(data, s+strlen("{DATE}"), MAX_STRING_LEN); found = SUCCEED; } else if( (s = strstr(str,"{TIME}")) != NULL ) { now=time(NULL); tm=localtime(&now); snprintf(tmp,sizeof(tmp)-1,"%.2d:%.2d:%.2d",tm->tm_hour,tm->tm_min,tm->tm_sec); s[0]=0; strcpy(data, str); strncat(data, tmp, MAX_STRING_LEN); strncat(data, s+strlen("{TIME}"), MAX_STRING_LEN); found = SUCCEED; } else if( (s = strstr(str,"{STATUS}")) != NULL ) { /* This is old value */ if(trigger->value == TRIGGER_VALUE_TRUE) { snprintf(tmp,sizeof(tmp)-1,"OFF"); } else { snprintf(tmp,sizeof(tmp)-1,"ON"); } s[0]=0; strcpy(data, str); strncat(data, tmp, MAX_STRING_LEN); strncat(data, s+strlen("{STATUS}"), MAX_STRING_LEN); found = SUCCEED; } else { found = FAIL; } } zabbix_log( LOG_LEVEL_DEBUG, "Result expression [%s]", data ); } /****************************************************************************** * * * Function: substitute_macros * * * * Purpose: substitute macros in data string with real values * * * * Parameters: data - data string * * trigger - trigger structure * * action - action structure * * * * Return value: SUCCEED - substituted succesfully, data - updated data * * FAIL - otherwise * * * * Author: Alexei Vladishev * * * * Comments: example: "{127.0.0.1:system[procload].last(0)}" to "1.34" * * * * Make this function more secure. Get rid of snprintf. Utilise substr() * * * ******************************************************************************/ int substitute_macros(DB_TRIGGER *trigger, DB_ACTION *action, char *data) { char res[MAX_STRING_LEN]; char macro[MAX_STRING_LEN]; char host[MAX_STRING_LEN]; char key[MAX_STRING_LEN]; char function[MAX_STRING_LEN]; char parameter[MAX_STRING_LEN]; static char value[MAX_STRING_LEN]; int i; int r,l; int r1,l1; zabbix_log(LOG_LEVEL_DEBUG, "In substitute_macros([%s])",data); substitute_simple_macros(trigger, action, data); while( find_char(data,'{') != FAIL ) { l=find_char(data,'{'); r=find_char(data,'}'); if( r == FAIL ) { zabbix_log( LOG_LEVEL_WARNING, "Cannot find right bracket. Expression:[%s]", data ); zabbix_syslog("Cannot find right bracket. Expression:[%s]", data ); return FAIL; } if( r < l ) { zabbix_log( LOG_LEVEL_WARNING, "Right bracket is before left one. Expression:[%s]", data ); zabbix_syslog("Right bracket is before left one. Expression:[%s]", data ); return FAIL; } for(i=l+1;i10)|({123}=0)" => "(6.456>10)|(0=0) * * * ******************************************************************************/ int substitute_functions(char *exp, char *error, int maxerrlen) { double value; char functionid[MAX_STRING_LEN]; char res[MAX_STRING_LEN]; int i,l,r; zabbix_log(LOG_LEVEL_DEBUG, "BEGIN substitute_functions (%s)", exp); while( find_char(exp,'{') != FAIL ) { l=find_char(exp,'{'); r=find_char(exp,'}'); if( r == FAIL ) { snprintf(error,maxerrlen-1,"Cannot find right bracket. Expression:[%s]", exp); zabbix_log( LOG_LEVEL_WARNING, error); zabbix_syslog(error); return FAIL; } if( r < l ) { snprintf(error,maxerrlen-1, "Right bracket is before left one. Expression:[%s]", exp); zabbix_log( LOG_LEVEL_WARNING, error); zabbix_syslog(error); return FAIL; } for(i=l+1;i1)| * * ({a0:system[procload].max(300)}>3) * * * ******************************************************************************/ int evaluate_expression(int *result,char *expression, char *error, int maxerrlen) { zabbix_log(LOG_LEVEL_DEBUG, "In evaluate_expression(%s)", expression ); delete_spaces(expression); if( substitute_functions(expression, error, maxerrlen) == SUCCEED) { if( evaluate(result, expression, error, maxerrlen) == SUCCEED) { return SUCCEED; } } zabbix_log(LOG_LEVEL_WARNING, "Evaluation of expression [%s] failed [%s]", expression, error ); zabbix_syslog("Evaluation of expression [%s] failed [%s]", expression, error ); return FAIL; }