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, &param_pos, &param_len, &sep_pos);
277 		params[nparam++] = zbx_function_param_unquote_dyn(ptr + param_pos, param_len, &quoted);
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