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 "lld.h"
21 #include "db.h"
22 #include "log.h"
23 #include "zbxalgo.h"
24 #include "zbxserver.h"
25 
26 typedef struct
27 {
28 	zbx_uint64_t	hostmacroid;
29 	char		*macro;
30 	char		*value;
31 }
32 zbx_lld_hostmacro_t;
33 
lld_hostmacro_free(zbx_lld_hostmacro_t * hostmacro)34 static void	lld_hostmacro_free(zbx_lld_hostmacro_t *hostmacro)
35 {
36 	zbx_free(hostmacro->macro);
37 	zbx_free(hostmacro->value);
38 	zbx_free(hostmacro);
39 }
40 
41 typedef struct
42 {
43 	zbx_uint64_t	interfaceid;
44 	zbx_uint64_t	parent_interfaceid;
45 	char		*ip;
46 	char		*dns;
47 	char		*port;
48 	unsigned char	main;
49 	unsigned char	main_orig;
50 	unsigned char	type;
51 	unsigned char	type_orig;
52 	unsigned char	useip;
53 	unsigned char	bulk;
54 #define ZBX_FLAG_LLD_INTERFACE_UPDATE_TYPE	__UINT64_C(0x00000001)	/* interface.type field should be updated  */
55 #define ZBX_FLAG_LLD_INTERFACE_UPDATE_MAIN	__UINT64_C(0x00000002)	/* interface.main field should be updated */
56 #define ZBX_FLAG_LLD_INTERFACE_UPDATE_USEIP	__UINT64_C(0x00000004)	/* interface.useip field should be updated */
57 #define ZBX_FLAG_LLD_INTERFACE_UPDATE_IP	__UINT64_C(0x00000008)	/* interface.ip field should be updated */
58 #define ZBX_FLAG_LLD_INTERFACE_UPDATE_DNS	__UINT64_C(0x00000010)	/* interface.dns field should be updated */
59 #define ZBX_FLAG_LLD_INTERFACE_UPDATE_PORT	__UINT64_C(0x00000020)	/* interface.port field should be updated */
60 #define ZBX_FLAG_LLD_INTERFACE_UPDATE_BULK	__UINT64_C(0x00000040)	/* interface.bulk field should be updated */
61 #define ZBX_FLAG_LLD_INTERFACE_UPDATE								\
62 		(ZBX_FLAG_LLD_INTERFACE_UPDATE_TYPE | ZBX_FLAG_LLD_INTERFACE_UPDATE_MAIN |	\
63 		ZBX_FLAG_LLD_INTERFACE_UPDATE_USEIP | ZBX_FLAG_LLD_INTERFACE_UPDATE_IP |	\
64 		ZBX_FLAG_LLD_INTERFACE_UPDATE_DNS | ZBX_FLAG_LLD_INTERFACE_UPDATE_PORT |	\
65 		ZBX_FLAG_LLD_INTERFACE_UPDATE_BULK)
66 #define ZBX_FLAG_LLD_INTERFACE_REMOVE		__UINT64_C(0x00000080)	/* interfaces which should be deleted */
67 	zbx_uint64_t	flags;
68 }
69 zbx_lld_interface_t;
70 
lld_interface_free(zbx_lld_interface_t * interface)71 static void	lld_interface_free(zbx_lld_interface_t *interface)
72 {
73 	zbx_free(interface->port);
74 	zbx_free(interface->dns);
75 	zbx_free(interface->ip);
76 	zbx_free(interface);
77 }
78 
79 typedef struct
80 {
81 	zbx_uint64_t		hostid;
82 	zbx_vector_uint64_t	new_groupids;		/* host groups which should be added */
83 	zbx_vector_uint64_t	lnk_templateids;	/* templates which should be linked */
84 	zbx_vector_uint64_t	del_templateids;	/* templates which should be unlinked */
85 	zbx_vector_ptr_t	new_hostmacros;		/* host macros which should be added */
86 	zbx_vector_ptr_t	interfaces;
87 	char			*host_proto;
88 	char			*host;
89 	char			*host_orig;
90 	char			*name;
91 	char			*name_orig;
92 	int			lastcheck;
93 	int			ts_delete;
94 
95 #define ZBX_FLAG_LLD_HOST_DISCOVERED			__UINT64_C(0x00000001)	/* hosts which should be updated or added */
96 #define ZBX_FLAG_LLD_HOST_UPDATE_HOST			__UINT64_C(0x00000002)	/* hosts.host and host_discovery.host fields should be updated */
97 #define ZBX_FLAG_LLD_HOST_UPDATE_NAME			__UINT64_C(0x00000004)	/* hosts.name field should be updated */
98 #define ZBX_FLAG_LLD_HOST_UPDATE_PROXY			__UINT64_C(0x00000008)	/* hosts.proxy_hostid field should be updated */
99 #define ZBX_FLAG_LLD_HOST_UPDATE_IPMI_AUTH		__UINT64_C(0x00000010)	/* hosts.ipmi_authtype field should be updated */
100 #define ZBX_FLAG_LLD_HOST_UPDATE_IPMI_PRIV		__UINT64_C(0x00000020)	/* hosts.ipmi_privilege field should be updated */
101 #define ZBX_FLAG_LLD_HOST_UPDATE_IPMI_USER		__UINT64_C(0x00000040)	/* hosts.ipmi_username field should be updated */
102 #define ZBX_FLAG_LLD_HOST_UPDATE_IPMI_PASS		__UINT64_C(0x00000080)	/* hosts.ipmi_password field should be updated */
103 #define ZBX_FLAG_LLD_HOST_UPDATE_TLS_CONNECT		__UINT64_C(0x00000100)	/* hosts.tls_connect field should be updated */
104 #define ZBX_FLAG_LLD_HOST_UPDATE_TLS_ACCEPT		__UINT64_C(0x00000200)	/* hosts.tls_accept field should be updated */
105 #define ZBX_FLAG_LLD_HOST_UPDATE_TLS_ISSUER		__UINT64_C(0x00000400)	/* hosts.tls_issuer field should be updated */
106 #define ZBX_FLAG_LLD_HOST_UPDATE_TLS_SUBJECT		__UINT64_C(0x00000800)	/* hosts.tls_subject field should be updated */
107 #define ZBX_FLAG_LLD_HOST_UPDATE_TLS_PSK_IDENTITY	__UINT64_C(0x00001000)	/* hosts.tls_psk_identity field should be updated */
108 #define ZBX_FLAG_LLD_HOST_UPDATE_TLS_PSK		__UINT64_C(0x00002000)	/* hosts.tls_psk field should be updated */
109 
110 #define ZBX_FLAG_LLD_HOST_UPDATE									\
111 		(ZBX_FLAG_LLD_HOST_UPDATE_HOST | ZBX_FLAG_LLD_HOST_UPDATE_NAME |			\
112 		ZBX_FLAG_LLD_HOST_UPDATE_PROXY | ZBX_FLAG_LLD_HOST_UPDATE_IPMI_AUTH |			\
113 		ZBX_FLAG_LLD_HOST_UPDATE_IPMI_PRIV | ZBX_FLAG_LLD_HOST_UPDATE_IPMI_USER |		\
114 		ZBX_FLAG_LLD_HOST_UPDATE_IPMI_PASS | ZBX_FLAG_LLD_HOST_UPDATE_TLS_CONNECT |		\
115 		ZBX_FLAG_LLD_HOST_UPDATE_TLS_ACCEPT | ZBX_FLAG_LLD_HOST_UPDATE_TLS_ISSUER |		\
116 		ZBX_FLAG_LLD_HOST_UPDATE_TLS_SUBJECT | ZBX_FLAG_LLD_HOST_UPDATE_TLS_PSK_IDENTITY |	\
117 		ZBX_FLAG_LLD_HOST_UPDATE_TLS_PSK)
118 
119 	zbx_uint64_t		flags;
120 	char			inventory_mode;
121 }
122 zbx_lld_host_t;
123 
lld_host_free(zbx_lld_host_t * host)124 static void	lld_host_free(zbx_lld_host_t *host)
125 {
126 	zbx_vector_uint64_destroy(&host->new_groupids);
127 	zbx_vector_uint64_destroy(&host->lnk_templateids);
128 	zbx_vector_uint64_destroy(&host->del_templateids);
129 	zbx_vector_ptr_clear_ext(&host->new_hostmacros, (zbx_clean_func_t)lld_hostmacro_free);
130 	zbx_vector_ptr_destroy(&host->new_hostmacros);
131 	zbx_vector_ptr_clear_ext(&host->interfaces, (zbx_clean_func_t)lld_interface_free);
132 	zbx_vector_ptr_destroy(&host->interfaces);
133 	zbx_free(host->host_proto);
134 	zbx_free(host->host);
135 	zbx_free(host->host_orig);
136 	zbx_free(host->name);
137 	zbx_free(host->name_orig);
138 	zbx_free(host);
139 }
140 
141 typedef struct
142 {
143 	zbx_uint64_t	group_prototypeid;
144 	char		*name;
145 }
146 zbx_lld_group_prototype_t;
147 
lld_group_prototype_free(zbx_lld_group_prototype_t * group_prototype)148 static void	lld_group_prototype_free(zbx_lld_group_prototype_t *group_prototype)
149 {
150 	zbx_free(group_prototype->name);
151 	zbx_free(group_prototype);
152 }
153 
154 typedef struct
155 {
156 	zbx_uint64_t		groupid;
157 	zbx_uint64_t		group_prototypeid;
158 	zbx_vector_ptr_t	hosts;
159 	char			*name_proto;
160 	char			*name;
161 	char			*name_orig;
162 	int			lastcheck;
163 	int			ts_delete;
164 #define ZBX_FLAG_LLD_GROUP_DISCOVERED		__UINT64_C(0x00000001)	/* groups which should be updated or added */
165 #define ZBX_FLAG_LLD_GROUP_UPDATE_NAME		__UINT64_C(0x00000002)	/* groups.name field should be updated */
166 #define ZBX_FLAG_LLD_GROUP_UPDATE		ZBX_FLAG_LLD_GROUP_UPDATE_NAME
167 	zbx_uint64_t		flags;
168 }
169 zbx_lld_group_t;
170 
lld_group_free(zbx_lld_group_t * group)171 static void	lld_group_free(zbx_lld_group_t *group)
172 {
173 	/* zbx_vector_ptr_clear_ext(&group->hosts, (zbx_clean_func_t)lld_host_free); is not missing here */
174 	zbx_vector_ptr_destroy(&group->hosts);
175 	zbx_free(group->name_proto);
176 	zbx_free(group->name);
177 	zbx_free(group->name_orig);
178 	zbx_free(group);
179 }
180 
181 /******************************************************************************
182  *                                                                            *
183  * Function: lld_hosts_get                                                    *
184  *                                                                            *
185  * Purpose: retrieves existing hosts for the specified host prototype         *
186  *                                                                            *
187  * Parameters: parent_hostid - [IN] host prototype identifier                 *
188  *             hosts         - [OUT] list of hosts                            *
189  *                                                                            *
190  ******************************************************************************/
lld_hosts_get(zbx_uint64_t parent_hostid,zbx_vector_ptr_t * hosts,zbx_uint64_t proxy_hostid,char ipmi_authtype,unsigned char ipmi_privilege,const char * ipmi_username,const char * ipmi_password,char inventory_mode,unsigned char tls_connect,unsigned char tls_accept,const char * tls_issuer,const char * tls_subject,const char * tls_psk_identity,const char * tls_psk)191 static void	lld_hosts_get(zbx_uint64_t parent_hostid, zbx_vector_ptr_t *hosts, zbx_uint64_t proxy_hostid,
192 		char ipmi_authtype, unsigned char ipmi_privilege, const char *ipmi_username, const char *ipmi_password,
193 		char inventory_mode, unsigned char tls_connect, unsigned char tls_accept, const char *tls_issuer,
194 		const char *tls_subject, const char *tls_psk_identity, const char *tls_psk)
195 {
196 	const char	*__function_name = "lld_hosts_get";
197 
198 	DB_RESULT	result;
199 	DB_ROW		row;
200 	zbx_lld_host_t	*host;
201 	zbx_uint64_t	db_proxy_hostid;
202 
203 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
204 
205 	result = DBselect(
206 			"select hd.hostid,hd.host,hd.lastcheck,hd.ts_delete,h.host,h.name,h.proxy_hostid,"
207 				"h.ipmi_authtype,h.ipmi_privilege,h.ipmi_username,h.ipmi_password,hi.inventory_mode,"
208 				"h.tls_connect,h.tls_accept,h.tls_issuer,h.tls_subject,h.tls_psk_identity,h.tls_psk"
209 			" from host_discovery hd"
210 				" join hosts h"
211 					" on hd.hostid=h.hostid"
212 				" left join host_inventory hi"
213 					" on hd.hostid=hi.hostid"
214 			" where hd.parent_hostid=" ZBX_FS_UI64,
215 			parent_hostid);
216 
217 	while (NULL != (row = DBfetch(result)))
218 	{
219 		host = zbx_malloc(NULL, sizeof(zbx_lld_host_t));
220 
221 		ZBX_STR2UINT64(host->hostid, row[0]);
222 		host->host_proto = zbx_strdup(NULL, row[1]);
223 		host->lastcheck = atoi(row[2]);
224 		host->ts_delete = atoi(row[3]);
225 		host->host = zbx_strdup(NULL, row[4]);
226 		host->host_orig = NULL;
227 		host->name = zbx_strdup(NULL, row[5]);
228 		host->name_orig = NULL;
229 		host->flags = 0x00;
230 
231 		ZBX_DBROW2UINT64(db_proxy_hostid, row[6]);
232 		if (db_proxy_hostid != proxy_hostid)
233 			host->flags |= ZBX_FLAG_LLD_HOST_UPDATE_PROXY;
234 
235 		if ((char)atoi(row[7]) != ipmi_authtype)
236 			host->flags |= ZBX_FLAG_LLD_HOST_UPDATE_IPMI_AUTH;
237 
238 		if ((unsigned char)atoi(row[8]) != ipmi_privilege)
239 			host->flags |= ZBX_FLAG_LLD_HOST_UPDATE_IPMI_PRIV;
240 
241 		if (0 != strcmp(row[9], ipmi_username))
242 			host->flags |= ZBX_FLAG_LLD_HOST_UPDATE_IPMI_USER;
243 
244 		if (0 != strcmp(row[10], ipmi_password))
245 			host->flags |= ZBX_FLAG_LLD_HOST_UPDATE_IPMI_PASS;
246 
247 		if (atoi(row[12]) != tls_connect)
248 			host->flags |= ZBX_FLAG_LLD_HOST_UPDATE_TLS_CONNECT;
249 
250 		if (atoi(row[13]) != tls_accept)
251 			host->flags |= ZBX_FLAG_LLD_HOST_UPDATE_TLS_ACCEPT;
252 
253 		if (0 != strcmp(tls_issuer, row[14]))
254 			host->flags |= ZBX_FLAG_LLD_HOST_UPDATE_TLS_ISSUER;
255 
256 		if (0 != strcmp(tls_subject, row[15]))
257 			host->flags |= ZBX_FLAG_LLD_HOST_UPDATE_TLS_SUBJECT;
258 
259 		if (0 != strcmp(tls_psk_identity, row[16]))
260 			host->flags |= ZBX_FLAG_LLD_HOST_UPDATE_TLS_PSK_IDENTITY;
261 
262 		if (0 != strcmp(tls_psk, row[17]))
263 			host->flags |= ZBX_FLAG_LLD_HOST_UPDATE_TLS_PSK;
264 
265 		if (SUCCEED == DBis_null(row[11]))
266 			host->inventory_mode = HOST_INVENTORY_DISABLED;
267 		else
268 			host->inventory_mode = (char)atoi(row[11]);
269 
270 		zbx_vector_uint64_create(&host->new_groupids);
271 		zbx_vector_uint64_create(&host->lnk_templateids);
272 		zbx_vector_uint64_create(&host->del_templateids);
273 		zbx_vector_ptr_create(&host->new_hostmacros);
274 		zbx_vector_ptr_create(&host->interfaces);
275 
276 		zbx_vector_ptr_append(hosts, host);
277 	}
278 	DBfree_result(result);
279 
280 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
281 }
282 
283 /******************************************************************************
284  *                                                                            *
285  * Function: lld_hosts_validate                                               *
286  *                                                                            *
287  * Parameters: hosts - [IN] list of hosts; should be sorted by hostid         *
288  *                                                                            *
289  ******************************************************************************/
lld_hosts_validate(zbx_vector_ptr_t * hosts,char ** error)290 void	lld_hosts_validate(zbx_vector_ptr_t *hosts, char **error)
291 {
292 	const char		*__function_name = "lld_hosts_validate";
293 
294 	DB_RESULT		result;
295 	DB_ROW			row;
296 	int			i, j;
297 	zbx_lld_host_t		*host, *host_b;
298 	zbx_vector_uint64_t	hostids;
299 	zbx_vector_str_t	tnames, vnames;
300 
301 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
302 
303 	zbx_vector_uint64_create(&hostids);
304 	zbx_vector_str_create(&tnames);		/* list of technical host names */
305 	zbx_vector_str_create(&vnames);		/* list of visible host names */
306 
307 	/* checking a host name validity */
308 	for (i = 0; i < hosts->values_num; i++)
309 	{
310 		char	*ch_error;
311 
312 		host = (zbx_lld_host_t *)hosts->values[i];
313 
314 		if (0 == (host->flags & ZBX_FLAG_LLD_HOST_DISCOVERED))
315 			continue;
316 
317 		/* only new hosts or hosts with changed host name will be validated */
318 		if (0 != host->hostid && 0 == (host->flags & ZBX_FLAG_LLD_HOST_UPDATE_HOST))
319 			continue;
320 
321 		/* host name is valid? */
322 		if (SUCCEED == zbx_check_hostname(host->host, &ch_error))
323 			continue;
324 
325 		*error = zbx_strdcatf(*error, "Cannot %s host \"%s\": %s.\n",
326 				(0 != host->hostid ? "update" : "create"), host->host, ch_error);
327 
328 		zbx_free(ch_error);
329 
330 		if (0 != host->hostid)
331 		{
332 			lld_field_str_rollback(&host->host, &host->host_orig, &host->flags,
333 					ZBX_FLAG_LLD_HOST_UPDATE_HOST);
334 		}
335 		else
336 			host->flags &= ~ZBX_FLAG_LLD_HOST_DISCOVERED;
337 	}
338 
339 	/* checking a visible host name validity */
340 	for (i = 0; i < hosts->values_num; i++)
341 	{
342 		host = (zbx_lld_host_t *)hosts->values[i];
343 
344 		if (0 == (host->flags & ZBX_FLAG_LLD_HOST_DISCOVERED))
345 			continue;
346 
347 		/* only new hosts or hosts with changed visible name will be validated */
348 		if (0 != host->hostid && 0 == (host->flags & ZBX_FLAG_LLD_HOST_UPDATE_NAME))
349 			continue;
350 
351 		/* visible host name is valid utf8 sequence and has a valid length */
352 		if (SUCCEED == zbx_is_utf8(host->name) && '\0' != *host->name &&
353 				HOST_NAME_LEN >= zbx_strlen_utf8(host->name))
354 		{
355 			continue;
356 		}
357 
358 		zbx_replace_invalid_utf8(host->name);
359 		*error = zbx_strdcatf(*error, "Cannot %s host: invalid visible host name \"%s\".\n",
360 				(0 != host->hostid ? "update" : "create"), host->name);
361 
362 		if (0 != host->hostid)
363 		{
364 			lld_field_str_rollback(&host->name, &host->name_orig, &host->flags,
365 					ZBX_FLAG_LLD_HOST_UPDATE_NAME);
366 		}
367 		else
368 			host->flags &= ~ZBX_FLAG_LLD_HOST_DISCOVERED;
369 	}
370 
371 	/* checking duplicated host names */
372 	for (i = 0; i < hosts->values_num; i++)
373 	{
374 		host = (zbx_lld_host_t *)hosts->values[i];
375 
376 		if (0 == (host->flags & ZBX_FLAG_LLD_HOST_DISCOVERED))
377 			continue;
378 
379 		/* only new hosts or hosts with changed host name will be validated */
380 		if (0 != host->hostid && 0 == (host->flags & ZBX_FLAG_LLD_HOST_UPDATE_HOST))
381 			continue;
382 
383 		for (j = 0; j < hosts->values_num; j++)
384 		{
385 			host_b = (zbx_lld_host_t *)hosts->values[j];
386 
387 			if (0 == (host_b->flags & ZBX_FLAG_LLD_HOST_DISCOVERED) || i == j)
388 				continue;
389 
390 			if (0 != strcmp(host->host, host_b->host))
391 				continue;
392 
393 			*error = zbx_strdcatf(*error, "Cannot %s host:"
394 					" host with the same name \"%s\" already exists.\n",
395 					(0 != host->hostid ? "update" : "create"), host->host);
396 
397 			if (0 != host->hostid)
398 			{
399 				lld_field_str_rollback(&host->host, &host->host_orig, &host->flags,
400 						ZBX_FLAG_LLD_HOST_UPDATE_HOST);
401 			}
402 			else
403 				host->flags &= ~ZBX_FLAG_LLD_HOST_DISCOVERED;
404 		}
405 	}
406 
407 	/* checking duplicated visible host names */
408 	for (i = 0; i < hosts->values_num; i++)
409 	{
410 		host = (zbx_lld_host_t *)hosts->values[i];
411 
412 		if (0 == (host->flags & ZBX_FLAG_LLD_HOST_DISCOVERED))
413 			continue;
414 
415 		/* only new hosts or hosts with changed visible name will be validated */
416 		if (0 != host->hostid && 0 == (host->flags & ZBX_FLAG_LLD_HOST_UPDATE_NAME))
417 			continue;
418 
419 		for (j = 0; j < hosts->values_num; j++)
420 		{
421 			host_b = (zbx_lld_host_t *)hosts->values[j];
422 
423 			if (0 == (host_b->flags & ZBX_FLAG_LLD_HOST_DISCOVERED) || i == j)
424 				continue;
425 
426 			if (0 != strcmp(host->name, host_b->name))
427 				continue;
428 
429 			*error = zbx_strdcatf(*error, "Cannot %s host:"
430 					" host with the same visible name \"%s\" already exists.\n",
431 					(0 != host->hostid ? "update" : "create"), host->name);
432 
433 			if (0 != host->hostid)
434 			{
435 				lld_field_str_rollback(&host->name, &host->name_orig, &host->flags,
436 						ZBX_FLAG_LLD_HOST_UPDATE_NAME);
437 			}
438 			else
439 				host->flags &= ~ZBX_FLAG_LLD_HOST_DISCOVERED;
440 		}
441 	}
442 
443 	/* checking duplicated host names and visible host names in DB */
444 
445 	for (i = 0; i < hosts->values_num; i++)
446 	{
447 		host = (zbx_lld_host_t *)hosts->values[i];
448 
449 		if (0 == (host->flags & ZBX_FLAG_LLD_HOST_DISCOVERED))
450 			continue;
451 
452 		if (0 != host->hostid)
453 			zbx_vector_uint64_append(&hostids, host->hostid);
454 
455 		if (0 == host->hostid || 0 != (host->flags & ZBX_FLAG_LLD_HOST_UPDATE_HOST))
456 			zbx_vector_str_append(&tnames, host->host);
457 
458 		if (0 == host->hostid || 0 != (host->flags & ZBX_FLAG_LLD_HOST_UPDATE_NAME))
459 			zbx_vector_str_append(&vnames, host->name);
460 	}
461 
462 	if (0 != tnames.values_num || 0 != vnames.values_num)
463 	{
464 		char	*sql = NULL;
465 		size_t	sql_alloc = 0, sql_offset = 0;
466 
467 		zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
468 				"select host,name"
469 				" from hosts"
470 				" where status in (%d,%d,%d)"
471 					" and flags<>%d"
472 					" and",
473 				HOST_STATUS_MONITORED, HOST_STATUS_NOT_MONITORED, HOST_STATUS_TEMPLATE,
474 				ZBX_FLAG_DISCOVERY_PROTOTYPE);
475 
476 		if (0 != tnames.values_num && 0 != vnames.values_num)
477 			zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, " (");
478 
479 		if (0 != tnames.values_num)
480 		{
481 			DBadd_str_condition_alloc(&sql, &sql_alloc, &sql_offset, "host",
482 					(const char **)tnames.values, tnames.values_num);
483 		}
484 
485 		if (0 != tnames.values_num && 0 != vnames.values_num)
486 			zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, " or");
487 
488 		if (0 != vnames.values_num)
489 		{
490 			DBadd_str_condition_alloc(&sql, &sql_alloc, &sql_offset, "name",
491 					(const char **)vnames.values, vnames.values_num);
492 		}
493 
494 		if (0 != tnames.values_num && 0 != vnames.values_num)
495 			zbx_chrcpy_alloc(&sql, &sql_alloc, &sql_offset, ')');
496 
497 		if (0 != hostids.values_num)
498 		{
499 			zbx_vector_uint64_sort(&hostids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
500 			zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, " and not");
501 			DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "hostid",
502 					hostids.values, hostids.values_num);
503 		}
504 
505 		result = DBselect("%s", sql);
506 
507 		while (NULL != (row = DBfetch(result)))
508 		{
509 			for (i = 0; i < hosts->values_num; i++)
510 			{
511 				host = (zbx_lld_host_t *)hosts->values[i];
512 
513 				if (0 == (host->flags & ZBX_FLAG_LLD_HOST_DISCOVERED))
514 					continue;
515 
516 				if (0 == strcmp(host->host, row[0]))
517 				{
518 					*error = zbx_strdcatf(*error, "Cannot %s host:"
519 							" host with the same name \"%s\" already exists.\n",
520 							(0 != host->hostid ? "update" : "create"), host->host);
521 
522 					if (0 != host->hostid)
523 					{
524 						lld_field_str_rollback(&host->host, &host->host_orig, &host->flags,
525 								ZBX_FLAG_LLD_HOST_UPDATE_HOST);
526 					}
527 					else
528 						host->flags &= ~ZBX_FLAG_LLD_HOST_DISCOVERED;
529 				}
530 
531 				if (0 == strcmp(host->name, row[1]))
532 				{
533 					*error = zbx_strdcatf(*error, "Cannot %s host:"
534 							" host with the same visible name \"%s\" already exists.\n",
535 							(0 != host->hostid ? "update" : "create"), host->name);
536 
537 					if (0 != host->hostid)
538 					{
539 						lld_field_str_rollback(&host->name, &host->name_orig, &host->flags,
540 								ZBX_FLAG_LLD_HOST_UPDATE_NAME);
541 					}
542 					else
543 						host->flags &= ~ZBX_FLAG_LLD_HOST_DISCOVERED;
544 				}
545 			}
546 		}
547 		DBfree_result(result);
548 
549 		zbx_free(sql);
550 	}
551 
552 	zbx_vector_str_destroy(&vnames);
553 	zbx_vector_str_destroy(&tnames);
554 	zbx_vector_uint64_destroy(&hostids);
555 
556 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
557 }
558 
lld_host_make(zbx_vector_ptr_t * hosts,const char * host_proto,const char * name_proto,const struct zbx_json_parse * jp_row)559 static zbx_lld_host_t	*lld_host_make(zbx_vector_ptr_t *hosts, const char *host_proto, const char *name_proto,
560 		const struct zbx_json_parse *jp_row)
561 {
562 	const char	*__function_name = "lld_host_make";
563 
564 	char		*buffer = NULL;
565 	int		i;
566 	zbx_lld_host_t	*host = NULL;
567 
568 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
569 
570 	for (i = 0; i < hosts->values_num; i++)
571 	{
572 		host = (zbx_lld_host_t *)hosts->values[i];
573 
574 		if (0 != (host->flags & ZBX_FLAG_LLD_HOST_DISCOVERED))
575 			continue;
576 
577 		buffer = zbx_strdup(buffer, host->host_proto);
578 		substitute_discovery_macros(&buffer, jp_row, ZBX_MACRO_ANY, NULL, 0);
579 		zbx_lrtrim(buffer, ZBX_WHITESPACE);
580 
581 		if (0 == strcmp(host->host, buffer))
582 			break;
583 	}
584 
585 	if (i == hosts->values_num)	/* no host found */
586 	{
587 		host = zbx_malloc(NULL, sizeof(zbx_lld_host_t));
588 
589 		host->hostid = 0;
590 		host->host_proto = NULL;
591 		host->lastcheck = 0;
592 		host->ts_delete = 0;
593 		host->host = zbx_strdup(NULL, host_proto);
594 		host->host_orig = NULL;
595 		substitute_discovery_macros(&host->host, jp_row, ZBX_MACRO_ANY, NULL, 0);
596 		zbx_lrtrim(host->host, ZBX_WHITESPACE);
597 		host->name = zbx_strdup(NULL, name_proto);
598 		substitute_discovery_macros(&host->name, jp_row, ZBX_MACRO_ANY, NULL, 0);
599 		zbx_lrtrim(host->name, ZBX_WHITESPACE);
600 		host->name_orig = NULL;
601 		zbx_vector_uint64_create(&host->new_groupids);
602 		zbx_vector_uint64_create(&host->lnk_templateids);
603 		zbx_vector_uint64_create(&host->del_templateids);
604 		zbx_vector_ptr_create(&host->new_hostmacros);
605 		zbx_vector_ptr_create(&host->interfaces);
606 		host->flags = ZBX_FLAG_LLD_HOST_DISCOVERED;
607 
608 		zbx_vector_ptr_append(hosts, host);
609 	}
610 	else
611 	{
612 		/* host technical name */
613 		if (0 != strcmp(host->host_proto, host_proto))	/* the new host prototype differs */
614 		{
615 			host->host_orig = host->host;
616 			host->host = zbx_strdup(NULL, host_proto);
617 			substitute_discovery_macros(&host->host, jp_row, ZBX_MACRO_ANY, NULL, 0);
618 			zbx_lrtrim(host->host, ZBX_WHITESPACE);
619 			host->flags |= ZBX_FLAG_LLD_HOST_UPDATE_HOST;
620 		}
621 
622 		/* host visible name */
623 		buffer = zbx_strdup(buffer, name_proto);
624 		substitute_discovery_macros(&buffer, jp_row, ZBX_MACRO_ANY, NULL, 0);
625 		zbx_lrtrim(buffer, ZBX_WHITESPACE);
626 		if (0 != strcmp(host->name, buffer))
627 		{
628 			host->name_orig = host->name;
629 			host->name = buffer;
630 			buffer = NULL;
631 			host->flags |= ZBX_FLAG_LLD_HOST_UPDATE_NAME;
632 		}
633 
634 		host->flags |= ZBX_FLAG_LLD_HOST_DISCOVERED;
635 	}
636 
637 	zbx_free(buffer);
638 
639 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%p", __function_name, host);
640 
641 	return host;
642 }
643 
644 /******************************************************************************
645  *                                                                            *
646  * Function: lld_simple_groups_get                                            *
647  *                                                                            *
648  * Purpose: retrieve list of host groups which should be present on the each  *
649  *          discovered host                                                   *
650  *                                                                            *
651  * Parameters: parent_hostid - [IN] host prototype identifier                 *
652  *             groupids      - [OUT] sorted list of host groups               *
653  *                                                                            *
654  ******************************************************************************/
lld_simple_groups_get(zbx_uint64_t parent_hostid,zbx_vector_uint64_t * groupids)655 static void	lld_simple_groups_get(zbx_uint64_t parent_hostid, zbx_vector_uint64_t *groupids)
656 {
657 	DB_RESULT	result;
658 	DB_ROW		row;
659 	zbx_uint64_t	groupid;
660 
661 	result = DBselect(
662 			"select groupid"
663 			" from group_prototype"
664 			" where groupid is not null"
665 				" and hostid=" ZBX_FS_UI64,
666 			parent_hostid);
667 
668 	while (NULL != (row = DBfetch(result)))
669 	{
670 		ZBX_STR2UINT64(groupid, row[0]);
671 		zbx_vector_uint64_append(groupids, groupid);
672 	}
673 	DBfree_result(result);
674 
675 	zbx_vector_uint64_sort(groupids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
676 }
677 
678 /******************************************************************************
679  *                                                                            *
680  * Function: lld_hostgroups_make                                              *
681  *                                                                            *
682  * Parameters: groupids         - [IN] sorted list of host group ids which    *
683  *                                     should be present on the each          *
684  *                                     discovered host (Groups)               *
685  *             hosts            - [IN/OUT] list of hosts                      *
686  *                                         should be sorted by hostid         *
687  *             groups           - [IN]  list of host groups (Group prototypes)*
688  *             del_hostgroupids - [OUT] sorted list of host groups which      *
689  *                                      should be deleted                     *
690  *                                                                            *
691  ******************************************************************************/
lld_hostgroups_make(const zbx_vector_uint64_t * groupids,zbx_vector_ptr_t * hosts,const zbx_vector_ptr_t * groups,zbx_vector_uint64_t * del_hostgroupids)692 static void	lld_hostgroups_make(const zbx_vector_uint64_t *groupids, zbx_vector_ptr_t *hosts,
693 		const zbx_vector_ptr_t *groups, zbx_vector_uint64_t *del_hostgroupids)
694 {
695 	const char		*__function_name = "lld_hostgroups_make";
696 
697 	DB_RESULT		result;
698 	DB_ROW			row;
699 	int			i, j;
700 	zbx_vector_uint64_t	hostids;
701 	zbx_uint64_t		hostgroupid, hostid, groupid;
702 	zbx_lld_host_t		*host;
703 	const zbx_lld_group_t	*group;
704 
705 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
706 
707 	zbx_vector_uint64_create(&hostids);
708 
709 	for (i = 0; i < hosts->values_num; i++)
710 	{
711 		host = (zbx_lld_host_t *)hosts->values[i];
712 
713 		if (0 == (host->flags & ZBX_FLAG_LLD_HOST_DISCOVERED))
714 			continue;
715 
716 		zbx_vector_uint64_reserve(&host->new_groupids, groupids->values_num);
717 		for (j = 0; j < groupids->values_num; j++)
718 			zbx_vector_uint64_append(&host->new_groupids, groupids->values[j]);
719 
720 		if (0 != host->hostid)
721 			zbx_vector_uint64_append(&hostids, host->hostid);
722 	}
723 
724 	for (i = 0; i < groups->values_num; i++)
725 	{
726 		group = (zbx_lld_group_t *)groups->values[i];
727 
728 		if (0 == (group->flags & ZBX_FLAG_LLD_GROUP_DISCOVERED) || 0 == group->groupid)
729 			continue;
730 
731 		for (j = 0; j < group->hosts.values_num; j++)
732 		{
733 			host = (zbx_lld_host_t *)group->hosts.values[j];
734 
735 			zbx_vector_uint64_append(&host->new_groupids, group->groupid);
736 		}
737 	}
738 
739 	for (i = 0; i < hosts->values_num; i++)
740 	{
741 		host = (zbx_lld_host_t *)hosts->values[i];
742 		zbx_vector_uint64_sort(&host->new_groupids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
743 	}
744 
745 	if (0 != hostids.values_num)
746 	{
747 		char	*sql = NULL;
748 		size_t	sql_alloc = 0, sql_offset = 0;
749 
750 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
751 				"select hostid,groupid,hostgroupid"
752 				" from hosts_groups"
753 				" where");
754 		DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "hostid", hostids.values, hostids.values_num);
755 
756 		result = DBselect("%s", sql);
757 
758 		zbx_free(sql);
759 
760 		while (NULL != (row = DBfetch(result)))
761 		{
762 			ZBX_STR2UINT64(hostid, row[0]);
763 			ZBX_STR2UINT64(groupid, row[1]);
764 
765 			if (FAIL == (i = zbx_vector_ptr_bsearch(hosts, &hostid, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC)))
766 			{
767 				THIS_SHOULD_NEVER_HAPPEN;
768 				continue;
769 			}
770 
771 			host = (zbx_lld_host_t *)hosts->values[i];
772 
773 			if (FAIL == (i = zbx_vector_uint64_bsearch(&host->new_groupids, groupid,
774 					ZBX_DEFAULT_UINT64_COMPARE_FUNC)))
775 			{
776 				/* host groups which should be unlinked */
777 				ZBX_STR2UINT64(hostgroupid, row[2]);
778 				zbx_vector_uint64_append(del_hostgroupids, hostgroupid);
779 			}
780 			else
781 			{
782 				/* host groups which are already added */
783 				zbx_vector_uint64_remove(&host->new_groupids, i);
784 			}
785 		}
786 		DBfree_result(result);
787 
788 		zbx_vector_uint64_sort(del_hostgroupids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
789 	}
790 
791 	zbx_vector_uint64_destroy(&hostids);
792 
793 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
794 }
795 
796 /******************************************************************************
797  *                                                                            *
798  * Function: lld_group_prototypes_get                                         *
799  *                                                                            *
800  * Purpose: retrieve list of group prototypes                                 *
801  *                                                                            *
802  * Parameters: parent_hostid    - [IN] host prototype identifier              *
803  *             group_prototypes - [OUT] sorted list of group prototypes       *
804  *                                                                            *
805  ******************************************************************************/
lld_group_prototypes_get(zbx_uint64_t parent_hostid,zbx_vector_ptr_t * group_prototypes)806 static void	lld_group_prototypes_get(zbx_uint64_t parent_hostid, zbx_vector_ptr_t *group_prototypes)
807 {
808 	const char			*__function_name = "lld_group_prototypes_get";
809 
810 	DB_RESULT			result;
811 	DB_ROW				row;
812 	zbx_lld_group_prototype_t	*group_prototype;
813 
814 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
815 
816 	result = DBselect(
817 			"select group_prototypeid,name"
818 			" from group_prototype"
819 			" where groupid is null"
820 				" and hostid=" ZBX_FS_UI64,
821 			parent_hostid);
822 
823 	while (NULL != (row = DBfetch(result)))
824 	{
825 		group_prototype = zbx_malloc(NULL, sizeof(zbx_lld_group_prototype_t));
826 
827 		ZBX_STR2UINT64(group_prototype->group_prototypeid, row[0]);
828 		group_prototype->name = zbx_strdup(NULL, row[1]);
829 
830 		zbx_vector_ptr_append(group_prototypes, group_prototype);
831 	}
832 	DBfree_result(result);
833 
834 	zbx_vector_ptr_sort(group_prototypes, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
835 
836 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
837 }
838 
839 /******************************************************************************
840  *                                                                            *
841  * Function: lld_groups_get                                                   *
842  *                                                                            *
843  * Purpose: retrieves existing groups for the specified host prototype        *
844  *                                                                            *
845  * Parameters: parent_hostid - [IN] host prototype identifier                 *
846  *             groups        - [OUT] list of groups                           *
847  *                                                                            *
848  ******************************************************************************/
lld_groups_get(zbx_uint64_t parent_hostid,zbx_vector_ptr_t * groups)849 static void	lld_groups_get(zbx_uint64_t parent_hostid, zbx_vector_ptr_t *groups)
850 {
851 	const char	*__function_name = "lld_groups_get";
852 
853 	DB_RESULT	result;
854 	DB_ROW		row;
855 	zbx_lld_group_t	*group;
856 
857 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
858 
859 	result = DBselect(
860 			"select gd.groupid,gp.group_prototypeid,gd.name,gd.lastcheck,gd.ts_delete,g.name"
861 			" from group_prototype gp,group_discovery gd"
862 				" join groups g"
863 					" on gd.groupid=g.groupid"
864 			" where gp.group_prototypeid=gd.parent_group_prototypeid"
865 				" and gp.hostid=" ZBX_FS_UI64,
866 			parent_hostid);
867 
868 	while (NULL != (row = DBfetch(result)))
869 	{
870 		group = zbx_malloc(NULL, sizeof(zbx_lld_group_t));
871 
872 		ZBX_STR2UINT64(group->groupid, row[0]);
873 		ZBX_STR2UINT64(group->group_prototypeid, row[1]);
874 		zbx_vector_ptr_create(&group->hosts);
875 		group->name_proto = zbx_strdup(NULL, row[2]);
876 		group->lastcheck = atoi(row[3]);
877 		group->ts_delete = atoi(row[4]);
878 		group->name = zbx_strdup(NULL, row[5]);
879 		group->name_orig = NULL;
880 		group->flags = 0x00;
881 
882 		zbx_vector_ptr_append(groups, group);
883 	}
884 	DBfree_result(result);
885 
886 	zbx_vector_ptr_sort(groups, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
887 
888 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
889 }
890 
891 /******************************************************************************
892  *                                                                            *
893  * Function: lld_group_make                                                   *
894  *                                                                            *
895  ******************************************************************************/
lld_group_make(zbx_vector_ptr_t * groups,zbx_uint64_t group_prototypeid,const char * name_proto,const struct zbx_json_parse * jp_row)896 static zbx_lld_group_t	*lld_group_make(zbx_vector_ptr_t *groups, zbx_uint64_t group_prototypeid,
897 		const char *name_proto, const struct zbx_json_parse *jp_row)
898 {
899 	const char	*__function_name = "lld_group_make";
900 
901 	char		*buffer = NULL;
902 	int		i;
903 	zbx_lld_group_t	*group = NULL;
904 
905 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
906 
907 	for (i = 0; i < groups->values_num; i++)
908 	{
909 		group = (zbx_lld_group_t *)groups->values[i];
910 
911 		if (group->group_prototypeid != group_prototypeid)
912 			continue;
913 
914 		if (0 != (group->flags & ZBX_FLAG_LLD_GROUP_DISCOVERED))
915 			continue;
916 
917 		buffer = zbx_strdup(buffer, group->name_proto);
918 		substitute_discovery_macros(&buffer, jp_row, ZBX_MACRO_ANY, NULL, 0);
919 		zbx_lrtrim(buffer, ZBX_WHITESPACE);
920 
921 		if (0 == strcmp(group->name, buffer))
922 			break;
923 	}
924 
925 	if (i == groups->values_num)	/* no group found */
926 	{
927 		/* trying to find an already existing group */
928 
929 		buffer = zbx_strdup(buffer, name_proto);
930 		substitute_discovery_macros(&buffer, jp_row, ZBX_MACRO_ANY, NULL, 0);
931 		zbx_lrtrim(buffer, ZBX_WHITESPACE);
932 
933 		for (i = 0; i < groups->values_num; i++)
934 		{
935 			group = (zbx_lld_group_t *)groups->values[i];
936 
937 			if (group->group_prototypeid != group_prototypeid)
938 				continue;
939 
940 			if (0 == (group->flags & ZBX_FLAG_LLD_GROUP_DISCOVERED))
941 				continue;
942 
943 			if (0 == strcmp(group->name, buffer))
944 				goto out;
945 		}
946 
947 		/* otherwise create a new group */
948 
949 		group = zbx_malloc(NULL, sizeof(zbx_lld_group_t));
950 
951 		group->groupid = 0;
952 		group->group_prototypeid = group_prototypeid;
953 		zbx_vector_ptr_create(&group->hosts);
954 		group->name_proto = NULL;
955 		group->name = zbx_strdup(NULL, name_proto);
956 		substitute_discovery_macros(&group->name, jp_row, ZBX_MACRO_ANY, NULL, 0);
957 		zbx_lrtrim(group->name, ZBX_WHITESPACE);
958 		group->name_orig = NULL;
959 		group->lastcheck = 0;
960 		group->ts_delete = 0;
961 		group->flags = 0x00;
962 		group->flags = ZBX_FLAG_LLD_GROUP_DISCOVERED;
963 
964 		zbx_vector_ptr_append(groups, group);
965 	}
966 	else
967 	{
968 		/* update an already existing group */
969 
970 		/* group name */
971 		buffer = zbx_strdup(buffer, name_proto);
972 		substitute_discovery_macros(&buffer, jp_row, ZBX_MACRO_ANY, NULL, 0);
973 		zbx_lrtrim(buffer, ZBX_WHITESPACE);
974 		if (0 != strcmp(group->name, buffer))
975 		{
976 			group->name_orig = group->name;
977 			group->name = buffer;
978 			buffer = NULL;
979 			group->flags |= ZBX_FLAG_LLD_GROUP_UPDATE_NAME;
980 		}
981 
982 		group->flags |= ZBX_FLAG_LLD_GROUP_DISCOVERED;
983 	}
984 out:
985 	zbx_free(buffer);
986 
987 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%p", __function_name, group);
988 
989 	return group;
990 }
991 
992 /******************************************************************************
993  *                                                                            *
994  * Function: lld_groups_make                                                  *
995  *                                                                            *
996  ******************************************************************************/
lld_groups_make(zbx_lld_host_t * host,zbx_vector_ptr_t * groups,const zbx_vector_ptr_t * group_prototypes,const struct zbx_json_parse * jp_row)997 static void	lld_groups_make(zbx_lld_host_t *host, zbx_vector_ptr_t *groups, const zbx_vector_ptr_t *group_prototypes,
998 		const struct zbx_json_parse *jp_row)
999 {
1000 	const char	*__function_name = "lld_groups_make";
1001 
1002 	int		i;
1003 
1004 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
1005 
1006 	for (i = 0; i < group_prototypes->values_num; i++)
1007 	{
1008 		const zbx_lld_group_prototype_t	*group_prototype;
1009 		zbx_lld_group_t			*group;
1010 
1011 		group_prototype = (zbx_lld_group_prototype_t *)group_prototypes->values[i];
1012 
1013 		group = lld_group_make(groups, group_prototype->group_prototypeid, group_prototype->name, jp_row);
1014 
1015 		zbx_vector_ptr_append(&group->hosts, host);
1016 	}
1017 
1018 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
1019 }
1020 
1021 /******************************************************************************
1022  *                                                                            *
1023  * Function: lld_groups_validate                                              *
1024  *                                                                            *
1025  * Parameters: groups - [IN] list of groups; should be sorted by groupid      *
1026  *                                                                            *
1027  ******************************************************************************/
lld_groups_validate(zbx_vector_ptr_t * groups,char ** error)1028 void	lld_groups_validate(zbx_vector_ptr_t *groups, char **error)
1029 {
1030 	const char		*__function_name = "lld_groups_validate";
1031 
1032 	DB_RESULT		result;
1033 	DB_ROW			row;
1034 	int			i, j;
1035 	zbx_lld_group_t		*group, *group_b;
1036 	zbx_vector_uint64_t	groupids;
1037 	zbx_vector_str_t	names;
1038 
1039 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
1040 
1041 	zbx_vector_uint64_create(&groupids);
1042 	zbx_vector_str_create(&names);		/* list of group names */
1043 
1044 	/* checking a group name validity */
1045 	for (i = 0; i < groups->values_num; i++)
1046 	{
1047 		group = (zbx_lld_group_t *)groups->values[i];
1048 
1049 		if (0 == (group->flags & ZBX_FLAG_LLD_GROUP_DISCOVERED))
1050 			continue;
1051 
1052 		/* only new groups or groups with changed group name will be validated */
1053 		if (0 != group->groupid && 0 == (group->flags & ZBX_FLAG_LLD_GROUP_UPDATE_NAME))
1054 			continue;
1055 
1056 		/* group name is valid utf8 sequence and has a valid length */
1057 		if (SUCCEED == zbx_is_utf8(group->name) && '\0' != *group->name &&
1058 				GROUP_NAME_LEN >= zbx_strlen_utf8(group->name))
1059 		{
1060 			continue;
1061 		}
1062 
1063 		zbx_replace_invalid_utf8(group->name);
1064 		*error = zbx_strdcatf(*error, "Cannot %s group: invalid group name \"%s\".\n",
1065 				(0 != group->groupid ? "update" : "create"), group->name);
1066 
1067 		if (0 != group->groupid)
1068 		{
1069 			lld_field_str_rollback(&group->name, &group->name_orig, &group->flags,
1070 					ZBX_FLAG_LLD_GROUP_UPDATE_NAME);
1071 		}
1072 		else
1073 			group->flags &= ~ZBX_FLAG_LLD_GROUP_DISCOVERED;
1074 	}
1075 
1076 	/* checking duplicated group names */
1077 	for (i = 0; i < groups->values_num; i++)
1078 	{
1079 		group = (zbx_lld_group_t *)groups->values[i];
1080 
1081 		if (0 == (group->flags & ZBX_FLAG_LLD_GROUP_DISCOVERED))
1082 			continue;
1083 
1084 		/* only new groups or groups with changed group name will be validated */
1085 		if (0 != group->groupid && 0 == (group->flags & ZBX_FLAG_LLD_GROUP_UPDATE_NAME))
1086 			continue;
1087 
1088 		for (j = 0; j < groups->values_num; j++)
1089 		{
1090 			group_b = (zbx_lld_group_t *)groups->values[j];
1091 
1092 			if (0 == (group_b->flags & ZBX_FLAG_LLD_GROUP_DISCOVERED) || i == j)
1093 				continue;
1094 
1095 			if (0 != strcmp(group->name, group_b->name))
1096 				continue;
1097 
1098 			*error = zbx_strdcatf(*error, "Cannot %s group:"
1099 					" group with the same name \"%s\" already exists.\n",
1100 					(0 != group->groupid ? "update" : "create"), group->name);
1101 
1102 			if (0 != group->groupid)
1103 			{
1104 				lld_field_str_rollback(&group->name, &group->name_orig, &group->flags,
1105 						ZBX_FLAG_LLD_GROUP_UPDATE_NAME);
1106 			}
1107 			else
1108 				group->flags &= ~ZBX_FLAG_LLD_GROUP_DISCOVERED;
1109 		}
1110 	}
1111 
1112 	/* checking duplicated group names and group names in DB */
1113 
1114 	for (i = 0; i < groups->values_num; i++)
1115 	{
1116 		group = (zbx_lld_group_t *)groups->values[i];
1117 
1118 		if (0 == (group->flags & ZBX_FLAG_LLD_GROUP_DISCOVERED))
1119 			continue;
1120 
1121 		if (0 != group->groupid)
1122 			zbx_vector_uint64_append(&groupids, group->groupid);
1123 
1124 		if (0 == group->groupid || 0 != (group->flags & ZBX_FLAG_LLD_GROUP_UPDATE_NAME))
1125 			zbx_vector_str_append(&names, group->name);
1126 	}
1127 
1128 	if (0 != names.values_num)
1129 	{
1130 		char	*sql = NULL;
1131 		size_t	sql_alloc = 0, sql_offset = 0;
1132 
1133 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "select name from groups where");
1134 		DBadd_str_condition_alloc(&sql, &sql_alloc, &sql_offset, "name",
1135 				(const char **)names.values, names.values_num);
1136 
1137 		if (0 != groupids.values_num)
1138 		{
1139 			zbx_vector_uint64_sort(&groupids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
1140 			zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, " and not");
1141 			DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "groupid",
1142 					groupids.values, groupids.values_num);
1143 		}
1144 
1145 		result = DBselect("%s", sql);
1146 
1147 		while (NULL != (row = DBfetch(result)))
1148 		{
1149 			for (i = 0; i < groups->values_num; i++)
1150 			{
1151 				group = (zbx_lld_group_t *)groups->values[i];
1152 
1153 				if (0 == (group->flags & ZBX_FLAG_LLD_GROUP_DISCOVERED))
1154 					continue;
1155 
1156 				if (0 == strcmp(group->name, row[0]))
1157 				{
1158 					*error = zbx_strdcatf(*error, "Cannot %s group:"
1159 							" group with the same name \"%s\" already exists.\n",
1160 							(0 != group->groupid ? "update" : "create"), group->name);
1161 
1162 					if (0 != group->groupid)
1163 					{
1164 						lld_field_str_rollback(&group->name, &group->name_orig, &group->flags,
1165 								ZBX_FLAG_LLD_GROUP_UPDATE_NAME);
1166 					}
1167 					else
1168 						group->flags &= ~ZBX_FLAG_LLD_GROUP_DISCOVERED;
1169 				}
1170 			}
1171 		}
1172 		DBfree_result(result);
1173 
1174 		zbx_free(sql);
1175 	}
1176 
1177 	zbx_vector_str_destroy(&names);
1178 	zbx_vector_uint64_destroy(&groupids);
1179 
1180 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
1181 }
1182 
1183 /******************************************************************************
1184  *                                                                            *
1185  * Function: lld_groups_save                                                  *
1186  *                                                                            *
1187  * Parameters: groups           - [IN/OUT] list of groups; should be sorted   *
1188  *                                         by groupid                         *
1189  *             group_prototypes - [IN] list of group prototypes; should be    *
1190  *                                     sorted by group_prototypeid            *
1191  *                                                                            *
1192  ******************************************************************************/
lld_groups_save(zbx_vector_ptr_t * groups,const zbx_vector_ptr_t * group_prototypes)1193 static void	lld_groups_save(zbx_vector_ptr_t *groups, const zbx_vector_ptr_t *group_prototypes)
1194 {
1195 	const char			*__function_name = "lld_groups_save";
1196 
1197 	int				i, j, new_groups = 0, upd_groups = 0;
1198 	zbx_lld_group_t			*group;
1199 	const zbx_lld_group_prototype_t	*group_prototype;
1200 	zbx_lld_host_t			*host;
1201 	zbx_uint64_t			groupid = 0;
1202 	char				*sql = NULL, *name_esc, *name_proto_esc;
1203 	size_t				sql_alloc = 0, sql_offset = 0;
1204 	zbx_db_insert_t			db_insert, db_insert_gdiscovery;
1205 
1206 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
1207 
1208 	for (i = 0; i < groups->values_num; i++)
1209 	{
1210 		group = (zbx_lld_group_t *)groups->values[i];
1211 
1212 		if (0 == (group->flags & ZBX_FLAG_LLD_GROUP_DISCOVERED))
1213 			continue;
1214 
1215 		if (0 == group->groupid)
1216 			new_groups++;
1217 		else if (0 != (group->flags & ZBX_FLAG_LLD_GROUP_UPDATE))
1218 			upd_groups++;
1219 	}
1220 
1221 	if (0 == new_groups && 0 == upd_groups)
1222 		goto out;
1223 
1224 	DBbegin();
1225 
1226 	if (0 != new_groups)
1227 	{
1228 		groupid = DBget_maxid_num("groups", new_groups);
1229 
1230 		zbx_db_insert_prepare(&db_insert, "groups", "groupid", "name", "flags", NULL);
1231 
1232 		zbx_db_insert_prepare(&db_insert_gdiscovery, "group_discovery", "groupid", "parent_group_prototypeid",
1233 				"name", NULL);
1234 	}
1235 
1236 	if (0 != upd_groups)
1237 	{
1238 		DBbegin_multiple_update(&sql, &sql_alloc, &sql_offset);
1239 	}
1240 
1241 	for (i = 0; i < groups->values_num; i++)
1242 	{
1243 		group = (zbx_lld_group_t *)groups->values[i];
1244 
1245 		if (0 == (group->flags & ZBX_FLAG_LLD_GROUP_DISCOVERED))
1246 			continue;
1247 
1248 		if (0 == group->groupid)
1249 		{
1250 			group->groupid = groupid++;
1251 
1252 			zbx_db_insert_add_values(&db_insert, group->groupid, group->name,
1253 					(int)ZBX_FLAG_DISCOVERY_CREATED);
1254 
1255 			if (FAIL != (j = zbx_vector_ptr_bsearch(group_prototypes, &group->group_prototypeid,
1256 					ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC)))
1257 			{
1258 				group_prototype = (zbx_lld_group_prototype_t *)group_prototypes->values[j];
1259 
1260 				zbx_db_insert_add_values(&db_insert_gdiscovery, group->groupid,
1261 						group->group_prototypeid, group_prototype->name);
1262 			}
1263 			else
1264 				THIS_SHOULD_NEVER_HAPPEN;
1265 
1266 			for (j = 0; j < group->hosts.values_num; j++)
1267 			{
1268 				host = (zbx_lld_host_t *)group->hosts.values[j];
1269 
1270 				/* hosts will be linked to a new host groups */
1271 				zbx_vector_uint64_append(&host->new_groupids, group->groupid);
1272 			}
1273 		}
1274 		else
1275 		{
1276 			if (0 != (group->flags & ZBX_FLAG_LLD_GROUP_UPDATE))
1277 			{
1278 				zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "update groups set ");
1279 				if (0 != (group->flags & ZBX_FLAG_LLD_GROUP_UPDATE_NAME))
1280 				{
1281 					name_esc = DBdyn_escape_string(group->name);
1282 
1283 					zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "name='%s'", name_esc);
1284 
1285 					zbx_free(name_esc);
1286 				}
1287 				zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
1288 						" where groupid=" ZBX_FS_UI64 ";\n", group->groupid);
1289 			}
1290 
1291 			if (0 != (group->flags & ZBX_FLAG_LLD_GROUP_UPDATE_NAME))
1292 			{
1293 				if (FAIL != (j = zbx_vector_ptr_bsearch(group_prototypes, &group->group_prototypeid,
1294 						ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC)))
1295 				{
1296 					group_prototype = (zbx_lld_group_prototype_t *)group_prototypes->values[j];
1297 
1298 					name_proto_esc = DBdyn_escape_string(group_prototype->name);
1299 
1300 					zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
1301 							"update group_discovery"
1302 							" set name='%s'"
1303 							" where groupid=" ZBX_FS_UI64 ";\n",
1304 							name_proto_esc, group->groupid);
1305 
1306 					zbx_free(name_proto_esc);
1307 				}
1308 				else
1309 					THIS_SHOULD_NEVER_HAPPEN;
1310 			}
1311 		}
1312 	}
1313 
1314 	if (0 != upd_groups)
1315 	{
1316 		DBend_multiple_update(&sql, &sql_alloc, &sql_offset);
1317 		DBexecute("%s", sql);
1318 		zbx_free(sql);
1319 	}
1320 
1321 	if (0 != new_groups)
1322 	{
1323 		zbx_db_insert_execute(&db_insert);
1324 		zbx_db_insert_clean(&db_insert);
1325 
1326 		zbx_db_insert_execute(&db_insert_gdiscovery);
1327 		zbx_db_insert_clean(&db_insert_gdiscovery);
1328 	}
1329 
1330 	DBcommit();
1331 out:
1332 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
1333 }
1334 
1335 /******************************************************************************
1336  *                                                                            *
1337  * Function: lld_hostmacros_get                                               *
1338  *                                                                            *
1339  * Purpose: retrieve list of host macros which should be present on the each  *
1340  *          discovered host                                                   *
1341  *                                                                            *
1342  * Parameters: hostmacros - [OUT] list of host macros                         *
1343  *                                                                            *
1344  ******************************************************************************/
lld_hostmacros_get(zbx_uint64_t lld_ruleid,zbx_vector_ptr_t * hostmacros)1345 static void	lld_hostmacros_get(zbx_uint64_t lld_ruleid, zbx_vector_ptr_t *hostmacros)
1346 {
1347 	const char		*__function_name = "lld_hostmacros_get";
1348 
1349 	DB_RESULT		result;
1350 	DB_ROW			row;
1351 	zbx_lld_hostmacro_t	*hostmacro;
1352 
1353 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
1354 
1355 	result = DBselect(
1356 			"select hm.macro,hm.value"
1357 			" from hostmacro hm,items i"
1358 			" where hm.hostid=i.hostid"
1359 				" and i.itemid=" ZBX_FS_UI64,
1360 			lld_ruleid);
1361 
1362 	while (NULL != (row = DBfetch(result)))
1363 	{
1364 		hostmacro = zbx_malloc(NULL, sizeof(zbx_lld_hostmacro_t));
1365 
1366 		hostmacro->macro = zbx_strdup(NULL, row[0]);
1367 		hostmacro->value = zbx_strdup(NULL, row[1]);
1368 
1369 		zbx_vector_ptr_append(hostmacros, hostmacro);
1370 	}
1371 	DBfree_result(result);
1372 
1373 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
1374 }
1375 
1376 /******************************************************************************
1377  *                                                                            *
1378  * Function: lld_hostmacros_make                                              *
1379  *                                                                            *
1380  * Parameters: hostmacros       - [IN] list of host macros which              *
1381  *                                     should be present on the each          *
1382  *                                     discovered host                        *
1383  *             hosts            - [IN/OUT] list of hosts                      *
1384  *                                         should be sorted by hostid         *
1385  *             del_hostmacroids - [OUT] list of host macros which should be   *
1386  *                                      deleted                               *
1387  *                                                                            *
1388  ******************************************************************************/
lld_hostmacros_make(const zbx_vector_ptr_t * hostmacros,zbx_vector_ptr_t * hosts,zbx_vector_uint64_t * del_hostmacroids)1389 static void	lld_hostmacros_make(const zbx_vector_ptr_t *hostmacros, zbx_vector_ptr_t *hosts,
1390 		zbx_vector_uint64_t *del_hostmacroids)
1391 {
1392 	const char		*__function_name = "lld_hostmacros_make";
1393 
1394 	DB_RESULT		result;
1395 	DB_ROW			row;
1396 	int			i, j;
1397 	zbx_vector_uint64_t	hostids;
1398 	zbx_uint64_t		hostmacroid, hostid;
1399 	zbx_lld_host_t		*host;
1400 	zbx_lld_hostmacro_t	*hostmacro = NULL;
1401 
1402 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
1403 
1404 	zbx_vector_uint64_create(&hostids);
1405 
1406 	for (i = 0; i < hosts->values_num; i++)
1407 	{
1408 		host = (zbx_lld_host_t *)hosts->values[i];
1409 
1410 		if (0 == (host->flags & ZBX_FLAG_LLD_HOST_DISCOVERED))
1411 			continue;
1412 
1413 		zbx_vector_ptr_reserve(&host->new_hostmacros, hostmacros->values_num);
1414 		for (j = 0; j < hostmacros->values_num; j++)
1415 		{
1416 			hostmacro = zbx_malloc(NULL, sizeof(zbx_lld_hostmacro_t));
1417 
1418 			hostmacro->hostmacroid = 0;
1419 			hostmacro->macro = zbx_strdup(NULL, ((zbx_lld_hostmacro_t *)hostmacros->values[j])->macro);
1420 			hostmacro->value = zbx_strdup(NULL, ((zbx_lld_hostmacro_t *)hostmacros->values[j])->value);
1421 
1422 			zbx_vector_ptr_append(&host->new_hostmacros, hostmacro);
1423 		}
1424 
1425 		if (0 != host->hostid)
1426 			zbx_vector_uint64_append(&hostids, host->hostid);
1427 	}
1428 
1429 	if (0 != hostids.values_num)
1430 	{
1431 		char	*sql = NULL;
1432 		size_t	sql_alloc = 0, sql_offset = 0;
1433 
1434 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
1435 				"select hostmacroid,hostid,macro,value"
1436 				" from hostmacro"
1437 				" where");
1438 		DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "hostid", hostids.values, hostids.values_num);
1439 
1440 		result = DBselect("%s", sql);
1441 
1442 		zbx_free(sql);
1443 
1444 		while (NULL != (row = DBfetch(result)))
1445 		{
1446 			ZBX_STR2UINT64(hostid, row[1]);
1447 
1448 			if (FAIL == (i = zbx_vector_ptr_bsearch(hosts, &hostid, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC)))
1449 			{
1450 				THIS_SHOULD_NEVER_HAPPEN;
1451 				continue;
1452 			}
1453 
1454 			host = (zbx_lld_host_t *)hosts->values[i];
1455 
1456 			for (i = 0; i < host->new_hostmacros.values_num; i++)
1457 			{
1458 				hostmacro = (zbx_lld_hostmacro_t *)host->new_hostmacros.values[i];
1459 
1460 				if (0 == strcmp(hostmacro->macro, row[2]))
1461 					break;
1462 			}
1463 
1464 			if (i == host->new_hostmacros.values_num)
1465 			{
1466 				/* host macros which should be deleted */
1467 				ZBX_STR2UINT64(hostmacroid, row[0]);
1468 				zbx_vector_uint64_append(del_hostmacroids, hostmacroid);
1469 			}
1470 			else
1471 			{
1472 				/* host macros which are already added */
1473 				if (0 == strcmp(hostmacro->value, row[3]))	/* value doesn't changed */
1474 				{
1475 					lld_hostmacro_free(hostmacro);
1476 					zbx_vector_ptr_remove(&host->new_hostmacros, i);
1477 				}
1478 				else
1479 					ZBX_STR2UINT64(hostmacro->hostmacroid, row[0]);
1480 			}
1481 		}
1482 		DBfree_result(result);
1483 
1484 		zbx_vector_uint64_sort(del_hostmacroids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
1485 	}
1486 
1487 	zbx_vector_uint64_destroy(&hostids);
1488 
1489 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
1490 }
1491 
1492 /******************************************************************************
1493  *                                                                            *
1494  * Function: lld_templates_make                                               *
1495  *                                                                            *
1496  * Purpose: gets templates from a host prototype                              *
1497  *                                                                            *
1498  * Parameters: parent_hostid - [IN] host prototype identifier                 *
1499  *             hosts         - [IN/OUT] list of hosts                         *
1500  *                                      should be sorted by hostid            *
1501  *                                                                            *
1502  ******************************************************************************/
lld_templates_make(zbx_uint64_t parent_hostid,zbx_vector_ptr_t * hosts)1503 static void	lld_templates_make(zbx_uint64_t parent_hostid, zbx_vector_ptr_t *hosts)
1504 {
1505 	const char		*__function_name = "lld_templates_make";
1506 
1507 	DB_RESULT		result;
1508 	DB_ROW			row;
1509 	zbx_vector_uint64_t	templateids, hostids;
1510 	zbx_uint64_t		templateid, hostid;
1511 	zbx_lld_host_t		*host;
1512 	int			i, j;
1513 
1514 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
1515 
1516 	zbx_vector_uint64_create(&templateids);
1517 	zbx_vector_uint64_create(&hostids);
1518 
1519 	/* select templates which should be linked */
1520 
1521 	result = DBselect("select templateid from hosts_templates where hostid=" ZBX_FS_UI64, parent_hostid);
1522 
1523 	while (NULL != (row = DBfetch(result)))
1524 	{
1525 		ZBX_STR2UINT64(templateid, row[0]);
1526 		zbx_vector_uint64_append(&templateids, templateid);
1527 	}
1528 	DBfree_result(result);
1529 
1530 	zbx_vector_uint64_sort(&templateids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
1531 
1532 	/* select list of already created hosts */
1533 
1534 	for (i = 0; i < hosts->values_num; i++)
1535 	{
1536 		host = (zbx_lld_host_t *)hosts->values[i];
1537 
1538 		if (0 == (host->flags & ZBX_FLAG_LLD_HOST_DISCOVERED))
1539 			continue;
1540 
1541 		zbx_vector_uint64_reserve(&host->lnk_templateids, templateids.values_num);
1542 		for (j = 0; j < templateids.values_num; j++)
1543 			zbx_vector_uint64_append(&host->lnk_templateids, templateids.values[j]);
1544 
1545 		if (0 != host->hostid)
1546 			zbx_vector_uint64_append(&hostids, host->hostid);
1547 	}
1548 
1549 	if (0 != hostids.values_num)
1550 	{
1551 		char	*sql = NULL;
1552 		size_t	sql_alloc = 0, sql_offset = 0;
1553 
1554 		/* select already linked temlates */
1555 
1556 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
1557 				"select hostid,templateid"
1558 				" from hosts_templates"
1559 				" where");
1560 		DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "hostid", hostids.values, hostids.values_num);
1561 
1562 		result = DBselect("%s", sql);
1563 
1564 		zbx_free(sql);
1565 
1566 		while (NULL != (row = DBfetch(result)))
1567 		{
1568 			ZBX_STR2UINT64(hostid, row[0]);
1569 			ZBX_STR2UINT64(templateid, row[1]);
1570 
1571 			if (FAIL == (i = zbx_vector_ptr_bsearch(hosts, &hostid, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC)))
1572 			{
1573 				THIS_SHOULD_NEVER_HAPPEN;
1574 				continue;
1575 			}
1576 
1577 			host = (zbx_lld_host_t *)hosts->values[i];
1578 
1579 			if (FAIL == (i = zbx_vector_uint64_bsearch(&host->lnk_templateids, templateid,
1580 					ZBX_DEFAULT_UINT64_COMPARE_FUNC)))
1581 			{
1582 				/* templates which should be unlinked */
1583 				zbx_vector_uint64_append(&host->del_templateids, templateid);
1584 			}
1585 			else
1586 			{
1587 				/* templates which are already linked */
1588 				zbx_vector_uint64_remove(&host->lnk_templateids, i);
1589 			}
1590 		}
1591 		DBfree_result(result);
1592 
1593 		for (i = 0; i < hosts->values_num; i++)
1594 		{
1595 			host = (zbx_lld_host_t *)hosts->values[i];
1596 
1597 			if (0 == (host->flags & ZBX_FLAG_LLD_HOST_DISCOVERED))
1598 				continue;
1599 
1600 			zbx_vector_uint64_sort(&host->del_templateids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
1601 		}
1602 	}
1603 
1604 	zbx_vector_uint64_destroy(&hostids);
1605 	zbx_vector_uint64_destroy(&templateids);
1606 
1607 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
1608 }
1609 
1610 /******************************************************************************
1611  *                                                                            *
1612  * Function: lld_hosts_save                                                   *
1613  *                                                                            *
1614  * Parameters: hosts            - [IN] list of hosts;                         *
1615  *                                     should be sorted by hostid             *
1616  *             status           - [IN] initial host status                    *
1617  *             del_hostgroupids - [IN] host groups which should be deleted    *
1618  *             del_hostmacroids - [IN] host macros which should be deleted    *
1619  *                                                                            *
1620  ******************************************************************************/
lld_hosts_save(zbx_uint64_t parent_hostid,zbx_vector_ptr_t * hosts,const char * host_proto,zbx_uint64_t proxy_hostid,char ipmi_authtype,unsigned char ipmi_privilege,const char * ipmi_username,const char * ipmi_password,unsigned char status,char inventory_mode,unsigned char tls_connect,unsigned char tls_accept,const char * tls_issuer,const char * tls_subject,const char * tls_psk_identity,const char * tls_psk,const zbx_vector_uint64_t * del_hostgroupids,const zbx_vector_uint64_t * del_hostmacroids)1621 static void	lld_hosts_save(zbx_uint64_t parent_hostid, zbx_vector_ptr_t *hosts, const char *host_proto,
1622 		zbx_uint64_t proxy_hostid, char ipmi_authtype, unsigned char ipmi_privilege, const char *ipmi_username,
1623 		const char *ipmi_password, unsigned char status, char inventory_mode, unsigned char tls_connect,
1624 		unsigned char tls_accept, const char *tls_issuer, const char *tls_subject, const char *tls_psk_identity,
1625 		const char *tls_psk, const zbx_vector_uint64_t *del_hostgroupids,
1626 		const zbx_vector_uint64_t *del_hostmacroids)
1627 {
1628 	const char		*__function_name = "lld_hosts_save";
1629 
1630 	int			i, j, new_hosts = 0, new_host_inventories = 0, upd_hosts = 0, new_hostgroups = 0,
1631 				new_hostmacros = 0, upd_hostmacros = 0, new_interfaces = 0, upd_interfaces = 0;
1632 	zbx_lld_host_t		*host;
1633 	zbx_lld_hostmacro_t	*hostmacro;
1634 	zbx_lld_interface_t	*interface;
1635 	zbx_vector_uint64_t	upd_host_inventory_hostids, del_host_inventory_hostids, del_interfaceids;
1636 	zbx_uint64_t		hostid = 0, hostgroupid = 0, hostmacroid = 0, interfaceid = 0;
1637 	char			*sql1 = NULL, *sql2 = NULL, *value_esc;
1638 	size_t			sql1_alloc = 0, sql1_offset = 0,
1639 				sql2_alloc = 0, sql2_offset = 0;
1640 	zbx_db_insert_t		db_insert, db_insert_hdiscovery, db_insert_hinventory, db_insert_hgroups,
1641 				db_insert_hmacro, db_insert_interface, db_insert_idiscovery;
1642 
1643 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
1644 
1645 	zbx_vector_uint64_create(&upd_host_inventory_hostids);
1646 	zbx_vector_uint64_create(&del_host_inventory_hostids);
1647 	zbx_vector_uint64_create(&del_interfaceids);
1648 
1649 	for (i = 0; i < hosts->values_num; i++)
1650 	{
1651 		host = (zbx_lld_host_t *)hosts->values[i];
1652 
1653 		if (0 == (host->flags & ZBX_FLAG_LLD_HOST_DISCOVERED))
1654 			continue;
1655 
1656 		if (0 == host->hostid)
1657 		{
1658 			new_hosts++;
1659 			if (HOST_INVENTORY_DISABLED != inventory_mode)
1660 				new_host_inventories++;
1661 		}
1662 		else
1663 		{
1664 			if (0 != (host->flags & ZBX_FLAG_LLD_HOST_UPDATE))
1665 				upd_hosts++;
1666 
1667 			if (host->inventory_mode != inventory_mode)
1668 			{
1669 				if (HOST_INVENTORY_DISABLED == inventory_mode)
1670 					zbx_vector_uint64_append(&del_host_inventory_hostids, host->hostid);
1671 				else if (HOST_INVENTORY_DISABLED == host->inventory_mode)
1672 					new_host_inventories++;
1673 				else
1674 					zbx_vector_uint64_append(&upd_host_inventory_hostids, host->hostid);
1675 			}
1676 		}
1677 
1678 		new_hostgroups += host->new_groupids.values_num;
1679 
1680 		for (j = 0; j < host->interfaces.values_num; j++)
1681 		{
1682 			interface = (zbx_lld_interface_t *)host->interfaces.values[j];
1683 
1684 			if (0 == interface->interfaceid)
1685 				new_interfaces++;
1686 			else if (0 != (interface->flags & ZBX_FLAG_LLD_INTERFACE_UPDATE))
1687 				upd_interfaces++;
1688 			else if (0 != (interface->flags & ZBX_FLAG_LLD_INTERFACE_REMOVE))
1689 				zbx_vector_uint64_append(&del_interfaceids, interface->interfaceid);
1690 		}
1691 
1692 		for (j = 0; j < host->new_hostmacros.values_num; j++)
1693 		{
1694 			hostmacro = (zbx_lld_hostmacro_t *)host->new_hostmacros.values[j];
1695 
1696 			if (0 == hostmacro->hostmacroid)
1697 				new_hostmacros++;
1698 			else
1699 				upd_hostmacros++;
1700 		}
1701 	}
1702 
1703 	if (0 == new_hosts && 0 == new_host_inventories && 0 == upd_hosts && 0 == upd_interfaces &&
1704 			0 == upd_hostmacros && 0 == new_hostgroups && 0 == new_hostmacros && 0 == new_interfaces &&
1705 			0 == del_hostgroupids->values_num && 0 == del_hostmacroids->values_num &&
1706 			0 == upd_host_inventory_hostids.values_num && 0 == del_host_inventory_hostids.values_num &&
1707 			0 == del_interfaceids.values_num)
1708 	{
1709 		goto out;
1710 	}
1711 
1712 	DBbegin();
1713 
1714 	if (0 != new_hosts)
1715 	{
1716 		hostid = DBget_maxid_num("hosts", new_hosts);
1717 
1718 		zbx_db_insert_prepare(&db_insert, "hosts", "hostid", "host", "name", "proxy_hostid", "ipmi_authtype",
1719 				"ipmi_privilege", "ipmi_username", "ipmi_password", "status", "flags", "tls_connect",
1720 				"tls_accept", "tls_issuer", "tls_subject", "tls_psk_identity", "tls_psk", NULL);
1721 
1722 		zbx_db_insert_prepare(&db_insert_hdiscovery, "host_discovery", "hostid", "parent_hostid", "host", NULL);
1723 	}
1724 
1725 	if (0 != new_host_inventories)
1726 	{
1727 		zbx_db_insert_prepare(&db_insert_hinventory, "host_inventory", "hostid", "inventory_mode", NULL);
1728 	}
1729 
1730 	if (0 != upd_hosts || 0 != upd_interfaces || 0 != upd_hostmacros)
1731 	{
1732 		DBbegin_multiple_update(&sql1, &sql1_alloc, &sql1_offset);
1733 	}
1734 
1735 	if (0 != new_hostgroups)
1736 	{
1737 		hostgroupid = DBget_maxid_num("hosts_groups", new_hostgroups);
1738 
1739 		zbx_db_insert_prepare(&db_insert_hgroups, "hosts_groups", "hostgroupid", "hostid", "groupid", NULL);
1740 	}
1741 
1742 	if (0 != new_hostmacros)
1743 	{
1744 		hostmacroid = DBget_maxid_num("hostmacro", new_hostmacros);
1745 
1746 		zbx_db_insert_prepare(&db_insert_hmacro, "hostmacro", "hostmacroid", "hostid", "macro", "value", NULL);
1747 	}
1748 
1749 	if (0 != new_interfaces)
1750 	{
1751 		interfaceid = DBget_maxid_num("interface", new_interfaces);
1752 
1753 		zbx_db_insert_prepare(&db_insert_interface, "interface", "interfaceid", "hostid", "type", "main",
1754 				"useip", "ip", "dns", "port", "bulk", NULL);
1755 
1756 		zbx_db_insert_prepare(&db_insert_idiscovery, "interface_discovery", "interfaceid",
1757 				"parent_interfaceid", NULL);
1758 	}
1759 
1760 	for (i = 0; i < hosts->values_num; i++)
1761 	{
1762 		host = (zbx_lld_host_t *)hosts->values[i];
1763 
1764 		if (0 == (host->flags & ZBX_FLAG_LLD_HOST_DISCOVERED))
1765 			continue;
1766 
1767 		if (0 == host->hostid)
1768 		{
1769 			host->hostid = hostid++;
1770 
1771 			zbx_db_insert_add_values(&db_insert, host->hostid, host->host, host->name, proxy_hostid,
1772 					(int)ipmi_authtype, (int)ipmi_privilege, ipmi_username, ipmi_password,
1773 					(int)status, (int)ZBX_FLAG_DISCOVERY_CREATED, (int)tls_connect,
1774 					(int)tls_accept, tls_issuer, tls_subject, tls_psk_identity, tls_psk);
1775 
1776 			zbx_db_insert_add_values(&db_insert_hdiscovery, host->hostid, parent_hostid, host_proto);
1777 
1778 			if (HOST_INVENTORY_DISABLED != inventory_mode)
1779 				zbx_db_insert_add_values(&db_insert_hinventory, host->hostid, (int)inventory_mode);
1780 		}
1781 		else
1782 		{
1783 			if (0 != (host->flags & ZBX_FLAG_LLD_HOST_UPDATE))
1784 			{
1785 				const char	*d = "";
1786 
1787 				zbx_strcpy_alloc(&sql1, &sql1_alloc, &sql1_offset, "update hosts set ");
1788 				if (0 != (host->flags & ZBX_FLAG_LLD_HOST_UPDATE_HOST))
1789 				{
1790 					value_esc = DBdyn_escape_string(host->host);
1791 
1792 					zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset, "host='%s'", value_esc);
1793 					d = ",";
1794 
1795 					zbx_free(value_esc);
1796 				}
1797 				if (0 != (host->flags & ZBX_FLAG_LLD_HOST_UPDATE_NAME))
1798 				{
1799 					value_esc = DBdyn_escape_string(host->name);
1800 
1801 					zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset,
1802 							"%sname='%s'", d, value_esc);
1803 					d = ",";
1804 
1805 					zbx_free(value_esc);
1806 				}
1807 				if (0 != (host->flags & ZBX_FLAG_LLD_HOST_UPDATE_PROXY))
1808 				{
1809 					zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset,
1810 							"%sproxy_hostid=%s", d, DBsql_id_ins(proxy_hostid));
1811 					d = ",";
1812 				}
1813 				if (0 != (host->flags & ZBX_FLAG_LLD_HOST_UPDATE_IPMI_AUTH))
1814 				{
1815 					zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset,
1816 							"%sipmi_authtype=%d", d, (int)ipmi_authtype);
1817 					d = ",";
1818 				}
1819 				if (0 != (host->flags & ZBX_FLAG_LLD_HOST_UPDATE_IPMI_PRIV))
1820 				{
1821 					zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset,
1822 							"%sipmi_privilege=%d", d, (int)ipmi_privilege);
1823 					d = ",";
1824 				}
1825 				if (0 != (host->flags & ZBX_FLAG_LLD_HOST_UPDATE_IPMI_USER))
1826 				{
1827 					value_esc = DBdyn_escape_string(ipmi_username);
1828 
1829 					zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset,
1830 							"%sipmi_username='%s'", d, value_esc);
1831 					d = ",";
1832 
1833 					zbx_free(value_esc);
1834 				}
1835 				if (0 != (host->flags & ZBX_FLAG_LLD_HOST_UPDATE_IPMI_PASS))
1836 				{
1837 					value_esc = DBdyn_escape_string(ipmi_password);
1838 
1839 					zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset,
1840 							"%sipmi_password='%s'", d, value_esc);
1841 					d = ",";
1842 
1843 					zbx_free(value_esc);
1844 				}
1845 				if (0 != (host->flags & ZBX_FLAG_LLD_HOST_UPDATE_TLS_CONNECT))
1846 				{
1847 					zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset,
1848 							"%stls_connect=%d", d, tls_connect);
1849 					d = ",";
1850 				}
1851 				if (0 != (host->flags & ZBX_FLAG_LLD_HOST_UPDATE_TLS_ACCEPT))
1852 				{
1853 					zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset,
1854 							"%stls_accept=%d", d, tls_accept);
1855 					d = ",";
1856 				}
1857 				if (0 != (host->flags & ZBX_FLAG_LLD_HOST_UPDATE_TLS_ISSUER))
1858 				{
1859 					value_esc = DBdyn_escape_string(tls_issuer);
1860 
1861 					zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset,
1862 							"%stls_issuer='%s'", d, value_esc);
1863 					d = ",";
1864 
1865 					zbx_free(value_esc);
1866 				}
1867 				if (0 != (host->flags & ZBX_FLAG_LLD_HOST_UPDATE_TLS_SUBJECT))
1868 				{
1869 					value_esc = DBdyn_escape_string(tls_subject);
1870 
1871 					zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset,
1872 							"%stls_subject='%s'", d, value_esc);
1873 					d = ",";
1874 
1875 					zbx_free(value_esc);
1876 				}
1877 				if (0 != (host->flags & ZBX_FLAG_LLD_HOST_UPDATE_TLS_PSK_IDENTITY))
1878 				{
1879 					value_esc = DBdyn_escape_string(tls_psk_identity);
1880 
1881 					zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset,
1882 							"%stls_psk_identity='%s'", d, value_esc);
1883 					d = ",";
1884 
1885 					zbx_free(value_esc);
1886 				}
1887 				if (0 != (host->flags & ZBX_FLAG_LLD_HOST_UPDATE_TLS_PSK))
1888 				{
1889 					value_esc = DBdyn_escape_string(tls_psk);
1890 
1891 					zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset,
1892 							"%stls_psk='%s'", d, value_esc);
1893 
1894 					zbx_free(value_esc);
1895 				}
1896 				zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset, " where hostid=" ZBX_FS_UI64 ";\n",
1897 						host->hostid);
1898 			}
1899 
1900 			if (host->inventory_mode != inventory_mode && HOST_INVENTORY_DISABLED == host->inventory_mode)
1901 				zbx_db_insert_add_values(&db_insert_hinventory, host->hostid, (int)inventory_mode);
1902 
1903 			if (0 != (host->flags & ZBX_FLAG_LLD_HOST_UPDATE_HOST))
1904 			{
1905 				value_esc = DBdyn_escape_string(host_proto);
1906 
1907 				zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset,
1908 						"update host_discovery"
1909 						" set host='%s'"
1910 						" where hostid=" ZBX_FS_UI64 ";\n",
1911 						value_esc, host->hostid);
1912 
1913 				zbx_free(value_esc);
1914 			}
1915 		}
1916 
1917 		for (j = 0; j < host->interfaces.values_num; j++)
1918 		{
1919 			interface = (zbx_lld_interface_t *)host->interfaces.values[j];
1920 
1921 			if (0 == interface->interfaceid)
1922 			{
1923 				interface->interfaceid = interfaceid++;
1924 
1925 				zbx_db_insert_add_values(&db_insert_interface, interface->interfaceid, host->hostid,
1926 						(int)interface->type, (int)interface->main, (int)interface->useip,
1927 						interface->ip, interface->dns, interface->port, (int)interface->bulk);
1928 
1929 				zbx_db_insert_add_values(&db_insert_idiscovery, interface->interfaceid,
1930 						interface->parent_interfaceid);
1931 			}
1932 			else if (0 != (interface->flags & ZBX_FLAG_LLD_INTERFACE_UPDATE))
1933 			{
1934 				const char	*d = "";
1935 
1936 				zbx_strcpy_alloc(&sql1, &sql1_alloc, &sql1_offset, "update interface set ");
1937 				if (0 != (interface->flags & ZBX_FLAG_LLD_INTERFACE_UPDATE_TYPE))
1938 				{
1939 					zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset, "type=%d",
1940 							(int)interface->type);
1941 					d = ",";
1942 				}
1943 				if (0 != (interface->flags & ZBX_FLAG_LLD_INTERFACE_UPDATE_MAIN))
1944 				{
1945 					zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset, "%smain=%d",
1946 							d, (int)interface->main);
1947 					d = ",";
1948 				}
1949 				if (0 != (interface->flags & ZBX_FLAG_LLD_INTERFACE_UPDATE_USEIP))
1950 				{
1951 					zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset, "%suseip=%d",
1952 							d, (int)interface->useip);
1953 					d = ",";
1954 				}
1955 				if (0 != (interface->flags & ZBX_FLAG_LLD_INTERFACE_UPDATE_IP))
1956 				{
1957 					value_esc = DBdyn_escape_string(interface->ip);
1958 					zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset, "%sip='%s'", d, value_esc);
1959 					zbx_free(value_esc);
1960 					d = ",";
1961 				}
1962 				if (0 != (interface->flags & ZBX_FLAG_LLD_INTERFACE_UPDATE_DNS))
1963 				{
1964 					value_esc = DBdyn_escape_string(interface->dns);
1965 					zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset, "%sdns='%s'", d, value_esc);
1966 					zbx_free(value_esc);
1967 					d = ",";
1968 				}
1969 				if (0 != (interface->flags & ZBX_FLAG_LLD_INTERFACE_UPDATE_PORT))
1970 				{
1971 					value_esc = DBdyn_escape_string(interface->port);
1972 					zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset, "%sport='%s'",
1973 							d, value_esc);
1974 					zbx_free(value_esc);
1975 					d = ",";
1976 				}
1977 				if (0 != (interface->flags & ZBX_FLAG_LLD_INTERFACE_UPDATE_BULK))
1978 				{
1979 					zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset, "%sbulk=%d",
1980 							d, (int)interface->bulk);
1981 				}
1982 				zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset,
1983 						" where interfaceid=" ZBX_FS_UI64 ";\n", interface->interfaceid);
1984 			}
1985 		}
1986 
1987 		for (j = 0; j < host->new_groupids.values_num; j++)
1988 		{
1989 			zbx_db_insert_add_values(&db_insert_hgroups, hostgroupid++, host->hostid,
1990 					host->new_groupids.values[j]);
1991 		}
1992 
1993 		for (j = 0; j < host->new_hostmacros.values_num; j++)
1994 		{
1995 			hostmacro = (zbx_lld_hostmacro_t *)host->new_hostmacros.values[j];
1996 
1997 			value_esc = DBdyn_escape_string(hostmacro->value);
1998 
1999 			if (0 == hostmacro->hostmacroid)
2000 			{
2001 				zbx_db_insert_add_values(&db_insert_hmacro, hostmacroid++, host->hostid,
2002 						hostmacro->macro, hostmacro->value);
2003 			}
2004 			else
2005 			{
2006 				zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset,
2007 						"update hostmacro"
2008 						" set value='%s'"
2009 						" where hostmacroid=" ZBX_FS_UI64 ";\n",
2010 						value_esc, hostmacro->hostmacroid);
2011 			}
2012 
2013 			zbx_free(value_esc);
2014 		}
2015 	}
2016 
2017 	if (0 != new_hosts)
2018 	{
2019 		zbx_db_insert_execute(&db_insert);
2020 		zbx_db_insert_clean(&db_insert);
2021 
2022 		zbx_db_insert_execute(&db_insert_hdiscovery);
2023 		zbx_db_insert_clean(&db_insert_hdiscovery);
2024 	}
2025 
2026 	if (0 != new_host_inventories)
2027 	{
2028 		zbx_db_insert_execute(&db_insert_hinventory);
2029 		zbx_db_insert_clean(&db_insert_hinventory);
2030 	}
2031 
2032 	if (0 != new_hostgroups)
2033 	{
2034 		zbx_db_insert_execute(&db_insert_hgroups);
2035 		zbx_db_insert_clean(&db_insert_hgroups);
2036 	}
2037 
2038 	if (0 != new_hostmacros)
2039 	{
2040 		zbx_db_insert_execute(&db_insert_hmacro);
2041 		zbx_db_insert_clean(&db_insert_hmacro);
2042 	}
2043 
2044 	if (0 != new_interfaces)
2045 	{
2046 		zbx_db_insert_execute(&db_insert_interface);
2047 		zbx_db_insert_clean(&db_insert_interface);
2048 
2049 		zbx_db_insert_execute(&db_insert_idiscovery);
2050 		zbx_db_insert_clean(&db_insert_idiscovery);
2051 	}
2052 
2053 	if (0 != upd_hosts || 0 != upd_interfaces || 0 != upd_hostmacros)
2054 	{
2055 		DBend_multiple_update(&sql1, &sql1_alloc, &sql1_offset);
2056 		DBexecute("%s", sql1);
2057 		zbx_free(sql1);
2058 	}
2059 
2060 	if (0 != del_hostgroupids->values_num || 0 != del_hostmacroids->values_num ||
2061 			0 != upd_host_inventory_hostids.values_num || 0 != del_host_inventory_hostids.values_num ||
2062 			0 != del_interfaceids.values_num)
2063 	{
2064 		DBbegin_multiple_update(&sql2, &sql2_alloc, &sql2_offset);
2065 
2066 		if (0 != del_hostgroupids->values_num)
2067 		{
2068 			zbx_strcpy_alloc(&sql2, &sql2_alloc, &sql2_offset, "delete from hosts_groups where");
2069 			DBadd_condition_alloc(&sql2, &sql2_alloc, &sql2_offset, "hostgroupid",
2070 					del_hostgroupids->values, del_hostgroupids->values_num);
2071 			zbx_strcpy_alloc(&sql2, &sql2_alloc, &sql2_offset, ";\n");
2072 		}
2073 
2074 		if (0 != del_hostmacroids->values_num)
2075 		{
2076 			zbx_strcpy_alloc(&sql2, &sql2_alloc, &sql2_offset, "delete from hostmacro where");
2077 			DBadd_condition_alloc(&sql2, &sql2_alloc, &sql2_offset, "hostmacroid",
2078 					del_hostmacroids->values, del_hostmacroids->values_num);
2079 			zbx_strcpy_alloc(&sql2, &sql2_alloc, &sql2_offset, ";\n");
2080 		}
2081 
2082 		if (0 != upd_host_inventory_hostids.values_num)
2083 		{
2084 			zbx_snprintf_alloc(&sql2, &sql2_alloc, &sql2_offset,
2085 					"update host_inventory set inventory_mode=%d where", (int)inventory_mode);
2086 			DBadd_condition_alloc(&sql2, &sql2_alloc, &sql2_offset, "hostid",
2087 					upd_host_inventory_hostids.values, upd_host_inventory_hostids.values_num);
2088 			zbx_strcpy_alloc(&sql2, &sql2_alloc, &sql2_offset, ";\n");
2089 		}
2090 
2091 		if (0 != del_host_inventory_hostids.values_num)
2092 		{
2093 			zbx_strcpy_alloc(&sql2, &sql2_alloc, &sql2_offset, "delete from host_inventory where");
2094 			DBadd_condition_alloc(&sql2, &sql2_alloc, &sql2_offset, "hostid",
2095 					del_host_inventory_hostids.values, del_host_inventory_hostids.values_num);
2096 			zbx_strcpy_alloc(&sql2, &sql2_alloc, &sql2_offset, ";\n");
2097 		}
2098 
2099 		if (0 != del_interfaceids.values_num)
2100 		{
2101 			zbx_strcpy_alloc(&sql2, &sql2_alloc, &sql2_offset, "delete from interface where");
2102 			DBadd_condition_alloc(&sql2, &sql2_alloc, &sql2_offset, "interfaceid",
2103 					del_interfaceids.values, del_interfaceids.values_num);
2104 			zbx_strcpy_alloc(&sql2, &sql2_alloc, &sql2_offset, ";\n");
2105 		}
2106 
2107 		DBend_multiple_update(&sql2, &sql2_alloc, &sql2_offset);
2108 		DBexecute("%s", sql2);
2109 		zbx_free(sql2);
2110 	}
2111 
2112 	DBcommit();
2113 out:
2114 	zbx_vector_uint64_destroy(&del_interfaceids);
2115 	zbx_vector_uint64_destroy(&del_host_inventory_hostids);
2116 	zbx_vector_uint64_destroy(&upd_host_inventory_hostids);
2117 
2118 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
2119 }
2120 
2121 /******************************************************************************
2122  *                                                                            *
2123  * Function: lld_templates_link                                               *
2124  *                                                                            *
2125  ******************************************************************************/
lld_templates_link(const zbx_vector_ptr_t * hosts,char ** error)2126 static void	lld_templates_link(const zbx_vector_ptr_t *hosts, char **error)
2127 {
2128 	const char	*__function_name = "lld_templates_link";
2129 
2130 	int		i;
2131 	zbx_lld_host_t	*host;
2132 	char		*err;
2133 
2134 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
2135 
2136 	for (i = 0; i < hosts->values_num; i++)
2137 	{
2138 		host = (zbx_lld_host_t *)hosts->values[i];
2139 
2140 		if (0 == (host->flags & ZBX_FLAG_LLD_HOST_DISCOVERED))
2141 			continue;
2142 
2143 		if (0 != host->del_templateids.values_num)
2144 		{
2145 			if (SUCCEED != DBdelete_template_elements(host->hostid, &host->del_templateids, &err))
2146 			{
2147 				*error = zbx_strdcatf(*error, "Cannot unlink template: %s.\n", err);
2148 				zbx_free(err);
2149 			}
2150 		}
2151 
2152 		if (0 != host->lnk_templateids.values_num)
2153 		{
2154 			if (SUCCEED != DBcopy_template_elements(host->hostid, &host->lnk_templateids, &err))
2155 			{
2156 				*error = zbx_strdcatf(*error, "Cannot link template(s) %s.\n", err);
2157 				zbx_free(err);
2158 			}
2159 		}
2160 	}
2161 
2162 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
2163 }
2164 
2165 /******************************************************************************
2166  *                                                                            *
2167  * Function: lld_hosts_remove                                                 *
2168  *                                                                            *
2169  * Purpose: updates host_discovery.lastcheck and host_discovery.ts_delete     *
2170  *          fields; removes lost resources                                    *
2171  *                                                                            *
2172  ******************************************************************************/
lld_hosts_remove(const zbx_vector_ptr_t * hosts,unsigned short lifetime,int lastcheck)2173 static void	lld_hosts_remove(const zbx_vector_ptr_t *hosts, unsigned short lifetime, int lastcheck)
2174 {
2175 	char			*sql = NULL;
2176 	size_t			sql_alloc = 0, sql_offset = 0;
2177 	const zbx_lld_host_t	*host;
2178 	zbx_vector_uint64_t	del_hostids, lc_hostids, ts_hostids;
2179 	int			i, lifetime_sec;
2180 
2181 	if (0 == hosts->values_num)
2182 		return;
2183 
2184 	lifetime_sec = lifetime * SEC_PER_DAY;
2185 
2186 	zbx_vector_uint64_create(&del_hostids);
2187 	zbx_vector_uint64_create(&lc_hostids);
2188 	zbx_vector_uint64_create(&ts_hostids);
2189 
2190 	DBbegin_multiple_update(&sql, &sql_alloc, &sql_offset);
2191 
2192 	for (i = 0; i < hosts->values_num; i++)
2193 	{
2194 		host = (zbx_lld_host_t *)hosts->values[i];
2195 
2196 		if (0 == host->hostid)
2197 			continue;
2198 
2199 		if (0 == (host->flags & ZBX_FLAG_LLD_HOST_DISCOVERED))
2200 		{
2201 			if (host->lastcheck < lastcheck - lifetime_sec)
2202 			{
2203 				zbx_vector_uint64_append(&del_hostids, host->hostid);
2204 			}
2205 			else if (host->ts_delete != host->lastcheck + lifetime_sec)
2206 			{
2207 				zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
2208 						"update host_discovery"
2209 						" set ts_delete=%d"
2210 						" where hostid=" ZBX_FS_UI64 ";\n",
2211 						host->lastcheck + lifetime_sec, host->hostid);
2212 			}
2213 		}
2214 		else
2215 		{
2216 			zbx_vector_uint64_append(&lc_hostids, host->hostid);
2217 			if (0 != host->ts_delete)
2218 				zbx_vector_uint64_append(&ts_hostids, host->hostid);
2219 		}
2220 	}
2221 
2222 	if (0 != lc_hostids.values_num)
2223 	{
2224 		zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "update host_discovery set lastcheck=%d where",
2225 				lastcheck);
2226 		DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "hostid",
2227 				lc_hostids.values, lc_hostids.values_num);
2228 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, ";\n");
2229 	}
2230 
2231 	if (0 != ts_hostids.values_num)
2232 	{
2233 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "update host_discovery set ts_delete=0 where");
2234 		DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "hostid",
2235 				ts_hostids.values, ts_hostids.values_num);
2236 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, ";\n");
2237 	}
2238 
2239 	if (16 < sql_offset)	/* in ORACLE always present begin..end; */
2240 	{
2241 		DBend_multiple_update(&sql, &sql_alloc, &sql_offset);
2242 
2243 		DBbegin();
2244 
2245 		DBexecute("%s", sql);
2246 
2247 		DBcommit();
2248 	}
2249 
2250 	zbx_free(sql);
2251 
2252 	if (0 != del_hostids.values_num)
2253 	{
2254 		zbx_vector_uint64_sort(&del_hostids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
2255 
2256 		DBbegin();
2257 
2258 		DBdelete_hosts(&del_hostids);
2259 
2260 		DBcommit();
2261 	}
2262 
2263 	zbx_vector_uint64_destroy(&ts_hostids);
2264 	zbx_vector_uint64_destroy(&lc_hostids);
2265 	zbx_vector_uint64_destroy(&del_hostids);
2266 }
2267 
2268 /******************************************************************************
2269  *                                                                            *
2270  * Function: lld_groups_remove                                                *
2271  *                                                                            *
2272  * Purpose: updates group_discovery.lastcheck and group_discovery.ts_delete   *
2273  *          fields; removes lost resources                                    *
2274  *                                                                            *
2275  ******************************************************************************/
lld_groups_remove(const zbx_vector_ptr_t * groups,unsigned short lifetime,int lastcheck)2276 static void	lld_groups_remove(const zbx_vector_ptr_t *groups, unsigned short lifetime, int lastcheck)
2277 {
2278 	char			*sql = NULL;
2279 	size_t			sql_alloc = 0, sql_offset = 0;
2280 	const zbx_lld_group_t	*group;
2281 	zbx_vector_uint64_t	del_groupids, lc_groupids, ts_groupids;
2282 	int			i, lifetime_sec;
2283 
2284 	if (0 == groups->values_num)
2285 		return;
2286 
2287 	lifetime_sec = lifetime * SEC_PER_DAY;
2288 
2289 	zbx_vector_uint64_create(&del_groupids);
2290 	zbx_vector_uint64_create(&lc_groupids);
2291 	zbx_vector_uint64_create(&ts_groupids);
2292 
2293 	DBbegin_multiple_update(&sql, &sql_alloc, &sql_offset);
2294 
2295 	for (i = 0; i < groups->values_num; i++)
2296 	{
2297 		group = (zbx_lld_group_t *)groups->values[i];
2298 
2299 		if (0 == group->groupid)
2300 			continue;
2301 
2302 		if (0 == (group->flags & ZBX_FLAG_LLD_GROUP_DISCOVERED))
2303 		{
2304 			if (group->lastcheck < lastcheck - lifetime_sec)
2305 			{
2306 				zbx_vector_uint64_append(&del_groupids, group->groupid);
2307 			}
2308 			else if (group->ts_delete != group->lastcheck + lifetime_sec)
2309 			{
2310 				zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
2311 						"update group_discovery"
2312 						" set ts_delete=%d"
2313 						" where groupid=" ZBX_FS_UI64 ";\n",
2314 						group->lastcheck + lifetime_sec, group->groupid);
2315 			}
2316 		}
2317 		else
2318 		{
2319 			zbx_vector_uint64_append(&lc_groupids, group->groupid);
2320 			if (0 != group->ts_delete)
2321 				zbx_vector_uint64_append(&ts_groupids, group->groupid);
2322 		}
2323 	}
2324 
2325 	if (0 != lc_groupids.values_num)
2326 	{
2327 		zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "update group_discovery set lastcheck=%d where",
2328 				lastcheck);
2329 		DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "groupid",
2330 				lc_groupids.values, lc_groupids.values_num);
2331 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, ";\n");
2332 	}
2333 
2334 	if (0 != ts_groupids.values_num)
2335 	{
2336 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "update group_discovery set ts_delete=0 where");
2337 		DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "groupid",
2338 				ts_groupids.values, ts_groupids.values_num);
2339 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, ";\n");
2340 	}
2341 
2342 	if (16 < sql_offset)	/* in ORACLE always present begin..end; */
2343 	{
2344 		DBend_multiple_update(&sql, &sql_alloc, &sql_offset);
2345 
2346 		DBbegin();
2347 
2348 		DBexecute("%s", sql);
2349 
2350 		DBcommit();
2351 	}
2352 
2353 	zbx_free(sql);
2354 
2355 	if (0 != del_groupids.values_num)
2356 	{
2357 		zbx_vector_uint64_sort(&del_groupids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
2358 
2359 		DBbegin();
2360 
2361 		DBdelete_groups(&del_groupids);
2362 
2363 		DBcommit();
2364 	}
2365 
2366 	zbx_vector_uint64_destroy(&ts_groupids);
2367 	zbx_vector_uint64_destroy(&lc_groupids);
2368 	zbx_vector_uint64_destroy(&del_groupids);
2369 }
2370 
2371 /******************************************************************************
2372  *                                                                            *
2373  * Function: lld_interfaces_get                                               *
2374  *                                                                            *
2375  * Purpose: retrieves list of interfaces from the lld rule's host             *
2376  *                                                                            *
2377  ******************************************************************************/
lld_interfaces_get(zbx_uint64_t lld_ruleid,zbx_vector_ptr_t * interfaces)2378 static void	lld_interfaces_get(zbx_uint64_t lld_ruleid, zbx_vector_ptr_t *interfaces)
2379 {
2380 	DB_RESULT		result;
2381 	DB_ROW			row;
2382 	zbx_lld_interface_t	*interface;
2383 
2384 	result = DBselect(
2385 			"select hi.interfaceid,hi.type,hi.main,hi.useip,hi.ip,hi.dns,hi.port,hi.bulk"
2386 			" from interface hi,items i"
2387 			" where hi.hostid=i.hostid"
2388 				" and i.itemid=" ZBX_FS_UI64,
2389 			lld_ruleid);
2390 
2391 	while (NULL != (row = DBfetch(result)))
2392 	{
2393 		interface = zbx_malloc(NULL, sizeof(zbx_lld_interface_t));
2394 
2395 		ZBX_STR2UINT64(interface->interfaceid, row[0]);
2396 		interface->type = (unsigned char)atoi(row[1]);
2397 		interface->main = (unsigned char)atoi(row[2]);
2398 		interface->useip = (unsigned char)atoi(row[3]);
2399 		interface->ip = zbx_strdup(NULL, row[4]);
2400 		interface->dns = zbx_strdup(NULL, row[5]);
2401 		interface->port = zbx_strdup(NULL, row[6]);
2402 		interface->bulk = (unsigned char)atoi(row[7]);
2403 
2404 		zbx_vector_ptr_append(interfaces, interface);
2405 	}
2406 	DBfree_result(result);
2407 
2408 	zbx_vector_ptr_sort(interfaces, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
2409 }
2410 
2411 /******************************************************************************
2412  *                                                                            *
2413  * Function: lld_interface_make                                               *
2414  *                                                                            *
2415  ******************************************************************************/
lld_interface_make(zbx_vector_ptr_t * interfaces,zbx_uint64_t parent_interfaceid,zbx_uint64_t interfaceid,unsigned char type,unsigned char main,unsigned char useip,const char * ip,const char * dns,const char * port,unsigned char bulk)2416 static void	lld_interface_make(zbx_vector_ptr_t *interfaces, zbx_uint64_t parent_interfaceid,
2417 		zbx_uint64_t interfaceid, unsigned char type, unsigned char main, unsigned char useip, const char *ip,
2418 		const char *dns, const char *port, unsigned char bulk)
2419 {
2420 	zbx_lld_interface_t	*interface = NULL;
2421 	int			i;
2422 
2423 	for (i = 0; i < interfaces->values_num; i++)
2424 	{
2425 		interface = (zbx_lld_interface_t *)interfaces->values[i];
2426 
2427 		if (0 != interface->interfaceid)
2428 			continue;
2429 
2430 		if (interface->parent_interfaceid == parent_interfaceid)
2431 			break;
2432 	}
2433 
2434 	if (i == interfaces->values_num)
2435 	{
2436 		/* interface which should be deleted */
2437 		interface = zbx_malloc(NULL, sizeof(zbx_lld_interface_t));
2438 
2439 		interface->interfaceid = interfaceid;
2440 		interface->parent_interfaceid = 0;
2441 		interface->type = type;
2442 		interface->main = main;
2443 		interface->useip = 0;
2444 		interface->ip = NULL;
2445 		interface->dns = NULL;
2446 		interface->port = NULL;
2447 		interface->bulk = SNMP_BULK_ENABLED;
2448 		interface->flags = ZBX_FLAG_LLD_INTERFACE_REMOVE;
2449 
2450 		zbx_vector_ptr_append(interfaces, interface);
2451 	}
2452 	else
2453 	{
2454 		/* interface which are already added */
2455 		if (interface->type != type)
2456 		{
2457 			interface->type_orig = type;
2458 			interface->flags |= ZBX_FLAG_LLD_INTERFACE_UPDATE_TYPE;
2459 		}
2460 		if (interface->main != main)
2461 		{
2462 			interface->main_orig = main;
2463 			interface->flags |= ZBX_FLAG_LLD_INTERFACE_UPDATE_MAIN;
2464 		}
2465 		if (interface->useip != useip)
2466 			interface->flags |= ZBX_FLAG_LLD_INTERFACE_UPDATE_USEIP;
2467 		if (0 != strcmp(interface->ip, ip))
2468 			interface->flags |= ZBX_FLAG_LLD_INTERFACE_UPDATE_IP;
2469 		if (0 != strcmp(interface->dns, dns))
2470 			interface->flags |= ZBX_FLAG_LLD_INTERFACE_UPDATE_DNS;
2471 		if (0 != strcmp(interface->port, port))
2472 			interface->flags |= ZBX_FLAG_LLD_INTERFACE_UPDATE_PORT;
2473 		if (interface->bulk != bulk)
2474 			interface->flags |= ZBX_FLAG_LLD_INTERFACE_UPDATE_BULK;
2475 	}
2476 
2477 	interface->interfaceid = interfaceid;
2478 }
2479 
2480 /******************************************************************************
2481  *                                                                            *
2482  * Function: lld_interfaces_make                                              *
2483  *                                                                            *
2484  * Parameters: interfaces - [IN] sorted list of interfaces which              *
2485  *                               should be present on the each                *
2486  *                               discovered host                              *
2487  *             hosts      - [IN/OUT] sorted list of hosts                     *
2488  *                                                                            *
2489  ******************************************************************************/
lld_interfaces_make(const zbx_vector_ptr_t * interfaces,zbx_vector_ptr_t * hosts)2490 static void	lld_interfaces_make(const zbx_vector_ptr_t *interfaces, zbx_vector_ptr_t *hosts)
2491 {
2492 	const char		*__function_name = "lld_interfaces_make";
2493 
2494 	DB_RESULT		result;
2495 	DB_ROW			row;
2496 	int			i, j;
2497 	zbx_vector_uint64_t	hostids;
2498 	zbx_uint64_t		parent_interfaceid, hostid, interfaceid;
2499 	zbx_lld_host_t		*host;
2500 	zbx_lld_interface_t	*new_interface, *interface;
2501 
2502 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
2503 
2504 	zbx_vector_uint64_create(&hostids);
2505 
2506 	for (i = 0; i < hosts->values_num; i++)
2507 	{
2508 		host = (zbx_lld_host_t *)hosts->values[i];
2509 
2510 		if (0 == (host->flags & ZBX_FLAG_LLD_HOST_DISCOVERED))
2511 			continue;
2512 
2513 		zbx_vector_ptr_reserve(&host->interfaces, interfaces->values_num);
2514 		for (j = 0; j < interfaces->values_num; j++)
2515 		{
2516 			interface = (zbx_lld_interface_t *)interfaces->values[j];
2517 
2518 			new_interface = zbx_malloc(NULL, sizeof(zbx_lld_interface_t));
2519 
2520 			new_interface->interfaceid = 0;
2521 			new_interface->parent_interfaceid = interface->interfaceid;
2522 			new_interface->type = interface->type;
2523 			new_interface->main = interface->main;
2524 			new_interface->useip = interface->useip;
2525 			new_interface->ip = zbx_strdup(NULL, interface->ip);
2526 			new_interface->dns = zbx_strdup(NULL, interface->dns);
2527 			new_interface->port = zbx_strdup(NULL, interface->port);
2528 			new_interface->bulk = interface->bulk;
2529 			new_interface->flags = 0x00;
2530 
2531 			zbx_vector_ptr_append(&host->interfaces, new_interface);
2532 		}
2533 
2534 		if (0 != host->hostid)
2535 			zbx_vector_uint64_append(&hostids, host->hostid);
2536 	}
2537 
2538 	if (0 != hostids.values_num)
2539 	{
2540 		char	*sql = NULL;
2541 		size_t	sql_alloc = 0, sql_offset = 0;
2542 
2543 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
2544 				"select hi.hostid,id.parent_interfaceid,hi.interfaceid,hi.type,hi.main,hi.useip,hi.ip,"
2545 					"hi.dns,hi.port,hi.bulk"
2546 				" from interface hi"
2547 					" left join interface_discovery id"
2548 						" on hi.interfaceid=id.interfaceid"
2549 				" where");
2550 		DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "hi.hostid", hostids.values, hostids.values_num);
2551 
2552 		result = DBselect("%s", sql);
2553 
2554 		zbx_free(sql);
2555 
2556 		while (NULL != (row = DBfetch(result)))
2557 		{
2558 			ZBX_STR2UINT64(hostid, row[0]);
2559 			ZBX_DBROW2UINT64(parent_interfaceid, row[1]);
2560 			ZBX_DBROW2UINT64(interfaceid, row[2]);
2561 
2562 			if (FAIL == (i = zbx_vector_ptr_bsearch(hosts, &hostid, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC)))
2563 			{
2564 				THIS_SHOULD_NEVER_HAPPEN;
2565 				continue;
2566 			}
2567 
2568 			host = (zbx_lld_host_t *)hosts->values[i];
2569 
2570 			lld_interface_make(&host->interfaces, parent_interfaceid, interfaceid,
2571 					(unsigned char)atoi(row[3]), (unsigned char)atoi(row[4]),
2572 					(unsigned char)atoi(row[5]), row[6], row[7], row[8],
2573 					(unsigned char)atoi(row[9]));
2574 		}
2575 		DBfree_result(result);
2576 	}
2577 
2578 	zbx_vector_uint64_destroy(&hostids);
2579 
2580 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
2581 }
2582 
2583 /******************************************************************************
2584  *                                                                            *
2585  * Function: another_main_interface_exists                                    *
2586  *                                                                            *
2587  * Return value: SUCCEED if interface with same type exists in the list of    *
2588  *               interfaces; FAIL - otherwise                                 *
2589  *                                                                            *
2590  * Comments: interfaces with ZBX_FLAG_LLD_INTERFACE_REMOVE flag are ignored   *
2591  *           auxiliary function for lld_interfaces_validate()                 *
2592  *                                                                            *
2593  ******************************************************************************/
another_main_interface_exists(const zbx_vector_ptr_t * interfaces,const zbx_lld_interface_t * interface)2594 static int	another_main_interface_exists(const zbx_vector_ptr_t *interfaces, const zbx_lld_interface_t *interface)
2595 {
2596 	const zbx_lld_interface_t	*interface_b;
2597 	int				i;
2598 
2599 	for (i = 0; i < interfaces->values_num; i++)
2600 	{
2601 		interface_b = (zbx_lld_interface_t *)interfaces->values[i];
2602 
2603 		if (interface_b == interface)
2604 			continue;
2605 
2606 		if (0 != (interface_b->flags & ZBX_FLAG_LLD_INTERFACE_REMOVE))
2607 			continue;
2608 
2609 		if (interface_b->type != interface->type)
2610 			continue;
2611 
2612 		if (1 == interface_b->main)
2613 			return SUCCEED;
2614 	}
2615 
2616 	return FAIL;
2617 }
2618 
2619 /******************************************************************************
2620  *                                                                            *
2621  * Function: lld_interfaces_validate                                          *
2622  *                                                                            *
2623  * Parameters: hosts - [IN/OUT] list of hosts                                 *
2624  *                                                                            *
2625  ******************************************************************************/
lld_interfaces_validate(zbx_vector_ptr_t * hosts,char ** error)2626 static void	lld_interfaces_validate(zbx_vector_ptr_t *hosts, char **error)
2627 {
2628 	const char		*__function_name = "lld_interfaces_validate";
2629 
2630 	DB_RESULT		result;
2631 	DB_ROW			row;
2632 	int			i, j;
2633 	zbx_vector_uint64_t	interfaceids;
2634 	zbx_uint64_t		interfaceid;
2635 	zbx_lld_host_t		*host;
2636 	zbx_lld_interface_t	*interface;
2637 	unsigned char		type;
2638 	char			*sql = NULL;
2639 	size_t			sql_alloc = 0, sql_offset = 0;
2640 
2641 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
2642 
2643 	/* validate changed types */
2644 
2645 	zbx_vector_uint64_create(&interfaceids);
2646 
2647 	for (i = 0; i < hosts->values_num; i++)
2648 	{
2649 		host = (zbx_lld_host_t *)hosts->values[i];
2650 
2651 		for (j = 0; j < host->interfaces.values_num; j++)
2652 		{
2653 			interface = (zbx_lld_interface_t *)host->interfaces.values[j];
2654 
2655 			if (0 == (interface->flags & ZBX_FLAG_LLD_INTERFACE_UPDATE_TYPE))
2656 				continue;
2657 
2658 			zbx_vector_uint64_append(&interfaceids, interface->interfaceid);
2659 		}
2660 	}
2661 
2662 	if (0 != interfaceids.values_num)
2663 	{
2664 		zbx_vector_uint64_sort(&interfaceids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
2665 
2666 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "select interfaceid,type from items where");
2667 		DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "interfaceid",
2668 				interfaceids.values, interfaceids.values_num);
2669 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, " group by interfaceid,type");
2670 
2671 		result = DBselect("%s", sql);
2672 
2673 		while (NULL != (row = DBfetch(result)))
2674 		{
2675 			type = get_interface_type_by_item_type((unsigned char)atoi(row[1]));
2676 
2677 			if (type != INTERFACE_TYPE_ANY && type != INTERFACE_TYPE_UNKNOWN)
2678 			{
2679 				ZBX_STR2UINT64(interfaceid, row[0]);
2680 
2681 				for (i = 0; i < hosts->values_num; i++)
2682 				{
2683 					host = (zbx_lld_host_t *)hosts->values[i];
2684 
2685 					for (j = 0; j < host->interfaces.values_num; j++)
2686 					{
2687 						interface = (zbx_lld_interface_t *)host->interfaces.values[j];
2688 
2689 						if (0 == (interface->flags & ZBX_FLAG_LLD_INTERFACE_UPDATE_TYPE))
2690 							continue;
2691 
2692 						if (interface->interfaceid != interfaceid)
2693 							continue;
2694 
2695 						*error = zbx_strdcatf(*error,
2696 								"Cannot update \"%s\" interface on host \"%s\":"
2697 								" the interface is used by items.\n",
2698 								zbx_interface_type_string(interface->type_orig),
2699 								host->host);
2700 
2701 						/* return an original interface type and drop the correspond flag */
2702 						interface->type = interface->type_orig;
2703 						interface->flags &= ~ZBX_FLAG_LLD_INTERFACE_UPDATE_TYPE;
2704 					}
2705 				}
2706 			}
2707 		}
2708 		DBfree_result(result);
2709 	}
2710 
2711 	/* validate interfaces which should be deleted */
2712 
2713 	zbx_vector_uint64_clear(&interfaceids);
2714 
2715 	for (i = 0; i < hosts->values_num; i++)
2716 	{
2717 		host = (zbx_lld_host_t *)hosts->values[i];
2718 
2719 		for (j = 0; j < host->interfaces.values_num; j++)
2720 		{
2721 			interface = (zbx_lld_interface_t *)host->interfaces.values[j];
2722 
2723 			if (0 == (interface->flags & ZBX_FLAG_LLD_INTERFACE_REMOVE))
2724 				continue;
2725 
2726 			zbx_vector_uint64_append(&interfaceids, interface->interfaceid);
2727 		}
2728 	}
2729 
2730 	if (0 != interfaceids.values_num)
2731 	{
2732 		zbx_vector_uint64_sort(&interfaceids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
2733 
2734 		sql_offset = 0;
2735 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "select interfaceid from items where");
2736 		DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "interfaceid",
2737 				interfaceids.values, interfaceids.values_num);
2738 		zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, " group by interfaceid");
2739 
2740 		result = DBselect("%s", sql);
2741 
2742 		while (NULL != (row = DBfetch(result)))
2743 		{
2744 			ZBX_STR2UINT64(interfaceid, row[0]);
2745 
2746 			for (i = 0; i < hosts->values_num; i++)
2747 			{
2748 				host = (zbx_lld_host_t *)hosts->values[i];
2749 
2750 				for (j = 0; j < host->interfaces.values_num; j++)
2751 				{
2752 					interface = (zbx_lld_interface_t *)host->interfaces.values[j];
2753 
2754 					if (0 == (interface->flags & ZBX_FLAG_LLD_INTERFACE_REMOVE))
2755 						continue;
2756 
2757 					if (interface->interfaceid != interfaceid)
2758 						continue;
2759 
2760 					*error = zbx_strdcatf(*error, "Cannot delete \"%s\" interface on host \"%s\":"
2761 							" the interface is used by items.\n",
2762 							zbx_interface_type_string(interface->type), host->host);
2763 
2764 					/* drop the correspond flag */
2765 					interface->flags &= ~ZBX_FLAG_LLD_INTERFACE_REMOVE;
2766 
2767 					if (SUCCEED == another_main_interface_exists(&host->interfaces, interface))
2768 					{
2769 						if (1 == interface->main)
2770 						{
2771 							/* drop main flag */
2772 							interface->main_orig = interface->main;
2773 							interface->main = 0;
2774 							interface->flags |= ZBX_FLAG_LLD_INTERFACE_UPDATE_MAIN;
2775 						}
2776 					}
2777 					else if (1 != interface->main)
2778 					{
2779 						/* set main flag */
2780 						interface->main_orig = interface->main;
2781 						interface->main = 1;
2782 						interface->flags |= ZBX_FLAG_LLD_INTERFACE_UPDATE_MAIN;
2783 					}
2784 				}
2785 			}
2786 		}
2787 		DBfree_result(result);
2788 	}
2789 
2790 	zbx_vector_uint64_destroy(&interfaceids);
2791 
2792 	zbx_free(sql);
2793 
2794 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
2795 }
2796 
2797 /******************************************************************************
2798  *                                                                            *
2799  * Function: lld_update_hosts                                                 *
2800  *                                                                            *
2801  * Purpose: add or update low-level discovered hosts                          *
2802  *                                                                            *
2803  ******************************************************************************/
lld_update_hosts(zbx_uint64_t lld_ruleid,const zbx_vector_ptr_t * lld_rows,char ** error,unsigned short lifetime,int lastcheck)2804 void	lld_update_hosts(zbx_uint64_t lld_ruleid, const zbx_vector_ptr_t *lld_rows, char **error,
2805 		unsigned short lifetime, int lastcheck)
2806 {
2807 	const char		*__function_name = "lld_update_hosts";
2808 
2809 	DB_RESULT		result;
2810 	DB_ROW			row;
2811 	zbx_vector_ptr_t	hosts, group_prototypes, groups, interfaces, hostmacros;
2812 	zbx_vector_uint64_t	groupids;		/* list of host groups which should be added */
2813 	zbx_vector_uint64_t	del_hostgroupids;	/* list of host groups which should be deleted */
2814 	zbx_vector_uint64_t	del_hostmacroids;	/* list of host macros which should be deleted */
2815 	zbx_uint64_t		proxy_hostid;
2816 	char			*ipmi_username = NULL, *ipmi_password, *tls_issuer, *tls_subject, *tls_psk_identity,
2817 				*tls_psk;
2818 	char			ipmi_authtype, inventory_mode;
2819 	unsigned char		ipmi_privilege, tls_connect, tls_accept;
2820 
2821 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
2822 
2823 	result = DBselect(
2824 			"select h.proxy_hostid,h.ipmi_authtype,h.ipmi_privilege,h.ipmi_username,h.ipmi_password,"
2825 				"h.tls_connect,h.tls_accept,h.tls_issuer,h.tls_subject,h.tls_psk_identity,h.tls_psk"
2826 			" from hosts h,items i"
2827 			" where h.hostid=i.hostid"
2828 				" and i.itemid=" ZBX_FS_UI64,
2829 			lld_ruleid);
2830 
2831 	if (NULL != (row = DBfetch(result)))
2832 	{
2833 		ZBX_DBROW2UINT64(proxy_hostid, row[0]);
2834 		ipmi_authtype = (char)atoi(row[1]);
2835 		ZBX_STR2UCHAR(ipmi_privilege, row[2]);
2836 		ipmi_username = zbx_strdup(NULL, row[3]);
2837 		ipmi_password = zbx_strdup(NULL, row[4]);
2838 
2839 		ZBX_STR2UCHAR(tls_connect, row[5]);
2840 		ZBX_STR2UCHAR(tls_accept, row[6]);
2841 		tls_issuer = zbx_strdup(NULL, row[7]);
2842 		tls_subject = zbx_strdup(NULL, row[8]);
2843 		tls_psk_identity = zbx_strdup(NULL, row[9]);
2844 		tls_psk = zbx_strdup(NULL, row[10]);
2845 	}
2846 	DBfree_result(result);
2847 
2848 	if (NULL == row)
2849 	{
2850 		*error = zbx_strdcatf(*error, "Cannot process host prototypes: a parent host not found.\n");
2851 		return;
2852 	}
2853 
2854 	zbx_vector_ptr_create(&hosts);
2855 	zbx_vector_uint64_create(&groupids);
2856 	zbx_vector_ptr_create(&group_prototypes);
2857 	zbx_vector_ptr_create(&groups);
2858 	zbx_vector_uint64_create(&del_hostgroupids);
2859 	zbx_vector_uint64_create(&del_hostmacroids);
2860 	zbx_vector_ptr_create(&interfaces);
2861 	zbx_vector_ptr_create(&hostmacros);
2862 
2863 	lld_interfaces_get(lld_ruleid, &interfaces);
2864 	lld_hostmacros_get(lld_ruleid, &hostmacros);
2865 
2866 	result = DBselect(
2867 			"select h.hostid,h.host,h.name,h.status,hi.inventory_mode"
2868 			" from hosts h,host_discovery hd"
2869 				" left join host_inventory hi"
2870 					" on hd.hostid=hi.hostid"
2871 			" where h.hostid=hd.hostid"
2872 				" and hd.parent_itemid=" ZBX_FS_UI64,
2873 			lld_ruleid);
2874 
2875 	while (NULL != (row = DBfetch(result)))
2876 	{
2877 		zbx_uint64_t	parent_hostid;
2878 		const char	*host_proto, *name_proto;
2879 		zbx_lld_host_t	*host;
2880 		unsigned char	status;
2881 		int		i;
2882 
2883 		ZBX_STR2UINT64(parent_hostid, row[0]);
2884 		host_proto = row[1];
2885 		name_proto = row[2];
2886 		status = (unsigned char)atoi(row[3]);
2887 		if (SUCCEED == DBis_null(row[4]))
2888 			inventory_mode = HOST_INVENTORY_DISABLED;
2889 		else
2890 			inventory_mode = (char)atoi(row[4]);
2891 
2892 		lld_hosts_get(parent_hostid, &hosts, proxy_hostid, ipmi_authtype, ipmi_privilege, ipmi_username,
2893 				ipmi_password, inventory_mode, tls_connect, tls_accept, tls_issuer, tls_subject,
2894 				tls_psk_identity, tls_psk);
2895 
2896 		lld_simple_groups_get(parent_hostid, &groupids);
2897 
2898 		lld_group_prototypes_get(parent_hostid, &group_prototypes);
2899 		lld_groups_get(parent_hostid, &groups);
2900 
2901 		for (i = 0; i < lld_rows->values_num; i++)
2902 		{
2903 			const zbx_lld_row_t	*lld_row = (zbx_lld_row_t *)lld_rows->values[i];
2904 
2905 			host = lld_host_make(&hosts, host_proto, name_proto, &lld_row->jp_row);
2906 			lld_groups_make(host, &groups, &group_prototypes, &lld_row->jp_row);
2907 		}
2908 
2909 		zbx_vector_ptr_sort(&hosts, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
2910 
2911 		lld_groups_validate(&groups, error);
2912 		lld_hosts_validate(&hosts, error);
2913 
2914 		lld_interfaces_make(&interfaces, &hosts);
2915 		lld_interfaces_validate(&hosts, error);
2916 
2917 		lld_hostgroups_make(&groupids, &hosts, &groups, &del_hostgroupids);
2918 		lld_templates_make(parent_hostid, &hosts);
2919 		lld_hostmacros_make(&hostmacros, &hosts, &del_hostmacroids);
2920 
2921 		lld_groups_save(&groups, &group_prototypes);
2922 		lld_hosts_save(parent_hostid, &hosts, host_proto, proxy_hostid, ipmi_authtype, ipmi_privilege,
2923 				ipmi_username, ipmi_password, status, inventory_mode, tls_connect, tls_accept,
2924 				tls_issuer, tls_subject, tls_psk_identity, tls_psk, &del_hostgroupids,
2925 				&del_hostmacroids);
2926 
2927 		/* linking of the templates */
2928 		lld_templates_link(&hosts, error);
2929 
2930 		lld_hosts_remove(&hosts, lifetime, lastcheck);
2931 		lld_groups_remove(&groups, lifetime, lastcheck);
2932 
2933 		zbx_vector_ptr_clear_ext(&groups, (zbx_clean_func_t)lld_group_free);
2934 		zbx_vector_ptr_clear_ext(&group_prototypes, (zbx_clean_func_t)lld_group_prototype_free);
2935 		zbx_vector_ptr_clear_ext(&hosts, (zbx_clean_func_t)lld_host_free);
2936 
2937 		zbx_vector_uint64_clear(&groupids);
2938 		zbx_vector_uint64_clear(&del_hostgroupids);
2939 		zbx_vector_uint64_clear(&del_hostmacroids);
2940 	}
2941 	DBfree_result(result);
2942 
2943 	zbx_vector_ptr_clear_ext(&hostmacros, (zbx_clean_func_t)lld_hostmacro_free);
2944 	zbx_vector_ptr_clear_ext(&interfaces, (zbx_clean_func_t)lld_interface_free);
2945 
2946 	zbx_vector_ptr_destroy(&hostmacros);
2947 	zbx_vector_ptr_destroy(&interfaces);
2948 	zbx_vector_uint64_destroy(&del_hostmacroids);
2949 	zbx_vector_uint64_destroy(&del_hostgroupids);
2950 	zbx_vector_ptr_destroy(&groups);
2951 	zbx_vector_ptr_destroy(&group_prototypes);
2952 	zbx_vector_uint64_destroy(&groupids);
2953 	zbx_vector_ptr_destroy(&hosts);
2954 
2955 	zbx_free(tls_psk);
2956 	zbx_free(tls_psk_identity);
2957 	zbx_free(tls_subject);
2958 	zbx_free(tls_issuer);
2959 	zbx_free(ipmi_password);
2960 	zbx_free(ipmi_username);
2961 
2962 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
2963 }
2964