Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/zabbix/zabbix.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/zabbix_server/lld/lld_host.c')
-rw-r--r--src/zabbix_server/lld/lld_host.c3211
1 files changed, 3211 insertions, 0 deletions
diff --git a/src/zabbix_server/lld/lld_host.c b/src/zabbix_server/lld/lld_host.c
new file mode 100644
index 00000000000..779d7f685ff
--- /dev/null
+++ b/src/zabbix_server/lld/lld_host.c
@@ -0,0 +1,3211 @@
+/*
+** Zabbix
+** Copyright (C) 2001-2019 Zabbix SIA
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+**/
+
+#include "lld.h"
+#include "db.h"
+#include "log.h"
+#include "zbxalgo.h"
+#include "zbxserver.h"
+
+typedef struct
+{
+ zbx_uint64_t hostmacroid;
+ char *macro;
+ char *value;
+}
+zbx_lld_hostmacro_t;
+
+static void lld_hostmacro_free(zbx_lld_hostmacro_t *hostmacro)
+{
+ zbx_free(hostmacro->macro);
+ zbx_free(hostmacro->value);
+ zbx_free(hostmacro);
+}
+
+typedef struct
+{
+ zbx_uint64_t interfaceid;
+ zbx_uint64_t parent_interfaceid;
+ char *ip;
+ char *dns;
+ char *port;
+ unsigned char main;
+ unsigned char main_orig;
+ unsigned char type;
+ unsigned char type_orig;
+ unsigned char useip;
+ unsigned char bulk;
+#define ZBX_FLAG_LLD_INTERFACE_UPDATE_TYPE __UINT64_C(0x00000001) /* interface.type field should be updated */
+#define ZBX_FLAG_LLD_INTERFACE_UPDATE_MAIN __UINT64_C(0x00000002) /* interface.main field should be updated */
+#define ZBX_FLAG_LLD_INTERFACE_UPDATE_USEIP __UINT64_C(0x00000004) /* interface.useip field should be updated */
+#define ZBX_FLAG_LLD_INTERFACE_UPDATE_IP __UINT64_C(0x00000008) /* interface.ip field should be updated */
+#define ZBX_FLAG_LLD_INTERFACE_UPDATE_DNS __UINT64_C(0x00000010) /* interface.dns field should be updated */
+#define ZBX_FLAG_LLD_INTERFACE_UPDATE_PORT __UINT64_C(0x00000020) /* interface.port field should be updated */
+#define ZBX_FLAG_LLD_INTERFACE_UPDATE_BULK __UINT64_C(0x00000040) /* interface.bulk field should be updated */
+#define ZBX_FLAG_LLD_INTERFACE_UPDATE \
+ (ZBX_FLAG_LLD_INTERFACE_UPDATE_TYPE | ZBX_FLAG_LLD_INTERFACE_UPDATE_MAIN | \
+ ZBX_FLAG_LLD_INTERFACE_UPDATE_USEIP | ZBX_FLAG_LLD_INTERFACE_UPDATE_IP | \
+ ZBX_FLAG_LLD_INTERFACE_UPDATE_DNS | ZBX_FLAG_LLD_INTERFACE_UPDATE_PORT | \
+ ZBX_FLAG_LLD_INTERFACE_UPDATE_BULK)
+#define ZBX_FLAG_LLD_INTERFACE_REMOVE __UINT64_C(0x00000080) /* interfaces which should be deleted */
+ zbx_uint64_t flags;
+}
+zbx_lld_interface_t;
+
+static void lld_interface_free(zbx_lld_interface_t *interface)
+{
+ zbx_free(interface->port);
+ zbx_free(interface->dns);
+ zbx_free(interface->ip);
+ zbx_free(interface);
+}
+
+typedef struct
+{
+ zbx_uint64_t hostid;
+ zbx_vector_uint64_t new_groupids; /* host groups which should be added */
+ zbx_vector_uint64_t lnk_templateids; /* templates which should be linked */
+ zbx_vector_uint64_t del_templateids; /* templates which should be unlinked */
+ zbx_vector_ptr_t new_hostmacros; /* host macros which should be added */
+ zbx_vector_ptr_t interfaces;
+ char *host_proto;
+ char *host;
+ char *host_orig;
+ char *name;
+ char *name_orig;
+ int lastcheck;
+ int ts_delete;
+
+#define ZBX_FLAG_LLD_HOST_DISCOVERED __UINT64_C(0x00000001) /* hosts which should be updated or added */
+#define ZBX_FLAG_LLD_HOST_UPDATE_HOST __UINT64_C(0x00000002) /* hosts.host and host_discovery.host fields should be updated */
+#define ZBX_FLAG_LLD_HOST_UPDATE_NAME __UINT64_C(0x00000004) /* hosts.name field should be updated */
+#define ZBX_FLAG_LLD_HOST_UPDATE_PROXY __UINT64_C(0x00000008) /* hosts.proxy_hostid field should be updated */
+#define ZBX_FLAG_LLD_HOST_UPDATE_IPMI_AUTH __UINT64_C(0x00000010) /* hosts.ipmi_authtype field should be updated */
+#define ZBX_FLAG_LLD_HOST_UPDATE_IPMI_PRIV __UINT64_C(0x00000020) /* hosts.ipmi_privilege field should be updated */
+#define ZBX_FLAG_LLD_HOST_UPDATE_IPMI_USER __UINT64_C(0x00000040) /* hosts.ipmi_username field should be updated */
+#define ZBX_FLAG_LLD_HOST_UPDATE_IPMI_PASS __UINT64_C(0x00000080) /* hosts.ipmi_password field should be updated */
+#define ZBX_FLAG_LLD_HOST_UPDATE_TLS_CONNECT __UINT64_C(0x00000100) /* hosts.tls_connect field should be updated */
+#define ZBX_FLAG_LLD_HOST_UPDATE_TLS_ACCEPT __UINT64_C(0x00000200) /* hosts.tls_accept field should be updated */
+#define ZBX_FLAG_LLD_HOST_UPDATE_TLS_ISSUER __UINT64_C(0x00000400) /* hosts.tls_issuer field should be updated */
+#define ZBX_FLAG_LLD_HOST_UPDATE_TLS_SUBJECT __UINT64_C(0x00000800) /* hosts.tls_subject field should be updated */
+#define ZBX_FLAG_LLD_HOST_UPDATE_TLS_PSK_IDENTITY __UINT64_C(0x00001000) /* hosts.tls_psk_identity field should be updated */
+#define ZBX_FLAG_LLD_HOST_UPDATE_TLS_PSK __UINT64_C(0x00002000) /* hosts.tls_psk field should be updated */
+
+#define ZBX_FLAG_LLD_HOST_UPDATE \
+ (ZBX_FLAG_LLD_HOST_UPDATE_HOST | ZBX_FLAG_LLD_HOST_UPDATE_NAME | \
+ ZBX_FLAG_LLD_HOST_UPDATE_PROXY | ZBX_FLAG_LLD_HOST_UPDATE_IPMI_AUTH | \
+ ZBX_FLAG_LLD_HOST_UPDATE_IPMI_PRIV | ZBX_FLAG_LLD_HOST_UPDATE_IPMI_USER | \
+ ZBX_FLAG_LLD_HOST_UPDATE_IPMI_PASS | ZBX_FLAG_LLD_HOST_UPDATE_TLS_CONNECT | \
+ ZBX_FLAG_LLD_HOST_UPDATE_TLS_ACCEPT | ZBX_FLAG_LLD_HOST_UPDATE_TLS_ISSUER | \
+ ZBX_FLAG_LLD_HOST_UPDATE_TLS_SUBJECT | ZBX_FLAG_LLD_HOST_UPDATE_TLS_PSK_IDENTITY | \
+ ZBX_FLAG_LLD_HOST_UPDATE_TLS_PSK)
+
+ zbx_uint64_t flags;
+ char inventory_mode;
+}
+zbx_lld_host_t;
+
+static void lld_host_free(zbx_lld_host_t *host)
+{
+ zbx_vector_uint64_destroy(&host->new_groupids);
+ zbx_vector_uint64_destroy(&host->lnk_templateids);
+ zbx_vector_uint64_destroy(&host->del_templateids);
+ zbx_vector_ptr_clear_ext(&host->new_hostmacros, (zbx_clean_func_t)lld_hostmacro_free);
+ zbx_vector_ptr_destroy(&host->new_hostmacros);
+ zbx_vector_ptr_clear_ext(&host->interfaces, (zbx_clean_func_t)lld_interface_free);
+ zbx_vector_ptr_destroy(&host->interfaces);
+ zbx_free(host->host_proto);
+ zbx_free(host->host);
+ zbx_free(host->host_orig);
+ zbx_free(host->name);
+ zbx_free(host->name_orig);
+ zbx_free(host);
+}
+
+typedef struct
+{
+ zbx_uint64_t group_prototypeid;
+ char *name;
+}
+zbx_lld_group_prototype_t;
+
+static void lld_group_prototype_free(zbx_lld_group_prototype_t *group_prototype)
+{
+ zbx_free(group_prototype->name);
+ zbx_free(group_prototype);
+}
+
+typedef struct
+{
+ zbx_uint64_t groupid;
+ zbx_uint64_t group_prototypeid;
+ zbx_vector_ptr_t hosts;
+ char *name_proto;
+ char *name;
+ char *name_orig;
+ int lastcheck;
+ int ts_delete;
+#define ZBX_FLAG_LLD_GROUP_DISCOVERED __UINT64_C(0x00000001) /* groups which should be updated or added */
+#define ZBX_FLAG_LLD_GROUP_UPDATE_NAME __UINT64_C(0x00000002) /* groups.name field should be updated */
+#define ZBX_FLAG_LLD_GROUP_UPDATE ZBX_FLAG_LLD_GROUP_UPDATE_NAME
+ zbx_uint64_t flags;
+}
+zbx_lld_group_t;
+
+static void lld_group_free(zbx_lld_group_t *group)
+{
+ /* zbx_vector_ptr_clear_ext(&group->hosts, (zbx_clean_func_t)lld_host_free); is not missing here */
+ zbx_vector_ptr_destroy(&group->hosts);
+ zbx_free(group->name_proto);
+ zbx_free(group->name);
+ zbx_free(group->name_orig);
+ zbx_free(group);
+}
+
+typedef struct
+{
+ char *name;
+ /* permission pair (usrgrpid, permission) */
+ zbx_vector_uint64_pair_t rights;
+ /* reference to the inherited rights */
+ zbx_vector_uint64_pair_t *prights;
+}
+zbx_lld_group_rights_t;
+
+/******************************************************************************
+ * *
+ * Function: lld_hosts_get *
+ * *
+ * Purpose: retrieves existing hosts for the specified host prototype *
+ * *
+ * Parameters: parent_hostid - [IN] host prototype identifier *
+ * hosts - [OUT] list of hosts *
+ * *
+ ******************************************************************************/
+static void 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,
+ 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 char *__function_name = "lld_hosts_get";
+
+ DB_RESULT result;
+ DB_ROW row;
+ zbx_lld_host_t *host;
+ zbx_uint64_t db_proxy_hostid;
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
+
+ result = DBselect(
+ "select hd.hostid,hd.host,hd.lastcheck,hd.ts_delete,h.host,h.name,h.proxy_hostid,"
+ "h.ipmi_authtype,h.ipmi_privilege,h.ipmi_username,h.ipmi_password,hi.inventory_mode,"
+ "h.tls_connect,h.tls_accept,h.tls_issuer,h.tls_subject,h.tls_psk_identity,h.tls_psk"
+ " from host_discovery hd"
+ " join hosts h"
+ " on hd.hostid=h.hostid"
+ " left join host_inventory hi"
+ " on hd.hostid=hi.hostid"
+ " where hd.parent_hostid=" ZBX_FS_UI64,
+ parent_hostid);
+
+ while (NULL != (row = DBfetch(result)))
+ {
+ host = (zbx_lld_host_t *)zbx_malloc(NULL, sizeof(zbx_lld_host_t));
+
+ ZBX_STR2UINT64(host->hostid, row[0]);
+ host->host_proto = zbx_strdup(NULL, row[1]);
+ host->lastcheck = atoi(row[2]);
+ host->ts_delete = atoi(row[3]);
+ host->host = zbx_strdup(NULL, row[4]);
+ host->host_orig = NULL;
+ host->name = zbx_strdup(NULL, row[5]);
+ host->name_orig = NULL;
+ host->flags = 0x00;
+
+ ZBX_DBROW2UINT64(db_proxy_hostid, row[6]);
+ if (db_proxy_hostid != proxy_hostid)
+ host->flags |= ZBX_FLAG_LLD_HOST_UPDATE_PROXY;
+
+ if ((char)atoi(row[7]) != ipmi_authtype)
+ host->flags |= ZBX_FLAG_LLD_HOST_UPDATE_IPMI_AUTH;
+
+ if ((unsigned char)atoi(row[8]) != ipmi_privilege)
+ host->flags |= ZBX_FLAG_LLD_HOST_UPDATE_IPMI_PRIV;
+
+ if (0 != strcmp(row[9], ipmi_username))
+ host->flags |= ZBX_FLAG_LLD_HOST_UPDATE_IPMI_USER;
+
+ if (0 != strcmp(row[10], ipmi_password))
+ host->flags |= ZBX_FLAG_LLD_HOST_UPDATE_IPMI_PASS;
+
+ if (atoi(row[12]) != tls_connect)
+ host->flags |= ZBX_FLAG_LLD_HOST_UPDATE_TLS_CONNECT;
+
+ if (atoi(row[13]) != tls_accept)
+ host->flags |= ZBX_FLAG_LLD_HOST_UPDATE_TLS_ACCEPT;
+
+ if (0 != strcmp(tls_issuer, row[14]))
+ host->flags |= ZBX_FLAG_LLD_HOST_UPDATE_TLS_ISSUER;
+
+ if (0 != strcmp(tls_subject, row[15]))
+ host->flags |= ZBX_FLAG_LLD_HOST_UPDATE_TLS_SUBJECT;
+
+ if (0 != strcmp(tls_psk_identity, row[16]))
+ host->flags |= ZBX_FLAG_LLD_HOST_UPDATE_TLS_PSK_IDENTITY;
+
+ if (0 != strcmp(tls_psk, row[17]))
+ host->flags |= ZBX_FLAG_LLD_HOST_UPDATE_TLS_PSK;
+
+ if (SUCCEED == DBis_null(row[11]))
+ host->inventory_mode = HOST_INVENTORY_DISABLED;
+ else
+ host->inventory_mode = (char)atoi(row[11]);
+
+ zbx_vector_uint64_create(&host->new_groupids);
+ zbx_vector_uint64_create(&host->lnk_templateids);
+ zbx_vector_uint64_create(&host->del_templateids);
+ zbx_vector_ptr_create(&host->new_hostmacros);
+ zbx_vector_ptr_create(&host->interfaces);
+
+ zbx_vector_ptr_append(hosts, host);
+ }
+ DBfree_result(result);
+
+ zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
+}
+
+/******************************************************************************
+ * *
+ * Function: lld_hosts_validate *
+ * *
+ * Parameters: hosts - [IN] list of hosts; should be sorted by hostid *
+ * *
+ ******************************************************************************/
+static void lld_hosts_validate(zbx_vector_ptr_t *hosts, char **error)
+{
+ const char *__function_name = "lld_hosts_validate";
+
+ DB_RESULT result;
+ DB_ROW row;
+ int i, j;
+ zbx_lld_host_t *host, *host_b;
+ zbx_vector_uint64_t hostids;
+ zbx_vector_str_t tnames, vnames;
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
+
+ zbx_vector_uint64_create(&hostids);
+ zbx_vector_str_create(&tnames); /* list of technical host names */
+ zbx_vector_str_create(&vnames); /* list of visible host names */
+
+ /* checking a host name validity */
+ for (i = 0; i < hosts->values_num; i++)
+ {
+ char *ch_error;
+
+ host = (zbx_lld_host_t *)hosts->values[i];
+
+ if (0 == (host->flags & ZBX_FLAG_LLD_HOST_DISCOVERED))
+ continue;
+
+ /* only new hosts or hosts with changed host name will be validated */
+ if (0 != host->hostid && 0 == (host->flags & ZBX_FLAG_LLD_HOST_UPDATE_HOST))
+ continue;
+
+ /* host name is valid? */
+ if (SUCCEED == zbx_check_hostname(host->host, &ch_error))
+ continue;
+
+ *error = zbx_strdcatf(*error, "Cannot %s host \"%s\": %s.\n",
+ (0 != host->hostid ? "update" : "create"), host->host, ch_error);
+
+ zbx_free(ch_error);
+
+ if (0 != host->hostid)
+ {
+ lld_field_str_rollback(&host->host, &host->host_orig, &host->flags,
+ ZBX_FLAG_LLD_HOST_UPDATE_HOST);
+ }
+ else
+ host->flags &= ~ZBX_FLAG_LLD_HOST_DISCOVERED;
+ }
+
+ /* checking a visible host name validity */
+ for (i = 0; i < hosts->values_num; i++)
+ {
+ host = (zbx_lld_host_t *)hosts->values[i];
+
+ if (0 == (host->flags & ZBX_FLAG_LLD_HOST_DISCOVERED))
+ continue;
+
+ /* only new hosts or hosts with changed visible name will be validated */
+ if (0 != host->hostid && 0 == (host->flags & ZBX_FLAG_LLD_HOST_UPDATE_NAME))
+ continue;
+
+ /* visible host name is valid utf8 sequence and has a valid length */
+ if (SUCCEED == zbx_is_utf8(host->name) && '\0' != *host->name &&
+ HOST_NAME_LEN >= zbx_strlen_utf8(host->name))
+ {
+ continue;
+ }
+
+ zbx_replace_invalid_utf8(host->name);
+ *error = zbx_strdcatf(*error, "Cannot %s host: invalid visible host name \"%s\".\n",
+ (0 != host->hostid ? "update" : "create"), host->name);
+
+ if (0 != host->hostid)
+ {
+ lld_field_str_rollback(&host->name, &host->name_orig, &host->flags,
+ ZBX_FLAG_LLD_HOST_UPDATE_NAME);
+ }
+ else
+ host->flags &= ~ZBX_FLAG_LLD_HOST_DISCOVERED;
+ }
+
+ /* checking duplicated host names */
+ for (i = 0; i < hosts->values_num; i++)
+ {
+ host = (zbx_lld_host_t *)hosts->values[i];
+
+ if (0 == (host->flags & ZBX_FLAG_LLD_HOST_DISCOVERED))
+ continue;
+
+ /* only new hosts or hosts with changed host name will be validated */
+ if (0 != host->hostid && 0 == (host->flags & ZBX_FLAG_LLD_HOST_UPDATE_HOST))
+ continue;
+
+ for (j = 0; j < hosts->values_num; j++)
+ {
+ host_b = (zbx_lld_host_t *)hosts->values[j];
+
+ if (0 == (host_b->flags & ZBX_FLAG_LLD_HOST_DISCOVERED) || i == j)
+ continue;
+
+ if (0 != strcmp(host->host, host_b->host))
+ continue;
+
+ *error = zbx_strdcatf(*error, "Cannot %s host:"
+ " host with the same name \"%s\" already exists.\n",
+ (0 != host->hostid ? "update" : "create"), host->host);
+
+ if (0 != host->hostid)
+ {
+ lld_field_str_rollback(&host->host, &host->host_orig, &host->flags,
+ ZBX_FLAG_LLD_HOST_UPDATE_HOST);
+ }
+ else
+ host->flags &= ~ZBX_FLAG_LLD_HOST_DISCOVERED;
+ }
+ }
+
+ /* checking duplicated visible host names */
+ for (i = 0; i < hosts->values_num; i++)
+ {
+ host = (zbx_lld_host_t *)hosts->values[i];
+
+ if (0 == (host->flags & ZBX_FLAG_LLD_HOST_DISCOVERED))
+ continue;
+
+ /* only new hosts or hosts with changed visible name will be validated */
+ if (0 != host->hostid && 0 == (host->flags & ZBX_FLAG_LLD_HOST_UPDATE_NAME))
+ continue;
+
+ for (j = 0; j < hosts->values_num; j++)
+ {
+ host_b = (zbx_lld_host_t *)hosts->values[j];
+
+ if (0 == (host_b->flags & ZBX_FLAG_LLD_HOST_DISCOVERED) || i == j)
+ continue;
+
+ if (0 != strcmp(host->name, host_b->name))
+ continue;
+
+ *error = zbx_strdcatf(*error, "Cannot %s host:"
+ " host with the same visible name \"%s\" already exists.\n",
+ (0 != host->hostid ? "update" : "create"), host->name);
+
+ if (0 != host->hostid)
+ {
+ lld_field_str_rollback(&host->name, &host->name_orig, &host->flags,
+ ZBX_FLAG_LLD_HOST_UPDATE_NAME);
+ }
+ else
+ host->flags &= ~ZBX_FLAG_LLD_HOST_DISCOVERED;
+ }
+ }
+
+ /* checking duplicated host names and visible host names in DB */
+
+ for (i = 0; i < hosts->values_num; i++)
+ {
+ host = (zbx_lld_host_t *)hosts->values[i];
+
+ if (0 == (host->flags & ZBX_FLAG_LLD_HOST_DISCOVERED))
+ continue;
+
+ if (0 != host->hostid)
+ zbx_vector_uint64_append(&hostids, host->hostid);
+
+ if (0 == host->hostid || 0 != (host->flags & ZBX_FLAG_LLD_HOST_UPDATE_HOST))
+ zbx_vector_str_append(&tnames, host->host);
+
+ if (0 == host->hostid || 0 != (host->flags & ZBX_FLAG_LLD_HOST_UPDATE_NAME))
+ zbx_vector_str_append(&vnames, host->name);
+ }
+
+ if (0 != tnames.values_num || 0 != vnames.values_num)
+ {
+ char *sql = NULL;
+ size_t sql_alloc = 0, sql_offset = 0;
+
+ zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
+ "select host,name"
+ " from hosts"
+ " where status in (%d,%d,%d)"
+ " and flags<>%d"
+ " and",
+ HOST_STATUS_MONITORED, HOST_STATUS_NOT_MONITORED, HOST_STATUS_TEMPLATE,
+ ZBX_FLAG_DISCOVERY_PROTOTYPE);
+
+ if (0 != tnames.values_num && 0 != vnames.values_num)
+ zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, " (");
+
+ if (0 != tnames.values_num)
+ {
+ DBadd_str_condition_alloc(&sql, &sql_alloc, &sql_offset, "host",
+ (const char **)tnames.values, tnames.values_num);
+ }
+
+ if (0 != tnames.values_num && 0 != vnames.values_num)
+ zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, " or");
+
+ if (0 != vnames.values_num)
+ {
+ DBadd_str_condition_alloc(&sql, &sql_alloc, &sql_offset, "name",
+ (const char **)vnames.values, vnames.values_num);
+ }
+
+ if (0 != tnames.values_num && 0 != vnames.values_num)
+ zbx_chrcpy_alloc(&sql, &sql_alloc, &sql_offset, ')');
+
+ if (0 != hostids.values_num)
+ {
+ zbx_vector_uint64_sort(&hostids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
+ zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, " and not");
+ DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "hostid",
+ hostids.values, hostids.values_num);
+ }
+
+ result = DBselect("%s", sql);
+
+ while (NULL != (row = DBfetch(result)))
+ {
+ for (i = 0; i < hosts->values_num; i++)
+ {
+ host = (zbx_lld_host_t *)hosts->values[i];
+
+ if (0 == (host->flags & ZBX_FLAG_LLD_HOST_DISCOVERED))
+ continue;
+
+ if (0 == strcmp(host->host, row[0]))
+ {
+ *error = zbx_strdcatf(*error, "Cannot %s host:"
+ " host with the same name \"%s\" already exists.\n",
+ (0 != host->hostid ? "update" : "create"), host->host);
+
+ if (0 != host->hostid)
+ {
+ lld_field_str_rollback(&host->host, &host->host_orig, &host->flags,
+ ZBX_FLAG_LLD_HOST_UPDATE_HOST);
+ }
+ else
+ host->flags &= ~ZBX_FLAG_LLD_HOST_DISCOVERED;
+ }
+
+ if (0 == strcmp(host->name, row[1]))
+ {
+ *error = zbx_strdcatf(*error, "Cannot %s host:"
+ " host with the same visible name \"%s\" already exists.\n",
+ (0 != host->hostid ? "update" : "create"), host->name);
+
+ if (0 != host->hostid)
+ {
+ lld_field_str_rollback(&host->name, &host->name_orig, &host->flags,
+ ZBX_FLAG_LLD_HOST_UPDATE_NAME);
+ }
+ else
+ host->flags &= ~ZBX_FLAG_LLD_HOST_DISCOVERED;
+ }
+ }
+ }
+ DBfree_result(result);
+
+ zbx_free(sql);
+ }
+
+ zbx_vector_str_destroy(&vnames);
+ zbx_vector_str_destroy(&tnames);
+ zbx_vector_uint64_destroy(&hostids);
+
+ zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
+}
+
+static zbx_lld_host_t *lld_host_make(zbx_vector_ptr_t *hosts, const char *host_proto, const char *name_proto,
+ const struct zbx_json_parse *jp_row, const zbx_vector_ptr_t *lld_macros)
+{
+ const char *__function_name = "lld_host_make";
+
+ char *buffer = NULL;
+ int i;
+ zbx_lld_host_t *host = NULL;
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
+
+ for (i = 0; i < hosts->values_num; i++)
+ {
+ host = (zbx_lld_host_t *)hosts->values[i];
+
+ if (0 != (host->flags & ZBX_FLAG_LLD_HOST_DISCOVERED))
+ continue;
+
+ buffer = zbx_strdup(buffer, host->host_proto);
+ substitute_lld_macros(&buffer, jp_row, lld_macros, ZBX_MACRO_ANY, NULL, 0);
+ zbx_lrtrim(buffer, ZBX_WHITESPACE);
+
+ if (0 == strcmp(host->host, buffer))
+ break;
+ }
+
+ if (i == hosts->values_num) /* no host found */
+ {
+ host = (zbx_lld_host_t *)zbx_malloc(NULL, sizeof(zbx_lld_host_t));
+
+ host->hostid = 0;
+ host->host_proto = NULL;
+ host->lastcheck = 0;
+ host->ts_delete = 0;
+ host->host = zbx_strdup(NULL, host_proto);
+ host->host_orig = NULL;
+ substitute_lld_macros(&host->host, jp_row, lld_macros, ZBX_MACRO_ANY, NULL, 0);
+ zbx_lrtrim(host->host, ZBX_WHITESPACE);
+ host->name = zbx_strdup(NULL, name_proto);
+ substitute_lld_macros(&host->name, jp_row, lld_macros, ZBX_MACRO_ANY, NULL, 0);
+ zbx_lrtrim(host->name, ZBX_WHITESPACE);
+ host->name_orig = NULL;
+ zbx_vector_uint64_create(&host->new_groupids);
+ zbx_vector_uint64_create(&host->lnk_templateids);
+ zbx_vector_uint64_create(&host->del_templateids);
+ zbx_vector_ptr_create(&host->new_hostmacros);
+ zbx_vector_ptr_create(&host->interfaces);
+ host->flags = ZBX_FLAG_LLD_HOST_DISCOVERED;
+
+ zbx_vector_ptr_append(hosts, host);
+ }
+ else
+ {
+ /* host technical name */
+ if (0 != strcmp(host->host_proto, host_proto)) /* the new host prototype differs */
+ {
+ host->host_orig = host->host;
+ host->host = zbx_strdup(NULL, host_proto);
+ substitute_lld_macros(&host->host, jp_row, lld_macros, ZBX_MACRO_ANY, NULL, 0);
+ zbx_lrtrim(host->host, ZBX_WHITESPACE);
+ host->flags |= ZBX_FLAG_LLD_HOST_UPDATE_HOST;
+ }
+
+ /* host visible name */
+ buffer = zbx_strdup(buffer, name_proto);
+ substitute_lld_macros(&buffer, jp_row, lld_macros, ZBX_MACRO_ANY, NULL, 0);
+ zbx_lrtrim(buffer, ZBX_WHITESPACE);
+ if (0 != strcmp(host->name, buffer))
+ {
+ host->name_orig = host->name;
+ host->name = buffer;
+ buffer = NULL;
+ host->flags |= ZBX_FLAG_LLD_HOST_UPDATE_NAME;
+ }
+
+ host->flags |= ZBX_FLAG_LLD_HOST_DISCOVERED;
+ }
+
+ zbx_free(buffer);
+
+ zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%p", __function_name, (void *)host);
+
+ return host;
+}
+
+/******************************************************************************
+ * *
+ * Function: lld_simple_groups_get *
+ * *
+ * Purpose: retrieve list of host groups which should be present on the each *
+ * discovered host *
+ * *
+ * Parameters: parent_hostid - [IN] host prototype identifier *
+ * groupids - [OUT] sorted list of host groups *
+ * *
+ ******************************************************************************/
+static void lld_simple_groups_get(zbx_uint64_t parent_hostid, zbx_vector_uint64_t *groupids)
+{
+ DB_RESULT result;
+ DB_ROW row;
+ zbx_uint64_t groupid;
+
+ result = DBselect(
+ "select groupid"
+ " from group_prototype"
+ " where groupid is not null"
+ " and hostid=" ZBX_FS_UI64,
+ parent_hostid);
+
+ while (NULL != (row = DBfetch(result)))
+ {
+ ZBX_STR2UINT64(groupid, row[0]);
+ zbx_vector_uint64_append(groupids, groupid);
+ }
+ DBfree_result(result);
+
+ zbx_vector_uint64_sort(groupids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
+}
+
+/******************************************************************************
+ * *
+ * Function: lld_hostgroups_make *
+ * *
+ * Parameters: groupids - [IN] sorted list of host group ids which *
+ * should be present on the each *
+ * discovered host (Groups) *
+ * hosts - [IN/OUT] list of hosts *
+ * should be sorted by hostid *
+ * groups - [IN] list of host groups (Group prototypes)*
+ * del_hostgroupids - [OUT] sorted list of host groups which *
+ * should be deleted *
+ * *
+ ******************************************************************************/
+static void 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)
+{
+ const char *__function_name = "lld_hostgroups_make";
+
+ DB_RESULT result;
+ DB_ROW row;
+ int i, j;
+ zbx_vector_uint64_t hostids;
+ zbx_uint64_t hostgroupid, hostid, groupid;
+ zbx_lld_host_t *host;
+ const zbx_lld_group_t *group;
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
+
+ zbx_vector_uint64_create(&hostids);
+
+ for (i = 0; i < hosts->values_num; i++)
+ {
+ host = (zbx_lld_host_t *)hosts->values[i];
+
+ if (0 == (host->flags & ZBX_FLAG_LLD_HOST_DISCOVERED))
+ continue;
+
+ zbx_vector_uint64_reserve(&host->new_groupids, groupids->values_num);
+ for (j = 0; j < groupids->values_num; j++)
+ zbx_vector_uint64_append(&host->new_groupids, groupids->values[j]);
+
+ if (0 != host->hostid)
+ zbx_vector_uint64_append(&hostids, host->hostid);
+ }
+
+ for (i = 0; i < groups->values_num; i++)
+ {
+ group = (zbx_lld_group_t *)groups->values[i];
+
+ if (0 == (group->flags & ZBX_FLAG_LLD_GROUP_DISCOVERED) || 0 == group->groupid)
+ continue;
+
+ for (j = 0; j < group->hosts.values_num; j++)
+ {
+ host = (zbx_lld_host_t *)group->hosts.values[j];
+
+ zbx_vector_uint64_append(&host->new_groupids, group->groupid);
+ }
+ }
+
+ for (i = 0; i < hosts->values_num; i++)
+ {
+ host = (zbx_lld_host_t *)hosts->values[i];
+ zbx_vector_uint64_sort(&host->new_groupids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
+ }
+
+ if (0 != hostids.values_num)
+ {
+ char *sql = NULL;
+ size_t sql_alloc = 0, sql_offset = 0;
+
+ zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
+ "select hostid,groupid,hostgroupid"
+ " from hosts_groups"
+ " where");
+ DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "hostid", hostids.values, hostids.values_num);
+
+ result = DBselect("%s", sql);
+
+ zbx_free(sql);
+
+ while (NULL != (row = DBfetch(result)))
+ {
+ ZBX_STR2UINT64(hostid, row[0]);
+ ZBX_STR2UINT64(groupid, row[1]);
+
+ if (FAIL == (i = zbx_vector_ptr_bsearch(hosts, &hostid, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC)))
+ {
+ THIS_SHOULD_NEVER_HAPPEN;
+ continue;
+ }
+
+ host = (zbx_lld_host_t *)hosts->values[i];
+
+ if (FAIL == (i = zbx_vector_uint64_bsearch(&host->new_groupids, groupid,
+ ZBX_DEFAULT_UINT64_COMPARE_FUNC)))
+ {
+ /* host groups which should be unlinked */
+ ZBX_STR2UINT64(hostgroupid, row[2]);
+ zbx_vector_uint64_append(del_hostgroupids, hostgroupid);
+ }
+ else
+ {
+ /* host groups which are already added */
+ zbx_vector_uint64_remove(&host->new_groupids, i);
+ }
+ }
+ DBfree_result(result);
+
+ zbx_vector_uint64_sort(del_hostgroupids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
+ }
+
+ zbx_vector_uint64_destroy(&hostids);
+
+ zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
+}
+
+/******************************************************************************
+ * *
+ * Function: lld_group_prototypes_get *
+ * *
+ * Purpose: retrieve list of group prototypes *
+ * *
+ * Parameters: parent_hostid - [IN] host prototype identifier *
+ * group_prototypes - [OUT] sorted list of group prototypes *
+ * *
+ ******************************************************************************/
+static void lld_group_prototypes_get(zbx_uint64_t parent_hostid, zbx_vector_ptr_t *group_prototypes)
+{
+ const char *__function_name = "lld_group_prototypes_get";
+
+ DB_RESULT result;
+ DB_ROW row;
+ zbx_lld_group_prototype_t *group_prototype;
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
+
+ result = DBselect(
+ "select group_prototypeid,name"
+ " from group_prototype"
+ " where groupid is null"
+ " and hostid=" ZBX_FS_UI64,
+ parent_hostid);
+
+ while (NULL != (row = DBfetch(result)))
+ {
+ group_prototype = (zbx_lld_group_prototype_t *)zbx_malloc(NULL, sizeof(zbx_lld_group_prototype_t));
+
+ ZBX_STR2UINT64(group_prototype->group_prototypeid, row[0]);
+ group_prototype->name = zbx_strdup(NULL, row[1]);
+
+ zbx_vector_ptr_append(group_prototypes, group_prototype);
+ }
+ DBfree_result(result);
+
+ zbx_vector_ptr_sort(group_prototypes, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
+
+ zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
+}
+
+/******************************************************************************
+ * *
+ * Function: lld_groups_get *
+ * *
+ * Purpose: retrieves existing groups for the specified host prototype *
+ * *
+ * Parameters: parent_hostid - [IN] host prototype identifier *
+ * groups - [OUT] list of groups *
+ * *
+ ******************************************************************************/
+static void lld_groups_get(zbx_uint64_t parent_hostid, zbx_vector_ptr_t *groups)
+{
+ const char *__function_name = "lld_groups_get";
+
+ DB_RESULT result;
+ DB_ROW row;
+ zbx_lld_group_t *group;
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
+
+ result = DBselect(
+ "select gd.groupid,gp.group_prototypeid,gd.name,gd.lastcheck,gd.ts_delete,g.name"
+ " from group_prototype gp,group_discovery gd"
+ " join hstgrp g"
+ " on gd.groupid=g.groupid"
+ " where gp.group_prototypeid=gd.parent_group_prototypeid"
+ " and gp.hostid=" ZBX_FS_UI64,
+ parent_hostid);
+
+ while (NULL != (row = DBfetch(result)))
+ {
+ group = (zbx_lld_group_t *)zbx_malloc(NULL, sizeof(zbx_lld_group_t));
+
+ ZBX_STR2UINT64(group->groupid, row[0]);
+ ZBX_STR2UINT64(group->group_prototypeid, row[1]);
+ zbx_vector_ptr_create(&group->hosts);
+ group->name_proto = zbx_strdup(NULL, row[2]);
+ group->lastcheck = atoi(row[3]);
+ group->ts_delete = atoi(row[4]);
+ group->name = zbx_strdup(NULL, row[5]);
+ group->name_orig = NULL;
+ group->flags = 0x00;
+
+ zbx_vector_ptr_append(groups, group);
+ }
+ DBfree_result(result);
+
+ zbx_vector_ptr_sort(groups, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
+
+ zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
+}
+
+/******************************************************************************
+ * *
+ * Function: lld_group_make *
+ * *
+ ******************************************************************************/
+static zbx_lld_group_t *lld_group_make(zbx_vector_ptr_t *groups, zbx_uint64_t group_prototypeid,
+ const char *name_proto, const struct zbx_json_parse *jp_row, const zbx_vector_ptr_t *lld_macros)
+{
+ const char *__function_name = "lld_group_make";
+
+ char *buffer = NULL;
+ int i;
+ zbx_lld_group_t *group = NULL;
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
+
+ for (i = 0; i < groups->values_num; i++)
+ {
+ group = (zbx_lld_group_t *)groups->values[i];
+
+ if (group->group_prototypeid != group_prototypeid)
+ continue;
+
+ if (0 != (group->flags & ZBX_FLAG_LLD_GROUP_DISCOVERED))
+ continue;
+
+ buffer = zbx_strdup(buffer, group->name_proto);
+ substitute_lld_macros(&buffer, jp_row, lld_macros, ZBX_MACRO_ANY, NULL, 0);
+ zbx_lrtrim(buffer, ZBX_WHITESPACE);
+
+ if (0 == strcmp(group->name, buffer))
+ break;
+ }
+
+ if (i == groups->values_num) /* no group found */
+ {
+ /* trying to find an already existing group */
+
+ buffer = zbx_strdup(buffer, name_proto);
+ substitute_lld_macros(&buffer, jp_row, lld_macros, ZBX_MACRO_ANY, NULL, 0);
+ zbx_lrtrim(buffer, ZBX_WHITESPACE);
+
+ for (i = 0; i < groups->values_num; i++)
+ {
+ group = (zbx_lld_group_t *)groups->values[i];
+
+ if (group->group_prototypeid != group_prototypeid)
+ continue;
+
+ if (0 == (group->flags & ZBX_FLAG_LLD_GROUP_DISCOVERED))
+ continue;
+
+ if (0 == strcmp(group->name, buffer))
+ goto out;
+ }
+
+ /* otherwise create a new group */
+
+ group = (zbx_lld_group_t *)zbx_malloc(NULL, sizeof(zbx_lld_group_t));
+
+ group->groupid = 0;
+ group->group_prototypeid = group_prototypeid;
+ zbx_vector_ptr_create(&group->hosts);
+ group->name_proto = NULL;
+ group->name = zbx_strdup(NULL, name_proto);
+ substitute_lld_macros(&group->name, jp_row, lld_macros, ZBX_MACRO_ANY, NULL, 0);
+ zbx_lrtrim(group->name, ZBX_WHITESPACE);
+ group->name_orig = NULL;
+ group->lastcheck = 0;
+ group->ts_delete = 0;
+ group->flags = 0x00;
+ group->flags = ZBX_FLAG_LLD_GROUP_DISCOVERED;
+
+ zbx_vector_ptr_append(groups, group);
+ }
+ else
+ {
+ /* update an already existing group */
+
+ /* group name */
+ buffer = zbx_strdup(buffer, name_proto);
+ substitute_lld_macros(&buffer, jp_row, lld_macros, ZBX_MACRO_ANY, NULL, 0);
+ zbx_lrtrim(buffer, ZBX_WHITESPACE);
+ if (0 != strcmp(group->name, buffer))
+ {
+ group->name_orig = group->name;
+ group->name = buffer;
+ buffer = NULL;
+ group->flags |= ZBX_FLAG_LLD_GROUP_UPDATE_NAME;
+ }
+
+ group->flags |= ZBX_FLAG_LLD_GROUP_DISCOVERED;
+ }
+out:
+ zbx_free(buffer);
+
+ zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%p", __function_name, (void *)group);
+
+ return group;
+}
+
+/******************************************************************************
+ * *
+ * Function: lld_groups_make *
+ * *
+ ******************************************************************************/
+static void 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, const zbx_vector_ptr_t *lld_macros)
+{
+ const char *__function_name = "lld_groups_make";
+
+ int i;
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
+
+ for (i = 0; i < group_prototypes->values_num; i++)
+ {
+ const zbx_lld_group_prototype_t *group_prototype;
+ zbx_lld_group_t *group;
+
+ group_prototype = (zbx_lld_group_prototype_t *)group_prototypes->values[i];
+
+ group = lld_group_make(groups, group_prototype->group_prototypeid, group_prototype->name, jp_row,
+ lld_macros);
+
+ zbx_vector_ptr_append(&group->hosts, host);
+ }
+
+ zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
+}
+
+/******************************************************************************
+ * *
+ * Function: lld_validate_group_name *
+ * *
+ * Purpose: validate group name *
+ * *
+ * Return value: SUCCEED - the group name is valid *
+ * FAIL - otherwise *
+ * *
+ ******************************************************************************/
+static int lld_validate_group_name(const char *name)
+{
+ /* group name cannot be empty */
+ if ('\0' == *name)
+ return FAIL;
+
+ /* group name must contain valid utf8 characters */
+ if (SUCCEED != zbx_is_utf8(name))
+ return FAIL;
+
+ /* group name cannot exceed field limits */
+ if (GROUP_NAME_LEN < zbx_strlen_utf8(name))
+ return FAIL;
+
+ /* group name cannot contain trailing and leading slashes (/) */
+ if ('/' == *name || '/' == name[strlen(name) - 1])
+ return FAIL;
+
+ /* group name cannot contain several slashes (/) in a row */
+ if (NULL != strstr(name, "//"))
+ return FAIL;
+
+ return SUCCEED;
+}
+
+/******************************************************************************
+ * *
+ * Function: lld_groups_validate *
+ * *
+ * Parameters: groups - [IN] list of groups; should be sorted by groupid *
+ * *
+ ******************************************************************************/
+static void lld_groups_validate(zbx_vector_ptr_t *groups, char **error)
+{
+ const char *__function_name = "lld_groups_validate";
+
+ DB_RESULT result;
+ DB_ROW row;
+ int i, j;
+ zbx_lld_group_t *group, *group_b;
+ zbx_vector_uint64_t groupids;
+ zbx_vector_str_t names;
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
+
+ zbx_vector_uint64_create(&groupids);
+ zbx_vector_str_create(&names); /* list of group names */
+
+ /* checking a group name validity */
+ for (i = 0; i < groups->values_num; i++)
+ {
+ group = (zbx_lld_group_t *)groups->values[i];
+
+ if (0 == (group->flags & ZBX_FLAG_LLD_GROUP_DISCOVERED))
+ continue;
+
+ /* only new groups or groups with changed group name will be validated */
+ if (0 != group->groupid && 0 == (group->flags & ZBX_FLAG_LLD_GROUP_UPDATE_NAME))
+ continue;
+
+ if (SUCCEED == lld_validate_group_name(group->name))
+ continue;
+
+ zbx_replace_invalid_utf8(group->name);
+ *error = zbx_strdcatf(*error, "Cannot %s group: invalid group name \"%s\".\n",
+ (0 != group->groupid ? "update" : "create"), group->name);
+
+ if (0 != group->groupid)
+ {
+ lld_field_str_rollback(&group->name, &group->name_orig, &group->flags,
+ ZBX_FLAG_LLD_GROUP_UPDATE_NAME);
+ }
+ else
+ group->flags &= ~ZBX_FLAG_LLD_GROUP_DISCOVERED;
+ }
+
+ /* checking duplicated group names */
+ for (i = 0; i < groups->values_num; i++)
+ {
+ group = (zbx_lld_group_t *)groups->values[i];
+
+ if (0 == (group->flags & ZBX_FLAG_LLD_GROUP_DISCOVERED))
+ continue;
+
+ /* only new groups or groups with changed group name will be validated */
+ if (0 != group->groupid && 0 == (group->flags & ZBX_FLAG_LLD_GROUP_UPDATE_NAME))
+ continue;
+
+ for (j = 0; j < groups->values_num; j++)
+ {
+ group_b = (zbx_lld_group_t *)groups->values[j];
+
+ if (0 == (group_b->flags & ZBX_FLAG_LLD_GROUP_DISCOVERED) || i == j)
+ continue;
+
+ if (0 != strcmp(group->name, group_b->name))
+ continue;
+
+ *error = zbx_strdcatf(*error, "Cannot %s group:"
+ " group with the same name \"%s\" already exists.\n",
+ (0 != group->groupid ? "update" : "create"), group->name);
+
+ if (0 != group->groupid)
+ {
+ lld_field_str_rollback(&group->name, &group->name_orig, &group->flags,
+ ZBX_FLAG_LLD_GROUP_UPDATE_NAME);
+ }
+ else
+ group->flags &= ~ZBX_FLAG_LLD_GROUP_DISCOVERED;
+ }
+ }
+
+ /* checking duplicated group names and group names in DB */
+
+ for (i = 0; i < groups->values_num; i++)
+ {
+ group = (zbx_lld_group_t *)groups->values[i];
+
+ if (0 == (group->flags & ZBX_FLAG_LLD_GROUP_DISCOVERED))
+ continue;
+
+ if (0 != group->groupid)
+ zbx_vector_uint64_append(&groupids, group->groupid);
+
+ if (0 == group->groupid || 0 != (group->flags & ZBX_FLAG_LLD_GROUP_UPDATE_NAME))
+ zbx_vector_str_append(&names, group->name);
+ }
+
+ if (0 != names.values_num)
+ {
+ char *sql = NULL;
+ size_t sql_alloc = 0, sql_offset = 0;
+
+ zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "select name from hstgrp where");
+ DBadd_str_condition_alloc(&sql, &sql_alloc, &sql_offset, "name",
+ (const char **)names.values, names.values_num);
+
+ if (0 != groupids.values_num)
+ {
+ zbx_vector_uint64_sort(&groupids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
+ zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, " and not");
+ DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "groupid",
+ groupids.values, groupids.values_num);
+ }
+
+ result = DBselect("%s", sql);
+
+ while (NULL != (row = DBfetch(result)))
+ {
+ for (i = 0; i < groups->values_num; i++)
+ {
+ group = (zbx_lld_group_t *)groups->values[i];
+
+ if (0 == (group->flags & ZBX_FLAG_LLD_GROUP_DISCOVERED))
+ continue;
+
+ if (0 == strcmp(group->name, row[0]))
+ {
+ *error = zbx_strdcatf(*error, "Cannot %s group:"
+ " group with the same name \"%s\" already exists.\n",
+ (0 != group->groupid ? "update" : "create"), group->name);
+
+ if (0 != group->groupid)
+ {
+ lld_field_str_rollback(&group->name, &group->name_orig, &group->flags,
+ ZBX_FLAG_LLD_GROUP_UPDATE_NAME);
+ }
+ else
+ group->flags &= ~ZBX_FLAG_LLD_GROUP_DISCOVERED;
+ }
+ }
+ }
+ DBfree_result(result);
+
+ zbx_free(sql);
+ }
+
+ zbx_vector_str_destroy(&names);
+ zbx_vector_uint64_destroy(&groupids);
+
+ zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
+}
+
+/******************************************************************************
+ * *
+ * Function: lld_group_rights_compare *
+ * *
+ * Purpose: sorting function to sort group rights vector by name *
+ * *
+ ******************************************************************************/
+static int lld_group_rights_compare(const void *d1, const void *d2)
+{
+ const zbx_lld_group_rights_t *r1 = *(const zbx_lld_group_rights_t **)d1;
+ const zbx_lld_group_rights_t *r2 = *(const zbx_lld_group_rights_t **)d2;
+
+ return strcmp(r1->name, r2->name);
+}
+
+/******************************************************************************
+ * *
+ * Function: lld_group_rights_append *
+ * *
+ * Purpose: append a new item to group rights vector *
+ * *
+ * Return value: Index of the added item. *
+ * *
+ ******************************************************************************/
+static int lld_group_rights_append(zbx_vector_ptr_t *group_rights, const char *name)
+{
+ zbx_lld_group_rights_t *rights;
+
+ rights = (zbx_lld_group_rights_t *)zbx_malloc(NULL, sizeof(zbx_lld_group_rights_t));
+ rights->name = zbx_strdup(NULL, name);
+ zbx_vector_uint64_pair_create(&rights->rights);
+ rights->prights = NULL;
+
+ zbx_vector_ptr_append(group_rights, rights);
+
+ return group_rights->values_num - 1;
+}
+
+/******************************************************************************
+ * *
+ * Function: lld_group_rights_free *
+ * *
+ * PUrpose: frees group rights data *
+ * *
+ ******************************************************************************/
+static void lld_group_rights_free(zbx_lld_group_rights_t *rights)
+{
+ zbx_free(rights->name);
+ zbx_vector_uint64_pair_destroy(&rights->rights);
+ zbx_free(rights);
+}
+
+/******************************************************************************
+ * *
+ * Function: lld_groups_save_rights *
+ * *
+ * Parameters: groups - [IN] list of new groups *
+ * *
+ ******************************************************************************/
+static void lld_groups_save_rights(zbx_vector_ptr_t *groups)
+{
+ const char *__function_name = "lld_groups_save_rights";
+
+ int i, j;
+ DB_ROW row;
+ DB_RESULT result;
+ char *ptr, *name, *sql = NULL;
+ size_t sql_alloc = 0, sql_offset = 0, offset;
+ zbx_lld_group_t *group;
+ zbx_vector_str_t group_names;
+ zbx_vector_ptr_t group_rights;
+ zbx_db_insert_t db_insert;
+ zbx_lld_group_rights_t *rights, rights_local, *parent_rights;
+ zbx_uint64_pair_t pair;
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
+
+ zbx_vector_str_create(&group_names);
+ zbx_vector_ptr_create(&group_rights);
+
+ /* make a list of direct parent group names and a list of new group rights */
+ for (i = 0; i < groups->values_num; i++)
+ {
+ group = (zbx_lld_group_t *)groups->values[i];
+
+ if (NULL == (ptr = strrchr(group->name, '/')))
+ continue;
+
+ lld_group_rights_append(&group_rights, group->name);
+
+ name = zbx_strdup(NULL, group->name);
+ name[ptr - group->name] = '\0';
+
+ if (FAIL != zbx_vector_str_search(&group_names, name, ZBX_DEFAULT_STR_COMPARE_FUNC))
+ {
+ zbx_free(name);
+ continue;
+ }
+
+ zbx_vector_str_append(&group_names, name);
+ }
+
+ if (0 == group_names.values_num)
+ goto out;
+
+ /* read the parent group rights */
+
+ zbx_db_insert_prepare(&db_insert, "rights", "rightid", "id", "permission", "groupid", NULL);
+ zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
+ "select g.name,r.permission,r.groupid from hstgrp g,rights r"
+ " where r.id=g.groupid"
+ " and");
+
+ DBadd_str_condition_alloc(&sql, &sql_alloc, &sql_offset, "g.name", (const char **)group_names.values,
+ group_names.values_num);
+ result = DBselect("%s", sql);
+
+ while (NULL != (row = DBfetch(result)))
+ {
+ rights_local.name = row[0];
+ if (FAIL == (i = zbx_vector_ptr_search(&group_rights, &rights_local, lld_group_rights_compare)))
+ i = lld_group_rights_append(&group_rights, row[0]);
+
+ rights = (zbx_lld_group_rights_t *)group_rights.values[i];
+ rights->prights = &rights->rights;
+
+ ZBX_STR2UINT64(pair.first, row[2]);
+ pair.second = atoi(row[1]);
+
+ zbx_vector_uint64_pair_append(&rights->rights, pair);
+ }
+ DBfree_result(result);
+
+ zbx_vector_ptr_sort(&group_rights, lld_group_rights_compare);
+
+ /* assign rights for the new groups */
+ for (i = 0; i < group_rights.values_num; i++)
+ {
+ rights = (zbx_lld_group_rights_t *)group_rights.values[i];
+
+ if (NULL != rights->prights)
+ continue;
+
+ if (NULL == (ptr = strrchr(rights->name, '/')))
+ continue;
+
+ offset = ptr - rights->name;
+
+ for (j = 0; j < i; j++)
+ {
+ parent_rights = (zbx_lld_group_rights_t *)group_rights.values[j];
+
+ if (strlen(parent_rights->name) != offset)
+ continue;
+
+ if (0 != strncmp(parent_rights->name, rights->name, offset))
+ continue;
+
+ rights->prights = parent_rights->prights;
+ break;
+ }
+ }
+
+ /* save rights for the new groups */
+ for (i = 0; i < groups->values_num; i++)
+ {
+ group = (zbx_lld_group_t *)groups->values[i];
+
+ rights_local.name = group->name;
+ if (FAIL == (j = zbx_vector_ptr_bsearch(&group_rights, &rights_local, lld_group_rights_compare)))
+ continue;
+
+ rights = (zbx_lld_group_rights_t *)group_rights.values[j];
+
+ if (NULL == rights->prights)
+ continue;
+
+ for (j = 0; j < rights->prights->values_num; j++)
+ {
+ zbx_db_insert_add_values(&db_insert, __UINT64_C(0), group->groupid,
+ (int)rights->prights->values[j].second, rights->prights->values[j].first);
+ }
+ }
+
+ zbx_db_insert_autoincrement(&db_insert, "rightid");
+ zbx_db_insert_execute(&db_insert);
+ zbx_db_insert_clean(&db_insert);
+
+ zbx_free(sql);
+ zbx_vector_ptr_clear_ext(&group_rights, (zbx_clean_func_t)lld_group_rights_free);
+ zbx_vector_str_clear_ext(&group_names, zbx_str_free);
+out:
+ zbx_vector_ptr_destroy(&group_rights);
+ zbx_vector_str_destroy(&group_names);
+
+ zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
+}
+
+/******************************************************************************
+ * *
+ * Function: lld_groups_save *
+ * *
+ * Parameters: groups - [IN/OUT] list of groups; should be sorted *
+ * by groupid *
+ * group_prototypes - [IN] list of group prototypes; should be *
+ * sorted by group_prototypeid *
+ * *
+ ******************************************************************************/
+static void lld_groups_save(zbx_vector_ptr_t *groups, const zbx_vector_ptr_t *group_prototypes)
+{
+ const char *__function_name = "lld_groups_save";
+
+ int i, j, new_groups_num = 0, upd_groups_num = 0;
+ zbx_lld_group_t *group;
+ const zbx_lld_group_prototype_t *group_prototype;
+ zbx_lld_host_t *host;
+ zbx_uint64_t groupid = 0;
+ char *sql = NULL, *name_esc, *name_proto_esc;
+ size_t sql_alloc = 0, sql_offset = 0;
+ zbx_db_insert_t db_insert, db_insert_gdiscovery;
+ zbx_vector_ptr_t new_groups;
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
+
+ for (i = 0; i < groups->values_num; i++)
+ {
+ group = (zbx_lld_group_t *)groups->values[i];
+
+ if (0 == (group->flags & ZBX_FLAG_LLD_GROUP_DISCOVERED))
+ continue;
+
+ if (0 == group->groupid)
+ new_groups_num++;
+ else if (0 != (group->flags & ZBX_FLAG_LLD_GROUP_UPDATE))
+ upd_groups_num++;
+ }
+
+ if (0 == new_groups_num && 0 == upd_groups_num)
+ goto out;
+
+ DBbegin();
+
+ if (0 != new_groups_num)
+ {
+ groupid = DBget_maxid_num("hstgrp", new_groups_num);
+
+ zbx_db_insert_prepare(&db_insert, "hstgrp", "groupid", "name", "flags", NULL);
+
+ zbx_db_insert_prepare(&db_insert_gdiscovery, "group_discovery", "groupid", "parent_group_prototypeid",
+ "name", NULL);
+
+ zbx_vector_ptr_create(&new_groups);
+ }
+
+ if (0 != upd_groups_num)
+ {
+ DBbegin_multiple_update(&sql, &sql_alloc, &sql_offset);
+ }
+
+ for (i = 0; i < groups->values_num; i++)
+ {
+ group = (zbx_lld_group_t *)groups->values[i];
+
+ if (0 == (group->flags & ZBX_FLAG_LLD_GROUP_DISCOVERED))
+ continue;
+
+ if (0 == group->groupid)
+ {
+ group->groupid = groupid++;
+
+ zbx_db_insert_add_values(&db_insert, group->groupid, group->name,
+ (int)ZBX_FLAG_DISCOVERY_CREATED);
+
+ if (FAIL != (j = zbx_vector_ptr_bsearch(group_prototypes, &group->group_prototypeid,
+ ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC)))
+ {
+ group_prototype = (zbx_lld_group_prototype_t *)group_prototypes->values[j];
+
+ zbx_db_insert_add_values(&db_insert_gdiscovery, group->groupid,
+ group->group_prototypeid, group_prototype->name);
+ }
+ else
+ THIS_SHOULD_NEVER_HAPPEN;
+
+ for (j = 0; j < group->hosts.values_num; j++)
+ {
+ host = (zbx_lld_host_t *)group->hosts.values[j];
+
+ /* hosts will be linked to a new host groups */
+ zbx_vector_uint64_append(&host->new_groupids, group->groupid);
+ }
+
+ zbx_vector_ptr_append(&new_groups, group);
+ }
+ else
+ {
+ if (0 != (group->flags & ZBX_FLAG_LLD_GROUP_UPDATE))
+ {
+ zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "update hstgrp set ");
+ if (0 != (group->flags & ZBX_FLAG_LLD_GROUP_UPDATE_NAME))
+ {
+ name_esc = DBdyn_escape_string(group->name);
+
+ zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "name='%s'", name_esc);
+
+ zbx_free(name_esc);
+ }
+ zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
+ " where groupid=" ZBX_FS_UI64 ";\n", group->groupid);
+ }
+
+ if (0 != (group->flags & ZBX_FLAG_LLD_GROUP_UPDATE_NAME))
+ {
+ if (FAIL != (j = zbx_vector_ptr_bsearch(group_prototypes, &group->group_prototypeid,
+ ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC)))
+ {
+ group_prototype = (zbx_lld_group_prototype_t *)group_prototypes->values[j];
+
+ name_proto_esc = DBdyn_escape_string(group_prototype->name);
+
+ zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
+ "update group_discovery"
+ " set name='%s'"
+ " where groupid=" ZBX_FS_UI64 ";\n",
+ name_proto_esc, group->groupid);
+
+ zbx_free(name_proto_esc);
+ }
+ else
+ THIS_SHOULD_NEVER_HAPPEN;
+ }
+ }
+ }
+
+ if (0 != upd_groups_num)
+ {
+ DBend_multiple_update(&sql, &sql_alloc, &sql_offset);
+ DBexecute("%s", sql);
+ zbx_free(sql);
+ }
+
+ if (0 != new_groups_num)
+ {
+ zbx_db_insert_execute(&db_insert);
+ zbx_db_insert_clean(&db_insert);
+
+ zbx_db_insert_execute(&db_insert_gdiscovery);
+ zbx_db_insert_clean(&db_insert_gdiscovery);
+
+ lld_groups_save_rights(&new_groups);
+ zbx_vector_ptr_destroy(&new_groups);
+ }
+
+ DBcommit();
+out:
+ zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
+}
+
+/******************************************************************************
+ * *
+ * Function: lld_hostmacros_get *
+ * *
+ * Purpose: retrieve list of host macros which should be present on the each *
+ * discovered host *
+ * *
+ * Parameters: hostmacros - [OUT] list of host macros *
+ * *
+ ******************************************************************************/
+static void lld_hostmacros_get(zbx_uint64_t lld_ruleid, zbx_vector_ptr_t *hostmacros)
+{
+ const char *__function_name = "lld_hostmacros_get";
+
+ DB_RESULT result;
+ DB_ROW row;
+ zbx_lld_hostmacro_t *hostmacro;
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
+
+ result = DBselect(
+ "select hm.macro,hm.value"
+ " from hostmacro hm,items i"
+ " where hm.hostid=i.hostid"
+ " and i.itemid=" ZBX_FS_UI64,
+ lld_ruleid);
+
+ while (NULL != (row = DBfetch(result)))
+ {
+ hostmacro = (zbx_lld_hostmacro_t *)zbx_malloc(NULL, sizeof(zbx_lld_hostmacro_t));
+
+ hostmacro->macro = zbx_strdup(NULL, row[0]);
+ hostmacro->value = zbx_strdup(NULL, row[1]);
+
+ zbx_vector_ptr_append(hostmacros, hostmacro);
+ }
+ DBfree_result(result);
+
+ zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
+}
+
+/******************************************************************************
+ * *
+ * Function: lld_hostmacros_make *
+ * *
+ * Parameters: hostmacros - [IN] list of host macros which *
+ * should be present on the each *
+ * discovered host *
+ * hosts - [IN/OUT] list of hosts *
+ * should be sorted by hostid *
+ * del_hostmacroids - [OUT] list of host macros which should be *
+ * deleted *
+ * *
+ ******************************************************************************/
+static void lld_hostmacros_make(const zbx_vector_ptr_t *hostmacros, zbx_vector_ptr_t *hosts,
+ zbx_vector_uint64_t *del_hostmacroids)
+{
+ const char *__function_name = "lld_hostmacros_make";
+
+ DB_RESULT result;
+ DB_ROW row;
+ int i, j;
+ zbx_vector_uint64_t hostids;
+ zbx_uint64_t hostmacroid, hostid;
+ zbx_lld_host_t *host;
+ zbx_lld_hostmacro_t *hostmacro = NULL;
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
+
+ zbx_vector_uint64_create(&hostids);
+
+ for (i = 0; i < hosts->values_num; i++)
+ {
+ host = (zbx_lld_host_t *)hosts->values[i];
+
+ if (0 == (host->flags & ZBX_FLAG_LLD_HOST_DISCOVERED))
+ continue;
+
+ zbx_vector_ptr_reserve(&host->new_hostmacros, hostmacros->values_num);
+ for (j = 0; j < hostmacros->values_num; j++)
+ {
+ hostmacro = (zbx_lld_hostmacro_t *)zbx_malloc(NULL, sizeof(zbx_lld_hostmacro_t));
+
+ hostmacro->hostmacroid = 0;
+ hostmacro->macro = zbx_strdup(NULL, ((zbx_lld_hostmacro_t *)hostmacros->values[j])->macro);
+ hostmacro->value = zbx_strdup(NULL, ((zbx_lld_hostmacro_t *)hostmacros->values[j])->value);
+
+ zbx_vector_ptr_append(&host->new_hostmacros, hostmacro);
+ }
+
+ if (0 != host->hostid)
+ zbx_vector_uint64_append(&hostids, host->hostid);
+ }
+
+ if (0 != hostids.values_num)
+ {
+ char *sql = NULL;
+ size_t sql_alloc = 0, sql_offset = 0;
+
+ zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
+ "select hostmacroid,hostid,macro,value"
+ " from hostmacro"
+ " where");
+ DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "hostid", hostids.values, hostids.values_num);
+
+ result = DBselect("%s", sql);
+
+ zbx_free(sql);
+
+ while (NULL != (row = DBfetch(result)))
+ {
+ ZBX_STR2UINT64(hostid, row[1]);
+
+ if (FAIL == (i = zbx_vector_ptr_bsearch(hosts, &hostid, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC)))
+ {
+ THIS_SHOULD_NEVER_HAPPEN;
+ continue;
+ }
+
+ host = (zbx_lld_host_t *)hosts->values[i];
+
+ for (i = 0; i < host->new_hostmacros.values_num; i++)
+ {
+ hostmacro = (zbx_lld_hostmacro_t *)host->new_hostmacros.values[i];
+
+ if (0 == strcmp(hostmacro->macro, row[2]))
+ break;
+ }
+
+ if (i == host->new_hostmacros.values_num)
+ {
+ /* host macros which should be deleted */
+ ZBX_STR2UINT64(hostmacroid, row[0]);
+ zbx_vector_uint64_append(del_hostmacroids, hostmacroid);
+ }
+ else
+ {
+ /* host macros which are already added */
+ if (0 == strcmp(hostmacro->value, row[3])) /* value doesn't changed */
+ {
+ lld_hostmacro_free(hostmacro);
+ zbx_vector_ptr_remove(&host->new_hostmacros, i);
+ }
+ else
+ ZBX_STR2UINT64(hostmacro->hostmacroid, row[0]);
+ }
+ }
+ DBfree_result(result);
+
+ zbx_vector_uint64_sort(del_hostmacroids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
+ }
+
+ zbx_vector_uint64_destroy(&hostids);
+
+ zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
+}
+
+/******************************************************************************
+ * *
+ * Function: lld_templates_make *
+ * *
+ * Purpose: gets templates from a host prototype *
+ * *
+ * Parameters: parent_hostid - [IN] host prototype identifier *
+ * hosts - [IN/OUT] list of hosts *
+ * should be sorted by hostid *
+ * *
+ ******************************************************************************/
+static void lld_templates_make(zbx_uint64_t parent_hostid, zbx_vector_ptr_t *hosts)
+{
+ const char *__function_name = "lld_templates_make";
+
+ DB_RESULT result;
+ DB_ROW row;
+ zbx_vector_uint64_t templateids, hostids;
+ zbx_uint64_t templateid, hostid;
+ zbx_lld_host_t *host;
+ int i, j;
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
+
+ zbx_vector_uint64_create(&templateids);
+ zbx_vector_uint64_create(&hostids);
+
+ /* select templates which should be linked */
+
+ result = DBselect("select templateid from hosts_templates where hostid=" ZBX_FS_UI64, parent_hostid);
+
+ while (NULL != (row = DBfetch(result)))
+ {
+ ZBX_STR2UINT64(templateid, row[0]);
+ zbx_vector_uint64_append(&templateids, templateid);
+ }
+ DBfree_result(result);
+
+ zbx_vector_uint64_sort(&templateids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
+
+ /* select list of already created hosts */
+
+ for (i = 0; i < hosts->values_num; i++)
+ {
+ host = (zbx_lld_host_t *)hosts->values[i];
+
+ if (0 == (host->flags & ZBX_FLAG_LLD_HOST_DISCOVERED))
+ continue;
+
+ zbx_vector_uint64_reserve(&host->lnk_templateids, templateids.values_num);
+ for (j = 0; j < templateids.values_num; j++)
+ zbx_vector_uint64_append(&host->lnk_templateids, templateids.values[j]);
+
+ if (0 != host->hostid)
+ zbx_vector_uint64_append(&hostids, host->hostid);
+ }
+
+ if (0 != hostids.values_num)
+ {
+ char *sql = NULL;
+ size_t sql_alloc = 0, sql_offset = 0;
+
+ /* select already linked temlates */
+
+ zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
+ "select hostid,templateid"
+ " from hosts_templates"
+ " where");
+ DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "hostid", hostids.values, hostids.values_num);
+
+ result = DBselect("%s", sql);
+
+ zbx_free(sql);
+
+ while (NULL != (row = DBfetch(result)))
+ {
+ ZBX_STR2UINT64(hostid, row[0]);
+ ZBX_STR2UINT64(templateid, row[1]);
+
+ if (FAIL == (i = zbx_vector_ptr_bsearch(hosts, &hostid, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC)))
+ {
+ THIS_SHOULD_NEVER_HAPPEN;
+ continue;
+ }
+
+ host = (zbx_lld_host_t *)hosts->values[i];
+
+ if (FAIL == (i = zbx_vector_uint64_bsearch(&host->lnk_templateids, templateid,
+ ZBX_DEFAULT_UINT64_COMPARE_FUNC)))
+ {
+ /* templates which should be unlinked */
+ zbx_vector_uint64_append(&host->del_templateids, templateid);
+ }
+ else
+ {
+ /* templates which are already linked */
+ zbx_vector_uint64_remove(&host->lnk_templateids, i);
+ }
+ }
+ DBfree_result(result);
+
+ for (i = 0; i < hosts->values_num; i++)
+ {
+ host = (zbx_lld_host_t *)hosts->values[i];
+
+ if (0 == (host->flags & ZBX_FLAG_LLD_HOST_DISCOVERED))
+ continue;
+
+ zbx_vector_uint64_sort(&host->del_templateids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
+ }
+ }
+
+ zbx_vector_uint64_destroy(&hostids);
+ zbx_vector_uint64_destroy(&templateids);
+
+ zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
+}
+
+/******************************************************************************
+ * *
+ * Function: lld_hosts_save *
+ * *
+ * Parameters: hosts - [IN] list of hosts; *
+ * should be sorted by hostid *
+ * status - [IN] initial host status *
+ * del_hostgroupids - [IN] host groups which should be deleted *
+ * del_hostmacroids - [IN] host macros which should be deleted *
+ * *
+ ******************************************************************************/
+static void 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)
+{
+ const char *__function_name = "lld_hosts_save";
+
+ int i, j, new_hosts = 0, new_host_inventories = 0, upd_hosts = 0, new_hostgroups = 0,
+ new_hostmacros = 0, upd_hostmacros = 0, new_interfaces = 0, upd_interfaces = 0;
+ zbx_lld_host_t *host;
+ zbx_lld_hostmacro_t *hostmacro;
+ zbx_lld_interface_t *interface;
+ zbx_vector_uint64_t upd_host_inventory_hostids, del_host_inventory_hostids, del_interfaceids;
+ zbx_uint64_t hostid = 0, hostgroupid = 0, hostmacroid = 0, interfaceid = 0;
+ char *sql1 = NULL, *sql2 = NULL, *value_esc;
+ size_t sql1_alloc = 0, sql1_offset = 0,
+ sql2_alloc = 0, sql2_offset = 0;
+ zbx_db_insert_t db_insert, db_insert_hdiscovery, db_insert_hinventory, db_insert_hgroups,
+ db_insert_hmacro, db_insert_interface, db_insert_idiscovery;
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
+
+ zbx_vector_uint64_create(&upd_host_inventory_hostids);
+ zbx_vector_uint64_create(&del_host_inventory_hostids);
+ zbx_vector_uint64_create(&del_interfaceids);
+
+ for (i = 0; i < hosts->values_num; i++)
+ {
+ host = (zbx_lld_host_t *)hosts->values[i];
+
+ if (0 == (host->flags & ZBX_FLAG_LLD_HOST_DISCOVERED))
+ continue;
+
+ if (0 == host->hostid)
+ {
+ new_hosts++;
+ if (HOST_INVENTORY_DISABLED != inventory_mode)
+ new_host_inventories++;
+ }
+ else
+ {
+ if (0 != (host->flags & ZBX_FLAG_LLD_HOST_UPDATE))
+ upd_hosts++;
+
+ if (host->inventory_mode != inventory_mode)
+ {
+ if (HOST_INVENTORY_DISABLED == inventory_mode)
+ zbx_vector_uint64_append(&del_host_inventory_hostids, host->hostid);
+ else if (HOST_INVENTORY_DISABLED == host->inventory_mode)
+ new_host_inventories++;
+ else
+ zbx_vector_uint64_append(&upd_host_inventory_hostids, host->hostid);
+ }
+ }
+
+ new_hostgroups += host->new_groupids.values_num;
+
+ for (j = 0; j < host->interfaces.values_num; j++)
+ {
+ interface = (zbx_lld_interface_t *)host->interfaces.values[j];
+
+ if (0 == interface->interfaceid)
+ new_interfaces++;
+ else if (0 != (interface->flags & ZBX_FLAG_LLD_INTERFACE_UPDATE))
+ upd_interfaces++;
+ else if (0 != (interface->flags & ZBX_FLAG_LLD_INTERFACE_REMOVE))
+ zbx_vector_uint64_append(&del_interfaceids, interface->interfaceid);
+ }
+
+ for (j = 0; j < host->new_hostmacros.values_num; j++)
+ {
+ hostmacro = (zbx_lld_hostmacro_t *)host->new_hostmacros.values[j];
+
+ if (0 == hostmacro->hostmacroid)
+ new_hostmacros++;
+ else
+ upd_hostmacros++;
+ }
+ }
+
+ if (0 == new_hosts && 0 == new_host_inventories && 0 == upd_hosts && 0 == upd_interfaces &&
+ 0 == upd_hostmacros && 0 == new_hostgroups && 0 == new_hostmacros && 0 == new_interfaces &&
+ 0 == del_hostgroupids->values_num && 0 == del_hostmacroids->values_num &&
+ 0 == upd_host_inventory_hostids.values_num && 0 == del_host_inventory_hostids.values_num &&
+ 0 == del_interfaceids.values_num)
+ {
+ goto out;
+ }
+
+ DBbegin();
+
+ if (0 != new_hosts)
+ {
+ hostid = DBget_maxid_num("hosts", new_hosts);
+
+ zbx_db_insert_prepare(&db_insert, "hosts", "hostid", "host", "name", "proxy_hostid", "ipmi_authtype",
+ "ipmi_privilege", "ipmi_username", "ipmi_password", "status", "flags", "tls_connect",
+ "tls_accept", "tls_issuer", "tls_subject", "tls_psk_identity", "tls_psk", NULL);
+
+ zbx_db_insert_prepare(&db_insert_hdiscovery, "host_discovery", "hostid", "parent_hostid", "host", NULL);
+ }
+
+ if (0 != new_host_inventories)
+ {
+ zbx_db_insert_prepare(&db_insert_hinventory, "host_inventory", "hostid", "inventory_mode", NULL);
+ }
+
+ if (0 != upd_hosts || 0 != upd_interfaces || 0 != upd_hostmacros)
+ {
+ DBbegin_multiple_update(&sql1, &sql1_alloc, &sql1_offset);
+ }
+
+ if (0 != new_hostgroups)
+ {
+ hostgroupid = DBget_maxid_num("hosts_groups", new_hostgroups);
+
+ zbx_db_insert_prepare(&db_insert_hgroups, "hosts_groups", "hostgroupid", "hostid", "groupid", NULL);
+ }
+
+ if (0 != new_hostmacros)
+ {
+ hostmacroid = DBget_maxid_num("hostmacro", new_hostmacros);
+
+ zbx_db_insert_prepare(&db_insert_hmacro, "hostmacro", "hostmacroid", "hostid", "macro", "value", NULL);
+ }
+
+ if (0 != new_interfaces)
+ {
+ interfaceid = DBget_maxid_num("interface", new_interfaces);
+
+ zbx_db_insert_prepare(&db_insert_interface, "interface", "interfaceid", "hostid", "type", "main",
+ "useip", "ip", "dns", "port", "bulk", NULL);
+
+ zbx_db_insert_prepare(&db_insert_idiscovery, "interface_discovery", "interfaceid",
+ "parent_interfaceid", NULL);
+ }
+
+ for (i = 0; i < hosts->values_num; i++)
+ {
+ host = (zbx_lld_host_t *)hosts->values[i];
+
+ if (0 == (host->flags & ZBX_FLAG_LLD_HOST_DISCOVERED))
+ continue;
+
+ if (0 == host->hostid)
+ {
+ host->hostid = hostid++;
+
+ zbx_db_insert_add_values(&db_insert, host->hostid, host->host, host->name, proxy_hostid,
+ (int)ipmi_authtype, (int)ipmi_privilege, ipmi_username, ipmi_password,
+ (int)status, (int)ZBX_FLAG_DISCOVERY_CREATED, (int)tls_connect,
+ (int)tls_accept, tls_issuer, tls_subject, tls_psk_identity, tls_psk);
+
+ zbx_db_insert_add_values(&db_insert_hdiscovery, host->hostid, parent_hostid, host_proto);
+
+ if (HOST_INVENTORY_DISABLED != inventory_mode)
+ zbx_db_insert_add_values(&db_insert_hinventory, host->hostid, (int)inventory_mode);
+ }
+ else
+ {
+ if (0 != (host->flags & ZBX_FLAG_LLD_HOST_UPDATE))
+ {
+ const char *d = "";
+
+ zbx_strcpy_alloc(&sql1, &sql1_alloc, &sql1_offset, "update hosts set ");
+ if (0 != (host->flags & ZBX_FLAG_LLD_HOST_UPDATE_HOST))
+ {
+ value_esc = DBdyn_escape_string(host->host);
+
+ zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset, "host='%s'", value_esc);
+ d = ",";
+
+ zbx_free(value_esc);
+ }
+ if (0 != (host->flags & ZBX_FLAG_LLD_HOST_UPDATE_NAME))
+ {
+ value_esc = DBdyn_escape_string(host->name);
+
+ zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset,
+ "%sname='%s'", d, value_esc);
+ d = ",";
+
+ zbx_free(value_esc);
+ }
+ if (0 != (host->flags & ZBX_FLAG_LLD_HOST_UPDATE_PROXY))
+ {
+ zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset,
+ "%sproxy_hostid=%s", d, DBsql_id_ins(proxy_hostid));
+ d = ",";
+ }
+ if (0 != (host->flags & ZBX_FLAG_LLD_HOST_UPDATE_IPMI_AUTH))
+ {
+ zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset,
+ "%sipmi_authtype=%d", d, (int)ipmi_authtype);
+ d = ",";
+ }
+ if (0 != (host->flags & ZBX_FLAG_LLD_HOST_UPDATE_IPMI_PRIV))
+ {
+ zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset,
+ "%sipmi_privilege=%d", d, (int)ipmi_privilege);
+ d = ",";
+ }
+ if (0 != (host->flags & ZBX_FLAG_LLD_HOST_UPDATE_IPMI_USER))
+ {
+ value_esc = DBdyn_escape_string(ipmi_username);
+
+ zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset,
+ "%sipmi_username='%s'", d, value_esc);
+ d = ",";
+
+ zbx_free(value_esc);
+ }
+ if (0 != (host->flags & ZBX_FLAG_LLD_HOST_UPDATE_IPMI_PASS))
+ {
+ value_esc = DBdyn_escape_string(ipmi_password);
+
+ zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset,
+ "%sipmi_password='%s'", d, value_esc);
+ d = ",";
+
+ zbx_free(value_esc);
+ }
+ if (0 != (host->flags & ZBX_FLAG_LLD_HOST_UPDATE_TLS_CONNECT))
+ {
+ zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset,
+ "%stls_connect=%d", d, tls_connect);
+ d = ",";
+ }
+ if (0 != (host->flags & ZBX_FLAG_LLD_HOST_UPDATE_TLS_ACCEPT))
+ {
+ zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset,
+ "%stls_accept=%d", d, tls_accept);
+ d = ",";
+ }
+ if (0 != (host->flags & ZBX_FLAG_LLD_HOST_UPDATE_TLS_ISSUER))
+ {
+ value_esc = DBdyn_escape_string(tls_issuer);
+
+ zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset,
+ "%stls_issuer='%s'", d, value_esc);
+ d = ",";
+
+ zbx_free(value_esc);
+ }
+ if (0 != (host->flags & ZBX_FLAG_LLD_HOST_UPDATE_TLS_SUBJECT))
+ {
+ value_esc = DBdyn_escape_string(tls_subject);
+
+ zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset,
+ "%stls_subject='%s'", d, value_esc);
+ d = ",";
+
+ zbx_free(value_esc);
+ }
+ if (0 != (host->flags & ZBX_FLAG_LLD_HOST_UPDATE_TLS_PSK_IDENTITY))
+ {
+ value_esc = DBdyn_escape_string(tls_psk_identity);
+
+ zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset,
+ "%stls_psk_identity='%s'", d, value_esc);
+ d = ",";
+
+ zbx_free(value_esc);
+ }
+ if (0 != (host->flags & ZBX_FLAG_LLD_HOST_UPDATE_TLS_PSK))
+ {
+ value_esc = DBdyn_escape_string(tls_psk);
+
+ zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset,
+ "%stls_psk='%s'", d, value_esc);
+
+ zbx_free(value_esc);
+ }
+ zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset, " where hostid=" ZBX_FS_UI64 ";\n",
+ host->hostid);
+ }
+
+ if (host->inventory_mode != inventory_mode && HOST_INVENTORY_DISABLED == host->inventory_mode)
+ zbx_db_insert_add_values(&db_insert_hinventory, host->hostid, (int)inventory_mode);
+
+ if (0 != (host->flags & ZBX_FLAG_LLD_HOST_UPDATE_HOST))
+ {
+ value_esc = DBdyn_escape_string(host_proto);
+
+ zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset,
+ "update host_discovery"
+ " set host='%s'"
+ " where hostid=" ZBX_FS_UI64 ";\n",
+ value_esc, host->hostid);
+
+ zbx_free(value_esc);
+ }
+ }
+
+ for (j = 0; j < host->interfaces.values_num; j++)
+ {
+ interface = (zbx_lld_interface_t *)host->interfaces.values[j];
+
+ if (0 == interface->interfaceid)
+ {
+ interface->interfaceid = interfaceid++;
+
+ zbx_db_insert_add_values(&db_insert_interface, interface->interfaceid, host->hostid,
+ (int)interface->type, (int)interface->main, (int)interface->useip,
+ interface->ip, interface->dns, interface->port, (int)interface->bulk);
+
+ zbx_db_insert_add_values(&db_insert_idiscovery, interface->interfaceid,
+ interface->parent_interfaceid);
+ }
+ else if (0 != (interface->flags & ZBX_FLAG_LLD_INTERFACE_UPDATE))
+ {
+ const char *d = "";
+
+ zbx_strcpy_alloc(&sql1, &sql1_alloc, &sql1_offset, "update interface set ");
+ if (0 != (interface->flags & ZBX_FLAG_LLD_INTERFACE_UPDATE_TYPE))
+ {
+ zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset, "type=%d",
+ (int)interface->type);
+ d = ",";
+ }
+ if (0 != (interface->flags & ZBX_FLAG_LLD_INTERFACE_UPDATE_MAIN))
+ {
+ zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset, "%smain=%d",
+ d, (int)interface->main);
+ d = ",";
+ }
+ if (0 != (interface->flags & ZBX_FLAG_LLD_INTERFACE_UPDATE_USEIP))
+ {
+ zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset, "%suseip=%d",
+ d, (int)interface->useip);
+ d = ",";
+ }
+ if (0 != (interface->flags & ZBX_FLAG_LLD_INTERFACE_UPDATE_IP))
+ {
+ value_esc = DBdyn_escape_string(interface->ip);
+ zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset, "%sip='%s'", d, value_esc);
+ zbx_free(value_esc);
+ d = ",";
+ }
+ if (0 != (interface->flags & ZBX_FLAG_LLD_INTERFACE_UPDATE_DNS))
+ {
+ value_esc = DBdyn_escape_string(interface->dns);
+ zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset, "%sdns='%s'", d, value_esc);
+ zbx_free(value_esc);
+ d = ",";
+ }
+ if (0 != (interface->flags & ZBX_FLAG_LLD_INTERFACE_UPDATE_PORT))
+ {
+ value_esc = DBdyn_escape_string(interface->port);
+ zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset, "%sport='%s'",
+ d, value_esc);
+ zbx_free(value_esc);
+ d = ",";
+ }
+ if (0 != (interface->flags & ZBX_FLAG_LLD_INTERFACE_UPDATE_BULK))
+ {
+ zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset, "%sbulk=%d",
+ d, (int)interface->bulk);
+ }
+ zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset,
+ " where interfaceid=" ZBX_FS_UI64 ";\n", interface->interfaceid);
+ }
+ }
+
+ for (j = 0; j < host->new_groupids.values_num; j++)
+ {
+ zbx_db_insert_add_values(&db_insert_hgroups, hostgroupid++, host->hostid,
+ host->new_groupids.values[j]);
+ }
+
+ for (j = 0; j < host->new_hostmacros.values_num; j++)
+ {
+ hostmacro = (zbx_lld_hostmacro_t *)host->new_hostmacros.values[j];
+
+ value_esc = DBdyn_escape_string(hostmacro->value);
+
+ if (0 == hostmacro->hostmacroid)
+ {
+ zbx_db_insert_add_values(&db_insert_hmacro, hostmacroid++, host->hostid,
+ hostmacro->macro, hostmacro->value);
+ }
+ else
+ {
+ zbx_snprintf_alloc(&sql1, &sql1_alloc, &sql1_offset,
+ "update hostmacro"
+ " set value='%s'"
+ " where hostmacroid=" ZBX_FS_UI64 ";\n",
+ value_esc, hostmacro->hostmacroid);
+ }
+
+ zbx_free(value_esc);
+ }
+ }
+
+ if (0 != new_hosts)
+ {
+ zbx_db_insert_execute(&db_insert);
+ zbx_db_insert_clean(&db_insert);
+
+ zbx_db_insert_execute(&db_insert_hdiscovery);
+ zbx_db_insert_clean(&db_insert_hdiscovery);
+ }
+
+ if (0 != new_host_inventories)
+ {
+ zbx_db_insert_execute(&db_insert_hinventory);
+ zbx_db_insert_clean(&db_insert_hinventory);
+ }
+
+ if (0 != new_hostgroups)
+ {
+ zbx_db_insert_execute(&db_insert_hgroups);
+ zbx_db_insert_clean(&db_insert_hgroups);
+ }
+
+ if (0 != new_hostmacros)
+ {
+ zbx_db_insert_execute(&db_insert_hmacro);
+ zbx_db_insert_clean(&db_insert_hmacro);
+ }
+
+ if (0 != new_interfaces)
+ {
+ zbx_db_insert_execute(&db_insert_interface);
+ zbx_db_insert_clean(&db_insert_interface);
+
+ zbx_db_insert_execute(&db_insert_idiscovery);
+ zbx_db_insert_clean(&db_insert_idiscovery);
+ }
+
+ if (0 != upd_hosts || 0 != upd_interfaces || 0 != upd_hostmacros)
+ {
+ DBend_multiple_update(&sql1, &sql1_alloc, &sql1_offset);
+ DBexecute("%s", sql1);
+ zbx_free(sql1);
+ }
+
+ if (0 != del_hostgroupids->values_num || 0 != del_hostmacroids->values_num ||
+ 0 != upd_host_inventory_hostids.values_num || 0 != del_host_inventory_hostids.values_num ||
+ 0 != del_interfaceids.values_num)
+ {
+ DBbegin_multiple_update(&sql2, &sql2_alloc, &sql2_offset);
+
+ if (0 != del_hostgroupids->values_num)
+ {
+ zbx_strcpy_alloc(&sql2, &sql2_alloc, &sql2_offset, "delete from hosts_groups where");
+ DBadd_condition_alloc(&sql2, &sql2_alloc, &sql2_offset, "hostgroupid",
+ del_hostgroupids->values, del_hostgroupids->values_num);
+ zbx_strcpy_alloc(&sql2, &sql2_alloc, &sql2_offset, ";\n");
+ }
+
+ if (0 != del_hostmacroids->values_num)
+ {
+ zbx_strcpy_alloc(&sql2, &sql2_alloc, &sql2_offset, "delete from hostmacro where");
+ DBadd_condition_alloc(&sql2, &sql2_alloc, &sql2_offset, "hostmacroid",
+ del_hostmacroids->values, del_hostmacroids->values_num);
+ zbx_strcpy_alloc(&sql2, &sql2_alloc, &sql2_offset, ";\n");
+ }
+
+ if (0 != upd_host_inventory_hostids.values_num)
+ {
+ zbx_snprintf_alloc(&sql2, &sql2_alloc, &sql2_offset,
+ "update host_inventory set inventory_mode=%d where", (int)inventory_mode);
+ DBadd_condition_alloc(&sql2, &sql2_alloc, &sql2_offset, "hostid",
+ upd_host_inventory_hostids.values, upd_host_inventory_hostids.values_num);
+ zbx_strcpy_alloc(&sql2, &sql2_alloc, &sql2_offset, ";\n");
+ }
+
+ if (0 != del_host_inventory_hostids.values_num)
+ {
+ zbx_strcpy_alloc(&sql2, &sql2_alloc, &sql2_offset, "delete from host_inventory where");
+ DBadd_condition_alloc(&sql2, &sql2_alloc, &sql2_offset, "hostid",
+ del_host_inventory_hostids.values, del_host_inventory_hostids.values_num);
+ zbx_strcpy_alloc(&sql2, &sql2_alloc, &sql2_offset, ";\n");
+ }
+
+ if (0 != del_interfaceids.values_num)
+ {
+ zbx_strcpy_alloc(&sql2, &sql2_alloc, &sql2_offset, "delete from interface where");
+ DBadd_condition_alloc(&sql2, &sql2_alloc, &sql2_offset, "interfaceid",
+ del_interfaceids.values, del_interfaceids.values_num);
+ zbx_strcpy_alloc(&sql2, &sql2_alloc, &sql2_offset, ";\n");
+ }
+
+ DBend_multiple_update(&sql2, &sql2_alloc, &sql2_offset);
+ DBexecute("%s", sql2);
+ zbx_free(sql2);
+ }
+
+ DBcommit();
+out:
+ zbx_vector_uint64_destroy(&del_interfaceids);
+ zbx_vector_uint64_destroy(&del_host_inventory_hostids);
+ zbx_vector_uint64_destroy(&upd_host_inventory_hostids);
+
+ zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
+}
+
+/******************************************************************************
+ * *
+ * Function: lld_templates_link *
+ * *
+ ******************************************************************************/
+static void lld_templates_link(const zbx_vector_ptr_t *hosts, char **error)
+{
+ const char *__function_name = "lld_templates_link";
+
+ int i;
+ zbx_lld_host_t *host;
+ char *err;
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
+
+ for (i = 0; i < hosts->values_num; i++)
+ {
+ host = (zbx_lld_host_t *)hosts->values[i];
+
+ if (0 == (host->flags & ZBX_FLAG_LLD_HOST_DISCOVERED))
+ continue;
+
+ if (0 != host->del_templateids.values_num)
+ {
+ if (SUCCEED != DBdelete_template_elements(host->hostid, &host->del_templateids, &err))
+ {
+ *error = zbx_strdcatf(*error, "Cannot unlink template: %s.\n", err);
+ zbx_free(err);
+ }
+ }
+
+ if (0 != host->lnk_templateids.values_num)
+ {
+ if (SUCCEED != DBcopy_template_elements(host->hostid, &host->lnk_templateids, &err))
+ {
+ *error = zbx_strdcatf(*error, "Cannot link template(s) %s.\n", err);
+ zbx_free(err);
+ }
+ }
+ }
+
+ zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
+}
+
+/******************************************************************************
+ * *
+ * Function: lld_hosts_remove *
+ * *
+ * Purpose: updates host_discovery.lastcheck and host_discovery.ts_delete *
+ * fields; removes lost resources *
+ * *
+ ******************************************************************************/
+static void lld_hosts_remove(const zbx_vector_ptr_t *hosts, int lifetime, int lastcheck)
+{
+ char *sql = NULL;
+ size_t sql_alloc = 0, sql_offset = 0;
+ const zbx_lld_host_t *host;
+ zbx_vector_uint64_t del_hostids, lc_hostids, ts_hostids;
+ int i;
+
+ if (0 == hosts->values_num)
+ return;
+
+ zbx_vector_uint64_create(&del_hostids);
+ zbx_vector_uint64_create(&lc_hostids);
+ zbx_vector_uint64_create(&ts_hostids);
+
+ DBbegin_multiple_update(&sql, &sql_alloc, &sql_offset);
+
+ for (i = 0; i < hosts->values_num; i++)
+ {
+ host = (zbx_lld_host_t *)hosts->values[i];
+
+ if (0 == host->hostid)
+ continue;
+
+ if (0 == (host->flags & ZBX_FLAG_LLD_HOST_DISCOVERED))
+ {
+ int ts_delete = lld_end_of_life(host->lastcheck, lifetime);
+
+ if (lastcheck > ts_delete)
+ {
+ zbx_vector_uint64_append(&del_hostids, host->hostid);
+ }
+ else if (host->ts_delete != ts_delete)
+ {
+ zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
+ "update host_discovery"
+ " set ts_delete=%d"
+ " where hostid=" ZBX_FS_UI64 ";\n",
+ ts_delete, host->hostid);
+ }
+ }
+ else
+ {
+ zbx_vector_uint64_append(&lc_hostids, host->hostid);
+ if (0 != host->ts_delete)
+ zbx_vector_uint64_append(&ts_hostids, host->hostid);
+ }
+ }
+
+ if (0 != lc_hostids.values_num)
+ {
+ zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "update host_discovery set lastcheck=%d where",
+ lastcheck);
+ DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "hostid",
+ lc_hostids.values, lc_hostids.values_num);
+ zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, ";\n");
+ }
+
+ if (0 != ts_hostids.values_num)
+ {
+ zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "update host_discovery set ts_delete=0 where");
+ DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "hostid",
+ ts_hostids.values, ts_hostids.values_num);
+ zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, ";\n");
+ }
+
+ if (16 < sql_offset) /* in ORACLE always present begin..end; */
+ {
+ DBend_multiple_update(&sql, &sql_alloc, &sql_offset);
+
+ DBbegin();
+
+ DBexecute("%s", sql);
+
+ DBcommit();
+ }
+
+ zbx_free(sql);
+
+ if (0 != del_hostids.values_num)
+ {
+ zbx_vector_uint64_sort(&del_hostids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
+
+ DBbegin();
+
+ DBdelete_hosts(&del_hostids);
+
+ DBcommit();
+ }
+
+ zbx_vector_uint64_destroy(&ts_hostids);
+ zbx_vector_uint64_destroy(&lc_hostids);
+ zbx_vector_uint64_destroy(&del_hostids);
+}
+
+/******************************************************************************
+ * *
+ * Function: lld_groups_remove *
+ * *
+ * Purpose: updates group_discovery.lastcheck and group_discovery.ts_delete *
+ * fields; removes lost resources *
+ * *
+ ******************************************************************************/
+static void lld_groups_remove(const zbx_vector_ptr_t *groups, int lifetime, int lastcheck)
+{
+ char *sql = NULL;
+ size_t sql_alloc = 0, sql_offset = 0;
+ const zbx_lld_group_t *group;
+ zbx_vector_uint64_t del_groupids, lc_groupids, ts_groupids;
+ int i;
+
+ if (0 == groups->values_num)
+ return;
+
+ zbx_vector_uint64_create(&del_groupids);
+ zbx_vector_uint64_create(&lc_groupids);
+ zbx_vector_uint64_create(&ts_groupids);
+
+ DBbegin_multiple_update(&sql, &sql_alloc, &sql_offset);
+
+ for (i = 0; i < groups->values_num; i++)
+ {
+ group = (zbx_lld_group_t *)groups->values[i];
+
+ if (0 == group->groupid)
+ continue;
+
+ if (0 == (group->flags & ZBX_FLAG_LLD_GROUP_DISCOVERED))
+ {
+ int ts_delete = lld_end_of_life(group->lastcheck, lifetime);
+
+ if (lastcheck > ts_delete)
+ {
+ zbx_vector_uint64_append(&del_groupids, group->groupid);
+ }
+ else if (group->ts_delete != ts_delete)
+ {
+ zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
+ "update group_discovery"
+ " set ts_delete=%d"
+ " where groupid=" ZBX_FS_UI64 ";\n",
+ ts_delete, group->groupid);
+ }
+ }
+ else
+ {
+ zbx_vector_uint64_append(&lc_groupids, group->groupid);
+ if (0 != group->ts_delete)
+ zbx_vector_uint64_append(&ts_groupids, group->groupid);
+ }
+ }
+
+ if (0 != lc_groupids.values_num)
+ {
+ zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "update group_discovery set lastcheck=%d where",
+ lastcheck);
+ DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "groupid",
+ lc_groupids.values, lc_groupids.values_num);
+ zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, ";\n");
+ }
+
+ if (0 != ts_groupids.values_num)
+ {
+ zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "update group_discovery set ts_delete=0 where");
+ DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "groupid",
+ ts_groupids.values, ts_groupids.values_num);
+ zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, ";\n");
+ }
+
+ if (16 < sql_offset) /* in ORACLE always present begin..end; */
+ {
+ DBend_multiple_update(&sql, &sql_alloc, &sql_offset);
+
+ DBbegin();
+
+ DBexecute("%s", sql);
+
+ DBcommit();
+ }
+
+ zbx_free(sql);
+
+ if (0 != del_groupids.values_num)
+ {
+ zbx_vector_uint64_sort(&del_groupids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
+
+ DBbegin();
+
+ DBdelete_groups(&del_groupids);
+
+ DBcommit();
+ }
+
+ zbx_vector_uint64_destroy(&ts_groupids);
+ zbx_vector_uint64_destroy(&lc_groupids);
+ zbx_vector_uint64_destroy(&del_groupids);
+}
+
+/******************************************************************************
+ * *
+ * Function: lld_interfaces_get *
+ * *
+ * Purpose: retrieves list of interfaces from the lld rule's host *
+ * *
+ ******************************************************************************/
+static void lld_interfaces_get(zbx_uint64_t lld_ruleid, zbx_vector_ptr_t *interfaces)
+{
+ DB_RESULT result;
+ DB_ROW row;
+ zbx_lld_interface_t *interface;
+
+ result = DBselect(
+ "select hi.interfaceid,hi.type,hi.main,hi.useip,hi.ip,hi.dns,hi.port,hi.bulk"
+ " from interface hi,items i"
+ " where hi.hostid=i.hostid"
+ " and i.itemid=" ZBX_FS_UI64,
+ lld_ruleid);
+
+ while (NULL != (row = DBfetch(result)))
+ {
+ interface = (zbx_lld_interface_t *)zbx_malloc(NULL, sizeof(zbx_lld_interface_t));
+
+ ZBX_STR2UINT64(interface->interfaceid, row[0]);
+ interface->type = (unsigned char)atoi(row[1]);
+ interface->main = (unsigned char)atoi(row[2]);
+ interface->useip = (unsigned char)atoi(row[3]);
+ interface->ip = zbx_strdup(NULL, row[4]);
+ interface->dns = zbx_strdup(NULL, row[5]);
+ interface->port = zbx_strdup(NULL, row[6]);
+ interface->bulk = (unsigned char)atoi(row[7]);
+
+ zbx_vector_ptr_append(interfaces, interface);
+ }
+ DBfree_result(result);
+
+ zbx_vector_ptr_sort(interfaces, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
+}
+
+/******************************************************************************
+ * *
+ * Function: lld_interface_make *
+ * *
+ ******************************************************************************/
+static void 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)
+{
+ zbx_lld_interface_t *interface = NULL;
+ int i;
+
+ for (i = 0; i < interfaces->values_num; i++)
+ {
+ interface = (zbx_lld_interface_t *)interfaces->values[i];
+
+ if (0 != interface->interfaceid)
+ continue;
+
+ if (interface->parent_interfaceid == parent_interfaceid)
+ break;
+ }
+
+ if (i == interfaces->values_num)
+ {
+ /* interface which should be deleted */
+ interface = (zbx_lld_interface_t *)zbx_malloc(NULL, sizeof(zbx_lld_interface_t));
+
+ interface->interfaceid = interfaceid;
+ interface->parent_interfaceid = 0;
+ interface->type = type;
+ interface->main = main;
+ interface->useip = 0;
+ interface->ip = NULL;
+ interface->dns = NULL;
+ interface->port = NULL;
+ interface->bulk = SNMP_BULK_ENABLED;
+ interface->flags = ZBX_FLAG_LLD_INTERFACE_REMOVE;
+
+ zbx_vector_ptr_append(interfaces, interface);
+ }
+ else
+ {
+ /* interface which are already added */
+ if (interface->type != type)
+ {
+ interface->type_orig = type;
+ interface->flags |= ZBX_FLAG_LLD_INTERFACE_UPDATE_TYPE;
+ }
+ if (interface->main != main)
+ {
+ interface->main_orig = main;
+ interface->flags |= ZBX_FLAG_LLD_INTERFACE_UPDATE_MAIN;
+ }
+ if (interface->useip != useip)
+ interface->flags |= ZBX_FLAG_LLD_INTERFACE_UPDATE_USEIP;
+ if (0 != strcmp(interface->ip, ip))
+ interface->flags |= ZBX_FLAG_LLD_INTERFACE_UPDATE_IP;
+ if (0 != strcmp(interface->dns, dns))
+ interface->flags |= ZBX_FLAG_LLD_INTERFACE_UPDATE_DNS;
+ if (0 != strcmp(interface->port, port))
+ interface->flags |= ZBX_FLAG_LLD_INTERFACE_UPDATE_PORT;
+ if (interface->bulk != bulk)
+ interface->flags |= ZBX_FLAG_LLD_INTERFACE_UPDATE_BULK;
+ }
+
+ interface->interfaceid = interfaceid;
+}
+
+/******************************************************************************
+ * *
+ * Function: lld_interfaces_make *
+ * *
+ * Parameters: interfaces - [IN] sorted list of interfaces which *
+ * should be present on the each *
+ * discovered host *
+ * hosts - [IN/OUT] sorted list of hosts *
+ * *
+ ******************************************************************************/
+static void lld_interfaces_make(const zbx_vector_ptr_t *interfaces, zbx_vector_ptr_t *hosts)
+{
+ const char *__function_name = "lld_interfaces_make";
+
+ DB_RESULT result;
+ DB_ROW row;
+ int i, j;
+ zbx_vector_uint64_t hostids;
+ zbx_uint64_t parent_interfaceid, hostid, interfaceid;
+ zbx_lld_host_t *host;
+ zbx_lld_interface_t *new_interface, *interface;
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
+
+ zbx_vector_uint64_create(&hostids);
+
+ for (i = 0; i < hosts->values_num; i++)
+ {
+ host = (zbx_lld_host_t *)hosts->values[i];
+
+ if (0 == (host->flags & ZBX_FLAG_LLD_HOST_DISCOVERED))
+ continue;
+
+ zbx_vector_ptr_reserve(&host->interfaces, interfaces->values_num);
+ for (j = 0; j < interfaces->values_num; j++)
+ {
+ interface = (zbx_lld_interface_t *)interfaces->values[j];
+
+ new_interface = (zbx_lld_interface_t *)zbx_malloc(NULL, sizeof(zbx_lld_interface_t));
+
+ new_interface->interfaceid = 0;
+ new_interface->parent_interfaceid = interface->interfaceid;
+ new_interface->type = interface->type;
+ new_interface->main = interface->main;
+ new_interface->useip = interface->useip;
+ new_interface->ip = zbx_strdup(NULL, interface->ip);
+ new_interface->dns = zbx_strdup(NULL, interface->dns);
+ new_interface->port = zbx_strdup(NULL, interface->port);
+ new_interface->bulk = interface->bulk;
+ new_interface->flags = 0x00;
+
+ zbx_vector_ptr_append(&host->interfaces, new_interface);
+ }
+
+ if (0 != host->hostid)
+ zbx_vector_uint64_append(&hostids, host->hostid);
+ }
+
+ if (0 != hostids.values_num)
+ {
+ char *sql = NULL;
+ size_t sql_alloc = 0, sql_offset = 0;
+
+ zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset,
+ "select hi.hostid,id.parent_interfaceid,hi.interfaceid,hi.type,hi.main,hi.useip,hi.ip,"
+ "hi.dns,hi.port,hi.bulk"
+ " from interface hi"
+ " left join interface_discovery id"
+ " on hi.interfaceid=id.interfaceid"
+ " where");
+ DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "hi.hostid", hostids.values, hostids.values_num);
+
+ result = DBselect("%s", sql);
+
+ zbx_free(sql);
+
+ while (NULL != (row = DBfetch(result)))
+ {
+ ZBX_STR2UINT64(hostid, row[0]);
+ ZBX_DBROW2UINT64(parent_interfaceid, row[1]);
+ ZBX_DBROW2UINT64(interfaceid, row[2]);
+
+ if (FAIL == (i = zbx_vector_ptr_bsearch(hosts, &hostid, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC)))
+ {
+ THIS_SHOULD_NEVER_HAPPEN;
+ continue;
+ }
+
+ host = (zbx_lld_host_t *)hosts->values[i];
+
+ lld_interface_make(&host->interfaces, parent_interfaceid, interfaceid,
+ (unsigned char)atoi(row[3]), (unsigned char)atoi(row[4]),
+ (unsigned char)atoi(row[5]), row[6], row[7], row[8],
+ (unsigned char)atoi(row[9]));
+ }
+ DBfree_result(result);
+ }
+
+ zbx_vector_uint64_destroy(&hostids);
+
+ zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
+}
+
+/******************************************************************************
+ * *
+ * Function: another_main_interface_exists *
+ * *
+ * Return value: SUCCEED if interface with same type exists in the list of *
+ * interfaces; FAIL - otherwise *
+ * *
+ * Comments: interfaces with ZBX_FLAG_LLD_INTERFACE_REMOVE flag are ignored *
+ * auxiliary function for lld_interfaces_validate() *
+ * *
+ ******************************************************************************/
+static int another_main_interface_exists(const zbx_vector_ptr_t *interfaces, const zbx_lld_interface_t *interface)
+{
+ const zbx_lld_interface_t *interface_b;
+ int i;
+
+ for (i = 0; i < interfaces->values_num; i++)
+ {
+ interface_b = (zbx_lld_interface_t *)interfaces->values[i];
+
+ if (interface_b == interface)
+ continue;
+
+ if (0 != (interface_b->flags & ZBX_FLAG_LLD_INTERFACE_REMOVE))
+ continue;
+
+ if (interface_b->type != interface->type)
+ continue;
+
+ if (1 == interface_b->main)
+ return SUCCEED;
+ }
+
+ return FAIL;
+}
+
+/******************************************************************************
+ * *
+ * Function: lld_interfaces_validate *
+ * *
+ * Parameters: hosts - [IN/OUT] list of hosts *
+ * *
+ ******************************************************************************/
+static void lld_interfaces_validate(zbx_vector_ptr_t *hosts, char **error)
+{
+ const char *__function_name = "lld_interfaces_validate";
+
+ DB_RESULT result;
+ DB_ROW row;
+ int i, j;
+ zbx_vector_uint64_t interfaceids;
+ zbx_uint64_t interfaceid;
+ zbx_lld_host_t *host;
+ zbx_lld_interface_t *interface;
+ unsigned char type;
+ char *sql = NULL;
+ size_t sql_alloc = 0, sql_offset = 0;
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
+
+ /* validate changed types */
+
+ zbx_vector_uint64_create(&interfaceids);
+
+ for (i = 0; i < hosts->values_num; i++)
+ {
+ host = (zbx_lld_host_t *)hosts->values[i];
+
+ for (j = 0; j < host->interfaces.values_num; j++)
+ {
+ interface = (zbx_lld_interface_t *)host->interfaces.values[j];
+
+ if (0 == (interface->flags & ZBX_FLAG_LLD_INTERFACE_UPDATE_TYPE))
+ continue;
+
+ zbx_vector_uint64_append(&interfaceids, interface->interfaceid);
+ }
+ }
+
+ if (0 != interfaceids.values_num)
+ {
+ zbx_vector_uint64_sort(&interfaceids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
+
+ zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "select interfaceid,type from items where");
+ DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "interfaceid",
+ interfaceids.values, interfaceids.values_num);
+ zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, " group by interfaceid,type");
+
+ result = DBselect("%s", sql);
+
+ while (NULL != (row = DBfetch(result)))
+ {
+ type = get_interface_type_by_item_type((unsigned char)atoi(row[1]));
+
+ if (type != INTERFACE_TYPE_ANY && type != INTERFACE_TYPE_UNKNOWN)
+ {
+ ZBX_STR2UINT64(interfaceid, row[0]);
+
+ for (i = 0; i < hosts->values_num; i++)
+ {
+ host = (zbx_lld_host_t *)hosts->values[i];
+
+ for (j = 0; j < host->interfaces.values_num; j++)
+ {
+ interface = (zbx_lld_interface_t *)host->interfaces.values[j];
+
+ if (0 == (interface->flags & ZBX_FLAG_LLD_INTERFACE_UPDATE_TYPE))
+ continue;
+
+ if (interface->interfaceid != interfaceid)
+ continue;
+
+ *error = zbx_strdcatf(*error,
+ "Cannot update \"%s\" interface on host \"%s\":"
+ " the interface is used by items.\n",
+ zbx_interface_type_string(interface->type_orig),
+ host->host);
+
+ /* return an original interface type and drop the correspond flag */
+ interface->type = interface->type_orig;
+ interface->flags &= ~ZBX_FLAG_LLD_INTERFACE_UPDATE_TYPE;
+ }
+ }
+ }
+ }
+ DBfree_result(result);
+ }
+
+ /* validate interfaces which should be deleted */
+
+ zbx_vector_uint64_clear(&interfaceids);
+
+ for (i = 0; i < hosts->values_num; i++)
+ {
+ host = (zbx_lld_host_t *)hosts->values[i];
+
+ for (j = 0; j < host->interfaces.values_num; j++)
+ {
+ interface = (zbx_lld_interface_t *)host->interfaces.values[j];
+
+ if (0 == (interface->flags & ZBX_FLAG_LLD_INTERFACE_REMOVE))
+ continue;
+
+ zbx_vector_uint64_append(&interfaceids, interface->interfaceid);
+ }
+ }
+
+ if (0 != interfaceids.values_num)
+ {
+ zbx_vector_uint64_sort(&interfaceids, ZBX_DEFAULT_UINT64_COMPARE_FUNC);
+
+ sql_offset = 0;
+ zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, "select interfaceid from items where");
+ DBadd_condition_alloc(&sql, &sql_alloc, &sql_offset, "interfaceid",
+ interfaceids.values, interfaceids.values_num);
+ zbx_strcpy_alloc(&sql, &sql_alloc, &sql_offset, " group by interfaceid");
+
+ result = DBselect("%s", sql);
+
+ while (NULL != (row = DBfetch(result)))
+ {
+ ZBX_STR2UINT64(interfaceid, row[0]);
+
+ for (i = 0; i < hosts->values_num; i++)
+ {
+ host = (zbx_lld_host_t *)hosts->values[i];
+
+ for (j = 0; j < host->interfaces.values_num; j++)
+ {
+ interface = (zbx_lld_interface_t *)host->interfaces.values[j];
+
+ if (0 == (interface->flags & ZBX_FLAG_LLD_INTERFACE_REMOVE))
+ continue;
+
+ if (interface->interfaceid != interfaceid)
+ continue;
+
+ *error = zbx_strdcatf(*error, "Cannot delete \"%s\" interface on host \"%s\":"
+ " the interface is used by items.\n",
+ zbx_interface_type_string(interface->type), host->host);
+
+ /* drop the correspond flag */
+ interface->flags &= ~ZBX_FLAG_LLD_INTERFACE_REMOVE;
+
+ if (SUCCEED == another_main_interface_exists(&host->interfaces, interface))
+ {
+ if (1 == interface->main)
+ {
+ /* drop main flag */
+ interface->main_orig = interface->main;
+ interface->main = 0;
+ interface->flags |= ZBX_FLAG_LLD_INTERFACE_UPDATE_MAIN;
+ }
+ }
+ else if (1 != interface->main)
+ {
+ /* set main flag */
+ interface->main_orig = interface->main;
+ interface->main = 1;
+ interface->flags |= ZBX_FLAG_LLD_INTERFACE_UPDATE_MAIN;
+ }
+ }
+ }
+ }
+ DBfree_result(result);
+ }
+
+ zbx_vector_uint64_destroy(&interfaceids);
+
+ zbx_free(sql);
+
+ zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
+}
+
+/******************************************************************************
+ * *
+ * Function: lld_update_hosts *
+ * *
+ * Purpose: add or update low-level discovered hosts *
+ * *
+ ******************************************************************************/
+void lld_update_hosts(zbx_uint64_t lld_ruleid, const zbx_vector_ptr_t *lld_rows,
+ const zbx_vector_ptr_t *lld_macro_paths, char **error, int lifetime, int lastcheck)
+{
+ const char *__function_name = "lld_update_hosts";
+
+ DB_RESULT result;
+ DB_ROW row;
+ zbx_vector_ptr_t hosts, group_prototypes, groups, interfaces, hostmacros;
+ zbx_vector_uint64_t groupids; /* list of host groups which should be added */
+ zbx_vector_uint64_t del_hostgroupids; /* list of host groups which should be deleted */
+ zbx_vector_uint64_t del_hostmacroids; /* list of host macros which should be deleted */
+ zbx_uint64_t proxy_hostid;
+ char *ipmi_username = NULL, *ipmi_password, *tls_issuer, *tls_subject, *tls_psk_identity,
+ *tls_psk;
+ char ipmi_authtype, inventory_mode;
+ unsigned char ipmi_privilege, tls_connect, tls_accept;
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
+
+ result = DBselect(
+ "select h.proxy_hostid,h.ipmi_authtype,h.ipmi_privilege,h.ipmi_username,h.ipmi_password,"
+ "h.tls_connect,h.tls_accept,h.tls_issuer,h.tls_subject,h.tls_psk_identity,h.tls_psk"
+ " from hosts h,items i"
+ " where h.hostid=i.hostid"
+ " and i.itemid=" ZBX_FS_UI64,
+ lld_ruleid);
+
+ if (NULL != (row = DBfetch(result)))
+ {
+ ZBX_DBROW2UINT64(proxy_hostid, row[0]);
+ ipmi_authtype = (char)atoi(row[1]);
+ ZBX_STR2UCHAR(ipmi_privilege, row[2]);
+ ipmi_username = zbx_strdup(NULL, row[3]);
+ ipmi_password = zbx_strdup(NULL, row[4]);
+
+ ZBX_STR2UCHAR(tls_connect, row[5]);
+ ZBX_STR2UCHAR(tls_accept, row[6]);
+ tls_issuer = zbx_strdup(NULL, row[7]);
+ tls_subject = zbx_strdup(NULL, row[8]);
+ tls_psk_identity = zbx_strdup(NULL, row[9]);
+ tls_psk = zbx_strdup(NULL, row[10]);
+ }
+ DBfree_result(result);
+
+ if (NULL == row)
+ {
+ *error = zbx_strdcatf(*error, "Cannot process host prototypes: a parent host not found.\n");
+ return;
+ }
+
+ zbx_vector_ptr_create(&hosts);
+ zbx_vector_uint64_create(&groupids);
+ zbx_vector_ptr_create(&group_prototypes);
+ zbx_vector_ptr_create(&groups);
+ zbx_vector_uint64_create(&del_hostgroupids);
+ zbx_vector_uint64_create(&del_hostmacroids);
+ zbx_vector_ptr_create(&interfaces);
+ zbx_vector_ptr_create(&hostmacros);
+
+ lld_interfaces_get(lld_ruleid, &interfaces);
+ lld_hostmacros_get(lld_ruleid, &hostmacros);
+
+ result = DBselect(
+ "select h.hostid,h.host,h.name,h.status,hi.inventory_mode"
+ " from hosts h,host_discovery hd"
+ " left join host_inventory hi"
+ " on hd.hostid=hi.hostid"
+ " where h.hostid=hd.hostid"
+ " and hd.parent_itemid=" ZBX_FS_UI64,
+ lld_ruleid);
+
+ while (NULL != (row = DBfetch(result)))
+ {
+ zbx_uint64_t parent_hostid;
+ const char *host_proto, *name_proto;
+ zbx_lld_host_t *host;
+ unsigned char status;
+ int i;
+
+ ZBX_STR2UINT64(parent_hostid, row[0]);
+ host_proto = row[1];
+ name_proto = row[2];
+ status = (unsigned char)atoi(row[3]);
+ if (SUCCEED == DBis_null(row[4]))
+ inventory_mode = HOST_INVENTORY_DISABLED;
+ else
+ inventory_mode = (char)atoi(row[4]);
+
+ lld_hosts_get(parent_hostid, &hosts, proxy_hostid, ipmi_authtype, ipmi_privilege, ipmi_username,
+ ipmi_password, tls_connect, tls_accept, tls_issuer, tls_subject,
+ tls_psk_identity, tls_psk);
+
+ lld_simple_groups_get(parent_hostid, &groupids);
+
+ lld_group_prototypes_get(parent_hostid, &group_prototypes);
+ lld_groups_get(parent_hostid, &groups);
+
+ for (i = 0; i < lld_rows->values_num; i++)
+ {
+ const zbx_lld_row_t *lld_row = (zbx_lld_row_t *)lld_rows->values[i];
+
+ host = lld_host_make(&hosts, host_proto, name_proto, &lld_row->jp_row, lld_macro_paths);
+ lld_groups_make(host, &groups, &group_prototypes, &lld_row->jp_row, lld_macro_paths);
+ }
+
+ zbx_vector_ptr_sort(&hosts, ZBX_DEFAULT_UINT64_PTR_COMPARE_FUNC);
+
+ lld_groups_validate(&groups, error);
+ lld_hosts_validate(&hosts, error);
+
+ lld_interfaces_make(&interfaces, &hosts);
+ lld_interfaces_validate(&hosts, error);
+
+ lld_hostgroups_make(&groupids, &hosts, &groups, &del_hostgroupids);
+ lld_templates_make(parent_hostid, &hosts);
+ lld_hostmacros_make(&hostmacros, &hosts, &del_hostmacroids);
+
+ lld_groups_save(&groups, &group_prototypes);
+ lld_hosts_save(parent_hostid, &hosts, host_proto, proxy_hostid, ipmi_authtype, ipmi_privilege,
+ ipmi_username, ipmi_password, status, inventory_mode, tls_connect, tls_accept,
+ tls_issuer, tls_subject, tls_psk_identity, tls_psk, &del_hostgroupids,
+ &del_hostmacroids);
+
+ /* linking of the templates */
+ lld_templates_link(&hosts, error);
+
+ lld_hosts_remove(&hosts, lifetime, lastcheck);
+ lld_groups_remove(&groups, lifetime, lastcheck);
+
+ zbx_vector_ptr_clear_ext(&groups, (zbx_clean_func_t)lld_group_free);
+ zbx_vector_ptr_clear_ext(&group_prototypes, (zbx_clean_func_t)lld_group_prototype_free);
+ zbx_vector_ptr_clear_ext(&hosts, (zbx_clean_func_t)lld_host_free);
+
+ zbx_vector_uint64_clear(&groupids);
+ zbx_vector_uint64_clear(&del_hostgroupids);
+ zbx_vector_uint64_clear(&del_hostmacroids);
+ }
+ DBfree_result(result);
+
+ zbx_vector_ptr_clear_ext(&hostmacros, (zbx_clean_func_t)lld_hostmacro_free);
+ zbx_vector_ptr_clear_ext(&interfaces, (zbx_clean_func_t)lld_interface_free);
+
+ zbx_vector_ptr_destroy(&hostmacros);
+ zbx_vector_ptr_destroy(&interfaces);
+ zbx_vector_uint64_destroy(&del_hostmacroids);
+ zbx_vector_uint64_destroy(&del_hostgroupids);
+ zbx_vector_ptr_destroy(&groups);
+ zbx_vector_ptr_destroy(&group_prototypes);
+ zbx_vector_uint64_destroy(&groupids);
+ zbx_vector_ptr_destroy(&hosts);
+
+ zbx_free(tls_psk);
+ zbx_free(tls_psk_identity);
+ zbx_free(tls_subject);
+ zbx_free(tls_issuer);
+ zbx_free(ipmi_password);
+ zbx_free(ipmi_username);
+
+ zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
+}