diff options
author | Andrejs Kozlovs <andrejs.kozlovs@zabbix.com> | 2022-11-09 10:54:18 +0300 |
---|---|---|
committer | Andrejs Kozlovs <andrejs.kozlovs@zabbix.com> | 2022-11-09 10:54:18 +0300 |
commit | 39d00691a0a0af2b4de3dfc33a2509e773478f8e (patch) | |
tree | 861173b9f07cb6c4c562a6f2fa3190b01d4895b2 /src | |
parent | 5887066f5624d9a8d4af3f836fae505569ad8aad (diff) | |
parent | d136fbbbe6cd01ae26c017e4750ce2b830a907ee (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')
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)); |