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 "log.h"
24 
25 /*
26  * 4.0 maintenance database patches
27  */
28 
29 #ifndef HAVE_SQLITE3
30 
31 extern unsigned char program_type;
32 
DBpatch_4000000(void)33 static int	DBpatch_4000000(void)
34 {
35 	return SUCCEED;
36 }
37 
38 /******************************************************************************
39  *                                                                            *
40  * Function: str_rename_macro                                                 *
41  *                                                                            *
42  * Purpose: rename macros in the string                                       *
43  *                                                                            *
44  * Parameters: in        - [IN] the input string                              *
45  *             oldmacro  - [IN] the macro to rename                           *
46  *             newmacro  - [IN] the new macro name                            *
47  *             out       - [IN/OUT] the string with renamed macros            *
48  *             out_alloc - [IN/OUT] the output buffer size                    *
49  *                                                                            *
50  * Return value: SUCCEED - macros were found and renamed                      *
51  *               FAIL    - no target macros were found                        *
52  *                                                                            *
53  * Comments: If the oldmacro is found in input string then all occurrences of *
54  *           it are replaced with the new macro in the output string.         *
55  *           Otherwise the output string is not changed.                      *
56  *                                                                            *
57  ******************************************************************************/
str_rename_macro(const char * in,const char * oldmacro,const char * newmacro,char ** out,size_t * out_alloc)58 static int	str_rename_macro(const char *in, const char *oldmacro, const char *newmacro, char **out,
59 		size_t *out_alloc)
60 {
61 	zbx_token_t	token;
62 	int		pos = 0, ret = FAIL;
63 	size_t		out_offset = 0, newmacro_len;
64 
65 	newmacro_len = strlen(newmacro);
66 	zbx_strcpy_alloc(out, out_alloc, &out_offset, in);
67 	out_offset++;
68 
69 	for (; SUCCEED == zbx_token_find(*out, pos, &token, ZBX_TOKEN_SEARCH_BASIC); pos++)
70 	{
71 		switch (token.type)
72 		{
73 			case ZBX_TOKEN_MACRO:
74 				pos = token.loc.r;
75 				if (0 == strncmp(*out + token.loc.l, oldmacro, token.loc.r - token.loc.l + 1))
76 				{
77 					pos += zbx_replace_mem_dyn(out, out_alloc, &out_offset, token.loc.l,
78 							token.loc.r - token.loc.l + 1, newmacro, newmacro_len);
79 					ret = SUCCEED;
80 				}
81 				break;
82 
83 			case ZBX_TOKEN_USER_MACRO:
84 			case ZBX_TOKEN_SIMPLE_MACRO:
85 				pos = token.loc.r;
86 				break;
87 		}
88 	}
89 
90 	return ret;
91 }
92 
93 /******************************************************************************
94  *                                                                            *
95  * Function: db_rename_macro                                                  *
96  *                                                                            *
97  * Purpose: rename macro in the specified database fields                     *
98  *                                                                            *
99  * Parameters: result     - [IN] database query with fields to replace. First *
100  *                               field is table id field, following with      *
101  *                               the target fields listed in fields parameter *
102  *             table      - [IN] the target table name                        *
103  *             pkey       - [IN] the primary key field name                   *
104  *             fields     - [IN] the table fields to check for macros and     *
105  *                               rename if found                              *
106  *             fields_num - [IN] the number of fields to check                *
107  *             oldmacro   - [IN] the macro to rename                          *
108  *             newmacro   - [IN] the new macro name                           *
109  *                                                                            *
110  * Return value: SUCCEED  - macros were renamed successfully                  *
111  *               FAIL     - database error occurred                           *
112  *                                                                            *
113  ******************************************************************************/
db_rename_macro(DB_RESULT result,const char * table,const char * pkey,const char ** fields,int fields_num,const char * oldmacro,const char * newmacro)114 static int	db_rename_macro(DB_RESULT result, const char *table, const char *pkey, const char **fields,
115 		int fields_num, const char *oldmacro, const char *newmacro)
116 {
117 	DB_ROW		row;
118 	char		*sql = 0, *field = NULL, *field_esc;
119 	size_t		sql_alloc = 4096, sql_offset = 0, field_alloc = 0, old_offset;
120 	int		i, ret = SUCCEED;
121 
122 	sql = zbx_malloc(NULL, sql_alloc);
123 
124 	DBbegin_multiple_update(&sql, &sql_alloc, &sql_offset);
125 
126 	while (NULL != (row = DBfetch(result)))
127 	{
128 		old_offset = sql_offset;
129 
130 		for (i = 0; i < fields_num; i++)
131 		{
132 			if (SUCCEED == str_rename_macro(row[i + 1], oldmacro, newmacro, &field, &field_alloc))
133 			{
134 				if (old_offset == sql_offset)
135 					zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "update %s set ", table);
136 				else
137 					zbx_chrcpy_alloc(&sql, &sql_alloc, &sql_offset, ',');
138 
139 				field_esc = DBdyn_escape_string(field);
140 				zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "%s='%s'", fields[i], field_esc);
141 				zbx_free(field_esc);
142 			}
143 		}
144 
145 		if (old_offset != sql_offset)
146 		{
147 			zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, " where %s=%s;\n", pkey, row[0]);
148 			if (SUCCEED != (ret = DBexecute_overflowed_sql(&sql, &sql_alloc, &sql_offset)))
149 				goto out;
150 		}
151 	}
152 
153 	DBend_multiple_update(&sql, &sql_alloc, &sql_offset);
154 
155 	if (16 < sql_offset && ZBX_DB_OK > DBexecute("%s", sql))
156 		ret = FAIL;
157 out:
158 	zbx_free(field);
159 	zbx_free(sql);
160 
161 	return ret;
162 }
163 
DBpatch_4000001(void)164 static int	DBpatch_4000001(void)
165 {
166 	DB_RESULT	result;
167 	int		ret;
168 	const char	*fields[] = {"def_shortdata", "def_longdata", "r_shortdata", "r_longdata", "ack_shortdata",
169 				"ack_longdata"};
170 
171 	/* 0 - EVENT_SOURCE_TRIGGERS */
172 	result = DBselect("select actionid,def_shortdata,def_longdata,r_shortdata,r_longdata,ack_shortdata,"
173 			"ack_longdata from actions where eventsource=0");
174 
175 	ret = db_rename_macro(result, "actions", "actionid", fields, ARRSIZE(fields), "{TRIGGER.NAME}",
176 			"{EVENT.NAME}");
177 
178 	DBfree_result(result);
179 
180 	return ret;
181 }
182 
DBpatch_4000002(void)183 static int	DBpatch_4000002(void)
184 {
185 	DB_RESULT	result;
186 	int		ret;
187 	const char	*fields[] = {"subject", "message"};
188 
189 	/* 0 - EVENT_SOURCE_TRIGGERS */
190 	result = DBselect("select om.operationid,om.subject,om.message"
191 			" from opmessage om,operations o,actions a"
192 			" where om.operationid=o.operationid"
193 				" and o.actionid=a.actionid"
194 				" and a.eventsource=0");
195 
196 	ret = db_rename_macro(result, "opmessage", "operationid", fields, ARRSIZE(fields), "{TRIGGER.NAME}",
197 			"{EVENT.NAME}");
198 
199 	DBfree_result(result);
200 
201 	return ret;
202 }
203 
DBpatch_4000003(void)204 static int	DBpatch_4000003(void)
205 {
206 	DB_RESULT	result;
207 	int		ret;
208 	const char	*fields[] = {"command"};
209 
210 	/* 0 - EVENT_SOURCE_TRIGGERS */
211 	result = DBselect("select oc.operationid,oc.command"
212 			" from opcommand oc,operations o,actions a"
213 			" where oc.operationid=o.operationid"
214 				" and o.actionid=a.actionid"
215 				" and a.eventsource=0");
216 
217 	ret = db_rename_macro(result, "opcommand", "operationid", fields, ARRSIZE(fields), "{TRIGGER.NAME}",
218 			"{EVENT.NAME}");
219 
220 	DBfree_result(result);
221 
222 	return ret;
223 }
224 
DBpatch_4000004(void)225 static int	DBpatch_4000004(void)
226 {
227 	int		i;
228 	const char	*values[] = {
229 			"alarm_ok",
230 			"no_sound",
231 			"alarm_information",
232 			"alarm_warning",
233 			"alarm_average",
234 			"alarm_high",
235 			"alarm_disaster"
236 		};
237 
238 	if (0 == (program_type & ZBX_PROGRAM_TYPE_SERVER))
239 		return SUCCEED;
240 
241 	for (i = 0; i < (int)ARRSIZE(values); i++)
242 	{
243 		if (ZBX_DB_OK > DBexecute(
244 				"update profiles"
245 				" set value_str='%s.mp3'"
246 				" where value_str='%s.wav'"
247 					" and idx='web.messages'", values[i], values[i]))
248 		{
249 			return FAIL;
250 		}
251 	}
252 
253 	return SUCCEED;
254 }
255 
DBpatch_4000005(void)256 static int	DBpatch_4000005(void)
257 {
258 	DB_RESULT		result;
259 	DB_ROW			row;
260 	zbx_uint64_t		time_period_id, every;
261 	int			invalidate = 0;
262 	const ZBX_TABLE		*timeperiods;
263 	const ZBX_FIELD		*field;
264 
265 	if (NULL != (timeperiods = DBget_table("timeperiods")) &&
266 			NULL != (field = DBget_field(timeperiods, "every")))
267 	{
268 		ZBX_STR2UINT64(every, field->default_value);
269 	}
270 	else
271 	{
272 		THIS_SHOULD_NEVER_HAPPEN;
273 		return FAIL;
274 	}
275 
276 	result = DBselect("select timeperiodid from timeperiods where every=0");
277 
278 	while (NULL != (row = DBfetch(result)))
279 	{
280 		ZBX_STR2UINT64(time_period_id, row[0]);
281 
282 		zabbix_log(LOG_LEVEL_WARNING, "Invalid maintenance time period found: "ZBX_FS_UI64
283 				", changing \"every\" to "ZBX_FS_UI64, time_period_id, every);
284 		invalidate = 1;
285 	}
286 
287 	DBfree_result(result);
288 
289 	if (0 != invalidate &&
290 			ZBX_DB_OK > DBexecute("update timeperiods set every=1 where timeperiodid!=0 and every=0"))
291 		return FAIL;
292 
293 	return SUCCEED;
294 }
295 
DBpatch_4000006(void)296 static int	DBpatch_4000006(void)
297 {
298 	if (0 == (program_type & ZBX_PROGRAM_TYPE_SERVER))
299 		return SUCCEED;
300 
301 	if (ZBX_DB_OK > DBexecute("delete from profiles where idx='web.screens.graphid'"))
302 		return FAIL;
303 
304 	return SUCCEED;
305 }
306 
307 #endif
308 
309 DBPATCH_START(4000)
310 
311 /* version, duplicates flag, mandatory flag */
312 
313 DBPATCH_ADD(4000000, 0, 1)
314 DBPATCH_ADD(4000001, 0, 0)
315 DBPATCH_ADD(4000002, 0, 0)
316 DBPATCH_ADD(4000003, 0, 0)
317 DBPATCH_ADD(4000004, 0, 0)
318 DBPATCH_ADD(4000005, 0, 0)
319 DBPATCH_ADD(4000006, 0, 0)
320 
321 DBPATCH_END()
322