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 "threads.h"
22 
23 #include "../zbxcrypto/tls.h"
24 
25 #ifdef HAVE_ICONV
26 #	include <iconv.h>
27 #endif
28 
29 static const char	copyright_message[] =
30 	"Copyright (C) 2021 Zabbix SIA\n"
31 	"License GPLv2+: GNU GPL version 2 or later <http://gnu.org/licenses/gpl.html>.\n"
32 	"This is free software: you are free to change and redistribute it according to\n"
33 	"the license. There is NO WARRANTY, to the extent permitted by law.";
34 
35 static const char	help_message_footer[] =
36 	"Report bugs to: <https://support.zabbix.com>\n"
37 	"Zabbix home page: <http://www.zabbix.com>\n"
38 	"Documentation: <https://www.zabbix.com/documentation>";
39 
40 /******************************************************************************
41  *                                                                            *
42  * Function: version                                                          *
43  *                                                                            *
44  * Purpose: print version and compilation time of application on stdout       *
45  *          by application request with parameter '-V'                        *
46  *                                                                            *
47  * Author: Eugene Grigorjev                                                   *
48  *                                                                            *
49  * Comments:  title_message - is global variable which must be initialized    *
50  *                            in each zabbix application                      *
51  *                                                                            *
52  ******************************************************************************/
version(void)53 void	version(void)
54 {
55 	printf("%s (Zabbix) %s\n", title_message, ZABBIX_VERSION);
56 	printf("Revision %s %s, compilation time: %s %s\n\n", ZABBIX_REVISION, ZABBIX_REVDATE, __DATE__, __TIME__);
57 	puts(copyright_message);
58 #if defined(HAVE_POLARSSL) || defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL)
59 	printf("\n");
60 	zbx_tls_version();
61 #endif
62 }
63 
64 /******************************************************************************
65  *                                                                            *
66  * Function: usage                                                            *
67  *                                                                            *
68  * Purpose: print application parameters on stdout with layout suitable for   *
69  *          80-column terminal                                                *
70  *                                                                            *
71  * Author: Eugene Grigorjev                                                   *
72  *                                                                            *
73  * Comments:  usage_message - is global variable which must be initialized    *
74  *                            in each zabbix application                      *
75  *                                                                            *
76  ******************************************************************************/
usage(void)77 void	usage(void)
78 {
79 #define ZBX_MAXCOL	79
80 #define ZBX_SPACE1	"  "			/* left margin for the first line */
81 #define ZBX_SPACE2	"               "	/* left margin for subsequent lines */
82 	const char	**p = usage_message;
83 
84 	if (NULL != *p)
85 		printf("usage:\n");
86 
87 	while (NULL != *p)
88 	{
89 		size_t	pos;
90 
91 		printf("%s%s", ZBX_SPACE1, progname);
92 		pos = ZBX_CONST_STRLEN(ZBX_SPACE1) + strlen(progname);
93 
94 		while (NULL != *p)
95 		{
96 			size_t	len;
97 
98 			len = strlen(*p);
99 
100 			if (ZBX_MAXCOL > pos + len)
101 			{
102 				pos += len + 1;
103 				printf(" %s", *p);
104 			}
105 			else
106 			{
107 				pos = ZBX_CONST_STRLEN(ZBX_SPACE2) + len + 1;
108 				printf("\n%s %s", ZBX_SPACE2, *p);
109 			}
110 
111 			p++;
112 		}
113 
114 		printf("\n");
115 		p++;
116 	}
117 #undef ZBX_MAXCOL
118 #undef ZBX_SPACE1
119 #undef ZBX_SPACE2
120 }
121 
122 /******************************************************************************
123  *                                                                            *
124  * Function: help                                                             *
125  *                                                                            *
126  * Purpose: print help of application parameters on stdout by application     *
127  *          request with parameter '-h'                                       *
128  *                                                                            *
129  * Author: Eugene Grigorjev                                                   *
130  *                                                                            *
131  * Comments:  help_message - is global variable which must be initialized     *
132  *                            in each zabbix application                      *
133  *                                                                            *
134  ******************************************************************************/
help(void)135 void	help(void)
136 {
137 	const char	**p = help_message;
138 
139 	usage();
140 	printf("\n");
141 
142 	while (NULL != *p)
143 		printf("%s\n", *p++);
144 
145 	printf("\n");
146 	puts(help_message_footer);
147 }
148 
149 /******************************************************************************
150  *                                                                            *
151  * Function: zbx_error                                                        *
152  *                                                                            *
153  * Purpose: Print error text to the stderr                                    *
154  *                                                                            *
155  * Parameters: fmt - format of message                                        *
156  *                                                                            *
157  * Return value:                                                              *
158  *                                                                            *
159  * Author: Eugene Grigorjev                                                   *
160  *                                                                            *
161  ******************************************************************************/
__zbx_zbx_error(const char * fmt,...)162 void	__zbx_zbx_error(const char *fmt, ...)
163 {
164 	va_list	args;
165 
166 	va_start(args, fmt);
167 
168 	fprintf(stderr, "%s [%li]: ", progname, zbx_get_thread_id());
169 	vfprintf(stderr, fmt, args);
170 	fprintf(stderr, "\n");
171 	fflush(stderr);
172 
173 	va_end(args);
174 }
175 
176 /******************************************************************************
177  *                                                                            *
178  * Function: zbx_snprintf                                                     *
179  *                                                                            *
180  * Purpose: Secure version of snprintf function.                              *
181  *          Add zero character at the end of string.                          *
182  *                                                                            *
183  * Parameters: str - destination buffer pointer                               *
184  *             count - size of destination buffer                             *
185  *             fmt - format                                                   *
186  *                                                                            *
187  * Return value:                                                              *
188  *                                                                            *
189  * Author: Eugene Grigorjev                                                   *
190  *                                                                            *
191  ******************************************************************************/
__zbx_zbx_snprintf(char * str,size_t count,const char * fmt,...)192 size_t	__zbx_zbx_snprintf(char *str, size_t count, const char *fmt, ...)
193 {
194 	size_t	written_len;
195 	va_list	args;
196 
197 	va_start(args, fmt);
198 	written_len = zbx_vsnprintf(str, count, fmt, args);
199 	va_end(args);
200 
201 	return written_len;
202 }
203 
204 /******************************************************************************
205  *                                                                            *
206  * Function: zbx_snprintf_alloc                                               *
207  *                                                                            *
208  * Purpose: Secure version of snprintf function.                              *
209  *          Add zero character at the end of string.                          *
210  *          Reallocs memory if not enough.                                    *
211  *                                                                            *
212  * Parameters: str       - [IN/OUT] destination buffer pointer                *
213  *             alloc_len - [IN/OUT] already allocated memory                  *
214  *             offset    - [IN/OUT] offset for writing                        *
215  *             fmt       - [IN] format                                        *
216  *                                                                            *
217  * Return value:                                                              *
218  *                                                                            *
219  * Author: Alexei Vladishev, Alexander Vladishev                              *
220  *                                                                            *
221  ******************************************************************************/
__zbx_zbx_snprintf_alloc(char ** str,size_t * alloc_len,size_t * offset,const char * fmt,...)222 void	__zbx_zbx_snprintf_alloc(char **str, size_t *alloc_len, size_t *offset, const char *fmt, ...)
223 {
224 	va_list	args;
225 	size_t	avail_len, written_len;
226 retry:
227 	if (NULL == *str)
228 	{
229 		/* zbx_vsnprintf() returns bytes actually written instead of bytes to write, */
230 		/* so we have to use the standard function                                   */
231 		va_start(args, fmt);
232 		*alloc_len = vsnprintf(NULL, 0, fmt, args) + 2;	/* '\0' + one byte to prevent the operation retry */
233 		va_end(args);
234 		*offset = 0;
235 		*str = zbx_malloc(*str, *alloc_len);
236 	}
237 
238 	avail_len = *alloc_len - *offset;
239 	va_start(args, fmt);
240 	written_len = zbx_vsnprintf(*str + *offset, avail_len, fmt, args);
241 	va_end(args);
242 
243 	if (written_len == avail_len - 1)
244 	{
245 		*alloc_len *= 2;
246 		*str = zbx_realloc(*str, *alloc_len);
247 
248 		goto retry;
249 	}
250 
251 	*offset += written_len;
252 }
253 
254 /******************************************************************************
255  *                                                                            *
256  * Function: zbx_vsnprintf                                                    *
257  *                                                                            *
258  * Purpose: Secure version of vsnprintf function.                             *
259  *          Add zero character at the end of string.                          *
260  *                                                                            *
261  * Parameters: str   - [IN/OUT] destination buffer pointer                    *
262  *             count - [IN] size of destination buffer                        *
263  *             fmt   - [IN] format                                            *
264  *                                                                            *
265  * Return value: the number of characters in the output buffer                *
266  *               (not including the trailing '\0')                            *
267  *                                                                            *
268  * Author: Alexei Vladishev (see also zbx_snprintf)                           *
269  *                                                                            *
270  ******************************************************************************/
zbx_vsnprintf(char * str,size_t count,const char * fmt,va_list args)271 size_t	zbx_vsnprintf(char *str, size_t count, const char *fmt, va_list args)
272 {
273 	int	written_len = 0;
274 
275 	if (0 < count)
276 	{
277 		if (0 > (written_len = vsnprintf(str, count, fmt, args)))
278 			written_len = (int)count - 1;		/* count an output error as a full buffer */
279 		else
280 			written_len = MIN(written_len, (int)count - 1);		/* result could be truncated */
281 	}
282 	str[written_len] = '\0';	/* always write '\0', even if buffer size is 0 or vsnprintf() error */
283 
284 	return (size_t)written_len;
285 }
286 
287 /******************************************************************************
288  *                                                                            *
289  * Function: zbx_strncpy_alloc, zbx_strcpy_alloc, zbx_chrcpy_alloc            *
290  *                                                                            *
291  * Purpose: If there is no '\0' byte among the first n bytes of src,          *
292  *          then all n bytes will be placed into the dest buffer.             *
293  *          In other case only strlen() bytes will be placed there.           *
294  *          Add zero character at the end of string.                          *
295  *          Reallocs memory if not enough.                                    *
296  *                                                                            *
297  * Parameters: str       - [IN/OUT] destination buffer pointer                *
298  *             alloc_len - [IN/OUT] already allocated memory                  *
299  *             offset    - [IN/OUT] offset for writing                        *
300  *             src       - [IN] copied string                                 *
301  *             n         - [IN] maximum number of bytes to copy               *
302  *                                                                            *
303  * Author: Alexander Vladishev                                                *
304  *                                                                            *
305  ******************************************************************************/
zbx_strncpy_alloc(char ** str,size_t * alloc_len,size_t * offset,const char * src,size_t n)306 void	zbx_strncpy_alloc(char **str, size_t *alloc_len, size_t *offset, const char *src, size_t n)
307 {
308 	if (NULL == *str)
309 	{
310 		*alloc_len = n + 1;
311 		*offset = 0;
312 		*str = zbx_malloc(*str, *alloc_len);
313 	}
314 	else if (*offset + n >= *alloc_len)
315 	{
316 		while (*offset + n >= *alloc_len)
317 			*alloc_len *= 2;
318 		*str = zbx_realloc(*str, *alloc_len);
319 	}
320 
321 	while (0 != n && '\0' != *src)
322 	{
323 		(*str)[(*offset)++] = *src++;
324 		n--;
325 	}
326 
327 	(*str)[*offset] = '\0';
328 }
329 
zbx_strcpy_alloc(char ** str,size_t * alloc_len,size_t * offset,const char * src)330 void	zbx_strcpy_alloc(char **str, size_t *alloc_len, size_t *offset, const char *src)
331 {
332 	zbx_strncpy_alloc(str, alloc_len, offset, src, strlen(src));
333 }
334 
zbx_chrcpy_alloc(char ** str,size_t * alloc_len,size_t * offset,char c)335 void	zbx_chrcpy_alloc(char **str, size_t *alloc_len, size_t *offset, char c)
336 {
337 	zbx_strncpy_alloc(str, alloc_len, offset, &c, 1);
338 }
339 
340 /* Has to be rewritten to avoid malloc */
string_replace(const char * str,const char * sub_str1,const char * sub_str2)341 char	*string_replace(const char *str, const char *sub_str1, const char *sub_str2)
342 {
343 	char *new_str = NULL;
344 	const char *p;
345 	const char *q;
346 	const char *r;
347 	char *t;
348 	long len;
349 	long diff;
350 	unsigned long count = 0;
351 
352 	assert(str);
353 	assert(sub_str1);
354 	assert(sub_str2);
355 
356 	len = (long)strlen(sub_str1);
357 
358 	/* count the number of occurrences of sub_str1 */
359 	for ( p=str; (p = strstr(p, sub_str1)); p+=len, count++ );
360 
361 	if ( 0 == count )	return strdup(str);
362 
363 	diff = (long)strlen(sub_str2) - len;
364 
365         /* allocate new memory */
366         new_str = zbx_malloc(new_str, (size_t)(strlen(str) + count*diff + 1)*sizeof(char));
367 
368         for (q=str,t=new_str,p=str; (p = strstr(p, sub_str1)); )
369         {
370                 /* copy until next occurrence of sub_str1 */
371                 for ( ; q < p; *t++ = *q++);
372                 q += len;
373                 p = q;
374                 for ( r = sub_str2; (*t++ = *r++); );
375                 --t;
376         }
377         /* copy the tail of str */
378         for( ; *q ; *t++ = *q++ );
379 
380 	*t = '\0';
381 
382 	return new_str;
383 }
384 
385 /******************************************************************************
386  *                                                                            *
387  * Function: del_zeroes                                                       *
388  *                                                                            *
389  * Purpose: delete all right '0' and '.' for the string                       *
390  *                                                                            *
391  * Parameters: s - string to trim '0'                                         *
392  *                                                                            *
393  * Return value: string without right '0'                                     *
394  *                                                                            *
395  * Author: Alexei Vladishev                                                   *
396  *                                                                            *
397  * Comments: 10.0100 => 10.01, 10. => 10                                      *
398  *                                                                            *
399  ******************************************************************************/
del_zeroes(char * s)400 void	del_zeroes(char *s)
401 {
402 	int	trim = 0;
403 	size_t	len = 0;
404 
405 	while ('\0' != s[len])
406 	{
407 		if ('e' == s[len] || 'E' == s[len])
408 		{
409 			/* don't touch numbers that are written in scientific notation */
410 			return;
411 		}
412 
413 		if ('.' == s[len])
414 		{
415 			/* number has decimal part */
416 			trim = 1;
417 		}
418 
419 		len++;
420 	}
421 
422 	if (1 == trim)
423 	{
424 		size_t	i;
425 
426 		for (i = len - 1; ; i--)
427 		{
428 			if ('0' == s[i])
429 			{
430 				s[i] = '\0';
431 			}
432 			else if ('.' == s[i])
433 			{
434 				s[i] = '\0';
435 				break;
436 			}
437 			else
438 			{
439 				break;
440 			}
441 		}
442 	}
443 }
444 
445 /******************************************************************************
446  *                                                                            *
447  * Function: zbx_rtrim                                                        *
448  *                                                                            *
449  * Purpose: Strip characters from the end of a string                         *
450  *                                                                            *
451  * Parameters: str - string for processing                                    *
452  *             charlist - null terminated list of characters                  *
453  *                                                                            *
454  * Return value: number of trimmed characters                                 *
455  *                                                                            *
456  * Author: Eugene Grigorjev, Aleksandrs Saveljevs                             *
457  *                                                                            *
458  ******************************************************************************/
zbx_rtrim(char * str,const char * charlist)459 int	zbx_rtrim(char *str, const char *charlist)
460 {
461 	char	*p;
462 	int	count = 0;
463 
464 	if (NULL == str || '\0' == *str)
465 		return count;
466 
467 	for (p = str + strlen(str) - 1; p >= str && NULL != strchr(charlist, *p); p--)
468 	{
469 		*p = '\0';
470 		count++;
471 	}
472 
473 	return count;
474 }
475 
476 /******************************************************************************
477  *                                                                            *
478  * Function: zbx_ltrim                                                        *
479  *                                                                            *
480  * Purpose: Strip characters from the beginning of a string                   *
481  *                                                                            *
482  * Parameters: str - string for processing                                    *
483  *             charlist - null terminated list of characters                  *
484  *                                                                            *
485  * Return value:                                                              *
486  *                                                                            *
487  * Author: Eugene Grigorjev                                                   *
488  *                                                                            *
489  ******************************************************************************/
zbx_ltrim(char * str,const char * charlist)490 void	zbx_ltrim(char *str, const char *charlist)
491 {
492 	char	*p;
493 
494 	if (NULL == str || '\0' == *str)
495 		return;
496 
497 	for (p = str; '\0' != *p && NULL != strchr(charlist, *p); p++)
498 		;
499 
500 	if (p == str)
501 		return;
502 
503 	while ('\0' != *p)
504 		*str++ = *p++;
505 
506 	*str = '\0';
507 }
508 
509 /******************************************************************************
510  *                                                                            *
511  * Function: zbx_lrtrim                                                       *
512  *                                                                            *
513  * Purpose: Removes leading and trailing characters from the specified        *
514  *          character string                                                  *
515  *                                                                            *
516  * Parameters: str      - [IN/OUT] string for processing                      *
517  *             charlist - [IN] null terminated list of characters             *
518  *                                                                            *
519  ******************************************************************************/
zbx_lrtrim(char * str,const char * charlist)520 void	zbx_lrtrim(char *str, const char *charlist)
521 {
522 	zbx_rtrim(str, charlist);
523 	zbx_ltrim(str, charlist);
524 }
525 
526 /******************************************************************************
527  *                                                                            *
528  * Function: zbx_remove_chars                                                 *
529  *                                                                            *
530  * Purpose: Remove characters 'charlist' from the whole string                *
531  *                                                                            *
532  * Parameters: str - string for processing                                    *
533  *             charlist - null terminated list of characters                  *
534  *                                                                            *
535  * Return value:                                                              *
536  *                                                                            *
537  * Author: Alexander Vladishev                                                *
538  *                                                                            *
539  ******************************************************************************/
zbx_remove_chars(register char * str,const char * charlist)540 void	zbx_remove_chars(register char *str, const char *charlist)
541 {
542 	register char *p;
543 
544 	if (NULL == str || NULL == charlist || '\0' == *str || '\0' == *charlist)
545 		return;
546 
547 	for (p = str; '\0' != *p; p++)
548 	{
549 		if (NULL == strchr(charlist, *p))
550 			*str++ = *p;
551 	}
552 
553 	*str = '\0';
554 }
555 
556 /******************************************************************************
557  *                                                                            *
558  * Function: zbx_strlcpy                                                      *
559  *                                                                            *
560  * Purpose: Copy src to string dst of size siz. At most siz - 1 characters    *
561  *          will be copied. Always null terminates (unless siz == 0).         *
562  *                                                                            *
563  * Return value: the number of characters copied (excluding the null byte)    *
564  *                                                                            *
565  ******************************************************************************/
zbx_strlcpy(char * dst,const char * src,size_t siz)566 size_t	zbx_strlcpy(char *dst, const char *src, size_t siz)
567 {
568 	const char	*s = src;
569 
570 	if (0 != siz)
571 	{
572 		while (0 != --siz && '\0' != *s)
573 			*dst++ = *s++;
574 
575 		*dst = '\0';
576 	}
577 
578 	return s - src;	/* count does not include null */
579 }
580 
581 /******************************************************************************
582  *                                                                            *
583  * Function: zbx_strlcat                                                      *
584  *                                                                            *
585  * Purpose: Appends src to string dst of size siz (unlike strncat, size is    *
586  *          the full size of dst, not space left). At most siz - 1 characters *
587  *          will be copied. Always null terminates (unless                    *
588  *          siz <= strlen(dst)).                                              *
589  *                                                                            *
590  ******************************************************************************/
zbx_strlcat(char * dst,const char * src,size_t siz)591 void	zbx_strlcat(char *dst, const char *src, size_t siz)
592 {
593 	while ('\0' != *dst)
594 	{
595 		dst++;
596 		siz--;
597 	}
598 
599 	zbx_strlcpy(dst, src, siz);
600 }
601 
602 /******************************************************************************
603  *                                                                            *
604  * Function: zbx_strlcpy_utf8                                                 *
605  *                                                                            *
606  * Purpose: copies utf-8 string + terminating zero character into specified   *
607  *          buffer                                                            *
608  *                                                                            *
609  * Return value: the number of copied bytes excluding terminating zero        *
610  *               character.                                                   *
611  *                                                                            *
612  * Comments: If the source string is larger than destination buffer then the  *
613  *           string is truncated after last valid utf-8 character rather than *
614  *           byte.                                                            *
615  *                                                                            *
616  ******************************************************************************/
zbx_strlcpy_utf8(char * dst,const char * src,size_t size)617 size_t	zbx_strlcpy_utf8(char *dst, const char *src, size_t size)
618 {
619 	size = zbx_strlen_utf8_nbytes(src, size - 1);
620 	memcpy(dst, src, size);
621 	dst[size] = '\0';
622 
623 	return size;
624 }
625 
626 /******************************************************************************
627  *                                                                            *
628  * Function: zbx_dvsprintf                                                    *
629  *                                                                            *
630  * Purpose: dynamical formatted output conversion                             *
631  *                                                                            *
632  * Return value: formatted string                                             *
633  *                                                                            *
634  * Author: Eugene Grigorjev                                                   *
635  *                                                                            *
636  * Comments: returns a pointer to allocated memory                            *
637  *                                                                            *
638  ******************************************************************************/
zbx_dvsprintf(char * dest,const char * f,va_list args)639 char	*zbx_dvsprintf(char *dest, const char *f, va_list args)
640 {
641 	char	*string = NULL;
642 	int	n, size = MAX_STRING_LEN >> 1;
643 
644 	va_list curr;
645 
646 	while (1)
647 	{
648 		string = zbx_malloc(string, size);
649 
650 		va_copy(curr, args);
651 		n = vsnprintf(string, size, f, curr);
652 		va_end(curr);
653 
654 		if (0 <= n && n < size)
655 			break;
656 
657 		/* result was truncated */
658 		if (-1 == n)
659 			size = size * 3 / 2 + 1;	/* the length is unknown */
660 		else
661 			size = n + 1;	/* n bytes + trailing '\0' */
662 
663 		zbx_free(string);
664 	}
665 
666 	zbx_free(dest);
667 
668 	return string;
669 }
670 
671 /******************************************************************************
672  *                                                                            *
673  * Function: zbx_dsprintf                                                     *
674  *                                                                            *
675  * Purpose: dynamical formatted output conversion                             *
676  *                                                                            *
677  * Return value: formatted string                                             *
678  *                                                                            *
679  * Author: Eugene Grigorjev                                                   *
680  *                                                                            *
681  * Comments: returns a pointer to allocated memory                            *
682  *                                                                            *
683  ******************************************************************************/
__zbx_zbx_dsprintf(char * dest,const char * f,...)684 char	*__zbx_zbx_dsprintf(char *dest, const char *f, ...)
685 {
686 	char	*string;
687 	va_list args;
688 
689 	va_start(args, f);
690 
691 	string = zbx_dvsprintf(dest, f, args);
692 
693 	va_end(args);
694 
695 	return string;
696 }
697 
698 /******************************************************************************
699  *                                                                            *
700  * Function: zbx_strdcat                                                      *
701  *                                                                            *
702  * Purpose: dynamical cating of strings                                       *
703  *                                                                            *
704  * Return value: new pointer of string                                        *
705  *                                                                            *
706  * Author: Eugene Grigorjev                                                   *
707  *                                                                            *
708  * Comments: returns a pointer to allocated memory                            *
709  *           zbx_strdcat(NULL, "") will return "", not NULL!                  *
710  *                                                                            *
711  ******************************************************************************/
zbx_strdcat(char * dest,const char * src)712 char	*zbx_strdcat(char *dest, const char *src)
713 {
714 	size_t	len_dest, len_src;
715 
716 	if (NULL == src)
717 		return dest;
718 
719 	if (NULL == dest)
720 		return zbx_strdup(NULL, src);
721 
722 	len_dest = strlen(dest);
723 	len_src = strlen(src);
724 
725 	dest = zbx_realloc(dest, len_dest + len_src + 1);
726 
727 	zbx_strlcpy(dest + len_dest, src, len_src + 1);
728 
729 	return dest;
730 }
731 
732 /******************************************************************************
733  *                                                                            *
734  * Function: zbx_strdcatf                                                     *
735  *                                                                            *
736  * Purpose: dynamical cating of formated strings                              *
737  *                                                                            *
738  * Return value: new pointer of string                                        *
739  *                                                                            *
740  * Author: Eugene Grigorjev                                                   *
741  *                                                                            *
742  * Comments: returns a pointer to allocated memory                            *
743  *                                                                            *
744  ******************************************************************************/
__zbx_zbx_strdcatf(char * dest,const char * f,...)745 char	*__zbx_zbx_strdcatf(char *dest, const char *f, ...)
746 {
747 	char	*string, *result;
748 	va_list	args;
749 
750 	va_start(args, f);
751 	string = zbx_dvsprintf(NULL, f, args);
752 	va_end(args);
753 
754 	result = zbx_strdcat(dest, string);
755 
756 	zbx_free(string);
757 
758 	return result;
759 }
760 
761 /******************************************************************************
762  *                                                                            *
763  * Function: zbx_check_hostname                                               *
764  *                                                                            *
765  * Purpose: check a byte stream for a valid hostname                          *
766  *                                                                            *
767  * Parameters: hostname - pointer to the first char of hostname               *
768  *             error - pointer to the error message (can be NULL)             *
769  *                                                                            *
770  * Return value: return SUCCEED if hostname is valid                          *
771  *               or FAIL if hostname contains invalid chars, is empty         *
772  *               or is longer than MAX_ZBX_HOSTNAME_LEN                       *
773  *                                                                            *
774  * Author: Alexander Vladishev                                                *
775  *                                                                            *
776  ******************************************************************************/
zbx_check_hostname(const char * hostname,char ** error)777 int	zbx_check_hostname(const char *hostname, char **error)
778 {
779 	int	len = 0;
780 
781 	while ('\0' != hostname[len])
782 	{
783 		if (FAIL == is_hostname_char(hostname[len]))
784 		{
785 			if (NULL != error)
786 				*error = zbx_dsprintf(NULL, "name contains invalid character '%c'", hostname[len]);
787 			return FAIL;
788 		}
789 
790 		len++;
791 	}
792 
793 	if (0 == len)
794 	{
795 		if (NULL != error)
796 			*error = zbx_strdup(NULL, "name is empty");
797 		return FAIL;
798 	}
799 
800 	if (MAX_ZBX_HOSTNAME_LEN < len)
801 	{
802 		if (NULL != error)
803 			*error = zbx_dsprintf(NULL, "name is too long (max %d characters)", MAX_ZBX_HOSTNAME_LEN);
804 		return FAIL;
805 	}
806 
807 	return SUCCEED;
808 }
809 
810 /******************************************************************************
811  *                                                                            *
812  * Function: get_item_key                                                     *
813  *                                                                            *
814  * Purpose: return key with parameters (if present)                           *
815  *                                                                            *
816  *  e.g., system.run[cat /etc/passwd | awk -F: '{ print $1 }']                *
817  *                                                                            *
818  * Parameters: exp - [IN] pointer to the first char of key                    *
819  *             key - [OUT] pointer to the resulted key                        *
820  *                                                                            *
821  *  e.g., {host:system.run[cat /etc/passwd | awk -F: '{ print $1 }'].last(0)} *
822  *              ^                                                             *
823  *                                                                            *
824  * Return value: return SUCCEED and move exp to the next character after key  *
825  *               or FAIL and move exp to incorrect character                  *
826  *                                                                            *
827  * Notes: implements the functionality of old parse_key() in a safe manner.   *
828  *        input pointer is NOT advanced.                                      *
829  *                                                                            *
830  ******************************************************************************/
get_item_key(char ** exp,char ** key)831 int	get_item_key(char **exp, char **key)
832 {
833 	char	*p = *exp, c;
834 
835 	if (SUCCEED != parse_key(&p))
836 		return FAIL;
837 
838 	if ('(' == *p)
839 	{
840 		for (p--; *exp < p && '.' != *p; p--)
841 			;
842 
843 		if (*exp == p)	/* the key is empty */
844 			return FAIL;
845 	}
846 
847 	c = *p;
848 	*p = '\0';
849 	*key = zbx_strdup(NULL, *exp);
850 	*p = c;
851 
852 	*exp = p;
853 
854 	return SUCCEED;
855 }
856 
857 /******************************************************************************
858  *                                                                            *
859  * Function: parse_host                                                       *
860  *                                                                            *
861  * Purpose: parse hostname                                                    *
862  *                                                                            *
863  *  e.g., Zabbix server                                                       *
864  *                                                                            *
865  * Parameters: exp - pointer to the first char of hostname                    *
866  *             host - optional pointer to resulted hostname                   *
867  *                                                                            *
868  *  e.g., {Zabbix server:agent.ping.last(0)}                                  *
869  *         ^                                                                  *
870  *                                                                            *
871  * Return value: return SUCCEED and move exp to the next char after hostname  *
872  *               or FAIL and move exp at the failed character                 *
873  *                                                                            *
874  * Author: Aleksandrs Saveljevs                                               *
875  *                                                                            *
876  ******************************************************************************/
parse_host(char ** exp,char ** host)877 int	parse_host(char **exp, char **host)
878 {
879 	char	*p, *s;
880 
881 	p = *exp;
882 
883 	for (s = *exp; SUCCEED == is_hostname_char(*s); s++)
884 		;
885 
886 	*exp = s;
887 
888 	if (p == s)
889 		return FAIL;
890 
891 	if (NULL != host)
892 	{
893 		char	c;
894 
895 		c = *s;
896 		*s = '\0';
897 		*host = strdup(p);
898 		*s = c;
899 	}
900 
901 	return SUCCEED;
902 }
903 
904 /******************************************************************************
905  *                                                                            *
906  * Function: parse_key                                                        *
907  *                                                                            *
908  * Purpose: advances pointer to first invalid character in string             *
909  *          ensuring that everything before it is a valid key                 *
910  *                                                                            *
911  *  e.g., system.run[cat /etc/passwd | awk -F: '{ print $1 }']                *
912  *                                                                            *
913  * Parameters: exp - [IN/OUT] pointer to the first char of key                *
914  *                                                                            *
915  *  e.g., {host:system.run[cat /etc/passwd | awk -F: '{ print $1 }'].last(0)} *
916  *              ^                                                             *
917  * Return value: returns FAIL only if no key is present (length 0),           *
918  *               or the whole string is invalid. SUCCEED otherwise.           *
919  *                                                                            *
920  * Author: Aleksandrs Saveljevs                                               *
921  *                                                                            *
922  ******************************************************************************/
parse_key(char ** exp)923 int	parse_key(char **exp)
924 {
925 	char	*s;
926 
927 	for (s = *exp; SUCCEED == is_key_char(*s); s++)
928 		;
929 
930 	if (*exp == s)	/* the key is empty */
931 		return FAIL;
932 
933 	if ('[' == *s)	/* for instance, net.tcp.port[,80] */
934 	{
935 		int	state = 0;	/* 0 - init, 1 - inside quoted param, 2 - inside unquoted param */
936 		int	array = 0;	/* array nest level */
937 
938 		for (s++; '\0' != *s; s++)
939 		{
940 			switch (state)
941 			{
942 				/* init state */
943 				case 0:
944 					if (',' == *s)
945 						;
946 					else if (']' == *s && '[' == s[1] && 0 == array)	/* Zapcat */
947 						s++;
948 					else if ('"' == *s)
949 						state = 1;
950 					else if ('[' == *s)
951 						array++;
952 					else if (']' == *s && 0 != array)
953 					{
954 						array--;
955 
956 						/* skip spaces */
957 						while (' ' == s[1])
958 							s++;
959 
960 						if (0 == array && ']' == s[1])
961 						{
962 							s++;
963 							goto succeed;
964 						}
965 
966 						if (',' != s[1] && !(0 != array && ']' == s[1]))
967 						{
968 							s++;
969 							goto fail;	/* incorrect syntax */
970 						}
971 					}
972 					else if (']' == *s && 0 == array)
973 						goto succeed;
974 					else if (' ' != *s)
975 						state = 2;
976 					break;
977 				/* quoted */
978 				case 1:
979 					if ('"' == *s)
980 					{
981 						/* skip spaces */
982 						while (' ' == s[1])
983 							s++;
984 
985 						if (0 == array && ']' == s[1] && '[' == s[2])	/* Zapcat */
986 						{
987 							state = 0;
988 							break;
989 						}
990 
991 						if (0 == array && ']' == s[1])
992 						{
993 							s++;
994 							goto succeed;
995 						}
996 
997 						if (',' != s[1] && !(0 != array && ']' == s[1]))
998 						{
999 							s++;
1000 							goto fail;	/* incorrect syntax */
1001 						}
1002 
1003 						state = 0;
1004 					}
1005 					else if ('\\' == *s && '"' == s[1])
1006 						s++;
1007 					break;
1008 				/* unquoted */
1009 				case 2:
1010 					if (0 == array && ']' == *s && '[' == s[1])	/* Zapcat */
1011 					{
1012 						s--;
1013 						state = 0;
1014 					}
1015 					else if (',' == *s || (']' == *s && 0 != array))
1016 					{
1017 						s--;
1018 						state = 0;
1019 					}
1020 					else if (']' == *s && 0 == array)
1021 						goto succeed;
1022 					break;
1023 			}
1024 		}
1025 fail:
1026 		*exp = s;
1027 		return FAIL;
1028 succeed:
1029 		s++;
1030 	}
1031 
1032 	*exp = s;
1033 	return SUCCEED;
1034 }
1035 
1036 /******************************************************************************
1037  *                                                                            *
1038  * Function: parse_host_key                                                   *
1039  *                                                                            *
1040  * Purpose: return hostname and key                                           *
1041  *          <hostname:>key                                                    *
1042  *                                                                            *
1043  * Parameters:                                                                *
1044  *         exp - pointer to the first char of hostname                        *
1045  *                host:key[key params]                                        *
1046  *                ^                                                           *
1047  *                                                                            *
1048  * Return value: return SUCCEED or FAIL                                       *
1049  *                                                                            *
1050  * Author: Alexander Vladishev                                                *
1051  *                                                                            *
1052  ******************************************************************************/
parse_host_key(char * exp,char ** host,char ** key)1053 int	parse_host_key(char *exp, char **host, char **key)
1054 {
1055 	char	*p, *s;
1056 
1057 	if (NULL == exp || '\0' == *exp)
1058 		return FAIL;
1059 
1060 	for (p = exp, s = exp; '\0' != *p; p++)	/* check for optional hostname */
1061 	{
1062 		if (':' == *p)	/* hostname:vfs.fs.size[/,total]
1063 				 * --------^
1064 				 */
1065 		{
1066 			*p = '\0';
1067 			*host = zbx_strdup(NULL, s);
1068 			*p++ = ':';
1069 
1070 			s = p;
1071 			break;
1072 		}
1073 
1074 		if (SUCCEED != is_hostname_char(*p))
1075 			break;
1076 	}
1077 
1078 	*key = zbx_strdup(NULL, s);
1079 
1080 	return SUCCEED;
1081 }
1082 
1083 /******************************************************************************
1084  *                                                                            *
1085  * Function: num_param                                                        *
1086  *                                                                            *
1087  * Purpose: calculate count of parameters from parameter list (param)         *
1088  *                                                                            *
1089  * Parameters:                                                                *
1090  *      param  - parameter list                                               *
1091  *                                                                            *
1092  * Return value: count of parameters                                          *
1093  *                                                                            *
1094  * Author: Alexei Vladishev                                                   *
1095  *                                                                            *
1096  * Comments:  delimeter for parameters is ','                                 *
1097  *                                                                            *
1098  ******************************************************************************/
num_param(const char * p)1099 int	num_param(const char *p)
1100 {
1101 /* 0 - init, 1 - inside quoted param, 2 - inside unquoted param */
1102 	int	ret = 1, state, array;
1103 
1104 	if (p == NULL)
1105 		return 0;
1106 
1107 	for (state = 0, array = 0; '\0' != *p; p++)
1108 	{
1109 		switch (state) {
1110 		/* Init state */
1111 		case 0:
1112 			if (',' == *p)
1113 			{
1114 				if (0 == array)
1115 					ret++;
1116 			}
1117 			else if ('"' == *p)
1118 				state = 1;
1119 			else if ('[' == *p)
1120 				array++;
1121 			else if (']' == *p && 0 != array)
1122 			{
1123 				array--;
1124 
1125 				/* skip spaces */
1126 				while (' ' == p[1])
1127 					p++;
1128 
1129 				if (',' != p[1] && '\0' != p[1] && (0 == array || ']' != p[1]))
1130 					return 0;	/* incorrect syntax */
1131 			}
1132 			else if (' ' != *p)
1133 				state = 2;
1134 			break;
1135 		/* Quoted */
1136 		case 1:
1137 			if ('"' == *p)
1138 			{
1139 				/* skip spaces */
1140 				while (' ' == p[1])
1141 					p++;
1142 
1143 				if (',' != p[1] && '\0' != p[1] && (0 == array || ']' != p[1]))
1144 					return 0;	/* incorrect syntax */
1145 
1146 				state = 0;
1147 			}
1148 			else if ('\\' == *p && '"' == p[1])
1149 				p++;
1150 			break;
1151 		/* Unquoted */
1152 		case 2:
1153 			if (',' == *p || (']' == *p && 0 != array))
1154 			{
1155 				p--;
1156 				state = 0;
1157 			}
1158 			break;
1159 		}
1160 	}
1161 
1162 	/* missing terminating '"' character */
1163 	if (state == 1)
1164 		return 0;
1165 
1166 	/* missing terminating ']' character */
1167 	if (array != 0)
1168 		return 0;
1169 
1170 	return ret;
1171 }
1172 
1173 /******************************************************************************
1174  *                                                                            *
1175  * Function: get_param                                                        *
1176  *                                                                            *
1177  * Purpose: return parameter by index (num) from parameter list (param)       *
1178  *                                                                            *
1179  * Parameters:                                                                *
1180  *      p       - parameter list                                              *
1181  *      num     - requested parameter index                                   *
1182  *      buf     - pointer of output buffer                                    *
1183  *      max_len - size of output buffer                                       *
1184  *                                                                            *
1185  * Return value:                                                              *
1186  *      1 - requested parameter missing or buffer overflow                    *
1187  *      0 - requested parameter found (value - 'buf' can be empty string)     *
1188  *                                                                            *
1189  * Author: Eugene Grigorjev, rewritten by Alexei Vladishev                    *
1190  *                                                                            *
1191  * Comments:  delimeter for parameters is ','                                 *
1192  *                                                                            *
1193  ******************************************************************************/
get_param(const char * p,int num,char * buf,size_t max_len)1194 int	get_param(const char *p, int num, char *buf, size_t max_len)
1195 {
1196 #define ZBX_ASSIGN_PARAM				\
1197 {							\
1198 	if (buf_i == max_len)				\
1199 		return 1;	/* buffer overflow */	\
1200 	buf[buf_i++] = *p;				\
1201 }
1202 
1203 	int	state;	/* 0 - init, 1 - inside quoted param, 2 - inside unquoted param */
1204 	int	array, idx = 1;
1205 	size_t	buf_i = 0;
1206 
1207 	if (0 == max_len)
1208 		return 1;	/* buffer overflow */
1209 
1210 	max_len--;	/* '\0' */
1211 
1212 	for (state = 0, array = 0; '\0' != *p && idx <= num; p++)
1213 	{
1214 		switch (state)
1215 		{
1216 			/* init state */
1217 			case 0:
1218 				if (',' == *p)
1219 				{
1220 					if (0 == array)
1221 						idx++;
1222 					else if (idx == num)
1223 						ZBX_ASSIGN_PARAM;
1224 				}
1225 				else if ('"' == *p)
1226 				{
1227 					state = 1;
1228 					if (0 != array && idx == num)
1229 						ZBX_ASSIGN_PARAM;
1230 				}
1231 				else if ('[' == *p)
1232 				{
1233 					if (0 != array && idx == num)
1234 						ZBX_ASSIGN_PARAM;
1235 					array++;
1236 				}
1237 				else if (']' == *p && 0 != array)
1238 				{
1239 					array--;
1240 					if (0 != array && idx == num)
1241 						ZBX_ASSIGN_PARAM;
1242 
1243 					/* skip spaces */
1244 					while (' ' == p[1])
1245 						p++;
1246 
1247 					if (',' != p[1] && '\0' != p[1] && (0 == array || ']' != p[1]))
1248 						return 1;	/* incorrect syntax */
1249 				}
1250 				else if (' ' != *p)
1251 				{
1252 					if (idx == num)
1253 						ZBX_ASSIGN_PARAM;
1254 					state = 2;
1255 				}
1256 				break;
1257 			case 1:
1258 				/* quoted */
1259 
1260 				if ('"' == *p)
1261 				{
1262 					if (0 != array && idx == num)
1263 						ZBX_ASSIGN_PARAM;
1264 
1265 					/* skip spaces */
1266 					while (' ' == p[1])
1267 						p++;
1268 
1269 					if (',' != p[1] && '\0' != p[1] && (0 == array || ']' != p[1]))
1270 						return 1;	/* incorrect syntax */
1271 
1272 					state = 0;
1273 				}
1274 				else if ('\\' == *p && '"' == p[1])
1275 				{
1276 					if (idx == num && 0 != array)
1277 						ZBX_ASSIGN_PARAM;
1278 
1279 					p++;
1280 
1281 					if (idx == num)
1282 						ZBX_ASSIGN_PARAM;
1283 				}
1284 				else if (idx == num)
1285 					ZBX_ASSIGN_PARAM;
1286 				break;
1287 			case 2:
1288 				/* unquoted */
1289 
1290 				if (',' == *p || (']' == *p && 0 != array))
1291 				{
1292 					p--;
1293 					state = 0;
1294 				}
1295 				else if (idx == num)
1296 					ZBX_ASSIGN_PARAM;
1297 				break;
1298 		}
1299 
1300 		if (idx > num)
1301 			break;
1302 	}
1303 #undef ZBX_ASSIGN_PARAM
1304 
1305 	/* missing terminating '"' character */
1306 	if (1 == state)
1307 		return 1;
1308 
1309 	/* missing terminating ']' character */
1310 	if (0 != array)
1311 		return 1;
1312 
1313 	buf[buf_i] = '\0';
1314 
1315 	if (idx >= num)
1316 		return 0;
1317 
1318 	return 1;
1319 }
1320 
1321 /******************************************************************************
1322  *                                                                            *
1323  * Function: get_param_len                                                    *
1324  *                                                                            *
1325  * Purpose: return length of the parameter by index (num)                     *
1326  *          from parameter list (param)                                       *
1327  *                                                                            *
1328  * Parameters:                                                                *
1329  *      p   - [IN]  parameter list                                            *
1330  *      num - [IN]  requested parameter index                                 *
1331  *      sz  - [OUT] length of requested parameter                             *
1332  *                                                                            *
1333  * Return value:                                                              *
1334  *      1 - requested parameter missing                                       *
1335  *      0 - requested parameter found                                         *
1336  *          (for first parameter result is always 0)                          *
1337  *                                                                            *
1338  * Author: Alexander Vladishev                                                *
1339  *                                                                            *
1340  * Comments: delimeter for parameters is ','                                  *
1341  *                                                                            *
1342  ******************************************************************************/
get_param_len(const char * p,int num,size_t * sz)1343 static int	get_param_len(const char *p, int num, size_t *sz)
1344 {
1345 /* 0 - init, 1 - inside quoted param, 2 - inside unquoted param */
1346 	int	state, array, idx = 1;
1347 
1348 	*sz = 0;
1349 
1350 	for (state = 0, array = 0; '\0' != *p && idx <= num; p++)
1351 	{
1352 		switch (state) {
1353 		/* Init state */
1354 		case 0:
1355 			if (',' == *p)
1356 			{
1357 				if (0 == array)
1358 					idx++;
1359 				else if (idx == num)
1360 					(*sz)++;
1361 			}
1362 			else if ('"' == *p)
1363 			{
1364 				state = 1;
1365 				if (0 != array && idx == num)
1366 					(*sz)++;
1367 			}
1368 			else if ('[' == *p)
1369 			{
1370 				if (0 != array && idx == num)
1371 					(*sz)++;
1372 				array++;
1373 			}
1374 			else if (']' == *p && 0 != array)
1375 			{
1376 				array--;
1377 				if (0 != array && idx == num)
1378 					(*sz)++;
1379 
1380 				/* skip spaces */
1381 				while (' ' == p[1])
1382 					p++;
1383 
1384 				if (',' != p[1] && '\0' != p[1] && (0 == array || ']' != p[1]))
1385 					return 1;	/* incorrect syntax */
1386 			}
1387 			else if (' ' != *p)
1388 			{
1389 				if (idx == num)
1390 					(*sz)++;
1391 				state = 2;
1392 			}
1393 			break;
1394 		/* Quoted */
1395 		case 1:
1396 			if ('"' == *p)
1397 			{
1398 				if (0 != array && idx == num)
1399 					(*sz)++;
1400 
1401 				/* skip spaces */
1402 				while (' ' == p[1])
1403 					p++;
1404 
1405 				if (',' != p[1] && '\0' != p[1] && (0 == array || ']' != p[1]))
1406 					return 1;	/* incorrect syntax */
1407 
1408 				state = 0;
1409 			}
1410 			else if ('\\' == *p && '"' == p[1])
1411 			{
1412 				if (idx == num && 0 != array)
1413 					(*sz)++;
1414 
1415 				p++;
1416 
1417 				if (idx == num)
1418 					(*sz)++;
1419 			}
1420 			else if (idx == num)
1421 				(*sz)++;
1422 			break;
1423 		/* Unquoted */
1424 		case 2:
1425 			if (',' == *p || (']' == *p && 0 != array))
1426 			{
1427 				p--;
1428 				state = 0;
1429 			}
1430 			else if (idx == num)
1431 				(*sz)++;
1432 			break;
1433 		}
1434 
1435 		if (idx > num)
1436 			break;
1437 	}
1438 
1439 	/* missing terminating '"' character */
1440 	if (state == 1)
1441 		return 1;
1442 
1443 	/* missing terminating ']' character */
1444 	if (array != 0)
1445 		return 1;
1446 
1447 	if (idx >= num)
1448 		return 0;
1449 
1450 	return 1;
1451 }
1452 
1453 /******************************************************************************
1454  *                                                                            *
1455  * Function: get_param_dyn                                                    *
1456  *                                                                            *
1457  * Purpose: return parameter by index (num) from parameter list (param)       *
1458  *                                                                            *
1459  * Parameters:                                                                *
1460  *      p   - [IN] parameter list                                             *
1461  *      num - [IN] requested parameter index                                  *
1462  *                                                                            *
1463  * Return value:                                                              *
1464  *      NULL - requested parameter missing                                    *
1465  *      otherwise - requested parameter                                       *
1466  *          (for first parameter result is not NULL)                          *
1467  *                                                                            *
1468  * Author: Alexander Vladishev                                                *
1469  *                                                                            *
1470  * Comments:  delimeter for parameters is ','                                 *
1471  *                                                                            *
1472  ******************************************************************************/
get_param_dyn(const char * p,int num)1473 char	*get_param_dyn(const char *p, int num)
1474 {
1475 	char	*buf = NULL;
1476 	size_t	sz;
1477 
1478 	if (0 != get_param_len(p, num, &sz))
1479 		return buf;
1480 
1481 	buf = zbx_malloc(buf, sz + 1);
1482 
1483 	if (0 != get_param(p, num, buf, sz + 1))
1484 		zbx_free(buf);
1485 
1486 	return buf;
1487 }
1488 
1489 /******************************************************************************
1490  *                                                                            *
1491  * Function: replace_key_param                                                *
1492  *                                                                            *
1493  * Purpose: replaces an item key, SNMP OID or their parameters when callback  *
1494  *          function returns a new string                                     *
1495  *                                                                            *
1496  * Comments: auxiliary function for replace_key_params_dyn()                  *
1497  *                                                                            *
1498  ******************************************************************************/
replace_key_param(char ** data,int key_type,size_t l,size_t * r,int level,int num,int quoted,replace_key_param_f cb,void * cb_data)1499 static int	replace_key_param(char **data, int key_type, size_t l, size_t *r, int level, int num, int quoted,
1500 		replace_key_param_f cb, void *cb_data)
1501 {
1502 	char	c = (*data)[*r], *param = NULL;
1503 	int	ret;
1504 
1505 	(*data)[*r] = '\0';
1506 	ret = cb(*data + l, key_type, level, num, quoted, cb_data, &param);
1507 	(*data)[*r] = c;
1508 
1509 	if (NULL != param)
1510 	{
1511 		(*r)--;
1512 		zbx_replace_string(data, l, r, param);
1513 		(*r)++;
1514 
1515 		zbx_free(param);
1516 	}
1517 
1518 	return ret;
1519 }
1520 
1521 /******************************************************************************
1522  *                                                                            *
1523  * Function: replace_key_params_dyn                                           *
1524  *                                                                            *
1525  * Purpose: replaces an item key, SNMP OID or their parameters by using       *
1526  *          callback function                                                 *
1527  *                                                                            *
1528  * Parameters:                                                                *
1529  *      data      - [IN/OUT] item key or SNMP OID                             *
1530  *      key_type  - [IN] ZBX_KEY_TYPE_*                                       *
1531  *      cb        - [IN] callback function                                    *
1532  *      cb_data   - [IN] callback function custom data                        *
1533  *      error     - [OUT] error messsage                                      *
1534  *      maxerrlen - [IN] error size                                           *
1535  *                                                                            *
1536  * Return value: SUCCEED - function executed successfully                     *
1537  *               FAIL - otherwise, error will contain error message           *
1538  *                                                                            *
1539  ******************************************************************************/
replace_key_params_dyn(char ** data,int key_type,replace_key_param_f cb,void * cb_data,char * error,size_t maxerrlen)1540 int	replace_key_params_dyn(char **data, int key_type, replace_key_param_f cb, void *cb_data, char *error,
1541 		size_t maxerrlen)
1542 {
1543 	typedef enum
1544 	{
1545 		ZBX_STATE_NEW,
1546 		ZBX_STATE_END,
1547 		ZBX_STATE_UNQUOTED,
1548 		ZBX_STATE_QUOTED
1549 	}
1550 	zbx_parser_state_t;
1551 
1552 	size_t			i, l = 0;
1553 	int			level = 0, num = 0, ret = SUCCEED;
1554 	zbx_parser_state_t	state = ZBX_STATE_END;
1555 
1556 	if (ZBX_KEY_TYPE_ITEM == key_type)
1557 	{
1558 		for (i = 0; SUCCEED == is_key_char((*data)[i]) && '\0' != (*data)[i]; i++)
1559 			;
1560 
1561 		if (0 == i)
1562 			goto clean;
1563 
1564 		if ('[' != (*data)[i] && '\0' != (*data)[i])
1565 			goto clean;
1566 	}
1567 	else
1568 	{
1569 		for (i = 0; '[' != (*data)[i] && '\0' != (*data)[i]; i++)
1570 			;
1571 	}
1572 
1573 	ret = replace_key_param(data, key_type, 0, &i, level, num, 0, cb, cb_data);
1574 
1575 	for (; '\0' != (*data)[i] && FAIL != ret; i++)
1576 	{
1577 		if (0 == level)
1578 		{
1579 			/* first square bracket + Zapcat compatibility */
1580 			if (ZBX_STATE_END == state && '[' == (*data)[i])
1581 				state = ZBX_STATE_NEW;
1582 			else
1583 				break;
1584 		}
1585 
1586 		switch (state)
1587 		{
1588 			case ZBX_STATE_NEW:	/* a new parameter started */
1589 				switch ((*data)[i])
1590 				{
1591 					case ' ':
1592 						break;
1593 					case ',':
1594 						ret = replace_key_param(data, key_type, i, &i, level, num, 0, cb,
1595 								cb_data);
1596 						if (1 == level)
1597 							num++;
1598 						break;
1599 					case '[':
1600 						level++;
1601 						if (1 == level)
1602 							num++;
1603 						break;
1604 					case ']':
1605 						ret = replace_key_param(data, key_type, i, &i, level, num, 0, cb,
1606 								cb_data);
1607 						level--;
1608 						state = ZBX_STATE_END;
1609 						break;
1610 					case '"':
1611 						state = ZBX_STATE_QUOTED;
1612 						l = i;
1613 						break;
1614 					default:
1615 						state = ZBX_STATE_UNQUOTED;
1616 						l = i;
1617 				}
1618 				break;
1619 			case ZBX_STATE_END:	/* end of parameter */
1620 				switch ((*data)[i])
1621 				{
1622 					case ' ':
1623 						break;
1624 					case ',':
1625 						state = ZBX_STATE_NEW;
1626 						if (1 == level)
1627 							num++;
1628 						break;
1629 					case ']':
1630 						level--;
1631 						break;
1632 					default:
1633 						goto clean;
1634 				}
1635 				break;
1636 			case ZBX_STATE_UNQUOTED:	/* an unquoted parameter */
1637 				if (']' == (*data)[i] || ',' == (*data)[i])
1638 				{
1639 					ret = replace_key_param(data, key_type, l, &i, level, num, 0, cb, cb_data);
1640 
1641 					i--;
1642 					state = ZBX_STATE_END;
1643 				}
1644 				break;
1645 			case ZBX_STATE_QUOTED:	/* a quoted parameter */
1646 				if ('"' == (*data)[i] && '\\' != (*data)[i - 1])
1647 				{
1648 					i++;
1649 					ret = replace_key_param(data, key_type, l, &i, level, num, 1, cb, cb_data);
1650 					i--;
1651 
1652 					state = ZBX_STATE_END;
1653 				}
1654 				break;
1655 		}
1656 	}
1657 clean:
1658 	if (0 == i || '\0' != (*data)[i] || 0 != level)
1659 	{
1660 		if (NULL != error)
1661 		{
1662 			zbx_snprintf(error, maxerrlen, "Invalid %s at position " ZBX_FS_SIZE_T,
1663 					(ZBX_KEY_TYPE_ITEM == key_type ? "item key" : "SNMP OID"), (zbx_fs_size_t)i);
1664 		}
1665 		ret = FAIL;
1666 	}
1667 
1668 	return ret;
1669 }
1670 
1671 /******************************************************************************
1672  *                                                                            *
1673  * Function: remove_param                                                     *
1674  *                                                                            *
1675  * Purpose: remove parameter by index (num) from parameter list (param)       *
1676  *                                                                            *
1677  * Parameters:                                                                *
1678  *      param  - parameter list                                               *
1679  *      num    - requested parameter index                                    *
1680  *                                                                            *
1681  * Return value:                                                              *
1682  *                                                                            *
1683  * Comments: delimiter for parameters is ','                                  *
1684  *                                                                            *
1685  ******************************************************************************/
remove_param(char * param,int num)1686 void	remove_param(char *param, int num)
1687 {
1688 	int	state = 0;	/* 0 - unquoted parameter, 1 - quoted parameter */
1689 	int	idx = 1, skip_char = 0;
1690 	char	*p;
1691 
1692 	for (p = param; '\0' != *p; p++)
1693 	{
1694 		switch (state)
1695 		{
1696 			case 0:			/* in unquoted parameter */
1697 				if (',' == *p)
1698 				{
1699 					if (1 == idx && 1 == num)
1700 						skip_char = 1;
1701 					idx++;
1702 				}
1703 				else if ('"' == *p)
1704 					state = 1;
1705 				break;
1706 			case 1:			/* in quoted parameter */
1707 				if ('"' == *p && '\\' != *(p - 1))
1708 					state = 0;
1709 				break;
1710 		}
1711 		if (idx != num && 0 == skip_char)
1712 			*param++ = *p;
1713 
1714 		skip_char = 0;
1715 	}
1716 
1717 	*param = '\0';
1718 }
1719 
1720 /******************************************************************************
1721  *                                                                            *
1722  * Function: zbx_num2hex                                                      *
1723  *                                                                            *
1724  * Purpose: convert parameter c (0-15) to hexadecimal value ('0'-'f')         *
1725  *                                                                            *
1726  * Parameters:                                                                *
1727  *      c - number 0-15                                                       *
1728  *                                                                            *
1729  * Return value:                                                              *
1730  *      '0'-'f'                                                               *
1731  *                                                                            *
1732  * Author: Alexander Vladishev                                                *
1733  *                                                                            *
1734  ******************************************************************************/
zbx_num2hex(u_char c)1735 char	zbx_num2hex(u_char c)
1736 {
1737 	if (c >= 10)
1738 		return c + 0x57; /* a-f */
1739 	else
1740 		return c + 0x30; /* 0-9 */
1741 }
1742 
1743 /******************************************************************************
1744  *                                                                            *
1745  * Function: zbx_hex2num                                                      *
1746  *                                                                            *
1747  * Purpose: convert hexit c ('0'-'9''a'-'f') to number (0-15)                 *
1748  *                                                                            *
1749  * Parameters:                                                                *
1750  *      c - char ('0'-'9''a'-'f')                                             *
1751  *                                                                            *
1752  * Return value:                                                              *
1753  *      0-15                                                                  *
1754  *                                                                            *
1755  * Author: Alexander Vladishev                                                *
1756  *                                                                            *
1757  ******************************************************************************/
zbx_hex2num(char c)1758 u_char	zbx_hex2num(char c)
1759 {
1760 	if (c >= 'a')
1761 		return c - 0x57; /* a-f */
1762 	else
1763 		return c - 0x30; /* 0-9 */
1764 }
1765 
1766 /******************************************************************************
1767  *                                                                            *
1768  * Function: str_in_list                                                      *
1769  *                                                                            *
1770  * Purpose: check if string is contained in a list of delimited strings       *
1771  *                                                                            *
1772  * Parameters: list      - strings a,b,ccc,ddd                                *
1773  *             value     - value                                              *
1774  *             delimiter - delimiter                                          *
1775  *                                                                            *
1776  * Return value: SUCCEED - string is in the list, FAIL - otherwise            *
1777  *                                                                            *
1778  * Author: Alexei Vladishev, Aleksandrs Saveljevs                             *
1779  *                                                                            *
1780  ******************************************************************************/
str_in_list(const char * list,const char * value,char delimiter)1781 int	str_in_list(const char *list, const char *value, char delimiter)
1782 {
1783 	const char	*end;
1784 	int		ret = FAIL;
1785 	size_t		len;
1786 
1787 	len = strlen(value);
1788 
1789 	while (SUCCEED != ret)
1790 	{
1791 		if (NULL != (end = strchr(list, delimiter)))
1792 		{
1793 			ret = (len == (size_t)(end - list) && 0 == strncmp(list, value, len) ? SUCCEED : FAIL);
1794 			list = end + 1;
1795 		}
1796 		else
1797 		{
1798 			ret = (0 == strcmp(list, value) ? SUCCEED : FAIL);
1799 			break;
1800 		}
1801 	}
1802 
1803 	return ret;
1804 }
1805 
1806 /******************************************************************************
1807  *                                                                            *
1808  * Function: get_key_param                                                    *
1809  *                                                                            *
1810  * Purpose: return parameter by index (num) from parameter list (param)       *
1811  *          to be used for keys: key[param1,param2]                           *
1812  *                                                                            *
1813  * Parameters:                                                                *
1814  *      param   - parameter list                                              *
1815  *      num     - requested parameter index                                   *
1816  *      buf     - pointer of output buffer                                    *
1817  *      max_len - size of output buffer                                       *
1818  *                                                                            *
1819  * Return value:                                                              *
1820  *      1 - requested parameter missing                                       *
1821  *      0 - requested parameter found (value - 'buf' can be empty string)     *
1822  *                                                                            *
1823  * Author: Alexei Vladishev                                                   *
1824  *                                                                            *
1825  * Comments:  delimeter for parameters is ','                                 *
1826  *                                                                            *
1827  ******************************************************************************/
get_key_param(char * param,int num,char * buf,size_t max_len)1828 int	get_key_param(char *param, int num, char *buf, size_t max_len)
1829 {
1830 	int	ret;
1831 	char	*pl, *pr;
1832 
1833 	pl = strchr(param, '[');
1834 	pr = strrchr(param, ']');
1835 
1836 	if (NULL == pl || NULL == pr || pl > pr)
1837 		return 1;
1838 
1839 	*pr = '\0';
1840 	ret = get_param(pl + 1, num, buf, max_len);
1841 	*pr = ']';
1842 
1843 	return ret;
1844 }
1845 
1846 /******************************************************************************
1847  *                                                                            *
1848  * Function: num_key_param                                                    *
1849  *                                                                            *
1850  * Purpose: calculate count of parameters from parameter list (param)         *
1851  *          to be used for keys: key[param1,param2]                           *
1852  *                                                                            *
1853  * Parameters:                                                                *
1854  *      param  - parameter list                                               *
1855  *                                                                            *
1856  * Return value: count of parameters                                          *
1857  *                                                                            *
1858  * Author: Alexei Vladishev                                                   *
1859  *                                                                            *
1860  * Comments:  delimeter for parameters is ','                                 *
1861  *                                                                            *
1862  ******************************************************************************/
num_key_param(char * param)1863 int	num_key_param(char *param)
1864 {
1865 	int	ret;
1866 	char	*pl, *pr;
1867 
1868 	if (NULL == param)
1869 		return 0;
1870 
1871 	pl = strchr(param, '[');
1872 	pr = strrchr(param, ']');
1873 
1874 	if (NULL == pl || NULL == pr || pl > pr)
1875 		return 0;
1876 
1877 	*pr = '\0';
1878 	ret = num_param(pl + 1);
1879 	*pr = ']';
1880 
1881 	return ret;
1882 }
1883 
1884 /******************************************************************************
1885  *                                                                            *
1886  * Function: zbx_get_escape_string_len                                        *
1887  *                                                                            *
1888  * Purpose: calculate the required size for the escaped string                *
1889  *                                                                            *
1890  * Parameters: src - [IN] null terminated source string                       *
1891  *             charlist - [IN] null terminated to-be-escaped character list   *
1892  *                                                                            *
1893  * Return value: size of the escaped string                                   *
1894  *                                                                            *
1895  * Author: Alexander Vladishev                                                *
1896  *                                                                            *
1897  ******************************************************************************/
zbx_get_escape_string_len(const char * src,const char * charlist)1898 size_t	zbx_get_escape_string_len(const char *src, const char *charlist)
1899 {
1900 	size_t	sz = 0;
1901 
1902 	for (; '\0' != *src; src++, sz++)
1903 	{
1904 		if (NULL != strchr(charlist, *src))
1905 			sz++;
1906 	}
1907 
1908 	return sz;
1909 }
1910 
1911 /******************************************************************************
1912  *                                                                            *
1913  * Function: zbx_dyn_escape_string                                            *
1914  *                                                                            *
1915  * Purpose: escape characters in the source string                            *
1916  *                                                                            *
1917  * Parameters: src - [IN] null terminated source string                       *
1918  *             charlist - [IN] null terminated to-be-escaped character list   *
1919  *                                                                            *
1920  * Return value: the escaped string                                           *
1921  *                                                                            *
1922  * Author: Alexander Vladishev                                                *
1923  *                                                                            *
1924  ******************************************************************************/
zbx_dyn_escape_string(const char * src,const char * charlist)1925 char	*zbx_dyn_escape_string(const char *src, const char *charlist)
1926 {
1927 	size_t	sz;
1928 	char	*d, *dst = NULL;
1929 
1930 	sz = zbx_get_escape_string_len(src, charlist) + 1;
1931 
1932 	dst = zbx_malloc(dst, sz);
1933 
1934 	for (d = dst; '\0' != *src; src++)
1935 	{
1936 		if (NULL != strchr(charlist, *src))
1937 			*d++ = '\\';
1938 
1939 		*d++ = *src;
1940 	}
1941 
1942 	*d = '\0';
1943 
1944 	return dst;
1945 }
1946 
zbx_age2str(int age)1947 char	*zbx_age2str(int age)
1948 {
1949 	size_t		offset = 0;
1950 	int		days, hours, minutes;
1951 	static char	buffer[32];
1952 
1953 	days = (int)((double)age / SEC_PER_DAY);
1954 	hours = (int)((double)(age - days * SEC_PER_DAY) / SEC_PER_HOUR);
1955 	minutes	= (int)((double)(age - days * SEC_PER_DAY - hours * SEC_PER_HOUR) / SEC_PER_MIN);
1956 
1957 	if (0 != days)
1958 		offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, "%dd ", days);
1959 	if (0 != days || 0 != hours)
1960 		offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, "%dh ", hours);
1961 	offset += zbx_snprintf(buffer + offset, sizeof(buffer) - offset, "%dm", minutes);
1962 
1963 	return buffer;
1964 }
1965 
zbx_date2str(time_t date)1966 char	*zbx_date2str(time_t date)
1967 {
1968 	static char	buffer[11];
1969 	struct tm	*tm;
1970 
1971 	tm = localtime(&date);
1972 	zbx_snprintf(buffer, sizeof(buffer), "%.4d.%.2d.%.2d",
1973 			tm->tm_year + 1900,
1974 			tm->tm_mon + 1,
1975 			tm->tm_mday);
1976 
1977 	return buffer;
1978 }
1979 
zbx_time2str(time_t time)1980 char	*zbx_time2str(time_t time)
1981 {
1982 	static char	buffer[9];
1983 	struct tm	*tm;
1984 
1985 	tm = localtime(&time);
1986 	zbx_snprintf(buffer, sizeof(buffer), "%.2d:%.2d:%.2d",
1987 			tm->tm_hour,
1988 			tm->tm_min,
1989 			tm->tm_sec);
1990 	return buffer;
1991 }
1992 
zbx_strncasecmp(const char * s1,const char * s2,size_t n)1993 int	zbx_strncasecmp(const char *s1, const char *s2, size_t n)
1994 {
1995 	if (NULL == s1 && NULL == s2)
1996 		return 0;
1997 
1998 	if (NULL == s1)
1999 		return 1;
2000 
2001 	if (NULL == s2)
2002 		return -1;
2003 
2004 	while (0 != n && '\0' != *s1 && '\0' != *s2 &&
2005 			tolower((unsigned char)*s1) == tolower((unsigned char)*s2))
2006 	{
2007 		s1++;
2008 		s2++;
2009 		n--;
2010 	}
2011 
2012 	return 0 == n ? 0 : tolower((unsigned char)*s1) - tolower((unsigned char)*s2);
2013 }
2014 
zbx_strcasestr(const char * haystack,const char * needle)2015 char	*zbx_strcasestr(const char *haystack, const char *needle)
2016 {
2017 	size_t		sz_h, sz_n;
2018 	const char	*p;
2019 
2020 	if (NULL == needle || '\0' == *needle)
2021 		return (char *)haystack;
2022 
2023 	if (NULL == haystack || '\0' == *haystack)
2024 		return NULL;
2025 
2026 	sz_h = strlen(haystack);
2027 	sz_n = strlen(needle);
2028 	if (sz_h < sz_n)
2029 		return NULL;
2030 
2031 	for (p = haystack; p <= &haystack[sz_h - sz_n]; p++)
2032 	{
2033 		if (0 == zbx_strncasecmp(p, needle, sz_n))
2034 			return (char *)p;
2035 	}
2036 
2037 	return NULL;
2038 }
2039 
zbx_mismatch(const char * s1,const char * s2)2040 int	zbx_mismatch(const char *s1, const char *s2)
2041 {
2042 	int	i = 0;
2043 
2044 	while (s1[i] == s2[i])
2045 	{
2046 		if ('\0' == s1[i++])
2047 			return FAIL;
2048 	}
2049 
2050 	return i;
2051 }
2052 
cmp_key_id(const char * key_1,const char * key_2)2053 int	cmp_key_id(const char *key_1, const char *key_2)
2054 {
2055 	const char	*p, *q;
2056 
2057 	for (p = key_1, q = key_2; *p == *q && '\0' != *q && '[' != *q; p++, q++)
2058 		;
2059 
2060 	return ('\0' == *p || '[' == *p) && ('\0' == *q || '[' == *q) ? SUCCEED : FAIL;
2061 }
2062 
get_program_type_string(unsigned char program_type)2063 const char	*get_program_type_string(unsigned char program_type)
2064 {
2065 	switch (program_type)
2066 	{
2067 		case ZBX_PROGRAM_TYPE_SERVER:
2068 			return "server";
2069 		case ZBX_PROGRAM_TYPE_PROXY_ACTIVE:
2070 		case ZBX_PROGRAM_TYPE_PROXY_PASSIVE:
2071 			return "proxy";
2072 		case ZBX_PROGRAM_TYPE_AGENTD:
2073 			return "agent";
2074 		case ZBX_PROGRAM_TYPE_SENDER:
2075 			return "sender";
2076 		case ZBX_PROGRAM_TYPE_GET:
2077 			return "get";
2078 		default:
2079 			return "unknown";
2080 	}
2081 }
2082 
zbx_permission_string(int perm)2083 const char	*zbx_permission_string(int perm)
2084 {
2085 	switch (perm)
2086 	{
2087 		case PERM_DENY:
2088 			return "dn";
2089 		case PERM_READ:
2090 			return "r";
2091 		case PERM_READ_WRITE:
2092 			return "rw";
2093 		default:
2094 			return "unknown";
2095 	}
2096 }
2097 
zbx_agent_type_string(zbx_item_type_t item_type)2098 const char	*zbx_agent_type_string(zbx_item_type_t item_type)
2099 {
2100 	switch (item_type)
2101 	{
2102 		case ITEM_TYPE_ZABBIX:
2103 			return "Zabbix agent";
2104 		case ITEM_TYPE_SNMPv1:
2105 		case ITEM_TYPE_SNMPv2c:
2106 		case ITEM_TYPE_SNMPv3:
2107 			return "SNMP agent";
2108 		case ITEM_TYPE_IPMI:
2109 			return "IPMI agent";
2110 		case ITEM_TYPE_JMX:
2111 			return "JMX agent";
2112 		default:
2113 			return "generic";
2114 	}
2115 }
2116 
zbx_item_value_type_string(zbx_item_value_type_t value_type)2117 const char	*zbx_item_value_type_string(zbx_item_value_type_t value_type)
2118 {
2119 	switch (value_type)
2120 	{
2121 		case ITEM_VALUE_TYPE_FLOAT:
2122 			return "Numeric (float)";
2123 		case ITEM_VALUE_TYPE_STR:
2124 			return "Character";
2125 		case ITEM_VALUE_TYPE_LOG:
2126 			return "Log";
2127 		case ITEM_VALUE_TYPE_UINT64:
2128 			return "Numeric (unsigned)";
2129 		case ITEM_VALUE_TYPE_TEXT:
2130 			return "Text";
2131 		default:
2132 			return "unknown";
2133 	}
2134 }
2135 
zbx_item_data_type_string(zbx_item_data_type_t data_type)2136 const char	*zbx_item_data_type_string(zbx_item_data_type_t data_type)
2137 {
2138 	switch (data_type)
2139 	{
2140 		case ITEM_DATA_TYPE_DECIMAL:
2141 			return "Decimal";
2142 		case ITEM_DATA_TYPE_OCTAL:
2143 			return "Octal";
2144 		case ITEM_DATA_TYPE_HEXADECIMAL:
2145 			return "Hexadecimal";
2146 		case ITEM_DATA_TYPE_BOOLEAN:
2147 			return "Boolean";
2148 		default:
2149 			return "unknown";
2150 	}
2151 }
2152 
zbx_interface_type_string(zbx_interface_type_t type)2153 const char	*zbx_interface_type_string(zbx_interface_type_t type)
2154 {
2155 	switch (type)
2156 	{
2157 		case INTERFACE_TYPE_AGENT:
2158 			return "Zabbix agent";
2159 		case INTERFACE_TYPE_SNMP:
2160 			return "SNMP";
2161 		case INTERFACE_TYPE_IPMI:
2162 			return "IPMI";
2163 		case INTERFACE_TYPE_JMX:
2164 			return "JMX";
2165 		case INTERFACE_TYPE_ANY:
2166 			return "any";
2167 		case INTERFACE_TYPE_UNKNOWN:
2168 		default:
2169 			return "unknown";
2170 	}
2171 }
2172 
2173 const int	INTERFACE_TYPE_PRIORITY[INTERFACE_TYPE_COUNT] =
2174 {
2175 	INTERFACE_TYPE_AGENT,
2176 	INTERFACE_TYPE_SNMP,
2177 	INTERFACE_TYPE_JMX,
2178 	INTERFACE_TYPE_IPMI
2179 };
2180 
zbx_result_string(int result)2181 const char	*zbx_result_string(int result)
2182 {
2183 	switch (result)
2184 	{
2185 		case SUCCEED:
2186 			return "SUCCEED";
2187 		case FAIL:
2188 			return "FAIL";
2189 		case CONFIG_ERROR:
2190 			return "CONFIG_ERROR";
2191 		case NOTSUPPORTED:
2192 			return "NOTSUPPORTED";
2193 		case NETWORK_ERROR:
2194 			return "NETWORK_ERROR";
2195 		case TIMEOUT_ERROR:
2196 			return "TIMEOUT_ERROR";
2197 		case AGENT_ERROR:
2198 			return "AGENT_ERROR";
2199 		case GATEWAY_ERROR:
2200 			return "GATEWAY_ERROR";
2201 		default:
2202 			return "unknown";
2203 	}
2204 }
2205 
zbx_item_logtype_string(unsigned char logtype)2206 const char	*zbx_item_logtype_string(unsigned char logtype)
2207 {
2208 	switch (logtype)
2209 	{
2210 		case ITEM_LOGTYPE_INFORMATION:
2211 			return "Information";
2212 		case ITEM_LOGTYPE_WARNING:
2213 			return "Warning";
2214 		case ITEM_LOGTYPE_ERROR:
2215 			return "Error";
2216 		case ITEM_LOGTYPE_FAILURE_AUDIT:
2217 			return "Failure Audit";
2218 		case ITEM_LOGTYPE_SUCCESS_AUDIT:
2219 			return "Success Audit";
2220 		case ITEM_LOGTYPE_CRITICAL:
2221 			return "Critical";
2222 		case ITEM_LOGTYPE_VERBOSE:
2223 			return "Verbose";
2224 		default:
2225 			return "unknown";
2226 	}
2227 }
2228 
zbx_dservice_type_string(zbx_dservice_type_t service)2229 const char	*zbx_dservice_type_string(zbx_dservice_type_t service)
2230 {
2231 	switch (service)
2232 	{
2233 		case SVC_SSH:
2234 			return "SSH";
2235 		case SVC_LDAP:
2236 			return "LDAP";
2237 		case SVC_SMTP:
2238 			return "SMTP";
2239 		case SVC_FTP:
2240 			return "FTP";
2241 		case SVC_HTTP:
2242 			return "HTTP";
2243 		case SVC_POP:
2244 			return "POP";
2245 		case SVC_NNTP:
2246 			return "NNTP";
2247 		case SVC_IMAP:
2248 			return "IMAP";
2249 		case SVC_TCP:
2250 			return "TCP";
2251 		case SVC_AGENT:
2252 			return "Zabbix agent";
2253 		case SVC_SNMPv1:
2254 			return "SNMPv1 agent";
2255 		case SVC_SNMPv2c:
2256 			return "SNMPv2c agent";
2257 		case SVC_SNMPv3:
2258 			return "SNMPv3 agent";
2259 		case SVC_ICMPPING:
2260 			return "ICMP ping";
2261 		case SVC_HTTPS:
2262 			return "HTTPS";
2263 		case SVC_TELNET:
2264 			return "Telnet";
2265 		default:
2266 			return "unknown";
2267 	}
2268 }
2269 
zbx_alert_type_string(unsigned char type)2270 const char	*zbx_alert_type_string(unsigned char type)
2271 {
2272 	switch (type)
2273 	{
2274 		case ALERT_TYPE_MESSAGE:
2275 			return "message";
2276 		default:
2277 			return "script";
2278 	}
2279 }
2280 
zbx_alert_status_string(unsigned char type,unsigned char status)2281 const char	*zbx_alert_status_string(unsigned char type, unsigned char status)
2282 {
2283 	switch (status)
2284 	{
2285 		case ALERT_STATUS_SENT:
2286 			return (ALERT_TYPE_MESSAGE == type ? "sent" : "executed");
2287 		case ALERT_STATUS_NOT_SENT:
2288 			return "in progress";
2289 		default:
2290 			return "failed";
2291 	}
2292 }
2293 
zbx_escalation_status_string(unsigned char status)2294 const char	*zbx_escalation_status_string(unsigned char status)
2295 {
2296 	switch (status)
2297 	{
2298 		case ESCALATION_STATUS_ACTIVE:
2299 			return "active";
2300 		case ESCALATION_STATUS_RECOVERY:
2301 			return "recovery";
2302 		case ESCALATION_STATUS_SLEEP:
2303 			return "sleep";
2304 		case ESCALATION_STATUS_COMPLETED:
2305 			return "completed";
2306 		default:
2307 			return "unknown";
2308 	}
2309 }
2310 
zbx_trigger_value_string(unsigned char value)2311 const char	*zbx_trigger_value_string(unsigned char value)
2312 {
2313 	switch (value)
2314 	{
2315 		case TRIGGER_VALUE_PROBLEM:
2316 			return "PROBLEM";
2317 		case TRIGGER_VALUE_OK:
2318 			return "OK";
2319 		default:
2320 			return "unknown";
2321 	}
2322 }
2323 
zbx_trigger_state_string(unsigned char state)2324 const char	*zbx_trigger_state_string(unsigned char state)
2325 {
2326 	switch (state)
2327 	{
2328 		case TRIGGER_STATE_NORMAL:
2329 			return "Normal";
2330 		case TRIGGER_STATE_UNKNOWN:
2331 			return "Unknown";
2332 		default:
2333 			return "unknown";
2334 	}
2335 }
2336 
zbx_item_state_string(unsigned char state)2337 const char	*zbx_item_state_string(unsigned char state)
2338 {
2339 	switch (state)
2340 	{
2341 		case ITEM_STATE_NORMAL:
2342 			return "Normal";
2343 		case ITEM_STATE_NOTSUPPORTED:
2344 			return "Not supported";
2345 		default:
2346 			return "unknown";
2347 	}
2348 }
2349 
zbx_event_value_string(unsigned char source,unsigned char object,unsigned char value)2350 const char	*zbx_event_value_string(unsigned char source, unsigned char object, unsigned char value)
2351 {
2352 	if (EVENT_SOURCE_TRIGGERS == source)
2353 		return zbx_trigger_value_string(value);
2354 
2355 	if (EVENT_SOURCE_INTERNAL == source)
2356 	{
2357 		switch (object)
2358 		{
2359 			case EVENT_OBJECT_TRIGGER:
2360 				return zbx_trigger_state_string(value);
2361 			case EVENT_OBJECT_ITEM:
2362 			case EVENT_OBJECT_LLDRULE:
2363 				return zbx_item_state_string(value);
2364 		}
2365 	}
2366 
2367 	return "unknown";
2368 }
2369 
2370 #ifdef _WINDOWS
get_codepage(const char * encoding,unsigned int * codepage)2371 static int	get_codepage(const char *encoding, unsigned int *codepage)
2372 {
2373 	typedef struct
2374 	{
2375 		unsigned int	codepage;
2376 		const char	*name;
2377 	}
2378 	codepage_t;
2379 
2380 	int		i;
2381 	char		buf[16];
2382 	codepage_t	cp[] = {{0, "ANSI"}, {37, "IBM037"}, {437, "IBM437"}, {500, "IBM500"}, {708, "ASMO-708"},
2383 			{709, NULL}, {710, NULL}, {720, "DOS-720"}, {737, "IBM737"}, {775, "IBM775"}, {850, "IBM850"},
2384 			{852, "IBM852"}, {855, "IBM855"}, {857, "IBM857"}, {858, "IBM00858"}, {860, "IBM860"},
2385 			{861, "IBM861"}, {862, "DOS-862"}, {863, "IBM863"}, {864, "IBM864"}, {865, "IBM865"},
2386 			{866, "CP866"}, {869, "IBM869"}, {870, "IBM870"}, {874, "WINDOWS-874"}, {875, "CP875"},
2387 			{932, "SHIFT_JIS"}, {936, "GB2312"}, {949, "KS_C_5601-1987"}, {950, "BIG5"}, {1026, "IBM1026"},
2388 			{1047, "IBM01047"}, {1140, "IBM01140"}, {1141, "IBM01141"}, {1142, "IBM01142"},
2389 			{1143, "IBM01143"}, {1144, "IBM01144"}, {1145, "IBM01145"}, {1146, "IBM01146"},
2390 			{1147, "IBM01147"}, {1148, "IBM01148"}, {1149, "IBM01149"}, {1200, "UTF-16"},
2391 			{1201, "UNICODEFFFE"}, {1250, "WINDOWS-1250"}, {1251, "WINDOWS-1251"}, {1252, "WINDOWS-1252"},
2392 			{1253, "WINDOWS-1253"}, {1254, "WINDOWS-1254"}, {1255, "WINDOWS-1255"}, {1256, "WINDOWS-1256"},
2393 			{1257, "WINDOWS-1257"}, {1258, "WINDOWS-1258"}, {1361, "JOHAB"}, {10000, "MACINTOSH"},
2394 			{10001, "X-MAC-JAPANESE"}, {10002, "X-MAC-CHINESETRAD"}, {10003, "X-MAC-KOREAN"},
2395 			{10004, "X-MAC-ARABIC"}, {10005, "X-MAC-HEBREW"}, {10006, "X-MAC-GREEK"},
2396 			{10007, "X-MAC-CYRILLIC"}, {10008, "X-MAC-CHINESESIMP"}, {10010, "X-MAC-ROMANIAN"},
2397 			{10017, "X-MAC-UKRAINIAN"}, {10021, "X-MAC-THAI"}, {10029, "X-MAC-CE"},
2398 			{10079, "X-MAC-ICELANDIC"}, {10081, "X-MAC-TURKISH"}, {10082, "X-MAC-CROATIAN"},
2399 			{12000, "UTF-32"}, {12001, "UTF-32BE"}, {20000, "X-CHINESE_CNS"}, {20001, "X-CP20001"},
2400 			{20002, "X_CHINESE-ETEN"}, {20003, "X-CP20003"}, {20004, "X-CP20004"}, {20005, "X-CP20005"},
2401 			{20105, "X-IA5"}, {20106, "X-IA5-GERMAN"}, {20107, "X-IA5-SWEDISH"}, {20108, "X-IA5-NORWEGIAN"},
2402 			{20127, "US-ASCII"}, {20261, "X-CP20261"}, {20269, "X-CP20269"}, {20273, "IBM273"},
2403 			{20277, "IBM277"}, {20278, "IBM278"}, {20280, "IBM280"}, {20284, "IBM284"}, {20285, "IBM285"},
2404 			{20290, "IBM290"}, {20297, "IBM297"}, {20420, "IBM420"}, {20423, "IBM423"}, {20424, "IBM424"},
2405 			{20833, "X-EBCDIC-KOREANEXTENDED"}, {20838, "IBM-THAI"}, {20866, "KOI8-R"}, {20871, "IBM871"},
2406 			{20880, "IBM880"}, {20905, "IBM905"}, {20924, "IBM00924"}, {20932, "EUC-JP"},
2407 			{20936, "X-CP20936"}, {20949, "X-CP20949"}, {21025, "CP1025"}, {21027, NULL}, {21866, "KOI8-U"},
2408 			{28591, "ISO-8859-1"}, {28592, "ISO-8859-2"}, {28593, "ISO-8859-3"}, {28594, "ISO-8859-4"},
2409 			{28595, "ISO-8859-5"}, {28596, "ISO-8859-6"}, {28597, "ISO-8859-7"}, {28598, "ISO-8859-8"},
2410 			{28599, "ISO-8859-9"}, {28603, "ISO-8859-13"}, {28605, "ISO-8859-15"}, {29001, "X-EUROPA"},
2411 			{38598, "ISO-8859-8-I"}, {50220, "ISO-2022-JP"}, {50221, "CSISO2022JP"}, {50222, "ISO-2022-JP"},
2412 			{50225, "ISO-2022-KR"}, {50227, "X-CP50227"}, {50229, NULL}, {50930, NULL}, {50931, NULL},
2413 			{50933, NULL}, {50935, NULL}, {50936, NULL}, {50937, NULL}, {50939, NULL}, {51932, "EUC-JP"},
2414 			{51936, "EUC-CN"}, {51949, "EUC-KR"}, {51950, NULL}, {52936, "HZ-GB-2312"}, {54936, "GB18030"},
2415 			{57002, "X-ISCII-DE"}, {57003, "X-ISCII-BE"}, {57004, "X-ISCII-TA"}, {57005, "X-ISCII-TE"},
2416 			{57006, "X-ISCII-AS"}, {57007, "X-ISCII-OR"}, {57008, "X-ISCII-KA"}, {57009, "X-ISCII-MA"},
2417 			{57010, "X-ISCII-GU"}, {57011, "X-ISCII-PA"}, {65000, "UTF-7"}, {65001, "UTF-8"}, {0, NULL}};
2418 
2419 	if ('\0' == *encoding)
2420 	{
2421 		*codepage = 0;	/* ANSI */
2422 		return SUCCEED;
2423 	}
2424 
2425 	/* by name */
2426 	for (i = 0; 0 != cp[i].codepage || NULL != cp[i].name; i++)
2427 	{
2428 		if (NULL == cp[i].name)
2429 			continue;
2430 
2431 		if (0 == strcmp(encoding, cp[i].name))
2432 		{
2433 			*codepage = cp[i].codepage;
2434 			return SUCCEED;
2435 		}
2436 	}
2437 
2438 	/* by number */
2439 	for (i = 0; 0 != cp[i].codepage || NULL != cp[i].name; i++)
2440 	{
2441 		_itoa_s(cp[i].codepage, buf, sizeof(buf), 10);
2442 		if (0 == strcmp(encoding, buf))
2443 		{
2444 			*codepage = cp[i].codepage;
2445 			return SUCCEED;
2446 		}
2447 	}
2448 
2449 	/* by 'cp' + number */
2450 	for (i = 0; 0 != cp[i].codepage || NULL != cp[i].name; i++)
2451 	{
2452 		zbx_snprintf(buf, sizeof(buf), "cp%li", cp[i].codepage);
2453 		if (0 == strcmp(encoding, buf))
2454 		{
2455 			*codepage = cp[i].codepage;
2456 			return SUCCEED;
2457 		}
2458 	}
2459 
2460 	return FAIL;
2461 }
2462 
2463 /* convert from selected code page to unicode */
zbx_to_unicode(unsigned int codepage,const char * cp_string)2464 static wchar_t	*zbx_to_unicode(unsigned int codepage, const char *cp_string)
2465 {
2466 	wchar_t	*wide_string = NULL;
2467 	int	wide_size;
2468 
2469 	wide_size = MultiByteToWideChar(codepage, 0, cp_string, -1, NULL, 0);
2470 	wide_string = (wchar_t *)zbx_malloc(wide_string, (size_t)wide_size * sizeof(wchar_t));
2471 
2472 	/* convert from cp_string to wide_string */
2473 	MultiByteToWideChar(codepage, 0, cp_string, -1, wide_string, wide_size);
2474 
2475 	return wide_string;
2476 }
2477 
2478 /* convert from Windows ANSI code page to unicode */
zbx_acp_to_unicode(const char * acp_string)2479 wchar_t	*zbx_acp_to_unicode(const char *acp_string)
2480 {
2481 	return zbx_to_unicode(CP_ACP, acp_string);
2482 }
2483 
2484 /* convert from Windows OEM code page to unicode */
zbx_oemcp_to_unicode(const char * oemcp_string)2485 wchar_t	*zbx_oemcp_to_unicode(const char *oemcp_string)
2486 {
2487 	return zbx_to_unicode(CP_OEMCP, oemcp_string);
2488 }
2489 
zbx_acp_to_unicode_static(const char * acp_string,wchar_t * wide_string,int wide_size)2490 int	zbx_acp_to_unicode_static(const char *acp_string, wchar_t *wide_string, int wide_size)
2491 {
2492 	/* convert from acp_string to wide_string */
2493 	if (0 == MultiByteToWideChar(CP_ACP, 0, acp_string, -1, wide_string, wide_size))
2494 		return FAIL;
2495 
2496 	return SUCCEED;
2497 }
2498 
2499 /* convert from UTF-8 to unicode */
zbx_utf8_to_unicode(const char * utf8_string)2500 wchar_t	*zbx_utf8_to_unicode(const char *utf8_string)
2501 {
2502 	return zbx_to_unicode(CP_UTF8, utf8_string);
2503 }
2504 
2505 /* convert from unicode to utf8 */
zbx_unicode_to_utf8(const wchar_t * wide_string)2506 char	*zbx_unicode_to_utf8(const wchar_t *wide_string)
2507 {
2508 	char	*utf8_string = NULL;
2509 	int	utf8_size;
2510 
2511 	utf8_size = WideCharToMultiByte(CP_UTF8, 0, wide_string, -1, NULL, 0, NULL, NULL);
2512 	utf8_string = (char *)zbx_malloc(utf8_string, (size_t)utf8_size);
2513 
2514 	/* convert from wide_string to utf8_string */
2515 	WideCharToMultiByte(CP_UTF8, 0, wide_string, -1, utf8_string, utf8_size, NULL, NULL);
2516 
2517 	return utf8_string;
2518 }
2519 
2520 /* convert from unicode to utf8 */
zbx_unicode_to_utf8_static(const wchar_t * wide_string,char * utf8_string,int utf8_size)2521 char	*zbx_unicode_to_utf8_static(const wchar_t *wide_string, char *utf8_string, int utf8_size)
2522 {
2523 	/* convert from wide_string to utf8_string */
2524 	if (0 == WideCharToMultiByte(CP_UTF8, 0, wide_string, -1, utf8_string, utf8_size, NULL, NULL))
2525 		*utf8_string = '\0';
2526 
2527 	return utf8_string;
2528 }
2529 #endif
2530 
zbx_strlower(char * str)2531 void	zbx_strlower(char *str)
2532 {
2533 	for (; '\0' != *str; str++)
2534 		*str = tolower(*str);
2535 }
2536 
zbx_strupper(char * str)2537 void	zbx_strupper(char *str)
2538 {
2539 	for (; '\0' != *str; str++)
2540 		*str = toupper(*str);
2541 }
2542 
2543 #ifdef _WINDOWS
2544 #include "log.h"
convert_to_utf8(char * in,size_t in_size,const char * encoding)2545 char	*convert_to_utf8(char *in, size_t in_size, const char *encoding)
2546 {
2547 #define STATIC_SIZE	1024
2548 	wchar_t		wide_string_static[STATIC_SIZE], *wide_string = NULL;
2549 	int		wide_size;
2550 	char		*utf8_string = NULL;
2551 	int		utf8_size;
2552 	unsigned int	codepage;
2553 
2554 	if ('\0' == *encoding || FAIL == get_codepage(encoding, &codepage))
2555 	{
2556 		utf8_size = (int)in_size + 1;
2557 		utf8_string = zbx_malloc(utf8_string, utf8_size);
2558 		memcpy(utf8_string, in, in_size);
2559 		utf8_string[in_size] = '\0';
2560 		return utf8_string;
2561 	}
2562 
2563 	zabbix_log(LOG_LEVEL_DEBUG, "convert_to_utf8() in_size:%d encoding:'%s' codepage:%u", in_size, encoding,
2564 			codepage);
2565 
2566 	if (1200 == codepage)		/* Unicode UTF-16, little-endian byte order */
2567 	{
2568 		wide_string = (wchar_t *)in;
2569 		wide_size = (int)in_size / 2;
2570 	}
2571 	else if (1201 == codepage)	/* unicodeFFFE UTF-16, big-endian byte order */
2572 	{
2573 		wchar_t	*wide_string_be = (wchar_t *)in;
2574 		int	i;
2575 
2576 		wide_size = (int)in_size / 2;
2577 
2578 		if (wide_size > STATIC_SIZE)
2579 			wide_string = (wchar_t *)zbx_malloc(wide_string, (size_t)wide_size * sizeof(wchar_t));
2580 		else
2581 			wide_string = wide_string_static;
2582 
2583 		/* convert from big-endian 'in' to little-endian 'wide_string' */
2584 		for (i = 0; i < wide_size; i++)
2585 			wide_string[i] = ((wide_string_be[i] << 8) & 0xff00) | ((wide_string_be[i] >> 8) & 0xff);
2586 	}
2587 	else
2588 	{
2589 		wide_size = MultiByteToWideChar(codepage, 0, in, (int)in_size, NULL, 0);
2590 
2591 		if (wide_size > STATIC_SIZE)
2592 			wide_string = (wchar_t *)zbx_malloc(wide_string, (size_t)wide_size * sizeof(wchar_t));
2593 		else
2594 			wide_string = wide_string_static;
2595 
2596 		/* convert from 'in' to 'wide_string' */
2597 		MultiByteToWideChar(codepage, 0, in, (int)in_size, wide_string, wide_size);
2598 	}
2599 
2600 	utf8_size = WideCharToMultiByte(CP_UTF8, 0, wide_string, wide_size, NULL, 0, NULL, NULL);
2601 	utf8_string = (char *)zbx_malloc(utf8_string, (size_t)utf8_size + 1/* '\0' */);
2602 
2603 	/* convert from 'wide_string' to 'utf8_string' */
2604 	WideCharToMultiByte(CP_UTF8, 0, wide_string, wide_size, utf8_string, utf8_size, NULL, NULL);
2605 	utf8_string[utf8_size] = '\0';
2606 	zabbix_log(LOG_LEVEL_DEBUG, "convert_to_utf8() utf8_size:%d utf8_string:'%s'", utf8_size, utf8_string);
2607 
2608 	if (wide_string != wide_string_static && wide_string != (wchar_t *)in)
2609 		zbx_free(wide_string);
2610 
2611 	return utf8_string;
2612 }
2613 #elif defined(HAVE_ICONV)
convert_to_utf8(char * in,size_t in_size,const char * encoding)2614 char	*convert_to_utf8(char *in, size_t in_size, const char *encoding)
2615 {
2616 	iconv_t		cd;
2617 	size_t		in_size_left, out_size_left, sz, out_alloc = 0;
2618 	const char	to_code[] = "UTF-8";
2619 	char		*out = NULL, *p;
2620 
2621 	out_alloc = in_size + 1;
2622 	p = out = zbx_malloc(out, out_alloc);
2623 
2624 	if ('\0' == *encoding || (iconv_t)-1 == (cd = iconv_open(to_code, encoding)))
2625 	{
2626 		memcpy(out, in, in_size);
2627 		out[in_size] = '\0';
2628 		return out;
2629 	}
2630 
2631 	in_size_left = in_size;
2632 	out_size_left = out_alloc - 1;
2633 
2634 	while ((size_t)(-1) == iconv(cd, &in, &in_size_left, &p, &out_size_left))
2635 	{
2636 		if (E2BIG != errno)
2637 			break;
2638 
2639 		sz = (size_t)(p - out);
2640 		out_alloc += in_size;
2641 		out_size_left += in_size;
2642 		p = out = zbx_realloc(out, out_alloc);
2643 		p += sz;
2644 	}
2645 
2646 	*p = '\0';
2647 
2648 	iconv_close(cd);
2649 
2650 	return out;
2651 }
2652 #endif	/* HAVE_ICONV */
2653 
zbx_strlen_utf8(const char * text)2654 size_t	zbx_strlen_utf8(const char *text)
2655 {
2656 	size_t	n = 0;
2657 
2658 	while ('\0' != *text)
2659 	{
2660 		if (0x80 != (0xc0 & *text++))
2661 			n++;
2662 	}
2663 
2664 	return n;
2665 }
2666 
2667 /******************************************************************************
2668  *                                                                            *
2669  * Function: zbx_utf8_char_len                                                *
2670  *                                                                            *
2671  * Purpose: Returns the size (in bytes) of an UTF-8 encoded character or 0    *
2672  *          if the character is not a valid UTF-8.                            *
2673  *                                                                            *
2674  * Parameters: text - [IN] pointer to the 1st byte of UTF-8 character         *
2675  *                                                                            *
2676  ******************************************************************************/
zbx_utf8_char_len(const char * text)2677 size_t	zbx_utf8_char_len(const char *text)
2678 {
2679 	if (0 == (*text & 0x80))		/* ASCII */
2680 		return 1;
2681 	else if (0xc0 == (*text & 0xe0))	/* 11000010-11011111 starts a 2-byte sequence */
2682 		return 2;
2683 	else if (0xe0 == (*text & 0xf0))	/* 11100000-11101111 starts a 3-byte sequence */
2684 		return 3;
2685 	else if (0xf0 == (*text & 0xf8))	/* 11110000-11110100 starts a 4-byte sequence */
2686 		return 4;
2687 #if ZBX_MAX_BYTES_IN_UTF8_CHAR != 4
2688 #	error "zbx_utf8_char_len() is not synchronized with ZBX_MAX_BYTES_IN_UTF8_CHAR"
2689 #endif
2690 	return 0;				/* not a valid UTF-8 character */
2691 }
2692 
2693 /******************************************************************************
2694  *                                                                            *
2695  * Function: zbx_strlen_utf8_nchars                                           *
2696  *                                                                            *
2697  * Purpose: calculates number of bytes in utf8 text limited by utf8_maxlen    *
2698  *          characters                                                        *
2699  *                                                                            *
2700  ******************************************************************************/
zbx_strlen_utf8_nchars(const char * text,size_t utf8_maxlen)2701 size_t	zbx_strlen_utf8_nchars(const char *text, size_t utf8_maxlen)
2702 {
2703 	size_t		sz = 0, csz = 0;
2704 	const char	*next;
2705 
2706 	while ('\0' != *text && 0 < utf8_maxlen && 0 != (csz = zbx_utf8_char_len(text)))
2707 	{
2708 		next = text + csz;
2709 		while (next > text)
2710 		{
2711 			if ('\0' == *text++)
2712 				return sz;
2713 		}
2714 		sz += csz;
2715 		utf8_maxlen--;
2716 	}
2717 
2718 	return sz;
2719 }
2720 
2721 /******************************************************************************
2722  *                                                                            *
2723  * Function: zbx_strlen_utf8_nbytes                                           *
2724  *                                                                            *
2725  * Purpose: calculates number of bytes in utf8 text limited by maxlen bytes   *
2726  *                                                                            *
2727  ******************************************************************************/
zbx_strlen_utf8_nbytes(const char * text,size_t maxlen)2728 size_t	zbx_strlen_utf8_nbytes(const char *text, size_t maxlen)
2729 {
2730 	size_t	sz;
2731 
2732 	sz = strlen(text);
2733 
2734 	if (sz > maxlen)
2735 	{
2736 		sz = maxlen;
2737 
2738 		/* ensure that the string is not cut in the middle of UTF-8 sequence */
2739 		while (0x80 == (0xc0 & text[sz]) && 0 < sz)
2740 			sz--;
2741 	}
2742 
2743 	return sz;
2744 }
2745 
2746 /******************************************************************************
2747  *                                                                            *
2748  * Function: zbx_replace_utf8                                                 *
2749  *                                                                            *
2750  * Purpose: replace non-ASCII UTF-8 characters with '?' character             *
2751  *                                                                            *
2752  * Parameters: text - [IN] pointer to the first char                          *
2753  *                                                                            *
2754  * Author: Aleksandrs Saveljevs                                               *
2755  *                                                                            *
2756  ******************************************************************************/
zbx_replace_utf8(const char * text)2757 char	*zbx_replace_utf8(const char *text)
2758 {
2759 	int	n;
2760 	char	*out, *p;
2761 
2762 	out = p = zbx_malloc(NULL, strlen(text) + 1);
2763 
2764 	while ('\0' != *text)
2765 	{
2766 		if (0 == (*text & 0x80))		/* ASCII */
2767 			n = 1;
2768 		else if (0xc0 == (*text & 0xe0))	/* 11000010-11011111 is a start of 2-byte sequence */
2769 			n = 2;
2770 		else if (0xe0 == (*text & 0xf0))	/* 11100000-11101111 is a start of 3-byte sequence */
2771 			n = 3;
2772 		else if (0xf0 == (*text & 0xf8))	/* 11110000-11110100 is a start of 4-byte sequence */
2773 			n = 4;
2774 		else
2775 			goto bad;
2776 
2777 		if (1 == n)
2778 			*p++ = *text++;
2779 		else
2780 		{
2781 			*p++ = ZBX_UTF8_REPLACE_CHAR;
2782 
2783 			while (0 != n)
2784 			{
2785 				if ('\0' == *text)
2786 					goto bad;
2787 				n--;
2788 				text++;
2789 			}
2790 		}
2791 	}
2792 
2793 	*p = '\0';
2794 	return out;
2795 bad:
2796 	zbx_free(out);
2797 	return NULL;
2798 }
2799 
2800 /******************************************************************************
2801  *                                                                            *
2802  * Function: zbx_is_utf8                                                      *
2803  *                                                                            *
2804  * Purpose: check UTF-8 sequences                                             *
2805  *                                                                            *
2806  * Parameters: text - [IN] pointer to the string                              *
2807  *                                                                            *
2808  * Return value: SUCCEED if string is valid or FAIL otherwise                 *
2809  *                                                                            *
2810  ******************************************************************************/
zbx_is_utf8(const char * text)2811 int	zbx_is_utf8(const char *text)
2812 {
2813 	unsigned int	utf32;
2814 	unsigned char	*utf8;
2815 	size_t		i, mb_len, expecting_bytes = 0;
2816 
2817 	while ('\0' != *text)
2818 	{
2819 		/* single ASCII character */
2820 		if (0 == (*text & 0x80))
2821 		{
2822 			text++;
2823 			continue;
2824 		}
2825 
2826 		/* unexpected continuation byte or invalid UTF-8 bytes '\xfe' & '\xff' */
2827 		if (0x80 == (*text & 0xc0) || 0xfe == (*text & 0xfe))
2828 			return FAIL;
2829 
2830 		/* multibyte sequence */
2831 
2832 		utf8 = (unsigned char *)text;
2833 
2834 		if (0xc0 == (*text & 0xe0))		/* 2-bytes multibyte sequence */
2835 			expecting_bytes = 1;
2836 		else if (0xe0 == (*text & 0xf0))	/* 3-bytes multibyte sequence */
2837 			expecting_bytes = 2;
2838 		else if (0xf0 == (*text & 0xf8))	/* 4-bytes multibyte sequence */
2839 			expecting_bytes = 3;
2840 		else if (0xf8 == (*text & 0xfc))	/* 5-bytes multibyte sequence */
2841 			expecting_bytes = 4;
2842 		else if (0xfc == (*text & 0xfe))	/* 6-bytes multibyte sequence */
2843 			expecting_bytes = 5;
2844 
2845 		mb_len = expecting_bytes + 1;
2846 		text++;
2847 
2848 		for (; 0 != expecting_bytes; expecting_bytes--)
2849 		{
2850 			/* not a continuation byte */
2851 			if (0x80 != (*text++ & 0xc0))
2852 				return FAIL;
2853 		}
2854 
2855 		/* overlong sequence */
2856 		if (0xc0 == (utf8[0] & 0xfe) ||
2857 				(0xe0 == utf8[0] && 0x00 == (utf8[1] & 0x20)) ||
2858 				(0xf0 == utf8[0] && 0x00 == (utf8[1] & 0x30)) ||
2859 				(0xf8 == utf8[0] && 0x00 == (utf8[1] & 0x38)) ||
2860 				(0xfc == utf8[0] && 0x00 == (utf8[1] & 0x3c)))
2861 		{
2862 			return FAIL;
2863 		}
2864 
2865 		utf32 = 0;
2866 
2867 		if (0xc0 == (utf8[0] & 0xe0))
2868 			utf32 = utf8[0] & 0x1f;
2869 		else if (0xe0 == (utf8[0] & 0xf0))
2870 			utf32 = utf8[0] & 0x0f;
2871 		else if (0xf0 == (utf8[0] & 0xf8))
2872 			utf32 = utf8[0] & 0x07;
2873 		else if (0xf8 == (utf8[0] & 0xfc))
2874 			utf32 = utf8[0] & 0x03;
2875 		else if (0xfc == (utf8[0] & 0xfe))
2876 			utf32 = utf8[0] & 0x01;
2877 
2878 		for (i = 1; i < mb_len; i++)
2879 		{
2880 			utf32 <<= 6;
2881 			utf32 += utf8[i] & 0x3f;
2882 		}
2883 
2884 		/* according to the Unicode standard the high and low
2885 		 * surrogate halves used by UTF-16 (U+D800 through U+DFFF)
2886 		 * and values above U+10FFFF are not legal
2887 		 */
2888 		if (utf32 > 0x10ffff || 0xd800 == (utf32 & 0xf800))
2889 			return FAIL;
2890 	}
2891 
2892 	return SUCCEED;
2893 }
2894 
2895 /******************************************************************************
2896  *                                                                            *
2897  * Function: zbx_replace_invalid_utf8                                         *
2898  *                                                                            *
2899  * Purpose: replace invalid UTF-8 sequences of bytes with '?' character       *
2900  *                                                                            *
2901  * Parameters: text - [IN/OUT] pointer to the first char                      *
2902  *                                                                            *
2903  ******************************************************************************/
zbx_replace_invalid_utf8(char * text)2904 void	zbx_replace_invalid_utf8(char *text)
2905 {
2906 	char	*out = text;
2907 
2908 	while ('\0' != *text)
2909 	{
2910 		if (0 == (*text & 0x80))			/* single ASCII character */
2911 			*out++ = *text++;
2912 		else if (0x80 == (*text & 0xc0) ||		/* unexpected continuation byte */
2913 				0xfe == (*text & 0xfe))		/* invalid UTF-8 bytes '\xfe' & '\xff' */
2914 		{
2915 			*out++ = ZBX_UTF8_REPLACE_CHAR;
2916 			text++;
2917 		}
2918 		else						/* multibyte sequence */
2919 		{
2920 			unsigned int	utf32;
2921 			unsigned char	*utf8 = (unsigned char *)out;
2922 			size_t		i, mb_len, expecting_bytes = 0;
2923 			int		ret = SUCCEED;
2924 
2925 			if (0xc0 == (*text & 0xe0))		/* 2-bytes multibyte sequence */
2926 				expecting_bytes = 1;
2927 			else if (0xe0 == (*text & 0xf0))	/* 3-bytes multibyte sequence */
2928 				expecting_bytes = 2;
2929 			else if (0xf0 == (*text & 0xf8))	/* 4-bytes multibyte sequence */
2930 				expecting_bytes = 3;
2931 			else if (0xf8 == (*text & 0xfc))	/* 5-bytes multibyte sequence */
2932 				expecting_bytes = 4;
2933 			else if (0xfc == (*text & 0xfe))	/* 6-bytes multibyte sequence */
2934 				expecting_bytes = 5;
2935 
2936 			*out++ = *text++;
2937 
2938 			for (; 0 != expecting_bytes; expecting_bytes--)
2939 			{
2940 				if (0x80 != (*text & 0xc0))	/* not a continuation byte */
2941 				{
2942 					ret = FAIL;
2943 					break;
2944 				}
2945 
2946 				*out++ = *text++;
2947 			}
2948 
2949 			mb_len = out - (char *)utf8;
2950 
2951 			if (SUCCEED == ret)
2952 			{
2953 				if (0xc0 == (utf8[0] & 0xfe) ||	/* overlong sequence */
2954 						(0xe0 == utf8[0] && 0x00 == (utf8[1] & 0x20)) ||
2955 						(0xf0 == utf8[0] && 0x00 == (utf8[1] & 0x30)) ||
2956 						(0xf8 == utf8[0] && 0x00 == (utf8[1] & 0x38)) ||
2957 						(0xfc == utf8[0] && 0x00 == (utf8[1] & 0x3c)))
2958 				{
2959 					ret = FAIL;
2960 				}
2961 			}
2962 
2963 			if (SUCCEED == ret)
2964 			{
2965 				utf32 = 0;
2966 
2967 				if (0xc0 == (utf8[0] & 0xe0))
2968 					utf32 = utf8[0] & 0x1f;
2969 				else if (0xe0 == (utf8[0] & 0xf0))
2970 					utf32 = utf8[0] & 0x0f;
2971 				else if (0xf0 == (utf8[0] & 0xf8))
2972 					utf32 = utf8[0] & 0x07;
2973 				else if (0xf8 == (utf8[0] & 0xfc))
2974 					utf32 = utf8[0] & 0x03;
2975 				else if (0xfc == (utf8[0] & 0xfe))
2976 					utf32 = utf8[0] & 0x01;
2977 
2978 				for (i = 1; i < mb_len; i++)
2979 				{
2980 					utf32 <<= 6;
2981 					utf32 += utf8[i] & 0x3f;
2982 				}
2983 
2984 				/* according to the Unicode standard the high and low
2985 				 * surrogate halves used by UTF-16 (U+D800 through U+DFFF)
2986 				 * and values above U+10FFFF are not legal
2987 				 */
2988 				if (utf32 > 0x10ffff || 0xd800 == (utf32 & 0xf800))
2989 					ret = FAIL;
2990 			}
2991 
2992 			if (SUCCEED != ret)
2993 			{
2994 				out -= mb_len;
2995 				*out++ = ZBX_UTF8_REPLACE_CHAR;
2996 			}
2997 		}
2998 	}
2999 
3000 	*out = '\0';
3001 }
3002 
dos2unix(char * str)3003 void	dos2unix(char *str)
3004 {
3005 	char	*o = str;
3006 
3007 	while ('\0' != *str)
3008 	{
3009 		if ('\r' == str[0] && '\n' == str[1])	/* CR+LF (Windows) */
3010 			str++;
3011 		*o++ = *str++;
3012 	}
3013 	*o = '\0';
3014 }
3015 
is_ascii_string(const char * str)3016 int	is_ascii_string(const char *str)
3017 {
3018 	while ('\0' != *str)
3019 	{
3020 		if (0 != ((1 << 7) & *str))	/* check for range 0..127 */
3021 			return FAIL;
3022 
3023 		str++;
3024 	}
3025 
3026 	return SUCCEED;
3027 }
3028 
3029 /******************************************************************************
3030  *                                                                            *
3031  * Function: str_linefeed                                                     *
3032  *                                                                            *
3033  * Purpose: wrap long string at specified position with linefeeds             *
3034  *                                                                            *
3035  * Parameters: src     - input string                                         *
3036  *             maxline - maximum length of a line                             *
3037  *             delim   - delimiter to use as linefeed (default "\n" if NULL)  *
3038  *                                                                            *
3039  * Return value: newly allocated copy of input string with linefeeds          *
3040  *                                                                            *
3041  * Author: Vladimir Levijev                                                   *
3042  *                                                                            *
3043  * Comments: allocates memory                                                 *
3044  *                                                                            *
3045  ******************************************************************************/
str_linefeed(const char * src,size_t maxline,const char * delim)3046 char	*str_linefeed(const char *src, size_t maxline, const char *delim)
3047 {
3048 	size_t		src_size, dst_size, delim_size, left;
3049 	int		feeds;		/* number of feeds */
3050 	char		*dst = NULL;	/* output with linefeeds */
3051 	const char	*p_src;
3052 	char		*p_dst;
3053 
3054 	assert(NULL != src);
3055 	assert(0 < maxline);
3056 
3057 	/* default delimiter */
3058 	if (NULL == delim)
3059 		delim = "\n";
3060 
3061 	src_size = strlen(src);
3062 	delim_size = strlen(delim);
3063 
3064 	/* make sure we don't feed the last line */
3065 	feeds = (int)(src_size / maxline - (0 != src_size % maxline || 0 == src_size ? 0 : 1));
3066 
3067 	left = src_size - feeds * maxline;
3068 	dst_size = src_size + feeds * delim_size + 1;
3069 
3070 	/* allocate memory for output */
3071 	dst = zbx_malloc(dst, dst_size);
3072 
3073 	p_src = src;
3074 	p_dst = dst;
3075 
3076 	/* copy chunks appending linefeeds */
3077 	while (0 < feeds--)
3078 	{
3079 		memcpy(p_dst, p_src, maxline);
3080 		p_src += maxline;
3081 		p_dst += maxline;
3082 
3083 		memcpy(p_dst, delim, delim_size);
3084 		p_dst += delim_size;
3085 	}
3086 
3087 	if (0 < left)
3088 	{
3089 		/* copy what's left */
3090 		memcpy(p_dst, p_src, left);
3091 		p_dst += left;
3092 	}
3093 
3094 	*p_dst = '\0';
3095 
3096 	return dst;
3097 }
3098 
3099 /******************************************************************************
3100  *                                                                            *
3101  * Function: zbx_strarr_init                                                  *
3102  *                                                                            *
3103  * Purpose: initialize dynamic string array                                   *
3104  *                                                                            *
3105  * Parameters: arr - a pointer to array of strings                            *
3106  *                                                                            *
3107  * Return value:                                                              *
3108  *                                                                            *
3109  * Author: Vladimir Levijev                                                   *
3110  *                                                                            *
3111  * Comments: allocates memory, calls assert() if that fails                   *
3112  *                                                                            *
3113  ******************************************************************************/
zbx_strarr_init(char *** arr)3114 void	zbx_strarr_init(char ***arr)
3115 {
3116 	*arr = zbx_malloc(*arr, sizeof(char *));
3117 	**arr = NULL;
3118 }
3119 
3120 /******************************************************************************
3121  *                                                                            *
3122  * Function: zbx_strarr_add                                                   *
3123  *                                                                            *
3124  * Purpose: add a string to dynamic string array                              *
3125  *                                                                            *
3126  * Parameters: arr - a pointer to array of strings                            *
3127  *             entry - string to add                                          *
3128  *                                                                            *
3129  * Return value:                                                              *
3130  *                                                                            *
3131  * Author: Vladimir Levijev                                                   *
3132  *                                                                            *
3133  * Comments: allocates memory, calls assert() if that fails                   *
3134  *                                                                            *
3135  ******************************************************************************/
zbx_strarr_add(char *** arr,const char * entry)3136 void	zbx_strarr_add(char ***arr, const char *entry)
3137 {
3138 	int	i;
3139 
3140 	assert(entry);
3141 
3142 	for (i = 0; NULL != (*arr)[i]; i++)
3143 		;
3144 
3145 	*arr = zbx_realloc(*arr, sizeof(char *) * (i + 2));
3146 
3147 	(*arr)[i] = zbx_strdup((*arr)[i], entry);
3148 	(*arr)[++i] = NULL;
3149 }
3150 
3151 /******************************************************************************
3152  *                                                                            *
3153  * Function: zbx_strarr_free                                                  *
3154  *                                                                            *
3155  * Purpose: free dynamic string array memory                                  *
3156  *                                                                            *
3157  * Parameters: arr - array of strings                                         *
3158  *                                                                            *
3159  * Return value:                                                              *
3160  *                                                                            *
3161  * Author: Vladimir Levijev                                                   *
3162  *                                                                            *
3163  ******************************************************************************/
zbx_strarr_free(char ** arr)3164 void	zbx_strarr_free(char **arr)
3165 {
3166 	char	**p;
3167 
3168 	for (p = arr; NULL != *p; p++)
3169 		zbx_free(*p);
3170 	zbx_free(arr);
3171 }
3172 
3173 /******************************************************************************
3174  *                                                                            *
3175  * Function: zbx_replace_string                                               *
3176  *                                                                            *
3177  * Purpose: replace data block with 'value'                                   *
3178  *                                                                            *
3179  * Parameters: data  - [IN/OUT] pointer to the string                         *
3180  *             l     - [IN] left position of the block                        *
3181  *             r     - [IN/OUT] right position of the block                   *
3182  *             value - [IN] the string to replace the block with              *
3183  *                                                                            *
3184  * Author: Alexander Vladishev                                                *
3185  *                                                                            *
3186  ******************************************************************************/
zbx_replace_string(char ** data,size_t l,size_t * r,const char * value)3187 void	zbx_replace_string(char **data, size_t l, size_t *r, const char *value)
3188 {
3189 	size_t	sz_data, sz_block, sz_value;
3190 	char	*src, *dst;
3191 
3192 	sz_value = strlen(value);
3193 	sz_block = *r - l + 1;
3194 
3195 	if (sz_value != sz_block)
3196 	{
3197 		sz_data = *r + strlen(*data + *r);
3198 		sz_data += sz_value - sz_block;
3199 
3200 		if (sz_value > sz_block)
3201 			*data = zbx_realloc(*data, sz_data + 1);
3202 
3203 		src = *data + l + sz_block;
3204 		dst = *data + l + sz_value;
3205 
3206 		memmove(dst, src, sz_data - l - sz_value + 1);
3207 
3208 		*r = l + sz_value - 1;
3209 	}
3210 
3211 	memcpy(&(*data)[l], value, sz_value);
3212 }
3213 
3214 /******************************************************************************
3215  *                                                                            *
3216  * Function: zbx_trim_str_list                                                *
3217  *                                                                            *
3218  * Purpose: remove whitespace surrounding a string list item delimiters       *
3219  *                                                                            *
3220  * Parameters: list      - the list (a string containing items separated by   *
3221  *                         delimiter)                                         *
3222  *             delimiter - the list delimiter                                 *
3223  *                                                                            *
3224  * Author: Andris Zeila                                                       *
3225  *                                                                            *
3226  ******************************************************************************/
zbx_trim_str_list(char * list,char delimiter)3227 void	zbx_trim_str_list(char *list, char delimiter)
3228 {
3229 	/* NB! strchr(3): "terminating null byte is considered part of the string" */
3230 	const char	*whitespace = " \t";
3231 	char		*out, *in;
3232 
3233 	out = in = list;
3234 
3235 	while ('\0' != *in)
3236 	{
3237 		/* trim leading spaces from list item */
3238 		while ('\0' != *in && NULL != strchr(whitespace, *in))
3239 			in++;
3240 
3241 		/* copy list item */
3242 		while (delimiter != *in && '\0' != *in)
3243 			*out++ = *in++;
3244 
3245 		/* trim trailing spaces from list item */
3246 		if (out > list)
3247 		{
3248 			while (NULL != strchr(whitespace, *(--out)))
3249 				;
3250 			out++;
3251 		}
3252 		if (delimiter == *in)
3253 			*out++ = *in++;
3254 	}
3255 	*out = '\0';
3256 }
3257 
3258 /******************************************************************************
3259  *                                                                            *
3260  * Function: zbx_strcmp_null                                                  *
3261  *                                                                            *
3262  * Purpose:                                                                   *
3263  *     compares two strings where any of them can be a NULL pointer           *
3264  *                                                                            *
3265  * Parameters: same as strcmp() except NULL values are allowed                *
3266  *                                                                            *
3267  * Return value: same as strcmp()                                             *
3268  *                                                                            *
3269  * Comments: NULL is less than any string                                     *
3270  *                                                                            *
3271  ******************************************************************************/
zbx_strcmp_null(const char * s1,const char * s2)3272 int	zbx_strcmp_null(const char *s1, const char *s2)
3273 {
3274 	if (NULL == s1)
3275 		return NULL == s2 ? 0 : -1;
3276 
3277 	if (NULL == s2)
3278 		return 1;
3279 
3280 	return strcmp(s1, s2);
3281 }
3282 
3283 /******************************************************************************
3284  *                                                                            *
3285  * Function: zbx_user_macro_parse                                             *
3286  *                                                                            *
3287  * Purpose:                                                                   *
3288  *     parses user macro and finds its end position and context location      *
3289  *                                                                            *
3290  * Parameters:                                                                *
3291  *     macro     - [IN] the macro to parse                                    *
3292  *     macro_r   - [OUT] the position of ending '}' character                 *
3293  *     context_l - [OUT] the position of context start character (first non   *
3294  *                       space character after context separator ':')         *
3295  *                       0 if macro does not have context specified.          *
3296  *     context_r - [OUT] the position of context end character (either the    *
3297  *                       ending '"' for quoted context values or the last     *
3298  *                       character before the ending '}' character)           *
3299  *                       0 if macro does not have context specified.          *
3300  *                                                                            *
3301  * Return value:                                                              *
3302  *     SUCCEED - the macro was parsed successfully.                           *
3303  *     FAIL    - the macro parsing failed, the content of output variables    *
3304  *               is not defined.                                              *
3305  *                                                                            *
3306  ******************************************************************************/
zbx_user_macro_parse(const char * macro,int * macro_r,int * context_l,int * context_r)3307 int	zbx_user_macro_parse(const char *macro, int *macro_r, int *context_l, int *context_r)
3308 {
3309 	int	i;
3310 
3311 	/* find the end of macro name by skipping {$ characters and iterating through */
3312 	/* valid macro name characters                                                */
3313 	for (i = 2; SUCCEED == is_macro_char(macro[i]); i++)
3314 		;
3315 
3316 	/* check for empty macro name */
3317 	if (2 == i)
3318 		return FAIL;
3319 
3320 	if ('}' == macro[i])
3321 	{
3322 		/* no macro context specified, parsing done */
3323 		*macro_r = i;
3324 		*context_l = 0;
3325 		*context_r = 0;
3326 		return SUCCEED;
3327 	}
3328 
3329 	/* fail if the next character is not a macro context separator */
3330 	if  (':' != macro[i])
3331 		return FAIL;
3332 
3333 	/* skip the whitespace after macro context separator */
3334 	while (' ' == macro[++i])
3335 		;
3336 
3337 	*context_l = i;
3338 
3339 	if ('"' == macro[i])
3340 	{
3341 		i++;
3342 
3343 		/* process quoted context */
3344 		for (; '"' != macro[i]; i++)
3345 		{
3346 			if ('\0' == macro[i])
3347 				return FAIL;
3348 
3349 			if ('\\' == macro[i] && '"' == macro[i + 1])
3350 				i++;
3351 		}
3352 
3353 		*context_r = i;
3354 
3355 		while (' ' == macro[++i])
3356 			;
3357 	}
3358 	else
3359 	{
3360 		/* process unquoted context */
3361 		for (; '}' != macro[i]; i++)
3362 		{
3363 			if ('\0' == macro[i])
3364 				return FAIL;
3365 		}
3366 
3367 		*context_r = i - 1;
3368 	}
3369 
3370 	if ('}' != macro[i])
3371 		return FAIL;
3372 
3373 	*macro_r = i;
3374 
3375 	return SUCCEED;
3376 }
3377 
3378 /******************************************************************************
3379  *                                                                            *
3380  * Function: zbx_user_macro_parse_dyn                                         *
3381  *                                                                            *
3382  * Purpose:                                                                   *
3383  *     parses user macro {$MACRO:<context>} into {$MACRO} and <context>       *
3384  *     strings                                                                *
3385  *                                                                            *
3386  * Parameters:                                                                *
3387  *     macro   - [IN] the macro to parse                                      *
3388  *     name    - [OUT] the macro name without context                         *
3389  *     context - [OUT] the unquoted macro context, NULL for macros without    *
3390  *                     context                                                *
3391  *     length  - [OUT] the length of parsed macro (optional)                  *
3392  *                                                                            *
3393  * Return value:                                                              *
3394  *     SUCCEED - the macro was parsed successfully                            *
3395  *     FAIL    - the macro parsing failed, invalid parameter syntax           *
3396  *                                                                            *
3397  ******************************************************************************/
zbx_user_macro_parse_dyn(const char * macro,char ** name,char ** context,int * length)3398 int	zbx_user_macro_parse_dyn(const char *macro, char **name, char **context, int *length)
3399 {
3400 	const char	*ptr;
3401 	int		macro_r, context_l, context_r, len;
3402 
3403 	if (SUCCEED != zbx_user_macro_parse(macro, &macro_r, &context_l, &context_r))
3404 		return FAIL;
3405 
3406 	zbx_free(*context);
3407 
3408 	if (0 != context_l)
3409 	{
3410 		ptr = macro + context_l;
3411 
3412 		/* find the context separator ':' by stripping spaces before context */
3413 		while (' ' == *(--ptr))
3414 			;
3415 
3416 		/* extract the macro name and close with '}' character */
3417 		len = ptr - macro + 1;
3418 		*name = zbx_realloc(*name, len + 1);
3419 		memcpy(*name, macro, len - 1);
3420 		(*name)[len - 1] = '}';
3421 		(*name)[len] = '\0';
3422 
3423 		*context = zbx_user_macro_unquote_context_dyn(macro + context_l, context_r - context_l + 1);
3424 	}
3425 	else
3426 	{
3427 		*name = zbx_realloc(*name, macro_r + 2);
3428 		zbx_strlcpy(*name, macro, macro_r + 2);
3429 	}
3430 
3431 	if (NULL != length)
3432 		*length = macro_r + 1;
3433 
3434 	return SUCCEED;
3435 }
3436 
3437 /******************************************************************************
3438  *                                                                            *
3439  * Function: zbx_user_macro_unquote_context_dyn                               *
3440  *                                                                            *
3441  * Purpose:                                                                   *
3442  *     extracts the macro context unquoting if necessary                      *
3443  *                                                                            *
3444  * Parameters:                                                                *
3445  *     context - [IN] the macro context inside a user macro                   *
3446  *     len     - [IN] the macro context length (including quotes for quoted   *
3447  *                    contexts)                                               *
3448  *                                                                            *
3449  * Return value:                                                              *
3450  *     A string containing extracted macro context. This string must be freed *
3451  *     by the caller.                                                         *
3452  *                                                                            *
3453  ******************************************************************************/
zbx_user_macro_unquote_context_dyn(const char * context,int len)3454 char	*zbx_user_macro_unquote_context_dyn(const char *context, int len)
3455 {
3456 	int	quoted = 0;
3457 	char	*buffer, *ptr;
3458 
3459 	ptr = buffer = zbx_malloc(NULL, len + 1);
3460 
3461 	if ('"' == *context)
3462 	{
3463 		quoted = 1;
3464 		context++;
3465 		len--;
3466 	}
3467 
3468 	while (0 < len)
3469 	{
3470 		if (1 == quoted && '\\' == *context && '"' == context[1])
3471 		{
3472 			context++;
3473 			len--;
3474 		}
3475 
3476 		*ptr++ = *context++;
3477 		len--;
3478 	}
3479 
3480 	if (1 == quoted)
3481 		ptr--;
3482 
3483 	*ptr = '\0';
3484 
3485 	return buffer;
3486 }
3487 
3488 /******************************************************************************
3489  *                                                                            *
3490  * Function: zbx_user_macro_quote_context_dyn                                 *
3491  *                                                                            *
3492  * Purpose:                                                                   *
3493  *     quotes user macro context if necessary                                 *
3494  *                                                                            *
3495  * Parameters:                                                                *
3496  *     context     - [IN] the macro context                                   *
3497  *     force_quote - [IN] if non zero then context quoting is enforced        *
3498  *                                                                            *
3499  * Return value:                                                              *
3500  *     A string containing quoted macro context. This string must be freed by *
3501  *     the caller.                                                            *
3502  *                                                                            *
3503  ******************************************************************************/
zbx_user_macro_quote_context_dyn(const char * context,int force_quote)3504 char	*zbx_user_macro_quote_context_dyn(const char *context, int force_quote)
3505 {
3506 	int		len, quotes = 0;
3507 	char		*buffer, *ptr_buffer;
3508 	const char	*ptr_context = context;
3509 
3510 	if ('"' == *ptr_context || ' ' == *ptr_context)
3511 		force_quote = 1;
3512 
3513 	for (; '\0' != *ptr_context; ptr_context++)
3514 	{
3515 		if ('}' == *ptr_context)
3516 			force_quote = 1;
3517 
3518 		if ('"' == *ptr_context)
3519 			quotes++;
3520 	}
3521 
3522 	if (0 == force_quote)
3523 		return zbx_strdup(NULL, context);
3524 
3525 	len = strlen(context) + 2 + quotes;
3526 	ptr_buffer = buffer = zbx_malloc(NULL, len + 1);
3527 
3528 	*ptr_buffer++ = '"';
3529 
3530 	while ('\0' != *context)
3531 	{
3532 		if ('"' == *context)
3533 			*ptr_buffer++ = '\\';
3534 
3535 		*ptr_buffer++ = *context++;
3536 	}
3537 
3538 	*ptr_buffer++ = '"';
3539 	*ptr_buffer++ = '\0';
3540 
3541 	return buffer;
3542 }
3543 
3544 /******************************************************************************
3545  *                                                                            *
3546  * Function: zbx_dyn_escape_shell_single_quote                                *
3547  *                                                                            *
3548  * Purpose: escape single quote in shell command arguments                    *
3549  *                                                                            *
3550  * Parameters: arg - [IN] the argument to escape                              *
3551  *                                                                            *
3552  * Return value: The escaped argument.                                        *
3553  *                                                                            *
3554  ******************************************************************************/
zbx_dyn_escape_shell_single_quote(const char * arg)3555 char	*zbx_dyn_escape_shell_single_quote(const char *arg)
3556 {
3557 	int		len = 1; /* include terminating zero character */
3558 	const char	*pin;
3559 	char		*arg_esc, *pout;
3560 
3561 	for (pin = arg; '\0' != *pin; pin++)
3562 	{
3563 		if ('\'' == *pin)
3564 			len += 3;
3565 		len++;
3566 	}
3567 
3568 	pout = arg_esc = zbx_malloc(NULL, len);
3569 
3570 	for (pin = arg; '\0' != *pin; pin++)
3571 	{
3572 		if ('\'' == *pin)
3573 		{
3574 			*pout++ = '\'';
3575 			*pout++ = '\\';
3576 			*pout++ = '\'';
3577 			*pout++ = '\'';
3578 		}
3579 		else
3580 			*pout++ = *pin;
3581 	}
3582 
3583 	*pout = '\0';
3584 
3585 	return arg_esc;
3586 }
3587 
3588 /******************************************************************************
3589  *                                                                            *
3590  * Function: function_parse_name                                              *
3591  *                                                                            *
3592  * Purpose: parses function name                                              *
3593  *                                                                            *
3594  * Parameters: expr     - [IN] the function expression: func(p1, p2,...)      *
3595  *             length   - [OUT] the function name length or the amount of     *
3596  *                              characters that can be safely skipped         *
3597  *                                                                            *
3598  * Return value: SUCCEED - the function name was successfully parsed          *
3599  *               FAIL    - failed to parse function name                      *
3600  *                                                                            *
3601  ******************************************************************************/
function_parse_name(const char * expr,size_t * length)3602 static int	function_parse_name(const char *expr, size_t *length)
3603 {
3604 	const char	*ptr;
3605 
3606 	for (ptr = expr; SUCCEED == is_function_char(*ptr); ptr++)
3607 		;
3608 
3609 	*length = ptr - expr;
3610 
3611 	return ptr != expr && '(' == *ptr ? SUCCEED : FAIL;
3612 }
3613 
3614 /******************************************************************************
3615  *                                                                            *
3616  * Function: zbx_function_param_parse                                         *
3617  *                                                                            *
3618  * Purpose: parses function parameter                                         *
3619  *                                                                            *
3620  * Parameters: expr      - [IN] pre-validated function parameter list         *
3621  *             param_pos - [OUT] the parameter position, excluding leading    *
3622  *                               whitespace                                   *
3623  *             length    - [OUT] the parameter length including trailing      *
3624  *                               whitespace for unquoted parameter            *
3625  *             sep_pos   - [OUT] the parameter separator character            *
3626  *                               (',' or '\0') position                       *
3627  *                                                                            *
3628  ******************************************************************************/
zbx_function_param_parse(const char * expr,size_t * param_pos,size_t * length,size_t * sep_pos)3629 void	zbx_function_param_parse(const char *expr, size_t *param_pos, size_t *length, size_t *sep_pos)
3630 {
3631 	const char	*ptr = expr;
3632 
3633 	/* skip the leading whitespace */
3634 	while (' ' == *ptr)
3635 		ptr++;
3636 
3637 	*param_pos = ptr - expr;
3638 
3639 	if ('"' == *ptr)	/* quoted parameter */
3640 	{
3641 		for (ptr++; '"' != *ptr || '\\' == *(ptr - 1); ptr++)
3642 			;
3643 
3644 		*length = ++ptr - expr - *param_pos;
3645 
3646 		/* skip trailing whitespace to find the next parameter */
3647 		while (' ' == *ptr)
3648 			ptr++;
3649 	}
3650 	else	/* unquoted parameter */
3651 	{
3652 		for (ptr = expr; '\0' != *ptr && ',' != *ptr; ptr++)
3653 			;
3654 
3655 		*length = ptr - expr - *param_pos;
3656 	}
3657 
3658 	*sep_pos = ptr - expr;
3659 }
3660 
3661 /******************************************************************************
3662  *                                                                            *
3663  * Function: zbx_function_param_unquote_dyn                                   *
3664  *                                                                            *
3665  * Purpose: unquotes function parameter                                       *
3666  *                                                                            *
3667  * Parameters: param -  [IN] the parameter to unquote                         *
3668  *             len   -  [IN] the parameter length                             *
3669  *             quoted - [OUT] the flag that specifies whether parameter was   *
3670  *                            quoted before extraction                        *
3671  *                                                                            *
3672  * Return value: The unquoted parameter. This value must be freed by the      *
3673  *               caller.                                                      *
3674  *                                                                            *
3675  ******************************************************************************/
zbx_function_param_unquote_dyn(const char * param,size_t len,int * quoted)3676 char	*zbx_function_param_unquote_dyn(const char *param, size_t len, int *quoted)
3677 {
3678 	char	*out;
3679 
3680 	out = (char *)zbx_malloc(NULL, len + 1);
3681 
3682 	if (0 == (*quoted = (0 != len && '"' == *param)))
3683 	{
3684 		/* unquoted parameter - simply copy it */
3685 		memcpy(out, param, len);
3686 		out[len] = '\0';
3687 	}
3688 	else
3689 	{
3690 		/* quoted parameter - remove enclosing " and replace \" with " */
3691 		const char	*pin;
3692 		char		*pout = out;
3693 
3694 		for (pin = param + 1; (size_t)(pin - param) < len - 1; pin++)
3695 		{
3696 			if ('\\' == pin[0] && '"' == pin[1])
3697 				pin++;
3698 
3699 			*pout++ = *pin;
3700 		}
3701 
3702 		*pout = '\0';
3703 	}
3704 
3705 	return out;
3706 }
3707 
3708 /******************************************************************************
3709  *                                                                            *
3710  * Function: zbx_function_param_quote                                         *
3711  *                                                                            *
3712  * Purpose: quotes function parameter                                         *
3713  *                                                                            *
3714  * Parameters: param   - [IN/OUT] function parameter                          *
3715  *             forced  - [IN] 1 - enclose parameter in " even if it does not  *
3716  *                                contain any special characters              *
3717  *                            0 - do nothing if the parameter does not        *
3718  *                                contain any special characters              *
3719  *                                                                            *
3720  * Return value: SUCCEED - if parameter was successfully quoted or quoting    *
3721  *                         was not necessary                                  *
3722  *               FAIL    - if parameter needs to but cannot be quoted due to  *
3723  *                         backslash in the end                               *
3724  *                                                                            *
3725  ******************************************************************************/
zbx_function_param_quote(char ** param,int forced)3726 int	zbx_function_param_quote(char **param, int forced)
3727 {
3728 	size_t	sz_src, sz_dst;
3729 
3730 	if (0 == forced && '"' != **param && ' ' != **param && NULL == strchr(*param, ',') &&
3731 			NULL == strchr(*param, ')'))
3732 	{
3733 		return SUCCEED;
3734 	}
3735 
3736 	if (0 != (sz_src = strlen(*param)) && '\\' == (*param)[sz_src - 1])
3737 		return FAIL;
3738 
3739 	sz_dst = zbx_get_escape_string_len(*param, "\"") + 3;
3740 
3741 	*param = zbx_realloc(*param, sz_dst);
3742 
3743 	(*param)[--sz_dst] = '\0';
3744 	(*param)[--sz_dst] = '"';
3745 
3746 	while (0 < sz_src)
3747 	{
3748 		(*param)[--sz_dst] = (*param)[--sz_src];
3749 		if ('"' == (*param)[sz_src])
3750 			(*param)[--sz_dst] = '\\';
3751 	}
3752 	(*param)[--sz_dst] = '"';
3753 
3754 	return SUCCEED;
3755 }
3756 
3757 /******************************************************************************
3758  *                                                                            *
3759  * Function: zbx_function_get_param_dyn                                       *
3760  *                                                                            *
3761  * Purpose: return parameter by index (Nparam) from parameter list (params)   *
3762  *                                                                            *
3763  * Parameters:                                                                *
3764  *      params - [IN] parameter list                                          *
3765  *      Nparam - [IN] requested parameter index (from 1)                      *
3766  *                                                                            *
3767  * Return value:                                                              *
3768  *      NULL - requested parameter missing                                    *
3769  *      otherwise - requested parameter                                       *
3770  *                                                                            *
3771  ******************************************************************************/
zbx_function_get_param_dyn(const char * params,int Nparam)3772 char	*zbx_function_get_param_dyn(const char *params, int Nparam)
3773 {
3774 	const char	*ptr;
3775 	size_t		sep_pos, params_len;
3776 	char		*out = NULL;
3777 	int		idx = 0;
3778 
3779 	params_len = strlen(params) + 1;
3780 
3781 	for (ptr = params; ++idx <= Nparam && ptr < params + params_len; ptr += sep_pos + 1)
3782 	{
3783 		size_t	param_pos, param_len;
3784 		int	quoted;
3785 
3786 		zbx_function_param_parse(ptr, &param_pos, &param_len, &sep_pos);
3787 
3788 		if (idx == Nparam)
3789 			out = zbx_function_param_unquote_dyn(ptr + param_pos, param_len, &quoted);
3790 	}
3791 
3792 	return out;
3793 }
3794 
3795 /******************************************************************************
3796  *                                                                            *
3797  * Function: zbx_no_function                                                  *
3798  *                                                                            *
3799  * Purpose: count calculated item (prototype) formula characters that can be  *
3800  *          skipped without the risk of missing a function                    *
3801  *                                                                            *
3802  ******************************************************************************/
zbx_no_function(const char * expr)3803 static size_t	zbx_no_function(const char *expr)
3804 {
3805 	const char	*ptr = expr;
3806 	int		len, c_l, c_r;
3807 
3808 	while ('\0' != *ptr)
3809 	{
3810 		if ('{' == *ptr && '$' == *(ptr + 1) && SUCCEED == zbx_user_macro_parse(ptr, &len, &c_l, &c_r))
3811 		{
3812 			ptr += len + 1;	/* skip to the position after user macro */
3813 		}
3814 		else if (SUCCEED != is_function_char(*ptr))
3815 		{
3816 			ptr++;	/* skip one character which cannot belong to function name */
3817 		}
3818 		else if ((0 == strncmp("and", ptr, len = ZBX_CONST_STRLEN("and")) ||
3819 				0 == strncmp("not", ptr, len = ZBX_CONST_STRLEN("not")) ||
3820 				0 == strncmp("or", ptr, len = ZBX_CONST_STRLEN("or"))) &&
3821 				NULL != strchr("()" ZBX_WHITESPACE, ptr[len]))
3822 		{
3823 			ptr += len;	/* skip to the position after and/or/not operator */
3824 		}
3825 		else if (ptr > expr && 0 != isdigit(*(ptr - 1)) && NULL != strchr("KMGTsmhdw", *ptr))
3826 		{
3827 			ptr++;	/* skip unit suffix symbol if it's preceded by a digit */
3828 		}
3829 		else
3830 			break;
3831 	}
3832 
3833 	return ptr - expr;
3834 }
3835 
3836 /******************************************************************************
3837  *                                                                            *
3838  * Function: function_match_parenthesis                                       *
3839  *                                                                            *
3840  * Purpose: given the position of opening function parenthesis find the       *
3841  *          position of a closing one                                         *
3842  *                                                                            *
3843  * Parameters: expr       - [IN] string to parse that contains parameters     *
3844  *                                                                            *
3845  *             terminator - [IN] use ')' if parameters end with               *
3846  *                               parenthesis or '\0' if ends with NULL        *
3847  *                               terminator                                   *
3848  *             par_r      - [OUT] position of the terminator if found         *
3849  *             lpp_offset - [OUT] offset of the last parsed parameter         *
3850  *             lpp_len    - [OUT] length of the last parsed parameter         *
3851  *                                                                            *
3852  * Return value: SUCCEED - closing parenthesis was found                      *
3853  *               FAIL    - string after par_l does not look like a valid      *
3854  *                         function parameter list                            *
3855  *                                                                            *
3856  ******************************************************************************/
function_validate_parameters(const char * expr,char terminator,size_t * par_r,size_t * lpp_offset,size_t * lpp_len)3857 static int	function_validate_parameters(const char *expr, char terminator, size_t *par_r, size_t *lpp_offset,
3858 			size_t *lpp_len)
3859 {
3860 #define ZBX_FUNC_PARAM_NEXT		0
3861 #define ZBX_FUNC_PARAM_QUOTED		1
3862 #define ZBX_FUNC_PARAM_UNQUOTED		2
3863 #define ZBX_FUNC_PARAM_POSTQUOTED	3
3864 
3865 	const char	*ptr;
3866 	int		state = ZBX_FUNC_PARAM_NEXT;
3867 
3868 	for (ptr = expr; '\0' != *ptr; ptr++)
3869 	{
3870 		if (')' == *ptr && ZBX_FUNC_PARAM_QUOTED != state)
3871 		{
3872 			*par_r = ptr - expr;
3873 			return SUCCEED;
3874 		}
3875 
3876 		switch (state)
3877 		{
3878 			case ZBX_FUNC_PARAM_NEXT:
3879 				*lpp_offset = ptr - expr;
3880 				if ('"' == *ptr)
3881 					state = ZBX_FUNC_PARAM_QUOTED;
3882 				else if (' ' != *ptr && ',' != *ptr)
3883 					state = ZBX_FUNC_PARAM_UNQUOTED;
3884 				break;
3885 			case ZBX_FUNC_PARAM_QUOTED:
3886 				if ('"' == *ptr && '\\' != *(ptr - 1))
3887 					state = ZBX_FUNC_PARAM_POSTQUOTED;
3888 				break;
3889 			case ZBX_FUNC_PARAM_UNQUOTED:
3890 				if (',' == *ptr)
3891 					state = ZBX_FUNC_PARAM_NEXT;
3892 				break;
3893 			case ZBX_FUNC_PARAM_POSTQUOTED:
3894 				if (',' == *ptr)
3895 				{
3896 					state = ZBX_FUNC_PARAM_NEXT;
3897 				}
3898 				else if (' ' != *ptr)
3899 				{
3900 					*lpp_len = ptr - (expr + *lpp_offset);
3901 					return FAIL;
3902 				}
3903 				break;
3904 			default:
3905 				THIS_SHOULD_NEVER_HAPPEN;
3906 		}
3907 	}
3908 
3909 	*lpp_len = ptr - (expr + *lpp_offset);
3910 
3911 	if (terminator == *ptr && ZBX_FUNC_PARAM_QUOTED != state)
3912 	{
3913 		*par_r = ptr - expr;
3914 		return SUCCEED;
3915 	}
3916 
3917 	return FAIL;
3918 
3919 #undef ZBX_FUNC_PARAM_NEXT
3920 #undef ZBX_FUNC_PARAM_QUOTED
3921 #undef ZBX_FUNC_PARAM_UNQUOTED
3922 #undef ZBX_FUNC_PARAM_POSTQUOTED
3923 }
3924 
3925 /******************************************************************************
3926  *                                                                            *
3927  * Function: function_match_parenthesis                                       *
3928  *                                                                            *
3929  * Purpose: given the position of opening function parenthesis find the       *
3930  *          position of a closing one                                         *
3931  *                                                                            *
3932  * Parameters: expr       - [IN] string to parse                              *
3933  *             par_l      - [IN] position of the opening parenthesis          *
3934  *             par_r      - [OUT] position of the closing parenthesis         *
3935  *             lpp_offset - [OUT] offset of the last parsed parameter         *
3936  *             lpp_len    - [OUT] length of the last parsed parameter         *
3937  *                                                                            *
3938  * Return value: SUCCEED - closing parenthesis was found                      *
3939  *               FAIL    - string after par_l does not look like a valid      *
3940  *                         function parameter list                            *
3941  *                                                                            *
3942  ******************************************************************************/
function_match_parenthesis(const char * expr,size_t par_l,size_t * par_r,size_t * lpp_offset,size_t * lpp_len)3943 static int	function_match_parenthesis(const char *expr, size_t par_l, size_t *par_r, size_t *lpp_offset,
3944 			size_t *lpp_len)
3945 {
3946 	if (SUCCEED == function_validate_parameters(expr + par_l + 1, ')', par_r, lpp_offset, lpp_len))
3947 	{
3948 		*par_r += par_l + 1;
3949 		return SUCCEED;
3950 	}
3951 
3952 	*lpp_offset += par_l + 1;
3953 	return FAIL;
3954 }
3955 
3956 /******************************************************************************
3957  *                                                                            *
3958  * Function: zbx_function_validate                                            *
3959  *                                                                            *
3960  * Purpose: check whether expression starts with a valid function             *
3961  *                                                                            *
3962  * Parameters: expr          - [IN] string to parse                           *
3963  *             par_l         - [OUT] position of the opening parenthesis      *
3964  *                                   or the amount of characters to skip      *
3965  *             par_r         - [OUT] position of the closing parenthesis      *
3966  *             error         - [OUT] error message                            *
3967  *             max_error_len - [IN] error size                                *
3968  *                                                                            *
3969  * Return value: SUCCEED - string starts with a valid function                *
3970  *               FAIL    - string does not start with a function and par_l    *
3971  *                         characters can be safely skipped                   *
3972  *                                                                            *
3973  ******************************************************************************/
zbx_function_validate(const char * expr,size_t * par_l,size_t * par_r,char * error,int max_error_len)3974 int	zbx_function_validate(const char *expr, size_t *par_l, size_t *par_r, char *error, int max_error_len)
3975 {
3976 	size_t	lpp_offset = 0, lpp_len;
3977 
3978 	/* try to validate function name */
3979 	if (SUCCEED == function_parse_name(expr, par_l))
3980 	{
3981 		/* now we know the position of '(', try to find ')' */
3982 		if (SUCCEED == function_match_parenthesis(expr, *par_l, par_r, &lpp_offset, &lpp_len))
3983 			return SUCCEED;
3984 
3985 		if (NULL != error && *par_l > *par_r)
3986 		{
3987 			zbx_snprintf(error, max_error_len, "Incorrect function '%.*s' expression. "
3988 				"Check expression part starting from: %.*s",
3989 				*par_l, expr, lpp_len, expr + lpp_offset);
3990 
3991 			return FAIL;
3992 		}
3993 	}
3994 
3995 	if (NULL != error)
3996 		zbx_snprintf(error, max_error_len, "Incorrect function expression: %s", expr);
3997 
3998 	return FAIL;
3999 }
4000 
4001 /******************************************************************************
4002  *                                                                            *
4003  * Function: zbx_function_find                                                *
4004  *                                                                            *
4005  * Purpose: find the location of the next function and its parameters in      *
4006  *          calculated item (prototype) formula                               *
4007  *                                                                            *
4008  * Parameters: expr          - [IN] string to parse                           *
4009  *             func_pos      - [OUT] function position in the string          *
4010  *             par_l         - [OUT] position of the opening parenthesis      *
4011  *             par_r         - [OUT] position of the closing parenthesis      *
4012  *             error         - [OUT] error message                            *
4013  *             max_error_len - [IN] error size                                *
4014  *                                                                            *
4015  *                                                                            *
4016  * Return value: SUCCEED - function was found at func_pos                     *
4017  *               FAIL    - there are no functions in the expression           *
4018  *                                                                            *
4019  ******************************************************************************/
zbx_function_find(const char * expr,size_t * func_pos,size_t * par_l,size_t * par_r,char * error,int max_error_len)4020 int	zbx_function_find(const char *expr, size_t *func_pos, size_t *par_l, size_t *par_r, char *error,
4021 		int max_error_len)
4022 {
4023 	const char	*ptr;
4024 
4025 	for (ptr = expr; '\0' != *ptr; ptr += *par_l)
4026 	{
4027 		/* skip the part of expression that is definitely not a function */
4028 		ptr += zbx_no_function(ptr);
4029 		*par_r = 0;
4030 
4031 		/* try to validate function candidate */
4032 		if (SUCCEED != zbx_function_validate(ptr, par_l, par_r, error, max_error_len))
4033 		{
4034 			if (*par_l > *par_r)
4035 				return FAIL;
4036 
4037 			continue;
4038 		}
4039 
4040 		*func_pos = ptr - expr;
4041 		*par_l += *func_pos;
4042 		*par_r += *func_pos;
4043 		return SUCCEED;
4044 	}
4045 
4046 	zbx_snprintf(error, max_error_len, "Incorrect function expression: %s", expr);
4047 
4048 	return FAIL;
4049 }
4050