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 "db.h"
22 #include "dbupgrade.h"
23 #include "dbupgrade_macros.h"
24 #include "log.h"
25 
26 /******************************************************************************
27  *                                                                            *
28  * Function: str_rename_macro                                                 *
29  *                                                                            *
30  * Purpose: rename macros in the string                                       *
31  *                                                                            *
32  * Parameters: in        - [IN] the input string                              *
33  *             oldmacro  - [IN] the macro to rename                           *
34  *             newmacro  - [IN] the new macro name                            *
35  *             out       - [IN/OUT] the string with renamed macros            *
36  *             out_alloc - [IN/OUT] the output buffer size                    *
37  *                                                                            *
38  * Return value: SUCCEED - macros were found and renamed                      *
39  *               FAIL    - no target macros were found                        *
40  *                                                                            *
41  * Comments: If the oldmacro is found in input string then all occurrences of *
42  *           it are replaced with the new macro in the output string.         *
43  *           Otherwise the output string is not changed.                      *
44  *                                                                            *
45  ******************************************************************************/
str_rename_macro(const char * in,const char * oldmacro,const char * newmacro,char ** out,size_t * out_alloc)46 static int	str_rename_macro(const char *in, const char *oldmacro, const char *newmacro, char **out,
47 		size_t *out_alloc)
48 {
49 	zbx_token_t	token;
50 	int		pos = 0, ret = FAIL;
51 	size_t		out_offset = 0, newmacro_len;
52 
53 	newmacro_len = strlen(newmacro);
54 	zbx_strcpy_alloc(out, out_alloc, &out_offset, in);
55 	out_offset++;
56 
57 	for (; SUCCEED == zbx_token_find(*out, pos, &token, ZBX_TOKEN_SEARCH_BASIC); pos++)
58 	{
59 		switch (token.type)
60 		{
61 			case ZBX_TOKEN_MACRO:
62 				pos = token.loc.r;
63 				if (0 == strncmp(*out + token.loc.l, oldmacro, token.loc.r - token.loc.l + 1))
64 				{
65 					pos += zbx_replace_mem_dyn(out, out_alloc, &out_offset, token.loc.l,
66 							token.loc.r - token.loc.l + 1, newmacro, newmacro_len);
67 					ret = SUCCEED;
68 				}
69 				break;
70 
71 			case ZBX_TOKEN_USER_MACRO:
72 			case ZBX_TOKEN_SIMPLE_MACRO:
73 				pos = token.loc.r;
74 				break;
75 		}
76 	}
77 
78 	return ret;
79 }
80 
81 /******************************************************************************
82  *                                                                            *
83  * Function: db_rename_macro                                                  *
84  *                                                                            *
85  * Purpose: rename macro in the specified database fields                     *
86  *                                                                            *
87  * Parameters: result     - [IN] database query with fields to replace. First *
88  *                               field is table id field, following with      *
89  *                               the target fields listed in fields parameter *
90  *             table      - [IN] the target table name                        *
91  *             pkey       - [IN] the primary key field name                   *
92  *             fields     - [IN] the table fields to check for macros and     *
93  *                               rename if found                              *
94  *             fields_num - [IN] the number of fields to check                *
95  *             oldmacro   - [IN] the macro to rename                          *
96  *             newmacro   - [IN] the new macro name                           *
97  *                                                                            *
98  * Return value: SUCCEED  - macros were renamed successfully                  *
99  *               FAIL     - database error occurred                           *
100  *                                                                            *
101  ******************************************************************************/
db_rename_macro(DB_RESULT result,const char * table,const char * pkey,zbx_field_len_t * fields,int fields_num,const char * oldmacro,const char * newmacro)102 int	db_rename_macro(DB_RESULT result, const char *table, const char *pkey, zbx_field_len_t *fields, int fields_num,
103 		const char *oldmacro, const char *newmacro)
104 {
105 	DB_ROW		row;
106 	char		*sql = 0, *value = NULL, *value_esc;
107 	size_t		sql_alloc = 4096, sql_offset = 0, field_alloc = 0, old_offset;
108 	int		i, ret = SUCCEED;
109 	zbx_field_len_t	*field;
110 
111 	sql = zbx_malloc(NULL, sql_alloc);
112 
113 	DBbegin_multiple_update(&sql, &sql_alloc, &sql_offset);
114 
115 	while (NULL != (row = DBfetch(result)))
116 	{
117 		old_offset = sql_offset;
118 
119 		for (i = 0; i < fields_num; i++)
120 		{
121 			field = fields + i;
122 
123 			if (SUCCEED == str_rename_macro(row[i + 1], oldmacro, newmacro, &value, &field_alloc))
124 			{
125 				if (0 != field->max_len && zbx_strlen_utf8(value) > field->max_len)
126 				{
127 					zabbix_log(LOG_LEVEL_WARNING, "cannot rename macros in table \"%s\" row "
128 							"\"%s:%s\" field \"%s\": value is too long",
129 							table, pkey, row[0], field->field_name);
130 					continue;
131 				}
132 
133 				value_esc = DBdyn_escape_string(value);
134 
135 				if (old_offset == sql_offset)
136 					zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "update %s set ", table);
137 				else
138 					zbx_chrcpy_alloc(&sql, &sql_alloc, &sql_offset, ',');
139 
140 				zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%s='%s'", fields[i].field_name,
141 						value_esc);
142 
143 				zbx_free(value_esc);
144 			}
145 		}
146 
147 		if (old_offset != sql_offset)
148 		{
149 			zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, " where %s=%s;\n", pkey, row[0]);
150 			if (SUCCEED != (ret = DBexecute_overflowed_sql(&sql, &sql_alloc, &sql_offset)))
151 				goto out;
152 		}
153 	}
154 
155 	DBend_multiple_update(&sql, &sql_alloc, &sql_offset);
156 
157 	if (16 < sql_offset && ZBX_DB_OK > DBexecute("%s", sql))
158 		ret = FAIL;
159 out:
160 	zbx_free(value);
161 	zbx_free(sql);
162 
163 	return ret;
164 }
165