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
path: root/src
diff options
context:
space:
mode:
authorAndrejs Kozlovs <andrejs.kozlovs@zabbix.com>2022-11-09 10:54:18 +0300
committerAndrejs Kozlovs <andrejs.kozlovs@zabbix.com>2022-11-09 10:54:18 +0300
commit39d00691a0a0af2b4de3dfc33a2509e773478f8e (patch)
tree861173b9f07cb6c4c562a6f2fa3190b01d4895b2 /src
parent5887066f5624d9a8d4af3f836fae505569ad8aad (diff)
parentd136fbbbe6cd01ae26c017e4750ce2b830a907ee (diff)
.......... [DEV-2135] updated from branch 'master' of ssh://git.zabbix.com:7999/zbx/zabbix into feature/DEV-2135-6.3-1
Diffstat (limited to 'src')
-rw-r--r--src/go/pkg/version/version.go4
-rw-r--r--src/go/pkg/zbxlib/globals_windows.go8
-rw-r--r--src/libs/Makefile.am3
-rw-r--r--src/libs/zbxdbupgrade/dbupgrade_6030.c88
-rw-r--r--src/libs/zbxjson/Makefile.am4
-rw-r--r--src/libs/zbxjson/json.c14
-rw-r--r--src/libs/zbxjson/json.h2
-rw-r--r--src/libs/zbxjson/json_parser.c127
-rw-r--r--src/libs/zbxjson/json_parser.h8
-rw-r--r--src/libs/zbxjson/jsonobj.c366
-rw-r--r--src/libs/zbxjson/jsonobj.h56
-rw-r--r--src/libs/zbxjson/jsonpath.c1297
-rw-r--r--src/libs/zbxjson/jsonpath.h21
-rw-r--r--src/libs/zbxnum/num.c2
-rw-r--r--src/libs/zbxsysinfo/common/dir.c4
-rw-r--r--src/libs/zbxsysinfo/common/system.c6
-rw-r--r--src/libs/zbxsysinfo/linux/diskio.c2
-rw-r--r--src/libs/zbxsysinfo/linux/hardware.c7
-rw-r--r--src/libs/zbxsysinfo/linux/proc.c5
-rw-r--r--src/libs/zbxsysinfo/sysinfo.h8
-rw-r--r--src/libs/zbxsysinfo/win32/pdhmon.c2
-rw-r--r--src/libs/zbxsysinfo/win32/proc.c5
-rw-r--r--src/libs/zbxsysinfo/win32/services.c27
-rw-r--r--src/libs/zbxsysinfo/win32/system.c2
-rw-r--r--src/libs/zbxsysinfo/win32/uptime.c6
-rw-r--r--src/libs/zbxsysinfo/win32/win32.c8
-rw-r--r--src/libs/zbxwin32/disk.c4
-rw-r--r--src/libs/zbxwin32/fatal.c65
-rw-r--r--src/libs/zbxwin32/perfmon.c29
-rw-r--r--src/libs/zbxwinservice/service.c (renamed from src/libs/zbxwin32/service.c)8
-rw-r--r--src/zabbix_agent/Makefile.am2
-rw-r--r--src/zabbix_agent/cpustat.c12
-rw-r--r--src/zabbix_agent/cpustat.h2
-rw-r--r--src/zabbix_agent/perfstat.c10
-rw-r--r--src/zabbix_agent/perfstat.h2
-rw-r--r--src/zabbix_agent/zabbix_agentd.c19
-rw-r--r--src/zabbix_agent/zbxconf.c2
-rw-r--r--src/zabbix_java/src/com/zabbix/gateway/GeneralInformation.java4
-rw-r--r--src/zabbix_server/Makefile.am2
-rw-r--r--src/zabbix_server/poller/checks_simple_vmware.c4
-rw-r--r--src/zabbix_server/preprocessor/item_preproc.c73
-rw-r--r--src/zabbix_server/preprocessor/preproc_cache.c5
-rw-r--r--src/zabbix_server/vmware/vmware.c678
-rw-r--r--src/zabbix_server/vmware/vmware.h1
-rw-r--r--src/zabbix_server/vmware/vmware_rest.c4
45 files changed, 2102 insertions, 906 deletions
diff --git a/src/go/pkg/version/version.go b/src/go/pkg/version/version.go
index faa436d3db6..b66e3e2fba1 100644
--- a/src/go/pkg/version/version.go
+++ b/src/go/pkg/version/version.go
@@ -26,11 +26,11 @@ import (
)
const (
- ZABBIX_REVDATE = "27 October 2022"
+ ZABBIX_REVDATE = "8 November 2022"
ZABBIX_VERSION_MAJOR = 6
ZABBIX_VERSION_MINOR = 4
ZABBIX_VERSION_PATCH = 0
- ZABBIX_VERSION_RC = "beta3"
+ ZABBIX_VERSION_RC = "beta4"
ZABBIX_VERSION_RC_NUM = "{ZABBIX_RC_NUM}"
ZABBIX_VERSION_REVISION = "{ZABBIX_REVISION}"
copyrightMessage = "Copyright (C) 2022 Zabbix SIA\n" +
diff --git a/src/go/pkg/zbxlib/globals_windows.go b/src/go/pkg/zbxlib/globals_windows.go
index c0883a12b63..f01106f489f 100644
--- a/src/go/pkg/zbxlib/globals_windows.go
+++ b/src/go/pkg/zbxlib/globals_windows.go
@@ -23,7 +23,7 @@ package zbxlib
#include "zbxstr.h"
#include "zbxsysinfo.h"
#include "zbxcomms.h"
-#include "perfmon.h"
+#include "zbxwin32.h"
#include "../src/zabbix_agent/metrics.h"
#cgo LDFLAGS: -Wl,--start-group
@@ -49,6 +49,7 @@ package zbxlib
#cgo LDFLAGS: ${SRCDIR}/../../../../build/mingw/output/md5.o
#cgo LDFLAGS: ${SRCDIR}/../../../../build/mingw/output/sysinfo.o
#cgo LDFLAGS: ${SRCDIR}/../../../../build/mingw/output/vector.o
+#cgo LDFLAGS: ${SRCDIR}/../../../../build/mingw/output/hashset.o
#cgo LDFLAGS: ${SRCDIR}/../../../../build/mingw/output/zbxregexp.o
#cgo LDFLAGS: ${SRCDIR}/../../../../build/mingw/output/algodefs.o
#cgo LDFLAGS: ${SRCDIR}/../../../../build/mingw/output/persistent_state.o
@@ -56,6 +57,7 @@ package zbxlib
#cgo LDFLAGS: ${SRCDIR}/../../../../build/mingw/output/json.o
#cgo LDFLAGS: ${SRCDIR}/../../../../build/mingw/output/json_parser.o
#cgo LDFLAGS: ${SRCDIR}/../../../../build/mingw/output/jsonpath.o
+#cgo LDFLAGS: ${SRCDIR}/../../../../build/mingw/output/jsonobj.o
#cgo LDFLAGS: ${SRCDIR}/../../../../build/mingw/output/sha256crypt.o
#cgo LDFLAGS: ${SRCDIR}/../../../../build/mingw/output/variant.o
#cgo LDFLAGS: ${SRCDIR}/../../../../build/mingw/output/sysinfo_system.o
@@ -121,12 +123,12 @@ int perf_counter(AGENT_REQUEST *request, AGENT_RESULT *result)
return SYSINFO_RET_FAIL;
}
-DWORD get_builtin_counter_index(zbx_builtin_counter_ref_t counter_ref)
+DWORD zbx_get_builtin_counter_index(zbx_builtin_counter_ref_t counter_ref)
{
return 0;
}
-DWORD get_builtin_object_index(zbx_builtin_counter_ref_t object_ref)
+DWORD zbx_get_builtin_object_index(zbx_builtin_counter_ref_t object_ref)
{
return 0;
}
diff --git a/src/libs/Makefile.am b/src/libs/Makefile.am
index f84b08af7a0..ed18d3c695a 100644
--- a/src/libs/Makefile.am
+++ b/src/libs/Makefile.am
@@ -189,4 +189,5 @@ SUBDIRS = \
EXTRA_DIST = \
zbxsymbols \
- zbxwin32
+ zbxwin32 \
+ zbxwinservice
diff --git a/src/libs/zbxdbupgrade/dbupgrade_6030.c b/src/libs/zbxdbupgrade/dbupgrade_6030.c
index a5313d6bb5c..5a0499ec53d 100644
--- a/src/libs/zbxdbupgrade/dbupgrade_6030.c
+++ b/src/libs/zbxdbupgrade/dbupgrade_6030.c
@@ -476,6 +476,92 @@ static int DBpatch_6030061(void)
return DBmodify_field_type("triggers", &field, NULL);
}
+static int DBpatch_6030062(void)
+{
+ DB_RESULT result;
+ DB_ROW row;
+ char *sql;
+ size_t sql_alloc = 4096, sql_offset = 0;
+ int ret = SUCCEED;
+
+ if (0 == (program_type & ZBX_PROGRAM_TYPE_SERVER))
+ return SUCCEED;
+
+ sql = zbx_malloc(NULL, sql_alloc);
+
+ zbx_DBbegin_multiple_update(&sql, &sql_alloc, &sql_offset);
+
+ result = DBselect("select moduleid,relative_path from module");
+
+ while (NULL != (row = DBfetch(result)))
+ {
+ const char *rel_path = row[1];
+ char *updated_path, *updated_path_esc;
+
+ if (NULL == rel_path || '\0' == *rel_path)
+ continue;
+
+ updated_path = zbx_dsprintf(NULL, "modules/%s", rel_path);
+
+ updated_path_esc = DBdyn_escape_string(updated_path);
+
+ zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, "update module set relative_path='%s' "
+ "where moduleid=%s;\n", updated_path_esc, row[0]);
+
+ zbx_free(updated_path);
+ zbx_free(updated_path_esc);
+
+ ret = DBexecute_overflowed_sql(&sql, &sql_alloc, &sql_offset);
+ }
+ DBfree_result(result);
+
+ zbx_DBend_multiple_update(&sql, &sql_alloc, &sql_offset);
+
+ if (SUCCEED == ret && 16 < sql_offset)
+ {
+ if (ZBX_DB_OK > DBexecute("%s", sql))
+ ret = FAIL;
+ }
+
+ zbx_free(sql);
+
+ return ret;
+}
+
+static int DBpatch_6030063(void)
+{
+ zbx_db_insert_t db_insert;
+ int i, ret = FAIL;
+
+ const char *modules[] = {
+ "actionlog", "clock", "dataover", "discovery", "favgraphs", "favmaps", "geomap", "graph",
+ "graphprototype", "hostavail", "item", "map", "navtree", "plaintext", "problemhosts",
+ "problems", "problemsbysv", "slareport", "svggraph", "systeminfo", "tophosts", "trigover",
+ "url", "web"
+ };
+
+ if (0 == (program_type & ZBX_PROGRAM_TYPE_SERVER))
+ return SUCCEED;
+
+ zbx_db_insert_prepare(&db_insert, "module", "moduleid", "id", "relative_path", "status", "config", NULL);
+
+ for (i = 0; i < (int)ARRSIZE(modules); i++)
+ {
+ char *path;
+
+ path = zbx_dsprintf(NULL, "widgets/%s", modules[i]);
+ zbx_db_insert_add_values(&db_insert, __UINT64_C(0), modules[i], path, 1, "[]");
+ zbx_free(path);
+ }
+
+ zbx_db_insert_autoincrement(&db_insert, "moduleid");
+ ret = zbx_db_insert_execute(&db_insert);
+
+ zbx_db_insert_clean(&db_insert);
+
+ return ret;
+}
+
#endif
DBPATCH_START(6030)
@@ -544,5 +630,7 @@ DBPATCH_ADD(6030058, 0, 1)
DBPATCH_ADD(6030059, 0, 1)
DBPATCH_ADD(6030060, 0, 1)
DBPATCH_ADD(6030061, 0, 1)
+DBPATCH_ADD(6030062, 0, 1)
+DBPATCH_ADD(6030063, 0, 1)
DBPATCH_END()
diff --git a/src/libs/zbxjson/Makefile.am b/src/libs/zbxjson/Makefile.am
index ad27f80c98e..f7981730a30 100644
--- a/src/libs/zbxjson/Makefile.am
+++ b/src/libs/zbxjson/Makefile.am
@@ -8,4 +8,6 @@ libzbxjson_a_SOURCES = \
json_parser.c \
json_parser.h \
jsonpath.c \
- jsonpath.h
+ jsonpath.h \
+ jsonobj.c \
+ jsonobj.h
diff --git a/src/libs/zbxjson/json.c b/src/libs/zbxjson/json.c
index e819f23e892..539c4d834bc 100644
--- a/src/libs/zbxjson/json.c
+++ b/src/libs/zbxjson/json.c
@@ -841,7 +841,7 @@ static unsigned int zbx_json_decode_character(const char **p, unsigned char *byt
* string copying failed. *
* *
******************************************************************************/
-static const char *zbx_json_copy_string(const char *p, char *out, size_t size)
+const char *json_copy_string(const char *p, char *out, size_t size)
{
char *start = out;
@@ -920,7 +920,7 @@ const char *zbx_json_decodevalue(const char *p, char *string, size_t size, zbx_j
/* only primitive values are decoded */
return NULL;
default:
- if (0 == (len = json_parse_value(p, NULL)))
+ if (0 == (len = json_parse_value(p, NULL, NULL)))
return NULL;
}
@@ -930,7 +930,7 @@ const char *zbx_json_decodevalue(const char *p, char *string, size_t size, zbx_j
switch (type_local)
{
case ZBX_JSON_TYPE_STRING:
- return zbx_json_copy_string(p, string, size);
+ return json_copy_string(p, string, size);
case ZBX_JSON_TYPE_NULL:
if (0 == size)
return NULL;
@@ -954,7 +954,7 @@ const char *zbx_json_decodevalue_dyn(const char *p, char **string, size_t *strin
/* only primitive values are decoded */
return NULL;
default:
- if (0 == (len = json_parse_value(p, NULL)))
+ if (0 == (len = json_parse_value(p, NULL, NULL)))
return NULL;
}
@@ -970,7 +970,7 @@ const char *zbx_json_decodevalue_dyn(const char *p, char **string, size_t *strin
switch (type_local)
{
case ZBX_JSON_TYPE_STRING:
- return zbx_json_copy_string(p, *string, *string_alloc);
+ return json_copy_string(p, *string, *string_alloc);
case ZBX_JSON_TYPE_NULL:
**string = '\0';
return p + len;
@@ -987,7 +987,7 @@ const char *zbx_json_pair_next(const struct zbx_json_parse *jp, const char *p, c
if (ZBX_JSON_TYPE_STRING != __zbx_json_type(p))
return NULL;
- if (NULL == (p = zbx_json_copy_string(p, name, len)))
+ if (NULL == (p = json_copy_string(p, name, len)))
return NULL;
SKIP_WHITESPACE(p);
@@ -1219,7 +1219,7 @@ int zbx_json_open_path(const struct zbx_json_parse *jp, const char *path, struct
object.start = p;
if (NULL == (object.end = __zbx_json_rbracket(p)))
- object.end = p + json_parse_value(p, NULL) - 1;
+ object.end = p + json_parse_value(p, NULL, NULL) - 1;
}
*out = object;
diff --git a/src/libs/zbxjson/json.h b/src/libs/zbxjson/json.h
index e0c02e174ab..27006bc5f01 100644
--- a/src/libs/zbxjson/json.h
+++ b/src/libs/zbxjson/json.h
@@ -32,4 +32,6 @@
void zbx_set_json_strerror(const char *fmt, ...) __zbx_attr_format_printf(1, 2);
+const char *json_copy_string(const char *p, char *out, size_t size);
+
#endif
diff --git a/src/libs/zbxjson/json_parser.c b/src/libs/zbxjson/json_parser.c
index 403a3ca2753..0ea71203ec8 100644
--- a/src/libs/zbxjson/json_parser.c
+++ b/src/libs/zbxjson/json_parser.c
@@ -21,27 +21,31 @@
#include "zbxcommon.h"
#include "json.h"
-
-static zbx_int64_t json_parse_object(const char *start, char **error);
+#include "jsonobj.h"
/******************************************************************************
* *
* Purpose: Prepares JSON parsing error message *
* *
- * Parameters: message - [IN] the error message *
- * json_buffer - [IN] the failing data fragment *
- * error - [OUT] the parsing error message (can be NULL) *
+ * Parameters: message - [IN] the error message *
+ * ptr - [IN] the failing data fragment *
+ * error - [OUT] the parsing error message (can be NULL) *
* *
* Return value: 0 - the json_error() function always returns 0 value *
* so it can be used to return from failed parses *
* *
******************************************************************************/
-static zbx_int64_t json_error(const char *message, const char *json_buffer, char **error)
+zbx_int64_t json_error(const char *message, const char *ptr, char **error)
{
if (NULL != error)
{
- if (NULL != json_buffer)
- *error = zbx_dsprintf(*error, "%s at: '%s'", message, json_buffer);
+ if (NULL != ptr)
+ {
+ if (128 < strlen(ptr))
+ *error = zbx_dsprintf(*error, "%s at: '%128s...'", message, ptr);
+ else
+ *error = zbx_dsprintf(*error, "%s at: '%s'", message, ptr);
+ }
else
*error = zbx_strdup(*error, message);
}
@@ -54,6 +58,7 @@ static zbx_int64_t json_error(const char *message, const char *json_buffer, char
* Purpose: Parses JSON string value or object name *
* *
* Parameters: start - [IN] the JSON data without leading whitespace *
+ * str - [OUT] the parsed unquoted string (can be NULL) *
* error - [OUT] the parsing error message (can be NULL) *
* *
* Return value: The number of characters parsed. On error 0 is returned and *
@@ -61,7 +66,7 @@ static zbx_int64_t json_error(const char *message, const char *json_buffer, char
* message. *
* *
******************************************************************************/
-static zbx_int64_t json_parse_string(const char *start, char **error)
+static zbx_int64_t json_parse_string(const char *start, char **str, char **error)
{
const char *ptr = start;
@@ -119,6 +124,12 @@ static zbx_int64_t json_parse_string(const char *start, char **error)
ptr++;
}
+ if (NULL != str)
+ {
+ *str = (char *)zbx_malloc(NULL, (size_t)(ptr - start));
+ json_copy_string(start, *str, (size_t)(ptr - start));
+ }
+
return ptr - start + 1;
}
@@ -127,6 +138,7 @@ static zbx_int64_t json_parse_string(const char *start, char **error)
* Purpose: Parses JSON array value *
* *
* Parameters: start - [IN] the JSON data without leading whitespace *
+ * obj - [IN/OUT] the JSON object (can be NULL) *
* error - [OUT] the parsing error message (can be NULL) *
* *
* Return value: The number of characters parsed. On error 0 is returned and *
@@ -134,11 +146,14 @@ static zbx_int64_t json_parse_string(const char *start, char **error)
* message. *
* *
******************************************************************************/
-static zbx_int64_t json_parse_array(const char *start, char **error)
+zbx_int64_t json_parse_array(const char *start, zbx_jsonobj_t *obj, char **error)
{
const char *ptr = start;
zbx_int64_t len;
+ if (NULL != obj)
+ jsonobj_init(obj, ZBX_JSON_TYPE_ARRAY);
+
ptr++;
SKIP_WHITESPACE(ptr);
@@ -146,9 +161,29 @@ static zbx_int64_t json_parse_array(const char *start, char **error)
{
while (1)
{
+ zbx_jsonobj_t *value;
+
+ if (NULL != obj)
+ {
+ value = zbx_malloc(NULL, sizeof(zbx_jsonobj_t));
+ jsonobj_init(value, ZBX_JSON_TYPE_UNKNOWN);
+ }
+ else
+ value = NULL;
+
/* json_parse_value strips leading whitespace, so we don't have to do it here */
- if (0 == (len = json_parse_value(ptr, error)))
+ if (0 == (len = json_parse_value(ptr, value, error)))
+ {
+ if (NULL != obj)
+ {
+ zbx_jsonobj_clear(value);
+ zbx_free(value);
+ }
return 0;
+ }
+
+ if (NULL != obj)
+ zbx_vector_jsonobj_ptr_append(&obj->data.array, value);
ptr += len;
SKIP_WHITESPACE(ptr);
@@ -171,15 +206,16 @@ static zbx_int64_t json_parse_array(const char *start, char **error)
* *
* Purpose: Parses JSON number value *
* *
- * Parameters: start - [IN] the JSON data without leading whitespace *
- * error - [OUT] the parsing error message (can be NULL) *
+ * Parameters: start - [IN] the JSON data without leading whitespace *
+ * number - [OUT] the parsed number (can be NULL) *
+ * error - [OUT] the parsing error message (can be NULL) *
* *
* Return value: The number of characters parsed. On error 0 is returned and *
* error parameter (if not NULL) contains allocated error *
* message. *
* *
******************************************************************************/
-static zbx_int64_t json_parse_number(const char *start, char **error)
+static zbx_int64_t json_parse_number(const char *start, double *number, char **error)
{
const char *ptr = start;
char first_digit;
@@ -235,6 +271,9 @@ static zbx_int64_t json_parse_number(const char *start, char **error)
}
}
+ if (NULL != number)
+ *number = atof(start);
+
return ptr - start;
}
@@ -281,10 +320,12 @@ static zbx_int64_t json_parse_literal(const char *start, const char *text, char
* message. *
* *
******************************************************************************/
-zbx_int64_t json_parse_value(const char *start, char **error)
+zbx_int64_t json_parse_value(const char *start, zbx_jsonobj_t *obj, char **error)
{
const char *ptr = start;
zbx_int64_t len;
+ char *str = NULL;
+ double number;
SKIP_WHITESPACE(ptr);
@@ -293,28 +334,40 @@ zbx_int64_t json_parse_value(const char *start, char **error)
case '\0':
return json_error("unexpected end of object value", NULL, error);
case '"':
- if (0 == (len = json_parse_string(ptr, error)))
+ if (0 == (len = json_parse_string(ptr, (NULL != obj ? &str : NULL), error)))
return 0;
+
+ if (NULL != obj)
+ jsonobj_set_string(obj, str);
break;
case '{':
- if (0 == (len = json_parse_object(ptr, error)))
+ if (0 == (len = json_parse_object(ptr, obj, error)))
return 0;
break;
case '[':
- if (0 == (len = json_parse_array(ptr, error)))
+ if (0 == (len = json_parse_array(ptr, obj, error)))
return 0;
break;
case 't':
if (0 == (len = json_parse_literal(ptr, "true", error)))
return 0;
+
+ if (NULL != obj)
+ jsonobj_set_true(obj);
break;
case 'f':
if (0 == (len = json_parse_literal(ptr, "false", error)))
return 0;
+
+ if (NULL != obj)
+ jsonobj_set_false(obj);
break;
case 'n':
if (0 == (len = json_parse_literal(ptr, "null", error)))
return 0;
+
+ if (NULL != obj)
+ jsonobj_set_null(obj);
break;
case '0':
case '1':
@@ -327,8 +380,12 @@ zbx_int64_t json_parse_value(const char *start, char **error)
case '8':
case '9':
case '-':
- if (0 == (len = json_parse_number(ptr, error)))
+ if (0 == (len = json_parse_number(ptr, (NULL != obj ? &number : NULL), error)))
return 0;
+
+ if (NULL != obj)
+ jsonobj_set_number(obj, number);
+
break;
default:
return json_error("invalid JSON object value starting character", ptr, error);
@@ -342,6 +399,7 @@ zbx_int64_t json_parse_value(const char *start, char **error)
* Purpose: Parses JSON object *
* *
* Parameters: start - [IN] the JSON data *
+ * obj - [IN/OUT] the JSON object (can be NULL) *
* error - [OUT] the parsing error message (can be NULL) *
* *
* Return value: The number of characters parsed. On error 0 is returned and *
@@ -349,10 +407,13 @@ zbx_int64_t json_parse_value(const char *start, char **error)
* message. *
* *
******************************************************************************/
-static zbx_int64_t json_parse_object(const char *start, char **error)
+zbx_int64_t json_parse_object(const char *start, zbx_jsonobj_t *obj, char **error)
{
- const char *ptr = start;
- zbx_int64_t len;
+ const char *ptr = start;
+ zbx_int64_t len;
+
+ if (NULL != obj)
+ jsonobj_init(obj, ZBX_JSON_TYPE_OBJECT);
/* parse object name */
SKIP_WHITESPACE(ptr);
@@ -364,11 +425,15 @@ static zbx_int64_t json_parse_object(const char *start, char **error)
{
while (1)
{
+ zbx_jsonobj_el_t el;
+
if ('"' != *ptr)
return json_error("invalid object name", ptr, error);
+ jsonobj_el_init(&el);
+
/* cannot parse object name, failing */
- if (0 == (len = json_parse_string(ptr, error)))
+ if (0 == (len = json_parse_string(ptr, (NULL != obj ? &el.name : NULL), error)))
return 0;
ptr += len;
@@ -377,11 +442,21 @@ static zbx_int64_t json_parse_object(const char *start, char **error)
SKIP_WHITESPACE(ptr);
if (':' != *ptr)
+ {
+ jsonobj_el_clear(&el);
return json_error("invalid object name/value separator", ptr, error);
+ }
+
ptr++;
- if (0 == (len = json_parse_value(ptr, error)))
+ if (0 == (len = json_parse_value(ptr, (NULL != obj ? &el.value : NULL), error)))
+ {
+ jsonobj_el_clear(&el);
return 0;
+ }
+
+ if (NULL != obj)
+ zbx_hashset_insert(&obj->data.object, &el, sizeof(el));
ptr += len;
@@ -426,11 +501,11 @@ zbx_int64_t zbx_json_validate(const char *start, char **error)
switch (*start)
{
case '{':
- if (0 == (len = json_parse_object(start, error)))
+ if (0 == (len = json_parse_object(start, NULL, error)))
return 0;
break;
case '[':
- if (0 == (len = json_parse_array(start, error)))
+ if (0 == (len = json_parse_array(start, NULL, error)))
return 0;
break;
default:
diff --git a/src/libs/zbxjson/json_parser.h b/src/libs/zbxjson/json_parser.h
index f9fb3bb8cf5..cd54939eb7d 100644
--- a/src/libs/zbxjson/json_parser.h
+++ b/src/libs/zbxjson/json_parser.h
@@ -21,9 +21,15 @@
#define ZABBIX_JSON_PARSER_H
#include "zbxtypes.h"
+#include "jsonobj.h"
zbx_int64_t zbx_json_validate(const char *start, char **error);
-zbx_int64_t json_parse_value(const char *start, char **error);
+zbx_int64_t json_parse_value(const char *start, zbx_jsonobj_t *obj, char **error);
+
+zbx_int64_t json_error(const char *message, const char *ptr, char **error);
+
+zbx_int64_t json_parse_object(const char *start, zbx_jsonobj_t *obj, char **error);
+zbx_int64_t json_parse_array(const char *start, zbx_jsonobj_t *obj, char **error);
#endif
diff --git a/src/libs/zbxjson/jsonobj.c b/src/libs/zbxjson/jsonobj.c
new file mode 100644
index 00000000000..2a7c365284c
--- /dev/null
+++ b/src/libs/zbxjson/jsonobj.c
@@ -0,0 +1,366 @@
+/*
+** Zabbix
+** Copyright (C) 2001-2022 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 "jsonobj.h"
+
+#include "json_parser.h"
+#include "json.h"
+#include "zbxstr.h"
+
+ZBX_PTR_VECTOR_IMPL(jsonobj_ptr, zbx_jsonobj_t *)
+ZBX_VECTOR_IMPL(jsonobj_ref, zbx_jsonobj_ref_t)
+
+/* jsonobject index hashset support */
+
+static zbx_hash_t jsonobj_index_el_hash(const void *v)
+{
+ const zbx_jsonobj_index_el_t *el = (const zbx_jsonobj_index_el_t *)v;
+
+ return ZBX_DEFAULT_STRING_HASH_FUNC(el->value);
+}
+
+static int jsonobj_index_el_compare(const void *v1, const void *v2)
+{
+ const zbx_jsonobj_index_el_t *el1 = (const zbx_jsonobj_index_el_t *)v1;
+ const zbx_jsonobj_index_el_t *el2 = (const zbx_jsonobj_index_el_t *)v2;
+
+ return strcmp(el1->value, el2->value);
+}
+
+/* jsonobject values hashset support */
+
+static zbx_hash_t jsonobj_el_hash(const void *v)
+{
+ const zbx_jsonobj_el_t *el = (const zbx_jsonobj_el_t *)v;
+
+ return ZBX_DEFAULT_STRING_HASH_FUNC(el->name);
+}
+
+static int jsonobj_el_compare(const void *v1, const void *v2)
+{
+ const zbx_jsonobj_el_t *el1 = (const zbx_jsonobj_el_t *)v1;
+ const zbx_jsonobj_el_t *el2 = (const zbx_jsonobj_el_t *)v2;
+
+ return strcmp(el1->name, el2->name);
+}
+
+/******************************************************************************
+ * *
+ * Purpose: initialize json object structure *
+ * *
+ * Parameters: obj - [IN/OUT] the json object to initialize *
+ * type - [IN] the json object type *
+ * *
+ ******************************************************************************/
+void jsonobj_init(zbx_jsonobj_t *obj, zbx_json_type_t type)
+{
+ obj->type = type;
+
+ switch (type)
+ {
+ case ZBX_JSON_TYPE_ARRAY:
+ zbx_vector_jsonobj_ptr_create(&obj->data.array);
+ break;
+ case ZBX_JSON_TYPE_OBJECT:
+ zbx_hashset_create(&obj->data.object, 0, jsonobj_el_hash, jsonobj_el_compare);
+ break;
+ default:
+ memset(&obj->data, 0, sizeof(obj->data));
+ break;
+ }
+
+ obj->index = NULL;
+}
+
+/******************************************************************************
+ * *
+ * Purpose: free resources allocated by json object index element *
+ * *
+ * Parameters: v - [IN] the json index element *
+ * *
+ ******************************************************************************/
+static void jsonobj_index_el_clear(void *v)
+{
+ zbx_jsonobj_index_el_t *el = (zbx_jsonobj_index_el_t *)v;
+ int i;
+
+ zbx_free(el->value);
+ for (i = 0; i < el->objects.values_num; i++)
+ {
+ zbx_free(el->objects.values[i].name);
+
+ if (0 != el->objects.values[i].external)
+ {
+ zbx_jsonobj_clear(el->objects.values[i].value);
+ zbx_free(el->objects.values[i].value);
+ }
+ }
+
+ zbx_vector_jsonobj_ref_destroy(&el->objects);
+}
+
+/******************************************************************************
+ * *
+ * Purpose: initialize json object index *
+ * *
+ * Parameters: obj - [IN/OUT] the json object *
+ * path - [IN] the indexed relative path *
+ * *
+ ******************************************************************************/
+void jsonobj_init_index(zbx_jsonobj_t *obj, const char *path)
+{
+ obj->index = (zbx_jsonobj_index_t *)zbx_malloc(NULL, sizeof(zbx_jsonobj_index_t));
+ obj->index->path = zbx_strdup(NULL, path);
+ zbx_hashset_create_ext(&obj->index->objects, 0, jsonobj_index_el_hash, jsonobj_index_el_compare,
+ jsonobj_index_el_clear, ZBX_DEFAULT_MEM_MALLOC_FUNC, ZBX_DEFAULT_MEM_REALLOC_FUNC,
+ ZBX_DEFAULT_MEM_FREE_FUNC);
+}
+
+/******************************************************************************
+ * *
+ * Purpose: set string value to json object *
+ * *
+ ******************************************************************************/
+void jsonobj_set_string(zbx_jsonobj_t *obj, char *str)
+{
+ obj->type = ZBX_JSON_TYPE_STRING;
+ obj->data.string = str;
+}
+
+/******************************************************************************
+ * *
+ * Purpose: set numeric value to json object *
+ * *
+ ******************************************************************************/
+void jsonobj_set_number(zbx_jsonobj_t *obj, double number)
+{
+ obj->type = ZBX_JSON_TYPE_NUMBER;
+ obj->data.number = number;
+}
+
+/******************************************************************************
+ * *
+ * Purpose: set true value to json object *
+ * *
+ ******************************************************************************/
+void jsonobj_set_true(zbx_jsonobj_t *obj)
+{
+ obj->type = ZBX_JSON_TYPE_TRUE;
+}
+
+/******************************************************************************
+ * *
+ * Purpose: set false value to json object *
+ * *
+ ******************************************************************************/
+void jsonobj_set_false(zbx_jsonobj_t *obj)
+{
+ obj->type = ZBX_JSON_TYPE_FALSE;
+}
+
+/******************************************************************************
+ * *
+ * Purpose: set null value to json object *
+ * *
+ ******************************************************************************/
+void jsonobj_set_null(zbx_jsonobj_t *obj)
+{
+ obj->type = ZBX_JSON_TYPE_NULL;
+}
+
+/******************************************************************************
+ * *
+ * Purpose: initialize json object element *
+ * *
+ ******************************************************************************/
+void jsonobj_el_init(zbx_jsonobj_el_t *el)
+{
+ el->name = NULL;
+ jsonobj_init(&el->value, ZBX_JSON_TYPE_UNKNOWN);
+}
+
+/******************************************************************************
+ * *
+ * Purpose: free resources allocated by json object element *
+ * *
+ ******************************************************************************/
+void jsonobj_el_clear(zbx_jsonobj_el_t *el)
+{
+ zbx_free(el->name);
+ zbx_jsonobj_clear(&el->value);
+}
+
+/******************************************************************************
+ * *
+ * Purpose: free json object *
+ * *
+ ******************************************************************************/
+static void jsonobj_free(zbx_jsonobj_t *obj)
+{
+ zbx_jsonobj_clear(obj);
+ zbx_free(obj);
+}
+
+/******************************************************************************
+ * *
+ * Purpose: free resources allocated by json object *
+ * *
+ ******************************************************************************/
+void zbx_jsonobj_clear(zbx_jsonobj_t *obj)
+{
+ zbx_jsonobj_el_t *el;
+ zbx_hashset_iter_t iter;
+
+ switch (obj->type)
+ {
+ case ZBX_JSON_TYPE_STRING:
+ zbx_free(obj->data.string);
+ break;
+ case ZBX_JSON_TYPE_ARRAY:
+ zbx_vector_jsonobj_ptr_clear_ext(&obj->data.array, jsonobj_free);
+ zbx_vector_jsonobj_ptr_destroy(&obj->data.array);
+ break;
+ case ZBX_JSON_TYPE_OBJECT:
+ zbx_hashset_iter_reset(&obj->data.object, &iter);
+ while (NULL != (el = (zbx_jsonobj_el_t *)zbx_hashset_iter_next(&iter)))
+ {
+ zbx_free(el->name);
+ zbx_jsonobj_clear(&el->value);
+ }
+ zbx_hashset_destroy(&obj->data.object);
+ break;
+ default:
+ break;
+ }
+
+ if (NULL != obj->index)
+ {
+ zbx_free(obj->index->path);
+ zbx_hashset_destroy(&obj->index->objects);
+ zbx_free(obj->index);
+ }
+}
+
+/******************************************************************************
+ * *
+ * Purpose: convert json object to text format *
+ * *
+ ******************************************************************************/
+int zbx_jsonobj_to_string(char **str, size_t *str_alloc, size_t *str_offset, zbx_jsonobj_t *obj)
+{
+ char *tmp, buf[32], delim;
+ int i;
+ zbx_hashset_iter_t iter;
+ zbx_jsonobj_el_t *el;
+
+ switch (obj->type)
+ {
+ case ZBX_JSON_TYPE_TRUE:
+ zbx_strcpy_alloc(str, str_alloc, str_offset, "true");
+ break;
+ case ZBX_JSON_TYPE_FALSE:
+ zbx_strcpy_alloc(str, str_alloc, str_offset, "false");
+ break;
+ case ZBX_JSON_TYPE_NULL:
+ zbx_strcpy_alloc(str, str_alloc, str_offset, "null");
+ break;
+ case ZBX_JSON_TYPE_STRING:
+ tmp = zbx_strdup(NULL, obj->data.string);
+ zbx_json_escape(&tmp);
+ zbx_snprintf_alloc(str, str_alloc, str_offset, "\"%s\"", tmp);
+ zbx_free(tmp);
+ break;
+ case ZBX_JSON_TYPE_NUMBER:
+ zbx_print_double(buf, sizeof(buf), obj->data.number);
+ zbx_strcpy_alloc(str, str_alloc, str_offset, buf);
+ break;
+ case ZBX_JSON_TYPE_ARRAY:
+ delim = '[';
+ for (i = 0; i < obj->data.array.values_num; i++)
+ {
+ zbx_chrcpy_alloc(str, str_alloc, str_offset, delim);
+ delim = ',';
+ zbx_jsonobj_to_string(str, str_alloc, str_offset, obj->data.array.values[i]);
+ }
+ zbx_chrcpy_alloc(str, str_alloc, str_offset, ']');
+ break;
+ case ZBX_JSON_TYPE_OBJECT:
+ delim = '{';
+ zbx_hashset_iter_reset(&obj->data.object, &iter);
+ while (NULL != (el = (zbx_jsonobj_el_t *)zbx_hashset_iter_next(&iter)))
+ {
+ zbx_chrcpy_alloc(str, str_alloc, str_offset, delim);
+ delim = ',';
+
+ tmp = zbx_strdup(NULL, el->name);
+ zbx_json_escape(&tmp);
+ zbx_snprintf_alloc(str, str_alloc, str_offset, "\"%s\"", tmp);
+ zbx_chrcpy_alloc(str, str_alloc, str_offset, ':');
+ zbx_free(tmp);
+
+ zbx_jsonobj_to_string(str, str_alloc, str_offset, &el->value);
+ }
+ zbx_chrcpy_alloc(str, str_alloc, str_offset, '}');
+ break;
+ default:
+ zbx_set_json_strerror("unknown json object with type: %u", obj->type);
+ return FAIL;
+ }
+
+ return SUCCEED;
+}
+
+/******************************************************************************
+ * *
+ * Purpose: parses json formatted data into json object structure *
+ * *
+ ******************************************************************************/
+int zbx_jsonobj_open(const char *data, zbx_jsonobj_t *obj)
+{
+ int ret = FAIL;
+ char *error = NULL;
+
+ switch (*data)
+ {
+ case '{':
+ if (0 == json_parse_object(data, obj, &error))
+ goto out;
+ break;
+ case '[':
+ if (0 == json_parse_array(data, obj, &error))
+ goto out;
+ break;
+ default:
+ /* not json data, failing */
+ jsonobj_init(obj, ZBX_JSON_TYPE_UNKNOWN);
+ (void)json_error("invalid object format, expected opening character '{' or '['", data, &error);
+ goto out;
+ }
+
+ ret = SUCCEED;
+out:
+ if (FAIL == ret)
+ {
+ zbx_jsonobj_clear(obj);
+ zbx_set_json_strerror("%s", error);
+ zbx_free(error);
+ }
+
+ return ret;
+}
diff --git a/src/libs/zbxjson/jsonobj.h b/src/libs/zbxjson/jsonobj.h
new file mode 100644
index 00000000000..dfd12df6b9b
--- /dev/null
+++ b/src/libs/zbxjson/jsonobj.h
@@ -0,0 +1,56 @@
+/*
+** Zabbix
+** Copyright (C) 2001-2022 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.
+**/
+
+#ifndef ZABBIX_JSONOBJ_H
+#define ZABBIX_JSONOBJ_H
+
+#include "zbxjson.h"
+
+typedef struct
+{
+ char *name;
+ zbx_jsonobj_t *value;
+ unsigned char external; /* 1 - the reference is to an external object. */
+ /* 0 - the reference is to a local object which must be freed */
+ /* when reference is destroyed */
+}
+zbx_jsonobj_ref_t;
+
+ZBX_VECTOR_DECL(jsonobj_ref, zbx_jsonobj_ref_t)
+
+typedef struct
+{
+ char *value; /* the value found at indexed path */
+ zbx_vector_jsonobj_ref_t objects; /* the objects matching value at indexed path */
+}
+zbx_jsonobj_index_el_t;
+
+void jsonobj_init(zbx_jsonobj_t *obj, zbx_json_type_t type);
+
+void jsonobj_el_init(zbx_jsonobj_el_t *el);
+void jsonobj_init_index(zbx_jsonobj_t *obj, const char *path);
+void jsonobj_el_clear(zbx_jsonobj_el_t *el);
+
+void jsonobj_set_string(zbx_jsonobj_t *obj, char *str);
+void jsonobj_set_number(zbx_jsonobj_t *obj, double number);
+void jsonobj_set_true(zbx_jsonobj_t *obj);
+void jsonobj_set_false(zbx_jsonobj_t *obj);
+void jsonobj_set_null(zbx_jsonobj_t *obj);
+
+#endif
diff --git a/src/libs/zbxjson/jsonpath.c b/src/libs/zbxjson/jsonpath.c
index b57aff6f8d5..eec2ffc6935 100644
--- a/src/libs/zbxjson/jsonpath.c
+++ b/src/libs/zbxjson/jsonpath.c
@@ -18,7 +18,6 @@
**/
#include "jsonpath.h"
-#include "zbxjson.h"
#include "zbxregexp.h"
#include "zbxvariant.h"
@@ -26,21 +25,17 @@
#include "zbxexpr.h"
#include "json.h"
#include "json_parser.h"
+#include "jsonobj.h"
typedef struct
{
- char *name;
- const char *value;
+ zbx_jsonobj_t *root; /* the root object */
+ zbx_jsonpath_t *path;
+ unsigned char found; /* set to 1 when one object was matched and */
+ /* no more matches are required */
+ zbx_vector_jsonobj_ref_t objects; /* the matched objects */
}
-zbx_json_element_t;
-
-ZBX_VECTOR_DECL(json, zbx_json_element_t)
-ZBX_VECTOR_IMPL(json, zbx_json_element_t)
-
-static int jsonpath_query_object(const struct zbx_json_parse *jp_root, const struct zbx_json_parse *jp,
- const zbx_jsonpath_t *jsonpath, int path_depth, zbx_vector_json_t *objects);
-static int jsonpath_query_array(const struct zbx_json_parse *jp_root, const struct zbx_json_parse *jp,
- const zbx_jsonpath_t *jsonpath, int path_depth, zbx_vector_json_t *objects);
+zbx_jsonpath_context_t;
typedef struct
{
@@ -49,6 +44,10 @@ typedef struct
}
zbx_jsonpath_token_def_t;
+static int jsonpath_query_object(zbx_jsonpath_context_t *ctx, zbx_jsonobj_t *obj, int path_depth);
+static int jsonpath_query_array(zbx_jsonpath_context_t *ctx, zbx_jsonobj_t *array, int path_depth);
+static int jsonpath_str_copy_value(char **str, size_t *str_alloc, size_t *str_offset, zbx_jsonobj_t *obj);
+
/* define token groups and precedence */
static zbx_jsonpath_token_def_t jsonpath_tokens[] = {
{0, 0},
@@ -74,6 +73,7 @@ static zbx_jsonpath_token_def_t jsonpath_tokens[] = {
{ZBX_JSONPATH_TOKEN_GROUP_OPERATOR2, 7} /* ZBX_JSONPATH_TOKEN_OP_REGEXP */
};
+
static int jsonpath_token_precedence(int type)
{
return jsonpath_tokens[type].precedence;
@@ -84,31 +84,118 @@ static int jsonpath_token_group(int type)
return jsonpath_tokens[type].group;
}
-/* json element vector support */
-static void zbx_vector_json_add_element(zbx_vector_json_t *elements, const char *name, const char *value)
+/******************************************************************************
+ * *
+ * Purpose: add external json object reference to a vector *
+ * *
+ * Parameters: refs - [IN/OUT] the json object reference vector *
+ * name - [IN] the json object name or array index *
+ * value - [IN] the json object *
+ * *
+ ******************************************************************************/
+static void zbx_vector_jsonobj_ref_add_object(zbx_vector_jsonobj_ref_t *refs, const char *name,
+ zbx_jsonobj_t *value)
{
- zbx_json_element_t el;
+ zbx_jsonobj_ref_t ref;
- el.name = zbx_strdup(NULL, name);
- el.value = value;
- zbx_vector_json_append(elements, el);
+ ref.name = zbx_strdup(NULL, name);
+ ref.external = 1;
+
+ ref.value = value;
+ zbx_vector_jsonobj_ref_append(refs, ref);
+}
+
+/******************************************************************************
+ * *
+ * Purpose: add internal json object reference to a vector *
+ * *
+ * Parameters: refs - [IN/OUT] the json object reference vector *
+ * name - [IN] the json object name or array index *
+ * str - [IN] the string value of the object *
+ * *
+ * Comments: This function will create json object and add internal reference,*
+ * meaning the object will be destroyed together with its reference.*
+ * *
+ ******************************************************************************/
+static void zbx_vector_jsonobj_ref_add_string(zbx_vector_jsonobj_ref_t *refs, const char *name,
+ const char *str)
+{
+ zbx_jsonobj_ref_t ref;
+
+ ref.name = zbx_strdup(NULL, name);
+ ref.external = 0;
+
+ ref.value = (zbx_jsonobj_t *)zbx_malloc(NULL, sizeof(zbx_jsonobj_t));
+ jsonobj_init(ref.value, ZBX_JSON_TYPE_STRING);
+ jsonobj_set_string(ref.value, zbx_strdup(NULL, str));
+
+ zbx_vector_jsonobj_ref_append(refs, ref);
+}
+
+/******************************************************************************
+ * *
+ * Purpose: add a copy of json object reference to a vector *
+ * *
+ * Parameters: refs - [IN/OUT] the json object reference vector *
+ * ref - [IN] the json object reference *
+ * *
+ * Comments: For internal references a new internal json object will be *
+ * created. *
+ * *
+ ******************************************************************************/
+static void zbx_vector_jsonobj_ref_add(zbx_vector_jsonobj_ref_t *refs, zbx_jsonobj_ref_t *ref)
+{
+ if (0 != ref->external)
+ zbx_vector_jsonobj_ref_add_object(refs, ref->name, ref->value);
+ else
+ zbx_vector_jsonobj_ref_add_string(refs, ref->name, ref->value->data.string);
}
-static void zbx_vector_json_copy(zbx_vector_json_t *dst, const zbx_vector_json_t *src)
+/******************************************************************************
+ * *
+ * Purpose: copy json object references from one vector to other *
+ * *
+ * Parameters: dst - [IN/OUT] the destination json object reference vector *
+ * src - [IN] the source json object reference vector *
+ * *
+ * Comments: For internal references a new internal json object will be *
+ * created. *
+ * *
+ ******************************************************************************/
+static void zbx_vector_jsonobj_ref_copy(zbx_vector_jsonobj_ref_t *dst, const zbx_vector_jsonobj_ref_t *src)
{
int i;
for (i = 0; i < src->values_num; i++)
- zbx_vector_json_add_element(dst, src->values[i].name, src->values[i].value);
+ {
+ if (0 != src->values[i].external)
+ zbx_vector_jsonobj_ref_add_object(dst, src->values[i].name, src->values[i].value);
+ else
+ zbx_vector_jsonobj_ref_add_string(dst, src->values[i].name, src->values[i].value->data.string);
+ }
}
-static void zbx_vector_json_clear_ext(zbx_vector_json_t *elements)
+/******************************************************************************
+ * *
+ * Purpose: free resources allocated by json object reference *
+ * *
+ ******************************************************************************/
+static void zbx_vector_jsonobj_ref_clear_ext(zbx_vector_jsonobj_ref_t *refs)
{
int i;
- for (i = 0; i < elements->values_num; i++)
- zbx_free(elements->values[i].name);
- zbx_vector_json_clear(elements);
+ for (i = 0; i < refs->values_num; i++)
+ {
+ zbx_jsonobj_ref_t *ref = &refs->values[i];
+
+ zbx_free(ref->name);
+ if (0 == ref->external)
+ {
+ zbx_jsonobj_clear(ref->value);
+ zbx_free(ref->value);
+ }
+ }
+ zbx_vector_jsonobj_ref_clear(refs);
}
/******************************************************************************
@@ -215,16 +302,116 @@ static void jsonpath_list_free(zbx_jsonpath_list_node_t *list)
/******************************************************************************
* *
+ * Purpose: append array index to list *
+ * *
+ ******************************************************************************/
+static zbx_jsonpath_list_node_t *jsonpath_list_append_index(zbx_jsonpath_list_node_t *head, int index,
+ int check_duplicate)
+{
+ zbx_jsonpath_list_node_t *node;
+
+ if (0 != check_duplicate)
+ {
+ for (node = head; NULL != node; node = node->next)
+ {
+ int query_index;
+
+ memcpy(&query_index, node->data, sizeof(query_index));
+ if (query_index == index)
+ return head;
+ }
+ }
+
+ node = jsonpath_list_create_node(sizeof(int));
+ node->next = head;
+ memcpy(node->data, &index, sizeof(int));
+
+ return node;
+}
+
+/******************************************************************************
+ * *
+ * Purpose: append name to list *
+ * *
+ ******************************************************************************/
+static zbx_jsonpath_list_node_t *jsonpath_list_append_name(zbx_jsonpath_list_node_t *head, const char *name, size_t len)
+{
+ zbx_jsonpath_list_node_t *node, *new_node;
+
+ new_node = jsonpath_list_create_node(len + 1);
+ jsonpath_unquote(new_node->data, name, len + 1);
+
+ for (node = head; NULL != node; node = node->next)
+ {
+ if (0 == strcmp((char *)new_node->data, (char *)node->data))
+ {
+ zbx_free(new_node);
+ return head;
+ }
+ }
+
+ new_node->next = head;
+
+ return new_node;
+}
+
+/******************************************************************************
+ * *
+ * Purpose: create jsonpath structure and compile json path *
+ * *
+ ******************************************************************************/
+static zbx_jsonpath_t *jsonpath_create_token_jsonpath(const char *text, size_t len)
+{
+ zbx_jsonpath_t *path;
+ char *tmp_text;
+
+ tmp_text = jsonpath_strndup(text, len);
+
+ if ('@' == *tmp_text)
+ *tmp_text = '$';
+
+ path = (zbx_jsonpath_t *)zbx_malloc(NULL, sizeof(zbx_jsonpath_t));
+
+ if (FAIL == zbx_jsonpath_compile(tmp_text, path))
+ {
+ zbx_free(path);
+ goto out;
+ }
+
+ if (1 != path->definite)
+ {
+ zbx_set_json_strerror("only simple path are supported in jsonpath expression: \"%s\"", text);
+ zbx_jsonpath_clear(path);
+ zbx_free(path);
+ goto out;
+ }
+
+ if (ZBX_JSONPATH_SEGMENT_FUNCTION == path->segments[path->segments_num - 1].type)
+ {
+ zbx_set_json_strerror("functions are not supported in jsonpath expression: \"%s\"", text);
+ zbx_jsonpath_clear(path);
+ zbx_free(path);
+ }
+out:
+ zbx_free(tmp_text);
+
+ return path;
+}
+
+/******************************************************************************
+ * *
* Purpose: create jsonpath expression token *
* *
* Parameters: type - [IN] the token type *
* expression - [IN] the expression *
* loc - [IN] the token location in the expression *
* *
- * Return value: The created token (must be freed by the caller). *
+ * Return value: The created token (must be freed by the caller) or *
+ * NULL in the case of error. *
* *
******************************************************************************/
-static zbx_jsonpath_token_t *jsonpath_create_token(int type, const char *expression, const zbx_strloc_t *loc)
+static zbx_jsonpath_token_t *jsonpath_create_token(unsigned char type, const char *expression,
+ const zbx_strloc_t *loc)
{
zbx_jsonpath_token_t *token;
@@ -234,23 +421,46 @@ static zbx_jsonpath_token_t *jsonpath_create_token(int type, const char *express
switch (token->type)
{
case ZBX_JSONPATH_TOKEN_CONST_STR:
- token->data = jsonpath_unquote_dyn(expression + loc->l, loc->r - loc->l + 1);
+ token->text = jsonpath_unquote_dyn(expression + loc->l, loc->r - loc->l + 1);
+ token->path = NULL;
break;
case ZBX_JSONPATH_TOKEN_PATH_ABSOLUTE:
case ZBX_JSONPATH_TOKEN_PATH_RELATIVE:
+ if (NULL == (token->path = jsonpath_create_token_jsonpath(expression + loc->l,
+ loc->r - loc->l + 1)))
+ {
+ zbx_free(token);
+ }
+ else
+ token->text = jsonpath_strndup(expression + loc->l, loc->r - loc->l + 1);
+ break;
case ZBX_JSONPATH_TOKEN_CONST_NUM:
- token->data = jsonpath_strndup(expression + loc->l, loc->r - loc->l + 1);
+ token->text = jsonpath_strndup(expression + loc->l, loc->r - loc->l + 1);
+ token->path = NULL;
break;
default:
- token->data = NULL;
+ token->text = NULL;
+ token->path = NULL;
}
return token;
}
+/******************************************************************************
+ * *
+ * Purpose: free jsonpath expression token *
+ * *
+ ******************************************************************************/
static void jsonpath_token_free(zbx_jsonpath_token_t *token)
{
- zbx_free(token->data);
+ zbx_free(token->text);
+
+ if (NULL != token->path)
+ {
+ zbx_jsonpath_clear(token->path);
+ zbx_free(token->path);
+ }
+
zbx_free(token);
}
@@ -274,16 +484,21 @@ static void jsonpath_reserve(zbx_jsonpath_t *jsonpath, int num)
jsonpath->segments_alloc *= 2;
jsonpath->segments = (zbx_jsonpath_segment_t *)zbx_realloc(jsonpath->segments,
- sizeof(zbx_jsonpath_segment_t) * jsonpath->segments_alloc);
+ sizeof(zbx_jsonpath_segment_t) * (size_t)jsonpath->segments_alloc);
/* Initialize the memory allocated for new segments, as parser can set */
/* detached flag for the next segment, so the memory cannot be initialized */
/* when creating a segment. */
memset(jsonpath->segments + old_alloc, 0,
- (jsonpath->segments_alloc - old_alloc) * sizeof(zbx_jsonpath_segment_t));
+ (size_t)(jsonpath->segments_alloc - old_alloc) * sizeof(zbx_jsonpath_segment_t));
}
}
+/******************************************************************************
+ * *
+ * Purpose: free resource allocated by jsonpath segment *
+ * *
+ ******************************************************************************/
static void jsonpath_segment_clear(zbx_jsonpath_segment_t *segment)
{
switch (segment->type)
@@ -391,7 +606,7 @@ static int jsonpath_next(const char **pnext)
* FAIL - otherwise *
* *
******************************************************************************/
-static int jsonpath_parse_substring(const char *start, int *len)
+static int jsonpath_parse_substring(const char *start, size_t *len)
{
const char *ptr;
char quotes;
@@ -400,7 +615,7 @@ static int jsonpath_parse_substring(const char *start, int *len)
{
if (*ptr == quotes)
{
- *len = ptr - start + 1;
+ *len = (size_t)(ptr - start + 1);
return SUCCEED;
}
@@ -429,7 +644,7 @@ static int jsonpath_parse_substring(const char *start, int *len)
* jsonpath filter expressions. *
* *
******************************************************************************/
-static int jsonpath_parse_path(const char *start, int *len)
+static int jsonpath_parse_path(const char *start, size_t *len)
{
const char *ptr = start + 1;
@@ -439,7 +654,7 @@ static int jsonpath_parse_path(const char *start, int *len)
return FAIL;
}
- *len = ptr - start;
+ *len = (size_t)(ptr - start);
return SUCCEED;
}
@@ -454,7 +669,7 @@ static int jsonpath_parse_path(const char *start, int *len)
* FAIL - otherwise *
* *
******************************************************************************/
-static int jsonpath_parse_number(const char *start, int *len)
+static int jsonpath_parse_number(const char *start, size_t *len)
{
const char *ptr = start;
char *end;
@@ -474,7 +689,7 @@ static int jsonpath_parse_number(const char *start, int *len)
if (ptr != end || HUGE_VAL == tmp || -HUGE_VAL == tmp || EDOM == errno)
return FAIL;
- *len = (int)(ptr - start);
+ *len = (size_t)(ptr - start);
return SUCCEED;
}
@@ -494,14 +709,14 @@ static int jsonpath_parse_number(const char *start, int *len)
* FAIL - otherwise *
* *
******************************************************************************/
-static int jsonpath_expression_next_token(const char *expression, int pos, int prev_group,
+static int jsonpath_expression_next_token(const char *expression, size_t pos, int prev_group,
zbx_jsonpath_token_type_t *type, zbx_strloc_t *loc)
{
- int len;
+ size_t len;
const char *ptr = expression + pos;
SKIP_WHITESPACE(ptr);
- loc->l = ptr - expression;
+ loc->l = (size_t)(ptr - expression);
switch (*ptr)
{
@@ -633,6 +848,139 @@ out:
return zbx_jsonpath_error(ptr);
}
+/* value types on index stack */
+typedef enum
+{
+ ZBX_JSONPATH_CONST = 1, /* constant value - string or number */
+ ZBX_JSONPATH_VALUE, /* result of an operation after which cannot be used in index */
+ ZBX_JSONPATH_PATH, /* relative jsonpath - @.a.b.c */
+ ZBX_JSONPATH_PATH_OP /* result of an operation with jsonpath which still can be used in index */
+}
+zbx_jsonpath_index_value_type_t;
+
+typedef struct
+{
+ zbx_jsonpath_index_value_type_t type;
+ zbx_jsonpath_token_t *index_token;
+ zbx_jsonpath_token_t *value_token;
+}
+zbx_jsonpath_index_value_t;
+
+ZBX_VECTOR_DECL(jpi_value, zbx_jsonpath_index_value_t)
+ZBX_VECTOR_IMPL(jpi_value, zbx_jsonpath_index_value_t)
+
+/******************************************************************************
+ * *
+ * Purpose: analyze expression and set indexing fields if possible *
+ * *
+ * Comments: Expression can be indexed if it contains relative json path *
+ * comparison with constant that is used in and operations. *
+ * This is tested by doing a pseudo evaluation by operand types *
+ * and checking the result type. *
+ * *
+ * So expressions like ?(@.a.b == 1), ?(@.a == "A" and @.b == "B") *
+ * can be indexed (by @.a.b and by @.a) while expressions like *
+ * ?(@.a == @.b), ?(@.a == "A" or @.b == "B") cannot. *
+ * *
+ ******************************************************************************/
+static void jsonpath_expression_prepare_index(zbx_jsonpath_expression_t *exp)
+{
+ int i;
+ zbx_vector_jpi_value_t stack;
+ zbx_jsonpath_index_value_t *left, *right;
+
+ zbx_vector_jpi_value_create(&stack);
+
+ for (i = 0; i < exp->tokens.values_num; i++)
+ {
+ zbx_jsonpath_token_t *token = (zbx_jsonpath_token_t *)exp->tokens.values[i];
+ zbx_jsonpath_index_value_t jpi = {0};
+
+ switch (token->type)
+ {
+ case ZBX_JSONPATH_TOKEN_OP_NOT:
+ if (1 > stack.values_num)
+ goto out;
+ stack.values[stack.values_num - 1].type = ZBX_JSONPATH_VALUE;
+ stack.values[stack.values_num - 1].index_token = NULL;
+ stack.values[stack.values_num - 1].value_token = NULL;
+ continue;
+ case ZBX_JSONPATH_TOKEN_PATH_RELATIVE:
+ jpi.index_token = token;
+ jpi.type = ZBX_JSONPATH_PATH;
+ zbx_vector_jpi_value_append(&stack, jpi);
+ continue;
+ case ZBX_JSONPATH_TOKEN_PATH_ABSOLUTE:
+ jpi.type = ZBX_JSONPATH_VALUE;
+ zbx_vector_jpi_value_append(&stack, jpi);
+ continue;
+ case ZBX_JSONPATH_TOKEN_CONST_STR:
+ case ZBX_JSONPATH_TOKEN_CONST_NUM:
+ jpi.value_token = token;
+ jpi.type = ZBX_JSONPATH_CONST;
+ zbx_vector_jpi_value_append(&stack, jpi);
+ continue;
+ }
+
+ if (2 > stack.values_num)
+ goto out;
+
+ left = &stack.values[stack.values_num - 2];
+ right = &stack.values[stack.values_num - 1];
+ stack.values_num--;
+
+ switch (token->type)
+ {
+ case ZBX_JSONPATH_TOKEN_OP_EQ:
+ if ((ZBX_JSONPATH_PATH == left->type || ZBX_JSONPATH_PATH == right->type) &&
+ (ZBX_JSONPATH_CONST == left->type || ZBX_JSONPATH_CONST == right->type))
+ {
+ left->type = ZBX_JSONPATH_PATH_OP;
+
+ if (ZBX_JSONPATH_CONST == right->type)
+ left->value_token = right->value_token;
+ else
+ left->index_token = right->index_token;
+ }
+ else
+ left->type = ZBX_JSONPATH_VALUE;
+ continue;
+ case ZBX_JSONPATH_TOKEN_OP_AND:
+ if (ZBX_JSONPATH_PATH == left->type)
+ left->type = ZBX_JSONPATH_VALUE;
+
+ if (ZBX_JSONPATH_PATH == right->type)
+ right->type = ZBX_JSONPATH_VALUE;
+
+ if (ZBX_JSONPATH_PATH_OP == left->type && ZBX_JSONPATH_PATH_OP == right->type)
+ continue;
+
+ if ((ZBX_JSONPATH_PATH_OP == left->type || ZBX_JSONPATH_PATH_OP == right->type) &&
+ (ZBX_JSONPATH_VALUE == left->type || ZBX_JSONPATH_VALUE == right->type))
+ {
+ if (ZBX_JSONPATH_PATH_OP != left->type)
+ *left = *right;
+ }
+ else
+ left->type = ZBX_JSONPATH_VALUE;
+ continue;
+ default:
+ left->type = ZBX_JSONPATH_VALUE;
+ left->index_token = NULL;
+ left->value_token = NULL;
+ break;
+ }
+ }
+
+ if (1 == stack.values_num && ZBX_JSONPATH_PATH_OP == stack.values[0].type)
+ {
+ exp->index_token = stack.values[0].index_token;
+ exp->value_token = stack.values[0].value_token;
+ }
+out:
+ zbx_vector_jpi_value_destroy(&stack);
+}
+
/******************************************************************************
* *
* Purpose: parse jsonpath filter expression in format *
@@ -659,7 +1007,7 @@ out:
static int jsonpath_parse_expression(const char *expression, zbx_jsonpath_t *jsonpath, const char **next)
{
int nesting = 1, ret = FAIL;
- zbx_jsonpath_token_t *optoken;
+ zbx_jsonpath_token_t *optoken, *token;
zbx_vector_ptr_t output, operators;
zbx_strloc_t loc = {0, 0};
zbx_jsonpath_token_type_t token_type;
@@ -706,7 +1054,10 @@ static int jsonpath_parse_expression(const char *expression, zbx_jsonpath_t *jso
goto out;
}
- zbx_vector_ptr_append(&output, jsonpath_create_token(token_type, expression, &loc));
+ if (NULL == (token = jsonpath_create_token(token_type, expression, &loc)))
+ goto cleanup;
+
+ zbx_vector_ptr_append(&operators, token);
prev_group = jsonpath_token_group(token_type);
continue;
}
@@ -746,14 +1097,20 @@ static int jsonpath_parse_expression(const char *expression, zbx_jsonpath_t *jso
zbx_vector_ptr_append(&output, optoken);
}
- zbx_vector_ptr_append(&operators, jsonpath_create_token(token_type, expression, &loc));
+ if (NULL == (token = jsonpath_create_token(token_type, expression, &loc)))
+ goto cleanup;
+
+ zbx_vector_ptr_append(&operators, token);
prev_group = jsonpath_token_group(token_type);
continue;
}
if (ZBX_JSONPATH_TOKEN_PAREN_LEFT == token_type)
{
- zbx_vector_ptr_append(&operators, jsonpath_create_token(token_type, expression, &loc));
+ if (NULL == (token = jsonpath_create_token(token_type, expression, &loc)))
+ goto cleanup;
+
+ zbx_vector_ptr_append(&operators, token);
prev_group = ZBX_JSONPATH_TOKEN_GROUP_NONE;
continue;
}
@@ -816,6 +1173,10 @@ out:
zbx_vector_ptr_create(&segment->data.expression.tokens);
zbx_vector_ptr_append_array(&segment->data.expression.tokens, output.values, output.values_num);
+ /* index only json path that has been definite until this point */
+ if (0 != jsonpath->definite)
+ jsonpath_expression_prepare_index(&segment->data.expression);
+
jsonpath->definite = 0;
}
cleanup:
@@ -869,18 +1230,13 @@ static int jsonpath_parse_names(const char *list, zbx_jsonpath_t *jsonpath, cons
}
else if (*start == *end)
{
- zbx_jsonpath_list_node_t *node;
-
if (start + 1 == end)
{
ret = zbx_jsonpath_error(start);
goto out;
}
- node = jsonpath_list_create_node(end - start + 1);
- jsonpath_unquote(node->data, start, end - start + 1);
- node->next = head;
- head = node;
+ head = jsonpath_list_append_name(head, start, (size_t)(end - start));
parsed_name = 1;
start = NULL;
}
@@ -987,19 +1343,13 @@ static int jsonpath_parse_indexes(const char *list, zbx_jsonpath_t *jsonpath, co
if (NULL != start)
{
- int value;
-
if ('-' == *start && end == start + 1)
{
ret = zbx_jsonpath_error(start);
goto out;
}
- node = jsonpath_list_create_node(sizeof(int));
- node->next = head;
- head = node;
- value = atoi(start);
- memcpy(node->data, &value, sizeof(int));
+ head = jsonpath_list_append_index(head, atoi(start), type == ZBX_JSONPATH_SEGMENT_MATCH_LIST);
start = NULL;
parsed_index = 1;
}
@@ -1163,7 +1513,7 @@ static int jsonpath_parse_dot_segment(const char *start, zbx_jsonpath_t *jsonpat
{
zbx_jsonpath_segment_t *segment;
const char *ptr;
- int len;
+ size_t len;
segment = &jsonpath->segments[jsonpath->segments_num];
jsonpath->segments_num++;
@@ -1179,6 +1529,8 @@ static int jsonpath_parse_dot_segment(const char *start, zbx_jsonpath_t *jsonpat
for (ptr = start; 0 != isalnum((unsigned char)*ptr) || '_' == *ptr;)
ptr++;
+ len = (size_t)(ptr - start);
+
if ('(' == *ptr)
{
const char *end = ptr + 1;
@@ -1186,18 +1538,31 @@ static int jsonpath_parse_dot_segment(const char *start, zbx_jsonpath_t *jsonpat
SKIP_WHITESPACE(end);
if (')' == *end)
{
- if (ZBX_CONST_STRLEN("min") == ptr - start && 0 == strncmp(start, "min", ptr - start))
+ if (ZBX_CONST_STRLEN("min") == len && 0 == strncmp(start, "min", len))
+ {
segment->data.function.type = ZBX_JSONPATH_FUNCTION_MIN;
- else if (ZBX_CONST_STRLEN("max") == ptr - start && 0 == strncmp(start, "max", ptr - start))
+ }
+ else if (ZBX_CONST_STRLEN("max") == len && 0 == strncmp(start, "max", len))
+ {
segment->data.function.type = ZBX_JSONPATH_FUNCTION_MAX;
- else if (ZBX_CONST_STRLEN("avg") == ptr - start && 0 == strncmp(start, "avg", ptr - start))
+ }
+ else if (ZBX_CONST_STRLEN("avg") == len && 0 == strncmp(start, "avg", len))
+ {
segment->data.function.type = ZBX_JSONPATH_FUNCTION_AVG;
- else if (ZBX_CONST_STRLEN("length") == ptr - start && 0 == strncmp(start, "length", ptr - start))
+ }
+ else if (ZBX_CONST_STRLEN("length") == len && 0 == strncmp(start, "length", len))
+ {
segment->data.function.type = ZBX_JSONPATH_FUNCTION_LENGTH;
- else if (ZBX_CONST_STRLEN("first") == ptr - start && 0 == strncmp(start, "first", ptr - start))
+ }
+ else if (ZBX_CONST_STRLEN("first") == len && 0 == strncmp(start, "first", len))
+ {
segment->data.function.type = ZBX_JSONPATH_FUNCTION_FIRST;
- else if (ZBX_CONST_STRLEN("sum") == ptr - start && 0 == strncmp(start, "sum", ptr - start))
+ jsonpath->first_match = 1;
+ }
+ else if (ZBX_CONST_STRLEN("sum") == len && 0 == strncmp(start, "sum", len))
+ {
segment->data.function.type = ZBX_JSONPATH_FUNCTION_SUM;
+ }
else
return zbx_jsonpath_error(start);
@@ -1207,7 +1572,7 @@ static int jsonpath_parse_dot_segment(const char *start, zbx_jsonpath_t *jsonpat
}
}
- if (0 < (len = ptr - start))
+ if (0 < len)
{
segment->type = ZBX_JSONPATH_SEGMENT_MATCH_LIST;
segment->data.list.type = ZBX_JSONPATH_LIST_NAME;
@@ -1247,117 +1612,84 @@ static int jsonpath_parse_name_reference(const char *start, zbx_jsonpath_t *json
/******************************************************************************
* *
- * Purpose: convert a pointer to an object/array/value in json data to *
- * json parse structure *
- * *
- * Parameters: pnext - [IN] a pointer to object/array/value data *
- * jp - [OUT] json parse data with start/end set *
- * *
- * Return value: SUCCEED - pointer was converted successfully *
- * FAIL - otherwise *
- * *
- ******************************************************************************/
-static int jsonpath_pointer_to_jp(const char *pnext, struct zbx_json_parse *jp)
-{
- if ('[' == *pnext || '{' == *pnext)
- {
- return zbx_json_brackets_open(pnext, jp);
- }
- else
- {
- jp->start = pnext;
- jp->end = pnext + json_parse_value(pnext, NULL) - 1;
- return SUCCEED;
- }
-}
-
-/******************************************************************************
- * *
* Purpose: perform the rest of jsonpath query on json data *
* *
- * Parameters: jp_root - [IN] the document root *
- * pnext - [IN] a pointer to object/array/value in json data *
- * jsonpath - [IN] the jsonpath *
+ * Parameters: ctx - [IN] the jsonpath query context *
+ * obj - [IN] the json object *
* path_depth - [IN] the jsonpath segment to match *
- * objects - [OUT] the matched json elements (name, value) *
* *
* Return value: SUCCEED - the data were queried successfully *
* FAIL - otherwise *
* *
******************************************************************************/
-static int jsonpath_query_contents(const struct zbx_json_parse *jp_root, const char *pnext,
- const zbx_jsonpath_t *jsonpath, int path_depth, zbx_vector_json_t *objects)
+static int jsonpath_query_contents(zbx_jsonpath_context_t *ctx, zbx_jsonobj_t *obj, int path_depth)
{
- struct zbx_json_parse jp_child;
+ int ret;
- switch (*pnext)
+ switch (obj->type)
{
- case '{':
- if (FAIL == zbx_json_brackets_open(pnext, &jp_child))
- return FAIL;
-
- return jsonpath_query_object(jp_root, &jp_child, jsonpath, path_depth, objects);
- case '[':
- if (FAIL == zbx_json_brackets_open(pnext, &jp_child))
- return FAIL;
-
- return jsonpath_query_array(jp_root, &jp_child, jsonpath, path_depth, objects);
+ case ZBX_JSON_TYPE_OBJECT:
+ ret = jsonpath_query_object(ctx, obj, path_depth);
+ break;
+ case ZBX_JSON_TYPE_ARRAY:
+ ret = jsonpath_query_array(ctx, obj, path_depth);
+ break;
+ default:
+ ret = SUCCEED;
}
- return SUCCEED;
+
+ return ret;
}
/******************************************************************************
* *
* Purpose: query next segment *
* *
- * Parameters: jp_root - [IN] the document root *
+ * Parameters: ctx - [IN] the jsonpath query context *
* name - [IN] name or index of the next json element *
- * pnext - [IN] a pointer to object/array/value in json data *
- * jsonpath - [IN] the jsonpath *
+ * obj - [IN] the current json object *
* path_depth - [IN] the jsonpath segment to match *
- * objects - [OUT] the matched json elements (name, value) *
* *
* Return value: SUCCEED - the segment was queried successfully *
* FAIL - otherwise *
* *
******************************************************************************/
-static int jsonpath_query_next_segment(const struct zbx_json_parse *jp_root, const char *name, const char *pnext,
- const zbx_jsonpath_t *jsonpath, int path_depth, zbx_vector_json_t *objects)
+static int jsonpath_query_next_segment(zbx_jsonpath_context_t *ctx, const char *name, zbx_jsonobj_t *obj,
+ int path_depth)
{
/* check if jsonpath end has been reached, so we have found matching data */
/* (functions are processed afterwards) */
- if (++path_depth == jsonpath->segments_num ||
- ZBX_JSONPATH_SEGMENT_FUNCTION == jsonpath->segments[path_depth].type)
+ if (++path_depth == ctx->path->segments_num ||
+ ZBX_JSONPATH_SEGMENT_FUNCTION == ctx->path->segments[path_depth].type)
{
- zbx_vector_json_add_element(objects, name, pnext);
+ if (1 == ctx->path->first_match)
+ ctx->found = 1;
+
+ zbx_vector_jsonobj_ref_add_object(&ctx->objects, name, obj);
return SUCCEED;
}
- /* continue by matching found data against the rest of jsonpath segments */
- return jsonpath_query_contents(jp_root, pnext, jsonpath, path_depth, objects);
+ /* continue by matching found object against the rest of jsonpath segments */
+ return jsonpath_query_contents(ctx, obj, path_depth);
}
/******************************************************************************
* *
- * Purpose: match object value name against jsonpath segment name list *
+ * Purpose: match object contents against jsonpath segment name list *
* *
- * Parameters: jp_root - [IN] the document root *
- * name - [IN] name or index of the next json element *
- * pnext - [IN] a pointer to object value with the specified *
- * name *
- * jsonpath - [IN] the jsonpath *
+ * Parameters: ctx - [IN] the jsonpath query context *
+ * parent - [IN] parent json object *
* path_depth - [IN] the jsonpath segment to match *
- * objects - [OUT] the matched json elements (name, value) *
* *
* Return value: SUCCEED - no errors, failed match is not an error *
* FAIL - otherwise *
* *
******************************************************************************/
-static int jsonpath_match_name(const struct zbx_json_parse *jp_root, const char *name, const char *pnext,
- const zbx_jsonpath_t *jsonpath, int path_depth, zbx_vector_json_t *objects)
+static int jsonpath_match_name(zbx_jsonpath_context_t *ctx, zbx_jsonobj_t *parent, int path_depth)
{
- const zbx_jsonpath_segment_t *segment = &jsonpath->segments[path_depth];
+ const zbx_jsonpath_segment_t *segment = &ctx->path->segments[path_depth];
const zbx_jsonpath_list_node_t *node;
+ zbx_jsonobj_el_t el_local, *el;
/* object contents can match only name list */
if (ZBX_JSONPATH_LIST_NAME != segment->data.list.type)
@@ -1365,11 +1697,11 @@ static int jsonpath_match_name(const struct zbx_json_parse *jp_root, const char
for (node = segment->data.list.values; NULL != node; node = node->next)
{
- if (0 == strcmp(name, node->data))
+ el_local.name = (char *)node->data;
+ if (NULL != (el = (zbx_jsonobj_el_t *)zbx_hashset_search(&parent->data.object, &el_local)))
{
- if (FAIL == jsonpath_query_next_segment(jp_root, name, pnext, jsonpath, path_depth, objects))
+ if (FAIL == jsonpath_query_next_segment(ctx, el->name, &el->value, path_depth))
return FAIL;
- break;
}
}
@@ -1380,8 +1712,8 @@ static int jsonpath_match_name(const struct zbx_json_parse *jp_root, const char
* *
* Purpose: extract value from json data by the specified path *
* *
- * Parameters: jp - [IN] the parent object *
- * path - [IN] the jsonpath (definite) *
+ * Parameters: obj - [IN] the parent object *
+ * path - [IN] the jsonpath *
* value - [OUT] the extracted value *
* *
* Return value: SUCCEED - the value was extracted successfully *
@@ -1389,35 +1721,28 @@ static int jsonpath_match_name(const struct zbx_json_parse *jp_root, const char
* extract *
* *
******************************************************************************/
-static int jsonpath_extract_value(const struct zbx_json_parse *jp, const char *path, zbx_variant_t *value)
+static int jsonpath_extract_value(zbx_jsonobj_t *obj, zbx_jsonpath_t *path, zbx_variant_t *value)
{
- struct zbx_json_parse jp_child;
- char *data = NULL, *tmp_path = NULL;
- size_t data_alloc = 0;
- int ret = FAIL;
+ int ret = FAIL;
+ zbx_jsonpath_context_t ctx;
- if ('@' == *path)
- {
- tmp_path = zbx_strdup(NULL, path);
- *tmp_path = '$';
- path = tmp_path;
- }
+ ctx.path = path;
+ ctx.found = 0;
+ ctx.root = obj;
+ zbx_vector_jsonobj_ref_create(&ctx.objects);
- if (FAIL == zbx_json_open_path(jp, path, &jp_child))
- goto out;
-
- if (NULL == zbx_json_decodevalue_dyn(jp_child.start, &data, &data_alloc, NULL))
+ if (SUCCEED == jsonpath_query_contents(&ctx, obj, 0) && 0 != ctx.objects.values_num)
{
- size_t len = jp_child.end - jp_child.start + 2;
+ char *str = NULL;
+ size_t str_alloc = 0, str_offset = 0;
- data = (char *)zbx_malloc(NULL, len);
- zbx_strlcpy(data, jp_child.start, len);
+ jsonpath_str_copy_value(&str, &str_alloc, &str_offset, ctx.objects.values[0].value);
+ zbx_variant_set_str(value, str);
+ ret = SUCCEED;
}
- zbx_variant_set_str(value, data);
- ret = SUCCEED;
-out:
- zbx_free(tmp_path);
+ zbx_vector_jsonobj_ref_clear_ext(&ctx.objects);
+ zbx_vector_jsonobj_ref_destroy(&ctx.objects);
return ret;
}
@@ -1452,7 +1777,7 @@ static char *jsonpath_expression_to_str(zbx_jsonpath_expression_t *expression)
case ZBX_JSONPATH_TOKEN_PATH_RELATIVE:
case ZBX_JSONPATH_TOKEN_CONST_STR:
case ZBX_JSONPATH_TOKEN_CONST_NUM:
- zbx_strcpy_alloc(&str, &str_alloc, &str_offset, token->data);
+ zbx_strcpy_alloc(&str, &str_alloc, &str_offset, token->text);
break;
case ZBX_JSONPATH_TOKEN_PAREN_LEFT:
zbx_strcpy_alloc(&str, &str_alloc, &str_offset, "(");
@@ -1604,35 +1929,123 @@ static int jsonpath_regexp_match(const char *text, const char *pattern, double *
/******************************************************************************
* *
+ * Purpose: add matched object to the index *
+ * *
+ * Parameters: index - [IN] the parent object index *
+ * name - [IN] the name of objec to add to index *
+ * obj - [IN] the object to add to index *
+ * value - [IN] the object matched by index path *
+ * *
+ ******************************************************************************/
+static void jsonpath_index_append_result(zbx_hashset_t *index, const char *name, zbx_jsonobj_t *obj,
+ zbx_jsonobj_t *value)
+{
+ zbx_jsonobj_index_el_t el_local = {.value = NULL}, *el;
+ size_t value_alloc = 0, value_offset = 0;
+ zbx_jsonobj_ref_t ref;
+
+ jsonpath_str_copy_value(&el_local.value, &value_alloc, &value_offset, value);
+
+ if (NULL == (el = (zbx_jsonobj_index_el_t *)zbx_hashset_search(index, &el_local)))
+ {
+ el = (zbx_jsonobj_index_el_t *)zbx_hashset_insert(index, &el_local, sizeof(el_local));
+ zbx_vector_jsonobj_ref_create(&el->objects);
+ }
+ else
+ zbx_free(el_local.value);
+
+ ref.name = zbx_strdup(NULL, name);
+ ref.value = obj;
+ ref.external = 0;
+ zbx_vector_jsonobj_ref_append(&el->objects, ref);
+}
+
+/******************************************************************************
+ * *
+ * Purpose: index json object using the expression token index path *
+ * *
+ * Parameters: obj - [IN] the object to index *
+ * index_token - [IN] the expression index token (relative path) *
+ * *
+ ******************************************************************************/
+static void jsonpath_create_index(zbx_jsonobj_t *obj, zbx_jsonpath_token_t *index_token)
+{
+ zbx_jsonpath_context_t ctx;
+
+ jsonobj_init_index(obj, index_token->text);
+
+ ctx.root = obj;
+ ctx.path = index_token->path;
+ zbx_vector_jsonobj_ref_create(&ctx.objects);
+
+ if (ZBX_JSON_TYPE_OBJECT == obj->type)
+ {
+ zbx_hashset_iter_t iter;
+ zbx_jsonobj_el_t *el;
+
+ zbx_hashset_iter_reset(&obj->data.object, &iter);
+ while (NULL != (el = (zbx_jsonobj_el_t *)zbx_hashset_iter_next(&iter)))
+ {
+ ctx.found = 0;
+ if (SUCCEED == jsonpath_query_contents(&ctx, &el->value, 0) && 1 == ctx.objects.values_num)
+ {
+ jsonpath_index_append_result(&obj->index->objects, el->name, &el->value,
+ ctx.objects.values[0].value);
+ }
+
+ zbx_vector_jsonobj_ref_clear_ext(&ctx.objects);
+ }
+ }
+ else
+ {
+ int i;
+
+ for (i = 0; i < obj->data.array.values_num; i++)
+ {
+ char name[MAX_ID_LEN + 1];
+ zbx_jsonobj_t *value = obj->data.array.values[i];
+
+ zbx_snprintf(name, sizeof(name), "%d", i);
+
+ ctx.found = 0;
+ if (SUCCEED == jsonpath_query_contents(&ctx, value, 0) && 1 == ctx.objects.values_num)
+ {
+ jsonpath_index_append_result(&obj->index->objects, name, value,
+ ctx.objects.values[0].value);
+ }
+
+ zbx_vector_jsonobj_ref_clear_ext(&ctx.objects);
+ }
+ }
+
+ zbx_vector_jsonobj_ref_destroy(&ctx.objects);
+}
+
+/******************************************************************************
+ * *
* Purpose: match json array element/object value against jsonpath expression *
* *
- * Parameters: jp_root - [IN] the document root *
+ * Parameters: ctx - [IN] the jsonpath query context *
* name - [IN] name or index of the next json element *
- * pnext - [IN] a pointer to array element/object value *
- * jsonpath - [IN] the jsonpath *
+ * obj - [IN] the jsonobject to match *
* path_depth - [IN] the jsonpath segment to match *
- * objects - [OUT] the matched json elements (name, value) *
* *
* Return value: SUCCEED - no errors, failed match is not an error *
* FAIL - otherwise *
* *
******************************************************************************/
-static int jsonpath_match_expression(const struct zbx_json_parse *jp_root, const char *name, const char *pnext,
- const zbx_jsonpath_t *jsonpath, int path_depth, zbx_vector_json_t *objects)
+static int jsonpath_match_expression(zbx_jsonpath_context_t *ctx, const char *name, zbx_jsonobj_t *obj,
+ int path_depth)
{
- struct zbx_json_parse jp;
zbx_vector_var_t stack;
int i, ret = SUCCEED;
zbx_jsonpath_segment_t *segment;
zbx_variant_t value, *right;
double res;
- if (SUCCEED != jsonpath_pointer_to_jp(pnext, &jp))
- return FAIL;
-
zbx_vector_var_create(&stack);
- segment = &jsonpath->segments[path_depth];
+ segment = &ctx->path->segments[path_depth];
for (i = 0; i < segment->data.expression.tokens.values_num; i++)
{
@@ -1779,25 +2192,25 @@ static int jsonpath_match_expression(const struct zbx_json_parse *jp_root, const
switch (token->type)
{
case ZBX_JSONPATH_TOKEN_PATH_ABSOLUTE:
- if (FAIL == jsonpath_extract_value(jp_root, token->data, &value))
+ if (FAIL == jsonpath_extract_value(ctx->root, token->path, &value))
zbx_variant_set_none(&value);
zbx_vector_var_append_ptr(&stack, &value);
break;
case ZBX_JSONPATH_TOKEN_PATH_RELATIVE:
/* relative path can be applied only to array or object */
- if ('[' != *jp.start && '{' != *jp.start)
+ if (ZBX_JSON_TYPE_ARRAY != obj->type && ZBX_JSON_TYPE_OBJECT != obj->type)
goto out;
- if (FAIL == jsonpath_extract_value(&jp, token->data, &value))
+ if (FAIL == jsonpath_extract_value(obj, token->path, &value))
zbx_variant_set_none(&value);
zbx_vector_var_append_ptr(&stack, &value);
break;
case ZBX_JSONPATH_TOKEN_CONST_STR:
- zbx_variant_set_str(&value, zbx_strdup(NULL, token->data));
+ zbx_variant_set_str(&value, zbx_strdup(NULL, token->text));
zbx_vector_var_append_ptr(&stack, &value);
break;
case ZBX_JSONPATH_TOKEN_CONST_NUM:
- zbx_variant_set_dbl(&value, atof(token->data));
+ zbx_variant_set_dbl(&value, atof(token->text));
zbx_vector_var_append_ptr(&stack, &value);
break;
case ZBX_JSONPATH_TOKEN_OP_NOT:
@@ -1824,7 +2237,7 @@ static int jsonpath_match_expression(const struct zbx_json_parse *jp_root, const
jsonpath_variant_to_boolean(&stack.values[0]);
if (SUCCEED != zbx_double_compare(stack.values[0].data.dbl, 0.0))
- ret = jsonpath_query_next_segment(jp_root, name, pnext, jsonpath, path_depth, objects);
+ ret = jsonpath_query_next_segment(ctx, name, obj, path_depth);
out:
for (i = 0; i < stack.values_num; i++)
zbx_variant_clear(&stack.values[i]);
@@ -1835,47 +2248,91 @@ out:
/******************************************************************************
* *
+ * Purpose: query indexed object fields for jsonpath segment match *
+ * *
+ * Parameters: ctx - [IN] the jsonpath query context *
+ * obj - [IN] the json object to query *
+ * path_depth - [IN] the jsonpath segment to match *
+ * *
+ * Return value: SUCCEED - the object was queried successfully *
+ * FAIL - otherwise *
+ * *
+ ******************************************************************************/
+static int jsonpath_match_indexed_expression(zbx_jsonpath_context_t *ctx, zbx_jsonobj_t *obj, int path_depth)
+{
+ zbx_jsonpath_segment_t *segment = &ctx->path->segments[path_depth];
+ zbx_jsonobj_index_el_t index_local, *el;
+
+ index_local.value = segment->data.expression.value_token->text;
+
+ if (NULL != (el = (zbx_jsonobj_index_el_t *)zbx_hashset_search(&obj->index->objects, &index_local)))
+ {
+ int i;
+
+ for (i = 0; i < el->objects.values_num; i++)
+ {
+ jsonpath_match_expression(ctx, el->objects.values[i].name, el->objects.values[i].value,
+ path_depth);
+ }
+ }
+
+ return SUCCEED;
+}
+
+/******************************************************************************
+ * *
* Purpose: query object fields for jsonpath segment match *
* *
- * Parameters: jp_root - [IN] the document root *
- * jp - [IN] the json object to query *
- * jsonpath - [IN] the jsonpath *
+ * Parameters: ctx - [IN] the jsonpath query context *
+ * obj - [IN] the json object to query *
* path_depth - [IN] the jsonpath segment to match *
- * objects - [OUT] the matched json elements (name, value) *
* *
* Return value: SUCCEED - the object was queried successfully *
* FAIL - otherwise *
* *
******************************************************************************/
-static int jsonpath_query_object(const struct zbx_json_parse *jp_root, const struct zbx_json_parse *jp,
- const zbx_jsonpath_t *jsonpath, int path_depth, zbx_vector_json_t *objects)
+static int jsonpath_query_object(zbx_jsonpath_context_t *ctx, zbx_jsonobj_t *obj, int path_depth)
{
- const char *pnext = NULL;
- char name[MAX_STRING_LEN];
const zbx_jsonpath_segment_t *segment;
int ret = SUCCEED;
+ zbx_hashset_iter_t iter;
+ zbx_jsonobj_el_t *el;
+
+ segment = &ctx->path->segments[path_depth];
+
+ if (ZBX_JSONPATH_SEGMENT_MATCH_LIST == segment->type)
+ {
+ ret = jsonpath_match_name(ctx, obj, path_depth);
+ if (FAIL == ret || 1 != segment->detached)
+ return ret;
+ }
+ else if (ZBX_JSONPATH_SEGMENT_MATCH_EXPRESSION == segment->type && NULL != segment->data.expression.index_token)
+ {
+ if (NULL == obj->index)
+ jsonpath_create_index(obj, segment->data.expression.index_token);
- segment = &jsonpath->segments[path_depth];
+ if (0 == strcmp(obj->index->path, segment->data.expression.index_token->text))
+ return jsonpath_match_indexed_expression(ctx, obj, path_depth);
+ }
- while (NULL != (pnext = zbx_json_pair_next(jp, pnext, name, sizeof(name))) && SUCCEED == ret)
+ zbx_hashset_iter_reset(&obj->data.object, &iter);
+ while (NULL != (el = (zbx_jsonobj_el_t *)zbx_hashset_iter_next(&iter)) && SUCCEED == ret &&
+ 0 == ctx->found)
{
switch (segment->type)
{
case ZBX_JSONPATH_SEGMENT_MATCH_ALL:
- ret = jsonpath_query_next_segment(jp_root, name, pnext, jsonpath, path_depth, objects);
- break;
- case ZBX_JSONPATH_SEGMENT_MATCH_LIST:
- ret = jsonpath_match_name(jp_root, name, pnext, jsonpath, path_depth, objects);
+ ret = jsonpath_query_next_segment(ctx, el->name, &el->value, path_depth);
break;
case ZBX_JSONPATH_SEGMENT_MATCH_EXPRESSION:
- ret = jsonpath_match_expression(jp_root, name, pnext, jsonpath, path_depth, objects);
+ ret = jsonpath_match_expression(ctx, el->name, &el->value, path_depth);
break;
default:
break;
}
if (1 == segment->detached)
- ret = jsonpath_query_contents(jp_root, pnext, jsonpath, path_depth, objects);
+ ret = jsonpath_query_contents(ctx, &el->value, path_depth);
}
return ret;
@@ -1883,25 +2340,19 @@ static int jsonpath_query_object(const struct zbx_json_parse *jp_root, const str
/******************************************************************************
* *
- * Purpose: match array element against segment index list *
+ * Purpose: array elements against segment index list *
* *
- * Parameters: jp_root - [IN] the document root *
- * name - [IN] the json element name (index) *
- * pnext - [IN] a pointer to an array element *
- * jsonpath - [IN] the jsonpath *
+ * Parameters: ctx - [IN] the jsonpath query context *
+ * parent - [IN] the json array *
* path_depth - [IN] the jsonpath segment to match *
- * index - [IN] the array element index *
- * elements_num - [IN] the total number of elements in array *
- * objects - [OUT] the matched json elements (name, value) *
* *
* Return value: SUCCEED - no errors, failed match is not an error *
* FAIL - otherwise *
* *
******************************************************************************/
-static int jsonpath_match_index(const struct zbx_json_parse *jp_root, const char *name, const char *pnext,
- const zbx_jsonpath_t *jsonpath, int path_depth, int index, int elements_num, zbx_vector_json_t *objects)
+static int jsonpath_match_index(zbx_jsonpath_context_t *ctx, zbx_jsonobj_t *parent, int path_depth)
{
- const zbx_jsonpath_segment_t *segment = &jsonpath->segments[path_depth];
+ const zbx_jsonpath_segment_t *segment = &ctx->path->segments[path_depth];
const zbx_jsonpath_list_node_t *node;
/* array contents can match only index list */
@@ -1914,11 +2365,20 @@ static int jsonpath_match_index(const struct zbx_json_parse *jp_root, const char
memcpy(&query_index, node->data, sizeof(query_index));
- if ((query_index >= 0 && index == query_index) || index == elements_num + query_index)
+ if (0 > query_index)
+ query_index += parent->data.array.values_num;
+
+ if (query_index >= 0 && query_index < parent->data.array.values_num)
{
- if (FAIL == jsonpath_query_next_segment(jp_root, name, pnext, jsonpath, path_depth, objects))
+ char name[MAX_ID_LEN + 1];
+
+ zbx_snprintf(name, sizeof(name), "%d", query_index);
+
+ if (FAIL == jsonpath_query_next_segment(ctx, name, parent->data.array.values[query_index],
+ path_depth))
+ {
return FAIL;
- break;
+ }
}
}
@@ -1927,38 +2387,37 @@ static int jsonpath_match_index(const struct zbx_json_parse *jp_root, const char
/******************************************************************************
* *
- * Purpose: match array element against segment index range *
+ * Purpose: match array elements against segment index range *
* *
- * Parameters: jp_root - [IN] the document root *
- * name - [IN] the json element name (index) *
- * pnext - [IN] a pointer to an array element *
- * jsonpath - [IN] the jsonpath *
- * path_depth - [IN] the jsonpath segment to match *
- * index - [IN] the array element index *
- * elements_num - [IN] the total number of elements in array *
- * objects - [OUT] the matched json elements (name, value) *
+ * Parameters: ctx - [IN] the jsonpath query context *
+ * parent - [IN] the json array *
+ * path_depth - [IN] the jsonpath segment to match *
* *
* Return value: SUCCEED - no errors, failed match is not an error *
* FAIL - otherwise *
* *
******************************************************************************/
-static int jsonpath_match_range(const struct zbx_json_parse *jp_root, const char *name, const char *pnext,
- const zbx_jsonpath_t *jsonpath, int path_depth, int index, int elements_num, zbx_vector_json_t *objects)
+static int jsonpath_match_range(zbx_jsonpath_context_t *ctx, zbx_jsonobj_t *parent, int path_depth)
{
- int start_index, end_index;
- const zbx_jsonpath_segment_t *segment = &jsonpath->segments[path_depth];
+ int i, start_index, end_index, values_num;
+ const zbx_jsonpath_segment_t *segment = &ctx->path->segments[path_depth];
+ values_num = parent->data.array.values_num;
start_index = (0 != (segment->data.range.flags & 0x01) ? segment->data.range.start : 0);
- end_index = (0 != (segment->data.range.flags & 0x02) ? segment->data.range.end : elements_num);
+ end_index = (0 != (segment->data.range.flags & 0x02) ? segment->data.range.end : values_num);
if (0 > start_index)
- start_index += elements_num;
+ start_index += values_num;
if (0 > end_index)
- end_index += elements_num;
+ end_index += values_num;
- if (start_index <= index && end_index > index)
+ for (i = start_index; i < end_index; i++)
{
- if (FAIL == jsonpath_query_next_segment(jp_root, name, pnext, jsonpath, path_depth, objects))
+ char name[MAX_ID_LEN + 1];
+
+ zbx_snprintf(name, sizeof(name), "%d", i);
+
+ if (FAIL == jsonpath_query_next_segment(ctx, name, parent->data.array.values[i], path_depth))
return FAIL;
}
@@ -1967,59 +2426,69 @@ static int jsonpath_match_range(const struct zbx_json_parse *jp_root, const char
/******************************************************************************
* *
- * Purpose: query array elements for jsonpath segment match *
+ * Purpose: query json array for jsonpath segment match *
* *
- * Parameters: jp_root - [IN] the document root *
- * jp - [IN] the json array to query *
- * jsonpath - [IN] the jsonpath *
+ * Parameters: ctx - [IN] the jsonpath query context *
+ * array - [IN] the json array to query *
* path_depth - [IN] the jsonpath segment to match *
- * objects - [OUT] the matched json elements (name, value) *
* *
* Return value: SUCCEED - the array was queried successfully *
* FAIL - otherwise *
* *
******************************************************************************/
-static int jsonpath_query_array(const struct zbx_json_parse *jp_root, const struct zbx_json_parse *jp,
- const zbx_jsonpath_t *jsonpath, int path_depth, zbx_vector_json_t *objects)
+static int jsonpath_query_array(zbx_jsonpath_context_t *ctx, zbx_jsonobj_t *array, int path_depth)
{
- const char *pnext = NULL;
- int index = 0, elements_num = 0, ret = SUCCEED;
+ int ret = SUCCEED, i;
zbx_jsonpath_segment_t *segment;
- segment = &jsonpath->segments[path_depth];
+ segment = &ctx->path->segments[path_depth];
- while (NULL != (pnext = zbx_json_next(jp, pnext)))
- elements_num++;
+ switch (segment->type)
+ {
+ case ZBX_JSONPATH_SEGMENT_MATCH_LIST:
+ ret = jsonpath_match_index(ctx, array, path_depth);
+ if (FAIL == ret || 1 != segment->detached)
+ return ret;
+ break;
+ case ZBX_JSONPATH_SEGMENT_MATCH_RANGE:
+ ret = jsonpath_match_range(ctx, array, path_depth);
+ if (FAIL == ret || 1 != segment->detached)
+ return ret;
+ break;
+ case ZBX_JSONPATH_SEGMENT_MATCH_EXPRESSION:
+ if (NULL != segment->data.expression.index_token)
+ {
+ if (NULL == array->index)
+ jsonpath_create_index(array, segment->data.expression.index_token);
- while (NULL != (pnext = zbx_json_next(jp, pnext)) && SUCCEED == ret)
+ if (0 == strcmp(array->index->path, segment->data.expression.index_token->text))
+ return jsonpath_match_indexed_expression(ctx, array, path_depth);
+ }
+ break;
+ default:
+ break;
+ }
+
+ for (i = 0; i < array->data.array.values_num && SUCCEED == ret && 0 == ctx->found; i++)
{
char name[MAX_ID_LEN + 1];
- zbx_snprintf(name, sizeof(name), "%d", index);
+ zbx_snprintf(name, sizeof(name), "%d", i);
+
switch (segment->type)
{
case ZBX_JSONPATH_SEGMENT_MATCH_ALL:
- ret = jsonpath_query_next_segment(jp_root, name, pnext, jsonpath, path_depth, objects);
- break;
- case ZBX_JSONPATH_SEGMENT_MATCH_LIST:
- ret = jsonpath_match_index(jp_root, name, pnext, jsonpath, path_depth, index,
- elements_num, objects);
- break;
- case ZBX_JSONPATH_SEGMENT_MATCH_RANGE:
- ret = jsonpath_match_range(jp_root, name, pnext, jsonpath, path_depth, index,
- elements_num, objects);
+ ret = jsonpath_query_next_segment(ctx, name, array->data.array.values[i], path_depth);
break;
case ZBX_JSONPATH_SEGMENT_MATCH_EXPRESSION:
- ret = jsonpath_match_expression(jp_root, name, pnext, jsonpath, path_depth, objects);
+ ret = jsonpath_match_expression(ctx, name, array->data.array.values[i], path_depth);
break;
default:
break;
}
if (1 == segment->detached)
- ret = jsonpath_query_contents(jp_root, pnext, jsonpath, path_depth, objects);
-
- index++;
+ ret = jsonpath_query_contents(ctx, array->data.array.values[i], path_depth);
}
return ret;
@@ -2027,123 +2496,99 @@ static int jsonpath_query_array(const struct zbx_json_parse *jp_root, const stru
/******************************************************************************
* *
- * Purpose: extract JSON element value from data *
- * *
- * Parameters: ptr - [IN] pointer to the element to extract *
- * element - [OUT] the extracted element *
+ * Purpose: get numeric value from json data *
* *
- * Return value: SUCCEED - the element was extracted successfully *
- * FAIL - the pointer was not pointing to a JSON element *
+ * Parameters: obj - [IN] json object *
+ * value - [OUT] the extracted value *
* *
- * Comments: String value element is unquoted, other elements are copied as *
- * is. *
+ * Return value: SUCCEED - the value was extracted successfully *
+ * FAIL - the pointer was not pointing at numeric value *
* *
******************************************************************************/
-static int jsonpath_extract_element(const char *ptr, char **element)
+static int jsonpath_get_numeric_value(const zbx_jsonobj_t *obj, double *value)
{
- size_t element_size = 0;
-
- if (NULL == zbx_json_decodevalue_dyn(ptr, element, &element_size, NULL))
+ switch (obj->type)
{
- struct zbx_json_parse jp;
-
- if (SUCCEED != zbx_json_brackets_open(ptr, &jp))
+ case ZBX_JSON_TYPE_NUMBER:
+ *value = obj->data.number;
+ return SUCCEED;
+ case ZBX_JSON_TYPE_STRING:
+ if (SUCCEED == zbx_is_double(obj->data.string, value))
+ return SUCCEED;
+ zbx_set_json_strerror("array value is not a number or out of range: %s", obj->data.string);
+ return FAIL;
+ default:
+ zbx_set_json_strerror("array value type is not a number or string");
return FAIL;
-
- *element = jsonpath_strndup(jp.start, jp.end - jp.start + 1);
}
-
- return SUCCEED;
}
/******************************************************************************
* *
- * Purpose: extract numeric value from json data *
- * *
- * Parameters: ptr - [IN] pointer to the value to extract *
- * value - [OUT] the extracted value *
+ * Purpose: get value from json data *
* *
* Return value: SUCCEED - the value was extracted successfully *
* FAIL - the pointer was not pointing at numeric value *
* *
******************************************************************************/
-static int jsonpath_extract_numeric_value(const char *ptr, double *value)
+static int jsonpath_str_copy_value(char **str, size_t *str_alloc, size_t *str_offset, zbx_jsonobj_t *obj)
{
- char buffer[MAX_STRING_LEN];
-
- if (NULL == zbx_json_decodevalue(ptr, buffer, sizeof(buffer), NULL) ||
- SUCCEED != zbx_is_double(buffer, value))
+ switch (obj->type)
{
- zbx_set_json_strerror("array value is not a number or out of range starting with: %s", ptr);
- return FAIL;
+ case ZBX_JSON_TYPE_STRING:
+ zbx_strcpy_alloc(str, str_alloc, str_offset, obj->data.string);
+ return SUCCEED;
+ break;
+ default:
+ return zbx_jsonobj_to_string(str, str_alloc, str_offset, obj);
}
-
- return SUCCEED;
}
/******************************************************************************
* *
* Purpose: apply jsonpath function to the extracted object list *
* *
- * Parameters: objects - [IN] the matched json elements (name, value) *
+ * Parameters: in - [IN] the matched objects *
* type - [IN] the function type *
- * definite_path - [IN] 1 - if the path is definite (pointing at *
- * single object) *
- * 0 - otherwise *
- * output - [OUT] the output value *
+ * definite_path - [IN/OUT] 1 - if the path is definite (pointing *
+ * at single object) *
+ * 0 - otherwise *
+ * out - [OUT] the result objects *
* *
* Return value: SUCCEED - the function was applied successfully *
* FAIL - invalid input data for the function or internal *
* json error *
* *
******************************************************************************/
-static int jsonpath_apply_function(const zbx_vector_json_t *objects, zbx_jsonpath_function_type_t type,
- int definite_path, char **output)
+static int jsonpath_apply_function(const zbx_vector_jsonobj_ref_t *in, zbx_jsonpath_function_type_t type,
+ int *definite_path, zbx_vector_jsonobj_ref_t *out)
{
- int i, ret = FAIL;
- zbx_vector_json_t objects_tmp;
- double result;
+ int i, ret = FAIL;
+ double result;
+ zbx_vector_jsonobj_ref_t tmp;
+ char buffer[64];
- zbx_vector_json_create(&objects_tmp);
+ zbx_vector_jsonobj_ref_create(&tmp);
if (ZBX_JSONPATH_FUNCTION_NAME == type)
{
- if (0 == objects->values_num)
+ if (0 == in->values_num)
{
zbx_set_json_strerror("cannot extract name from empty result");
goto out;
}
- /* For definite paths we have single output value, so return its name. */
- /* Otherwise return array of all output element names. */
- if (0 == definite_path)
- {
- struct zbx_json j;
-
- /* reserve some space for output json, 1k being large enough to satisfy most queries */
- zbx_json_initarray(&j, 1024);
- for (i = 0; i < objects->values_num; i++)
- zbx_json_addstring(&j, NULL, objects->values[i].name, ZBX_JSON_TYPE_STRING);
-
- zbx_json_close(&j);
- *output = zbx_strdup(NULL, j.buffer);
- zbx_json_clean(&j);
- }
- else
- *output = zbx_strdup(NULL, objects->values[0].name);
+ for (i = 0; i < in->values_num; i++)
+ zbx_vector_jsonobj_ref_add_string(out, "", in->values[i].name);
ret = SUCCEED;
goto out;
}
/* convert definite path result to object array if possible */
- if (0 != definite_path)
+ if (0 != *definite_path)
{
- const char *pnext;
- struct zbx_json_parse jp;
- int index = 0;
-
- if (0 == objects->values_num || '[' != *objects->values[0].value)
+ if (0 == in->values_num || ZBX_JSON_TYPE_ARRAY != in->values[0].value->type)
{
/* all functions can be applied only to arrays */
/* attempt to apply a function to non-array will fail */
@@ -2151,51 +2596,51 @@ static int jsonpath_apply_function(const zbx_vector_json_t *objects, zbx_jsonpat
goto out;
}
- if (FAIL == zbx_json_brackets_open(objects->values[0].value, &jp))
- goto out;
-
- for (pnext = NULL; NULL != (pnext = zbx_json_next(&jp, pnext));)
+ for (i = 0; i < in->values[0].value->data.array.values_num; i++)
{
char name[MAX_ID_LEN + 1];
- zbx_snprintf(name, sizeof(name), "%d", index++);
- zbx_vector_json_add_element(&objects_tmp, name, pnext);
+ zbx_snprintf(name, sizeof(name), "%d", i);
+ zbx_vector_jsonobj_ref_add_object(&tmp, name, in->values[0].value->data.array.values[i]);
}
- objects = &objects_tmp;
+ in = &tmp;
+ *definite_path = 0;
}
if (ZBX_JSONPATH_FUNCTION_LENGTH == type)
{
- *output = zbx_dsprintf(NULL, "%d", objects->values_num);
+ zbx_snprintf(buffer, sizeof(buffer), "%d", in->values_num);
+ zbx_vector_jsonobj_ref_add_string(out, "", buffer);
+ *definite_path = 1;
ret = SUCCEED;
goto out;
}
if (ZBX_JSONPATH_FUNCTION_FIRST == type)
{
- if (0 < objects->values_num)
- ret = jsonpath_extract_element(objects->values[0].value, output);
- else
- ret = SUCCEED;
+ if (0 < in->values_num)
+ zbx_vector_jsonobj_ref_add(out, &in->values[0]);
+ *definite_path = 1;
+ ret = SUCCEED;
goto out;
}
- if (0 == objects->values_num)
+ if (0 == in->values_num)
{
zbx_set_json_strerror("cannot apply aggregation function to empty array");
goto out;
}
- if (FAIL == jsonpath_extract_numeric_value(objects->values[0].value, &result))
+ if (FAIL == jsonpath_get_numeric_value(in->values[0].value, &result))
goto out;
- for (i = 1; i < objects->values_num; i++)
+ for (i = 1; i < in->values_num; i++)
{
double value;
- if (FAIL == jsonpath_extract_numeric_value(objects->values[i].value, &value))
+ if (FAIL == jsonpath_get_numeric_value(in->values[i].value, &value))
goto out;
switch (type)
@@ -2218,19 +2663,22 @@ static int jsonpath_apply_function(const zbx_vector_json_t *objects, zbx_jsonpat
}
if (ZBX_JSONPATH_FUNCTION_AVG == type)
- result /= objects->values_num;
+ result /= in->values_num;
- *output = zbx_dsprintf(NULL, ZBX_FS_DBL, result);
- if (SUCCEED != zbx_is_double(*output, NULL))
+ zbx_print_double(buffer, sizeof(buffer), result);
+ if (SUCCEED != zbx_is_double(buffer, NULL))
{
- zbx_set_json_strerror("invalid function result: %s", *output);
+ zbx_set_json_strerror("invalid function result: %s", buffer);
goto out;
}
- zbx_del_zeros(*output);
+
+ zbx_del_zeros(buffer);
+ zbx_vector_jsonobj_ref_add_string(out, "", buffer);
+ *definite_path = 1;
ret = SUCCEED;
out:
- zbx_vector_json_clear_ext(&objects_tmp);
- zbx_vector_json_destroy(&objects_tmp);
+ zbx_vector_jsonobj_ref_clear_ext(&tmp);
+ zbx_vector_jsonobj_ref_destroy(&tmp);
return ret;
}
@@ -2239,58 +2687,47 @@ out:
* *
* Purpose: apply jsonpath function to the extracted object list *
* *
- * Parameters: jp_root - [IN] the document root *
- * objects - [IN] the matched json elements (name, value) *
- * jsonpath - [IN] the jsonpath *
- * path_depth - [IN] the jsonpath segment to match *
- * output - [OUT] the output value *
+ * Parameters: ctx - [IN] the jsonpath query context *
+ * path_depth - [IN] the jsonpath segment to match *
+ * definite_path - [IN/OUT] *
+ * out - [OUT] the result object *
* *
* Return value: SUCCEED - the function was applied successfully *
* FAIL - invalid input data for the function or internal *
* json error *
* *
******************************************************************************/
-static int jsonpath_apply_functions(const struct zbx_json_parse *jp_root, const zbx_vector_json_t *objects,
- const zbx_jsonpath_t *jsonpath, int path_depth, char **output)
+static int jsonpath_apply_functions(zbx_jsonpath_context_t *ctx, int path_depth, int *definite_path,
+ zbx_vector_jsonobj_ref_t *out)
{
- int ret, definite_path;
- zbx_vector_json_t input;
- char *input_json = NULL;
+ int ret;
+ zbx_vector_jsonobj_ref_t in;
- zbx_vector_json_create(&input);
+ zbx_vector_jsonobj_ref_create(&in);
/* when functions are applied directly to the json document (at the start of the jsonpath ) */
/* it makes all document as input object */
if (0 == path_depth)
- zbx_vector_json_add_element(&input, "", jp_root->start);
+ zbx_vector_jsonobj_ref_add_object(&in, "", ctx->root);
else
- zbx_vector_json_copy(&input, objects);
-
- definite_path = jsonpath->definite;
+ zbx_vector_jsonobj_ref_copy(&in, &ctx->objects);
for (;;)
{
- ret = jsonpath_apply_function(&input, jsonpath->segments[path_depth++].data.function.type,
- definite_path, output);
+ ret = jsonpath_apply_function(&in, ctx->path->segments[path_depth++].data.function.type,
+ definite_path, out);
- zbx_vector_json_clear_ext(&input);
- zbx_free(input_json);
+ zbx_vector_jsonobj_ref_clear_ext(&in);
- if (SUCCEED != ret || path_depth == jsonpath->segments_num)
+ if (SUCCEED != ret || path_depth == ctx->path->segments_num)
break;
- if (NULL != *output)
- {
- zbx_vector_json_add_element(&input, "", *output);
- input_json = *output;
- *output = NULL;
- }
-
- /* functions return single value, so for the next functions path becomes definite */
- definite_path = 1;
+ zbx_vector_jsonobj_ref_copy(&in, out);
+ zbx_vector_jsonobj_ref_clear_ext(out);
}
- zbx_vector_json_destroy(&input);
+ zbx_vector_jsonobj_ref_clear_ext(&in);
+ zbx_vector_jsonobj_ref_destroy(&in);
return ret;
}
@@ -2299,49 +2736,37 @@ static int jsonpath_apply_functions(const struct zbx_json_parse *jp_root, const
* *
* Purpose: format query result, depending on jsonpath type *
* *
- * Parameters: objects - [IN] the matched json elements (name, value) *
- * jsonpath - [IN] the jsonpath used to acquire result *
- * output - [OUT] the output value *
+ * Parameters: objects - [IN] the matched json refs (name, value) *
+ * definite_path - [IN] the jsonpath definite flag *
+ * output - [OUT] the output value *
* *
* Return value: SUCCEED - the result was formatted successfully *
* FAIL - invalid result data (internal json error) *
* *
******************************************************************************/
-static int jsonpath_format_query_result(const zbx_vector_json_t *objects, zbx_jsonpath_t *jsonpath, char **output)
+static int jsonpath_format_query_result(const zbx_vector_jsonobj_ref_t *objects, int definite_path, char **output)
{
size_t output_offset = 0, output_alloc;
int i;
+ char delim;
if (0 == objects->values_num)
return SUCCEED;
- if (1 == jsonpath->definite)
- {
- return jsonpath_extract_element(objects->values[0].value, output);
- }
+ if (1 == definite_path)
+ return jsonpath_str_copy_value(output, &output_alloc, &output_offset, objects->values[0].value);
/* reserve 32 bytes per returned object plus array start/end [] and terminating zero */
- output_alloc = objects->values_num * 32 + 3;
+ output_alloc = (size_t)objects->values_num * 32 + 3;
*output = (char *)zbx_malloc(NULL, output_alloc);
- zbx_chrcpy_alloc(output, &output_alloc, &output_offset, '[');
+ delim = '[';
for (i = 0; i < objects->values_num; i++)
{
- struct zbx_json_parse jp;
-
- if (FAIL == jsonpath_pointer_to_jp(objects->values[i].value, &jp))
- {
- zbx_set_json_strerror("cannot format query result, unrecognized json part starting with: %s",
- objects->values[i].value);
- zbx_free(*output);
- return FAIL;
- }
-
- if (0 != i)
- zbx_chrcpy_alloc(output, &output_alloc, &output_offset, ',');
-
- zbx_strncpy_alloc(output, &output_alloc, &output_offset, jp.start, jp.end - jp.start + 1);
+ zbx_chrcpy_alloc(output, &output_alloc, &output_offset, delim);
+ zbx_jsonobj_to_string(output, &output_alloc, &output_offset, objects->values[i].value);
+ delim = ',';
}
zbx_chrcpy_alloc(output, &output_alloc, &output_offset, ']');
@@ -2364,7 +2789,7 @@ void zbx_jsonpath_clear(zbx_jsonpath_t *jsonpath)
* Purpose: compile jsonpath to be used in queries *
* *
* Parameters: path - [IN] the path to parse *
- * jsonpath - [IN/OUT] the compiled jsonpath *
+ * jsonpath - [IN/OUT] the compiled jsonpath *
* *
* Return value: SUCCEED - the segment was parsed successfully *
* FAIL - otherwise *
@@ -2386,6 +2811,7 @@ int zbx_jsonpath_compile(const char *path, zbx_jsonpath_t *jsonpath)
memset(&jpquery, 0, sizeof(zbx_jsonpath_t));
jsonpath_reserve(&jpquery, 4);
jpquery.definite = 1;
+ jpquery.first_match = 0;
for (ptr++; '\0' != *ptr; ptr = next)
{
@@ -2453,7 +2879,10 @@ int zbx_jsonpath_compile(const char *path, zbx_jsonpath_t *jsonpath)
ret = zbx_jsonpath_error(ptr);
if (SUCCEED == ret)
+ {
+ jpquery.first_match |= jpquery.definite;
*jsonpath = jpquery;
+ }
else
zbx_jsonpath_clear(&jpquery);
@@ -2472,37 +2901,89 @@ int zbx_jsonpath_compile(const char *path, zbx_jsonpath_t *jsonpath)
* being counted as successful query) *
* FAIL - otherwise *
* *
+ * Comments: This function is for compatibility purposes. Where possible the *
+ * zbx_jsonobj_query() function must be used. *
+ * *
******************************************************************************/
int zbx_jsonpath_query(const struct zbx_json_parse *jp, const char *path, char **output)
{
+ int ret;
+ zbx_jsonobj_t obj;
+
+ if (SUCCEED != zbx_jsonobj_open(jp->start, &obj))
+ return FAIL;
+
+ ret = zbx_jsonobj_query(&obj, path, output);
+
+ zbx_jsonobj_clear(&obj);
+
+ return ret;
+}
+
+/******************************************************************************
+ * *
+ * Purpose: perform jsonpath query on the specified json object *
+ * *
+ * Parameters: obj - [IN] the json object *
+ * path - [IN] the jsonpath *
+ * output - [OUT] the output value *
+ * *
+ * Return value: SUCCEED - the query was performed successfully (empty result *
+ * being counted as successful query) *
+ * FAIL - otherwise *
+ * *
+ ******************************************************************************/
+int zbx_jsonobj_query(zbx_jsonobj_t *obj, const char *path, char **output)
+{
+ zbx_jsonpath_context_t ctx;
zbx_jsonpath_t jsonpath;
- int path_depth = 0, ret = SUCCEED;
- zbx_vector_json_t objects;
+ int ret = SUCCEED;
if (FAIL == zbx_jsonpath_compile(path, &jsonpath))
return FAIL;
- zbx_vector_json_create(&objects);
+ ctx.found = 0;
+ ctx.root = obj;
+ ctx.path = &jsonpath;
+ zbx_vector_jsonobj_ref_create(&ctx.objects);
- if ('{' == *jp->start)
- ret = jsonpath_query_object(jp, jp, &jsonpath, path_depth, &objects);
- else if ('[' == *jp->start)
- ret = jsonpath_query_array(jp, jp, &jsonpath, path_depth, &objects);
+ switch (obj->type)
+ {
+ case ZBX_JSON_TYPE_OBJECT:
+ ret = jsonpath_query_object(&ctx, obj, 0);
+ break;
+ case ZBX_JSON_TYPE_ARRAY:
+ ret = jsonpath_query_array(&ctx, obj, 0);
+ break;
+ default:
+ break;
+ }
if (SUCCEED == ret)
{
+ zbx_vector_jsonobj_ref_t out;
+ int definite_path = jsonpath.definite, path_depth;
+
+ zbx_vector_jsonobj_ref_create(&out);
+
path_depth = jsonpath.segments_num;
while (0 < path_depth && ZBX_JSONPATH_SEGMENT_FUNCTION == jsonpath.segments[path_depth - 1].type)
path_depth--;
if (path_depth < jsonpath.segments_num)
- ret = jsonpath_apply_functions(jp, &objects, &jsonpath, path_depth, output);
+ {
+ if (SUCCEED == (ret = jsonpath_apply_functions(&ctx, path_depth, &definite_path, &out)))
+ ret = jsonpath_format_query_result(&out, definite_path, output);
+ }
else
- ret = jsonpath_format_query_result(&objects, &jsonpath, output);
+ ret = jsonpath_format_query_result(&ctx.objects, definite_path, output);
+
+ zbx_vector_jsonobj_ref_clear_ext(&out);
+ zbx_vector_jsonobj_ref_destroy(&out);
}
- zbx_vector_json_clear_ext(&objects);
- zbx_vector_json_destroy(&objects);
+ zbx_vector_jsonobj_ref_clear_ext(&ctx.objects);
+ zbx_vector_jsonobj_ref_destroy(&ctx.objects);
zbx_jsonpath_clear(&jsonpath);
return ret;
diff --git a/src/libs/zbxjson/jsonpath.h b/src/libs/zbxjson/jsonpath.h
index 3a5be7c9413..644aef6aa4a 100644
--- a/src/libs/zbxjson/jsonpath.h
+++ b/src/libs/zbxjson/jsonpath.h
@@ -20,7 +20,9 @@
#ifndef ZABBIX_JSONPATH_H
#define ZABBIX_JSONPATH_H
-#include "zbxalgo.h"
+#include "zbxjson.h"
+
+typedef struct zbx_jsonpath_token zbx_jsonpath_token_t;
typedef enum
{
@@ -78,10 +80,19 @@ typedef struct
}
zbx_jsonpath_range_t;
+typedef enum
+{
+ ZBX_JSONPATH_EXPRESSION_INDEX_TRUE,
+ ZBX_JSONPATH_EXPRESSION_INDEX_FALSE,
+}
+zbx_json_path_expression_index_t;
+
/* expression tokens in postfix notation */
typedef struct
{
zbx_vector_ptr_t tokens;
+ zbx_jsonpath_token_t *index_token; /* relative path token that is used to index parent object */
+ zbx_jsonpath_token_t *value_token; /* the index value token */
}
zbx_jsonpath_expression_t;
@@ -150,11 +161,11 @@ typedef enum
}
zbx_jsonpath_token_type_t;
-typedef struct
+struct zbx_jsonpath_token
{
unsigned char type;
- char *data;
-}
-zbx_jsonpath_token_t;
+ char *text;
+ zbx_jsonpath_t *path;
+};
#endif
diff --git a/src/libs/zbxnum/num.c b/src/libs/zbxnum/num.c
index 9c06ffa138f..0ad81ad3315 100644
--- a/src/libs/zbxnum/num.c
+++ b/src/libs/zbxnum/num.c
@@ -294,7 +294,7 @@ int zbx_is_double(const char *str, double *value)
}
#if defined(_WINDOWS) || defined(__MINGW32__)
-int _wis_uint(const wchar_t *wide_string)
+int zbx_wis_uint(const wchar_t *wide_string)
{
const wchar_t *wide_char = wide_string;
diff --git a/src/libs/zbxsysinfo/common/dir.c b/src/libs/zbxsysinfo/common/dir.c
index 79be22d7297..a207e627147 100644
--- a/src/libs/zbxsysinfo/common/dir.c
+++ b/src/libs/zbxsysinfo/common/dir.c
@@ -28,7 +28,7 @@
#include "log.h"
#if defined(_WINDOWS) || defined(__MINGW32__)
-# include "disk.h"
+# include "zbxwin32.h"
#endif
/******************************************************************************
@@ -590,7 +590,7 @@ static int vfs_dir_size_local(AGENT_REQUEST *request, AGENT_RESULT *result, HAND
goto err2;
}
- if (SIZE_MODE_DISK == mode && 0 == (cluster_size = get_cluster_size(item->path, &error)))
+ if (SIZE_MODE_DISK == mode && 0 == (cluster_size = zbx_get_cluster_size(item->path, &error)))
{
SET_MSG_RESULT(result, error);
list.values_num++;
diff --git a/src/libs/zbxsysinfo/common/system.c b/src/libs/zbxsysinfo/common/system.c
index 6222cee571e..40dc805201a 100644
--- a/src/libs/zbxsysinfo/common/system.c
+++ b/src/libs/zbxsysinfo/common/system.c
@@ -25,7 +25,7 @@
#if defined(_WINDOWS) || defined(__MINGW32__)
# include "zbxsysinfo.h"
-# include "perfmon.h"
+# include "zbxwin32.h"
# pragma comment(lib, "user32.lib")
#endif
@@ -83,8 +83,8 @@ int system_users_num(AGENT_REQUEST *request, AGENT_RESULT *result)
ZBX_UNUSED(request);
zbx_snprintf(counter_path, sizeof(counter_path), "\\%u\\%u",
- (unsigned int)get_builtin_object_index(PCI_TOTAL_SESSIONS),
- (unsigned int)get_builtin_counter_index(PCI_TOTAL_SESSIONS));
+ (unsigned int)zbx_get_builtin_object_index(PCI_TOTAL_SESSIONS),
+ (unsigned int)zbx_get_builtin_counter_index(PCI_TOTAL_SESSIONS));
request_tmp.nparam = 1;
request_tmp.params = zbx_malloc(NULL, request_tmp.nparam * sizeof(char *));
diff --git a/src/libs/zbxsysinfo/linux/diskio.c b/src/libs/zbxsysinfo/linux/diskio.c
index 4464a09c8d2..cc356549508 100644
--- a/src/libs/zbxsysinfo/linux/diskio.c
+++ b/src/libs/zbxsysinfo/linux/diskio.c
@@ -357,6 +357,8 @@ int vfs_dev_discovery(AGENT_REQUEST *request, AGENT_RESULT *result)
zbx_fclose(f);
}
+ else
+ continue;
if (0 == devtype_found)
{
diff --git a/src/libs/zbxsysinfo/linux/hardware.c b/src/libs/zbxsysinfo/linux/hardware.c
index d8eff864d47..8ebd7086a47 100644
--- a/src/libs/zbxsysinfo/linux/hardware.c
+++ b/src/libs/zbxsysinfo/linux/hardware.c
@@ -496,7 +496,12 @@ int system_hw_cpu(AGENT_REQUEST *request, AGENT_RESULT *result)
filter))
{
ret = SYSINFO_RET_OK;
- sscanf(tmp, ZBX_FS_UI64, &curfreq);
+ if (1 != sscanf(tmp, ZBX_FS_UI64, &curfreq))
+ {
+ zbx_fclose(f);
+ SET_MSG_RESULT(result, zbx_strdup(NULL, "Cannot obtain CPU frequency."));
+ return SYSINFO_RET_FAIL;
+ }
}
}
diff --git a/src/libs/zbxsysinfo/linux/proc.c b/src/libs/zbxsysinfo/linux/proc.c
index f2e80c49d09..01b602af9a2 100644
--- a/src/libs/zbxsysinfo/linux/proc.c
+++ b/src/libs/zbxsysinfo/linux/proc.c
@@ -1881,11 +1881,12 @@ int proc_get(AGENT_REQUEST *request, AGENT_RESULT *result)
if (SUCCEED != get_cmdline(f_cmd, &cmdline, &l))
continue;
- read_value_from_proc_file(f_status, 0, "Name", PROC_VAL_TYPE_TEXT, NULL, &prname);
+ if (SUCCEED != read_value_from_proc_file(f_status, 0, "Name", PROC_VAL_TYPE_TEXT, NULL, &prname))
+ continue;
if ('\0' != *cmdline)
{
- char *p, *pend, sep;
+ char *p, *pend, sep = 0;
size_t len;
if (NULL != (pend = strpbrk(cmdline, " :")))
diff --git a/src/libs/zbxsysinfo/sysinfo.h b/src/libs/zbxsysinfo/sysinfo.h
index ba6474293a9..384fbe09c93 100644
--- a/src/libs/zbxsysinfo/sysinfo.h
+++ b/src/libs/zbxsysinfo/sysinfo.h
@@ -176,10 +176,10 @@ int perf_counter(AGENT_REQUEST *request, AGENT_RESULT *result);
int perf_counter_en(AGENT_REQUEST *request, AGENT_RESULT *result);
int perf_instance_discovery(AGENT_REQUEST *request, AGENT_RESULT *result);
int perf_instance_discovery_en(AGENT_REQUEST *request, AGENT_RESULT *result);
-int service_discovery(AGENT_REQUEST *request, AGENT_RESULT *result);
-int service_info(AGENT_REQUEST *request, AGENT_RESULT *result);
-int service_state(AGENT_REQUEST *request, AGENT_RESULT *result);
-int services(AGENT_REQUEST *request, AGENT_RESULT *result);
+int discover_services(AGENT_REQUEST *request, AGENT_RESULT *result);
+int get_service_info(AGENT_REQUEST *request, AGENT_RESULT *result);
+int get_service_state(AGENT_REQUEST *request, AGENT_RESULT *result);
+int get_list_of_services(AGENT_REQUEST *request, AGENT_RESULT *result);
int proc_info(AGENT_REQUEST *request, AGENT_RESULT *result);
int net_if_list(AGENT_REQUEST *request, AGENT_RESULT *result);
int wmi_get(AGENT_REQUEST *request, AGENT_RESULT *result);
diff --git a/src/libs/zbxsysinfo/win32/pdhmon.c b/src/libs/zbxsysinfo/win32/pdhmon.c
index e6787bebed2..2f2cdb4cdfc 100644
--- a/src/libs/zbxsysinfo/win32/pdhmon.c
+++ b/src/libs/zbxsysinfo/win32/pdhmon.c
@@ -104,7 +104,7 @@ static int perf_counter_ex(const char *function, AGENT_REQUEST *request, AGENT_R
goto out;
}
- if (FAIL == check_counter_path(counterpath, PERF_COUNTER_LANG_DEFAULT == lang))
+ if (FAIL == zbx_check_counter_path(counterpath, PERF_COUNTER_LANG_DEFAULT == lang))
{
SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid performance counter path."));
goto out;
diff --git a/src/libs/zbxsysinfo/win32/proc.c b/src/libs/zbxsysinfo/win32/proc.c
index dedbea03361..ed7babb04d1 100644
--- a/src/libs/zbxsysinfo/win32/proc.c
+++ b/src/libs/zbxsysinfo/win32/proc.c
@@ -73,7 +73,10 @@ static int zbx_get_process_username(HANDLE hProcess, char *userName, char *sid)
int iUse, res = FAIL;
/* clean result; */
- *userName = *sid = '\0';
+ *userName = '\0';
+
+ if (NULL != sid)
+ *sid = '\0';
/* open the processes token */
if (0 == OpenProcessToken(hProcess, TOKEN_QUERY, &tok))
diff --git a/src/libs/zbxsysinfo/win32/services.c b/src/libs/zbxsysinfo/win32/services.c
index c80b911ccf3..c3a24fd0ec2 100644
--- a/src/libs/zbxsysinfo/win32/services.c
+++ b/src/libs/zbxsysinfo/win32/services.c
@@ -254,7 +254,7 @@ static zbx_startup_type_t get_service_startup_type(SC_HANDLE h_srv, QUERY_SERVIC
}
}
-int service_discovery(AGENT_REQUEST *request, AGENT_RESULT *result)
+int discover_services(AGENT_REQUEST *request, AGENT_RESULT *result)
{
ENUM_SERVICE_STATUS_PROCESS *ssp = NULL;
SC_HANDLE h_mgr;
@@ -391,7 +391,7 @@ next:
return SYSINFO_RET_OK;
}
-int service_info(AGENT_REQUEST *request, AGENT_RESULT *result)
+int get_service_info(AGENT_REQUEST *request, AGENT_RESULT *result)
{
#define ZBX_SRV_PARAM_STATE 0x01
#define ZBX_SRV_PARAM_DISPLAYNAME 0x02
@@ -550,7 +550,7 @@ int service_info(AGENT_REQUEST *request, AGENT_RESULT *result)
#undef ZBX_NON_EXISTING_SRV
}
-int service_state(AGENT_REQUEST *request, AGENT_RESULT *result)
+int get_service_state(AGENT_REQUEST *request, AGENT_RESULT *result)
{
SC_HANDLE mgr, service;
char *name;
@@ -657,7 +657,8 @@ static int check_service_starttype(SC_HANDLE h_srv, int start_type)
*/
#define ZBX_SRV_STATE_ALL 0x007f /* ZBX_SRV_STATE_STOPPED | ZBX_SRV_STATE_STARTED
*/
-static int check_service_state(SC_HANDLE h_srv, int service_state)
+
+static int get_service_state_local(SC_HANDLE h_srv, int service_state)
{
SERVICE_STATUS status;
@@ -699,7 +700,7 @@ static int check_service_state(SC_HANDLE h_srv, int service_state)
return FAIL;
}
-int services(AGENT_REQUEST *request, AGENT_RESULT *result)
+int get_list_of_services(AGENT_REQUEST *request, AGENT_RESULT *result)
{
int start_type, service_state;
char *type, *state, *exclude, *buf = NULL, *utf8;
@@ -776,7 +777,7 @@ int services(AGENT_REQUEST *request, AGENT_RESULT *result)
if (SUCCEED == check_service_starttype(h_srv, start_type))
{
- if (SUCCEED == check_service_state(h_srv, service_state))
+ if (SUCCEED == get_service_state_local(h_srv, service_state))
{
utf8 = zbx_unicode_to_utf8(ssp[i].lpServiceName);
@@ -811,17 +812,3 @@ int services(AGENT_REQUEST *request, AGENT_RESULT *result)
return SYSINFO_RET_OK;
}
-#undef ZBX_SRV_STARTTYPE_ALL
-#undef ZBX_SRV_STARTTYPE_AUTOMATIC
-#undef ZBX_SRV_STARTTYPE_MANUAL
-#undef ZBX_SRV_STARTTYPE_DISABLED
-
-#undef ZBX_SRV_STATE_STOPPED
-#undef ZBX_SRV_STATE_START_PENDING
-#undef ZBX_SRV_STATE_STOP_PENDING
-#undef ZBX_SRV_STATE_RUNNING
-#undef ZBX_SRV_STATE_CONTINUE_PENDING
-#undef ZBX_SRV_STATE_PAUSE_PENDING
-#undef ZBX_SRV_STATE_PAUSED
-#undef ZBX_SRV_STATE_STARTED
-#undef ZBX_SRV_STATE_ALL
diff --git a/src/libs/zbxsysinfo/win32/system.c b/src/libs/zbxsysinfo/win32/system.c
index 99cdef09897..cc35553090c 100644
--- a/src/libs/zbxsysinfo/win32/system.c
+++ b/src/libs/zbxsysinfo/win32/system.c
@@ -24,7 +24,7 @@
#include "cfg.h"
#include "zbxtime.h"
-#include "perfmon.h"
+#include "zbxwin32.h"
#pragma comment(lib, "user32.lib")
diff --git a/src/libs/zbxsysinfo/win32/uptime.c b/src/libs/zbxsysinfo/win32/uptime.c
index 91d047ea627..d264c3c9f61 100644
--- a/src/libs/zbxsysinfo/win32/uptime.c
+++ b/src/libs/zbxsysinfo/win32/uptime.c
@@ -20,7 +20,7 @@
#include "zbxsysinfo.h"
#include "../sysinfo.h"
-#include "perfmon.h"
+#include "zbxwin32.h"
int system_uptime(AGENT_REQUEST *request, AGENT_RESULT *result)
{
@@ -29,8 +29,8 @@ int system_uptime(AGENT_REQUEST *request, AGENT_RESULT *result)
int ret;
zbx_snprintf(counter_path, sizeof(counter_path), "\\%u\\%u",
- (unsigned int)get_builtin_object_index(PCI_SYSTEM_UP_TIME),
- (unsigned int)get_builtin_counter_index(PCI_SYSTEM_UP_TIME));
+ (unsigned int)zbx_get_builtin_object_index(PCI_SYSTEM_UP_TIME),
+ (unsigned int)zbx_get_builtin_counter_index(PCI_SYSTEM_UP_TIME));
request_tmp.nparam = 1;
request_tmp.params = zbx_malloc(NULL, request_tmp.nparam * sizeof(char *));
diff --git a/src/libs/zbxsysinfo/win32/win32.c b/src/libs/zbxsysinfo/win32/win32.c
index 3357f46d566..65ec0854913 100644
--- a/src/libs/zbxsysinfo/win32/win32.c
+++ b/src/libs/zbxsysinfo/win32/win32.c
@@ -56,10 +56,10 @@ ZBX_METRIC parameters_specific[] =
{"system.uname", 0, system_uname, NULL},
- {"service.discovery", 0, service_discovery, NULL},
- {"service.info", CF_HAVEPARAMS, service_info, ZABBIX_SERVICE_NAME},
- {"service_state", CF_HAVEPARAMS, service_state, ZABBIX_SERVICE_NAME},
- {"services", CF_HAVEPARAMS, services, NULL},
+ {"service.discovery", 0, discover_services, NULL},
+ {"service.info", CF_HAVEPARAMS, get_service_info, ZABBIX_SERVICE_NAME},
+ {"service_state", CF_HAVEPARAMS, get_service_state, ZABBIX_SERVICE_NAME},
+ {"services", CF_HAVEPARAMS, get_list_of_services, NULL},
{"perf_counter", CF_HAVEPARAMS, perf_counter, "\\System\\Processes"},
{"perf_counter_en", CF_HAVEPARAMS, perf_counter_en, "\\System\\Processes"},
{"perf_instance.discovery", CF_HAVEPARAMS, perf_instance_discovery, "Processor"},
diff --git a/src/libs/zbxwin32/disk.c b/src/libs/zbxwin32/disk.c
index 7b88dc80b68..da2bdebe1be 100644
--- a/src/libs/zbxwin32/disk.c
+++ b/src/libs/zbxwin32/disk.c
@@ -17,6 +17,8 @@
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
**/
+#include "zbxwin32.h"
+
#include "zbxstr.h"
#include "log.h"
@@ -32,7 +34,7 @@
* On error, 0 is returned. *
* *
******************************************************************************/
-zbx_uint64_t get_cluster_size(const char *path, char **error)
+zbx_uint64_t zbx_get_cluster_size(const char *path, char **error)
{
wchar_t *disk = NULL, *wpath = NULL;
unsigned long sectors_per_cluster, bytes_per_sector, path_length;
diff --git a/src/libs/zbxwin32/fatal.c b/src/libs/zbxwin32/fatal.c
index 9e040c6dca5..7c684fb9615 100644
--- a/src/libs/zbxwin32/fatal.c
+++ b/src/libs/zbxwin32/fatal.c
@@ -17,6 +17,8 @@
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
**/
+#include "zbxwin32.h"
+
#include "zbxstr.h"
#include "log.h"
@@ -25,28 +27,35 @@
#pragma comment(lib, "DbgHelp.lib")
-#define STACKWALK_MAX_NAMELEN 4096
-
-#define ZBX_LSHIFT(value, bits) (((unsigned __int64)value) << bits)
-
-extern const char *progname;
+typedef BOOL (WINAPI *SymGetLineFromAddrW64_func_t)(HANDLE, DWORD64, PDWORD, PIMAGEHLP_LINE64);
+typedef BOOL (WINAPI *SymFromAddr_func_t)(HANDLE a, DWORD64 b , PDWORD64 c, PSYMBOL_INFO d);
#ifdef _M_X64
-
-#define ZBX_IMAGE_FILE_MACHINE IMAGE_FILE_MACHINE_AMD64
-
static void print_register(const char *name, unsigned __int64 value)
{
zabbix_log(LOG_LEVEL_CRIT, "%-7s = %16I64x = %20I64u = %20I64d", name, value, value, value);
}
+#else
+static void print_register(const char *name, unsigned __int32 value)
+{
+ zabbix_log(LOG_LEVEL_CRIT, "%-7s = %16lx = %20lu = %20ld", name, value, value, value);
+}
+#endif
static void print_fatal_info(CONTEXT *pctx)
{
zabbix_log(LOG_LEVEL_CRIT, "====== Fatal information: ======");
+#ifdef _M_X64
zabbix_log(LOG_LEVEL_CRIT, "Program counter: 0x%08lx", pctx->Rip);
+#else
+ zabbix_log(LOG_LEVEL_CRIT, "Program counter: 0x%04x", pctx->Eip);
+#endif
zabbix_log(LOG_LEVEL_CRIT, "=== Registers: ===");
+#define ZBX_LSHIFT(value, bits) (((unsigned __int64)value) << bits)
+
+#ifdef _M_X64
print_register("r8", pctx->R8);
print_register("r9", pctx->R9);
print_register("r10", pctx->R10);
@@ -68,24 +77,7 @@ static void print_fatal_info(CONTEXT *pctx)
print_register("rsp", pctx->Rsp);
print_register("efl", pctx->EFlags);
print_register("csgsfs", ZBX_LSHIFT(pctx->SegCs, 24) | ZBX_LSHIFT(pctx->SegGs, 16) | ZBX_LSHIFT(pctx->SegFs, 8));
-}
-
#else
-
-#define ZBX_IMAGE_FILE_MACHINE IMAGE_FILE_MACHINE_I386
-
-static void print_register(const char *name, unsigned __int32 value)
-{
- zabbix_log(LOG_LEVEL_CRIT, "%-7s = %16lx = %20lu = %20ld", name, value, value, value);
-}
-
-static void print_fatal_info(CONTEXT *pctx)
-{
- zabbix_log(LOG_LEVEL_CRIT, "====== Fatal information: ======");
-
- zabbix_log(LOG_LEVEL_CRIT, "Program counter: 0x%04x", pctx->Eip);
- zabbix_log(LOG_LEVEL_CRIT, "=== Registers: ===");
-
print_register("edi", pctx->Edi);
print_register("esi", pctx->Esi);
print_register("ebp", pctx->Ebp);
@@ -98,12 +90,12 @@ static void print_fatal_info(CONTEXT *pctx)
print_register("esp", pctx->Esp);
print_register("efl", pctx->EFlags);
print_register("csgsfs", ZBX_LSHIFT(pctx->SegCs, 24) | ZBX_LSHIFT(pctx->SegGs, 16) | ZBX_LSHIFT(pctx->SegFs, 8));
-}
-
#endif
-typedef BOOL (WINAPI *SymGetLineFromAddrW64_func_t)(HANDLE, DWORD64, PDWORD, PIMAGEHLP_LINE64);
-typedef BOOL (WINAPI *SymFromAddr_func_t)(HANDLE a, DWORD64 b , PDWORD64 c, PSYMBOL_INFO d);
+#undef ZBX_LSHIFT
+}
+
+static zbx_get_progname_f get_progname_cb = NULL;
void zbx_backtrace(void)
{
@@ -154,7 +146,7 @@ static void print_backtrace(CONTEXT *pctx)
process_name = zbx_unicode_to_utf8(szProcessName);
- if (NULL != (ptr = strstr(process_name, progname)))
+ if (NULL != (ptr = strstr(process_name, get_progname_cb())))
zbx_strncpy_alloc(&process_path, &path_alloc, &path_offset, process_name, ptr - process_name);
}
@@ -181,6 +173,12 @@ static void print_backtrace(CONTEXT *pctx)
scount = s;
ctxcount = ctx;
+#ifdef _M_X64
+#define ZBX_IMAGE_FILE_MACHINE IMAGE_FILE_MACHINE_AMD64
+#else
+#define ZBX_IMAGE_FILE_MACHINE IMAGE_FILE_MACHINE_I386
+#endif
+
/* get number of frames, ctxcount may be modified during StackWalk64() calls */
while (TRUE == StackWalk64(ZBX_IMAGE_FILE_MACHINE, hProcess, hThread, &scount, &ctxcount, NULL, NULL, NULL,
NULL))
@@ -223,6 +221,8 @@ static void print_backtrace(CONTEXT *pctx)
break;
}
+#undef ZBX_IMAGE_FILE_MACHINE
+
SymCleanup(hProcess);
zbx_free(frame);
@@ -231,6 +231,11 @@ static void print_backtrace(CONTEXT *pctx)
zbx_free(pSym);
}
+void zbx_init_library_win32(zbx_get_progname_f get_progname)
+{
+ get_progname_cb = get_progname;
+}
+
int zbx_win_exception_filter(struct _EXCEPTION_POINTERS *ep)
{
zabbix_log(LOG_LEVEL_CRIT, "Unhandled exception %x detected at 0x%p. Crashing ...",
diff --git a/src/libs/zbxwin32/perfmon.c b/src/libs/zbxwin32/perfmon.c
index 661b6af2fa2..9958556ba0f 100644
--- a/src/libs/zbxwin32/perfmon.c
+++ b/src/libs/zbxwin32/perfmon.c
@@ -17,9 +17,10 @@
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
**/
-#include "perfmon.h"
+#include "zbxwin32.h"
#include "zbxstr.h"
+#include "zbxnum.h"
#include "stats.h"
#include "log.h"
@@ -230,7 +231,7 @@ PDH_STATUS zbx_PdhGetRawCounterValue(const char *function, const char *counterpa
* sleep 1 second to get the second raw value. *
* *
******************************************************************************/
-PDH_STATUS calculate_counter_value(const char *function, const char *counterpath,
+PDH_STATUS zbx_calculate_counter_value(const char *function, const char *counterpath,
zbx_perf_counter_lang_t lang, double *value)
{
PDH_HQUERY query;
@@ -300,7 +301,7 @@ close_query:
* installations for the same names *
* *
******************************************************************************/
-DWORD get_builtin_object_index(zbx_builtin_counter_ref_t counter_ref)
+DWORD zbx_get_builtin_object_index(zbx_builtin_counter_ref_t counter_ref)
{
return builtin_object_map[builtin_counter_map[counter_ref].object].pdhIndex;
}
@@ -316,7 +317,7 @@ DWORD get_builtin_object_index(zbx_builtin_counter_ref_t counter_ref)
* installations for the same names *
* *
******************************************************************************/
-DWORD get_builtin_counter_index(zbx_builtin_counter_ref_t counter_ref)
+DWORD zbx_get_builtin_counter_index(zbx_builtin_counter_ref_t counter_ref)
{
return builtin_counter_map[counter_ref].pdhIndex;
}
@@ -340,7 +341,7 @@ DWORD get_builtin_counter_index(zbx_builtin_counter_ref_t counter_ref)
* by the caller. *
* *
******************************************************************************/
-wchar_t *get_all_counter_names(HKEY reg_key, wchar_t *reg_value_name)
+wchar_t *zbx_get_all_counter_names(HKEY reg_key, wchar_t *reg_value_name)
{
wchar_t *buffer = NULL;
DWORD buffer_size = 0;
@@ -508,7 +509,7 @@ out:
* initialization from init_perf_collector(). *
* *
******************************************************************************/
-int init_builtin_counter_indexes(void)
+int zbx_init_builtin_counter_indexes(void)
{
int ret = SUCCEED, i;
wchar_t *counter_text, *eng_names, *counter_base;
@@ -526,7 +527,7 @@ int init_builtin_counter_indexes(void)
/* Get buffer holding a list of performance counter indexes and English counter names. */
/* L"Counter" stores names, L"Help" stores descriptions ("Help" is not used). */
- if (NULL == (counter_base = eng_names = get_all_counter_names(HKEY_PERFORMANCE_TEXT, L"Counter")))
+ if (NULL == (counter_base = eng_names = zbx_get_all_counter_names(HKEY_PERFORMANCE_TEXT, L"Counter")))
{
ret = FAIL;
goto out;
@@ -568,7 +569,7 @@ int init_builtin_counter_indexes(void)
builtin_counter_map[i].minSupported_dwMajorVersion && vi->dwMinorVersion >=
builtin_counter_map[i].minSupported_dwMinorVersion && 0 ==
wcscmp(builtin_counter_map[i].eng_name, counter_text) && SUCCEED ==
- validate_object_counter(get_builtin_object_index(i), counter_index))
+ validate_object_counter(zbx_get_builtin_object_index(i), counter_index))
{
builtin_counter_map[i].pdhIndex = counter_index;
break;
@@ -617,7 +618,7 @@ out:
* installations for the same names *
* *
******************************************************************************/
-wchar_t *get_counter_name(DWORD pdhIndex)
+wchar_t *zbx_get_counter_name(DWORD pdhIndex)
{
zbx_perf_counter_id_t *counterName;
@@ -656,7 +657,7 @@ wchar_t *get_counter_name(DWORD pdhIndex)
return counterName->name;
}
-int check_counter_path(char *counterPath, int convert_from_numeric)
+int zbx_check_counter_path(char *counterPath, int convert_from_numeric)
{
PDH_COUNTER_PATH_ELEMENTS *cpe = NULL;
PDH_STATUS status;
@@ -687,15 +688,15 @@ int check_counter_path(char *counterPath, int convert_from_numeric)
if (0 != convert_from_numeric)
{
- int is_numeric = (SUCCEED == _wis_uint(cpe->szObjectName) ? 0x01 : 0);
- is_numeric |= (SUCCEED == _wis_uint(cpe->szCounterName) ? 0x02 : 0);
+ int is_numeric = (SUCCEED == zbx_wis_uint(cpe->szObjectName) ? 0x01 : 0);
+ is_numeric |= (SUCCEED == zbx_wis_uint(cpe->szCounterName) ? 0x02 : 0);
if (0 != is_numeric)
{
if (0x01 & is_numeric)
- cpe->szObjectName = get_counter_name(_wtoi(cpe->szObjectName));
+ cpe->szObjectName = zbx_get_counter_name(_wtoi(cpe->szObjectName));
if (0x02 & is_numeric)
- cpe->szCounterName = get_counter_name(_wtoi(cpe->szCounterName));
+ cpe->szCounterName = zbx_get_counter_name(_wtoi(cpe->szCounterName));
if (ERROR_SUCCESS != zbx_PdhMakeCounterPath(__func__, cpe, counterPath))
goto clean;
diff --git a/src/libs/zbxwin32/service.c b/src/libs/zbxwinservice/service.c
index 767591843b4..c83f3510185 100644
--- a/src/libs/zbxwin32/service.c
+++ b/src/libs/zbxwinservice/service.c
@@ -23,7 +23,6 @@
#include "cfg.h"
#include "log.h"
#include "zbxconf.h"
-#include "perfmon.h"
#define EVENTLOG_REG_PATH TEXT("SYSTEM\\CurrentControlSet\\Services\\EventLog\\")
@@ -117,6 +116,9 @@ static VOID WINAPI ServiceEntry(DWORD argc, wchar_t **argv)
{
wchar_t *wservice_name;
+ ZBX_UNUSED(argc);
+ ZBX_UNUSED(argv);
+
wservice_name = zbx_utf8_to_unicode(ZABBIX_SERVICE_NAME);
serviceHandle = RegisterServiceCtrlHandler(wservice_name, ServiceCtrlHandler);
zbx_free(wservice_name);
@@ -140,7 +142,7 @@ static VOID WINAPI ServiceEntry(DWORD argc, wchar_t **argv)
MAIN_ZABBIX_ENTRY(0);
}
-void service_start(int flags)
+void zbx_service_start(int flags)
{
int ret;
static SERVICE_TABLE_ENTRY serviceTable[2];
@@ -425,7 +427,7 @@ int ZabbixStopService(void)
return ret;
}
-void set_parent_signal_handler(zbx_on_exit_t zbx_on_exit_cb_arg)
+void zbx_set_parent_signal_handler(zbx_on_exit_t zbx_on_exit_cb_arg)
{
zbx_on_exit_cb = zbx_on_exit_cb_arg;
signal(SIGINT, parent_signal_handler);
diff --git a/src/zabbix_agent/Makefile.am b/src/zabbix_agent/Makefile.am
index 7faa9ad9a17..39ce4441557 100644
--- a/src/zabbix_agent/Makefile.am
+++ b/src/zabbix_agent/Makefile.am
@@ -54,7 +54,6 @@ zabbix_agentd_LDADD = \
$(top_builddir)/src/libs/zbxsysinfo/alias/libalias.a \
$(top_builddir)/src/libs/zbxlog/libzbxlog.a \
$(top_builddir)/src/libs/zbxregexp/libzbxregexp.a \
- $(top_builddir)/src/libs/zbxalgo/libzbxalgo.a \
$(top_builddir)/src/libs/zbxthreads/libzbxthreads.a \
$(top_builddir)/src/libs/zbxmutexs/libzbxmutexs.a \
$(top_builddir)/src/libs/zbxnix/libzbxnix.a \
@@ -62,6 +61,7 @@ zabbix_agentd_LDADD = \
$(top_builddir)/src/libs/zbxcommshigh/libzbxcommshigh.a \
$(top_builddir)/src/libs/zbxconf/libzbxconf.a \
$(top_builddir)/src/libs/zbxjson/libzbxjson.a \
+ $(top_builddir)/src/libs/zbxalgo/libzbxalgo.a \
$(top_builddir)/src/libs/zbxvariant/libzbxvariant.a \
$(top_builddir)/src/libs/zbxcommon/libzbxcommon.a \
$(top_builddir)/src/libs/zbxgetopt/libzbxgetopt.a \
diff --git a/src/zabbix_agent/cpustat.c b/src/zabbix_agent/cpustat.c
index 2bdc991ed6d..4f465d8021b 100644
--- a/src/zabbix_agent/cpustat.c
+++ b/src/zabbix_agent/cpustat.c
@@ -136,11 +136,11 @@ int init_cpu_collector(ZBX_CPUS_STAT_DATA *pcpus)
#ifdef _WINDOWS
cpe.szMachineName = NULL;
- cpe.szObjectName = get_builtin_object_name(PCI_PROCESSOR_TIME);
+ cpe.szObjectName = zbx_get_builtin_object_name(PCI_PROCESSOR_TIME);
cpe.szInstanceName = cpu;
cpe.szParentInstance = NULL;
cpe.dwInstanceIndex = (DWORD)-1;
- cpe.szCounterName = get_builtin_counter_name(PCI_PROCESSOR_TIME);
+ cpe.szCounterName = zbx_get_builtin_counter_name(PCI_PROCESSOR_TIME);
/* 64 logical CPUs (threads) is a hard limit for 32-bit Windows systems and some old 64-bit versions, */
/* such as Windows Vista. Systems with <= 64 threads will always have one processor group, which means */
@@ -190,8 +190,8 @@ int init_cpu_collector(ZBX_CPUS_STAT_DATA *pcpus)
pcpus->count, cpu_groups);
- cpe.szObjectName = get_builtin_object_name(PCI_INFORMATION_PROCESSOR_TIME);
- cpe.szCounterName = get_builtin_counter_name(PCI_INFORMATION_PROCESSOR_TIME);
+ cpe.szObjectName = zbx_get_builtin_object_name(PCI_INFORMATION_PROCESSOR_TIME);
+ cpe.szCounterName = zbx_get_builtin_counter_name(PCI_INFORMATION_PROCESSOR_TIME);
/* This doesn't seem to be well documented but it looks like Windows treats Processor Information */
/* object differently on NUMA-enabled systems. First index for the object may either mean logical */
@@ -232,9 +232,9 @@ int init_cpu_collector(ZBX_CPUS_STAT_DATA *pcpus)
}
}
- cpe.szObjectName = get_builtin_object_name(PCI_PROCESSOR_QUEUE_LENGTH);
+ cpe.szObjectName = zbx_get_builtin_object_name(PCI_PROCESSOR_QUEUE_LENGTH);
cpe.szInstanceName = NULL;
- cpe.szCounterName = get_builtin_counter_name(PCI_PROCESSOR_QUEUE_LENGTH);
+ cpe.szCounterName = zbx_get_builtin_counter_name(PCI_PROCESSOR_QUEUE_LENGTH);
if (ERROR_SUCCESS != zbx_PdhMakeCounterPath(__func__, &cpe, counterPath))
goto clean;
diff --git a/src/zabbix_agent/cpustat.h b/src/zabbix_agent/cpustat.h
index c4ffc5f6599..fe58eeb77f5 100644
--- a/src/zabbix_agent/cpustat.h
+++ b/src/zabbix_agent/cpustat.h
@@ -24,7 +24,7 @@
#include "zbxalgo.h"
#ifdef _WINDOWS
-# include "perfmon.h"
+# include "zbxwin32.h"
typedef struct
{
diff --git a/src/zabbix_agent/perfstat.c b/src/zabbix_agent/perfstat.c
index bc1d23619da..3f846f94d79 100644
--- a/src/zabbix_agent/perfstat.c
+++ b/src/zabbix_agent/perfstat.c
@@ -249,8 +249,8 @@ static int set_object_names(void)
if (TRUE == refresh)
ppsd.lastrefresh_objects = time(NULL);
- if (NULL == (p_eng = names_eng = get_all_counter_names(HKEY_PERFORMANCE_TEXT, L"Counter")) ||
- NULL == (p_loc = names_loc = get_all_counter_names(HKEY_PERFORMANCE_NLSTEXT, L"Counter")))
+ if (NULL == (p_eng = names_eng = zbx_get_all_counter_names(HKEY_PERFORMANCE_TEXT, L"Counter")) ||
+ NULL == (p_loc = names_loc = zbx_get_all_counter_names(HKEY_PERFORMANCE_NLSTEXT, L"Counter")))
{
goto out;
}
@@ -448,7 +448,7 @@ int init_perf_collector(zbx_threadedness_t threadedness, char **error)
ppsd.lastrefresh_objects = 0;
ppsd.lastupdate_names = 0;
- if (SUCCEED != init_builtin_counter_indexes())
+ if (SUCCEED != zbx_init_builtin_counter_indexes())
{
*error = zbx_strdup(*error, "cannot initialize built-in counter indexes");
goto out;
@@ -680,7 +680,7 @@ out:
if (NULL != counterpath)
{
/* request counter value directly from Windows performance counters */
- PDH_STATUS pdh_status = calculate_counter_value(__func__, counterpath, perfs->lang, value);
+ PDH_STATUS pdh_status = zbx_calculate_counter_value(__func__, counterpath, perfs->lang, value);
if (PDH_NOT_IMPLEMENTED == pdh_status)
*error = zbx_strdup(*error, "Counter is not supported for this Microsoft Windows version");
@@ -756,7 +756,7 @@ out:
if (SUCCEED != ret && NULL != perfs)
{
/* request counter value directly from Windows performance counters */
- if (ERROR_SUCCESS == calculate_counter_value(__func__, counterpath, lang, value))
+ if (ERROR_SUCCESS == zbx_calculate_counter_value(__func__, counterpath, lang, value))
ret = SUCCEED;
}
diff --git a/src/zabbix_agent/perfstat.h b/src/zabbix_agent/perfstat.h
index 8b2ff9474a0..525f6af2b16 100644
--- a/src/zabbix_agent/perfstat.h
+++ b/src/zabbix_agent/perfstat.h
@@ -24,7 +24,7 @@
# error "This module is only available for Windows OS"
#endif
-#include "perfmon.h"
+#include "zbxwin32.h"
zbx_perf_counter_data_t *add_perf_counter(const char *name, const char *counterpath, int interval,
zbx_perf_counter_lang_t lang, char **error);
diff --git a/src/zabbix_agent/zabbix_agentd.c b/src/zabbix_agent/zabbix_agentd.c
index 47b3b0c74da..8551c8a8136 100644
--- a/src/zabbix_agent/zabbix_agentd.c
+++ b/src/zabbix_agent/zabbix_agentd.c
@@ -86,6 +86,7 @@ int CONFIG_HEARTBEAT_FREQUENCY = 60;
#include "stats.h"
#ifdef _WINDOWS
# include "perfstat.h"
+# include "zbxwin32.h"
#else
# include "zbxnix.h"
#endif
@@ -242,6 +243,13 @@ static unsigned char get_program_type(void)
return program_type;
}
+#if defined(_WINDOWS) || defined(__MINGW32__)
+static const char *get_progname(void)
+{
+ return progname;
+}
+#endif
+
static zbx_thread_activechk_args *config_active_args = NULL;
int CONFIG_ALERTER_FORKS = 0;
@@ -286,7 +294,6 @@ char *opt = NULL;
#ifdef _WINDOWS
void zbx_co_uninitialize();
-int zbx_win_exception_filter(struct _EXCEPTION_POINTERS *ep);
#endif
int get_process_info_by_thread(int local_server_num, unsigned char *local_process_type, int *local_process_num);
@@ -1248,7 +1255,7 @@ int MAIN_ZABBIX_ENTRY(int flags)
}
#ifdef _WINDOWS
- set_parent_signal_handler(zbx_on_exit); /* must be called after all threads are created */
+ zbx_set_parent_signal_handler(zbx_on_exit); /* must be called after all threads are created */
/* wait for an exiting thread */
res = WaitForMultipleObjectsEx(threads_num, threads, FALSE, INFINITE, FALSE);
@@ -1339,7 +1346,11 @@ int main(int argc, char **argv)
char *error = NULL;
#ifdef _WINDOWS
int ret;
-
+#endif
+#if defined(_WINDOWS) || defined(__MINGW32__)
+ zbx_init_library_win32(&get_progname);
+#endif
+#ifdef _WINDOWS
/* Provide, so our process handles errors instead of the system itself. */
/* Attention!!! */
/* The system does not display the critical-error-handler message box. */
@@ -1491,7 +1502,7 @@ int main(int argc, char **argv)
}
#if defined(ZABBIX_SERVICE)
- service_start(t.flags);
+ zbx_service_start(t.flags);
#elif defined(ZABBIX_DAEMON)
zbx_daemon_start(config_allow_root, CONFIG_USER, t.flags, get_pid_file_path, zbx_on_exit);
#endif
diff --git a/src/zabbix_agent/zbxconf.c b/src/zabbix_agent/zbxconf.c
index 8be84467eef..b36d58566a5 100644
--- a/src/zabbix_agent/zbxconf.c
+++ b/src/zabbix_agent/zbxconf.c
@@ -185,7 +185,7 @@ void load_perf_counters(const char **def_lines, const char **eng_lines)
zbx_unicode_to_utf8_static(wcounterPath, counterpath, PDH_MAX_COUNTER_PATH);
zbx_free(wcounterPath);
- if (FAIL == check_counter_path(counterpath, lang == PERF_COUNTER_LANG_DEFAULT))
+ if (FAIL == zbx_check_counter_path(counterpath, lang == PERF_COUNTER_LANG_DEFAULT))
{
error = zbx_strdup(error, "Invalid counter path.");
goto pc_fail;
diff --git a/src/zabbix_java/src/com/zabbix/gateway/GeneralInformation.java b/src/zabbix_java/src/com/zabbix/gateway/GeneralInformation.java
index 9ff9e9cab5e..d282d4d8191 100644
--- a/src/zabbix_java/src/com/zabbix/gateway/GeneralInformation.java
+++ b/src/zabbix_java/src/com/zabbix/gateway/GeneralInformation.java
@@ -22,9 +22,9 @@ package com.zabbix.gateway;
class GeneralInformation
{
static final String APPLICATION_NAME = "Zabbix Java Gateway";
- static final String REVISION_DATE = "27 October 2022";
+ static final String REVISION_DATE = "8 November 2022";
static final String REVISION = "{ZABBIX_REVISION}";
- static final String VERSION = "6.4.0beta3";
+ static final String VERSION = "6.4.0beta4";
static void printVersion()
{
diff --git a/src/zabbix_server/Makefile.am b/src/zabbix_server/Makefile.am
index fe2b885e0d9..ca7a24f4b8b 100644
--- a/src/zabbix_server/Makefile.am
+++ b/src/zabbix_server/Makefile.am
@@ -112,7 +112,6 @@ zabbix_server_LDADD = \
$(top_builddir)/src/libs/zbxself/libzbxself.a \
$(top_builddir)/src/libs/zbxself/libzbxself_server.a \
$(top_builddir)/src/libs/zbxipcservice/libzbxipcservice.a \
- $(top_builddir)/src/libs/zbxalgo/libzbxalgo.a \
$(top_builddir)/src/libs/zbxthreads/libzbxthreads.a \
$(top_builddir)/src/libs/zbxmutexs/libzbxmutexs.a \
$(top_builddir)/src/libs/zbxconf/libzbxconf.a \
@@ -124,6 +123,7 @@ zabbix_server_LDADD = \
$(top_builddir)/src/libs/zbxcommshigh/libzbxcommshigh.a \
$(top_builddir)/src/libs/zbxxml/libzbxxml.a \
$(top_builddir)/src/libs/zbxjson/libzbxjson.a \
+ $(top_builddir)/src/libs/zbxalgo/libzbxalgo.a \
$(top_builddir)/src/libs/zbxvault/libzbxvault.a \
$(top_builddir)/src/libs/zbxcyberark/libzbxcyberark.a \
$(top_builddir)/src/libs/zbxhashicorp/libzbxhashicorp.a \
diff --git a/src/zabbix_server/poller/checks_simple_vmware.c b/src/zabbix_server/poller/checks_simple_vmware.c
index f2bfbe6e618..14a13ba2872 100644
--- a/src/zabbix_server/poller/checks_simple_vmware.c
+++ b/src/zabbix_server/poller/checks_simple_vmware.c
@@ -4299,7 +4299,7 @@ int check_vcenter_vm_discovery(AGENT_REQUEST *request, const char *username, con
rpool_cmp.id = vm->props[ZBX_VMWARE_VMPROP_RESOURCEPOOL];
if (FAIL != (idx = zbx_vector_vmware_resourcepool_bsearch(&service->data->resourcepools,
- &rpool_cmp, vmware_resourcepool_compare_id)))
+ &rpool_cmp, ZBX_DEFAULT_STR_PTR_COMPARE_FUNC)))
{
zbx_json_addstring(&json_data, "{#VM.RPOOL.PATH}", ZBX_NULL2EMPTY_STR(
service->data->resourcepools.values[idx]->path),
@@ -5817,7 +5817,7 @@ static int check_vcenter_rp_common(const char *url, const char *username, const
rp_cmp.id = (char *)rpid;
if (FAIL == zbx_vector_vmware_resourcepool_bsearch(&service->data->resourcepools, &rp_cmp,
- vmware_resourcepool_compare_id))
+ ZBX_DEFAULT_STR_PTR_COMPARE_FUNC))
{
SET_MSG_RESULT(result, zbx_strdup(NULL, "Unknown resource pool id."));
goto unlock;
diff --git a/src/zabbix_server/preprocessor/item_preproc.c b/src/zabbix_server/preprocessor/item_preproc.c
index 065eb31ae2e..ae511b94532 100644
--- a/src/zabbix_server/preprocessor/item_preproc.c
+++ b/src/zabbix_server/preprocessor/item_preproc.c
@@ -934,7 +934,8 @@ static int item_preproc_regsub(zbx_variant_t *value, const char *params, char **
* *
* Purpose: execute jsonpath query *
* *
- * Parameters: value - [IN/OUT] the value to process *
+ * Parameters: cache - [IN] the preprocessing cache *
+ * value - [IN/OUT] the value to process *
* params - [IN] the operation parameters *
* errmsg - [OUT] error message *
* *
@@ -942,18 +943,59 @@ static int item_preproc_regsub(zbx_variant_t *value, const char *params, char **
* FAIL - otherwise *
* *
******************************************************************************/
-static int item_preproc_jsonpath_op(zbx_variant_t *value, const char *params, char **errmsg)
+static int item_preproc_jsonpath_op(zbx_preproc_cache_t *cache, zbx_variant_t *value, const char *params,
+ char **errmsg)
{
- struct zbx_json_parse jp;
- char *data = NULL;
+ char *data = NULL;
- if (FAIL == item_preproc_convert_value(value, ZBX_VARIANT_STR, errmsg))
- return FAIL;
+ if (NULL == cache)
+ {
+ zbx_jsonobj_t obj;
+
+ if (FAIL == item_preproc_convert_value(value, ZBX_VARIANT_STR, errmsg))
+ return FAIL;
- if (FAIL == zbx_json_open(value->data.str, &jp) || FAIL == zbx_jsonpath_query(&jp, params, &data))
+ if (FAIL == zbx_jsonobj_open(value->data.str, &obj))
+ {
+ *errmsg = zbx_strdup(*errmsg, zbx_json_strerror());
+ return FAIL;
+ }
+
+ if (FAIL == zbx_jsonobj_query(&obj, params, &data))
+ {
+ zbx_jsonobj_clear(&obj);
+ *errmsg = zbx_strdup(*errmsg, zbx_json_strerror());
+ return FAIL;
+ }
+
+ zbx_jsonobj_clear(&obj);
+ }
+ else
{
- *errmsg = zbx_strdup(*errmsg, zbx_json_strerror());
- return FAIL;
+ zbx_jsonobj_t *obj;
+
+ if (NULL == (obj = (zbx_jsonobj_t *)zbx_preproc_cache_get(cache, ZBX_PREPROC_JSONPATH)))
+ {
+ if (FAIL == item_preproc_convert_value(value, ZBX_VARIANT_STR, errmsg))
+ return FAIL;
+
+ obj = (zbx_jsonobj_t *)zbx_malloc(NULL, sizeof(zbx_jsonobj_t));
+
+ if (SUCCEED != zbx_jsonobj_open(value->data.str, obj))
+ {
+ *errmsg = zbx_strdup(*errmsg, zbx_json_strerror());
+ zbx_free(obj);
+ return FAIL;
+ }
+
+ zbx_preproc_cache_put(cache, ZBX_PREPROC_JSONPATH, obj);
+ }
+
+ if (FAIL == zbx_jsonobj_query(obj, params, &data))
+ {
+ *errmsg = zbx_strdup(*errmsg, zbx_json_strerror());
+ return FAIL;
+ }
}
if (NULL == data)
@@ -972,7 +1014,8 @@ static int item_preproc_jsonpath_op(zbx_variant_t *value, const char *params, ch
* *
* Purpose: execute jsonpath query *
* *
- * Parameters: value - [IN/OUT] the value to process *
+ * Parameters: cache - [IN] the preprocessing cache *
+ * value - [IN/OUT] the value to process *
* params - [IN] the operation parameters *
* errmsg - [OUT] error message *
* *
@@ -980,11 +1023,12 @@ static int item_preproc_jsonpath_op(zbx_variant_t *value, const char *params, ch
* FAIL - otherwise *
* *
******************************************************************************/
-static int item_preproc_jsonpath(zbx_variant_t *value, const char *params, char **errmsg)
+static int item_preproc_jsonpath(zbx_preproc_cache_t *cache, zbx_variant_t *value, const char *params,
+ char **errmsg)
{
char *err = NULL;
- if (SUCCEED == item_preproc_jsonpath_op(value, params, &err))
+ if (SUCCEED == item_preproc_jsonpath_op(cache, value, params, &err))
return SUCCEED;
*errmsg = zbx_dsprintf(*errmsg, "cannot extract value from json by path \"%s\": %s", params, err);
@@ -1571,7 +1615,8 @@ fail:
* *
* Purpose: parse Prometheus format metrics *
* *
- * Parameters: value - [IN/OUT] the value to process *
+ * Parameters: cache - [IN] the preprocessing cache *
+ * value - [IN/OUT] the value to process *
* params - [IN] the operation parameters *
* errmsg - [OUT] error message *
* *
@@ -2148,7 +2193,7 @@ int zbx_item_preproc(zbx_preproc_cache_t *cache, unsigned char value_type, zbx_v
ret = item_preproc_xpath(value, op->params, error);
break;
case ZBX_PREPROC_JSONPATH:
- ret = item_preproc_jsonpath(value, op->params, error);
+ ret = item_preproc_jsonpath(cache, value, op->params, error);
break;
case ZBX_PREPROC_VALIDATE_RANGE:
ret = item_preproc_validate_range(value_type, value, op->params, error);
diff --git a/src/zabbix_server/preprocessor/preproc_cache.c b/src/zabbix_server/preprocessor/preproc_cache.c
index 9b7cff0731e..556f58e53e9 100644
--- a/src/zabbix_server/preprocessor/preproc_cache.c
+++ b/src/zabbix_server/preprocessor/preproc_cache.c
@@ -95,6 +95,11 @@ void zbx_preproc_cache_clear(zbx_preproc_cache_t *cache)
case ZBX_PREPROC_PROMETHEUS_PATTERN:
zbx_prometheus_clear((zbx_prometheus_t *)cache->refs.values[i].impl);
zbx_free(cache->refs.values[i].impl);
+ break;
+ case ZBX_PREPROC_JSONPATH:
+ zbx_jsonobj_clear((zbx_jsonobj_t *)cache->refs.values[i].impl);
+ zbx_free(cache->refs.values[i].impl);
+ break;
}
}
diff --git a/src/zabbix_server/vmware/vmware.c b/src/zabbix_server/vmware/vmware.c
index c945040cd45..d710e9e86f8 100644
--- a/src/zabbix_server/vmware/vmware.c
+++ b/src/zabbix_server/vmware/vmware.c
@@ -239,6 +239,21 @@ static zbx_hashset_t evt_msg_strpool;
static zbx_uint64_t evt_req_chunk_size;
+/* the vmware resource pool chunk */
+typedef struct
+{
+ char *id;
+ char *first_parentid;
+ char *name;
+ const char *path;
+ const char *parentid;
+ unsigned char parent_is_rp;
+}
+zbx_vmware_rpool_chunk_t;
+
+ZBX_PTR_VECTOR_DECL(vmware_rpool_chunk, zbx_vmware_rpool_chunk_t *)
+ZBX_PTR_VECTOR_IMPL(vmware_rpool_chunk, zbx_vmware_rpool_chunk_t *)
+
/*
* SOAP support
*/
@@ -500,17 +515,6 @@ static zbx_vmware_propmap_t vm_propmap[] = {
ZBX_XPATH_PROP_OBJECT_ID(ZBX_VMWARE_SOAP_FOLDER, "[text()='" id "']") "/" \
ZBX_XPATH_PROP_NAME_NODE("parent") "[@type='Folder']"
-#define ZBX_XPATH_GET_RESOURCEPOOL_NAME(id) \
- ZBX_XPATH_GET_OBJECT_NAME(ZBX_VMWARE_SOAP_RESOURCEPOOL, id)
-
-#define ZBX_XPATH_GET_RESOURCEPOOL_PARENTID(id) \
- ZBX_XPATH_PROP_OBJECT_ID(ZBX_VMWARE_SOAP_RESOURCEPOOL, "[text()='" id "']") "/" \
- ZBX_XPATH_PROP_NAME_NODE("parent") "[@type='ResourcePool']"
-
-#define ZBX_XPATH_GET_NON_RESOURCEPOOL_PARENTID(id) \
- ZBX_XPATH_PROP_OBJECT_ID(ZBX_VMWARE_SOAP_RESOURCEPOOL, "[text()='" id "']") "/" \
- ZBX_XPATH_PROP_NAME_NODE("parent") "[@type!='ResourcePool']"
-
/* hypervisor hashset support */
static zbx_hash_t vmware_hv_hash(const void *data)
{
@@ -2375,6 +2379,22 @@ static void vmware_datacenter_free(zbx_vmware_datacenter_t *datacenter)
/******************************************************************************
* *
+ * Purpose: frees resources allocated to store rp_chunk data *
+ * *
+ * Parameters: rp_chunk - [IN] the resourcepool chunk *
+ * *
+ ******************************************************************************/
+static void vmware_rp_chunk_free(zbx_vmware_rpool_chunk_t *rp_chunk)
+{
+ zbx_free(rp_chunk->id);
+ zbx_free(rp_chunk->name);
+ zbx_free(rp_chunk->first_parentid);
+ /* path and parent are not cleared */
+ zbx_free(rp_chunk);
+}
+
+/******************************************************************************
+ * *
* Purpose: frees resources allocated to store resourcepool data *
* *
* Parameters: resourcepool - [IN] the resourcepool *
@@ -2864,14 +2884,15 @@ typedef struct
zbx_property_collection_iter;
static int zbx_property_collection_init(CURL *easyhandle, const char *property_collection_query,
- const char *property_collector, zbx_property_collection_iter **iter, xmlDoc **xdoc, char **error)
+ const char *property_collector, const char *fn_parent, zbx_property_collection_iter **iter,
+ xmlDoc **xdoc, char **error)
{
*iter = (zbx_property_collection_iter *)zbx_malloc(*iter, sizeof(zbx_property_collection_iter));
(*iter)->property_collector = property_collector;
(*iter)->easyhandle = easyhandle;
(*iter)->token = NULL;
- if (SUCCEED != zbx_soap_post(__func__, (*iter)->easyhandle, property_collection_query, xdoc, &(*iter)->token,
+ if (SUCCEED != zbx_soap_post(fn_parent, (*iter)->easyhandle, property_collection_query, xdoc, &(*iter)->token,
error))
{
return FAIL;
@@ -2880,7 +2901,8 @@ static int zbx_property_collection_init(CURL *easyhandle, const char *property_c
return SUCCEED;
}
-static int zbx_property_collection_next(zbx_property_collection_iter *iter, xmlDoc **xdoc, char **error)
+static int zbx_property_collection_next(const char *fn_parent, zbx_property_collection_iter *iter, xmlDoc **xdoc,
+ char **error)
{
# define ZBX_POST_CONTINUE_RETRIEVE_PROPERTIES \
ZBX_POST_VSPHERE_HEADER \
@@ -2904,7 +2926,7 @@ static int zbx_property_collection_next(zbx_property_collection_iter *iter, xmlD
zbx_snprintf(post, sizeof(post), ZBX_POST_CONTINUE_RETRIEVE_PROPERTIES, iter->property_collector, token_esc);
zbx_free(token_esc);
- if (SUCCEED != zbx_soap_post(__func__, iter->easyhandle, post, xdoc, NULL, error))
+ if (SUCCEED != zbx_soap_post(fn_parent, iter->easyhandle, post, xdoc, NULL, error))
return FAIL;
zbx_free(iter->token);
@@ -3989,83 +4011,6 @@ out:
/******************************************************************************
* *
- * Purpose: get resource pool parentid and path (chain of resource pool *
- * names divided by '/') *
- * *
- * Parameters: xdoc - [IN] the xml with all vm details *
- * r_id - [IN] the resource pool id *
- * parentid - [OUT] the resource pool parent id *
- * path - [OUT] the resource pool path *
- * *
- * Return value: SUCCEED - the operation has completed successfully *
- * FAIL - the operation has failed *
- * *
- ******************************************************************************/
-static int vmware_service_get_resourcepool_data(xmlDoc *xdoc, const char *r_id, char **parentid, char **path)
-{
- char tmp[MAX_STRING_LEN], *id, *name;
- int ret = SUCCEED;
-
- zabbix_log(LOG_LEVEL_DEBUG, "In %s() resource pool id:'%s'", __func__, r_id);
- id = zbx_strdup(NULL, r_id);
- *path = *parentid = NULL;
-
- do
- {
- char *id_esc;
-
- id_esc = zbx_xml_escape_dyn(id);
- zbx_free(id);
- zbx_snprintf(tmp, sizeof(tmp), ZBX_XPATH_GET_RESOURCEPOOL_NAME("%s"), id_esc);
-
- if (NULL == (name = zbx_xml_doc_read_value(xdoc , tmp)))
- {
- zbx_free(*parentid);
- zbx_free(*path);
- zbx_free(id_esc);
- ret = FAIL;
- break;
- }
-
- zbx_snprintf(tmp, sizeof(tmp), ZBX_XPATH_GET_RESOURCEPOOL_PARENTID("%s"), id_esc);
- id = zbx_xml_doc_read_value(xdoc , tmp);
-
- if (NULL != id) /* we do not include the last default 'ResourcePool' */
- {
- if (NULL == *path)
- {
- *path = name;
- name = NULL;
- }
- else
- *path = zbx_dsprintf(*path, "%s/%s", name, *path);
-
- }
- else
- zbx_snprintf(tmp, sizeof(tmp), ZBX_XPATH_GET_NON_RESOURCEPOOL_PARENTID("%s"), id_esc);
-
- zbx_free(id_esc);
- zbx_free(name);
- }
- while (NULL != id);
-
- if (SUCCEED == ret)
- {
- if (NULL != *path && NULL == (*parentid = zbx_xml_doc_read_value(xdoc , tmp)))
- zbx_free(*path);
-
- if (NULL == *path)
- ret = FAIL;
- }
-
- zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s resource pool path: '%s', parentid: '%s'", __func__,
- zbx_result_string(ret), ZBX_NULL2EMPTY_STR(*path), ZBX_NULL2EMPTY_STR(*parentid));
-
- return ret;
-}
-
-/******************************************************************************
- * *
* Purpose: get alarm details *
* *
* Parameters: service - [IN] the vmware service *
@@ -4363,7 +4308,7 @@ static zbx_vmware_vm_t *vmware_service_create_vm(zbx_vmware_service_t *service,
rpool_cmp.id = vm->props[ZBX_VMWARE_VMPROP_RESOURCEPOOL];
if (FAIL != (i = zbx_vector_vmware_resourcepool_bsearch(rpools, &rpool_cmp,
- vmware_resourcepool_compare_id)))
+ ZBX_DEFAULT_STR_PTR_COMPARE_FUNC)))
{
rpools->values[i]->vm_num += 1;
}
@@ -5279,7 +5224,7 @@ static int vmware_service_hv_disks_get_info(const zbx_vmware_service_t *service,
zbx_free(hvid_esc);
zbx_free(scsi_req);
- if (SUCCEED != (ret = zbx_property_collection_init(easyhandle, tmp, pcollecter, &iter, &doc, error)))
+ if (SUCCEED != (ret = zbx_property_collection_init(easyhandle, tmp, pcollecter, __func__, &iter, &doc, error)))
goto out;
updated += vmware_service_hv_disks_parse_info(doc, dss, disks_info);
@@ -5289,7 +5234,7 @@ static int vmware_service_hv_disks_get_info(const zbx_vmware_service_t *service,
zbx_xml_free_doc(doc);
doc = NULL;
- if (SUCCEED != (ret = zbx_property_collection_next(iter, &doc, error)))
+ if (SUCCEED != (ret = zbx_property_collection_next(__func__, iter, &doc, error)))
goto out;
updated += vmware_service_hv_disks_parse_info(doc, dss, disks_info);
@@ -5306,7 +5251,8 @@ static int vmware_service_hv_disks_get_info(const zbx_vmware_service_t *service,
"<ns0:pathSet>config.vsanHostConfig.storageInfo.diskMapping</ns0:pathSet>", hvid_esc);
zbx_free(hvid_esc);
- if (SUCCEED != (ret = zbx_property_collection_init(easyhandle, tmp, pcollecter, &iter, &doc_dinfo, &err)))
+ if (SUCCEED != (ret = zbx_property_collection_init(easyhandle, tmp, pcollecter, __func__, &iter, &doc_dinfo,
+ &err)))
{
zabbix_log(LOG_LEVEL_DEBUG, "%s() cannot get vsan disk_info:%s", __func__, err);
zbx_str_free(err);
@@ -5320,7 +5266,7 @@ static int vmware_service_hv_disks_get_info(const zbx_vmware_service_t *service,
zbx_xml_free_doc(doc_dinfo);
doc_dinfo = NULL;
- if (SUCCEED != (ret = zbx_property_collection_next(iter, &doc_dinfo, error)))
+ if (SUCCEED != (ret = zbx_property_collection_next(__func__, iter, &doc_dinfo, error)))
goto out;
updated_vsan += vmware_service_hv_vsan_parse_info(doc_dinfo, vsan_uuid, disks_info);
@@ -5862,7 +5808,7 @@ static int vmware_hv_ds_access_update(zbx_vmware_service_t *service, CURL *easyh
zbx_snprintf(tmp, sizeof(tmp), ZBX_POST_HV_DS_ACCESS, pcollector, hvid_esc, hvid_esc, hvid_esc, hvid_esc);
zbx_free(hvid_esc);
- if (SUCCEED != zbx_property_collection_init(easyhandle, tmp, pcollector, &iter, &doc, error))
+ if (SUCCEED != zbx_property_collection_init(easyhandle, tmp, pcollector, __func__, &iter, &doc, error))
goto out;
updated += vmware_hv_ds_access_parse(doc, hv_dss, hv_uuid, hv_id, dss);
@@ -5872,7 +5818,7 @@ static int vmware_hv_ds_access_update(zbx_vmware_service_t *service, CURL *easyh
zbx_xml_free_doc(doc);
doc = NULL;
- if (SUCCEED != zbx_property_collection_next(iter, &doc, error))
+ if (SUCCEED != zbx_property_collection_next(__func__, iter, &doc, error))
goto out;
updated += vmware_hv_ds_access_parse(doc, hv_dss, hv_uuid, hv_id, dss);
@@ -6007,19 +5953,6 @@ static const char *vmware_hv_vsan_uuid(zbx_vector_vmware_datastore_t *dss, zbx_v
/******************************************************************************
* *
- * Purpose: sorting function to sort Resource pool names vector by name *
- * *
- ******************************************************************************/
-int vmware_resourcepool_compare_id(const void *r1, const void *r2)
-{
- const zbx_vmware_resourcepool_t *rp1 = *(const zbx_vmware_resourcepool_t * const *)r1;
- const zbx_vmware_resourcepool_t *rp2 = *(const zbx_vmware_resourcepool_t * const *)r2;
-
- return strcmp(rp1->id, rp2->id);
-}
-
-/******************************************************************************
- * *
* Function: vmware_service_init_hv *
* *
* Purpose: initialize vmware hypervisor object *
@@ -6600,7 +6533,7 @@ static int vmware_service_get_hv_ds_dc_dvs_list(const zbx_vmware_service_t *serv
zbx_snprintf(tmp, sizeof(tmp), ZBX_POST_VCENTER_HV_DS_LIST, pcollector,
vmware_service_objects[service->type].root_folder);
- if (SUCCEED != zbx_property_collection_init(easyhandle, tmp, pcollector, &iter, &doc, error))
+ if (SUCCEED != zbx_property_collection_init(easyhandle, tmp, pcollector, __func__, &iter, &doc, error))
goto out;
if (ZBX_VMWARE_TYPE_VCENTER == service->type)
@@ -6625,7 +6558,7 @@ static int vmware_service_get_hv_ds_dc_dvs_list(const zbx_vmware_service_t *serv
zbx_xml_free_doc(doc);
doc = NULL;
- if (SUCCEED != zbx_property_collection_next(iter, &doc, error))
+ if (SUCCEED != zbx_property_collection_next(__func__, iter, &doc, error))
goto out;
if (ZBX_VMWARE_TYPE_VCENTER == service->type)
@@ -7366,15 +7299,256 @@ out:
* *
* Purpose: retrieves a list of vmware service clusters and resource pools *
* *
+ * Parameters: service - [IN] the vmware service *
+ * easyhandle - [IN] the CURL handle *
+ * cluster_data - [OUT] a pointer to the output variable *
+ * clusters - [OUT] a pointer to the resulting clusters *
+ * vector *
+ * rp_chunks - [OUT] a pointer to the resulting resource pool *
+ * vector *
+ * alarms_data - [OUT] the vector with all alarms *
+ * error - [OUT] the error message in the case of failure *
+ * *
+ * Return value: SUCCEED - the operation has completed successfully *
+ * FAIL - the operation has failed *
+ * *
+ ******************************************************************************/
+static int vmware_service_process_cluster_data(zbx_vmware_service_t *service, CURL *easyhandle,
+ xmlDoc *cluster_data, zbx_vector_ptr_t *clusters, zbx_vector_vmware_rpool_chunk_t *rp_chunks,
+ zbx_vmware_alarms_data_t *alarms_data, char **error)
+{
+#define ZBX_XPATH_GET_RESOURCEPOOL_PARENTID \
+ ZBX_XPATH_PROP_NAME_NODE("parent") "[@type='ResourcePool']"
+#define ZBX_XPATH_GET_NON_RESOURCEPOOL_PARENTID \
+ ZBX_XPATH_PROP_NAME_NODE("parent") "[@type!='ResourcePool']"
+
+ int ret, i;
+ char *id_esc, tmp[MAX_STRING_LEN * 2];
+ zbx_vmware_cluster_t *cluster;
+ zbx_vector_str_t rp_ids, ids;
+ xmlNode *node;
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
+
+ zbx_vector_str_create(&ids);
+
+ zbx_xml_read_values(cluster_data, ZBX_XPATH_OBJS_BY_TYPE(ZBX_VMWARE_SOAP_CLUSTER), &ids);
+ zbx_vector_ptr_reserve(clusters, (size_t)(clusters->values_alloc + ids.values_num));
+
+ for (i = 0; i < ids.values_num; i++)
+ {
+ char *name;
+
+ id_esc = zbx_xml_escape_dyn(ids.values[i]);
+ zbx_snprintf(tmp, sizeof(tmp), ZBX_XPATH_PROP_OBJECT_ID(ZBX_VMWARE_SOAP_CLUSTER, "[text()='%s']"),
+ id_esc);
+ zbx_str_free(id_esc);
+
+ if (NULL == (node = zbx_xml_doc_get(cluster_data, tmp)) ||
+ NULL == (name = zbx_xml_node_read_value(cluster_data, node,
+ ZBX_XPATH_PROP_NAME_NODE("name"))))
+ {
+ continue;
+ }
+
+ cluster = (zbx_vmware_cluster_t *)zbx_malloc(NULL, sizeof(zbx_vmware_cluster_t));
+ cluster->id = zbx_strdup(NULL, ids.values[i]);
+ cluster->name = name;
+ cluster->status = NULL;
+ zbx_vector_str_create(&cluster->dss_uuid);
+ zbx_vector_str_create(&cluster->alarm_ids);
+
+ if (SUCCEED != vmware_service_get_alarms_data(__func__, service, easyhandle, cluster_data,
+ zbx_xml_node_get(cluster_data, node, ZBX_XPATH_PROP_NAME_NODE("triggeredAlarmState")),
+ &cluster->alarm_ids, alarms_data, error))
+ {
+ vmware_cluster_free(cluster);
+ ret = FAIL;
+ goto out;
+ }
+
+ zbx_vector_ptr_append(clusters, cluster);
+ }
+
+ zbx_vector_str_create(&rp_ids);
+ zbx_xml_read_values(cluster_data, ZBX_XPATH_OBJS_BY_TYPE(ZBX_VMWARE_SOAP_RESOURCEPOOL), &rp_ids);
+ zbx_vector_vmware_rpool_chunk_reserve(rp_chunks, (size_t)(rp_chunks->values_num + rp_ids.values_num));
+
+ for (i = 0; i < rp_ids.values_num; i++)
+ {
+ zbx_vmware_rpool_chunk_t *rp_chunk;
+
+ rp_chunk = (zbx_vmware_rpool_chunk_t *)zbx_malloc(NULL, sizeof(zbx_vmware_rpool_chunk_t));
+
+ id_esc = zbx_xml_escape_dyn(rp_ids.values[i]);
+ zbx_snprintf(tmp, sizeof(tmp), ZBX_XPATH_PROP_OBJECT_ID(ZBX_VMWARE_SOAP_RESOURCEPOOL, "[text()='%s']"),
+ id_esc);
+ zbx_str_free(id_esc);
+
+ if (NULL == (node = zbx_xml_doc_get(cluster_data, tmp)) || NULL == (
+ rp_chunk->name = zbx_xml_node_read_value(cluster_data, node,
+ ZBX_XPATH_PROP_NAME_NODE("name"))))
+ {
+ zbx_free(rp_chunk);
+ continue;
+ }
+
+ if (NULL == (rp_chunk->first_parentid = zbx_xml_node_read_value(cluster_data , node,
+ ZBX_XPATH_GET_RESOURCEPOOL_PARENTID)))
+ {
+ if (NULL == (rp_chunk->first_parentid = zbx_xml_node_read_value(cluster_data , node,
+ ZBX_XPATH_GET_NON_RESOURCEPOOL_PARENTID)))
+ {
+ zbx_free(rp_chunk->name);
+ zbx_free(rp_chunk);
+ continue;
+ }
+
+ rp_chunk->parent_is_rp = 0;
+ }
+ else
+ rp_chunk->parent_is_rp = 1;
+
+ rp_chunk->id = zbx_strdup(NULL, rp_ids.values[i]);
+ rp_chunk->path = rp_chunk->parentid = NULL;
+ zbx_vector_vmware_rpool_chunk_append(rp_chunks, rp_chunk);
+ }
+
+ zbx_vector_str_clear_ext(&rp_ids, zbx_str_free);
+ zbx_vector_str_destroy(&rp_ids);
+
+ ret = SUCCEED;
+out:
+ zbx_vector_str_clear_ext(&ids, zbx_str_free);
+ zbx_vector_str_destroy(&ids);
+
+ zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s cl:%d rp:%d", __func__, zbx_result_string(ret),
+ clusters->values_num, rp_chunks->values_num);
+
+ return ret;
+
+#undef ZBX_XPATH_GET_RESOURCEPOOL_PARENTID
+#undef ZBX_XPATH_GET_NON_RESOURCEPOOL_PARENTID
+}
+
+/******************************************************************************
+ * *
+ * Purpose: retrieves status of the specified vmware cluster *
+ * *
* Parameters: easyhandle - [IN] the CURL handle *
- * data - [OUT] a pointer to the output variable *
+ * datastores - [IN] all available Datastores *
+ * cluster - [IN/OUT] the cluster *
+ * cq_values - [IN/OUT] the vector with custom query entries *
* error - [OUT] the error message in the case of failure *
* *
* Return value: SUCCEED - the operation has completed successfully *
* FAIL - the operation has failed *
* *
******************************************************************************/
-static int vmware_service_get_cluster_data(CURL *easyhandle, xmlDoc **data, char **error)
+static int vmware_service_get_cluster_state(CURL *easyhandle, const zbx_vector_vmware_datastore_t *datastores,
+ zbx_vmware_cluster_t *cluster, zbx_vector_cq_value_t *cq_values, char **error)
+{
+# define ZBX_POST_VMWARE_CLUSTER_STATUS \
+ ZBX_POST_VSPHERE_HEADER \
+ "<ns0:RetrievePropertiesEx>" \
+ "<ns0:_this type=\"PropertyCollector\">propertyCollector</ns0:_this>" \
+ "<ns0:specSet>" \
+ "<ns0:propSet>" \
+ "<ns0:type>ClusterComputeResource</ns0:type>" \
+ "<ns0:all>false</ns0:all>" \
+ "<ns0:pathSet>summary.overallStatus</ns0:pathSet>" \
+ "<ns0:pathSet>datastore</ns0:pathSet>" \
+ "%s" \
+ "</ns0:propSet>" \
+ "<ns0:objectSet>" \
+ "<ns0:obj type=\"ClusterComputeResource\">%s</ns0:obj>" \
+ "</ns0:objectSet>" \
+ "</ns0:specSet>" \
+ "<ns0:options></ns0:options>" \
+ "</ns0:RetrievePropertiesEx>" \
+ ZBX_POST_VSPHERE_FOOTER
+
+ char *tmp, *clusterid_esc, *cq_prop;
+ int i, ret;
+ xmlDoc *doc = NULL;
+ zbx_vector_cq_value_t cqvs;
+ zbx_vector_str_t ids;
+
+ zabbix_log(LOG_LEVEL_DEBUG, "In %s() clusterid:'%s'", __func__, cluster->id);
+
+ zbx_vector_str_create(&ids);
+ zbx_vector_cq_value_create(&cqvs);
+ clusterid_esc = zbx_xml_escape_dyn(cluster->id);
+ cq_prop = vmware_cq_prop_soap_request(cq_values, ZBX_VMWARE_SOAP_CLUSTER, cluster->id, &cqvs);
+
+ tmp = zbx_dsprintf(NULL, ZBX_POST_VMWARE_CLUSTER_STATUS, cq_prop, clusterid_esc);
+
+ zbx_str_free(cq_prop);
+ zbx_str_free(clusterid_esc);
+ ret = zbx_soap_post(__func__, easyhandle, tmp, &doc, NULL, error);
+ zbx_str_free(tmp);
+
+ if (FAIL == ret)
+ goto out;
+
+ cluster->status = zbx_xml_doc_read_value(doc, ZBX_XPATH_PROP_NAME("summary.overallStatus"));
+
+ if (0 != cqvs.values_num)
+ vmware_service_cq_prop_value(__func__, doc, &cqvs);
+
+ zbx_xml_read_values(doc, ZBX_XPATH_PROP_NAME("datastore") "/*", &ids);
+
+ for (i = 0; i < ids.values_num; i++)
+ {
+ int j;
+ zbx_vmware_datastore_t ds_cmp;
+
+ ds_cmp.id = ids.values[i];
+
+ if (FAIL == (j = zbx_vector_vmware_datastore_bsearch(datastores, &ds_cmp, vmware_ds_id_compare)))
+ {
+ zabbix_log(LOG_LEVEL_DEBUG, "%s(): Datastore \"%s\" not found on cluster \"%s\".", __func__,
+ ds_cmp.id, cluster->id);
+ continue;
+ }
+
+ zbx_vector_str_append(&cluster->dss_uuid, zbx_strdup(NULL, datastores->values[j]->uuid));
+ }
+out:
+ zbx_vector_cq_value_destroy(&cqvs);
+ zbx_vector_str_clear_ext(&ids, zbx_str_free);
+ zbx_vector_str_destroy(&ids);
+ zbx_xml_free_doc(doc);
+ zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
+
+ return ret;
+
+# undef ZBX_POST_VMWARE_CLUSTER_STATUS
+}
+
+/******************************************************************************
+ * *
+ * Purpose: creates lists of vmware cluster and resource pool objects *
+ * *
+ * Parameters: service - [IN] the vmware service *
+ * easyhandle - [IN] the CURL handle *
+ * datastores - [IN] all available Datastores *
+ * cq_values - [IN/OUT] the vector with custom query entries *
+ * clusters - [OUT] a pointer to the resulting clusters *
+ * vector *
+ * resourcepools - [OUT] a pointer to the resulting resource pool *
+ * vector *
+ * alarms_data - [OUT] the vector with all alarms *
+ * error - [OUT] the error message in the case of failure *
+ * *
+ * Return value: SUCCEED - the operation has completed successfully *
+ * FAIL - the operation has failed *
+ * *
+ ******************************************************************************/
+static int vmware_service_get_clusters_and_resourcepools(zbx_vmware_service_t *service, CURL *easyhandle,
+ const zbx_vector_vmware_datastore_t *datastores, zbx_vector_cq_value_t *cq_values,
+ zbx_vector_ptr_t *clusters, zbx_vector_vmware_resourcepool_t *resourcepools,
+ zbx_vmware_alarms_data_t *alarms_data, char **error)
{
# define ZBX_POST_VCENTER_CLUSTER \
ZBX_POST_VSPHERE_HEADER \
@@ -7384,15 +7558,9 @@ static int vmware_service_get_cluster_data(CURL *easyhandle, xmlDoc **data, char
"<ns0:propSet>" \
"<ns0:type>ClusterComputeResource</ns0:type>" \
"<ns0:pathSet>name</ns0:pathSet>" \
- "<ns0:pathSet>resourcePool</ns0:pathSet>" \
"<ns0:pathSet>triggeredAlarmState</ns0:pathSet>" \
"</ns0:propSet>" \
"<ns0:propSet>" \
- "<ns0:type>ComputeResource</ns0:type>" \
- "<ns0:pathSet>resourcePool</ns0:pathSet>" \
- "<ns0:pathSet>name</ns0:pathSet>" \
- "</ns0:propSet>" \
- "<ns0:propSet>" \
"<ns0:type>ResourcePool</ns0:type>" \
"<ns0:pathSet>resourcePool</ns0:pathSet>" \
"<ns0:pathSet>name</ns0:pathSet>" \
@@ -7521,243 +7689,113 @@ static int vmware_service_get_cluster_data(CURL *easyhandle, xmlDoc **data, char
"</ns0:RetrievePropertiesEx>" \
ZBX_POST_VSPHERE_FOOTER
- int ret = FAIL;
+ int i, ret = FAIL;
+ xmlDoc *cluster_data = NULL;
+ zbx_property_collection_iter *iter = NULL;
+ zbx_vector_vmware_rpool_chunk_t rp_chunks;
+ zbx_vector_ptr_t cl_chunks;
zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
- if (SUCCEED != zbx_soap_post(__func__, easyhandle, ZBX_POST_VCENTER_CLUSTER, data, NULL, error))
- goto out;
-
- ret = SUCCEED;
-out:
- zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
-
- return ret;
-
-# undef ZBX_POST_VCENTER_CLUSTER
-}
-
-/******************************************************************************
- * *
- * Purpose: retrieves status of the specified vmware cluster *
- * *
- * Parameters: easyhandle - [IN] the CURL handle *
- * clusterid - [IN] the cluster id *
- * datastores - [IN] all available Datastores *
- * cq_values - [IN/OUT] the vector with custom query entries *
- * status - [OUT] a pointer to the output variable *
- * dss - [OUT] a list of DS available for cluster *
- * error - [OUT] the error message in the case of failure *
- * *
- * Return value: SUCCEED - the operation has completed successfully *
- * FAIL - the operation has failed *
- * *
- ******************************************************************************/
-static int vmware_service_get_cluster_state(CURL *easyhandle, const char *clusterid,
- const zbx_vector_vmware_datastore_t *datastores, zbx_vector_cq_value_t *cq_values, char **status,
- zbx_vector_str_t *dss, char **error)
-{
-# define ZBX_POST_VMWARE_CLUSTER_STATUS \
- ZBX_POST_VSPHERE_HEADER \
- "<ns0:RetrievePropertiesEx>" \
- "<ns0:_this type=\"PropertyCollector\">propertyCollector</ns0:_this>" \
- "<ns0:specSet>" \
- "<ns0:propSet>" \
- "<ns0:type>ClusterComputeResource</ns0:type>" \
- "<ns0:all>false</ns0:all>" \
- "<ns0:pathSet>summary.overallStatus</ns0:pathSet>" \
- "<ns0:pathSet>datastore</ns0:pathSet>" \
- "%s" \
- "</ns0:propSet>" \
- "<ns0:objectSet>" \
- "<ns0:obj type=\"ClusterComputeResource\">%s</ns0:obj>" \
- "</ns0:objectSet>" \
- "</ns0:specSet>" \
- "<ns0:options></ns0:options>" \
- "</ns0:RetrievePropertiesEx>" \
- ZBX_POST_VSPHERE_FOOTER
-
- char *tmp, *clusterid_esc, *cq_prop;
- int i, ret = FAIL;
- xmlDoc *doc = NULL;
- zbx_vector_cq_value_t cqvs;
- zbx_vector_str_t ids;
-
- zabbix_log(LOG_LEVEL_DEBUG, "In %s() clusterid:'%s'", __func__, clusterid);
-
- zbx_vector_str_create(&ids);
- zbx_vector_cq_value_create(&cqvs);
- clusterid_esc = zbx_xml_escape_dyn(clusterid);
- cq_prop = vmware_cq_prop_soap_request(cq_values, ZBX_VMWARE_SOAP_CLUSTER, clusterid, &cqvs);
-
- tmp = zbx_dsprintf(NULL, ZBX_POST_VMWARE_CLUSTER_STATUS, cq_prop, clusterid_esc);
-
- zbx_str_free(cq_prop);
- zbx_str_free(clusterid_esc);
- ret = zbx_soap_post(__func__, easyhandle, tmp, &doc, NULL, error);
- zbx_str_free(tmp);
+ zbx_vector_vmware_rpool_chunk_create(&rp_chunks);
+ zbx_vector_ptr_create(&cl_chunks);
- if (FAIL == ret)
+ if (SUCCEED != zbx_property_collection_init(easyhandle, ZBX_POST_VCENTER_CLUSTER, "propertyCollector",
+ __func__, &iter, &cluster_data, error))
+ {
goto out;
+ }
- *status = zbx_xml_doc_read_value(doc, ZBX_XPATH_PROP_NAME("summary.overallStatus"));
-
- if (0 != cqvs.values_num)
- vmware_service_cq_prop_value(__func__, doc, &cqvs);
-
- zbx_xml_read_values(doc, ZBX_XPATH_PROP_NAME("datastore") "/*", &ids);
+ if (SUCCEED != vmware_service_process_cluster_data(service, easyhandle, cluster_data, &cl_chunks, &rp_chunks,
+ alarms_data, error))
+ {
+ goto out;
+ }
- for (i = 0; i < ids.values_num; i++)
+ while (NULL != iter->token)
{
- int j;
- zbx_vmware_datastore_t ds_cmp;
+ zbx_xml_free_doc(cluster_data);
+ cluster_data = NULL;
- ds_cmp.id = ids.values[i];
+ if (SUCCEED != zbx_property_collection_next(__func__, iter, &cluster_data, error))
+ goto out;
- if (FAIL == (j = zbx_vector_vmware_datastore_bsearch(datastores, &ds_cmp, vmware_ds_id_compare)))
+ if (SUCCEED != vmware_service_process_cluster_data(service, easyhandle, cluster_data, &cl_chunks,
+ &rp_chunks, alarms_data, error))
{
- zabbix_log(LOG_LEVEL_DEBUG, "%s(): Datastore \"%s\" not found on cluster \"%s\".", __func__,
- ds_cmp.id, clusterid);
- continue;
+ goto out;
}
-
- zbx_vector_str_append(dss, zbx_strdup(NULL, datastores->values[j]->uuid));
}
-out:
- zbx_vector_cq_value_destroy(&cqvs);
- zbx_vector_str_clear_ext(&ids, zbx_str_free);
- zbx_vector_str_destroy(&ids);
- zbx_xml_free_doc(doc);
- zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret));
-
- return ret;
-
-# undef ZBX_POST_VMWARE_CLUSTER_STATUS
-}
-/******************************************************************************
- * *
- * Purpose: creates lists of vmware cluster and resource pool objects *
- * *
- * Parameters: service - [IN] the vmware service *
- * easyhandle - [IN] the CURL handle *
- * datastores - [IN] all available Datastores *
- * cq_values - [IN/OUT] the vector with custom query entries *
- * clusters - [OUT] a pointer to the resulting clusters *
- * vector *
- * resourcepools - [OUT] a pointer to the resulting resource pool *
- * vector *
- * alarms_data - [OUT] the vector with all alarms *
- * error - [OUT] the error message in the case of failure *
- * *
- * Return value: SUCCEED - the operation has completed successfully *
- * FAIL - the operation has failed *
- * *
- ******************************************************************************/
-static int vmware_service_get_clusters_and_resourcepools(zbx_vmware_service_t *service, CURL *easyhandle,
- const zbx_vector_vmware_datastore_t *datastores, zbx_vector_cq_value_t *cq_values,
- zbx_vector_ptr_t *clusters, zbx_vector_vmware_resourcepool_t *resourcepools,
- zbx_vmware_alarms_data_t *alarms_data, char **error)
-{
- char xpath[MAX_STRING_LEN];
- int i, ret = FAIL;
- xmlDoc *cluster_data = NULL;
- zbx_vector_str_t ids, rpools_all, rpools_uniq, dss;
- zbx_vmware_cluster_t *cluster;
-
- zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__);
-
- zbx_vector_str_create(&ids);
- zbx_vector_str_create(&dss);
-
- if (SUCCEED != vmware_service_get_cluster_data(easyhandle, &cluster_data, error))
- goto out;
-
- zbx_xml_read_values(cluster_data, ZBX_XPATH_OBJS_BY_TYPE(ZBX_VMWARE_SOAP_CLUSTER), &ids);
- zbx_vector_ptr_reserve(clusters, (size_t)(ids.values_num + clusters->values_alloc));
+ zbx_property_collection_free(iter);
+ zbx_vector_vmware_rpool_chunk_sort(&rp_chunks, ZBX_DEFAULT_STR_PTR_COMPARE_FUNC);
- for (i = 0; i < ids.values_num; i++)
+ for (i = 0; i < rp_chunks.values_num; i++)
{
- char *status, *name;
-
- zbx_snprintf(xpath, sizeof(xpath), ZBX_XPATH_PROP_OBJECT_ID(ZBX_VMWARE_SOAP_CLUSTER, "[text()='%s']")
- "/" ZBX_XPATH_PROP_NAME_NODE("name"), ids.values[i]);
+ int k;
+ zbx_vmware_resourcepool_t *rpool;
+ zbx_vmware_rpool_chunk_t rp_parent, *rp_chunk = rp_chunks.values[i];
- if (NULL == (name = zbx_xml_doc_read_value(cluster_data, xpath)))
+ if (0 == rp_chunk->parent_is_rp) /* skipped the top (default) resource pool name */
continue;
- if (SUCCEED != vmware_service_get_cluster_state(easyhandle, ids.values[i], datastores, cq_values,
- &status, &dss, error))
- {
- zbx_free(name);
- goto out;
- }
+ rpool = (zbx_vmware_resourcepool_t*)zbx_malloc(NULL, sizeof(zbx_vmware_resourcepool_t));
+ rpool->id = zbx_strdup(NULL, rp_chunk->id);
+ rpool->path = zbx_strdup(NULL, rp_chunk->name);
+ rpool->vm_num = 0;
- cluster = (zbx_vmware_cluster_t *)zbx_malloc(NULL, sizeof(zbx_vmware_cluster_t));
- cluster->id = zbx_strdup(NULL, ids.values[i]);
- cluster->name = name;
- cluster->status = status;
- zbx_vector_str_create(&cluster->dss_uuid);
- zbx_vector_str_append_array(&cluster->dss_uuid, dss.values, dss.values_num);
- zbx_vector_str_clear(&dss);
- zbx_vector_str_create(&cluster->alarm_ids);
+ rp_parent.id = rp_chunk->first_parentid;
- if (FAIL == vmware_service_get_alarms_data(__func__, service, easyhandle, cluster_data, NULL,
- &cluster->alarm_ids, alarms_data, error))
+ while (FAIL != (k = zbx_vector_vmware_rpool_chunk_bsearch(&rp_chunks, &rp_parent,
+ ZBX_DEFAULT_STR_PTR_COMPARE_FUNC)))
{
- vmware_cluster_free(cluster);
- goto out;
- }
+ zbx_vmware_rpool_chunk_t *rp_next = rp_chunks.values[k];
- zbx_vector_ptr_append(clusters, cluster);
- }
+ if (NULL != rp_next->path)
+ rpool->path = zbx_dsprintf(rpool->path, "%s/%s", rp_next->path, rpool->path);
- /* Add resource pools */
+ if (0 == rp_next->parent_is_rp || NULL != rp_next->path)
+ {
+ rpool->parentid = zbx_strdup(NULL, 0 == rp_next->parent_is_rp ?
+ rp_next->first_parentid : rp_next->parentid);
+ zbx_vector_vmware_resourcepool_append(resourcepools, rpool);
+ rp_chunk->path = rpool->path;
+ rp_chunk->parentid = rpool->parentid;
+ break;
+ }
- zbx_vector_str_create(&rpools_all);
- zbx_vector_str_create(&rpools_uniq);
- zbx_xml_read_values(cluster_data, "//*[@type='ResourcePool']", &rpools_all);
- zbx_vector_str_sort(&rpools_all, ZBX_DEFAULT_STR_COMPARE_FUNC);
- zbx_vector_str_append_array(&rpools_uniq, rpools_all.values, rpools_all.values_num);
- zbx_vector_str_uniq(&rpools_uniq, ZBX_DEFAULT_STR_COMPARE_FUNC);
- zbx_vector_vmware_resourcepool_reserve(resourcepools, (size_t)rpools_all.values_num);
+ rpool->path = zbx_dsprintf(rpool->path, "%s/%s", rp_next->name, rpool->path);
+ rp_parent.id = rp_next->first_parentid;
+ }
+ }
- for (i = 0; i < rpools_uniq.values_num; i++)
+ zbx_vector_vmware_resourcepool_sort(resourcepools, ZBX_DEFAULT_STR_PTR_COMPARE_FUNC);
+ zbx_vector_ptr_reserve(clusters, (size_t)(clusters->values_alloc + cl_chunks.values_num));
+
+ for (i = cl_chunks.values_num - 1; i >= 0 ; i--)
{
- zbx_vmware_resourcepool_t *rpool;
- char *path, *parentid;
- const char *id = rpools_uniq.values[i];
+ zbx_vmware_cluster_t *cluster = (zbx_vmware_cluster_t*)(cl_chunks.values[i]);
- if (SUCCEED != vmware_service_get_resourcepool_data(cluster_data, id, &parentid, &path))
- {
- zabbix_log(LOG_LEVEL_DEBUG, "%s(): cannot find resource pool name for id:%s", __func__, id);
- continue;
- }
+ if (SUCCEED != vmware_service_get_cluster_state(easyhandle, datastores, cluster, cq_values, error))
+ goto out;
- rpool = (zbx_vmware_resourcepool_t *)zbx_malloc(NULL, sizeof(zbx_vmware_resourcepool_t));
- rpool->id = zbx_strdup(NULL, id);
- rpool->path = path;
- rpool->parentid = parentid;
- rpool->vm_num = 0;
- zbx_vector_vmware_resourcepool_append(resourcepools, rpool);
+ zbx_vector_ptr_append(clusters, cluster);
+ zbx_vector_ptr_remove_noorder(&cl_chunks, i);
}
- zbx_vector_vmware_resourcepool_sort(resourcepools, vmware_resourcepool_compare_id);
- zbx_vector_str_clear_ext(&rpools_all, zbx_str_free);
- zbx_vector_str_destroy(&rpools_all);
- zbx_vector_str_destroy(&rpools_uniq);
-
ret = SUCCEED;
out:
zbx_xml_free_doc(cluster_data);
- zbx_vector_str_clear_ext(&ids, zbx_str_free);
- zbx_vector_str_destroy(&ids);
- zbx_vector_str_destroy(&dss);
+ zbx_vector_vmware_rpool_chunk_clear_ext(&rp_chunks, vmware_rp_chunk_free);
+ zbx_vector_vmware_rpool_chunk_destroy(&rp_chunks);
+ zbx_vector_ptr_clear_ext(&cl_chunks, (zbx_clean_func_t)vmware_cluster_free);
+ zbx_vector_ptr_destroy(&cl_chunks);
zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s found cl:%d rp:%d", __func__, zbx_result_string(ret),
clusters->values_num, resourcepools->values_num);
return ret;
+# undef ZBX_POST_VCENTER_CLUSTER
}
/******************************************************************************
diff --git a/src/zabbix_server/vmware/vmware.h b/src/zabbix_server/vmware/vmware.h
index 15adb060d09..68e95685654 100644
--- a/src/zabbix_server/vmware/vmware.h
+++ b/src/zabbix_server/vmware/vmware.h
@@ -341,7 +341,6 @@ typedef struct
}
zbx_vmware_resourcepool_t;
-int vmware_resourcepool_compare_id(const void *r1, const void *r2);
ZBX_PTR_VECTOR_DECL(vmware_resourcepool, zbx_vmware_resourcepool_t *)
/* the vmware eventlog state */
diff --git a/src/zabbix_server/vmware/vmware_rest.c b/src/zabbix_server/vmware/vmware_rest.c
index 19665791ae5..78245603fda 100644
--- a/src/zabbix_server/vmware/vmware_rest.c
+++ b/src/zabbix_server/vmware/vmware_rest.c
@@ -510,8 +510,8 @@ static void vmware_service_rest_logout(CURL *easyhandle, ZBX_HTTPPAGE *page)
zbx_snprintf(tmp, sizeof(tmp),"%s/session", page->url);
if (CURLE_OK != (err = curl_easy_setopt(easyhandle, opt = CURLOPT_URL, tmp)) ||
- CURLE_OK != (err = curl_easy_setopt(easyhandle, opt = CURLOPT_CUSTOMREQUEST, "DELETE")) ||
- CURLE_OK != (err = curl_easy_setopt(easyhandle, opt = CURLOPT_POST, 0L)))
+ CURLE_OK != (err = curl_easy_setopt(easyhandle, opt = CURLOPT_POST, 0L)) ||
+ CURLE_OK != (err = curl_easy_setopt(easyhandle, opt = CURLOPT_CUSTOMREQUEST, "DELETE")))
{
zabbix_log(LOG_LEVEL_DEBUG, "%s() cannot set cURL option %d: %s.",
__func__, (int)opt, curl_easy_strerror(err));