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 "zbxregexp.h"
22 #include "macrofunc.h"
23 #include "log.h"
24
25 /******************************************************************************
26 * *
27 * Function: macrofunc_regsub *
28 * *
29 * Purpose: calculates regular expression substitution *
30 * *
31 * Parameters: params - [IN] the function parameters *
32 * nparam - [IN] the function parameter count *
33 * out - [IN/OUT] the input/output value *
34 * *
35 * Return value: SUCCEED - the function was calculated successfully. *
36 * FAIL - the function calculation failed. *
37 * *
38 ******************************************************************************/
macrofunc_regsub(char ** params,size_t nparam,char ** out)39 static int macrofunc_regsub(char **params, size_t nparam, char **out)
40 {
41 char *value = NULL;
42
43 if (2 != nparam)
44 return FAIL;
45
46 if (FAIL == zbx_regexp_sub(*out, params[0], params[1], &value))
47 return FAIL;
48
49 if (NULL == value)
50 value = zbx_strdup(NULL, "");
51
52 zbx_free(*out);
53 *out = value;
54
55 return SUCCEED;
56 }
57
58 /******************************************************************************
59 * *
60 * Function: macrofunc_iregsub *
61 * *
62 * Purpose: calculates case insensitive regular expression substitution *
63 * *
64 * Parameters: params - [IN] the function parameters *
65 * nparam - [IN] the function parameter count *
66 * out - [IN/OUT] the input/output value *
67 * *
68 * Return value: SUCCEED - the function was calculated successfully. *
69 * FAIL - the function calculation failed. *
70 * *
71 ******************************************************************************/
macrofunc_iregsub(char ** params,size_t nparam,char ** out)72 static int macrofunc_iregsub(char **params, size_t nparam, char **out)
73 {
74 char *value = NULL;
75
76 if (2 != nparam)
77 return FAIL;
78
79 if (FAIL == zbx_iregexp_sub(*out, params[0], params[1], &value))
80 return FAIL;
81
82 if (NULL == value)
83 value = zbx_strdup(NULL, "");
84
85 zbx_free(*out);
86 *out = value;
87
88 return SUCCEED;
89 }
90
91 /******************************************************************************
92 * *
93 * Function: macrofunc_fmttime *
94 * *
95 * Purpose: time formatting macro function *
96 * *
97 * Parameters: params - [IN] the function parameters *
98 * nparam - [IN] the function parameter count *
99 * out - [IN/OUT] the input/output value *
100 * *
101 * Return value: SUCCEED - the function was calculated successfully. *
102 * FAIL - the function calculation failed. *
103 * *
104 ******************************************************************************/
macrofunc_fmttime(char ** params,size_t nparam,char ** out)105 static int macrofunc_fmttime(char **params, size_t nparam, char **out)
106 {
107 struct tm local_time;
108 time_t time_new;
109 char *buf = NULL;
110
111 if (0 == nparam || 2 < nparam)
112 return FAIL;
113
114 time_new = time(&time_new);
115 localtime_r(&time_new, &local_time);
116
117 if (2 == nparam)
118 {
119 char *p = params[1];
120 size_t len;
121
122 while ('\0' != *p)
123 {
124 zbx_time_unit_t unit;
125
126 if ('/' == *p)
127 {
128 if (ZBX_TIME_UNIT_UNKNOWN == (unit = zbx_tm_str_to_unit(++p)))
129 {
130 zabbix_log(LOG_LEVEL_DEBUG, "unexpected character starting with \"%s\"", p);
131 return FAIL;
132 }
133
134 zbx_tm_round_down(&local_time, unit);
135
136 p++;
137 }
138 else if ('+' == *p || '-' == *p)
139 {
140 int num;
141 char op, *error = NULL;
142
143 op = *(p++);
144
145 if (FAIL == zbx_tm_parse_period(p, &len, &num, &unit, &error))
146 {
147 zabbix_log(LOG_LEVEL_DEBUG, "failed to parse time period: %s", error);
148 zbx_free(error);
149 return FAIL;
150 }
151
152 if ('+' == op)
153 zbx_tm_add(&local_time, num, unit);
154 else
155 zbx_tm_sub(&local_time, num, unit);
156
157 p += len;
158 }
159 else
160 {
161 zabbix_log(LOG_LEVEL_DEBUG, "unexpected character starting with \"%s\"", p);
162 return FAIL;
163 }
164 }
165 }
166
167 buf = zbx_malloc(NULL, MAX_STRING_LEN);
168
169 if (0 == strftime(buf, MAX_STRING_LEN, params[0], &local_time))
170 {
171 zabbix_log(LOG_LEVEL_DEBUG, "invalid first parameter \"%s\"", params[0]);
172 zbx_free(buf);
173 return FAIL;
174 }
175
176 zbx_free(*out);
177 *out = buf;
178
179 return SUCCEED;
180 }
181
182 /******************************************************************************
183 * *
184 * Function: macrofunc_fmtnum *
185 * *
186 * Purpose: number formatting macro function *
187 * *
188 * Parameters: params - [IN] the function data *
189 * nparam - [IN] parameter count *
190 * out - [IN/OUT] the input/output value *
191 * *
192 * Return value: SUCCEED - the function was calculated successfully. *
193 * FAIL - the function calculation failed. *
194 * *
195 ******************************************************************************/
macrofunc_fmtnum(char ** params,size_t nparam,char ** out)196 static int macrofunc_fmtnum(char **params, size_t nparam, char **out)
197 {
198 double value;
199 int precision;
200
201 if (1 != nparam)
202 return FAIL;
203
204 if (SUCCEED == is_uint32(*out, &value))
205 return SUCCEED;
206
207 if (FAIL == is_double(*out, &value))
208 {
209 zabbix_log(LOG_LEVEL_DEBUG, "macro \"%s\" is not a number", *out);
210 return FAIL;
211 }
212
213 if (FAIL == is_uint32(params[0], &precision))
214 {
215 zabbix_log(LOG_LEVEL_DEBUG, "invalid parameter \"%s\"", params[0]);
216 return FAIL;
217 }
218
219 *out = zbx_dsprintf(*out, "%.*f", precision, value);
220
221 return SUCCEED;
222 }
223
224 /******************************************************************************
225 * *
226 * Function: zbx_calculate_macro_function *
227 * *
228 * Purpose: calculates macro function value *
229 * *
230 * Parameters: expression - [IN] expression containing macro function *
231 * func_macro - [IN] information about macro function token *
232 * out - [IN/OUT] the input/output value *
233 * *
234 * Return value: SUCCEED - the function was calculated successfully. *
235 * FAIL - the function calculation failed. *
236 * *
237 ******************************************************************************/
zbx_calculate_macro_function(const char * expression,const zbx_token_func_macro_t * func_macro,char ** out)238 int zbx_calculate_macro_function(const char *expression, const zbx_token_func_macro_t *func_macro, char **out)
239 {
240 char **params, *buf = NULL;
241 const char *ptr;
242 size_t nparam = 0, param_alloc = 8, buf_alloc = 0, buf_offset = 0, len, sep_pos;
243 int (*macrofunc)(char **params, size_t nparam, char **out), ret;
244
245 zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
246
247 ptr = expression + func_macro->func.l;
248 len = func_macro->func_param.l - func_macro->func.l;
249
250 if (ZBX_CONST_STRLEN("regsub") == len && 0 == strncmp(ptr, "regsub", len))
251 macrofunc = macrofunc_regsub;
252 else if (ZBX_CONST_STRLEN("iregsub") == len && 0 == strncmp(ptr, "iregsub", len))
253 macrofunc = macrofunc_iregsub;
254 else if (ZBX_CONST_STRLEN("fmttime") == len && 0 == strncmp(ptr, "fmttime", len))
255 macrofunc = macrofunc_fmttime;
256 else if (ZBX_CONST_STRLEN("fmtnum") == len && 0 == strncmp(ptr, "fmtnum", len))
257 macrofunc = macrofunc_fmtnum;
258 else
259 return FAIL;
260
261 zbx_strncpy_alloc(&buf, &buf_alloc, &buf_offset, expression + func_macro->func_param.l + 1,
262 func_macro->func_param.r - func_macro->func_param.l - 1);
263 params = (char **)zbx_malloc(NULL, sizeof(char *) * param_alloc);
264
265 for (ptr = buf; ptr < buf + buf_offset; ptr += sep_pos + 1)
266 {
267 size_t param_pos, param_len;
268 int quoted;
269
270 if (nparam == param_alloc)
271 {
272 param_alloc *= 2;
273 params = (char **)zbx_realloc(params, sizeof(char *) * param_alloc);
274 }
275
276 zbx_function_param_parse(ptr, ¶m_pos, ¶m_len, &sep_pos);
277 params[nparam++] = zbx_function_param_unquote_dyn(ptr + param_pos, param_len, "ed);
278 }
279
280 ret = macrofunc(params, nparam, out);
281
282 while (0 < nparam--)
283 zbx_free(params[nparam]);
284
285 zbx_free(params);
286 zbx_free(buf);
287
288 zabbix_log(LOG_LEVEL_DEBUG, "End of %s(), ret: %s", __func__, zbx_result_string(ret));
289
290 return ret;
291 }
292