diff options
author | Thomas Haller <thaller@redhat.com> | 2020-07-09 13:49:25 +0200 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2020-07-09 13:49:25 +0200 |
commit | 341111ff315f69363a4aec1081303733fcabe969 (patch) | |
tree | 1099ecbc315ea9e152723f2010a9fc4fdd77d384 | |
parent | 3e5fc04df320486b0f395fe6898c86f4c0144e05 (diff) | |
parent | ca7bb15591bb585156bcf17aa3c43817605b05ee (diff) | |
download | NetworkManager-341111ff315f69363a4aec1081303733fcabe969.tar.gz |
libnm,json: merge branch 'th/libnm_jansson-2'
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/559
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | Makefile.am | 45 | ||||
-rw-r--r-- | config.h.meson | 3 | ||||
-rw-r--r-- | configure.ac | 21 | ||||
-rw-r--r-- | libnm-core/meson.build | 6 | ||||
-rw-r--r-- | libnm-core/nm-json.c | 110 | ||||
-rw-r--r-- | libnm-core/nm-json.h | 39 | ||||
-rw-r--r-- | libnm-core/nm-team-utils.c | 130 | ||||
-rw-r--r-- | libnm-core/nm-utils.c | 30 | ||||
-rw-r--r-- | libnm-core/tests/test-general.c | 185 | ||||
-rw-r--r-- | libnm-core/tests/test-keyfile.c | 3 | ||||
-rw-r--r-- | libnm-core/tests/test-setting.c | 35 | ||||
-rw-r--r-- | meson.build | 12 | ||||
-rw-r--r-- | meson_options.txt | 1 | ||||
-rw-r--r-- | shared/nm-glib-aux/nm-jansson.h | 105 | ||||
-rw-r--r-- | shared/nm-glib-aux/nm-json-aux.c | 155 | ||||
-rw-r--r-- | shared/nm-glib-aux/nm-json-aux.h | 297 | ||||
-rw-r--r-- | shared/nm-glib-aux/tests/meson.build | 42 | ||||
-rw-r--r-- | shared/nm-glib-aux/tests/test-json-aux.c | 163 | ||||
-rw-r--r-- | src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c | 3 |
20 files changed, 857 insertions, 529 deletions
diff --git a/.gitignore b/.gitignore index 5cb43a0374..919b1830c9 100644 --- a/.gitignore +++ b/.gitignore @@ -131,6 +131,7 @@ test-*.trs /examples/C/qt/monitor-nm-running /examples/C/qt/monitor-nm-running.moc +/shared/nm-glib-aux/tests/test-json-aux /shared/nm-glib-aux/tests/test-shared-general /shared/nm-version-macros.h diff --git a/Makefile.am b/Makefile.am index e6d55b0bc1..01fd835e17 100644 --- a/Makefile.am +++ b/Makefile.am @@ -642,6 +642,39 @@ shared_nm_glib_aux_tests_test_shared_general_LDADD = \ ############################################################################### +if WITH_JANSSON + +check_programs += shared/nm-glib-aux/tests/test-json-aux + +shared_nm_glib_aux_tests_test_json_aux_CPPFLAGS = \ + $(dflt_cppflags) \ + -I$(srcdir)/shared \ + -DNETWORKMANAGER_COMPILATION_TEST \ + -DNETWORKMANAGER_COMPILATION='(NM_NETWORKMANAGER_COMPILATION_GLIB|NM_NETWORKMANAGER_COMPILATION_WITH_GLIB_I18N_PROG)' \ + $(CODE_COVERAGE_CFLAGS) \ + $(GLIB_CFLAGS) \ + $(JANSSON_CFLAGS) \ + $(SANITIZER_LIB_CFLAGS) \ + $(NULL) + +shared_nm_glib_aux_tests_test_json_aux_LDFLAGS = \ + $(CODE_COVERAGE_LDFLAGS) \ + $(SANITIZER_EXEC_LDFLAGS) \ + $(NULL) + +shared_nm_glib_aux_tests_test_json_aux_LDADD = \ + $(JANSSON_LIBS) \ + shared/nm-glib-aux/libnm-glib-aux.la \ + shared/systemd/libnm-systemd-logging-stub.la \ + shared/nm-std-aux/libnm-std-aux.la \ + shared/libcsiphash.la \ + $(GLIB_LIBS) \ + $(NULL) + +endif + +############################################################################### + noinst_LTLIBRARIES += introspection/libnmdbus.la introspection_libnmdbus_la_CPPFLAGS = $(GLIB_CFLAGS) @@ -1031,13 +1064,6 @@ libnm_core_lib_c_real = \ libnm-core/nm-vpn-plugin-info.c \ $(NULL) -if WITH_JSON_VALIDATION -libnm_core_lib_h_priv += \ - libnm-core/nm-json.h -libnm_core_lib_c_real += \ - libnm-core/nm-json.c -endif - libnm_core_lib_c_mkenums = \ libnm-core/nm-core-enum-types.c @@ -1092,11 +1118,6 @@ libnm_core_libnm_core_la_CPPFLAGS = \ -DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_LIBNM_CORE \ $(NULL) -if WITH_JSON_VALIDATION -libnm_core_libnm_core_la_CPPFLAGS += $(JANSSON_CFLAGS) -libnm_core_libnm_core_la_CPPFLAGS += -fcommon -endif - libnm_core_libnm_core_la_SOURCES = \ $(libnm_core_lib_h_pub_real) \ $(libnm_core_lib_h_priv) \ diff --git a/config.h.meson b/config.h.meson index b421ee1e71..bb5458aa64 100644 --- a/config.h.meson +++ b/config.h.meson @@ -212,9 +212,6 @@ /* Define if JANSSON is enabled */ #mesondefine WITH_JANSSON -/* Define if JSON validation in libnm is enabled */ -#mesondefine WITH_JSON_VALIDATION - /* Define if you have libpsl */ #mesondefine WITH_LIBPSL diff --git a/configure.ac b/configure.ac index 1e6823b494..86f91e21fe 100644 --- a/configure.ac +++ b/configure.ac @@ -583,7 +583,7 @@ PKG_CHECK_MODULES(UUID, uuid) # Teamd control checks -PKG_CHECK_MODULES(JANSSON, [jansson >= 2.5], [have_jansson=yes], [have_jansson=no]) +PKG_CHECK_MODULES(JANSSON, [jansson >= 2.7], [have_jansson=yes], [have_jansson=no]) if test "$have_jansson" = "yes"; then AC_DEFINE(WITH_JANSSON, 1, [Define if JANSSON is enabled]) @@ -596,6 +596,8 @@ if test "$have_jansson" = "yes"; then fi AC_DEFINE_UNQUOTED(JANSSON_SONAME, "$JANSSON_SONAME", [Define to path to the Jansson shared library]) else + have_jansson=no + JANSSON_SONAME= AC_DEFINE(WITH_JANSSON, 0, [Define if JANSSON is enabled]) fi AM_CONDITIONAL(WITH_JANSSON, test "${have_jansson}" = "yes") @@ -622,21 +624,6 @@ if test "${enable_teamdctl}" = "yes"; then fi AM_CONDITIONAL(WITH_TEAMDCTL, test "${enable_teamdctl}" = "yes") -# Jansson for team configuration validation -AC_ARG_ENABLE(json-validation, - AS_HELP_STRING([--enable-json-validation], [Enable JSON validation in libnm]), - [enable_json_validation=${enableval}], - [enable_json_validation=${have_jansson}]) -if test "${enable_json_validation}" = "no"; then - AC_DEFINE(WITH_JSON_VALIDATION, 0, [Define if JSON validation in libnm is enabled]) -else - if test "$have_jansson" = "no"; then - AC_MSG_ERROR([jansson is needed for team configuration validation. Use --disable-json-validation to build without it.]) - fi - AC_DEFINE(WITH_JSON_VALIDATION, 1, [Define if JSON validation in libnm is enabled]) -fi -AM_CONDITIONAL(WITH_JSON_VALIDATION, test "${enable_json_validation}" != "no") - # we usually compile with polkit support. --enable-polkit=yes|no only sets the # default configuration for main.auth-polkit. User can always enable/disable polkit # authorization via config. @@ -1366,6 +1353,7 @@ echo " nmcli: $build_nmcli" echo " nmtui: $build_nmtui" echo " nm-cloud-setup: $with_nm_cloud_setup" echo " iwd: $ac_with_iwd" +echo " jansson: $have_jansson${JANSSON_SONAME:+ (soname: $JANSSON_SONAME)}" echo echo "Configuration plugins (main.plugins=${config_plugins_default})" @@ -1398,7 +1386,6 @@ echo " valgrind: $with_valgrind $with_valgrind_suppressions" echo " code coverage: $enable_code_coverage" echo " LTO: $enable_lto" echo " linker garbage collection: $enable_ld_gc" -echo " JSON validation for libnm: $enable_json_validation" echo " crypto: $with_crypto (have-gnutls: $have_crypto_gnutls, have-nss: $have_crypto_nss)" echo " sanitizers: $sanitizers" echo " Mozilla Public Suffix List: $with_libpsl" diff --git a/libnm-core/meson.build b/libnm-core/meson.build index 89acaf72ad..0509deaa54 100644 --- a/libnm-core/meson.build +++ b/libnm-core/meson.build @@ -196,12 +196,6 @@ links = [ libnm_core_c_args = common_c_flags -if enable_json_validation - libnm_core_sources += files('nm-json.c') - deps += jansson_dep - libnm_core_c_args += ['-fcommon'] -endif - libnm_core = static_library( 'nm-core', sources: libnm_core_sources + libnm_core_enum_sources + nm_meta_setting_source + [nm_version_macro_header], diff --git a/libnm-core/nm-json.c b/libnm-core/nm-json.c deleted file mode 100644 index 001d53dbb6..0000000000 --- a/libnm-core/nm-json.c +++ /dev/null @@ -1,110 +0,0 @@ -// SPDX-License-Identifier: LGPL-2.1+ -/* - * Copyright (C) 2017, 2018 Red Hat, Inc. - */ - -#include "nm-default.h" - -#define NM_JANSSON_C -#include "nm-json.h" - -#include <dlfcn.h> - -void *_nm_jansson_json_object_iter_value; -void *_nm_jansson_json_object_key_to_iter; -void *_nm_jansson_json_integer; -void *_nm_jansson_json_object_del; -void *_nm_jansson_json_array_get; -void *_nm_jansson_json_array_size; -void *_nm_jansson_json_array_append_new; -void *_nm_jansson_json_string; -void *_nm_jansson_json_object_iter_next; -void *_nm_jansson_json_loads; -void *_nm_jansson_json_dumps; -void *_nm_jansson_json_object_iter_key; -void *_nm_jansson_json_object; -void *_nm_jansson_json_object_get; -void *_nm_jansson_json_array; -void *_nm_jansson_json_false; -void *_nm_jansson_json_delete; -void *_nm_jansson_json_true; -void *_nm_jansson_json_object_size; -void *_nm_jansson_json_object_set_new; -void *_nm_jansson_json_object_iter; -void *_nm_jansson_json_integer_value; -void *_nm_jansson_json_string_value; - -#define TRY_BIND_SYMBOL(symbol) \ - G_STMT_START { \ - void *sym = dlsym (handle, #symbol); \ - if (_nm_jansson_ ## symbol && sym != _nm_jansson_ ## symbol) \ - return FALSE; \ - _nm_jansson_ ## symbol = sym; \ - } G_STMT_END - -static gboolean -bind_symbols (void *handle) -{ - TRY_BIND_SYMBOL (json_object_iter_value); - TRY_BIND_SYMBOL (json_object_key_to_iter); - TRY_BIND_SYMBOL (json_integer); - TRY_BIND_SYMBOL (json_object_del); - TRY_BIND_SYMBOL (json_array_get); - TRY_BIND_SYMBOL (json_array_size); - TRY_BIND_SYMBOL (json_array_append_new); - TRY_BIND_SYMBOL (json_string); - TRY_BIND_SYMBOL (json_object_iter_next); - TRY_BIND_SYMBOL (json_loads); - TRY_BIND_SYMBOL (json_dumps); - TRY_BIND_SYMBOL (json_object_iter_key); - TRY_BIND_SYMBOL (json_object); - TRY_BIND_SYMBOL (json_object_get); - TRY_BIND_SYMBOL (json_array); - TRY_BIND_SYMBOL (json_false); - TRY_BIND_SYMBOL (json_delete); - TRY_BIND_SYMBOL (json_true); - TRY_BIND_SYMBOL (json_object_size); - TRY_BIND_SYMBOL (json_object_set_new); - TRY_BIND_SYMBOL (json_object_iter); - TRY_BIND_SYMBOL (json_integer_value); - TRY_BIND_SYMBOL (json_string_value); - - return TRUE; -} - -gboolean -nm_jansson_load (void) -{ - static enum { - UNKNOWN, - AVAILABLE, - MISSING, - } state = UNKNOWN; - void *handle; - int mode; - - if (G_LIKELY (state != UNKNOWN)) - goto out; - - /* First just resolve the symbols to see if there's a conflict already. */ - if (!bind_symbols (RTLD_DEFAULT)) - goto out; - - mode = RTLD_LAZY | RTLD_LOCAL | RTLD_NODELETE | RTLD_DEEPBIND; -#if defined (ASAN_BUILD) - /* Address sanitizer is incompatible with RTLD_DEEPBIND. */ - mode &= ~RTLD_DEEPBIND; -#endif - handle = dlopen (JANSSON_SONAME, mode); - - if (!handle) - goto out; - - /* Now do the actual binding. */ - if (!bind_symbols (handle)) - goto out; - - state = AVAILABLE; -out: - return state == AVAILABLE; -} diff --git a/libnm-core/nm-json.h b/libnm-core/nm-json.h deleted file mode 100644 index d857fe0275..0000000000 --- a/libnm-core/nm-json.h +++ /dev/null @@ -1,39 +0,0 @@ -// SPDX-License-Identifier: LGPL-2.1+ -/* - * Copyright (C) 2017, 2018 Red Hat, Inc. - */ - -#ifndef __NM_JSON_H__ -#define __NM_JSON_H__ - -gboolean nm_jansson_load (void); - -#ifndef NM_JANSSON_C -#define json_object_iter_value (*_nm_jansson_json_object_iter_value) -#define json_object_key_to_iter (*_nm_jansson_json_object_key_to_iter) -#define json_integer (*_nm_jansson_json_integer) -#define json_object_del (*_nm_jansson_json_object_del) -#define json_array_get (*_nm_jansson_json_array_get) -#define json_array_size (*_nm_jansson_json_array_size) -#define json_array_append_new (*_nm_jansson_json_array_append_new) -#define json_string (*_nm_jansson_json_string) -#define json_object_iter_next (*_nm_jansson_json_object_iter_next) -#define json_loads (*_nm_jansson_json_loads) -#define json_dumps (*_nm_jansson_json_dumps) -#define json_object_iter_key (*_nm_jansson_json_object_iter_key) -#define json_object (*_nm_jansson_json_object) -#define json_object_get (*_nm_jansson_json_object_get) -#define json_array (*_nm_jansson_json_array) -#define json_false (*_nm_jansson_json_false) -#define json_delete (*_nm_jansson_json_delete) -#define json_true (*_nm_jansson_json_true) -#define json_object_size (*_nm_jansson_json_object_size) -#define json_object_set_new (*_nm_jansson_json_object_set_new) -#define json_object_iter (*_nm_jansson_json_object_iter) -#define json_integer_value (*_nm_jansson_json_integer_value) -#define json_string_value (*_nm_jansson_json_string_value) - -#include "nm-glib-aux/nm-jansson.h" -#endif - -#endif /* __NM_JSON_H__ */ diff --git a/libnm-core/nm-team-utils.c b/libnm-core/nm-team-utils.c index 084547c8f8..ca18c7d6a0 100644 --- a/libnm-core/nm-team-utils.c +++ b/libnm-core/nm-team-utils.c @@ -11,7 +11,6 @@ #include "nm-errors.h" #include "nm-utils-private.h" -#include "nm-json.h" #include "nm-glib-aux/nm-json-aux.h" #include "nm-core-internal.h" #include "nm-setting-team.h" @@ -460,9 +459,9 @@ _team_attr_data_to_json (const TeamAttrData *attr_data, _team_attr_data_ASSERT (attr_data); nm_assert (p_field); - nm_json_aux_gstr_append_obj_name (gstr, - attr_data->js_keys[attr_data->js_keys_len - 1], - '\0'); + nm_json_gstr_append_obj_name (gstr, + attr_data->js_keys[attr_data->js_keys_len - 1], + '\0'); if (attr_data->value_type != NM_VALUE_TYPE_UNSPEC) { nm_value_type_to_json (attr_data->value_type, gstr, p_field); @@ -482,7 +481,7 @@ _team_attr_data_to_json (const TeamAttrData *attr_data, g_string_append (gstr, "[ "); for (i = 0; i < v_ptrarray->len; i++) { if (i > 0) - nm_json_aux_gstr_append_delimiter (gstr); + nm_json_gstr_append_delimiter (gstr); _link_watcher_to_json (v_ptrarray->pdata[i], gstr); } g_string_append (gstr, " ]"); @@ -500,8 +499,8 @@ _team_attr_data_to_json (const TeamAttrData *attr_data, g_string_append (gstr, "[ "); for (i = 0; i < v_ptrarray->len; i++) { if (i > 0) - nm_json_aux_gstr_append_delimiter (gstr); - nm_json_aux_gstr_append_string (gstr, v_ptrarray->pdata[i]); + nm_json_gstr_append_delimiter (gstr); + nm_json_gstr_append_string (gstr, v_ptrarray->pdata[i]); } g_string_append (gstr, i > 0 ? " ]" : "]"); } @@ -671,7 +670,7 @@ _team_setting_field_to_json (const NMTeamSetting *self, return FALSE; if (prepend_delimiter) - nm_json_aux_gstr_append_delimiter (gstr); + nm_json_gstr_append_delimiter (gstr); _team_attr_data_to_json (attr_data, self->d.is_port, gstr, @@ -1108,29 +1107,29 @@ _link_watcher_to_json (const NMTeamLinkWatcher *link_watcher, if (is_first) is_first = FALSE; else - nm_json_aux_gstr_append_delimiter (gstr); - nm_json_aux_gstr_append_obj_name (gstr, attr_data->js_key, '\0'); + nm_json_gstr_append_delimiter (gstr); + nm_json_gstr_append_obj_name (gstr, attr_data->js_key, '\0'); nm_value_type_to_json (attr_data->value_type, gstr, &p_val->val); } g_string_append (gstr, " }"); } -#if WITH_JSON_VALIDATION static NMTeamLinkWatcher * -_link_watcher_from_json (const json_t *root_js_obj, +_link_watcher_from_json (const NMJsonVt *vt, + const nm_json_t *root_js_obj, gboolean *out_unrecognized_content) { NMValueTypUnioMaybe args[G_N_ELEMENTS (link_watcher_attr_datas)] = { }; const char *j_key; - json_t *j_val; + nm_json_t *j_val; const char *v_name; NMTeamLinkWatcher *result = NULL; - if (!json_is_object (root_js_obj)) + if (!nm_json_is_object (root_js_obj)) goto fail; - json_object_foreach ((json_t *) root_js_obj, j_key, j_val) { + nm_json_object_foreach (vt, (nm_json_t *) root_js_obj, j_key, j_val) { const LinkWatcherAttrData *attr_data = NULL; NMValueTypUnioMaybe *parse_result; @@ -1154,7 +1153,7 @@ _link_watcher_from_json (const json_t *root_js_obj, if (parse_result->has) *out_unrecognized_content = TRUE; - if (!nm_value_type_from_json (attr_data->value_type, j_val, &parse_result->val)) + if (!nm_value_type_from_json (vt, attr_data->value_type, j_val, &parse_result->val)) *out_unrecognized_content = TRUE; else parse_result->has = TRUE; @@ -1218,7 +1217,6 @@ fail: *out_unrecognized_content = TRUE; return NULL; } -#endif /*****************************************************************************/ @@ -1575,15 +1573,15 @@ nm_team_setting_config_get (const NMTeamSetting *self) nm_assert (list_is_empty); - nm_json_aux_gstr_append_obj_name (gstr, "runner", '{'); + nm_json_gstr_append_obj_name (gstr, "runner", '{'); if (_team_setting_fields_to_json_maybe (self, gstr, !list_is_empty2, attr_lst_runner_pt1, G_N_ELEMENTS (attr_lst_runner_pt1))) list_is_empty2 = FALSE; if (_team_setting_has_fields_any_v (self, attr_lst_runner_pt2, G_N_ELEMENTS (attr_lst_runner_pt2))) { if (!list_is_empty2) - nm_json_aux_gstr_append_delimiter (gstr); - nm_json_aux_gstr_append_obj_name (gstr, "tx_balancer", '{'); + nm_json_gstr_append_delimiter (gstr); + nm_json_gstr_append_obj_name (gstr, "tx_balancer", '{'); if (!_team_setting_fields_to_json_maybe (self, gstr, FALSE, attr_lst_runner_pt2, G_N_ELEMENTS (attr_lst_runner_pt2))) nm_assert_not_reached (); g_string_append (gstr, " }"); @@ -1600,8 +1598,8 @@ nm_team_setting_config_get (const NMTeamSetting *self) if (_team_setting_has_fields_any_v (self, attr_lst_notify_peers, G_N_ELEMENTS (attr_lst_notify_peers))) { if (!list_is_empty) - nm_json_aux_gstr_append_delimiter (gstr); - nm_json_aux_gstr_append_obj_name (gstr, "notify_peers", '{'); + nm_json_gstr_append_delimiter (gstr); + nm_json_gstr_append_obj_name (gstr, "notify_peers", '{'); if (!_team_setting_fields_to_json_maybe (self, gstr, FALSE, attr_lst_notify_peers, G_N_ELEMENTS (attr_lst_notify_peers))) nm_assert_not_reached (); g_string_append (gstr, " }"); @@ -1610,8 +1608,8 @@ nm_team_setting_config_get (const NMTeamSetting *self) if (_team_setting_has_fields_any_v (self, attr_lst_mcast_rejoin, G_N_ELEMENTS (attr_lst_mcast_rejoin))) { if (!list_is_empty) - nm_json_aux_gstr_append_delimiter (gstr); - nm_json_aux_gstr_append_obj_name (gstr, "mcast_rejoin", '{'); + nm_json_gstr_append_delimiter (gstr); + nm_json_gstr_append_obj_name (gstr, "mcast_rejoin", '{'); if (!_team_setting_fields_to_json_maybe (self, gstr, FALSE, attr_lst_mcast_rejoin, G_N_ELEMENTS (attr_lst_mcast_rejoin))) nm_assert_not_reached (); g_string_append (gstr, " }"); @@ -1641,7 +1639,6 @@ nm_team_setting_config_get (const NMTeamSetting *self) /*****************************************************************************/ -#if WITH_JSON_VALIDATION static gboolean _attr_data_match_keys (const TeamAttrData *attr_data, const char *const*keys, @@ -1686,18 +1683,21 @@ _attr_data_find_by_json_key (gboolean is_port, } static void -_js_parse_locate_keys (NMTeamSetting *self, - json_t *root_js_obj, - json_t *found_keys[static _NM_TEAM_ATTRIBUTE_NUM], +_js_parse_locate_keys (const NMJsonVt *vt, + NMTeamSetting *self, + nm_json_t *root_js_obj, + nm_json_t *found_keys[static _NM_TEAM_ATTRIBUTE_NUM], gboolean *out_unrecognized_content) { const char *keys[3]; const char *cur_key1; const char *cur_key2; const char *cur_key3; - json_t *cur_val1; - json_t *cur_val2; - json_t *cur_val3; + nm_json_t *cur_val1; + nm_json_t *cur_val2; + nm_json_t *cur_val3; + + nm_assert (vt); #define _handle(_self, _cur_key, _cur_val, _keys, _level, _found_keys, _out_unrecognized_content) \ ({ \ @@ -1713,18 +1713,18 @@ _js_parse_locate_keys (NMTeamSetting *self, (_found_keys)[_attr_data->team_attr] = (_cur_val); \ _handled = TRUE; \ } else if ( !_attr_data \ - || !json_is_object ((_cur_val))) { \ + || !nm_json_is_object ((_cur_val))) { \ *(_out_unrecognized_content) = TRUE; \ _handled = TRUE; \ } \ _handled; \ }) - json_object_foreach (root_js_obj, cur_key1, cur_val1) { + nm_json_object_foreach (vt, root_js_obj, cur_key1, cur_val1) { if (!_handle (self, cur_key1, cur_val1, keys, 1, found_keys, out_unrecognized_content)) { - json_object_foreach (cur_val1, cur_key2, cur_val2) { + nm_json_object_foreach (vt, cur_val1, cur_key2, cur_val2) { if (!_handle (self, cur_key2, cur_val2, keys, 2, found_keys, out_unrecognized_content)) { - json_object_foreach (cur_val2, cur_key3, cur_val3) { + nm_json_object_foreach (vt, cur_val2, cur_key3, cur_val3) { if (!_handle (self, cur_key3, cur_val3, keys, 3, found_keys, out_unrecognized_content)) *out_unrecognized_content = TRUE; } @@ -1737,8 +1737,9 @@ _js_parse_locate_keys (NMTeamSetting *self, } static void -_js_parse_unpack (gboolean is_port, - json_t *found_keys[static _NM_TEAM_ATTRIBUTE_NUM], +_js_parse_unpack (const NMJsonVt *vt, + gboolean is_port, + nm_json_t *found_keys[static _NM_TEAM_ATTRIBUTE_NUM], bool out_has_lst[static _NM_TEAM_ATTRIBUTE_NUM], NMValueTypUnion out_val_lst[static _NM_TEAM_ATTRIBUTE_NUM], gboolean *out_unrecognized_content, @@ -1747,10 +1748,12 @@ _js_parse_unpack (gboolean is_port, { const TeamAttrData *attr_data; + nm_assert (vt); + for (attr_data = &team_attr_datas[TEAM_ATTR_IDX_CONFIG + 1]; attr_data < &team_attr_datas[G_N_ELEMENTS (team_attr_datas)]; attr_data++) { NMValueTypUnion *p_out_val; gboolean valid = FALSE; - json_t *arg_js_obj; + nm_json_t *arg_js_obj; if (!_team_attr_data_is_relevant (attr_data, is_port)) continue; @@ -1764,25 +1767,27 @@ _js_parse_unpack (gboolean is_port, p_out_val = &out_val_lst[attr_data->team_attr]; if (attr_data->value_type != NM_VALUE_TYPE_UNSPEC) - valid = nm_value_type_from_json (attr_data->value_type, arg_js_obj, p_out_val); + valid = nm_value_type_from_json (vt, attr_data->value_type, arg_js_obj, p_out_val); else if (attr_data->team_attr == NM_TEAM_ATTRIBUTE_LINK_WATCHERS) { GPtrArray *link_watchers = NULL; NMTeamLinkWatcher *link_watcher; nm_assert (out_ptr_array_link_watchers_free && !*out_ptr_array_link_watchers_free); - if (json_is_array (arg_js_obj)) { + if (nm_json_is_array (arg_js_obj)) { gsize i, len; - len = json_array_size (arg_js_obj); + len = vt->nm_json_array_size (arg_js_obj); link_watchers = g_ptr_array_new_full (len, (GDestroyNotify) nm_team_link_watcher_unref); for (i = 0; i < len; i++) { - link_watcher = _link_watcher_from_json (json_array_get (arg_js_obj, i), + link_watcher = _link_watcher_from_json (vt, + vt->nm_json_array_get (arg_js_obj, i), out_unrecognized_content); if (link_watcher) g_ptr_array_add (link_watchers, link_watcher); } } else { - link_watcher = _link_watcher_from_json (arg_js_obj, + link_watcher = _link_watcher_from_json (vt, + arg_js_obj, out_unrecognized_content); if (link_watcher) { link_watchers = g_ptr_array_new_full (1, (GDestroyNotify) nm_team_link_watcher_unref); @@ -1799,16 +1804,17 @@ _js_parse_unpack (gboolean is_port, GPtrArray *strv = NULL; nm_assert (out_ptr_array_master_runner_tx_hash_free && !*out_ptr_array_master_runner_tx_hash_free); - if (json_is_array (arg_js_obj)) { + if (nm_json_is_array (arg_js_obj)) { gsize i, len; - len = json_array_size (arg_js_obj); + len = vt->nm_json_array_size (arg_js_obj); if (len > 0) { strv = g_ptr_array_sized_new (len); for (i = 0; i < len; i++) { const char *v_string; - if ( nm_jansson_json_as_string (json_array_get (arg_js_obj, i), + if ( nm_jansson_json_as_string (vt, + vt->nm_json_array_get (arg_js_obj, i), &v_string) <= 0 || !v_string || v_string[0] == '\0') { @@ -1832,11 +1838,11 @@ _js_parse_unpack (gboolean is_port, *out_unrecognized_content = TRUE; } } -#endif guint32 nm_team_setting_config_set (NMTeamSetting *self, const char *js_str) { + const NMJsonVt *vt; guint32 changed_flags = 0; gboolean do_set_default = TRUE; gboolean new_js_str_invalid = FALSE; @@ -1866,30 +1872,29 @@ nm_team_setting_config_set (NMTeamSetting *self, const char *js_str) } else changed_flags |= nm_team_attribute_to_flags (NM_TEAM_ATTRIBUTE_CONFIG); -#if WITH_JSON_VALIDATION - { - nm_auto_decref_json json_t *root_js_obj = NULL; - - if (nm_jansson_load ()) - root_js_obj = json_loads (js_str, 0, NULL); + if ((vt = nm_json_vt ())) { + nm_auto_decref_json nm_json_t *root_js_obj = NULL; + root_js_obj = vt->nm_json_loads (js_str, 0, NULL); if ( !root_js_obj - || !json_is_object (root_js_obj)) + || !nm_json_is_object (root_js_obj)) new_js_str_invalid = TRUE; else { gboolean unrecognized_content = FALSE; bool has_lst[_NM_TEAM_ATTRIBUTE_NUM] = { FALSE, }; NMValueTypUnion val_lst[_NM_TEAM_ATTRIBUTE_NUM]; - json_t *found_keys[_NM_TEAM_ATTRIBUTE_NUM] = { NULL, }; + nm_json_t *found_keys[_NM_TEAM_ATTRIBUTE_NUM] = { NULL, }; gs_unref_ptrarray GPtrArray *ptr_array_master_runner_tx_hash_free = NULL; gs_unref_ptrarray GPtrArray *ptr_array_link_watchers_free = NULL; - _js_parse_locate_keys (self, + _js_parse_locate_keys (vt, + self, root_js_obj, found_keys, &unrecognized_content); - _js_parse_unpack (self->d.is_port, + _js_parse_unpack (vt, + self->d.is_port, found_keys, has_lst, val_lst, @@ -1906,8 +1911,6 @@ nm_team_setting_config_set (NMTeamSetting *self, const char *js_str) } } -#endif - if (do_set_default) changed_flags |= _team_setting_set_default (self); @@ -2222,6 +2225,7 @@ nm_team_setting_reset_from_dbus (NMTeamSetting *self, GVariantIter iter; const char *v_key; GVariant *v_val; + const NMJsonVt *vt; *out_changed = 0; @@ -2271,10 +2275,12 @@ nm_team_setting_reset_from_dbus (NMTeamSetting *self, variants[attr_data->team_attr] = g_steal_pointer (&v_val_free); } + vt = nm_json_vt (); + if (variants[NM_TEAM_ATTRIBUTE_LINK_WATCHERS]) { if ( variants[NM_TEAM_ATTRIBUTE_CONFIG] - && WITH_JSON_VALIDATION + && vt && !NM_FLAGS_HAS (parse_flags, NM_SETTING_PARSE_FLAGS_STRICT)) { /* we don't require the content of the "link-watchers" and we also * don't perform strict validation. No need to parse it. */ @@ -2282,7 +2288,7 @@ nm_team_setting_reset_from_dbus (NMTeamSetting *self, gs_free_error GError *local = NULL; /* We might need the parsed v_link_watchers array below (because there is no JSON - * "config" present or because we don't build WITH_JSON_VALIDATION). + * "config" present or because we don't have json support). * * Or we might run with NM_SETTING_PARSE_FLAGS_STRICT. In that mode, we may not necessarily * require that the entire setting as a whole validates (if a JSON config is present and @@ -2310,7 +2316,7 @@ nm_team_setting_reset_from_dbus (NMTeamSetting *self, ? g_variant_get_string (variants[NM_TEAM_ATTRIBUTE_CONFIG], NULL) : NULL); - if ( WITH_JSON_VALIDATION + if ( vt && variants[NM_TEAM_ATTRIBUTE_CONFIG]) { /* for team settings, the JSON must be able to express all possible options. That means, * if the GVariant contains both the JSON "config" and other options, then the other options diff --git a/libnm-core/nm-utils.c b/libnm-core/nm-utils.c index 4127abb54d..b633a5099c 100644 --- a/libnm-core/nm-utils.c +++ b/libnm-core/nm-utils.c @@ -16,10 +16,7 @@ #include <sys/stat.h> #include <linux/pkt_sched.h> -#if WITH_JSON_VALIDATION -#include "nm-json.h" -#endif - +#include "nm-glib-aux/nm-json-aux.h" #include "nm-glib-aux/nm-str-buf.h" #include "nm-glib-aux/nm-enum-utils.h" #include "nm-glib-aux/nm-time-utils.h" @@ -5493,9 +5490,9 @@ _nm_utils_is_json_object_no_validation (const char *str, GError **error) gboolean nm_utils_is_json_object (const char *str, GError **error) { -#if WITH_JSON_VALIDATION - nm_auto_decref_json json_t *json = NULL; - json_error_t jerror; + nm_auto_decref_json nm_json_t *json = NULL; + const NMJsonVt *vt; + nm_json_error_t jerror; g_return_val_if_fail (!error || !*error, FALSE); @@ -5507,10 +5504,10 @@ nm_utils_is_json_object (const char *str, GError **error) return FALSE; } - if (!nm_jansson_load ()) + if (!(vt = nm_json_vt ())) return _nm_utils_is_json_object_no_validation (str, error); - json = json_loads (str, JSON_REJECT_DUPLICATES, &jerror); + json = vt->nm_json_loads (str, NM_JSON_REJECT_DUPLICATES, &jerror); if (!json) { g_set_error (error, NM_CONNECTION_ERROR, @@ -5523,7 +5520,7 @@ nm_utils_is_json_object (const char *str, GError **error) /* valid JSON (depending on the definition) can also be a literal. * Here we only allow objects. */ - if (!json_is_object (json)) { + if (!nm_json_is_object (json)) { g_set_error_literal (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY, @@ -5532,19 +5529,6 @@ nm_utils_is_json_object (const char *str, GError **error) } return TRUE; -#else /* !WITH_JSON_VALIDATION */ - g_return_val_if_fail (!error || !*error, FALSE); - - if (!str || !str[0]) { - g_set_error_literal (error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - str ? _("value is NULL") : _("value is empty")); - return FALSE; - } - - return _nm_utils_is_json_object_no_validation (str, error); -#endif } static char * diff --git a/libnm-core/tests/test-general.c b/libnm-core/tests/test-general.c index 040bcb9f1f..1e4efe2452 100644 --- a/libnm-core/tests/test-general.c +++ b/libnm-core/tests/test-general.c @@ -14,6 +14,7 @@ #include "nm-std-aux/c-list-util.h" #include "nm-glib-aux/nm-enum-utils.h" #include "nm-glib-aux/nm-str-buf.h" +#include "nm-glib-aux/nm-json-aux.h" #include "systemd/nm-sd-utils-shared.h" #include "nm-utils.h" @@ -7125,17 +7126,19 @@ test_nm_utils_check_valid_json (void) { _json_config_check_valid (NULL, FALSE); _json_config_check_valid ("", FALSE); -#if WITH_JSON_VALIDATION - _json_config_check_valid ("{ }", TRUE); - _json_config_check_valid ("{ \"a\" : 1 }", TRUE); - _json_config_check_valid ("{ \"a\" : }", FALSE); -#else + /* Without JSON library everything except empty string is considered valid */ + nmtst_json_vt_reset (FALSE); _json_config_check_valid ("{ }", TRUE); _json_config_check_valid ("{'%!-a1} ", TRUE); _json_config_check_valid (" {'%!-a1}", TRUE); _json_config_check_valid ("{'%!-a1", FALSE); -#endif + + if (nmtst_json_vt_reset (TRUE)) { + _json_config_check_valid ("{ }", TRUE); + _json_config_check_valid ("{ \"a\" : 1 }", TRUE); + _json_config_check_valid ("{ \"a\" : }", FALSE); + } } static void @@ -7172,86 +7175,96 @@ _team_config_equal_check (const char *conf1, static void test_nm_utils_team_config_equal (void) { - _team_config_equal_check ("", - "", - TRUE, - TRUE); - _team_config_equal_check ("", - " ", - TRUE, - TRUE); - _team_config_equal_check ("{}", - "{ }", - TRUE, - TRUE); - _team_config_equal_check ("{}", - "{", - TRUE, - TRUE); - _team_config_equal_check ("{ \"a\": 1 }", - "{ \"a\": 1 }", - TRUE, - TRUE); - _team_config_equal_check ("{ \"a\": 1 }", - "{ \"a\": 1 }", - TRUE, - TRUE); - - /* team config */ - _team_config_equal_check ("{ }", - "{ \"runner\" : { \"name\" : \"random\"} }", - FALSE, - !WITH_JSON_VALIDATION); - _team_config_equal_check ("{ \"runner\" : { \"name\" : \"roundrobin\"} }", - "{ \"runner\" : { \"name\" : \"random\"} }", - FALSE, - !WITH_JSON_VALIDATION); - _team_config_equal_check ("{ \"runner\" : { \"name\" : \"random\"} }", - "{ \"runner\" : { \"name\" : \"random\"} }", - FALSE, - TRUE); - _team_config_equal_check ("{ \"runner\" : { \"name\" : \"loadbalance\"} }", - "{ \"runner\" : { \"name\" : \"loadbalance\"} }", - FALSE, - TRUE); - _team_config_equal_check ("{ \"runner\" : { \"name\" : \"random\"}, \"ports\" : { \"eth0\" : {} } }", - "{ \"runner\" : { \"name\" : \"random\"}, \"ports\" : { \"eth1\" : {} } }", - FALSE, - TRUE); - _team_config_equal_check ("{ \"runner\" : { \"name\" : \"lacp\"} }", - "{ \"runner\" : { \"name\" : \"lacp\", \"tx_hash\" : [ \"eth\", \"ipv4\", \"ipv6\" ] } }", - FALSE, - !WITH_JSON_VALIDATION); - _team_config_equal_check ("{ \"runner\" : { \"name\" : \"roundrobin\"} }", - "{ \"runner\" : { \"name\" : \"roundrobin\", \"tx_hash\" : [ \"eth\", \"ipv4\", \"ipv6\" ] } }", - FALSE, - !WITH_JSON_VALIDATION); - _team_config_equal_check ("{ \"runner\" : { \"name\" : \"lacp\"} }", - "{ \"runner\" : { \"name\" : \"lacp\", \"tx_hash\" : [ \"eth\" ] } }", - FALSE, - !WITH_JSON_VALIDATION); - - /* team port config */ - _team_config_equal_check ("{ }", - "{ \"link_watch\" : { \"name\" : \"ethtool\"} }", - TRUE, - !WITH_JSON_VALIDATION); - _team_config_equal_check ("{ }", - "{ \"link_watch\" : { \"name\" : \"arp_ping\"} }", - TRUE, - TRUE); - _team_config_equal_check ("{ \"link_watch\" : { \"name\" : \"ethtool\"} }", - "{ \"link_watch\" : { \"name\" : \"arp_ping\"} }", - TRUE, - !WITH_JSON_VALIDATION); - _team_config_equal_check ("{ \"link_watch\" : { \"name\" : \"arp_ping\"} }", - "{ \"link_watch\" : { \"name\" : \"arp_ping\"} }", - TRUE, - TRUE); - _team_config_equal_check ("{ \"link_watch\" : { \"name\" : \"arp_ping\"}, \"ports\" : { \"eth0\" : {} } }", - "{ \"link_watch\" : { \"name\" : \"arp_ping\"}, \"ports\" : { \"eth1\" : {} } }", - TRUE, - TRUE); + int with_json_vt; + + for (with_json_vt = 0; with_json_vt < 2; with_json_vt++) { + const NMJsonVt *vt; + + vt = nmtst_json_vt_reset (!!with_json_vt); + + _team_config_equal_check ("", + "", + TRUE, + TRUE); + _team_config_equal_check ("", + " ", + TRUE, + TRUE); + _team_config_equal_check ("{}", + "{ }", + TRUE, + TRUE); + _team_config_equal_check ("{}", + "{", + TRUE, + TRUE); + _team_config_equal_check ("{ \"a\": 1 }", + "{ \"a\": 1 }", + TRUE, + TRUE); + _team_config_equal_check ("{ \"a\": 1 }", + "{ \"a\": 1 }", + TRUE, + TRUE); + + /* team config */ + _team_config_equal_check ("{ }", + "{ \"runner\" : { \"name\" : \"random\"} }", + FALSE, + !vt); + _team_config_equal_check ("{ \"runner\" : { \"name\" : \"roundrobin\"} }", + "{ \"runner\" : { \"name\" : \"random\"} }", + FALSE, + !vt); + _team_config_equal_check ("{ \"runner\" : { \"name\" : \"random\"} }", + "{ \"runner\" : { \"name\" : \"random\"} }", + FALSE, + TRUE); + _team_config_equal_check ("{ \"runner\" : { \"name\" : \"loadbalance\"} }", + "{ \"runner\" : { \"name\" : \"loadbalance\"} }", + FALSE, + TRUE); + _team_config_equal_check ("{ \"runner\" : { \"name\" : \"random\"}, \"ports\" : { \"eth0\" : {} } }", + "{ \"runner\" : { \"name\" : \"random\"}, \"ports\" : { \"eth1\" : {} } }", + FALSE, + TRUE); + _team_config_equal_check ("{ \"runner\" : { \"name\" : \"lacp\"} }", + "{ \"runner\" : { \"name\" : \"lacp\", \"tx_hash\" : [ \"eth\", \"ipv4\", \"ipv6\" ] } }", + FALSE, + !vt); + _team_config_equal_check ("{ \"runner\" : { \"name\" : \"roundrobin\"} }", + "{ \"runner\" : { \"name\" : \"roundrobin\", \"tx_hash\" : [ \"eth\", \"ipv4\", \"ipv6\" ] } }", + FALSE, + !vt); + _team_config_equal_check ("{ \"runner\" : { \"name\" : \"lacp\"} }", + "{ \"runner\" : { \"name\" : \"lacp\", \"tx_hash\" : [ \"eth\" ] } }", + FALSE, + !vt); + + /* team port config */ + _team_config_equal_check ("{ }", + "{ \"link_watch\" : { \"name\" : \"ethtool\"} }", + TRUE, + !vt); + _team_config_equal_check ("{ }", + "{ \"link_watch\" : { \"name\" : \"arp_ping\"} }", + TRUE, + TRUE); + _team_config_equal_check ("{ \"link_watch\" : { \"name\" : \"ethtool\"} }", + "{ \"link_watch\" : { \"name\" : \"arp_ping\"} }", + TRUE, + !vt); + _team_config_equal_check ("{ \"link_watch\" : { \"name\" : \"arp_ping\"} }", + "{ \"link_watch\" : { \"name\" : \"arp_ping\"} }", + TRUE, + TRUE); + _team_config_equal_check ("{ \"link_watch\" : { \"name\" : \"arp_ping\"}, \"ports\" : { \"eth0\" : {} } }", + "{ \"link_watch\" : { \"name\" : \"arp_ping\"}, \"ports\" : { \"eth1\" : {} } }", + TRUE, + TRUE); + } + + nmtst_json_vt_reset (TRUE); } /*****************************************************************************/ diff --git a/libnm-core/tests/test-keyfile.c b/libnm-core/tests/test-keyfile.c index 23149b618d..c9ec51f01b 100644 --- a/libnm-core/tests/test-keyfile.c +++ b/libnm-core/tests/test-keyfile.c @@ -5,6 +5,7 @@ #include "nm-default.h" +#include "nm-glib-aux/nm-json-aux.h" #include "nm-keyfile/nm-keyfile-utils.h" #include "nm-keyfile/nm-keyfile-internal.h" #include "nm-simple-connection.h" @@ -627,7 +628,7 @@ test_team_conf_read_invalid (void) gs_unref_object NMConnection *con = NULL; NMSettingTeam *s_team; - if (!WITH_JSON_VALIDATION) { + if (!nm_json_vt ()) { g_test_skip ("team test requires JSON validation"); return; } diff --git a/libnm-core/tests/test-setting.c b/libnm-core/tests/test-setting.c index 1a32d91a49..1b53baeda3 100644 --- a/libnm-core/tests/test-setting.c +++ b/libnm-core/tests/test-setting.c @@ -8,6 +8,7 @@ #include <linux/pkt_sched.h> #include <net/if.h> +#include "nm-glib-aux/nm-json-aux.h" #include "nm-core-internal.h" #include "nm-utils.h" #include "nm-utils-private.h" @@ -32,15 +33,6 @@ /*****************************************************************************/ -/* assert that the define is just a plain integer (boolean). */ - -G_STATIC_ASSERT ( (WITH_JSON_VALIDATION) == 1 - || (WITH_JSON_VALIDATION) == 0); - -_nm_unused static const int _with_json_validation = WITH_JSON_VALIDATION; - -/*****************************************************************************/ - /* converts @dict to a connection. In this case, @dict must be good, without warnings, so that * NM_SETTING_PARSE_FLAGS_STRICT and NM_SETTING_PARSE_FLAGS_BEST_EFFORT yield the exact same results. */ static NMConnection * @@ -979,6 +971,24 @@ test_dcb_bandwidth_sums (void) /*****************************************************************************/ static void +test_nm_json (void) +{ + g_assert (NM_IN_SET (WITH_JANSSON, 0, 1)); + +#if WITH_JANSSON + g_assert (nm_json_vt ()); +#else + g_assert (!nm_json_vt ()); +#endif + +#if WITH_JANSSON != defined (JANSSON_SONAME) +#error "WITH_JANSON and JANSSON_SONAME are defined inconsistently." +#endif +} + +/*****************************************************************************/ + +static void _test_team_config_sync (const char *team_config, int notify_peer_count, int notify_peers_interval, @@ -1000,7 +1010,7 @@ _test_team_config_sync (const char *team_config, guint i, j; gboolean found; - if (!WITH_JSON_VALIDATION) { + if (!nm_json_vt ()) { g_test_skip ("team test requires JSON validation"); return; } @@ -1265,7 +1275,7 @@ _test_team_port_config_sync (const char *team_port_config, guint i, j; gboolean found; - if (!WITH_JSON_VALIDATION) { + if (!nm_json_vt ()) { g_test_skip ("team test requires JSON validation"); return; } @@ -1397,7 +1407,7 @@ _check_team_setting (NMSetting *setting) : nm_setting_team_get_config (NM_SETTING_TEAM (setting)), NULL); - if (WITH_JSON_VALIDATION) + if (nm_json_vt ()) nmtst_assert_setting_is_equal (setting, setting2, NM_SETTING_COMPARE_FLAG_EXACT); g_clear_object (&setting2); @@ -4095,6 +4105,7 @@ main (int argc, char **argv) g_test_add_func ("/libnm/settings/bridge/vlans", test_bridge_vlans); g_test_add_func ("/libnm/settings/bridge/verify", test_bridge_verify); + g_test_add_func ("/libnm/test_nm_json", test_nm_json); g_test_add_func ("/libnm/settings/team/sync_runner_from_config_roundrobin", test_runner_roundrobin_sync_from_config); g_test_add_func ("/libnm/settings/team/sync_runner_from_config_broadcast", diff --git a/meson.build b/meson.build index 8eed507f08..f8973b4680 100644 --- a/meson.build +++ b/meson.build @@ -253,9 +253,10 @@ libudev_dep = dependency('libudev', version: '>= 175') dbus_dep = dependency('dbus-1', version: '>= 1.1') libndp_dep = dependency('libndp') -jansson_dep = dependency('jansson', version: '>= 2.5', required: false) +jansson_dep = dependency('jansson', version: '>= 2.7', required: false) config_h.set10('WITH_JANSSON', jansson_dep.found()) +jansson_msg = 'no' if jansson_dep.found() jansson_libdir = jansson_dep.get_pkgconfig_variable('libdir') res = run_command(find_program('eu-readelf', 'readelf'), '-d', join_paths(jansson_libdir, 'libjansson.so')) @@ -267,6 +268,7 @@ if jansson_dep.found() endforeach assert(jansson_soname != '', 'Unable to determine Jansson SONAME') config_h.set_quoted('JANSSON_SONAME', jansson_soname) + jansson_msg = 'yes (soname: ' + jansson_soname + ')' endif libsystemd_dep = dependency('libsystemd', version: '>= 209', required: false) @@ -497,12 +499,6 @@ if enable_teamdctl assert(libteamdctl_dep.found(), 'You must have libteamdctl installed to build. Use -Dteamdctl=false to disable it') endif -enable_json_validation = get_option('json_validation') -if enable_json_validation - assert(jansson_dep.found(), 'jansson is needed for team configuration validation. Use -Djson_validation=false to disable it') -endif -config_h.set10('WITH_JSON_VALIDATION', enable_json_validation) - # polkit enable_polkit = get_option('polkit') if enable_polkit @@ -1013,6 +1009,7 @@ if enable_ppp output += ' ' + pppd_path + ' plugins:' + pppd_plugin_dir endif output += '\n' +output += ' jansson: ' + jansson_msg + '\n' output += ' modemmanager-1: ' + enable_modem_manager.to_string() + '\n' output += ' ofono: ' + enable_ofono.to_string() + '\n' output += ' concheck: ' + enable_concheck.to_string() + '\n' @@ -1047,7 +1044,6 @@ output += '\n' output += ' code coverage: ' + get_option('b_coverage').to_string() + '\n' output += ' LTO: ' + enable_lto.to_string() + '\n' output += ' Linker garbage collection: ' + enable_ld_gc.to_string() + '\n' -output += ' JSON validation for libnm: ' + enable_json_validation.to_string() + '\n' output += ' crypto: ' + crypto + '\n' output += ' sanitizers: ' + get_option('b_sanitize') + '\n' output += ' Mozilla Public Suffix List: ' + enable_libpsl.to_string() + '\n' diff --git a/meson_options.txt b/meson_options.txt index a5c6a22fb0..d6306711ec 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -69,6 +69,5 @@ option('valgrind', type: 'array', value: ['no'], description: 'Use valgrind to m option('valgrind_suppressions', type: 'string', value: '', description: 'Use specific valgrind suppression file') option('ld_gc', type: 'boolean', value: true, description: 'Enable garbage collection of unused symbols on linking') option('libpsl', type: 'boolean', value: true, description: 'Link against libpsl') -option('json_validation', type: 'boolean', value: true, description: 'Enable JSON validation in libnm') option('crypto', type: 'combo', choices: ['nss', 'gnutls'], value: 'nss', description: 'Cryptography library to use for certificate and key operations') option('qt', type: 'boolean', value: true, description: 'enable Qt examples') diff --git a/shared/nm-glib-aux/nm-jansson.h b/shared/nm-glib-aux/nm-jansson.h index 7c034222c4..9314b50c69 100644 --- a/shared/nm-glib-aux/nm-jansson.h +++ b/shared/nm-glib-aux/nm-jansson.h @@ -12,11 +12,6 @@ #include <jansson.h> -/* Added in Jansson v2.7 */ -#ifndef json_boolean_value -#define json_boolean_value json_is_true -#endif - /* Added in Jansson v2.8 */ #ifndef json_object_foreach_safe #define json_object_foreach_safe(object, n, key, value) \ @@ -30,106 +25,6 @@ NM_AUTO_DEFINE_FCN0 (json_t *, _nm_auto_decref_json, json_decref) #define nm_auto_decref_json nm_auto(_nm_auto_decref_json) -/*****************************************************************************/ - -static inline int -nm_jansson_json_as_bool (const json_t *elem, - bool *out_val) -{ - if (!elem) - return 0; - - if (!json_is_boolean (elem)) - return -EINVAL; - - NM_SET_OUT (out_val, json_boolean_value (elem)); - return 1; -} - -static inline int -nm_jansson_json_as_int32 (const json_t *elem, - gint32 *out_val) -{ - json_int_t v; - - if (!elem) - return 0; - - if (!json_is_integer (elem)) - return -EINVAL; - - v = json_integer_value (elem); - if ( v < (gint64) G_MININT32 - || v > (gint64) G_MAXINT32) - return -ERANGE; - - NM_SET_OUT (out_val, v); - return 1; -} - -static inline int -nm_jansson_json_as_int (const json_t *elem, - int *out_val) -{ - json_int_t v; - - if (!elem) - return 0; - - if (!json_is_integer (elem)) - return -EINVAL; - - v = json_integer_value (elem); - if ( v < (gint64) G_MININT - || v > (gint64) G_MAXINT) - return -ERANGE; - - NM_SET_OUT (out_val, v); - return 1; -} - -static inline int -nm_jansson_json_as_string (const json_t *elem, - const char **out_val) -{ - if (!elem) - return 0; - - if (!json_is_string (elem)) - return -EINVAL; - - NM_SET_OUT (out_val, json_string_value (elem)); - return 1; -} - -/*****************************************************************************/ - -#ifdef NM_VALUE_TYPE_DEFINE_FUNCTIONS -#include "nm-value-type.h" -static inline gboolean -nm_value_type_from_json (NMValueType value_type, - const json_t *elem, - gpointer out_val) -{ - switch (value_type) { - case NM_VALUE_TYPE_BOOL: return (nm_jansson_json_as_bool (elem, out_val) > 0); - case NM_VALUE_TYPE_INT32: return (nm_jansson_json_as_int32 (elem, out_val) > 0); - case NM_VALUE_TYPE_INT: return (nm_jansson_json_as_int (elem, out_val) > 0); - - /* warning: this overwrites/leaks the previous value. You better have *out_val - * point to uninitialized memory or NULL. */ - case NM_VALUE_TYPE_STRING: return (nm_jansson_json_as_string (elem, out_val) > 0); - - case NM_VALUE_TYPE_UNSPEC: - break; - } - nm_assert_not_reached (); - return FALSE; -} -#endif - -/*****************************************************************************/ - #endif /* WITH_JANSON */ #endif /* __NM_JANSSON_H__ */ diff --git a/shared/nm-glib-aux/nm-json-aux.c b/shared/nm-glib-aux/nm-json-aux.c index afa92531c6..e9816d7781 100644 --- a/shared/nm-glib-aux/nm-json-aux.c +++ b/shared/nm-glib-aux/nm-json-aux.c @@ -1,12 +1,14 @@ // SPDX-License-Identifier: LGPL-2.1+ /* - * Copyright (C) 2019 Red Hat, Inc. + * Copyright (C) 2017 - 2019 Red Hat, Inc. */ #include "nm-default.h" #include "nm-json-aux.h" +#include <dlfcn.h> + /*****************************************************************************/ static void @@ -96,9 +98,9 @@ _gstr_append_string_len (GString *gstr, } void -nm_json_aux_gstr_append_string_len (GString *gstr, - const char *str, - gsize n) +nm_json_gstr_append_string_len (GString *gstr, + const char *str, + gsize n) { g_return_if_fail (gstr); @@ -106,8 +108,8 @@ nm_json_aux_gstr_append_string_len (GString *gstr, } void -nm_json_aux_gstr_append_string (GString *gstr, - const char *str) +nm_json_gstr_append_string (GString *gstr, + const char *str) { g_return_if_fail (gstr); @@ -118,14 +120,14 @@ nm_json_aux_gstr_append_string (GString *gstr, } void -nm_json_aux_gstr_append_obj_name (GString *gstr, - const char *key, - char start_container) +nm_json_gstr_append_obj_name (GString *gstr, + const char *key, + char start_container) { g_return_if_fail (gstr); g_return_if_fail (key); - nm_json_aux_gstr_append_string (gstr, key); + nm_json_gstr_append_string (gstr, key); if (start_container != '\0') { nm_assert (NM_IN_SET (start_container, '[', '{')); @@ -133,3 +135,136 @@ nm_json_aux_gstr_append_obj_name (GString *gstr, } else g_string_append (gstr, ": "); } + +/*****************************************************************************/ + +typedef struct { + NMJsonVt vt; + void *dl_handle; +} NMJsonVtInternal; + +static NMJsonVtInternal * +_nm_json_vt_internal_load (void) +{ + NMJsonVtInternal *v; + const char *soname; + void *handle; + + v = g_new0 (NMJsonVtInternal, 1); + +#if WITH_JANSSON && defined (JANSSON_SONAME) + G_STATIC_ASSERT_EXPR (NM_STRLEN (JANSSON_SONAME) > 0); + nm_assert (strlen (JANSSON_SONAME) > 0); + soname = JANSSON_SONAME; +#elif !WITH_JANSSON && !defined (JANSSON_SONAME) + soname = NULL; +#else +#error "WITH_JANSON and JANSSON_SONAME are defined inconsistently." +#endif + + if (!soname) + return v; + + handle = dlopen (soname, RTLD_LAZY + | RTLD_LOCAL + | RTLD_NODELETE +#if !defined (ASAN_BUILD) + | RTLD_DEEPBIND +#endif + | 0); + if (!handle) + return v; + +#define TRY_BIND_SYMBOL(symbol) \ + G_STMT_START { \ + void *_sym = dlsym (handle, #symbol); \ + \ + if (!_sym) \ + goto fail_symbol; \ + v->vt.nm_ ## symbol = _sym; \ + } G_STMT_END + + TRY_BIND_SYMBOL (json_array); + TRY_BIND_SYMBOL (json_array_append_new); + TRY_BIND_SYMBOL (json_array_get); + TRY_BIND_SYMBOL (json_array_size); + TRY_BIND_SYMBOL (json_delete); + TRY_BIND_SYMBOL (json_dumps); + TRY_BIND_SYMBOL (json_false); + TRY_BIND_SYMBOL (json_integer); + TRY_BIND_SYMBOL (json_integer_value); + TRY_BIND_SYMBOL (json_loads); + TRY_BIND_SYMBOL (json_object); + TRY_BIND_SYMBOL (json_object_del); + TRY_BIND_SYMBOL (json_object_get); + TRY_BIND_SYMBOL (json_object_iter); + TRY_BIND_SYMBOL (json_object_iter_key); + TRY_BIND_SYMBOL (json_object_iter_next); + TRY_BIND_SYMBOL (json_object_iter_value); + TRY_BIND_SYMBOL (json_object_key_to_iter); + TRY_BIND_SYMBOL (json_object_set_new); + TRY_BIND_SYMBOL (json_object_size); + TRY_BIND_SYMBOL (json_string); + TRY_BIND_SYMBOL (json_string_value); + TRY_BIND_SYMBOL (json_true); + + v->vt.loaded = TRUE; + v->dl_handle = handle; + return v; + +fail_symbol: + dlclose (&handle); + *v = (NMJsonVtInternal) { }; + return v; +} + +const NMJsonVt *_nm_json_vt_ptr = NULL; + +const NMJsonVt * +_nm_json_vt_init (void) +{ + NMJsonVtInternal *v; + +again: + v = g_atomic_pointer_get ((gpointer *) &_nm_json_vt_ptr); + if (G_UNLIKELY (!v)) { + v = _nm_json_vt_internal_load (); + if (!g_atomic_pointer_compare_and_exchange ((gpointer *) &_nm_json_vt_ptr, NULL, v)) { + if (v->dl_handle) + dlclose (v->dl_handle); + g_free (v); + goto again; + } + + /* we transfer ownership. */ + } + + nm_assert (v && v == g_atomic_pointer_get ((gpointer *) &_nm_json_vt_ptr)); + return &v->vt; +} + +const NMJsonVt * +nmtst_json_vt_reset (gboolean loaded) +{ + NMJsonVtInternal *v_old; + NMJsonVtInternal *v; + + v_old = g_atomic_pointer_get ((gpointer *) &_nm_json_vt_ptr); + + if (!loaded) { + /* load a fake instance for testing. */ + v = g_new0 (NMJsonVtInternal, 1); + } else + v = _nm_json_vt_internal_load (); + + if (!g_atomic_pointer_compare_and_exchange ((gpointer *) &_nm_json_vt_ptr, v_old, v)) + g_assert_not_reached (); + + if (v_old) { + if (v_old->dl_handle) + dlclose (v_old->dl_handle); + g_free ((gpointer *) v_old); + } + + return v->vt.loaded ? &v->vt : NULL; +} diff --git a/shared/nm-glib-aux/nm-json-aux.h b/shared/nm-glib-aux/nm-json-aux.h index ed3be3768f..082b9e5205 100644 --- a/shared/nm-glib-aux/nm-json-aux.h +++ b/shared/nm-glib-aux/nm-json-aux.h @@ -1,49 +1,281 @@ // SPDX-License-Identifier: LGPL-2.1+ /* - * Copyright (C) 2019 Red Hat, Inc. + * Copyright (C) 2017 - 2019 Red Hat, Inc. */ #ifndef __NM_JSON_AUX_H__ #define __NM_JSON_AUX_H__ +#include "nm-value-type.h" + /*****************************************************************************/ static inline GString * -nm_json_aux_gstr_append_delimiter (GString *gstr) +nm_json_gstr_append_delimiter (GString *gstr) { g_string_append (gstr, ", "); return gstr; } -void nm_json_aux_gstr_append_string_len (GString *gstr, - const char *str, - gsize n); +void nm_json_gstr_append_string_len (GString *gstr, + const char *str, + gsize n); -void nm_json_aux_gstr_append_string (GString *gstr, - const char *str); +void nm_json_gstr_append_string (GString *gstr, + const char *str); static inline void -nm_json_aux_gstr_append_bool (GString *gstr, - gboolean v) +nm_json_gstr_append_bool (GString *gstr, + gboolean v) { g_string_append (gstr, v ? "true" : "false"); } static inline void -nm_json_aux_gstr_append_int64 (GString *gstr, - gint64 v) +nm_json_gstr_append_int64 (GString *gstr, + gint64 v) { g_string_append_printf (gstr, "%"G_GINT64_FORMAT, v); } -void nm_json_aux_gstr_append_obj_name (GString *gstr, - const char *key, - char start_container); +void nm_json_gstr_append_obj_name (GString *gstr, + const char *key, + char start_container); + +/*****************************************************************************/ + +#define NM_JSON_REJECT_DUPLICATES 0x1 + +typedef enum { + NM_JSON_OBJECT, + NM_JSON_ARRAY, + NM_JSON_STRING, + NM_JSON_INTEGER, + NM_JSON_REAL, + NM_JSON_TRUE, + NM_JSON_FALSE, + NM_JSON_NULL, +} nm_json_type; + +typedef struct nm_json_t { + nm_json_type type; + volatile size_t refcount; +} nm_json_t; + +typedef long long nm_json_int_t; + +#define NM_JSON_ERROR_TEXT_LENGTH 160 +#define NM_JSON_ERROR_SOURCE_LENGTH 80 + +typedef struct nm_json_error_t { + int line; + int column; + int position; + char source[NM_JSON_ERROR_SOURCE_LENGTH]; + char text[NM_JSON_ERROR_TEXT_LENGTH]; +} nm_json_error_t; + +typedef struct { + gboolean loaded; + char *(*nm_json_dumps) (const nm_json_t *json, size_t flags); + const char *(*nm_json_object_iter_key) (void *iter); + const char *(*nm_json_string_value) (const nm_json_t *json); + int (*nm_json_array_append_new) (nm_json_t *json, nm_json_t *value); + int (*nm_json_object_del) (nm_json_t *json, const char *key); + int (*nm_json_object_set_new) (nm_json_t *json, const char *key, nm_json_t *value); + nm_json_int_t (*nm_json_integer_value) (const nm_json_t *json); + nm_json_t *(*nm_json_array) (void); + nm_json_t *(*nm_json_array_get) (const nm_json_t *json, size_t index); + nm_json_t *(*nm_json_false) (void); + nm_json_t *(*nm_json_integer) (nm_json_int_t value); + nm_json_t *(*nm_json_loads) (const char *string, size_t flags, nm_json_error_t *error); + nm_json_t *(*nm_json_object) (void); + nm_json_t *(*nm_json_object_get) (const nm_json_t *json, const char *key); + nm_json_t *(*nm_json_object_iter_value) (void *); + nm_json_t *(*nm_json_string) (const char *value); + nm_json_t *(*nm_json_true) (void); + size_t (*nm_json_array_size) (const nm_json_t *json); + size_t (*nm_json_object_size) (const nm_json_t *json); + void (*nm_json_delete) (nm_json_t *json); + void *(*nm_json_object_iter) (nm_json_t *json); + void *(*nm_json_object_iter_next) (nm_json_t *json, void *iter); + void *(*nm_json_object_key_to_iter) (const char *key); +} NMJsonVt; + +extern const NMJsonVt *_nm_json_vt_ptr; + +const NMJsonVt *_nm_json_vt_init (void); + +static inline const NMJsonVt * +_nm_json_vt (void) +{ + const NMJsonVt *vt; + + vt = g_atomic_pointer_get ((gpointer *) &_nm_json_vt_ptr); + if (G_UNLIKELY (!vt)) { + vt = _nm_json_vt_init (); + nm_assert (vt); + } + return vt; +} + +static inline const NMJsonVt * +nm_json_vt (void) +{ + const NMJsonVt *vt; + + vt = _nm_json_vt(); + return vt->loaded ? vt : NULL; +} + +static inline const NMJsonVt * +nm_json_vt_assert (void) +{ + const NMJsonVt *vt; + + vt = _nm_json_vt(); + nm_assert (vt->loaded); + return vt; +} + +const NMJsonVt *nmtst_json_vt_reset (gboolean loaded); + +/*****************************************************************************/ + +#define nm_json_boolean(vt, val) \ + ((val) ? (vt)->nm_json_true () : (vt)->nm_json_false ()) + +static inline void +nm_json_decref (const NMJsonVt *vt, nm_json_t *json) +{ + /* Our ref-counting is not threadsafe, unlike libjansson's. But we never + * share one json_t instance between threads, and if we would, we would very likely + * wrap a mutex around it. */ + if ( json + && json->refcount != (size_t) -1 + && --json->refcount == 0) + vt->nm_json_delete (json); +} + +static inline void +_nm_auto_decref_json (nm_json_t **p_json) +{ + if ( *p_json + && (*p_json)->refcount != (size_t) -1 + && --(*p_json)->refcount == 0) + nm_json_vt ()->nm_json_delete (*p_json); +} + +#define nm_auto_decref_json nm_auto(_nm_auto_decref_json) + +/*****************************************************************************/ + +/* the following are implemented as pure macros in jansson.h. + * They can be used directly, however, add a nm_json* variant, + * to make it explict we don't accidentally use jansson ABI. */ + +#define nm_json_typeof(json) ((json)->type) +#define nm_json_is_object(json) ((json) && nm_json_typeof(json) == NM_JSON_OBJECT) +#define nm_json_is_array(json) ((json) && nm_json_typeof(json) == NM_JSON_ARRAY) +#define nm_json_is_string(json) ((json) && nm_json_typeof(json) == NM_JSON_STRING) +#define nm_json_is_integer(json) ((json) && nm_json_typeof(json) == NM_JSON_INTEGER) +#define nm_json_is_real(json) ((json) && nm_json_typeof(json) == NM_JSON_REAL) +#define nm_json_is_number(json) (nm_json_is_integer(json) || nm_json_is_real(json)) +#define nm_json_is_true(json) ((json) && nm_json_typeof(json) == NM_JSON_TRUE) +#define nm_json_is_false(json) ((json) && nm_json_typeof(json) == NM_JSON_FALSE) +#define nm_json_boolean_value nm_json_is_true +#define nm_json_is_boolean(json) (nm_json_is_true(json) || nm_json_is_false(json)) +#define nm_json_is_null(json) ((json) && nm_json_typeof(json) == NM_JSON_NULL) + +#define nm_json_array_foreach(vt, array, index, value) \ + for(index = 0; \ + index < vt->nm_json_array_size (array) && (value = vt->nm_json_array_get (array, index)); \ + index++) + +#define nm_json_object_foreach(vt, object, key, value) \ + for(key = vt->nm_json_object_iter_key (vt->nm_json_object_iter (object)); \ + key && (value = vt->nm_json_object_iter_value (vt->nm_json_object_key_to_iter (key))); \ + key = vt->nm_json_object_iter_key (vt->nm_json_object_iter_next (object, vt->nm_json_object_key_to_iter (key)))) + +/*****************************************************************************/ + +static inline int +nm_jansson_json_as_bool (const nm_json_t *elem, + bool *out_val) +{ + if (!elem) + return 0; + + if (!nm_json_is_boolean (elem)) + return -EINVAL; + + NM_SET_OUT (out_val, nm_json_boolean_value (elem)); + return 1; +} + +static inline int +nm_jansson_json_as_int32 (const NMJsonVt *vt, + const nm_json_t *elem, + gint32 *out_val) +{ + nm_json_int_t v; + + if (!elem) + return 0; + + if (!nm_json_is_integer (elem)) + return -EINVAL; + + v = vt->nm_json_integer_value (elem); + if ( v < (gint64) G_MININT32 + || v > (gint64) G_MAXINT32) + return -ERANGE; + + NM_SET_OUT (out_val, v); + return 1; +} + +static inline int +nm_jansson_json_as_int (const NMJsonVt *vt, + const nm_json_t *elem, + int *out_val) +{ + nm_json_int_t v; + + if (!elem) + return 0; + + if (!nm_json_is_integer (elem)) + return -EINVAL; + + v = vt->nm_json_integer_value (elem); + if ( v < (gint64) G_MININT + || v > (gint64) G_MAXINT) + return -ERANGE; + + NM_SET_OUT (out_val, v); + return 1; +} + +static inline int +nm_jansson_json_as_string (const NMJsonVt *vt, + const nm_json_t *elem, + const char **out_val) +{ + if (!elem) + return 0; + + if (!nm_json_is_string (elem)) + return -EINVAL; + + NM_SET_OUT (out_val, vt->nm_json_string_value (elem)); + return 1; +} /*****************************************************************************/ #ifdef NM_VALUE_TYPE_DEFINE_FUNCTIONS -#include "nm-value-type.h" + static inline void nm_value_type_to_json (NMValueType value_type, GString *gstr, @@ -53,17 +285,38 @@ nm_value_type_to_json (NMValueType value_type, nm_assert (gstr); switch (value_type) { - case NM_VALUE_TYPE_BOOL: nm_json_aux_gstr_append_bool (gstr, *((const bool *) p_field)); return; - case NM_VALUE_TYPE_INT32: nm_json_aux_gstr_append_int64 (gstr, *((const gint32 *) p_field)); return; - case NM_VALUE_TYPE_INT: nm_json_aux_gstr_append_int64 (gstr, *((const int *) p_field)); return; - case NM_VALUE_TYPE_STRING: nm_json_aux_gstr_append_string (gstr, *((const char *const *) p_field)); return; + case NM_VALUE_TYPE_BOOL: nm_json_gstr_append_bool (gstr, *((const bool *) p_field)); return; + case NM_VALUE_TYPE_INT32: nm_json_gstr_append_int64 (gstr, *((const gint32 *) p_field)); return; + case NM_VALUE_TYPE_INT: nm_json_gstr_append_int64 (gstr, *((const int *) p_field)); return; + case NM_VALUE_TYPE_STRING: nm_json_gstr_append_string (gstr, *((const char *const *) p_field)); return; case NM_VALUE_TYPE_UNSPEC: break; } nm_assert_not_reached (); } -#endif -/*****************************************************************************/ +static inline gboolean +nm_value_type_from_json (const NMJsonVt *vt, + NMValueType value_type, + const nm_json_t *elem, + gpointer out_val) +{ + switch (value_type) { + case NM_VALUE_TYPE_BOOL: return (nm_jansson_json_as_bool (elem, out_val) > 0); + case NM_VALUE_TYPE_INT32: return (nm_jansson_json_as_int32 (vt, elem, out_val) > 0); + case NM_VALUE_TYPE_INT: return (nm_jansson_json_as_int (vt, elem, out_val) > 0); + + /* warning: this overwrites/leaks the previous value. You better have *out_val + * point to uninitialized memory or NULL. */ + case NM_VALUE_TYPE_STRING: return (nm_jansson_json_as_string (vt, elem, out_val) > 0); + + case NM_VALUE_TYPE_UNSPEC: + break; + } + nm_assert_not_reached (); + return FALSE; +} + +#endif /* NM_VALUE_TYPE_DEFINE_FUNCTIONS */ -#endif /* __NM_JSON_AUX_H__ */ +#endif /* __NM_JSON_AUX_H__ */ diff --git a/shared/nm-glib-aux/tests/meson.build b/shared/nm-glib-aux/tests/meson.build index f6328db916..8136eff935 100644 --- a/shared/nm-glib-aux/tests/meson.build +++ b/shared/nm-glib-aux/tests/meson.build @@ -1,23 +1,43 @@ # SPDX-License-Identifier: LGPL-2.1+ -test_unit = 'test-shared-general' - -c_flags = [ - '-DNETWORKMANAGER_COMPILATION_TEST', - '-DNETWORKMANAGER_COMPILATION=(NM_NETWORKMANAGER_COMPILATION_GLIB|NM_NETWORKMANAGER_COMPILATION_WITH_GLIB_I18N_PROG)', -] - exe = executable( - test_unit, - test_unit + '.c', - c_args: c_flags, + 'test-shared-general', + 'test-shared-general.c', + c_args: [ + '-DNETWORKMANAGER_COMPILATION_TEST', + '-DNETWORKMANAGER_COMPILATION=(NM_NETWORKMANAGER_COMPILATION_GLIB|NM_NETWORKMANAGER_COMPILATION_WITH_GLIB_I18N_PROG)', + ], dependencies: libnm_utils_base_dep, link_with: libnm_systemd_logging_stub, ) test( - 'shared/nm-glib-aux/' + test_unit, + 'shared/nm-glib-aux/test-shared-general', test_script, args: test_args + [exe.full_path()], timeout: default_test_timeout, ) + +if jansson_dep.found() + exe = executable( + 'test-json-aux', + 'test-json-aux.c', + c_args: [ + '-DNETWORKMANAGER_COMPILATION_TEST', + '-DNETWORKMANAGER_COMPILATION=(NM_NETWORKMANAGER_COMPILATION_GLIB|NM_NETWORKMANAGER_COMPILATION_WITH_GLIB_I18N_PROG)', + ], + dependencies: [ + libnm_utils_base_dep, + jansson_dep, + dl_dep, + ], + link_with: libnm_systemd_logging_stub, + ) + + test( + 'shared/nm-glib-aux/test-json-aux', + test_script, + args: test_args + [exe.full_path()], + timeout: default_test_timeout, + ) +endif diff --git a/shared/nm-glib-aux/tests/test-json-aux.c b/shared/nm-glib-aux/tests/test-json-aux.c new file mode 100644 index 0000000000..cde1bef3b0 --- /dev/null +++ b/shared/nm-glib-aux/tests/test-json-aux.c @@ -0,0 +1,163 @@ +// SPDX-License-Identifier: LGPL-2.1+ + +#define NM_TEST_UTILS_NO_LIBNM 1 + +#include "nm-default.h" + +#include <jansson.h> + +#include "nm-glib-aux/nm-json-aux.h" + +#include "nm-utils/nm-test-utils.h" + +/*****************************************************************************/ + +static void +test_jansson (void) +{ + const NMJsonVt *vt; + nm_auto_decref_json nm_json_t *js1 = NULL; + nm_auto_decref_json nm_json_t *js2 = NULL; + +#define _ASSERT_FIELD(type1, type2, field) \ + G_STMT_START { \ + G_STATIC_ASSERT_EXPR (sizeof (((type1 *) NULL)->field) == sizeof (((type2 *) NULL)->field)); \ + G_STATIC_ASSERT_EXPR (G_STRUCT_OFFSET (type1, field) == G_STRUCT_OFFSET (type2, field)); \ + } G_STMT_END + + G_STATIC_ASSERT_EXPR (NM_JSON_REJECT_DUPLICATES == JSON_REJECT_DUPLICATES); + + G_STATIC_ASSERT_EXPR (sizeof (nm_json_type) == sizeof (json_type)); + + G_STATIC_ASSERT_EXPR ((int) NM_JSON_OBJECT == JSON_OBJECT); + G_STATIC_ASSERT_EXPR ((int) NM_JSON_ARRAY == JSON_ARRAY); + G_STATIC_ASSERT_EXPR ((int) NM_JSON_STRING == JSON_STRING); + G_STATIC_ASSERT_EXPR ((int) NM_JSON_INTEGER == JSON_INTEGER); + G_STATIC_ASSERT_EXPR ((int) NM_JSON_REAL == JSON_REAL); + G_STATIC_ASSERT_EXPR ((int) NM_JSON_TRUE == JSON_TRUE); + G_STATIC_ASSERT_EXPR ((int) NM_JSON_FALSE == JSON_FALSE); + G_STATIC_ASSERT_EXPR ((int) NM_JSON_NULL == JSON_NULL); + + G_STATIC_ASSERT_EXPR (sizeof (nm_json_int_t) == sizeof (json_int_t)); + + G_STATIC_ASSERT_EXPR (sizeof (nm_json_t) == sizeof (json_t)); + _ASSERT_FIELD (nm_json_t, json_t, refcount); + _ASSERT_FIELD (nm_json_t, json_t, type); + + G_STATIC_ASSERT_EXPR (NM_JSON_ERROR_TEXT_LENGTH == JSON_ERROR_TEXT_LENGTH); + G_STATIC_ASSERT_EXPR (NM_JSON_ERROR_SOURCE_LENGTH == JSON_ERROR_SOURCE_LENGTH); + + G_STATIC_ASSERT_EXPR (sizeof (nm_json_error_t) == sizeof (json_error_t)); + _ASSERT_FIELD (nm_json_error_t, json_error_t, line); + _ASSERT_FIELD (nm_json_error_t, json_error_t, column); + _ASSERT_FIELD (nm_json_error_t, json_error_t, position); + _ASSERT_FIELD (nm_json_error_t, json_error_t, source); + _ASSERT_FIELD (nm_json_error_t, json_error_t, text); + + vt = nm_json_vt (); + + g_assert (vt); + g_assert (vt->loaded); + + js1 = vt->nm_json_loads ("{ \"a\": 5 }", 0, NULL); + g_assert (js1); + nm_json_decref (vt, g_steal_pointer (&js1)); + + js2 = vt->nm_json_loads ("{ \"a\": 6 }", 0, NULL); + g_assert (js2); + +#define CHECK_FCN(vt, fcn, nm_type, js_type) \ + G_STMT_START { \ + const NMJsonVt *const _vt = (vt); \ + _nm_unused nm_type = (_vt->nm_##fcn); \ + _nm_unused js_type = (fcn); \ + \ + g_assert (_vt->nm_##fcn); \ + g_assert (_f_nm); \ + g_assert (_f_js); \ + g_assert (_f_nm == _vt->nm_##fcn); \ + } G_STMT_END + + CHECK_FCN (vt, json_array, + nm_json_t *(*_f_nm) (void), + json_t *(*_f_js) (void)); + CHECK_FCN (vt, json_array_append_new, + int (*_f_nm) (nm_json_t *, nm_json_t *), + int (*_f_js) ( json_t *, json_t *)); + CHECK_FCN (vt, json_array_get, + nm_json_t *(*_f_nm) (const nm_json_t *, gsize ), + json_t *(*_f_js) (const json_t *, size_t)); + CHECK_FCN (vt, json_array_size, + gsize (*_f_nm) (const nm_json_t *), + size_t (*_f_js) (const json_t *)); + CHECK_FCN (vt, json_delete, + void (*_f_nm) (nm_json_t *), + void (*_f_js) ( json_t *)); + CHECK_FCN (vt, json_dumps, + char *(*_f_nm) (const nm_json_t *, gsize ), + char *(*_f_js) (const json_t *, size_t)); + CHECK_FCN (vt, json_false, + nm_json_t *(*_f_nm) (void), + json_t *(*_f_js) (void)); + CHECK_FCN (vt, json_integer, + nm_json_t *(*_f_nm) (nm_json_int_t), + json_t *(*_f_js) ( json_int_t)); + CHECK_FCN (vt, json_integer_value, + nm_json_int_t (*_f_nm) (const nm_json_t *), + json_int_t (*_f_js) (const json_t *)); + CHECK_FCN (vt, json_loads, + nm_json_t *(*_f_nm) (const char *, gsize , nm_json_error_t *), + json_t *(*_f_js) (const char *, size_t, json_error_t *)); + CHECK_FCN (vt, json_object, + nm_json_t *(*_f_nm) (void), + json_t *(*_f_js) (void)); + CHECK_FCN (vt, json_object_del, + int (*_f_nm) (nm_json_t *, const char *), + int (*_f_js) ( json_t *, const char *)); + CHECK_FCN (vt, json_object_get, + nm_json_t *(*_f_nm) (const nm_json_t *, const char *), + json_t *(*_f_js) (const json_t *, const char *)); + CHECK_FCN (vt, json_object_iter, + void *(*_f_nm) (nm_json_t *), + void *(*_f_js) ( json_t *)); + CHECK_FCN (vt, json_object_iter_key, + const char *(*_f_nm) (void *), + const char *(*_f_js) (void *)); + CHECK_FCN (vt, json_object_iter_next, + void *(*_f_nm) (nm_json_t *, void *), + void *(*_f_js) ( json_t *, void *)); + CHECK_FCN (vt, json_object_iter_value, + nm_json_t *(*_f_nm) (void *), + json_t *(*_f_js) (void *)); + CHECK_FCN (vt, json_object_key_to_iter, + void *(*_f_nm) (const char *), + void *(*_f_js) (const char *)); + CHECK_FCN (vt, json_object_set_new, + int (*_f_nm) (nm_json_t *, const char *, nm_json_t *), + int (*_f_js) ( json_t *, const char *, json_t *)); + CHECK_FCN (vt, json_object_size, + gsize (*_f_nm) (const nm_json_t *), + size_t (*_f_js) (const json_t *)); + CHECK_FCN (vt, json_string, + nm_json_t *(*_f_nm) (const char *), + json_t *(*_f_js) (const char *)); + CHECK_FCN (vt, json_string_value, + const char *(*_f_nm) (const nm_json_t *), + const char *(*_f_js) (const json_t *)); + CHECK_FCN (vt, json_true, + nm_json_t *(*_f_nm) (void), + json_t *(*_f_js) (void)); +} + +/*****************************************************************************/ + +NMTST_DEFINE (); + +int main (int argc, char **argv) +{ + nmtst_init (&argc, &argv, TRUE); + + g_test_add_func ("/general/test_jansson", test_jansson); + + return g_test_run (); +} diff --git a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c index 934c4901f9..935ea9fdf8 100644 --- a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c +++ b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c @@ -15,6 +15,7 @@ #include <sys/types.h> #include <sys/stat.h> +#include "nm-glib-aux/nm-json-aux.h" #include "nm-utils.h" #include "nm-setting-connection.h" #include "nm-setting-wired.h" @@ -9129,7 +9130,7 @@ test_read_team_master_invalid (gconstpointer user_data) gs_free_error GError *error = NULL; gs_unref_object NMConnection *connection = NULL; - if (WITH_JSON_VALIDATION) { + if (nm_json_vt ()) { _connection_from_file_fail (PATH_NAME, NULL, TYPE_ETHERNET, &error); g_assert_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY); |