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