diff options
| author | Thomas Haller <thaller@redhat.com> | 2019-03-25 10:15:08 +0100 |
|---|---|---|
| committer | Thomas Haller <thaller@redhat.com> | 2019-03-25 10:15:08 +0100 |
| commit | f224d6a8537dd58fafc8b7ba977ec7fffe8c31e9 (patch) | |
| tree | af24ac8141818d4adcb27e67a437e8f26ca2d685 | |
| parent | c7864fc1b226de0e2699fd1b33b6dd8e6cb3b343 (diff) | |
| parent | 8b0461380febd98cb6b8b867104653325bcddac4 (diff) | |
| download | NetworkManager-f224d6a8537dd58fafc8b7ba977ec7fffe8c31e9.tar.gz | |
nmcli: merge branch 'th/nmcli-list-options'
https://github.com/NetworkManager/NetworkManager/pull/317
28 files changed, 2248 insertions, 2685 deletions
diff --git a/Makefile.am b/Makefile.am index 21c43884b7..a8353656da 100644 --- a/Makefile.am +++ b/Makefile.am @@ -669,6 +669,7 @@ libnm_core_lib_h_pub_mkenums = \ libnm-core/nm-core-enum-types.h libnm_core_lib_h_priv = \ shared/nm-ethtool-utils.h \ + shared/nm-libnm-core-utils.h \ shared/nm-meta-setting.h \ libnm-core/nm-crypto.h \ libnm-core/nm-crypto-impl.h \ @@ -731,6 +732,7 @@ libnm_core_lib_c_settings_real = \ libnm_core_lib_c_real = \ $(libnm_core_lib_c_settings_real) \ shared/nm-ethtool-utils.c \ + shared/nm-libnm-core-utils.c \ shared/nm-meta-setting.c \ libnm-core/nm-crypto.c \ libnm-core/nm-connection.c \ @@ -3914,6 +3916,8 @@ clients_common_libnmc_la_SOURCES = \ \ shared/nm-ethtool-utils.c \ shared/nm-ethtool-utils.h \ + shared/nm-libnm-core-utils.c \ + shared/nm-libnm-core-utils.h \ \ clients/common/nm-meta-setting-desc.c \ clients/common/nm-meta-setting-desc.h \ diff --git a/clients/cli/connections.c b/clients/cli/connections.c index 6db44f8760..c8a6b37bfa 100644 --- a/clients/cli/connections.c +++ b/clients/cli/connections.c @@ -3959,11 +3959,12 @@ set_property (NMClient *client, char modifier, GError **error) { - gs_free char *property_name = NULL, *value_free = NULL; + gs_free char *property_name = NULL; + gs_free_error GError *local = NULL; NMSetting *setting; - GError *local = NULL; - g_assert (setting_name && setting_name[0]); + nm_assert (setting_name && setting_name[0]); + nm_assert (NM_IN_SET (modifier, '\0', '+', '-')); setting = nm_connection_get_setting_by_name (connection, setting_name); if (!setting) { @@ -3977,48 +3978,26 @@ set_property (NMClient *client, g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT, _("Error: invalid property '%s': %s."), property, local->message); - g_clear_error (&local); return FALSE; } - if (modifier != '-') { - /* Set/add value */ - if (modifier != '+') { - /* We allow the existing property value to be passed as parameter, - * so make a copy if we are going to free it. - */ - value = value_free = g_strdup (value); - nmc_setting_reset_property (setting, property_name, NULL); - } - if (!nmc_setting_set_property (client, setting, property_name, value, &local)) { - g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT, - _("Error: failed to modify %s.%s: %s."), - setting_name, property, local->message); - g_clear_error (&local); - return FALSE; - } - } else { - /* Remove value - * - either empty: remove whole value - * - or specified by index <0-n>: remove item at the index - * - or option name: remove item with the option name - */ - if (value) { - unsigned long idx; - - if (nmc_string_to_uint (value, TRUE, 0, G_MAXUINT32, &idx)) - nmc_setting_remove_property_option (setting, property_name, NULL, idx, &local); - else - nmc_setting_remove_property_option (setting, property_name, value, 0, &local); - if (local) { - g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT, - _("Error: failed to remove a value from %s.%s: %s."), - setting_name, property, local->message); - g_clear_error (&local); - return FALSE; - } - } else - nmc_setting_reset_property (setting, property_name, NULL); + if (!nmc_setting_set_property (client, + setting, + property_name, + ( (modifier == '-' && !value) + ? '\0' + : modifier), + value, + &local)) { + g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT, + _("Error: failed to %s %s.%s: %s."), + ( modifier != '-' + ? "modify" + : "remove a value from"), + setting_name, + property, + local->message); + return FALSE; } /* Don't ask for this property in interactive mode. */ @@ -6904,7 +6883,6 @@ property_edit_submenu (NmCli *nmc, gs_free char *cmd_property_user = NULL; gs_free char *cmd_property_arg = NULL; gs_free char *prop_val_user = NULL; - nm_auto_unset_gvalue GValue prop_g_value = G_VALUE_INIT; gboolean removed; gboolean dirty; @@ -6954,24 +6932,17 @@ property_edit_submenu (NmCli *nmc, } else prop_val_user = g_strdup (cmd_property_arg); - /* nmc_setting_set_property() only adds new value, thus we have to - * remove the original value and save it for error cases. - */ - if (cmdsub == NMC_EDITOR_SUB_CMD_SET) { - nmc_property_get_gvalue (curr_setting, prop_name, &prop_g_value); - nmc_property_set_default_value (curr_setting, prop_name); - } - - set_result = nmc_setting_set_property (nmc->client, curr_setting, prop_name, prop_val_user, &tmp_err); + set_result = nmc_setting_set_property (nmc->client, + curr_setting, + prop_name, + (cmdsub == NMC_EDITOR_SUB_CMD_SET) + ? '\0' + : '+', + prop_val_user, + &tmp_err); if (!set_result) { g_print (_("Error: failed to set '%s' property: %s\n"), prop_name, tmp_err->message); g_clear_error (&tmp_err); - if (cmdsub == NMC_EDITOR_SUB_CMD_SET) { - /* Block change signals and restore original value */ - g_signal_handlers_block_matched (curr_setting, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, NULL); - nmc_property_set_gvalue (curr_setting, prop_name, &prop_g_value); - g_signal_handlers_unblock_matched (curr_setting, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, NULL); - } } break; @@ -6982,41 +6953,23 @@ property_edit_submenu (NmCli *nmc, _("Edit '%s' value: "), prop_name); - nmc_property_get_gvalue (curr_setting, prop_name, &prop_g_value); - nmc_property_set_default_value (curr_setting, prop_name); - - if (!nmc_setting_set_property (nmc->client, curr_setting, prop_name, prop_val_user, &tmp_err)) { + if (!nmc_setting_set_property (nmc->client, curr_setting, prop_name, '\0', prop_val_user, &tmp_err)) { g_print (_("Error: failed to set '%s' property: %s\n"), prop_name, tmp_err->message); g_clear_error (&tmp_err); - g_signal_handlers_block_matched (curr_setting, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, NULL); - nmc_property_set_gvalue (curr_setting, prop_name, &prop_g_value); - g_signal_handlers_unblock_matched (curr_setting, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, NULL); } break; case NMC_EDITOR_SUB_CMD_REMOVE: - if (cmd_property_arg) { - unsigned long val_int = G_MAXUINT32; - gs_free char *option = NULL; - - if (!nmc_string_to_uint (cmd_property_arg, TRUE, 0, G_MAXUINT32, &val_int)) { - option = g_strdup (cmd_property_arg); - g_strstrip (option); - } - - if (!nmc_setting_remove_property_option (curr_setting, prop_name, - option, - (guint32) val_int, - &tmp_err)) { - g_print (_("Error: %s\n"), tmp_err->message); - g_clear_error (&tmp_err); - } - } else { - if (!nmc_setting_reset_property (curr_setting, prop_name, &tmp_err)) { - g_print (_("Error: failed to remove value of '%s': %s\n"), prop_name, - tmp_err->message); - g_clear_error (&tmp_err); - } + if (!nmc_setting_set_property (nmc->client, + curr_setting, + prop_name, + ( cmd_property_arg + ? '-' + : '\0'), + cmd_property_arg, + &tmp_err)) { + g_print (_("Error: %s\n"), tmp_err->message); + g_clear_error (&tmp_err); } break; @@ -7367,8 +7320,7 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t _("Enter '%s' value: "), prop_name); - /* Set property value */ - if (!nmc_setting_set_property (nmc->client, menu_ctx.curr_setting, prop_name, prop_val_user, &tmp_err)) { + if (!nmc_setting_set_property (nmc->client, menu_ctx.curr_setting, prop_name, '+', prop_val_user, &tmp_err)) { g_print (_("Error: failed to set '%s' property: %s\n"), prop_name, tmp_err->message); g_clear_error (&tmp_err); } @@ -7428,8 +7380,13 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t prop_name); } - /* Set property value */ - if (!nmc_setting_set_property (nmc->client, ss, prop_name, cmd_arg_v, &tmp_err)) { + /* setting a value in edit mode "appends". That seems unexpected behavior. */ + if (!nmc_setting_set_property (nmc->client, + ss, + prop_name, + cmd_arg_v ? '+' : '\0', + cmd_arg_v, + &tmp_err)) { g_print (_("Error: failed to set '%s' property: %s\n"), prop_name, tmp_err->message); g_clear_error (&tmp_err); @@ -7526,8 +7483,7 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t if (!prop_name) break; - /* Delete property value */ - if (!nmc_setting_reset_property (menu_ctx.curr_setting, prop_name, &tmp_err)) { + if (!nmc_setting_set_property (nmc->client, menu_ctx.curr_setting, prop_name, '\0', NULL, &tmp_err)) { g_print (_("Error: failed to remove value of '%s': %s\n"), prop_name, tmp_err->message); g_clear_error (&tmp_err); @@ -7577,8 +7533,7 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t prop_name = is_property_valid (ss, cmd_arg_p, &tmp_err); if (prop_name) { - /* Delete property value */ - if (!nmc_setting_reset_property (ss, prop_name, &tmp_err)) { + if (!nmc_setting_set_property (nmc->client, ss, prop_name, '\0', NULL, &tmp_err)) { g_print (_("Error: failed to remove value of '%s': %s\n"), prop_name, tmp_err->message); g_clear_error (&tmp_err); @@ -8148,6 +8103,9 @@ editor_init_existing_connection (NMConnection *connection) NMSettingWireless *s_wireless; NMSettingConnection *s_con; + /* FIXME: this approach of connecting handlers to do something is fundamentally + * flawed. See the comment in nmc_setting_ip6_connect_handlers(). */ + s_ip4 = nm_connection_get_setting_ip4_config (connection); s_ip6 = nm_connection_get_setting_ip6_config (connection); s_proxy = nm_connection_get_setting_proxy (connection); diff --git a/clients/cli/settings.c b/clients/cli/settings.c index a04c8eb604..aa0a7ff23c 100644 --- a/clients/cli/settings.c +++ b/clients/cli/settings.c @@ -89,7 +89,7 @@ ipv4_addresses_changed_cb (GObject *object, GParamSpec *pspec, gpointer user_dat static void ipv4_method_changed_cb (GObject *object, GParamSpec *pspec, gpointer user_data) { - static GValue value = G_VALUE_INIT; + static GPtrArray *old_value = NULL; static gboolean answered = FALSE; static gboolean answer = FALSE; @@ -103,17 +103,17 @@ ipv4_method_changed_cb (GObject *object, GParamSpec *pspec, gpointer user_data) answer = get_answer ("ipv4.addresses", NULL); } if (answer) { - if (G_IS_VALUE (&value)) - g_value_unset (&value); - nmc_property_get_gvalue (NM_SETTING (object), NM_SETTING_IP_CONFIG_ADDRESSES, &value); + nm_clear_pointer (&old_value, g_ptr_array_unref); + g_object_get (object, NM_SETTING_IP_CONFIG_ADDRESSES, &old_value, NULL); g_object_set (object, NM_SETTING_IP_CONFIG_ADDRESSES, NULL, NULL); } } } else { answered = FALSE; - if (G_IS_VALUE (&value)) { - nmc_property_set_gvalue (NM_SETTING (object), NM_SETTING_IP_CONFIG_ADDRESSES, &value); - g_value_unset (&value); + if (old_value) { + gs_unref_ptrarray GPtrArray *v = g_steal_pointer (&old_value); + + g_object_set (object, NM_SETTING_IP_CONFIG_ADDRESSES, v, NULL); } } @@ -142,6 +142,25 @@ ipv6_addresses_changed_cb (GObject *object, GParamSpec *pspec, gpointer user_dat } } else { answered = FALSE; + /* FIXME: editor_init_existing_connection() and registering handlers is not the + * right approach. + * + * This only happens to work because in nmcli's edit mode + * tends to append addresses -- instead of setting them. + * If we would change that (to behavior I'd expect), we'd get: + * + * nmcli> set ipv6.addresses fc01::1:5/68 + * Do you also want to set 'ipv6.method' to 'manual'? [yes]: y + * nmcli> set ipv6.addresses fc01::1:6/68 + * Do you also want to set 'ipv6.method' to 'manual'? [yes]: + * + * That's because nmc_setting_set_property() calls set_fcn(). With modifier '\0' + * (set), it would first clear all addresses before adding the address. Thereby + * emitting multiple property changed signals. + * + * That can be avoided by freezing/thawing the signals, but this solution + * here is ugly in general. + */ if (!g_strcmp0 (nm_setting_ip_config_get_method (NM_SETTING_IP_CONFIG (object)), NM_SETTING_IP6_CONFIG_METHOD_MANUAL)) g_object_set (object, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_AUTO, NULL); } @@ -152,7 +171,7 @@ ipv6_addresses_changed_cb (GObject *object, GParamSpec *pspec, gpointer user_dat static void ipv6_method_changed_cb (GObject *object, GParamSpec *pspec, gpointer user_data) { - static GValue value = G_VALUE_INIT; + static GPtrArray *old_value = NULL; static gboolean answered = FALSE; static gboolean answer = FALSE; @@ -166,17 +185,17 @@ ipv6_method_changed_cb (GObject *object, GParamSpec *pspec, gpointer user_data) answer = get_answer ("ipv6.addresses", NULL); } if (answer) { - if (G_IS_VALUE (&value)) - g_value_unset (&value); - nmc_property_get_gvalue (NM_SETTING (object), NM_SETTING_IP_CONFIG_ADDRESSES, &value); + nm_clear_pointer (&old_value, g_ptr_array_unref); + g_object_get (object, NM_SETTING_IP_CONFIG_ADDRESSES, &old_value, NULL); g_object_set (object, NM_SETTING_IP_CONFIG_ADDRESSES, NULL, NULL); } } } else { answered = FALSE; - if (G_IS_VALUE (&value)) { - nmc_property_set_gvalue (NM_SETTING (object), NM_SETTING_IP_CONFIG_ADDRESSES, &value); - g_value_unset (&value); + if (old_value) { + gs_unref_ptrarray GPtrArray *v = g_steal_pointer (&old_value); + + g_object_set (object, NM_SETTING_IP_CONFIG_ADDRESSES, v, NULL); } } @@ -509,152 +528,68 @@ nmc_setting_get_property_parsable (NMSetting *setting, const char *prop, GError return get_property_val (setting, prop, NM_META_ACCESSOR_GET_TYPE_PARSABLE, TRUE, error); } -static gboolean -_set_fcn_call (const NMMetaPropertyInfo *property_info, - NMSetting *setting, - const char *value, - GError **error) -{ - return property_info->property_type->set_fcn (property_info, - nmc_meta_environment, - nmc_meta_environment_arg, - setting, - value, - error); -} - -/* - * Generic function for setting property value. - * - * Sets property=value in setting by calling specialized functions. - * If value is NULL then default property value is set. - * - * Returns: TRUE on success; FALSE on failure and sets error - */ gboolean -nmc_setting_set_property (NMClient *client, NMSetting *setting, const char *prop, const char *value, GError **error) +nmc_setting_set_property (NMClient *client, + NMSetting *setting, + const char *prop, + char modifier, + const char *value, + GError **error) { const NMMetaPropertyInfo *property_info; + gs_free char *value_to_free = NULL; + gboolean success; g_return_val_if_fail (NM_IS_SETTING (setting), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - - if ((property_info = nm_meta_property_info_find_by_setting (setting, prop))) { - - if (!value) { - /* No value argument sets default value */ - nmc_property_set_default_value (setting, prop); - return TRUE; - } - - if (property_info->property_type->set_fcn) { - switch (property_info->setting_info->general->meta_type) { - case NM_META_SETTING_TYPE_CONNECTION: - if (nm_streq (property_info->property_name, NM_SETTING_CONNECTION_SECONDARIES)) { - gs_free char *value_coerced = NULL; - - if (!_set_fcn_precheck_connection_secondaries (client, value, &value_coerced, error)) - return FALSE; - - return _set_fcn_call (property_info, - setting, - value_coerced ?: value, - error); - } - break; - default: - break; - } - return _set_fcn_call (property_info, - setting, - value, - error); - } - } - - g_set_error_literal (error, 1, 0, _("the property can't be changed")); - return FALSE; -} - -void -nmc_property_set_default_value (NMSetting *setting, const char *prop) -{ - GValue value = G_VALUE_INIT; - GParamSpec *param_spec; - - param_spec = g_object_class_find_property (G_OBJECT_GET_CLASS (G_OBJECT (setting)), prop); - if (param_spec) { - g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (param_spec)); - g_param_value_set_default (param_spec, &value); - g_object_set_property (G_OBJECT (setting), prop, &value); + g_return_val_if_fail (NM_IN_SET (modifier, '\0', '-', '+'), FALSE); + g_return_val_if_fail (value || modifier == '\0', FALSE); + + if (!(property_info = nm_meta_property_info_find_by_setting (setting, prop))) + goto out_fail_read_only; + if (!property_info->property_type->set_fcn) + goto out_fail_read_only; + + if ( modifier == '-' + && !property_info->property_type->set_supports_remove) { + /* The property is a plain property. It does not support '-'. + * + * Maybe we should fail, but just return silently. */ + return TRUE; } -} - -/* - * Generic function for resetting (single value) properties. - * - * The function resets the property value to the default one. It respects - * nmcli restrictions for changing properties. So if 'set_func' is NULL, - * resetting the value is denied. - * - * Returns: TRUE on success; FALSE on failure and sets error - */ -gboolean -nmc_setting_reset_property (NMSetting *setting, const char *prop, GError **error) -{ - const NMMetaPropertyInfo *property_info; - g_return_val_if_fail (NM_IS_SETTING (setting), FALSE); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - - if ((property_info = nm_meta_property_info_find_by_setting (setting, prop))) { - if (property_info->property_type->set_fcn) { - nmc_property_set_default_value (setting, prop); - return TRUE; + if (value) { + switch (property_info->setting_info->general->meta_type) { + case NM_META_SETTING_TYPE_CONNECTION: + if (nm_streq (property_info->property_name, NM_SETTING_CONNECTION_SECONDARIES)) { + if (!_set_fcn_precheck_connection_secondaries (client, value, &value_to_free, error)) + return FALSE; + if (value_to_free) + value = value_to_free; + } + break; + default: + break; } } - g_set_error_literal (error, 1, 0, _("the property can't be changed")); + g_object_freeze_notify (G_OBJECT (setting)); + success = property_info->property_type->set_fcn (property_info, + nmc_meta_environment, + nmc_meta_environment_arg, + setting, + modifier, + value, + error); + g_object_thaw_notify (G_OBJECT (setting)); + return success; + +out_fail_read_only: + nm_utils_error_set (error, NM_UTILS_ERROR_UNKNOWN, _("the property can't be changed")); return FALSE; } /* - * Generic function for removing items for collection-type properties. - * - * If 'option' is not NULL, it tries to remove it, otherwise 'idx' is used. - * For single-value properties (not having specialized remove function) this - * function does nothing and just returns TRUE. - * - * Returns: TRUE on success; FALSE on failure and sets error - */ -gboolean -nmc_setting_remove_property_option (NMSetting *setting, - const char *prop, - const char *option, - guint32 idx, - GError **error) -{ - const NMMetaPropertyInfo *property_info; - - g_return_val_if_fail (NM_IS_SETTING (setting), FALSE); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - - if ((property_info = nm_meta_property_info_find_by_setting (setting, prop))) { - if (property_info->property_type->remove_fcn) { - return property_info->property_type->remove_fcn (property_info, - nmc_meta_environment, - nmc_meta_environment_arg, - setting, - option, - idx, - error); - } - } - - return TRUE; -} - -/* * Get valid property names for a setting. * * Returns: string array with the properties or NULL on failure. @@ -749,41 +684,6 @@ nmc_setting_get_property_desc (NMSetting *setting, const char *prop) nmcli_desc ?: ""); } -/* - * Gets setting:prop property value and returns it in 'value'. - * Caller is responsible for freeing the GValue resources using g_value_unset() - */ -gboolean -nmc_property_get_gvalue (NMSetting *setting, const char *prop, GValue *value) -{ - GParamSpec *param_spec; - - param_spec = g_object_class_find_property (G_OBJECT_GET_CLASS (G_OBJECT (setting)), prop); - if (param_spec) { - memset (value, 0, sizeof (GValue)); - g_value_init (value, G_PARAM_SPEC_VALUE_TYPE (param_spec)); - g_object_get_property (G_OBJECT (setting), prop, value); - return TRUE; - } - return FALSE; -} - -/* - * Sets setting:prop property value from 'value'. - */ -gboolean -nmc_property_set_gvalue (NMSetting *setting, const char *prop, GValue *value) -{ - GParamSpec *param_spec; - - param_spec = g_object_class_find_property (G_OBJECT_GET_CLASS (G_OBJECT (setting)), prop); - if (param_spec && G_VALUE_TYPE (value) == G_PARAM_SPEC_VALUE_TYPE (param_spec)) { - g_object_set_property (G_OBJECT (setting), prop, value); - return TRUE; - } - return FALSE; -} - /*****************************************************************************/ gboolean diff --git a/clients/cli/settings.h b/clients/cli/settings.h index 4e7e38df85..1ff936859c 100644 --- a/clients/cli/settings.h +++ b/clients/cli/settings.h @@ -45,20 +45,9 @@ char *nmc_setting_get_property_parsable (NMSetting *setting, gboolean nmc_setting_set_property (NMClient *client, NMSetting *setting, const char *prop, + char modifier, const char *val, GError **error); -gboolean nmc_setting_reset_property (NMSetting *setting, - const char *prop, - GError **error); -gboolean nmc_setting_remove_property_option (NMSetting *setting, - const char *prop, - const char *option, - guint32 idx, - GError **error); -void nmc_property_set_default_value (NMSetting *setting, const char *prop); - -gboolean nmc_property_get_gvalue (NMSetting *setting, const char *prop, GValue *value); -gboolean nmc_property_set_gvalue (NMSetting *setting, const char *prop, GValue *value); gboolean setting_details (const NmcConfig *nmc_config, NMSetting *setting, const char *one_prop); diff --git a/clients/common/meson.build b/clients/common/meson.build index b4b6bcacd3..c137d4463e 100644 --- a/clients/common/meson.build +++ b/clients/common/meson.build @@ -55,7 +55,7 @@ libnmc = static_library( sources: files( 'nm-meta-setting-access.c', 'nm-meta-setting-desc.c', - ) + shared_nm_meta_setting_c + shared_nm_ethtool_utils_c + [settings_docs_source], + ) + shared_nm_meta_setting_c + shared_nm_ethtool_utils_c + shared_nm_libnm_core_utils_c + [settings_docs_source], dependencies: deps, c_args: cflags, link_with: libnmc_base, diff --git a/clients/common/nm-client-utils.c b/clients/common/nm-client-utils.c index 1241131a11..0a155dae40 100644 --- a/clients/common/nm-client-utils.c +++ b/clients/common/nm-client-utils.c @@ -82,6 +82,10 @@ nmc_string_to_uint_base (const char *str, char *end; unsigned long int tmp; + if (!str || !str[0]) + return FALSE; + + /* FIXME: don't use this function, replace by _nm_utils_ascii_str_to_int64() */ errno = 0; tmp = strtoul (str, &end, base); if (errno || *end != '\0' || (range_check && (tmp < min || tmp > max))) { diff --git a/clients/common/nm-client-utils.h b/clients/common/nm-client-utils.h index a5bc05fab0..fd726ee93c 100644 --- a/clients/common/nm-client-utils.h +++ b/clients/common/nm-client-utils.h @@ -23,13 +23,7 @@ #include "nm-meta-setting.h" #include "nm-active-connection.h" #include "nm-device.h" - - -#define nm_auto_unref_ip_address nm_auto (_nm_ip_address_unref) -NM_AUTO_DEFINE_FCN0 (NMIPAddress *, _nm_ip_address_unref, nm_ip_address_unref) - -#define nm_auto_unref_wgpeer nm_auto (_nm_auto_unref_wgpeer) -NM_AUTO_DEFINE_FCN0 (NMWireGuardPeer *, _nm_auto_unref_wgpeer, nm_wireguard_peer_unref) +#include "nm-libnm-core-utils.h" const NMObject **nmc_objects_sort_by_path (const NMObject *const*objs, gssize len); diff --git a/clients/common/nm-meta-setting-desc.c b/clients/common/nm-meta-setting-desc.c index 6e35228ad6..0529420118 100644 --- a/clients/common/nm-meta-setting-desc.c +++ b/clients/common/nm-meta-setting-desc.c @@ -26,6 +26,8 @@ #include "nm-common-macros.h" #include "nm-utils/nm-enum-utils.h" +#include "nm-utils/nm-secret-utils.h" +#include "nm-libnm-core-utils.h" #include "nm-vpn-helpers.h" #include "nm-client-utils.h" @@ -74,6 +76,168 @@ _gtype_property_get_gtype (GType gtype, const char *property_name) /*****************************************************************************/ +static int +_int64_cmp_desc (gconstpointer a, + gconstpointer b, + gpointer user_data) +{ + NM_CMP_DIRECT (*((const gint64 *) b), *((const gint64 *) a)); + return 0; +} + +static gint64 * +_value_str_as_index_list (const char *value, gsize *out_len) +{ + gs_free char *str_clone_free = NULL; + gboolean str_cloned = FALSE; + char *str; + gsize i, j; + gsize n_alloc; + gsize len; + gs_free gint64 *arr = NULL; + + *out_len = 0; + + if (!value) + return NULL; + + str = (char *) value; + n_alloc = 0; + len = 0; + while (TRUE) { + gint64 i64; + const char *s; + gsize good; + + good = strcspn (str, ","NM_ASCII_SPACES); + if (good == 0) { + if (str[0] == '\0') + break; + str++; + continue; + } + if (str[good] == '\0') { + s = str; + str += good; + } else { + if (!str_cloned) { + str_cloned = TRUE; + str = nm_strndup_a (200, str, strlen (str), &str_clone_free); + } + s = str; + str[good] = '\0'; + str += good + 1; + } + + i64 = _nm_utils_ascii_str_to_int64 (s, 10, 0, G_MAXINT64, -1); + if (i64 == -1) + return NULL; + + if (len >= n_alloc) { + if (n_alloc > 0) { + n_alloc = n_alloc * 2; + arr = g_realloc (arr, n_alloc * sizeof (gint64)); + } else { + n_alloc = 4; + arr = g_new (gint64, n_alloc); + } + } + arr[len++] = i64; + } + + if (len > 1) { + /* sort the list of indexes descendingly, and drop duplicates. */ + g_qsort_with_data (arr, + len, + sizeof (gint64), + _int64_cmp_desc, + NULL); + j = 1; + for (i = 1; i < len; i++) { + nm_assert (arr[i - 1] >= arr[i]); + if (arr[i - 1] > arr[i]) + arr[j++] = arr[i]; + } + len = j; + } + + *out_len = len; + return g_steal_pointer (&arr); +} + +#define MULTILIST_WITH_ESCAPE_CHARS NM_ASCII_SPACES"," + +typedef enum { + VALUE_STRSPLIT_MODE_STRIPPED, + VALUE_STRSPLIT_MODE_OBJLIST, + VALUE_STRSPLIT_MODE_MULTILIST, + VALUE_STRSPLIT_MODE_MULTILIST_WITH_ESCAPE, +} ValueStrsplitMode; + +static const char * +_value_strescape (const char *str, char **out_to_free) +{ + return _nm_utils_escape_plain (str, MULTILIST_WITH_ESCAPE_CHARS, out_to_free); +} + +static const char ** +_value_strsplit (const char *value, + ValueStrsplitMode split_mode, + gsize *out_len) +{ + gs_free const char **strv = NULL; + gsize i; + gsize len; + + /* FIXME: some modes should support backslash escaping. + * In particular, to distingish from _value_str_as_index_list(), which + * does not accept '\\'. */ + + /* note that all modes remove empty tokens (",", "a,,b", ",,"). */ + switch (split_mode) { + case VALUE_STRSPLIT_MODE_STRIPPED: + strv = nm_utils_strsplit_set (value, NM_ASCII_SPACES",", FALSE); + break; + case VALUE_STRSPLIT_MODE_OBJLIST: + strv = nm_utils_strsplit_set (value, ",", FALSE); + break; + case VALUE_STRSPLIT_MODE_MULTILIST: + strv = nm_utils_strsplit_set (value, " \t,", FALSE); + break; + case VALUE_STRSPLIT_MODE_MULTILIST_WITH_ESCAPE: + strv = nm_utils_strsplit_set (value, MULTILIST_WITH_ESCAPE_CHARS, TRUE); + break; + default: + nm_assert_not_reached (); + break; + } + + NM_SET_OUT (out_len, 0); + + if (!strv) + return NULL; + + len = 0; + for (i = 0; strv[i]; i++) { + const char *s = strv[i]; + + s = nm_str_skip_leading_spaces (s); + if (s[0] == '\0') + continue; + + if (split_mode == VALUE_STRSPLIT_MODE_MULTILIST_WITH_ESCAPE) + _nm_utils_unescape_plain ((char *) s, MULTILIST_WITH_ESCAPE_CHARS, TRUE); + else + g_strchomp ((char *) s); + + strv[len++] = s; + } + strv[len] = NULL; + + NM_SET_OUT (out_len, len); + return g_steal_pointer (&strv); +} + static NMIPAddress * _parse_ip_address (int family, const char *address, GError **error) { @@ -123,19 +287,19 @@ _parse_ip_route (int family, gint64 metric = -1; guint i; gs_free const char **routev = NULL; - gs_free char *str_clean = NULL; + gs_free char *str_clean_free = NULL; + const char *str_clean; gs_free char *dest_clone = NULL; const char *dest; const char *plen; gs_unref_hashtable GHashTable *attrs = NULL; - GHashTable *tmp_attrs; #define ROUTE_SYNTAX _("The valid syntax is: 'ip[/prefix] [next-hop] [metric] [attribute=val]... [,ip[/prefix] ...]'") nm_assert (NM_IN_SET (family, AF_INET, AF_INET6)); nm_assert (str); nm_assert (!error || !*error); - str_clean = g_strstrip (g_strdup (str)); + str_clean = nm_strstrip_avoid_copy (str, &str_clean_free); routev = nm_utils_strsplit_set (str_clean, " \t", FALSE); if (!routev) { g_set_error (error, 1, 0, @@ -182,6 +346,7 @@ _parse_ip_route (int family, GHashTableIter iter; char *iter_key; GVariant *iter_value; + gs_unref_hashtable GHashTable *tmp_attrs = NULL; tmp_attrs = nm_utils_parse_variant_attributes (routev[i], ' ', '=', FALSE, nm_ip_route_get_variant_attribute_spec(), @@ -207,13 +372,11 @@ _parse_ip_route (int family, if (!nm_ip_route_attribute_validate (iter_key, iter_value, family, NULL, error)) { g_prefix_error (error, "%s: ", iter_key); - g_hash_table_unref (tmp_attrs); return NULL; } g_hash_table_insert (attrs, iter_key, iter_value); g_hash_table_iter_steal (&iter); } - g_hash_table_unref (tmp_attrs); } else { g_set_error (error, 1, 0, "%s", ROUTE_SYNTAX); return NULL; @@ -298,7 +461,8 @@ _parse_team_link_watcher (const char *str, GError **error) { gs_free const char **watcherv = NULL; - gs_free char *str_clean = NULL; + gs_free char *str_clean_free = NULL; + const char *str_clean; guint i; gs_free const char *name = NULL; int val1 = 0, val2 = 0, val3 = 3, val4 = -1; @@ -309,7 +473,7 @@ _parse_team_link_watcher (const char *str, nm_assert (str); nm_assert (!error || !*error); - str_clean = g_strstrip (g_strdup (str)); + str_clean = nm_strstrip_avoid_copy (str, &str_clean_free); watcherv = nm_utils_strsplit_set (str_clean, " \t", FALSE); if (!watcherv) { g_set_error (error, 1, 0, "'%s' is not valid", str); @@ -398,62 +562,6 @@ _parse_team_link_watcher (const char *str, #define MAX_8021P_PRIO 7 /* Max 802.1p priority */ /* - * Parse VLAN priority mappings from the following format: 2:1,3:4,7:3 - * and verify if the priority numbers are valid - * - * Return: string array with split maps, or NULL on error - * Caller is responsible for freeing the array. - */ -static char ** -_parse_vlan_priority_maps (const char *priority_map, - NMVlanPriorityMap map_type, - GError **error) -{ - char **mapping = NULL, **iter; - unsigned long from, to, from_max, to_max; - - g_return_val_if_fail (priority_map != NULL, NULL); - g_return_val_if_fail (error == NULL || *error == NULL, NULL); - - if (map_type == NM_VLAN_INGRESS_MAP) { - from_max = MAX_8021P_PRIO; - to_max = MAX_SKB_PRIO; - } else { - from_max = MAX_SKB_PRIO; - to_max = MAX_8021P_PRIO; - } - - mapping = g_strsplit (priority_map, ",", 0); - for (iter = mapping; iter && *iter; iter++) { - char *left, *right; - - left = g_strstrip (*iter); - right = strchr (left, ':'); - if (!right) { - g_set_error (error, 1, 0, _("invalid priority map '%s'"), *iter); - g_strfreev (mapping); - return NULL; - } - *right++ = '\0'; - - if (!nmc_string_to_uint (left, TRUE, 0, from_max, &from)) { - g_set_error (error, 1, 0, _("priority '%s' is not valid (<0-%ld>)"), - left, from_max); - g_strfreev (mapping); - return NULL; - } - if (!nmc_string_to_uint (right, TRUE, 0, to_max, &to)) { - g_set_error (error, 1, 0, _("priority '%s' is not valid (<0-%ld>)"), - right, to_max); - g_strfreev (mapping); - return NULL; - } - *(right-1) = ':'; /* Put back ':' */ - } - return mapping; -} - -/* * nmc_proxy_check_script: * @script: file name with PAC script, or raw PAC Script data * @out_script: raw PAC Script (with removed new-line characters) @@ -646,10 +754,10 @@ _env_warn_fcn (const NMMetaEnvironment *environment, const NMMetaPropertyInfo *property_info, const NMMetaEnvironment *environment, gpointer environment_user_data, NMSetting *setting, NMMetaAccessorGetType get_type, NMMetaAccessorGetFlags get_flags, NMMetaAccessorGetOutFlags *out_flags, gboolean *out_is_default, gpointer *out_to_free #define ARGS_SET_FCN \ - const NMMetaPropertyInfo *property_info, const NMMetaEnvironment *environment, gpointer environment_user_data, NMSetting *setting, const char *value, GError **error + const NMMetaPropertyInfo *property_info, const NMMetaEnvironment *environment, gpointer environment_user_data, NMSetting *setting, char modifier, const char *value, GError **error #define ARGS_REMOVE_FCN \ - const NMMetaPropertyInfo *property_info, const NMMetaEnvironment *environment, gpointer environment_user_data, NMSetting *setting, const char *value, guint32 idx, GError **error + const NMMetaPropertyInfo *property_info, const NMMetaEnvironment *environment, gpointer environment_user_data, NMSetting *setting, const char *value, GError **error #define ARGS_COMPLETE_FCN \ const NMMetaPropertyInfo *property_info, const NMMetaEnvironment *environment, gpointer environment_user_data, const NMMetaOperationContext *operation_context, const char *text, char ***out_to_free @@ -660,6 +768,46 @@ _env_warn_fcn (const NMMetaEnvironment *environment, #define ARGS_SETTING_INIT_FCN \ const NMMetaSettingInfoEditor *setting_info, NMSetting *setting, NMMetaAccessorSettingInitType init_type +static gboolean +_SET_FCN_DO_RESET_DEFAULT (const NMMetaPropertyInfo *property_info, char modifier, const char *value) +{ + nm_assert (property_info); + nm_assert (!property_info->property_type->set_supports_remove); + nm_assert (NM_IN_SET (modifier, '\0', '+')); + nm_assert (value || modifier == '\0'); + + return value == NULL; +} + +static gboolean +_SET_FCN_DO_RESET_DEFAULT_WITH_SUPPORTS_REMOVE (const NMMetaPropertyInfo *property_info, char modifier, const char *value) +{ + nm_assert (property_info); + nm_assert (property_info->property_type->set_supports_remove); + nm_assert (NM_IN_SET (modifier, '\0', '+', '-')); + nm_assert (value || modifier == '\0'); + + return value == NULL; +} + +static gboolean +_SET_FCN_DO_SET_ALL (char modifier, const char *value) +{ + nm_assert (NM_IN_SET (modifier, '\0', '+', '-')); + nm_assert (value); + + return modifier == '\0'; +} + +static gboolean +_SET_FCN_DO_REMOVE (char modifier, const char *value) +{ + nm_assert (NM_IN_SET (modifier, '\0', '+', '-')); + nm_assert (value); + + return modifier == '-'; +} + #define RETURN_UNSUPPORTED_GET_TYPE() \ G_STMT_START { \ if (!NM_IN_SET (get_type, \ @@ -677,7 +825,7 @@ _env_warn_fcn (const NMMetaEnvironment *environment, } G_STMT_END static gboolean -property_is_default (NMSetting *setting, const char *prop_name) +_gobject_property_is_default (NMSetting *setting, const char *prop_name) { nm_auto_unset_gvalue GValue v = G_VALUE_INIT; GParamSpec *pspec; @@ -703,32 +851,30 @@ property_is_default (NMSetting *setting, const char *prop_name) return g_param_value_defaults (pspec, &v); } -static gconstpointer -_get_fcn_nmc_with_default (ARGS_GET_FCN) +static gboolean +_gobject_property_reset (NMSetting *setting, + const char *prop_name, + gboolean reset_default) { - const char *s; - char *s_full; - GValue val = G_VALUE_INIT; - - RETURN_UNSUPPORTED_GET_TYPE (); - NM_SET_OUT (out_is_default, property_is_default (setting, property_info->property_name)); + nm_auto_unset_gvalue GValue v = G_VALUE_INIT; + GParamSpec *pspec; - if (property_info->property_typ_data->subtype.get_with_default.fcn (setting)) { - if (get_type == NM_META_ACCESSOR_GET_TYPE_PRETTY) - return _("(default)"); - return ""; - } + pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (G_OBJECT (setting)), + prop_name); + if (!G_IS_PARAM_SPEC (pspec)) + g_return_val_if_reached (FALSE); - g_value_init (&val, G_TYPE_STRING); - g_object_get_property (G_OBJECT (setting), property_info->property_name, &val); - s = g_value_get_string (&val); - if (get_type == NM_META_ACCESSOR_GET_TYPE_PRETTY) - s_full = s ? g_strdup_printf ("\"%s\"", s) : g_strdup (""); - else - s_full = g_strdup (s && *s ? s : " "); - g_value_unset (&val); + g_value_init (&v, pspec->value_type); + if (reset_default) + g_param_value_defaults (pspec, &v); + g_object_set_property (G_OBJECT (setting), prop_name, &v); + return TRUE; +} - RETURN_STR_TO_FREE (s_full); +static gboolean +_gobject_property_reset_default (NMSetting *setting, const char *prop_name) +{ + return _gobject_property_reset (setting, prop_name, TRUE); } static gconstpointer @@ -738,13 +884,20 @@ _get_fcn_gobject_impl (const NMMetaPropertyInfo *property_info, gboolean *out_is_default, gpointer *out_to_free) { - char *s; - const char *s_c; + const char *cstr; GType gtype_prop; nm_auto_unset_gvalue GValue val = G_VALUE_INIT; RETURN_UNSUPPORTED_GET_TYPE (); - NM_SET_OUT (out_is_default, property_is_default (setting, property_info->property_name)); + NM_SET_OUT (out_is_default, _gobject_property_is_default (setting, property_info->property_name)); + + if ( property_info->property_typ_data + && property_info->property_typ_data->is_default_fcn + && property_info->property_typ_data->is_default_fcn (setting)) { + if (get_type == NM_META_ACCESSOR_GET_TYPE_PRETTY) + return _("(default)"); + return ""; + } gtype_prop = _gobject_property_get_gtype (G_OBJECT (setting), property_info->property_name); @@ -755,15 +908,35 @@ _get_fcn_gobject_impl (const NMMetaPropertyInfo *property_info, g_object_get_property (G_OBJECT (setting), property_info->property_name, &val); b = g_value_get_boolean (&val); if (get_type == NM_META_ACCESSOR_GET_TYPE_PRETTY) - s_c = b ? _("yes") : _("no"); + cstr = b ? _("yes") : _("no"); else - s_c = b ? "yes" : "no"; - return s_c; + cstr = b ? "yes" : "no"; + return cstr; } else { + char *str; + + /* Note that we register certain transform functions in nmc_value_transforms_register(). + * This makes G_TYPE_STRV working. + * + * FIXME: that is particularly ugly because it's non-obvious which code relies + * on nmc_value_transforms_register(). Also, nmc_value_transforms_register() is + * in clients/cli, while we are here in clients/common. */ g_value_init (&val, G_TYPE_STRING); g_object_get_property (G_OBJECT (setting), property_info->property_name, &val); - s = g_value_dup_string (&val); - RETURN_STR_TO_FREE (s); + cstr = g_value_get_string (&val); + + if ( property_info->property_typ_data + && property_info->property_typ_data->is_default_fcn) { + if (get_type == NM_META_ACCESSOR_GET_TYPE_PRETTY) { + str = cstr + ? g_strdup_printf ("\"%s\"", cstr) + : g_strdup (""); + } else + str = g_strdup (cstr && cstr[0] ? cstr : " "); + } else + str = cstr ? g_strdup (cstr) : NULL; + + RETURN_STR_TO_FREE (str); } } @@ -842,10 +1015,9 @@ _get_fcn_gobject_int (ARGS_GET_FCN) for (; value_infos->nick; value_infos++) { if ( ( is_uint64 && value_infos->value.u64 == v.u64) || (!is_uint64 && value_infos->value.i64 == v.i64)) { - char *old_str = return_str; + gs_free char *old_str = return_str; return_str = g_strdup_printf ("%s (%s)", old_str, value_infos->nick); - g_free (old_str); break; } } @@ -1033,6 +1205,9 @@ _set_fcn_gobject_string (ARGS_SET_FCN) { gs_free char *to_free = NULL; + if (_SET_FCN_DO_RESET_DEFAULT (property_info, modifier, value)) + return _gobject_property_reset_default (setting, property_info->property_name); + if (property_info->property_typ_data) { if (property_info->property_typ_data->subtype.gobject_string.validate_fcn) { value = property_info->property_typ_data->subtype.gobject_string.validate_fcn (value, &to_free, error); @@ -1055,6 +1230,9 @@ _set_fcn_gobject_bool (ARGS_SET_FCN) { gboolean val_bool; + if (_SET_FCN_DO_RESET_DEFAULT (property_info, modifier, value)) + return _gobject_property_reset_default (setting, property_info->property_name); + if (!nmc_string_to_bool (value, &val_bool, error)) return FALSE; @@ -1076,6 +1254,9 @@ _set_fcn_gobject_int (ARGS_SET_FCN) guint base = 10; const NMMetaUtilsIntValueInfo *value_infos; + if (_SET_FCN_DO_RESET_DEFAULT (property_info, modifier, value)) + return _gobject_property_reset_default (setting, property_info->property_name); + pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (G_OBJECT (setting)), property_info->property_name); if (!G_IS_PARAM_SPEC (pspec)) g_return_val_if_reached (FALSE); @@ -1085,14 +1266,10 @@ _set_fcn_gobject_int (ARGS_SET_FCN) if (property_info->property_typ_data) { if ( value && (value_infos = property_info->property_typ_data->subtype.gobject_int.value_infos)) { - gs_free char *vv_stripped = NULL; - const char *vv = nm_str_skip_leading_spaces (value); - - if (vv[0] && g_ascii_isspace (vv[strlen (vv) - 1])) { - vv_stripped = g_strstrip (g_strdup (vv)); - vv = vv_stripped; - } + gs_free char *vv_free = NULL; + const char *vv; + vv = nm_strstrip_avoid_copy (value, &vv_free); for (; value_infos->nick; value_infos++) { if (nm_streq (value_infos->nick, vv)) { v = value_infos->value; @@ -1216,7 +1393,10 @@ _set_fcn_gobject_mtu (ARGS_SET_FCN) const GParamSpec *pspec; gint64 v; - if (nm_streq0 (value, "auto")) + if (_SET_FCN_DO_RESET_DEFAULT (property_info, modifier, value)) + return _gobject_property_reset_default (setting, property_info->property_name); + + if (nm_streq (value, "auto")) value = "0"; pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (G_OBJECT (setting)), @@ -1254,6 +1434,9 @@ _set_fcn_gobject_mac (ARGS_SET_FCN) NMMetaPropertyTypeMacMode mode; gboolean valid; + if (_SET_FCN_DO_RESET_DEFAULT (property_info, modifier, value)) + return _gobject_property_reset_default (setting, property_info->property_name); + if (property_info->property_typ_data) mode = property_info->property_typ_data->subtype.mac.mode; else @@ -1289,6 +1472,9 @@ _set_fcn_gobject_enum (ARGS_SET_FCN) gboolean is_flags; int v; + if (_SET_FCN_DO_RESET_DEFAULT (property_info, modifier, value)) + return _gobject_property_reset_default (setting, property_info->property_name); + if (property_info->property_typ_data) { if (property_info->property_typ_data->subtype.gobject_enum.get_gtype) { gtype = property_info->property_typ_data->subtype.gobject_enum.get_gtype (); @@ -1619,166 +1805,202 @@ vpn_data_item (const char *key, const char *value, gpointer user_data) g_string_append_printf (ret_str, "%s = %s", key, value); } -#define DEFINE_SETTER_STR_LIST_MULTI(def_func, s_macro, set_func) \ - static gboolean \ - def_func (NMSetting *setting, \ - const char *prop, \ - const char *value, \ - const char **valid_strv, \ - GError **error) \ - { \ - gs_free const char **strv = NULL; \ - gsize i; \ - const char *item; \ - nm_assert (!error || !*error); \ - strv = nm_utils_strsplit_set (value, " \t,", FALSE); \ - if (strv) { \ - for (i = 0; strv[i]; i++) { \ - if (!(item = nmc_string_is_valid (strv[i], valid_strv, error))) { \ - return FALSE; \ - } \ - set_func (s_macro (setting), item); \ - } \ - } \ - return TRUE; \ +static const char * +_multilist_do_validate (const NMMetaPropertyInfo *property_info, + NMSetting *setting, + const char *item, + GError **error) +{ + if (property_info->property_typ_data->values_static) { + nm_assert (!property_info->property_typ_data->subtype.multilist.validate_fcn); + return nmc_string_is_valid (item, + (const char **) property_info->property_typ_data->values_static, + error); + } + if (property_info->property_typ_data->subtype.multilist.validate_fcn) { + return property_info->property_typ_data->subtype.multilist.validate_fcn (item, + error); + } + if (property_info->property_typ_data->subtype.multilist.validate2_fcn) { + return property_info->property_typ_data->subtype.multilist.validate2_fcn (setting, + item, + error); } -#define DEFINE_SETTER_OPTIONS(def_func, s_macro, s_type, add_func, valid_func1, valid_func2) \ - static gboolean \ - def_func (ARGS_SET_FCN) \ - { \ - gs_free const char **strv = NULL; \ - const char **iter; \ - const char **(*valid_func1_p) (s_type *) = valid_func1; \ - const char * (*valid_func2_p) (const char *, const char *, GError **) = valid_func2; \ - const char *opt_name, *opt_val; \ - \ - nm_assert (!error || !*error); \ - \ - strv = nm_utils_strsplit_set (value, ",", FALSE); \ - for (iter = strv; iter && *iter; iter++) { \ - gs_free char *left_clone = g_strstrip (g_strdup (*iter)); \ - char *left = left_clone; \ - char *right = strchr (left, '='); \ - if (!right) { \ - g_set_error (error, 1, 0, _("'%s' is not valid; use <option>=<value>"), *iter); \ - return FALSE; \ - } \ - *right++ = '\0'; \ - g_strchomp (left); \ - \ - if (valid_func1_p) { \ - const char **valid_options = valid_func1_p (s_macro (setting)); \ - if (!(opt_name = nmc_string_is_valid (left, valid_options, error))) { \ - return FALSE; \ - } \ - } else \ - opt_name = left;\ - \ - opt_val = g_strchug (right); \ - if (valid_func2_p) { \ - if (!(opt_val = valid_func2_p ((const char *) left, (const char *) opt_val, error))) { \ - return FALSE; \ - }\ - }\ - add_func (s_macro (setting), opt_name, opt_val); \ - } \ - return TRUE; \ + return item; +} + +static gboolean +_set_fcn_multilist (ARGS_SET_FCN) +{ + gs_free const char **strv = NULL; + gsize i, j, nstrv; + + if (_SET_FCN_DO_RESET_DEFAULT_WITH_SUPPORTS_REMOVE (property_info, modifier, value)) { + if (property_info->property_typ_data->subtype.multilist.clear_all_fcn) { + property_info->property_typ_data->subtype.multilist.clear_all_fcn (setting); + return TRUE; + } + return _gobject_property_reset (setting, property_info->property_name, FALSE); + } + + if ( _SET_FCN_DO_REMOVE (modifier, value) + && ( property_info->property_typ_data->subtype.multilist.remove_by_idx_fcn_u32 + || property_info->property_typ_data->subtype.multilist.remove_by_idx_fcn_s + || property_info->property_typ_data->subtype.multilist.remove_by_idx_fcn_u)) { + gs_free gint64 *indexes = NULL; + + indexes = _value_str_as_index_list (value, &nstrv); + if (indexes) { + gint64 num; + + if (property_info->property_typ_data->subtype.multilist.get_num_fcn_u32) + num = property_info->property_typ_data->subtype.multilist.get_num_fcn_u32 (setting); + else + num = property_info->property_typ_data->subtype.multilist.get_num_fcn_u (setting); + for (i = 0; i < nstrv; i++) { + gint64 idx = indexes[i]; + + if (idx >= num) + continue; + + if (property_info->property_typ_data->subtype.multilist.remove_by_idx_fcn_u32) + property_info->property_typ_data->subtype.multilist.remove_by_idx_fcn_u32 (setting, idx); + else if (property_info->property_typ_data->subtype.multilist.remove_by_idx_fcn_s) + property_info->property_typ_data->subtype.multilist.remove_by_idx_fcn_s (setting, idx); + else + property_info->property_typ_data->subtype.multilist.remove_by_idx_fcn_u (setting, idx); + } + return TRUE; + } } -#define DEFINE_REMOVER_INDEX_OR_VALUE(def_func, s_macro, num_func, rem_func_idx, rem_func_val) \ - static gboolean \ - def_func (ARGS_REMOVE_FCN) \ - { \ - guint32 num; \ - if (value) { \ - gboolean ret; \ - char *value_stripped = g_strstrip (g_strdup (value)); \ - ret = rem_func_val (s_macro (setting), value_stripped, error); \ - g_free (value_stripped); \ - return ret; \ - } \ - num = num_func (s_macro (setting)); \ - if (num == 0) { \ - g_set_error_literal (error, 1, 0, _("no item to remove")); \ - return FALSE; \ - } \ - if (idx >= num) { \ - g_set_error (error, 1, 0, _("index '%d' is not in range <0-%d>"), idx, num - 1); \ - return FALSE; \ - } \ - rem_func_idx (s_macro (setting), idx); \ - return TRUE; \ + strv = _value_strsplit (value, + property_info->property_typ_data->subtype.multilist.with_escaped_spaces + ? VALUE_STRSPLIT_MODE_MULTILIST_WITH_ESCAPE + : VALUE_STRSPLIT_MODE_MULTILIST, + &nstrv); + + j = 0; + for (i = 0; i < nstrv; i++) { + const char *item = strv[i]; + + item = _multilist_do_validate (property_info, + setting, + item, + error); + if (!item) + return FALSE; + strv[j++] = item; } + nstrv = j; -#define DEFINE_REMOVER_OPTION(def_func, s_macro, rem_func) \ - static gboolean \ - def_func (ARGS_REMOVE_FCN) \ - { \ - gboolean success = FALSE; \ - if (value && *value) { \ - success = rem_func (s_macro (setting), value); \ - if (!success) \ - g_set_error (error, 1, 0, _("invalid option '%s'"), value); \ - } else \ - g_set_error_literal (error, 1, 0, _("missing option")); \ - return success; \ - } - -#define DEFINE_ALLOWED_VAL_FUNC(def_func, valid_values) \ - static const char *const* \ - def_func (NMSetting *setting, const char *prop) \ - { \ - return valid_values; \ + if (_SET_FCN_DO_SET_ALL (modifier, value)) { + if (property_info->property_typ_data->subtype.multilist.clear_all_fcn) + property_info->property_typ_data->subtype.multilist.clear_all_fcn (setting); + else + _gobject_property_reset (setting, property_info->property_name, FALSE); } -#define DEFINE_SETTER_MAC_BLACKLIST(def_func, s_macro, add_func) \ - static gboolean \ - def_func (ARGS_SET_FCN) \ - { \ - guint8 buf[32]; \ - gs_free const char **strv = NULL; \ - const char *const*iter; \ - \ - nm_assert (!error || !*error); \ - \ - strv = nm_utils_strsplit_set (value, " \t,", FALSE); \ - for (iter = strv; strv && *iter; iter++) { \ - if (!nm_utils_hwaddr_aton (*iter, buf, ETH_ALEN)) { \ - g_set_error (error, 1, 0, _("'%s' is not a valid MAC"), *iter); \ - return FALSE; \ - } \ - } \ - \ - for (iter = strv; strv && *iter; iter++) \ - add_func (s_macro (setting), *iter); \ - \ - return TRUE; \ + for (i = 0; i < nstrv; i++) { + if (_SET_FCN_DO_REMOVE (modifier, value)) { + property_info->property_typ_data->subtype.multilist.remove_by_value_fcn (setting, + strv[i]); + } else { + if (property_info->property_typ_data->subtype.multilist.add2_fcn) + property_info->property_typ_data->subtype.multilist.add2_fcn (setting, strv[i]); + else + property_info->property_typ_data->subtype.multilist.add_fcn (setting, strv[i]); + } } + return TRUE; +} static gboolean -verify_string_list (const char *const*strv, - const char *prop, - gboolean (*validate_func) (const char *), - GError **error) +_set_fcn_optionlist (ARGS_SET_FCN) { - const char *const*iter; + gs_free const char **strv = NULL; + gs_free const char **strv_val = NULL; + gsize i, nstrv; nm_assert (!error || !*error); + if (_SET_FCN_DO_RESET_DEFAULT_WITH_SUPPORTS_REMOVE (property_info, modifier, value)) + return _gobject_property_reset_default (setting, property_info->property_name); + + nstrv = 0; + strv = nm_utils_strsplit_set (value, ",", FALSE); if (strv) { - for (iter = strv; *iter; iter++) { - if (**iter == '\0') - continue; - if (validate_func) { - if (!validate_func (*iter)) { - g_set_error (error, 1, 0, _("'%s' is not valid"), - *iter); + strv_val = g_new (const char *, NM_PTRARRAY_LEN (strv)); + for (i = 0; strv[i]; i++) { + const char *opt_name; + const char *opt_value; + + opt_name = nm_str_skip_leading_spaces (strv[i]); + + /* FIXME: support backslash escaping for the option list. */ + opt_value = strchr (opt_name, '='); + if (opt_value) { + ((char *) opt_value)[0] = '\0'; + opt_value++; + opt_value = nm_str_skip_leading_spaces (opt_value); + g_strchomp ((char *) opt_value); + } + g_strchomp ((char *) opt_name); + + if ( property_info->property_type->values_fcn + || property_info->property_typ_data->values_static) { + gs_strfreev char **valid_options_to_free = NULL; + const char *const*valid_options; + + if (property_info->property_type->values_fcn) + valid_options = property_info->property_type->values_fcn (property_info, &valid_options_to_free); + else + valid_options = property_info->property_typ_data->values_static; + + opt_name = nmc_string_is_valid (opt_name, (const char **) valid_options, error); + if (!opt_name) + return FALSE; + } + + if (opt_value) { + if (_SET_FCN_DO_REMOVE (modifier, value)) + opt_value = NULL; + } else { + if (!_SET_FCN_DO_REMOVE (modifier, value)) { + nm_utils_error_set (error, NM_UTILS_ERROR_INVALID_ARGUMENT, + _("'%s' is not valid; use <option>=<value>"), + opt_name); return FALSE; } } + + if ( opt_value + && opt_value[0] == '\0' + && property_info->property_typ_data->subtype.optionlist.no_empty_value) { + nm_utils_error_set (error, NM_UTILS_ERROR_INVALID_ARGUMENT, + _("cannot set empty \"%s\" option"), + opt_name); + return FALSE; + } + + strv[nstrv] = opt_name; + strv_val[nstrv] = opt_value; + nstrv++; } } + + if (_SET_FCN_DO_SET_ALL (modifier, value)) + _gobject_property_reset (setting, property_info->property_name, FALSE); + + for (i = 0; i < nstrv; i++) { + if (!property_info->property_typ_data->subtype.optionlist.set_fcn (setting, + strv[i], + strv_val[i], + error)) + return FALSE; + } + return TRUE; } @@ -1811,11 +2033,13 @@ validate_flags (NMSetting *setting, const char* prop, guint val, GError **error) if (g_param_value_validate (pspec, &value)) { GParamSpecFlags *pspec_flags = (GParamSpecFlags *) pspec; - char *flag_values = flag_values_to_string (pspec_flags->flags_class->values, - pspec_flags->flags_class->n_values); + gs_free char *flag_values = NULL; + + flag_values = flag_values_to_string (pspec_flags->flags_class->values, + pspec_flags->flags_class->n_values); + g_set_error (error, 1, 0, _("'%u' flags are not valid; use combination of %s"), val, flag_values); - g_free (flag_values); success = FALSE; } g_value_unset (&value); @@ -1823,30 +2047,12 @@ validate_flags (NMSetting *setting, const char* prop, guint val, GError **error) } static gboolean -check_and_set_string (NMSetting *setting, - const char *prop, - const char *val, - const char **valid_strv, - GError **error) -{ - const char *checked_val; - - nm_assert (!error || !*error); - - checked_val = nmc_string_is_valid (val, valid_strv, error); - if (!checked_val) - return FALSE; - - g_object_set (setting, prop, checked_val, NULL); - return TRUE; -} - -static gboolean _set_fcn_gobject_flags (ARGS_SET_FCN) { unsigned long val_int; - nm_assert (!error || !*error); + if (_SET_FCN_DO_RESET_DEFAULT (property_info, modifier, value)) + return _gobject_property_reset_default (setting, property_info->property_name); if (!nmc_string_to_uint (value, TRUE, 0, G_MAXUINT, &val_int)) { g_set_error (error, 1, 0, _("'%s' is not a valid number (or out of range)"), value); @@ -1864,9 +2070,10 @@ _set_fcn_gobject_flags (ARGS_SET_FCN) static gboolean _set_fcn_gobject_ssid (ARGS_SET_FCN) { - GBytes *ssid; + gs_unref_bytes GBytes *ssid = NULL; - nm_assert (!error || !*error); + if (_SET_FCN_DO_RESET_DEFAULT (property_info, modifier, value)) + return _gobject_property_reset_default (setting, property_info->property_name); if (strlen (value) > 32) { g_set_error (error, 1, 0, _("'%s' is not valid"), value); @@ -1875,14 +2082,14 @@ _set_fcn_gobject_ssid (ARGS_SET_FCN) ssid = g_bytes_new (value, strlen (value)); g_object_set (setting, property_info->property_name, ssid, NULL); - g_bytes_unref (ssid); return TRUE; } static gboolean _set_fcn_gobject_ifname (ARGS_SET_FCN) { - nm_assert (!error || !*error); + if (_SET_FCN_DO_RESET_DEFAULT (property_info, modifier, value)) + return _gobject_property_reset_default (setting, property_info->property_name); if (!nm_utils_is_valid_iface_name (value, error)) return FALSE; @@ -1895,6 +2102,9 @@ _set_fcn_vpn_service_type (ARGS_SET_FCN) { gs_free char *service_name = NULL; + if (_SET_FCN_DO_RESET_DEFAULT (property_info, modifier, value)) + return _gobject_property_reset_default (setting, property_info->property_name); + service_name = nm_vpn_plugin_info_list_find_service_type (nm_vpn_get_plugin_infos (), value); g_object_set (setting, property_info->property_name, service_name ?: value, NULL); return TRUE; @@ -1933,11 +2143,11 @@ _complete_fcn_vpn_service_type (ARGS_COMPLETE_FCN) return (const char *const*) (*out_to_free = values); } -static gboolean -nmc_util_is_domain (const char *domain) +static const char * +_multilist_validate_fcn_is_domain (const char *domain, GError **error) { //FIXME: implement - return TRUE; + return domain; } static gboolean @@ -1950,7 +2160,8 @@ _set_fcn_gobject_bytes (ARGS_SET_FCN) gs_unref_bytes GBytes *bytes = NULL; GByteArray *array; - nm_assert (!error || !*error); + if (_SET_FCN_DO_RESET_DEFAULT (property_info, modifier, value)) + return _gobject_property_reset_default (setting, property_info->property_name); val_strip = nm_strstrip_avoid_copy (value, &val_strip_free); @@ -1995,113 +2206,85 @@ done: /*****************************************************************************/ static gconstpointer -_get_fcn_802_1x_ca_cert (ARGS_GET_FCN) +_get_fcn_cert_8021x (ARGS_GET_FCN) { NMSetting8021x *s_8021X = NM_SETTING_802_1X (setting); - char *ca_cert_str = NULL; + const NMSetting8021xSchemeVtable *vtable; + char *str = NULL; RETURN_UNSUPPORTED_GET_TYPE (); - switch (nm_setting_802_1x_get_ca_cert_scheme (s_8021X)) { - case NM_SETTING_802_1X_CK_SCHEME_BLOB: - ca_cert_str = bytes_to_string (nm_setting_802_1x_get_ca_cert_blob (s_8021X)); - break; - case NM_SETTING_802_1X_CK_SCHEME_PATH: - ca_cert_str = g_strdup (nm_setting_802_1x_get_ca_cert_path (s_8021X)); - break; - case NM_SETTING_802_1X_CK_SCHEME_PKCS11: - ca_cert_str = g_strdup (nm_setting_802_1x_get_ca_cert_uri (s_8021X)); - break; - case NM_SETTING_802_1X_CK_SCHEME_UNKNOWN: - break; - } - - NM_SET_OUT (out_is_default, !ca_cert_str || !ca_cert_str[0]); - RETURN_STR_TO_FREE (ca_cert_str); -} - -static gconstpointer -_get_fcn_802_1x_client_cert (ARGS_GET_FCN) -{ - NMSetting8021x *s_8021X = NM_SETTING_802_1X (setting); - char *cert_str = NULL; - - RETURN_UNSUPPORTED_GET_TYPE (); + vtable = &nm_setting_8021x_scheme_vtable[property_info->property_typ_data->subtype.cert_8021x.scheme_type]; - switch (nm_setting_802_1x_get_client_cert_scheme (s_8021X)) { + switch (vtable->scheme_func (s_8021X)) { case NM_SETTING_802_1X_CK_SCHEME_BLOB: - if (NM_FLAGS_HAS (get_flags, NM_META_ACCESSOR_GET_FLAGS_SHOW_SECRETS)) - cert_str = bytes_to_string (nm_setting_802_1x_get_client_cert_blob (s_8021X)); - else + if ( vtable->is_secret + && !NM_FLAGS_HAS (get_flags, NM_META_ACCESSOR_GET_FLAGS_SHOW_SECRETS)) return _get_text_hidden (get_type); + str = bytes_to_string (vtable->blob_func (s_8021X)); break; case NM_SETTING_802_1X_CK_SCHEME_PATH: - cert_str = g_strdup (nm_setting_802_1x_get_client_cert_path (s_8021X)); + str = g_strdup (vtable->path_func (s_8021X)); break; case NM_SETTING_802_1X_CK_SCHEME_PKCS11: - cert_str = g_strdup (nm_setting_802_1x_get_client_cert_uri (s_8021X)); + str = g_strdup (vtable->uri_func (s_8021X)); break; case NM_SETTING_802_1X_CK_SCHEME_UNKNOWN: break; } - NM_SET_OUT (out_is_default, !cert_str || !cert_str[0]); - RETURN_STR_TO_FREE (cert_str); + NM_SET_OUT (out_is_default, !str || !str[0]); + RETURN_STR_TO_FREE (str); } -static gconstpointer -_get_fcn_802_1x_phase2_ca_cert (ARGS_GET_FCN) +static gboolean +_set_fcn_cert_8021x (ARGS_SET_FCN) { - NMSetting8021x *s_8021X = NM_SETTING_802_1X (setting); - char *phase2_ca_cert_str = NULL; + gs_free char *value_to_free = NULL; + NMSetting8021xCKScheme scheme = NM_SETTING_802_1X_CK_SCHEME_PATH; + const NMSetting8021xSchemeVtable *vtable; - RETURN_UNSUPPORTED_GET_TYPE (); + if (_SET_FCN_DO_RESET_DEFAULT (property_info, modifier, value)) + return _gobject_property_reset_default (setting, property_info->property_name); - switch (nm_setting_802_1x_get_phase2_ca_cert_scheme (s_8021X)) { - case NM_SETTING_802_1X_CK_SCHEME_BLOB: - phase2_ca_cert_str = bytes_to_string (nm_setting_802_1x_get_phase2_ca_cert_blob (s_8021X)); - break; - case NM_SETTING_802_1X_CK_SCHEME_PATH: - phase2_ca_cert_str = g_strdup (nm_setting_802_1x_get_phase2_ca_cert_path (s_8021X)); - break; - case NM_SETTING_802_1X_CK_SCHEME_PKCS11: - phase2_ca_cert_str = g_strdup (nm_setting_802_1x_get_phase2_ca_cert_uri (s_8021X)); - break; - case NM_SETTING_802_1X_CK_SCHEME_UNKNOWN: - break; - } + value = nm_strstrip_avoid_copy (value, &value_to_free); - NM_SET_OUT (out_is_default, !phase2_ca_cert_str || !phase2_ca_cert_str[0]); - RETURN_STR_TO_FREE (phase2_ca_cert_str); -} + if (strncmp (value, NM_SETTING_802_1X_CERT_SCHEME_PREFIX_PKCS11, NM_STRLEN (NM_SETTING_802_1X_CERT_SCHEME_PREFIX_PKCS11)) == 0) + scheme = NM_SETTING_802_1X_CK_SCHEME_PKCS11; + else if (strncmp (value, NM_SETTING_802_1X_CERT_SCHEME_PREFIX_PATH, NM_STRLEN (NM_SETTING_802_1X_CERT_SCHEME_PREFIX_PATH)) == 0) + value += NM_STRLEN (NM_SETTING_802_1X_CERT_SCHEME_PREFIX_PATH); -static gconstpointer -_get_fcn_802_1x_phase2_client_cert (ARGS_GET_FCN) -{ - NMSetting8021x *s_8021X = NM_SETTING_802_1X (setting); - char *cert_str = NULL; + vtable = &nm_setting_8021x_scheme_vtable[property_info->property_typ_data->subtype.cert_8021x.scheme_type]; - RETURN_UNSUPPORTED_GET_TYPE (); + if (vtable->is_secret) { + gs_free char *path = NULL; + nm_auto_free_secret char *password_free = NULL; + char *password; - switch (nm_setting_802_1x_get_phase2_client_cert_scheme (s_8021X)) { - case NM_SETTING_802_1X_CK_SCHEME_BLOB: - if (NM_FLAGS_HAS (get_flags, NM_META_ACCESSOR_GET_FLAGS_SHOW_SECRETS)) - cert_str = bytes_to_string (nm_setting_802_1x_get_phase2_client_cert_blob (s_8021X)); - else - return _get_text_hidden (get_type); - break; - case NM_SETTING_802_1X_CK_SCHEME_PATH: - cert_str = g_strdup (nm_setting_802_1x_get_phase2_client_cert_path (s_8021X)); - break; - case NM_SETTING_802_1X_CK_SCHEME_PKCS11: - cert_str = g_strdup (nm_setting_802_1x_get_phase2_client_cert_uri (s_8021X)); - break; - case NM_SETTING_802_1X_CK_SCHEME_UNKNOWN: - break; - } + path = g_strdup (value); + password = path + strcspn (path, " \t"); + if (password[0] != '\0') { + password[0] = '\0'; + while (nm_utils_is_separator (password[0])) + password++; + } else { + password_free = g_strdup (vtable->passwd_func (NM_SETTING_802_1X (setting))); + password = password_free; + } - NM_SET_OUT (out_is_default, !cert_str || !cert_str[0]); - RETURN_STR_TO_FREE (cert_str); + return vtable->set_private_key_func (NM_SETTING_802_1X (setting), + path, + password, + scheme, + NULL, + error); + } else { + return vtable->set_cert_func (NM_SETTING_802_1X (setting), + value, + scheme, + NULL, + error); + } } static gconstpointer @@ -2120,219 +2303,6 @@ _get_fcn_gobject_bytes (ARGS_GET_FCN) } static gconstpointer -_get_fcn_802_1x_private_key (ARGS_GET_FCN) -{ - NMSetting8021x *s_8021X = NM_SETTING_802_1X (setting); - char *key_str = NULL; - - RETURN_UNSUPPORTED_GET_TYPE (); - - switch (nm_setting_802_1x_get_private_key_scheme (s_8021X)) { - case NM_SETTING_802_1X_CK_SCHEME_BLOB: - if (NM_FLAGS_HAS (get_flags, NM_META_ACCESSOR_GET_FLAGS_SHOW_SECRETS)) - key_str = bytes_to_string (nm_setting_802_1x_get_private_key_blob (s_8021X)); - else - return _get_text_hidden (get_type); - break; - case NM_SETTING_802_1X_CK_SCHEME_PATH: - key_str = g_strdup (nm_setting_802_1x_get_private_key_path (s_8021X)); - break; - case NM_SETTING_802_1X_CK_SCHEME_PKCS11: - key_str = g_strdup (nm_setting_802_1x_get_private_key_uri (s_8021X)); - break; - case NM_SETTING_802_1X_CK_SCHEME_UNKNOWN: - break; - } - - NM_SET_OUT (out_is_default, !key_str || !key_str[0]); - RETURN_STR_TO_FREE (key_str); -} - -static gconstpointer -_get_fcn_802_1x_phase2_private_key (ARGS_GET_FCN) -{ - NMSetting8021x *s_8021X = NM_SETTING_802_1X (setting); - char *key_str = NULL; - - RETURN_UNSUPPORTED_GET_TYPE (); - - switch (nm_setting_802_1x_get_phase2_private_key_scheme (s_8021X)) { - case NM_SETTING_802_1X_CK_SCHEME_BLOB: - if (NM_FLAGS_HAS (get_flags, NM_META_ACCESSOR_GET_FLAGS_SHOW_SECRETS)) - key_str = bytes_to_string (nm_setting_802_1x_get_phase2_private_key_blob (s_8021X)); - else - return _get_text_hidden (get_type); - break; - case NM_SETTING_802_1X_CK_SCHEME_PATH: - key_str = g_strdup (nm_setting_802_1x_get_phase2_private_key_path (s_8021X)); - break; - case NM_SETTING_802_1X_CK_SCHEME_PKCS11: - key_str = g_strdup (nm_setting_802_1x_get_phase2_private_key_uri (s_8021X)); - break; - case NM_SETTING_802_1X_CK_SCHEME_UNKNOWN: - break; - } - - NM_SET_OUT (out_is_default, !key_str || !key_str[0]); - RETURN_STR_TO_FREE (key_str); -} - -#define DEFINE_SETTER_STR_LIST(def_func, set_func) \ - static gboolean \ - def_func (ARGS_SET_FCN) \ - { \ - const char **strv = NULL; \ - gsize i; \ - \ - nm_assert (error == NULL || *error == NULL); \ - \ - strv = nm_utils_strsplit_set (value, " \t,", FALSE); \ - if (strv) { \ - for (i = 0; strv[i]; i++) \ - set_func (NM_SETTING_802_1X (setting), strv[i]); \ - } \ - return TRUE; \ - } - -#define DEFINE_SETTER_CERT(def_func, set_func) \ - static gboolean \ - def_func (ARGS_SET_FCN) \ - { \ - char *val_strip = g_strstrip (g_strdup (value)); \ - char *p = val_strip; \ - NMSetting8021xCKScheme scheme = NM_SETTING_802_1X_CK_SCHEME_PATH; \ - gboolean success; \ - \ - if (strncmp (val_strip, NM_SETTING_802_1X_CERT_SCHEME_PREFIX_PKCS11, NM_STRLEN (NM_SETTING_802_1X_CERT_SCHEME_PREFIX_PKCS11)) == 0) \ - scheme = NM_SETTING_802_1X_CK_SCHEME_PKCS11; \ - else if (strncmp (val_strip, NM_SETTING_802_1X_CERT_SCHEME_PREFIX_PATH, NM_STRLEN (NM_SETTING_802_1X_CERT_SCHEME_PREFIX_PATH)) == 0) \ - p += NM_STRLEN (NM_SETTING_802_1X_CERT_SCHEME_PREFIX_PATH); \ - \ - success = set_func (NM_SETTING_802_1X (setting), p, scheme, NULL, error); \ - g_free (val_strip); \ - return success; \ - } - -#define DEFINE_SETTER_PRIV_KEY(def_func, pwd_func, set_func) \ - static gboolean \ - def_func (ARGS_SET_FCN) \ - { \ - gs_free char *path = NULL; \ - gs_free char *password_free = NULL; \ - char *password; \ - NMSetting8021xCKScheme scheme = NM_SETTING_802_1X_CK_SCHEME_PATH; \ - \ - value = nm_str_skip_leading_spaces (value); \ - \ - if (strncmp (value, NM_SETTING_802_1X_CERT_SCHEME_PREFIX_PKCS11, NM_STRLEN (NM_SETTING_802_1X_CERT_SCHEME_PREFIX_PKCS11)) == 0) \ - scheme = NM_SETTING_802_1X_CK_SCHEME_PKCS11; \ - else if (strncmp (value, NM_SETTING_802_1X_CERT_SCHEME_PREFIX_PATH, NM_STRLEN (NM_SETTING_802_1X_CERT_SCHEME_PREFIX_PATH)) == 0) \ - value += NM_STRLEN (NM_SETTING_802_1X_CERT_SCHEME_PREFIX_PATH); \ - \ - path = g_strdup (value); \ - password = path + strcspn (path, " \t"); \ - if (password[0] != '\0') { \ - password[0] = '\0'; \ - while (nm_utils_is_separator (password[0])) \ - password++; \ - } else \ - password = password_free = g_strdup (pwd_func (NM_SETTING_802_1X (setting))); \ - return set_func (NM_SETTING_802_1X (setting), path, password, scheme, NULL, error); \ - } - -DEFINE_SETTER_STR_LIST_MULTI (check_and_add_eap_method, - NM_SETTING_802_1X, - nm_setting_802_1x_add_eap_method) - -static gboolean -_set_fcn_802_1x_eap (ARGS_SET_FCN) -{ - return check_and_add_eap_method (setting, - property_info->property_name, - value, - (const char **) property_info->property_typ_data->values_static, - error); -} - -static gboolean -_validate_and_remove_eap_method (NMSetting8021x *setting, - const char *eap, - GError **error) -{ - gboolean ret; - - ret = nm_setting_802_1x_remove_eap_method_by_value (setting, eap); - if (!ret) - g_set_error (error, 1, 0, _("the property doesn't contain EAP method '%s'"), eap); - return ret; -} -DEFINE_REMOVER_INDEX_OR_VALUE (_remove_fcn_802_1x_eap, - NM_SETTING_802_1X, - nm_setting_802_1x_get_num_eap_methods, - nm_setting_802_1x_remove_eap_method, - _validate_and_remove_eap_method) - -DEFINE_SETTER_CERT (_set_fcn_802_1x_ca_cert, nm_setting_802_1x_set_ca_cert) - -DEFINE_SETTER_STR_LIST (_set_fcn_802_1x_altsubject_matches, nm_setting_802_1x_add_altsubject_match) - -static gboolean -_validate_and_remove_altsubject_match (NMSetting8021x *setting, - const char *altsubject_match, - GError **error) -{ - gboolean ret; - - ret = nm_setting_802_1x_remove_altsubject_match_by_value (setting, altsubject_match); - if (!ret) - g_set_error (error, 1, 0, - _("the property doesn't contain alternative subject match '%s'"), - altsubject_match); - return ret; -} -DEFINE_REMOVER_INDEX_OR_VALUE (_remove_fcn_802_1x_altsubject_matches, - NM_SETTING_802_1X, - nm_setting_802_1x_get_num_altsubject_matches, - nm_setting_802_1x_remove_altsubject_match, - _validate_and_remove_altsubject_match) - -DEFINE_SETTER_CERT (_set_fcn_802_1x_client_cert, nm_setting_802_1x_set_client_cert) - -DEFINE_SETTER_CERT (_set_fcn_802_1x_phase2_ca_cert, nm_setting_802_1x_set_phase2_ca_cert) - -DEFINE_SETTER_STR_LIST (_set_fcn_802_1x_phase2_altsubject_matches, nm_setting_802_1x_add_phase2_altsubject_match) - -static gboolean -_validate_and_remove_phase2_altsubject_match (NMSetting8021x *setting, - const char *phase2_altsubject_match, - GError **error) -{ - gboolean ret; - - ret = nm_setting_802_1x_remove_phase2_altsubject_match_by_value (setting, phase2_altsubject_match); - if (!ret) - g_set_error (error, 1, 0, - _("the property doesn't contain \"phase2\" alternative subject match '%s'"), - phase2_altsubject_match); - return ret; -} -DEFINE_REMOVER_INDEX_OR_VALUE (_remove_fcn_802_1x_phase2_altsubject_matches, - NM_SETTING_802_1X, - nm_setting_802_1x_get_num_phase2_altsubject_matches, - nm_setting_802_1x_remove_phase2_altsubject_match, - _validate_and_remove_phase2_altsubject_match) - -DEFINE_SETTER_CERT (_set_fcn_802_1x_phase2_client_cert, nm_setting_802_1x_set_phase2_client_cert) - -DEFINE_SETTER_PRIV_KEY (_set_fcn_802_1x_private_key, - nm_setting_802_1x_get_private_key_password, - nm_setting_802_1x_set_private_key) - -DEFINE_SETTER_PRIV_KEY (_set_fcn_802_1x_phase2_private_key, - nm_setting_802_1x_get_phase2_private_key_password, - nm_setting_802_1x_set_phase2_private_key) - -static gconstpointer _get_fcn_bond_options (ARGS_GET_FCN) { NMSettingBond *s_bond = NM_SETTING_BOND (setting); @@ -2365,59 +2335,40 @@ _get_fcn_bond_options (ARGS_GET_FCN) RETURN_STR_TO_FREE (g_string_free (bond_options_s, FALSE)); } -/* example: miimon=100,mode=balance-rr, updelay=5 */ static gboolean -_validate_and_remove_bond_option (NMSettingBond *setting, const char *option) -{ - const char *opt; - const char **valid_options; - - valid_options = nm_setting_bond_get_valid_options (setting); - opt = nmc_string_is_valid (option, valid_options, NULL); - - if (opt) - return nm_setting_bond_remove_option (setting, opt); - else - return FALSE; -} - -static const char * -_validate_bond_option_value (const char *option, const char *value, GError **error) -{ - if (!g_strcmp0 (option, NM_SETTING_BOND_OPTION_MODE)) - return nmc_bond_validate_mode (value, error); - - return value; -} - -static gboolean -_bond_add_option (NMSettingBond *setting, - const char *name, - const char *value) +_optionlist_set_fcn_bond_options (NMSetting *setting, + const char *name, + const char *value, + GError **error) { gs_free char *tmp_value = NULL; char *p; - if (nm_streq0 (name, NM_SETTING_BOND_OPTION_ARP_IP_TARGET)) { + if (!value) { + nm_setting_bond_remove_option (NM_SETTING_BOND (setting), name); + return TRUE; + } + + if (nm_streq (name, NM_SETTING_BOND_OPTION_MODE)) { + value = nmc_bond_validate_mode (value, error); + if (!value) + return FALSE; + } else if (nm_streq (name, NM_SETTING_BOND_OPTION_ARP_IP_TARGET)) { value = tmp_value = g_strdup (value); for (p = tmp_value; p && *p; p++) if (*p == ' ') *p = ','; } - return nm_setting_bond_add_option (setting, name, value); + if (!nm_setting_bond_add_option (NM_SETTING_BOND (setting), name, value)) { + nm_utils_error_set (error, NM_UTILS_ERROR_INVALID_ARGUMENT, + _("failed to set bond option \"%s\""), + name); + return FALSE; + } + return TRUE; } -DEFINE_SETTER_OPTIONS (_set_fcn_bond_options, - NM_SETTING_BOND, - NMSettingBond, - _bond_add_option, - nm_setting_bond_get_valid_options, - _validate_bond_option_value) -DEFINE_REMOVER_OPTION (_remove_fcn_bond_options, - NM_SETTING_BOND, - _validate_and_remove_bond_option) - static const char * _describe_fcn_bond_options (ARGS_DESCRIBE_FCN) { @@ -2456,25 +2407,27 @@ _get_fcn_connection_permissions (ARGS_GET_FCN) GString *perm = NULL; const char *perm_item; const char *perm_type; - int i; + guint i, n; RETURN_UNSUPPORTED_GET_TYPE (); - perm = g_string_new (NULL); - for (i = 0; i < nm_setting_connection_get_num_permissions (s_con); i++) { - if (nm_setting_connection_get_permission (s_con, i, &perm_type, &perm_item, NULL)) - g_string_append_printf (perm, "%s:%s,", perm_type, perm_item); + n = nm_setting_connection_get_num_permissions (s_con); + for (i = 0; i < n; i++) { + if (!nm_setting_connection_get_permission (s_con, i, &perm_type, &perm_item, NULL)) + continue; + + if (!perm) + perm = g_string_new (NULL); + else + g_string_append_c (perm, ','); + g_string_append_printf (perm, "%s:%s", perm_type, perm_item); } - NM_SET_OUT (out_is_default, perm->len == 0); + NM_SET_OUT (out_is_default, !perm); - if (perm->len > 0) { - g_string_truncate (perm, perm->len-1); /* remove trailing , */ + if (perm) RETURN_STR_TO_FREE (g_string_free (perm, FALSE)); - } - /* No value from get_permission */ - g_string_free (perm, TRUE); return NULL; } @@ -2495,6 +2448,11 @@ _set_fcn_connection_type (ARGS_SET_FCN) return FALSE; } + if (_SET_FCN_DO_RESET_DEFAULT (property_info, modifier, value)) { + g_object_set (G_OBJECT (setting), property_info->property_name, NULL, NULL); + return TRUE; + } + uuid = nm_utils_uuid_generate (); g_object_set (G_OBJECT (setting), NM_SETTING_CONNECTION_UUID, uuid, @@ -2541,75 +2499,61 @@ _complete_fcn_connection_type (ARGS_COMPLETE_FCN) return (const char *const*) (*out_to_free = result); } -/* define from libnm-core/nm-setting-connection.c */ #define PERM_USER_PREFIX "user:" -static gboolean -permissions_valid (const char *perm) +static const char * +_sanitize_connection_permission_user (const char *perm) { - if (!perm || perm[0] == '\0') - return FALSE; + if (NM_STR_HAS_PREFIX (perm, PERM_USER_PREFIX)) + perm += NM_STRLEN (PERM_USER_PREFIX); - if (strncmp (perm, PERM_USER_PREFIX, strlen (PERM_USER_PREFIX)) == 0) { - if ( strlen (perm) <= strlen (PERM_USER_PREFIX) - || strchr (perm + strlen (PERM_USER_PREFIX), ':')) - return FALSE; - } else { - if (strchr (perm, ':')) - return FALSE; - } + if (perm[0] == '\0') + return NULL; + if (!g_utf8_validate (perm, -1, NULL)) + return NULL; - return TRUE; + return perm; } -static gboolean -_set_fcn_connection_permissions (ARGS_SET_FCN) -{ - gs_free const char **strv = NULL; - gsize i; - - nm_assert (!error || !*error); - - strv = nm_utils_strsplit_set (value, " \t,", FALSE); - if (!verify_string_list (strv, property_info->property_name, permissions_valid, error)) - return FALSE; - - for (i = 0; strv && strv[i]; i++) { - const char *user = strv[i]; - - if (strncmp (user, PERM_USER_PREFIX, NM_STRLEN (PERM_USER_PREFIX)) == 0) - user += NM_STRLEN (PERM_USER_PREFIX); - nm_setting_connection_add_permission (NM_SETTING_CONNECTION (setting), "user", user, NULL); +static const char * +_multilist_validate2_fcn_connection_permissions (NMSetting *setting, + const char *item, + GError **error) +{ + if (!_sanitize_connection_permission_user (item)) { + nm_utils_error_set (error, NM_UTILS_ERROR_INVALID_ARGUMENT, + _("invalid permission \"%s\""), + item); + return NULL; } + return item; +} +static gboolean +_multilist_set_fcn_connection_permissions (NMSetting *setting, + const char *item) +{ + item = _sanitize_connection_permission_user (item); + nm_setting_connection_add_permission (NM_SETTING_CONNECTION (setting), "user", item, NULL); return TRUE; } static gboolean -_validate_and_remove_connection_permission (NMSettingConnection *setting, - const char *perm, - GError **error) +_multilist_remove_by_value_fcn_connection_permissions (NMSetting *setting, + const char *item) { - gboolean ret; + const char *sanitized; - ret = nm_setting_connection_remove_permission_by_value (setting, "user", perm, NULL); - if (!ret) - g_set_error (error, 1, 0, _("the property doesn't contain permission '%s'"), perm); - return ret; + sanitized = _sanitize_connection_permission_user (item); + nm_setting_connection_remove_permission_by_value (NM_SETTING_CONNECTION (setting), "user", sanitized ?: item, NULL); + return TRUE; } -DEFINE_REMOVER_INDEX_OR_VALUE (_remove_fcn_connection_permissions, - NM_SETTING_CONNECTION, - nm_setting_connection_get_num_permissions, - nm_setting_connection_remove_permission, - _validate_and_remove_connection_permission) static gboolean _set_fcn_connection_master (ARGS_SET_FCN) { - nm_assert (!error || !*error); - - if (!value) - ; + if (_SET_FCN_DO_RESET_DEFAULT (property_info, modifier, value)) + value = NULL; else if (!*value) value = NULL; else if ( !nm_utils_is_valid_iface_name (value, NULL) @@ -2689,44 +2633,20 @@ _complete_fcn_connection_master (ARGS_COMPLETE_FCN) return (const char *const*) (*out_to_free = result); } -static gboolean -_set_fcn_connection_secondaries (ARGS_SET_FCN) -{ - gs_free const char **strv = NULL; - const char *const*iter; - - strv = nm_utils_strsplit_set (value, " \t,", FALSE); - if (strv) { - for (iter = strv; *iter; iter++) - nm_setting_connection_add_secondary (NM_SETTING_CONNECTION (setting), *iter); - } - return TRUE; -} - -static gboolean -_validate_and_remove_connection_secondary (NMSettingConnection *setting, - const char *secondary_uuid, - GError **error) +static const char * +_multilist_validate2_fcn_uuid (NMSetting *setting, + const char *item, + GError **error) { - gboolean ret; - - if (!nm_utils_is_uuid (secondary_uuid)) { - g_set_error (error, 1, 0, - _("the value '%s' is not a valid UUID"), secondary_uuid); - return FALSE; + if (!nm_utils_is_uuid (item)) { + nm_utils_error_set (error, NM_UTILS_ERROR_INVALID_ARGUMENT, + _("the value '%s' is not a valid UUID"), + item); + return NULL; } - ret = nm_setting_connection_remove_secondary_by_value (setting, secondary_uuid); - if (!ret) - g_set_error (error, 1, 0, - _("the property doesn't contain UUID '%s'"), secondary_uuid); - return ret; + return item; } -DEFINE_REMOVER_INDEX_OR_VALUE (_remove_fcn_connection_secondaries, - NM_SETTING_CONNECTION, - nm_setting_connection_get_num_secondaries, - nm_setting_connection_remove_secondary, - _validate_and_remove_connection_secondary) static gconstpointer _get_fcn_connection_metered (ARGS_GET_FCN) @@ -2761,6 +2681,9 @@ _set_fcn_connection_metered (ARGS_SET_FCN) NMMetered metered; NMTernary ts_val; + if (_SET_FCN_DO_RESET_DEFAULT (property_info, modifier, value)) + return _gobject_property_reset_default (setting, property_info->property_name); + if (!nmc_string_to_ternary (value, &ts_val, error)) return FALSE; @@ -2810,87 +2733,54 @@ dcb_flags_to_string (NMSettingDcbFlags flags) return g_string_free (flag_str, FALSE); } -#define DEFINE_DCB_FLAGS_GETTER(func_name, property_name) \ - static gconstpointer \ - func_name (ARGS_GET_FCN) \ - { \ - guint v; \ - GValue val = G_VALUE_INIT; \ - \ - RETURN_UNSUPPORTED_GET_TYPE (); \ - g_value_init (&val, G_TYPE_UINT); \ - g_object_get_property (G_OBJECT (setting), property_name, &val); \ - v = g_value_get_uint (&val); \ - g_value_unset (&val); \ - RETURN_STR_TO_FREE (dcb_flags_to_string (v)); \ - } +static gconstpointer +_get_fcn_dcb (ARGS_GET_FCN) +{ + NMSettingDcb *s_dcb = NM_SETTING_DCB (setting); + GString *str; + guint i; -#define DEFINE_DCB_BOOL_GETTER(func_name, getter_func_name) \ - static gconstpointer \ - func_name (ARGS_GET_FCN) \ - { \ - NMSettingDcb *s_dcb = NM_SETTING_DCB (setting); \ - GString *str; \ - guint i; \ - \ - RETURN_UNSUPPORTED_GET_TYPE (); \ - \ - str = g_string_new (NULL); \ - for (i = 0; i < 8; i++) { \ - if (getter_func_name (s_dcb, i)) \ - g_string_append_c (str, '1'); \ - else \ - g_string_append_c (str, '0'); \ - if (i < 7) \ - g_string_append_c (str, ','); \ - } \ - \ - RETURN_STR_TO_FREE (g_string_free (str, FALSE)); \ - } + RETURN_UNSUPPORTED_GET_TYPE (); -#define DEFINE_DCB_UINT_GETTER(func_name, getter_func_name) \ - static gconstpointer \ - func_name (ARGS_GET_FCN) \ - { \ - NMSettingDcb *s_dcb = NM_SETTING_DCB (setting); \ - GString *str; \ - guint i; \ - \ - RETURN_UNSUPPORTED_GET_TYPE (); \ - \ - str = g_string_new (NULL); \ - for (i = 0; i < 8; i++) { \ - g_string_append_printf (str, "%u", getter_func_name (s_dcb, i)); \ - if (i < 7) \ - g_string_append_c (str, ','); \ - } \ - \ - RETURN_STR_TO_FREE (g_string_free (str, FALSE)); \ - } + str = g_string_new (NULL); + for (i = 0; i < 8; i++) { + guint v; -DEFINE_DCB_FLAGS_GETTER (_get_fcn_dcb_app_fcoe_flags, NM_SETTING_DCB_APP_FCOE_FLAGS) -DEFINE_DCB_FLAGS_GETTER (_get_fcn_dcb_app_iscsi_flags, NM_SETTING_DCB_APP_ISCSI_FLAGS) -DEFINE_DCB_FLAGS_GETTER (_get_fcn_dcb_app_fip_flags, NM_SETTING_DCB_APP_FIP_FLAGS) + v = property_info->property_typ_data->subtype.dcb.get_fcn (s_dcb, i); -DEFINE_DCB_FLAGS_GETTER (_get_fcn_dcb_priority_flow_control_flags, NM_SETTING_DCB_PRIORITY_FLOW_CONTROL_FLAGS) -DEFINE_DCB_BOOL_GETTER (_get_fcn_dcb_priority_flow_control, nm_setting_dcb_get_priority_flow_control) + if (i > 0) + g_string_append_c (str, ','); + g_string_append_printf (str, "%u", v); + } -DEFINE_DCB_FLAGS_GETTER (_get_fcn_dcb_priority_group_flags, NM_SETTING_DCB_PRIORITY_GROUP_FLAGS) -DEFINE_DCB_UINT_GETTER (_get_fcn_dcb_priority_group_id, nm_setting_dcb_get_priority_group_id) -DEFINE_DCB_UINT_GETTER (_get_fcn_dcb_priority_group_bandwidth, nm_setting_dcb_get_priority_group_bandwidth) -DEFINE_DCB_UINT_GETTER (_get_fcn_dcb_priority_bandwidth, nm_setting_dcb_get_priority_bandwidth) -DEFINE_DCB_BOOL_GETTER (_get_fcn_dcb_priority_strict, nm_setting_dcb_get_priority_strict_bandwidth) -DEFINE_DCB_UINT_GETTER (_get_fcn_dcb_priority_traffic_class, nm_setting_dcb_get_priority_traffic_class) + RETURN_STR_TO_FREE (g_string_free (str, FALSE)); +} #define DCB_ALL_FLAGS (NM_SETTING_DCB_FLAG_ENABLE | NM_SETTING_DCB_FLAG_ADVERTISE | NM_SETTING_DCB_FLAG_WILLING) +static gconstpointer +_get_fcn_dcb_flags (ARGS_GET_FCN) +{ + nm_auto_unset_gvalue GValue val = G_VALUE_INIT; + guint v; + + RETURN_UNSUPPORTED_GET_TYPE (); + + g_value_init (&val, G_TYPE_UINT); + g_object_get_property (G_OBJECT (setting), property_info->property_name, &val); + v = g_value_get_uint (&val); + + RETURN_STR_TO_FREE (dcb_flags_to_string (v)); +} + static gboolean _set_fcn_dcb_flags (ARGS_SET_FCN) { NMSettingDcbFlags flags = NM_SETTING_DCB_FLAG_NONE; long int t; - nm_assert (!error || !*error); + if (_SET_FCN_DO_RESET_DEFAULT (property_info, modifier, value)) + return _gobject_property_reset_default (setting, property_info->property_name); /* Check for overall hex numeric value */ t = _nm_utils_ascii_str_to_int64 (value, 0, 0, DCB_ALL_FLAGS, -1); @@ -2938,15 +2828,13 @@ static gboolean dcb_parse_uint_array (const char *val, guint max, guint other, - guint *out_array, + guint out_array[static 8], GError **error) { gs_strfreev char **items = NULL; char **iter; gsize i; - nm_assert (out_array); - items = g_strsplit_set (val, ",", -1); if (g_strv_length (items) != 8) { g_set_error_literal (error, 1, 0, _("must contain 8 comma-separated numbers")); @@ -2995,117 +2883,89 @@ dcb_check_feature_enabled (const NMMetaEnvironment *environment, gpointer *envir } static gboolean -_set_fcn_dcb_priority_flow_control (ARGS_SET_FCN) +_set_fcn_dcb (ARGS_SET_FCN) { guint i = 0; - guint nums[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + guint nums[8] = { 0, }; - nm_assert (!error || !*error); + if (_SET_FCN_DO_RESET_DEFAULT (property_info, modifier, value)) + return _gobject_property_reset_default (setting, property_info->property_name); - if (!dcb_parse_uint_array (value, 1, 0, nums, error)) + if (!dcb_parse_uint_array (value, + property_info->property_typ_data->subtype.dcb.max, + property_info->property_typ_data->subtype.dcb.other, + nums, + error)) return FALSE; - for (i = 0; i < 8; i++) - nm_setting_dcb_set_priority_flow_control (NM_SETTING_DCB (setting), i, !!nums[i]); - - dcb_check_feature_enabled (environment, environment_user_data, NM_SETTING_DCB (setting), NM_SETTING_DCB_PRIORITY_FLOW_CONTROL_FLAGS); - return TRUE; -} - -static gboolean -_set_fcn_dcb_priority_group_id (ARGS_SET_FCN) -{ - guint i = 0; - guint nums[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; - - nm_assert (!error || !*error); - - if (!dcb_parse_uint_array (value, 7, 15, nums, error)) - return FALSE; - - for (i = 0; i < 8; i++) - nm_setting_dcb_set_priority_group_id (NM_SETTING_DCB (setting), i, nums[i]); - - dcb_check_feature_enabled (environment, environment_user_data, NM_SETTING_DCB (setting), NM_SETTING_DCB_PRIORITY_GROUP_FLAGS); - return TRUE; -} + if (property_info->property_typ_data->subtype.dcb.is_percent) { + guint sum = 0; -static gboolean -_set_fcn_dcb_priority_group_bandwidth (ARGS_SET_FCN) -{ - guint i = 0, sum = 0; - guint nums[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; - - nm_assert (!error || !*error); - - if (!dcb_parse_uint_array (value, 100, 0, nums, error)) - return FALSE; - - for (i = 0; i < 8; i++) - sum += nums[i]; - if (sum != 100) { - g_set_error_literal (error, 1, 0, _("bandwidth percentages must total 100%%")); - return FALSE; + for (i = 0; i < 8; i++) { + sum += nums[i]; + if (nums[i] > 100 || sum > 100) + break; + } + if (sum != 100) { + g_set_error_literal (error, 1, 0, _("bandwidth percentages must total 100%%")); + return FALSE; + } } for (i = 0; i < 8; i++) - nm_setting_dcb_set_priority_group_bandwidth (NM_SETTING_DCB (setting), i, nums[i]); + property_info->property_typ_data->subtype.dcb.set_fcn (NM_SETTING_DCB (setting), i, nums[i]); dcb_check_feature_enabled (environment, environment_user_data, NM_SETTING_DCB (setting), NM_SETTING_DCB_PRIORITY_GROUP_FLAGS); return TRUE; } -static gboolean -_set_fcn_dcb_priority_bandwidth (ARGS_SET_FCN) +static gconstpointer +_get_fcn_dcb_bool (ARGS_GET_FCN) { - guint i = 0; - guint nums[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; - - nm_assert (!error || !*error); - - if (!dcb_parse_uint_array (value, 100, 0, nums, error)) - return FALSE; - - for (i = 0; i < 8; i++) - nm_setting_dcb_set_priority_bandwidth (NM_SETTING_DCB (setting), i, nums[i]); - - dcb_check_feature_enabled (environment, environment_user_data, NM_SETTING_DCB (setting), NM_SETTING_DCB_PRIORITY_GROUP_FLAGS); - return TRUE; -} + NMSettingDcb *s_dcb = NM_SETTING_DCB (setting); + GString *str; + guint i; -static gboolean -_set_fcn_dcb_priority_strict (ARGS_SET_FCN) -{ - guint i = 0; - guint nums[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + RETURN_UNSUPPORTED_GET_TYPE (); - nm_assert (!error || !*error); + str = g_string_new (NULL); + for (i = 0; i < 8; i++) { + gboolean v; - if (!dcb_parse_uint_array (value, 1, 0, nums, error)) - return FALSE; + v = property_info->property_typ_data->subtype.dcb_bool.get_fcn (s_dcb, i); - for (i = 0; i < 8; i++) - nm_setting_dcb_set_priority_strict_bandwidth (NM_SETTING_DCB (setting), i, !!nums[i]); + if (i > 0) + g_string_append_c (str, ','); + g_string_append_c (str, v ? '1': '0'); + } - dcb_check_feature_enabled (environment, environment_user_data, NM_SETTING_DCB (setting), NM_SETTING_DCB_PRIORITY_GROUP_FLAGS); - return TRUE; + RETURN_STR_TO_FREE (g_string_free (str, FALSE)); } static gboolean -_set_fcn_dcb_priority_traffic_class (ARGS_SET_FCN) +_set_fcn_dcb_bool (ARGS_SET_FCN) { guint i = 0; - guint nums[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + guint nums[8] = { 0, }; - nm_assert (!error || !*error); + if (_SET_FCN_DO_RESET_DEFAULT (property_info, modifier, value)) + return _gobject_property_reset_default (setting, property_info->property_name); - if (!dcb_parse_uint_array (value, 7, 0, nums, error)) + if (!dcb_parse_uint_array (value, 1, 0, nums, error)) return FALSE; - for (i = 0; i < 8; i++) - nm_setting_dcb_set_priority_traffic_class (NM_SETTING_DCB (setting), i, nums[i]); + for (i = 0; i < 8; i++) { + property_info->property_typ_data->subtype.dcb_bool.set_fcn (NM_SETTING_DCB (setting), + i, + !!nums[i]); + } - dcb_check_feature_enabled (environment, environment_user_data, NM_SETTING_DCB (setting), NM_SETTING_DCB_PRIORITY_GROUP_FLAGS); + dcb_check_feature_enabled (environment, + environment_user_data, + NM_SETTING_DCB (setting), + ( property_info->property_typ_data->subtype.dcb_bool.with_flow_control_flags + ? NM_SETTING_DCB_PRIORITY_FLOW_CONTROL_FLAGS + : NM_SETTING_DCB_PRIORITY_GROUP_FLAGS)); return TRUE; } @@ -3114,9 +2974,10 @@ _set_fcn_gsm_sim_operator_id (ARGS_SET_FCN) { const char *p = value; - nm_assert (!error || !*error); + if (_SET_FCN_DO_RESET_DEFAULT (property_info, modifier, value)) + return _gobject_property_reset_default (setting, property_info->property_name); - if (strlen (value) != 5 && strlen (value) != 6) { + if (!NM_IN_SET (strlen (value), 5, 6)) { g_set_error_literal (error, 1, 0, _("SIM operator ID must be a 5 or 6 number MCCMNC code")); return FALSE; } @@ -3137,16 +2998,16 @@ _set_fcn_gsm_sim_operator_id (ARGS_SET_FCN) static gboolean _set_fcn_infiniband_p_key (ARGS_SET_FCN) { - const gint64 INVALID = G_MININT64; gint64 p_key; - nm_assert (!error || !*error); + if (_SET_FCN_DO_RESET_DEFAULT (property_info, modifier, value)) + return _gobject_property_reset_default (setting, property_info->property_name); if (nm_streq (value, "default")) p_key = -1; else { - p_key = _nm_utils_ascii_str_to_int64 (value, 0, -1, G_MAXUINT16, INVALID); - if (p_key == INVALID) { + p_key = _nm_utils_ascii_str_to_int64 (value, 0, -1, G_MAXUINT16, -2); + if (p_key == -2) { g_set_error (error, 1, 0, _("'%s' is not a valid IBoIP P_Key"), value); return FALSE; } @@ -3177,525 +3038,302 @@ _get_fcn_infiniband_p_key (ARGS_GET_FCN) } static gconstpointer -_get_fcn_ip_config_addresses (ARGS_GET_FCN) +_get_fcn_objlist (ARGS_GET_FCN) { - NMSettingIPConfig *s_ip = NM_SETTING_IP_CONFIG (setting); - GString *printable; - guint num_addresses, i; - NMIPAddress *addr; - - RETURN_UNSUPPORTED_GET_TYPE (); - - printable = g_string_new (NULL); - - num_addresses = NM_MIN ((guint) G_MAXINT, nm_setting_ip_config_get_num_addresses (s_ip)); - for (i = 0; i < num_addresses; i++) { - addr = nm_setting_ip_config_get_address (s_ip, i); - - if (printable->len > 0) - g_string_append (printable, ", "); - - g_string_append_printf (printable, "%s/%u", - nm_ip_address_get_address (addr), - nm_ip_address_get_prefix (addr)); - } - - NM_SET_OUT (out_is_default, num_addresses == 0); - RETURN_STR_TO_FREE (g_string_free (printable, FALSE)); -} - -static gconstpointer -_get_fcn_ip_config_routes (ARGS_GET_FCN) -{ - NMSettingIPConfig *s_ip = NM_SETTING_IP_CONFIG (setting); - GString *printable; - guint num_routes, i; - NMIPRoute *route; + GString *str = NULL; + guint num; + guint idx; RETURN_UNSUPPORTED_GET_TYPE (); - printable = g_string_new (NULL); - - num_routes = NM_MIN ((guint) G_MAXINT, nm_setting_ip_config_get_num_routes (s_ip)); - for (i = 0; i < num_routes; i++) { - gs_free char *attr_str = NULL; - gs_strfreev char **attr_names = NULL; - gs_unref_hashtable GHashTable *hash = g_hash_table_new (nm_str_hash, g_str_equal); - int j; - - route = nm_setting_ip_config_get_route (s_ip, i); - - attr_names = nm_ip_route_get_attribute_names (route); - for (j = 0; attr_names && attr_names[j]; j++) { - g_hash_table_insert (hash, attr_names[j], - nm_ip_route_get_attribute (route, attr_names[j])); + num = property_info->property_typ_data->subtype.objlist.get_num_fcn (setting); + + for (idx = 0; idx < num; idx++) { + if (!str) + str = g_string_new (NULL); + else if (str->len > 0) { + if ( get_type == NM_META_ACCESSOR_GET_TYPE_PRETTY + && property_info->property_typ_data->subtype.objlist.delimit_pretty_with_semicolon) + g_string_append (str, "; "); + else + g_string_append (str, ", "); } - attr_str = nm_utils_format_variant_attributes (hash, ' ', '='); - - if (get_type != NM_META_ACCESSOR_GET_TYPE_PRETTY) { - if (printable->len > 0) - g_string_append (printable, ", "); - - g_string_append_printf (printable, "%s/%u", - nm_ip_route_get_dest (route), - nm_ip_route_get_prefix (route)); - - if (nm_ip_route_get_next_hop (route)) - g_string_append_printf (printable, " %s", nm_ip_route_get_next_hop (route)); - if (nm_ip_route_get_metric (route) != -1) - g_string_append_printf (printable, " %u", (guint32) nm_ip_route_get_metric (route)); - if (attr_str) - g_string_append_printf (printable, " %s", attr_str); - } else { - - if (printable->len > 0) - g_string_append (printable, "; "); - - g_string_append (printable, "{ "); - - g_string_append_printf (printable, "ip = %s/%u", - nm_ip_route_get_dest (route), - nm_ip_route_get_prefix (route)); - - if (nm_ip_route_get_next_hop (route)) { - g_string_append_printf (printable, ", nh = %s", - nm_ip_route_get_next_hop (route)); - } - - if (nm_ip_route_get_metric (route) != -1) - g_string_append_printf (printable, ", mt = %u", (guint32) nm_ip_route_get_metric (route)); - if (attr_str) - g_string_append_printf (printable, " %s", attr_str); - - g_string_append (printable, " }"); - } + property_info->property_typ_data->subtype.objlist.obj_to_str_fcn (get_type, + setting, + idx, + str); } - NM_SET_OUT (out_is_default, num_routes == 0); - RETURN_STR_TO_FREE (g_string_free (printable, FALSE)); + NM_SET_OUT (out_is_default, num == 0); + if (str) + RETURN_STR_TO_FREE (g_string_free (str, FALSE)); + return NULL; } -static const char *ipv4_valid_methods[] = { - NM_SETTING_IP4_CONFIG_METHOD_AUTO, - NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL, - NM_SETTING_IP4_CONFIG_METHOD_MANUAL, - NM_SETTING_IP4_CONFIG_METHOD_SHARED, - NM_SETTING_IP4_CONFIG_METHOD_DISABLED, - NULL -}; - -static gboolean -_set_fcn_ip4_config_method (ARGS_SET_FCN) +static void +_objlist_obj_to_str_fcn_ip_config_addresses (NMMetaAccessorGetType get_type, + NMSetting *setting, + guint idx, + GString *str) { - /* Silently accept "static" and convert to "manual" */ - if (value && strlen (value) > 1 && matches (value, "static")) - value = NM_SETTING_IP4_CONFIG_METHOD_MANUAL; + NMIPAddress *obj; - return check_and_set_string (setting, property_info->property_name, value, ipv4_valid_methods, error); + obj = nm_setting_ip_config_get_address (NM_SETTING_IP_CONFIG (setting), + idx); + g_string_append_printf (str, + "%s/%u", + nm_ip_address_get_address (obj), + nm_ip_address_get_prefix (obj)); } -static gboolean -_set_fcn_ip4_config_dns (ARGS_SET_FCN) +static void +_objlist_obj_to_str_fcn_ip_config_routes (NMMetaAccessorGetType get_type, + NMSetting *setting, + guint idx, + GString *str) { - const char **strv = NULL; - const char *const*iter; - in_addr_t ip4_addr; - - nm_assert (!error || !*error); + NMIPRoute *route; + gs_free char *attr_str = NULL; + gs_strfreev char **attr_names = NULL; + gs_unref_hashtable GHashTable *hash = g_hash_table_new (nm_str_hash, g_str_equal); + int j; - strv = nm_utils_strsplit_set (value, " \t,", FALSE); - for (iter = strv; iter && *iter; iter++) { - gs_free char *addr = g_strstrip (g_strdup (*iter)); + route = nm_setting_ip_config_get_route (NM_SETTING_IP_CONFIG (setting), idx); - if (inet_pton (AF_INET, addr, &ip4_addr) < 1) { - g_set_error (error, 1, 0, _("invalid IPv4 address '%s'"), addr); - return FALSE; - } - nm_setting_ip_config_add_dns (NM_SETTING_IP_CONFIG (setting), addr); + attr_names = nm_ip_route_get_attribute_names (route); + for (j = 0; attr_names && attr_names[j]; j++) { + g_hash_table_insert (hash, attr_names[j], + nm_ip_route_get_attribute (route, attr_names[j])); } - return TRUE; -} -static gboolean -_validate_and_remove_ipv4_dns (NMSettingIPConfig *setting, - const char *dns, - GError **error) -{ - guint32 ip4_addr; - gboolean ret; + attr_str = nm_utils_format_variant_attributes (hash, ' ', '='); - if (inet_pton (AF_INET, dns, &ip4_addr) < 1) { - g_set_error (error, 1, 0, _("invalid IPv4 address '%s'"), dns); - return FALSE; - } + if (get_type != NM_META_ACCESSOR_GET_TYPE_PRETTY) { + g_string_append_printf (str, "%s/%u", + nm_ip_route_get_dest (route), + nm_ip_route_get_prefix (route)); - ret = nm_setting_ip_config_remove_dns_by_value (setting, dns); - if (!ret) - g_set_error (error, 1, 0, _("the property doesn't contain DNS server '%s'"), dns); - return ret; -} -DEFINE_REMOVER_INDEX_OR_VALUE (_remove_fcn_ipv4_config_dns, - NM_SETTING_IP_CONFIG, - nm_setting_ip_config_get_num_dns, - nm_setting_ip_config_remove_dns, - _validate_and_remove_ipv4_dns) + if (nm_ip_route_get_next_hop (route)) + g_string_append_printf (str, " %s", nm_ip_route_get_next_hop (route)); + if (nm_ip_route_get_metric (route) != -1) + g_string_append_printf (str, " %u", (guint32) nm_ip_route_get_metric (route)); + if (attr_str) + g_string_append_printf (str, " %s", attr_str); + } else { + g_string_append (str, "{ "); -static gboolean -_set_fcn_ip_config_dns_search (ARGS_SET_FCN) -{ - gs_free const char **strv = NULL; - gsize i; + g_string_append_printf (str, "ip = %s/%u", + nm_ip_route_get_dest (route), + nm_ip_route_get_prefix (route)); - nm_assert (!error || !*error); + if (nm_ip_route_get_next_hop (route)) { + g_string_append_printf (str, ", nh = %s", + nm_ip_route_get_next_hop (route)); + } - strv = nm_utils_strsplit_set (value, " \t,", FALSE); - if (!verify_string_list (strv, property_info->property_name, nmc_util_is_domain, error)) - return FALSE; + if (nm_ip_route_get_metric (route) != -1) + g_string_append_printf (str, ", mt = %u", (guint32) nm_ip_route_get_metric (route)); + if (attr_str) + g_string_append_printf (str, " %s", attr_str); - if (strv) { - for (i = 0; strv[i]; i++) - nm_setting_ip_config_add_dns_search (NM_SETTING_IP_CONFIG (setting), strv[i]); + g_string_append (str, " }"); } - return TRUE; -} - -static gboolean -_validate_and_remove_ip_dns_search (NMSettingIPConfig *setting, - const char *dns_search, - GError **error) -{ - gboolean ret; - - ret = nm_setting_ip_config_remove_dns_search_by_value (setting, dns_search); - if (!ret) - g_set_error (error, 1, 0, - _("the property doesn't contain DNS search domain '%s'"), - dns_search); - return ret; } -DEFINE_REMOVER_INDEX_OR_VALUE (_remove_fcn_ip_config_dns_search, - NM_SETTING_IP_CONFIG, - nm_setting_ip_config_get_num_dns_searches, - nm_setting_ip_config_remove_dns_search, - _validate_and_remove_ip_dns_search) static gboolean -_set_fcn_ip_config_dns_options (ARGS_SET_FCN) +_set_fcn_ip_config_method (ARGS_SET_FCN) { - gs_free const char **strv = NULL; - NMSettingIPConfig *s_ip; - gsize i; + if (_SET_FCN_DO_RESET_DEFAULT (property_info, modifier, value)) + return _gobject_property_reset_default (setting, property_info->property_name); - nm_assert (!error || !*error); - s_ip = NM_SETTING_IP_CONFIG (setting); - - strv = nm_utils_strsplit_set (value, " \t,", FALSE); - if (strv) { - for (i = 0; strv[i]; i++) { - nm_setting_ip_config_remove_dns_option_by_value (s_ip, strv[i]); - nm_setting_ip_config_add_dns_option (s_ip, strv[i]); - } + /* Silently accept "static" and convert to "manual" */ + if ( strlen (value) > 1 + && matches (value, "static")) { + if (nm_setting_ip_config_get_addr_family (NM_SETTING_IP_CONFIG (setting)) == AF_INET) + value = NM_SETTING_IP4_CONFIG_METHOD_MANUAL; + else + value = NM_SETTING_IP6_CONFIG_METHOD_MANUAL; } - return TRUE; -} - -static gboolean -_validate_and_remove_ip_dns_option (NMSettingIPConfig *setting, - const char *dns_option, - GError **error) -{ - gboolean ret; - - ret = nm_setting_ip_config_remove_dns_option_by_value (setting, dns_option); - if (!ret) - g_set_error (error, 1, 0, - _("the property doesn't contain DNS option '%s'"), - dns_option); - return ret; -} -DEFINE_REMOVER_INDEX_OR_VALUE (_remove_fcn_ip_config_dns_options, - NM_SETTING_IP_CONFIG, - nm_setting_ip_config_get_num_dns_options, - nm_setting_ip_config_remove_dns_option, - _validate_and_remove_ip_dns_option) -static gboolean -_set_fcn_ip4_config_addresses (ARGS_SET_FCN) -{ - gs_free const char **strv = NULL; - const char *const*iter; - NMIPAddress *ip4addr; + value = nmc_string_is_valid (value, + (const char **) property_info->property_typ_data->values_static, + error); + if (!value) + return FALSE; - strv = nm_utils_strsplit_set (value, ",", FALSE); - for (iter = strv; *iter; iter++) { - ip4addr = _parse_ip_address (AF_INET, *iter, error); - if (!ip4addr) - return FALSE; - nm_setting_ip_config_add_address (NM_SETTING_IP_CONFIG (setting), ip4addr); - nm_ip_address_unref (ip4addr); - } + g_object_set (setting, property_info->property_name, value, NULL); return TRUE; } -static gboolean -_validate_and_remove_ipv4_address (NMSettingIPConfig *setting, - const char *address, - GError **error) +static const char * +_multilist_validate2_fcn_ip_config_dns (NMSetting *setting, + const char *value, + GError **error) { - NMIPAddress *ip4addr; - gboolean ret; - - ip4addr = _parse_ip_address (AF_INET, address, error); - if (!ip4addr) - return FALSE; + int addr_family = nm_setting_ip_config_get_addr_family (NM_SETTING_IP_CONFIG (setting)); - ret = nm_setting_ip_config_remove_address_by_value (setting, ip4addr); - if (!ret) { - g_set_error (error, 1, 0, - _("the property doesn't contain IP address '%s'"), address); + if (!nm_utils_parse_inaddr (addr_family, value, NULL)) { + nm_utils_error_set (error, NM_UTILS_ERROR_INVALID_ARGUMENT, + _("invalid IPv%c address '%s'"), + nm_utils_addr_family_to_char (addr_family), + value); + return NULL; } - nm_ip_address_unref (ip4addr); - return ret; -} -DEFINE_REMOVER_INDEX_OR_VALUE (_remove_fcn_ipv4_config_addresses, - NM_SETTING_IP_CONFIG, - nm_setting_ip_config_get_num_addresses, - nm_setting_ip_config_remove_address, - _validate_and_remove_ipv4_address) - -static gboolean -_set_fcn_ip4_config_gateway (ARGS_SET_FCN) -{ - gs_free char *addr = NULL; - - addr = g_strstrip (g_strdup (value)); - if (!nm_utils_ipaddr_valid (AF_INET, addr)) { - g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_INVALID_ARGUMENT, - _("invalid gateway address '%s'"), value); - return FALSE; - } - g_object_set (setting, property_info->property_name, addr, NULL); - return TRUE; + return value; } static gboolean -_set_fcn_ip4_config_routes (ARGS_SET_FCN) +_multilist_add_fcn_ip_config_dns_options (NMSetting *setting, + const char *item) { - gs_free const char **strv = NULL; - const char *const*iter; - NMIPRoute *ip4route; + NMSettingIPConfig *s_ip = NM_SETTING_IP_CONFIG (setting); - strv = nm_utils_strsplit_set (value, ",", FALSE); - for (iter = strv; *iter; iter++) { - ip4route = _parse_ip_route (AF_INET, *iter, error); - if (!ip4route) - return FALSE; - nm_setting_ip_config_add_route (NM_SETTING_IP_CONFIG (setting), ip4route); - nm_ip_route_unref (ip4route); + if (!nm_setting_ip_config_add_dns_option (s_ip, item)) { + /* maybe it failed, because the element already existed. *sigh*. */ + nm_setting_ip_config_remove_dns_option_by_value (s_ip, item); + return nm_setting_ip_config_add_dns_option (s_ip, item); } return TRUE; } static gboolean -_validate_and_remove_ipv4_route (NMSettingIPConfig *setting, - const char *route, - GError **error) -{ - NMIPRoute *ip4route; - gboolean ret; - - ip4route = _parse_ip_route (AF_INET, route, error); - if (!ip4route) - return FALSE; - - ret = nm_setting_ip_config_remove_route_by_value (setting, ip4route); - if (!ret) - g_set_error (error, 1, 0, _("the property doesn't contain route '%s'"), route); - nm_ip_route_unref (ip4route); - return ret; -} -DEFINE_REMOVER_INDEX_OR_VALUE (_remove_fcn_ipv4_config_routes, - NM_SETTING_IP_CONFIG, - nm_setting_ip_config_get_num_routes, - nm_setting_ip_config_remove_route, - _validate_and_remove_ipv4_route) - -static const char *ipv6_valid_methods[] = { - NM_SETTING_IP6_CONFIG_METHOD_IGNORE, - NM_SETTING_IP6_CONFIG_METHOD_AUTO, - NM_SETTING_IP6_CONFIG_METHOD_DHCP, - NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL, - NM_SETTING_IP6_CONFIG_METHOD_MANUAL, - NM_SETTING_IP6_CONFIG_METHOD_SHARED, - NULL -}; - -static gboolean -_set_fcn_ip6_config_method (ARGS_SET_FCN) -{ - /* Silently accept "static" and convert to "manual" */ - if (value && strlen (value) > 1 && matches (value, "static")) - value = NM_SETTING_IP6_CONFIG_METHOD_MANUAL; - - return check_and_set_string (setting, property_info->property_name, value, ipv6_valid_methods, error); -} - -static gboolean -_set_fcn_ip6_config_dns (ARGS_SET_FCN) +_set_fcn_objlist (ARGS_SET_FCN) { gs_free const char **strv = NULL; - const char *const*iter; - struct in6_addr ip6_addr; - - nm_assert (!error || !*error); + gsize i, nstrv; - strv = nm_utils_strsplit_set (value, " \t,", FALSE); - for (iter = strv; iter && *iter; iter++) { - gs_free char *addr = g_strstrip (g_strdup (*iter)); - - if (inet_pton (AF_INET6, addr, &ip6_addr) < 1) { - g_set_error (error, 1, 0, _("invalid IPv6 address '%s'"), addr); - return FALSE; + if (_SET_FCN_DO_RESET_DEFAULT_WITH_SUPPORTS_REMOVE (property_info, modifier, value)) { + if (property_info->property_typ_data->subtype.objlist.clear_all_fcn) { + property_info->property_typ_data->subtype.objlist.clear_all_fcn (setting); + return TRUE; } - nm_setting_ip_config_add_dns (NM_SETTING_IP_CONFIG (setting), addr); + return _gobject_property_reset_default (setting, property_info->property_name); } - return TRUE; -} -static gboolean -_validate_and_remove_ipv6_dns (NMSettingIPConfig *setting, - const char *dns, - GError **error) -{ - struct in6_addr ip6_addr; - gboolean ret; + if ( _SET_FCN_DO_REMOVE (modifier, value) + && ( property_info->property_typ_data->subtype.objlist.remove_by_idx_fcn_u + || property_info->property_typ_data->subtype.objlist.remove_by_idx_fcn_s)) { + gs_free gint64 *indexes = NULL; - if (inet_pton (AF_INET6, dns, &ip6_addr) < 1) { - g_set_error (error, 1, 0, _("invalid IPv6 address '%s'"), dns); - return FALSE; - } + indexes = _value_str_as_index_list (value, &nstrv); + if (indexes) { + gint64 num; - ret = nm_setting_ip_config_remove_dns_by_value (setting, dns); - if (!ret) - g_set_error (error, 1, 0, _("the property doesn't contain DNS server '%s'"), dns); - return ret; -} -DEFINE_REMOVER_INDEX_OR_VALUE (_remove_fcn_ipv6_config_dns, - NM_SETTING_IP_CONFIG, - nm_setting_ip_config_get_num_dns, - nm_setting_ip_config_remove_dns, - _validate_and_remove_ipv6_dns) + num = property_info->property_typ_data->subtype.objlist.get_num_fcn (setting); + for (i = 0; i < nstrv; i++) { + gint64 idx = indexes[i]; -static gboolean -_dns_options_is_default (NMSettingIPConfig *setting) -{ - return nm_setting_ip_config_has_dns_options (setting) - && !nm_setting_ip_config_get_num_dns_options (setting); -} + if (idx >= num) + continue; + if (property_info->property_typ_data->subtype.objlist.remove_by_idx_fcn_u) + property_info->property_typ_data->subtype.objlist.remove_by_idx_fcn_u (setting, idx); + else + property_info->property_typ_data->subtype.objlist.remove_by_idx_fcn_s (setting, idx); + } + return TRUE; + } + } -static gboolean -_set_fcn_ip6_config_addresses (ARGS_SET_FCN) -{ - gs_free const char **strv = NULL; - const char *const*iter; - NMIPAddress *ip6addr; + strv = _value_strsplit (value, + VALUE_STRSPLIT_MODE_OBJLIST, + &nstrv); - strv = nm_utils_strsplit_set (value, ",", FALSE); - for (iter = strv; strv && *iter; iter++) { - ip6addr = _parse_ip_address (AF_INET6, *iter, error); - if (!ip6addr) + if (_SET_FCN_DO_SET_ALL (modifier, value)) { + if (property_info->property_typ_data->subtype.objlist.clear_all_fcn) + property_info->property_typ_data->subtype.objlist.clear_all_fcn (setting); + else + _gobject_property_reset (setting, property_info->property_name, FALSE); + } + + for (i = 0; i < nstrv; i++) { + /* FIXME: there is the problem here that set_fcn() might succed on the first item + * (modifying it), and fail to parse the second one. + * + * Optimally, we would first parse all input strings before starting the + * modify the setting. The setting should only be modified if (and only if) + * the entire operation succeeds to set all items. + * + * Currently, in interactive mode this leads to odd behavior. + * + * This does not only affect objlist.set_fcn() or _pt_objlist properties. + * E.g. we also call _gobject_property_reset() before validating the input. */ + if (!property_info->property_typ_data->subtype.objlist.set_fcn (setting, + !_SET_FCN_DO_REMOVE (modifier, value), + strv[i], + error)) return FALSE; - nm_setting_ip_config_add_address (NM_SETTING_IP_CONFIG (setting), ip6addr); - nm_ip_address_unref (ip6addr); } return TRUE; } static gboolean -_validate_and_remove_ipv6_address (NMSettingIPConfig *setting, - const char *address, - GError **error) +_objlist_set_fcn_ip_config_addresses (NMSetting *setting, + gboolean do_add, + const char *value, + GError **error) { - NMIPAddress *ip6addr; - gboolean ret; + int addr_family = nm_setting_ip_config_get_addr_family (NM_SETTING_IP_CONFIG (setting)); + nm_auto_unref_ip_address NMIPAddress *addr = NULL; - ip6addr = _parse_ip_address (AF_INET6, address, error); - if (!ip6addr) + addr = _parse_ip_address (addr_family, value, error); + if (!addr) return FALSE; - - ret = nm_setting_ip_config_remove_address_by_value (setting, ip6addr); - if (!ret) - g_set_error (error, 1, 0, _("the property doesn't contain IP address '%s'"), address); - nm_ip_address_unref (ip6addr); - return ret; + if (do_add) + nm_setting_ip_config_add_address (NM_SETTING_IP_CONFIG (setting), addr); + else + nm_setting_ip_config_remove_address_by_value (NM_SETTING_IP_CONFIG (setting), addr); + return TRUE; } -DEFINE_REMOVER_INDEX_OR_VALUE (_remove_fcn_ipv6_config_addresses, - NM_SETTING_IP_CONFIG, - nm_setting_ip_config_get_num_addresses, - nm_setting_ip_config_remove_address, - _validate_and_remove_ipv6_address) static gboolean -_set_fcn_ip6_config_gateway (ARGS_SET_FCN) +_set_fcn_ip_config_gateway (ARGS_SET_FCN) { - gs_free char *addr = NULL; + gs_free char *value_to_free = NULL; + int addr_family = nm_setting_ip_config_get_addr_family (NM_SETTING_IP_CONFIG (setting)); - addr = g_strstrip (g_strdup (value)); + if (_SET_FCN_DO_RESET_DEFAULT (property_info, modifier, value)) + return _gobject_property_reset_default (setting, property_info->property_name); - if (!nm_utils_ipaddr_valid (AF_INET6, addr)) { + value = nm_strstrip_avoid_copy (value, &value_to_free); + + if (!nm_utils_ipaddr_valid (addr_family, value)) { g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_INVALID_ARGUMENT, _("invalid gateway address '%s'"), - addr); + value); return FALSE; } - g_object_set (setting, property_info->property_name, addr, NULL); + g_object_set (setting, property_info->property_name, value, NULL); return TRUE; } static gboolean -_set_fcn_ip6_config_routes (ARGS_SET_FCN) +_objlist_set_fcn_ip_config_routes (NMSetting *setting, + gboolean do_add, + const char *value, + GError **error) { - gs_free const char **strv = NULL; - const char *const*iter; - NMIPRoute *ip6route; + int addr_family = nm_setting_ip_config_get_addr_family (NM_SETTING_IP_CONFIG (setting)); + nm_auto_unref_ip_route NMIPRoute *route = NULL; - strv = nm_utils_strsplit_set (value, ",", FALSE); - for (iter = strv; strv && *iter; iter++) { - ip6route = _parse_ip_route (AF_INET6, *iter, error); - if (!ip6route) - return FALSE; - nm_setting_ip_config_add_route (NM_SETTING_IP_CONFIG (setting), ip6route); - nm_ip_route_unref (ip6route); - } + route = _parse_ip_route (addr_family, value, error); + if (!route) + return FALSE; + if (do_add) + nm_setting_ip_config_add_route (NM_SETTING_IP_CONFIG (setting), route); + else + nm_setting_ip_config_remove_route_by_value (NM_SETTING_IP_CONFIG (setting), route); return TRUE; } static gboolean -_validate_and_remove_ipv6_route (NMSettingIPConfig *setting, - const char *route, - GError **error) +_is_default_func_ip_config_dns_options (NMSetting *setting) { - NMIPRoute *ip6route; - gboolean ret; - - ip6route = _parse_ip_route (AF_INET6, route, error); - if (!ip6route) - return FALSE; - - ret = nm_setting_ip_config_remove_route_by_value (setting, ip6route); - if (!ret) - g_set_error (error, 1, 0, _("the property doesn't contain route '%s'"), route); - nm_ip_route_unref (ip6route); - return ret; + return nm_setting_ip_config_has_dns_options (NM_SETTING_IP_CONFIG (setting)) + && !nm_setting_ip_config_get_num_dns_options (NM_SETTING_IP_CONFIG (setting)); } -DEFINE_REMOVER_INDEX_OR_VALUE (_remove_fcn_ipv6_config_routes, - NM_SETTING_IP_CONFIG, - nm_setting_ip_config_get_num_routes, - nm_setting_ip_config_remove_route, - _validate_and_remove_ipv6_route) static gconstpointer _get_fcn_match_interface_name (ARGS_GET_FCN) @@ -3716,49 +3354,11 @@ _get_fcn_match_interface_name (ARGS_GET_FCN) else g_string_append_c (str, ' '); name = nm_setting_match_get_interface_name (s_match, i); - g_string_append (str, _nm_utils_escape_spaces (name, &to_free)); + g_string_append (str, _value_strescape (name, &to_free)); } RETURN_STR_TO_FREE (g_string_free (str, FALSE)); } -static gboolean -_set_fcn_match_interface_name (ARGS_SET_FCN) -{ - gs_free const char **strv = NULL; - gsize i; - - nm_assert (!error || !*error); - - strv = nm_utils_strsplit_set (value, " \t", TRUE); - if (strv) { - for (i = 0; strv[i]; i++) { - nm_setting_match_add_interface_name (NM_SETTING_MATCH (setting), - _nm_utils_unescape_spaces ((char *) strv[i])); - } - } - return TRUE; -} - -static gboolean -_validate_and_remove_match_interface_name (NMSettingMatch *setting, - const char *interface_name, - GError **error) -{ - gboolean ret; - - ret = nm_setting_match_remove_interface_name_by_value (setting, interface_name); - if (!ret) - g_set_error (error, 1, 0, - _("the property doesn't contain interface name '%s'"), - interface_name); - return ret; -} -DEFINE_REMOVER_INDEX_OR_VALUE (_remove_fcn_match_interface_name, - NM_SETTING_MATCH, - nm_setting_match_get_num_interface_names, - nm_setting_match_remove_interface_name, - _validate_and_remove_match_interface_name) - static gconstpointer _get_fcn_olpc_mesh_ssid (ARGS_GET_FCN) { @@ -3783,7 +3383,8 @@ _set_fcn_olpc_mesh_channel (ARGS_SET_FCN) { unsigned long chan_int; - nm_assert (!error || !*error); + if (_SET_FCN_DO_RESET_DEFAULT (property_info, modifier, value)) + return _gobject_property_reset_default (setting, property_info->property_name); if (!nmc_string_to_uint (value, TRUE, 1, 13, &chan_int)) { g_set_error (error, 1, 0, _("'%s' is not a valid channel; use <1-13>"), value); @@ -3803,241 +3404,123 @@ _validate_fcn_proxy_pac_script (const char *value, char **out_to_free, GError ** RETURN_STR_TO_FREE (script); } -static gconstpointer -_get_fcn_sriov_vfs (ARGS_GET_FCN) +static void +_objlist_obj_to_str_fcn_sriov_vfs (NMMetaAccessorGetType get_type, + NMSetting *setting, + guint idx, + GString *str) { - NMSettingSriov *s_sriov = NM_SETTING_SRIOV (setting); - GString *printable; - guint num_vfs, i; + gs_free char *s = NULL; NMSriovVF *vf; - char *str; - - RETURN_UNSUPPORTED_GET_TYPE (); - - printable = g_string_new (NULL); - - num_vfs = nm_setting_sriov_get_num_vfs (s_sriov); - for (i = 0; i < num_vfs; i++) { - vf = nm_setting_sriov_get_vf (s_sriov, i); - - if (printable->len > 0) - g_string_append (printable, ", "); - str = nm_utils_sriov_vf_to_str (vf, FALSE, NULL); - if (str) { - g_string_append (printable, str); - g_free (str); - } - } - - NM_SET_OUT (out_is_default, num_vfs == 0); - RETURN_STR_TO_FREE (g_string_free (printable, FALSE)); + vf = nm_setting_sriov_get_vf (NM_SETTING_SRIOV (setting), idx); + s = nm_utils_sriov_vf_to_str (vf, FALSE, NULL); + if (s) + g_string_append (str, s); } -static gconstpointer -_get_fcn_tc_config_qdiscs (ARGS_GET_FCN) +static void +_objlist_obj_to_str_fcn_tc_config_qdiscs (NMMetaAccessorGetType get_type, + NMSetting *setting, + guint idx, + GString *str) { - NMSettingTCConfig *s_tc = NM_SETTING_TC_CONFIG (setting); - GString *printable; - guint num_qdiscs, i; + gs_free char *s = NULL; NMTCQdisc *qdisc; - char *str; - - RETURN_UNSUPPORTED_GET_TYPE (); - printable = g_string_new (NULL); - - num_qdiscs = nm_setting_tc_config_get_num_qdiscs (s_tc); - for (i = 0; i < num_qdiscs; i++) { - qdisc = nm_setting_tc_config_get_qdisc (s_tc, i); - - if (printable->len > 0) - g_string_append (printable, ", "); - - str = nm_utils_tc_qdisc_to_str (qdisc, NULL); - if (str) { - g_string_append (printable, str); - g_free (str); - } - } - - NM_SET_OUT (out_is_default, num_qdiscs == 0); - RETURN_STR_TO_FREE (g_string_free (printable, FALSE)); + qdisc = nm_setting_tc_config_get_qdisc (NM_SETTING_TC_CONFIG (setting), idx); + s = nm_utils_tc_qdisc_to_str (qdisc, NULL); + if (s) + g_string_append (str, s); } static gboolean -_set_fcn_sriov_vfs (ARGS_SET_FCN) -{ - gs_free const char **strv = NULL; - const char *const*iter; - NMSriovVF *vf; - GError *local = NULL; - - strv = nm_utils_strsplit_set (value, ",", FALSE); - for (iter = strv; strv && *iter; iter++) { - vf = nm_utils_sriov_vf_from_str (*iter, &local); - if (!vf) { - g_set_error (error, 1, 0, "%s. %s", local->message, - _("The valid syntax is: vf [attribute=value]... [,vf [attribute=value]...]")); - return FALSE; - } - nm_setting_sriov_add_vf (NM_SETTING_SRIOV (setting), vf); - nm_sriov_vf_unref (vf); +_objlist_set_fcn_sriov_vfs (NMSetting *setting, + gboolean do_add, + const char *value, + GError **error) +{ + nm_auto_unref_sriov_vf NMSriovVF *vf = NULL; + gs_free_error GError *local = NULL; + + vf = nm_utils_sriov_vf_from_str (value, &local); + if (!vf) { + nm_utils_error_set (error, NM_UTILS_ERROR_INVALID_ARGUMENT, + "%s. %s", + local->message, + _("The valid syntax is: vf [attribute=value]... [,vf [attribute=value]...]")); + return FALSE; } + if (do_add) + nm_setting_sriov_add_vf (NM_SETTING_SRIOV (setting), vf); + else + nm_setting_sriov_remove_vf_by_index (NM_SETTING_SRIOV (setting), nm_sriov_vf_get_index (vf)); return TRUE; } static gboolean -_set_fcn_tc_config_qdiscs (ARGS_SET_FCN) +_objlist_set_fcn_tc_config_qdiscs (NMSetting *setting, + gboolean do_add, + const char *value, + GError **error) { - gs_free const char **strv = NULL; - const char *const*iter; - NMTCQdisc *tc_qdisc; - GError *local = NULL; + nm_auto_unref_tc_qdisc NMTCQdisc *tc_qdisc = NULL; + gs_free_error GError *local = NULL; - strv = nm_utils_strsplit_set (value, ",", FALSE); - for (iter = strv; strv && *iter; iter++) { - tc_qdisc = nm_utils_tc_qdisc_from_str (*iter, &local); - if (!tc_qdisc) { - g_set_error (error, 1, 0, "%s %s", local->message, - _("The valid syntax is: '[root | parent <handle>] [handle <handle>] <qdisc>'")); - return FALSE; - } - nm_setting_tc_config_add_qdisc (NM_SETTING_TC_CONFIG (setting), tc_qdisc); - nm_tc_qdisc_unref (tc_qdisc); + tc_qdisc = nm_utils_tc_qdisc_from_str (value, &local); + if (!tc_qdisc) { + nm_utils_error_set (error, NM_UTILS_ERROR_INVALID_ARGUMENT, + "%s %s", + local->message, + _("The valid syntax is: '[root | parent <handle>] [handle <handle>] <qdisc>'")); + return FALSE; } + if (do_add) + nm_setting_tc_config_add_qdisc (NM_SETTING_TC_CONFIG (setting), tc_qdisc); + else + nm_setting_tc_config_remove_qdisc_by_value (NM_SETTING_TC_CONFIG (setting), tc_qdisc); return TRUE; } -static gboolean -_validate_and_remove_sriov_vf (NMSettingSriov *setting, - const char *value, - GError **error) +static void +_objlist_obj_to_str_fcn_tc_config_tfilters (NMMetaAccessorGetType get_type, + NMSetting *setting, + guint idx, + GString *str) { - NMSriovVF *vf; - gboolean ret; - - vf = nm_utils_sriov_vf_from_str (value, error); - if (!vf) - return FALSE; + NMTCTfilter *tfilter; + gs_free char *s = NULL; - ret = nm_setting_sriov_remove_vf_by_index (setting, nm_sriov_vf_get_index (vf)); - if (!ret) { - g_set_error (error, 1, 0, - _("the property doesn't contain vf with index %u"), - nm_sriov_vf_get_index (vf)); - } - nm_sriov_vf_unref (vf); - return ret; + tfilter = nm_setting_tc_config_get_tfilter (NM_SETTING_TC_CONFIG (setting), idx); + s = nm_utils_tc_tfilter_to_str (tfilter, NULL); + if (s) + g_string_append (str, s); } -DEFINE_REMOVER_INDEX_OR_VALUE (_remove_fcn_sriov_vfs, - NM_SETTING_SRIOV, - nm_setting_sriov_get_num_vfs, - nm_setting_sriov_remove_vf, - _validate_and_remove_sriov_vf) - static gboolean -_validate_and_remove_tc_qdisc (NMSettingTCConfig *setting, - const char *value, - GError **error) +_objlist_set_fcn_tc_config_tfilters (NMSetting *setting, + gboolean do_add, + const char *value, + GError **error) { - NMTCQdisc *qdisc; - gboolean ret; + gs_free_error GError *local = NULL; + nm_auto_unref_tc_tfilter NMTCTfilter *tc_tfilter = NULL; - qdisc = nm_utils_tc_qdisc_from_str (value, error); - if (!qdisc) + tc_tfilter = nm_utils_tc_tfilter_from_str (value, &local); + if (!tc_tfilter) { + nm_utils_error_set (error, NM_UTILS_ERROR_INVALID_ARGUMENT, + "%s %s", + local->message, + _("The valid syntax is: '[root | parent <handle>] [handle <handle>] <tfilter>'")); return FALSE; - - ret = nm_setting_tc_config_remove_qdisc_by_value (setting, qdisc); - if (!ret) - g_set_error (error, 1, 0, _("the property doesn't contain qdisc '%s'"), value); - nm_tc_qdisc_unref (qdisc); - return ret; -} -DEFINE_REMOVER_INDEX_OR_VALUE (_remove_fcn_tc_config_qdiscs, - NM_SETTING_TC_CONFIG, - nm_setting_tc_config_get_num_qdiscs, - nm_setting_tc_config_remove_qdisc, - _validate_and_remove_tc_qdisc) - -static gconstpointer -_get_fcn_tc_config_tfilters (ARGS_GET_FCN) -{ - NMSettingTCConfig *s_tc = NM_SETTING_TC_CONFIG (setting); - GString *printable; - guint num_tfilters, i; - NMTCTfilter *tfilter; - char *str; - - RETURN_UNSUPPORTED_GET_TYPE (); - - printable = g_string_new (NULL); - - num_tfilters = nm_setting_tc_config_get_num_tfilters (s_tc); - for (i = 0; i < num_tfilters; i++) { - tfilter = nm_setting_tc_config_get_tfilter (s_tc, i); - - if (printable->len > 0) - g_string_append (printable, ", "); - - str = nm_utils_tc_tfilter_to_str (tfilter, NULL); - if (str) { - g_string_append (printable, str); - g_free (str); - } } - - NM_SET_OUT (out_is_default, num_tfilters == 0); - RETURN_STR_TO_FREE (g_string_free (printable, FALSE)); -} - -static gboolean -_set_fcn_tc_config_tfilters (ARGS_SET_FCN) -{ - gs_free const char **strv = NULL; - const char *const*iter; - NMTCTfilter *tc_tfilter; - GError *local = NULL; - - strv = nm_utils_strsplit_set (value, ",", FALSE); - for (iter = strv; strv && *iter; iter++) { - tc_tfilter = nm_utils_tc_tfilter_from_str (*iter, &local); - if (!tc_tfilter) { - g_set_error (error, 1, 0, "%s %s", local->message, - _("The valid syntax is: '[root | parent <handle>] [handle <handle>] <tfilter>'")); - return FALSE; - } + if (do_add) nm_setting_tc_config_add_tfilter (NM_SETTING_TC_CONFIG (setting), tc_tfilter); - nm_tc_tfilter_unref (tc_tfilter); - } + else + nm_setting_tc_config_remove_tfilter_by_value (NM_SETTING_TC_CONFIG (setting), tc_tfilter); return TRUE; } -static gboolean -_validate_and_remove_tc_tfilter (NMSettingTCConfig *setting, - const char *value, - GError **error) -{ - NMTCTfilter *tfilter; - gboolean ret; - - tfilter = nm_utils_tc_tfilter_from_str (value, error); - if (!tfilter) - return FALSE; - - ret = nm_setting_tc_config_remove_tfilter_by_value (setting, tfilter); - if (!ret) - g_set_error (error, 1, 0, _("the property doesn't contain tfilter '%s'"), value); - nm_tc_tfilter_unref (tfilter); - return ret; -} -DEFINE_REMOVER_INDEX_OR_VALUE (_remove_fcn_tc_config_tfilters, - NM_SETTING_TC_CONFIG, - nm_setting_tc_config_get_num_tfilters, - nm_setting_tc_config_remove_tfilter, - _validate_and_remove_tc_tfilter) - static const char * _validate_fcn_team_config (const char *value, char **out_to_free, GError **error) { @@ -4048,214 +3531,129 @@ _validate_fcn_team_config (const char *value, char **out_to_free, GError **error RETURN_STR_TO_FREE (json); } -static gboolean -_is_valid_team_runner_tx_hash_element (const char *tx_hash_element, - GError **error) -{ - nm_assert (!error || !*error); - - if (NM_IN_STRSET (tx_hash_element, - "eth", "vlan", "ipv4", "ipv6", "ip", - "l3", "tcp", "udp", "sctp", "l4")) { - return TRUE; - } - - g_set_error (error, 1, 0, "'%s' is not valid. %s", tx_hash_element, - "Valid tx-hashes: [eth, vlan, ipv4, ipv6, ip, l3, tcp, udp, sctp, l4]"); - return FALSE; -} - -static gboolean -_set_fcn_team_runner_tx_hash (ARGS_SET_FCN) -{ - gs_free const char **strv = NULL; - const char *const*iter; - - nm_assert (!error || !*error); - - strv = nm_utils_strsplit_set (value, " \t,", FALSE); - for (iter = strv; strv && *iter; iter++) { - if (!_is_valid_team_runner_tx_hash_element (*iter, error)) - return FALSE; - } - +static void +_multilist_clear_all_fcn_team_runner_tx_hash (NMSetting *setting) +{ + /* Workaround libnm bug (confirmed against version 1.16.0). + * We need to both clear the GObject property and call the libnm API. + * + * This workaround was added in nmcli as [1]. This needs fixing in libnm. + * + * Without this, CI test "team_abs_set_runner_tx_hash" fails. + * Try (without the following workaround): */ +#if 0 + $ (nmcli connection delete team0 ; :); \ + nmcli connection add type team con-name team0 ifname team0 autoconnect no \ + team.runner lacp && \ + echo ">>> FIRST:" && \ + PAGER= nmcli -o connection show team0 && \ + nmcli connection modify team0 team.runner-tx-hash l3 && \ + echo ">>> AFTER:" && \ + PAGER= nmcli -o connection show team0 +#endif + /* See also: + * + * - https://github.com/NetworkManager/NetworkManager/pull/318 + * - https://bugzilla.redhat.com/show_bug.cgi?id=1691619 + * + * [1] https://cgit.freedesktop.org/NetworkManager/NetworkManager/commit/?id=350dbb55abf3a80267c398e6f64c2cee4645475a + */ + + /* it appears, we don't really need _gobject_property_reset(). Just to be sure + * also call it. */ + _gobject_property_reset (setting, NM_SETTING_TEAM_RUNNER_TX_HASH, FALSE); while (nm_setting_team_get_num_runner_tx_hash (NM_SETTING_TEAM (setting))) nm_setting_team_remove_runner_tx_hash (NM_SETTING_TEAM (setting), 0); - - for (iter = strv; strv && *iter; iter++) - nm_setting_team_add_runner_tx_hash (NM_SETTING_TEAM (setting), *iter); - - return TRUE; } -static gboolean -_validate_and_remove_team_runner_tx_hash (NMSettingTeam *setting, - const char *tx_hash, - GError **error) -{ - if (!nm_setting_team_remove_runner_tx_hash_by_value (setting, tx_hash)) { - g_set_error (error, 1, 0, - _("the property doesn't contain string '%s'"), - tx_hash); - return FALSE; +static void +_objlist_clear_all_fcn_team_link_watchers (NMSetting *setting) +{ + /* the same workaround as _multilist_clear_all_fcn_team_runner_tx_hash() above. + * + * Reproduce with: */ +#if 0 + $ (nmcli connection delete team0 ; :); \ + nmcli connection add type team con-name team0 ifname team0 autoconnect no \ + team.link-watchers 'name=arp_ping source-host=172.16.1.1 target-host=172.16.1.254, name=ethtool delay-up=3' && \ + echo ">>> FIRST:" && \ + PAGER= nmcli -o connection show team0 && \ + nmcli connection modify team0 team.link-watchers 'name=ethtool delay-up=4' && \ + echo ">>> AFTER:" && \ + PAGER= nmcli -o connection show team0 + + (nmcli connection delete team0-slave ; :); \ + nmcli connection add type ethernet con-name team0-slave master team0 slave-type team ifname eth0 autoconnect no \ + team-port.link-watchers 'name=arp_ping source-host=172.16.1.1 target-host=172.16.1.254, name=ethtool delay-up=3' && \ + echo ">>> FIRST:" && \ + PAGER= nmcli -o connection show team0-slave && \ + nmcli connection modify team0-slave team.link-watchers 'name=ethtool delay-up=4' && \ + echo ">>> AFTER:" && \ + PAGER= nmcli -o connection show team0-slave +#endif + /* See also: + * + * - https://cgit.freedesktop.org/NetworkManager/NetworkManager/commit/?id=72bf38cad6ca6033d0117bf67b0e726001922d8f + * - https://github.com/NetworkManager/NetworkManager/pull/318 + * - https://bugzilla.redhat.com/show_bug.cgi?id=1691619 + */ + + /* In this case, it appears both GObject reset and nm_setting_team*_clear_link_watchers() + * work (on their own). So, we might not need the workaround. + * Just to be sure, as something is not right with libnm here. */ + if (NM_IS_SETTING_TEAM (setting)) { + _gobject_property_reset (setting, NM_SETTING_TEAM_LINK_WATCHERS, FALSE); + nm_setting_team_clear_link_watchers (NM_SETTING_TEAM (setting)); + } else { + _gobject_property_reset (setting, NM_SETTING_TEAM_PORT_LINK_WATCHERS, FALSE); + nm_setting_team_port_clear_link_watchers (NM_SETTING_TEAM_PORT (setting)); } - - return TRUE; } -DEFINE_REMOVER_INDEX_OR_VALUE (_remove_fcn_team_runner_tx_hash, - NM_SETTING_TEAM, - nm_setting_team_get_num_runner_tx_hash, - nm_setting_team_remove_runner_tx_hash, - _validate_and_remove_team_runner_tx_hash) -static gconstpointer -_get_fcn_team_link_watchers (ARGS_GET_FCN) +static void +_objlist_obj_to_str_fcn_team_link_watchers (NMMetaAccessorGetType get_type, + NMSetting *setting, + guint idx, + GString *str) { - NMSettingTeam *s_team = NM_SETTING_TEAM (setting); - GString *printable; - guint num_watchers, i; NMTeamLinkWatcher *watcher; - char *watcher_str; - - RETURN_UNSUPPORTED_GET_TYPE (); - - printable = g_string_new (NULL); - - num_watchers = nm_setting_team_get_num_link_watchers (s_team); - for (i = 0; i < num_watchers; i++) { - watcher = nm_setting_team_get_link_watcher (s_team, i); - watcher_str = _dump_team_link_watcher (watcher); - if (watcher_str) { - if (printable->len > 0) - g_string_append (printable, ", "); - g_string_append (printable, watcher_str); - g_free (watcher_str); - } - } - - NM_SET_OUT (out_is_default, num_watchers == 0); - RETURN_STR_TO_FREE (g_string_free (printable, FALSE)); -} + gs_free char *s = NULL; -static gboolean -_set_fcn_team_link_watchers (ARGS_SET_FCN) -{ - gs_free const char **strv = NULL; - const char *const*iter; - NMTeamLinkWatcher *watcher; + if (NM_IS_SETTING_TEAM (setting)) + watcher = nm_setting_team_get_link_watcher (NM_SETTING_TEAM (setting), idx); + else + watcher = nm_setting_team_port_get_link_watcher (NM_SETTING_TEAM_PORT (setting), idx); - nm_setting_team_clear_link_watchers (NM_SETTING_TEAM (setting)); - strv = nm_utils_strsplit_set (value, ",", FALSE); - for (iter = strv; strv && *iter; iter++) { - watcher = _parse_team_link_watcher (*iter, error); - if (!watcher) - return FALSE; - nm_setting_team_add_link_watcher (NM_SETTING_TEAM (setting), watcher); - nm_team_link_watcher_unref (watcher); - } - return TRUE; + s = _dump_team_link_watcher (watcher); + if (s) + g_string_append (str, s); } static gboolean -_validate_and_remove_team_link_watcher (NMSettingTeam *setting, - const char *watcher_str, - GError **error) +_objlist_set_fcn_team_link_watchers (NMSetting *setting, + gboolean do_add, + const char *value, + GError **error) { - NMTeamLinkWatcher *watcher; - gboolean ret; + nm_auto_unref_team_link_watcher NMTeamLinkWatcher *watcher = NULL; - watcher = _parse_team_link_watcher (watcher_str, error); + watcher = _parse_team_link_watcher (value, error); if (!watcher) return FALSE; - - ret = nm_setting_team_remove_link_watcher_by_value (setting, watcher); - if (!ret) { - g_set_error (error, 1, 0, _("the property doesn't contain link watcher '%s'"), - watcher_str); - } - nm_team_link_watcher_unref (watcher); - return ret; -} -DEFINE_REMOVER_INDEX_OR_VALUE (_remove_fcn_team_link_watchers, - NM_SETTING_TEAM, - nm_setting_team_get_num_link_watchers, - nm_setting_team_remove_link_watcher, - _validate_and_remove_team_link_watcher) - -static gconstpointer -_get_fcn_team_port_link_watchers (ARGS_GET_FCN) -{ - NMSettingTeamPort *s_team_port = NM_SETTING_TEAM_PORT (setting); - GString *printable; - guint num_watchers, i; - NMTeamLinkWatcher *watcher; - char *watcher_str; - - RETURN_UNSUPPORTED_GET_TYPE (); - - printable = g_string_new (NULL); - - num_watchers = nm_setting_team_port_get_num_link_watchers (s_team_port); - for (i = 0; i < num_watchers; i++) { - watcher = nm_setting_team_port_get_link_watcher (s_team_port, i); - watcher_str = _dump_team_link_watcher (watcher); - if (watcher_str) { - if (printable->len > 0) - g_string_append (printable, ", "); - g_string_append (printable, watcher_str); - g_free (watcher_str); - } - } - - NM_SET_OUT (out_is_default, num_watchers == 0); - RETURN_STR_TO_FREE (g_string_free (printable, FALSE)); -} - -static gboolean -_set_fcn_team_port_link_watchers (ARGS_SET_FCN) -{ - gs_free const char **strv = NULL; - const char *const*iter; - NMTeamLinkWatcher *watcher; - - nm_setting_team_port_clear_link_watchers (NM_SETTING_TEAM_PORT (setting)); - strv = nm_utils_strsplit_set (value, ",", FALSE); - for (iter = strv; strv && *iter; iter++) { - watcher = _parse_team_link_watcher (*iter, error); - if (!watcher) - return FALSE; - nm_setting_team_port_add_link_watcher (NM_SETTING_TEAM_PORT (setting), watcher); - nm_team_link_watcher_unref (watcher); + if (NM_IS_SETTING_TEAM (setting)) { + if (do_add) + nm_setting_team_add_link_watcher (NM_SETTING_TEAM (setting), watcher); + else + nm_setting_team_remove_link_watcher_by_value (NM_SETTING_TEAM (setting), watcher); + } else { + if (do_add) + nm_setting_team_port_add_link_watcher (NM_SETTING_TEAM_PORT (setting), watcher); + else + nm_setting_team_port_remove_link_watcher_by_value (NM_SETTING_TEAM_PORT (setting), watcher); } return TRUE; } -static gboolean -_validate_and_remove_team_port_link_watcher (NMSettingTeamPort *setting, - const char *watcher_str, - GError **error) -{ - NMTeamLinkWatcher *watcher; - gboolean ret; - - watcher = _parse_team_link_watcher (watcher_str, error); - if (!watcher) - return FALSE; - - ret = nm_setting_team_port_remove_link_watcher_by_value (setting, watcher); - if (!ret) { - g_set_error (error, 1, 0, _("the property doesn't contain link watcher '%s'"), - watcher_str); - } - nm_team_link_watcher_unref (watcher); - return ret; -} -DEFINE_REMOVER_INDEX_OR_VALUE (_remove_fcn_team_port_link_watchers, - NM_SETTING_TEAM_PORT, - nm_setting_team_port_get_num_link_watchers, - nm_setting_team_port_remove_link_watcher, - _validate_and_remove_team_port_link_watcher) - static gconstpointer _get_fcn_vlan_flags (ARGS_GET_FCN) { @@ -4269,142 +3667,75 @@ _get_fcn_vlan_flags (ARGS_GET_FCN) RETURN_STR_TO_FREE (vlan_flags_to_string (flags, get_type)); } -static gconstpointer -_get_fcn_vlan_ingress_priority_map (ARGS_GET_FCN) +static NMVlanPriorityMap +_vlan_priority_map_type_from_property_info (const NMMetaPropertyInfo *property_info) { - NMSettingVlan *s_vlan = NM_SETTING_VLAN (setting); - char *str; + nm_assert (property_info); + nm_assert (property_info->setting_info == &nm_meta_setting_infos_editor[NM_META_SETTING_TYPE_VLAN]); + nm_assert (NM_IN_STRSET (property_info->property_name, NM_SETTING_VLAN_INGRESS_PRIORITY_MAP, + NM_SETTING_VLAN_EGRESS_PRIORITY_MAP)); - RETURN_UNSUPPORTED_GET_TYPE (); - - str = vlan_priorities_to_string (s_vlan, NM_VLAN_INGRESS_MAP); - NM_SET_OUT (out_is_default, !str || !str[0]); - RETURN_STR_TO_FREE (str); + return nm_streq (property_info->property_name, NM_SETTING_VLAN_INGRESS_PRIORITY_MAP) + ? NM_VLAN_INGRESS_MAP + : NM_VLAN_EGRESS_MAP; } static gconstpointer -_get_fcn_vlan_egress_priority_map (ARGS_GET_FCN) +_get_fcn_vlan_xgress_priority_map (ARGS_GET_FCN) { NMSettingVlan *s_vlan = NM_SETTING_VLAN (setting); char *str; RETURN_UNSUPPORTED_GET_TYPE (); - str = vlan_priorities_to_string (s_vlan, NM_VLAN_EGRESS_MAP); + str = vlan_priorities_to_string (s_vlan, _vlan_priority_map_type_from_property_info (property_info)); NM_SET_OUT (out_is_default, !str || !str[0]); RETURN_STR_TO_FREE (str); } static gboolean -_set_vlan_xgress_priority_map (NMSetting *setting, - const char *value, - NMVlanPriorityMap map_type, - GError **error) -{ - char **prio_map, **p; - - prio_map = _parse_vlan_priority_maps (value, map_type, error); - if (!prio_map) - return FALSE; - - for (p = prio_map; p && *p; p++) - nm_setting_vlan_add_priority_str (NM_SETTING_VLAN (setting), map_type, *p); - - g_strfreev (prio_map); - return TRUE; -} - -static gboolean -_set_fcn_vlan_ingress_priority_map (ARGS_SET_FCN) -{ - return _set_vlan_xgress_priority_map (setting, value, NM_VLAN_INGRESS_MAP, error); -} - -static gboolean -_set_fcn_vlan_egress_priority_map (ARGS_SET_FCN) +_set_fcn_vlan_xgress_priority_map (ARGS_SET_FCN) { - return _set_vlan_xgress_priority_map (setting, value, NM_VLAN_EGRESS_MAP, error); -} + NMVlanPriorityMap map_type = _vlan_priority_map_type_from_property_info (property_info); + gs_free const char **prio_map = NULL; + gsize i, len; -static gboolean -_remove_vlan_xgress_priority_map (const NMMetaEnvironment *environment, - gpointer environment_user_data, - NMSetting *setting, - const NMMetaPropertyInfo *property_info, - const char *value, - guint32 idx, - NMVlanPriorityMap map_type, - GError **error) -{ - guint32 num; + if (_SET_FCN_DO_RESET_DEFAULT_WITH_SUPPORTS_REMOVE (property_info, modifier, value)) { + nm_setting_vlan_clear_priorities (NM_SETTING_VLAN (setting), map_type); + return TRUE; + } - /* If value != NULL, remove by value */ - if (value) { - gboolean ret; - char **prio_map; - gs_free char *v = g_strdup (value); + prio_map = _value_strsplit (value, VALUE_STRSPLIT_MODE_STRIPPED, &len); - prio_map = _parse_vlan_priority_maps (v, map_type, error); - if (!prio_map) + for (i = 0; i < len; i++) { + if (!nm_utils_vlan_priority_map_parse_str (map_type, + prio_map[i], + _SET_FCN_DO_REMOVE (modifier, value), + NULL, + NULL, + NULL)) { + g_set_error (error, 1, 0, _("invalid priority map '%s'"), prio_map[i]); return FALSE; - if (prio_map[1]) { - _env_warn_fcn (environment, environment_user_data, - NM_META_ENV_WARN_LEVEL_WARN, - N_("only one mapping at a time is supported; taking the first one (%s)"), - prio_map[0]); } - ret = nm_setting_vlan_remove_priority_str_by_value (NM_SETTING_VLAN (setting), - map_type, - prio_map[0]); - - if (!ret) - g_set_error (error, 1, 0, _("the property doesn't contain mapping '%s'"), prio_map[0]); - g_strfreev (prio_map); - return ret; } - /* Else remove by index */ - num = nm_setting_vlan_get_num_priorities (NM_SETTING_VLAN (setting), map_type); - if (num == 0) { - g_set_error_literal (error, 1, 0, _("no priority to remove")); - return FALSE; - } - if (idx >= num) { - g_set_error (error, 1, 0, _("index '%d' is not in the range of <0-%d>"), - idx, num - 1); - return FALSE; - } + if (_SET_FCN_DO_SET_ALL (modifier, value)) + nm_setting_vlan_clear_priorities (NM_SETTING_VLAN (setting), map_type); - nm_setting_vlan_remove_priority (NM_SETTING_VLAN (setting), map_type, idx); + for (i = 0; i < len; i++) { + if (_SET_FCN_DO_REMOVE (modifier, value)) { + nm_setting_vlan_remove_priority_str_by_value (NM_SETTING_VLAN (setting), + map_type, + prio_map[i]); + } else { + nm_setting_vlan_add_priority_str (NM_SETTING_VLAN (setting), + map_type, + prio_map[i]); + } + } return TRUE; } -static gboolean -_remove_fcn_vlan_ingress_priority_map (ARGS_REMOVE_FCN) -{ - return _remove_vlan_xgress_priority_map (environment, - environment_user_data, - setting, - property_info, - value, - idx, - NM_VLAN_INGRESS_MAP, - error); -} - -static gboolean -_remove_fcn_vlan_egress_priority_map (ARGS_REMOVE_FCN) -{ - return _remove_vlan_xgress_priority_map (environment, - environment_user_data, - setting, - property_info, - value, - idx, - NM_VLAN_EGRESS_MAP, - error); -} - static gconstpointer _get_fcn_vpn_data (ARGS_GET_FCN) { @@ -4433,65 +3764,31 @@ _get_fcn_vpn_secrets (ARGS_GET_FCN) RETURN_STR_TO_FREE (g_string_free (secret_str, FALSE)); } -static const char * -_validate_vpn_hash_value (const char *option, const char *value, GError **error) +static gboolean +_optionlist_set_fcn_vpn_data (NMSetting *setting, + const char *option, + const char *value, + GError **error) { - /* nm_setting_vpn_add_data_item() and nm_setting_vpn_add_secret() does not - * allow empty strings */ - if (!value || !*value) { - g_set_error (error, 1, 0, _("'%s' cannot be empty"), option); - return NULL; - } - return value; + if (value) + nm_setting_vpn_add_data_item (NM_SETTING_VPN (setting), option, value); + else + nm_setting_vpn_remove_data_item (NM_SETTING_VPN (setting), option); + return TRUE; } -DEFINE_SETTER_OPTIONS (_set_fcn_vpn_data, - NM_SETTING_VPN, - NMSettingVpn, - nm_setting_vpn_add_data_item, - NULL, - _validate_vpn_hash_value) -DEFINE_REMOVER_OPTION (_remove_fcn_vpn_data, - NM_SETTING_VPN, - nm_setting_vpn_remove_data_item) - -DEFINE_SETTER_OPTIONS (_set_fcn_vpn_secrets, - NM_SETTING_VPN, - NMSettingVpn, - nm_setting_vpn_add_secret, - NULL, - _validate_vpn_hash_value) -DEFINE_REMOVER_OPTION (_remove_fcn_vpn_secrets, - NM_SETTING_VPN, - nm_setting_vpn_remove_secret) - -DEFINE_SETTER_MAC_BLACKLIST (_set_fcn_wired_mac_address_blacklist, - NM_SETTING_WIRED, - nm_setting_wired_add_mac_blacklist_item) - static gboolean -_validate_and_remove_wired_mac_blacklist_item (NMSettingWired *setting, - const char *mac, - GError **error) +_optionlist_set_fcn_vpn_secrets (NMSetting *setting, + const char *option, + const char *value, + GError **error) { - gboolean ret; - guint8 buf[32]; - - if (!nm_utils_hwaddr_aton (mac, buf, ETH_ALEN)) { - g_set_error (error, 1, 0, _("'%s' is not a valid MAC address"), mac); - return FALSE; - } - - ret = nm_setting_wired_remove_mac_blacklist_item_by_value (setting, mac); - if (!ret) - g_set_error (error, 1, 0, _("the property doesn't contain MAC address '%s'"), mac); - return ret; + if (value) + nm_setting_vpn_add_secret (NM_SETTING_VPN (setting), option, value); + else + nm_setting_vpn_remove_secret (NM_SETTING_VPN (setting), option); + return TRUE; } -DEFINE_REMOVER_INDEX_OR_VALUE (_remove_fcn_wired_mac_address_blacklist, - NM_SETTING_WIRED, - nm_setting_wired_get_num_mac_blacklist_items, - nm_setting_wired_remove_mac_blacklist_item, - _validate_and_remove_wired_mac_blacklist_item) static gboolean _set_fcn_wired_s390_subchannels (ARGS_SET_FCN) @@ -4499,6 +3796,9 @@ _set_fcn_wired_s390_subchannels (ARGS_SET_FCN) gs_free const char **strv = NULL; gsize len; + if (_SET_FCN_DO_RESET_DEFAULT (property_info, modifier, value)) + return _gobject_property_reset_default (setting, property_info->property_name); + strv = nm_utils_strsplit_set (value, " ,\t", FALSE); len = NM_PTRARRAY_LEN (strv); if (len != 2 && len != 3) { @@ -4511,28 +3811,21 @@ _set_fcn_wired_s390_subchannels (ARGS_SET_FCN) return TRUE; } -static const char * -_validate_s390_option_value (const char *option, const char *value, GError **error) +static gboolean +_optionlist_set_fcn_wired_s390_options (NMSetting *setting, + const char *name, + const char *value, + GError **error) { - /* nm_setting_wired_add_s390_option() requires value len in <1,199> interval */ - if (!value || !*value || strlen (value) >= 200) { - g_set_error (error, 1, 0, _("'%s' string value should consist of 1 - 199 characters"), option); - return NULL; - } - return value; + if (value) + nm_setting_wired_add_s390_option (NM_SETTING_WIRED (setting), name, value); + else + nm_setting_wired_remove_s390_option (NM_SETTING_WIRED (setting), name); + return TRUE; } -DEFINE_SETTER_OPTIONS (_set_fcn_wired_s390_options, - NM_SETTING_WIRED, - NMSettingWired, - nm_setting_wired_add_s390_option, - nm_setting_wired_get_valid_s390_options, - _validate_s390_option_value) -DEFINE_REMOVER_OPTION (_remove_fcn_wired_s390_options, - NM_SETTING_WIRED, - nm_setting_wired_remove_s390_option) static const char *const* -_values_fcn__wired_s390_options (ARGS_VALUES_FCN) +_values_fcn_wired_s390_options (ARGS_VALUES_FCN) { return nm_setting_wired_get_valid_s390_options (NULL); } @@ -4579,7 +3872,8 @@ _set_fcn_wireless_channel (ARGS_SET_FCN) { unsigned long chan_int; - nm_assert (!error || !*error); + if (_SET_FCN_DO_RESET_DEFAULT (property_info, modifier, value)) + return _gobject_property_reset_default (setting, property_info->property_name); if (!nmc_string_to_uint (value, FALSE, 0, 0, &chan_int)) { g_set_error (error, 1, 0, _("'%s' is not a valid channel"), value); @@ -4596,33 +3890,21 @@ _set_fcn_wireless_channel (ARGS_SET_FCN) return TRUE; } -DEFINE_SETTER_MAC_BLACKLIST (_set_fcn_wireless_mac_address_blacklist, - NM_SETTING_WIRELESS, - nm_setting_wireless_add_mac_blacklist_item) - -static gboolean -_validate_and_remove_wifi_mac_blacklist_item (NMSettingWireless *setting, - const char *mac, - GError **error) +static const char * +_multilist_validate2_fcn_mac_addr (NMSetting *setting, + const char *item, + GError **error) { - gboolean ret; - guint8 buf[32]; + guint8 buf[ETH_ALEN]; - if (!nm_utils_hwaddr_aton (mac, buf, ETH_ALEN)) { - g_set_error (error, 1, 0, _("'%s' is not a valid MAC address"), mac); - return FALSE; + if (!nm_utils_hwaddr_aton (item, buf, ETH_ALEN)) { + nm_utils_error_set (error, NM_UTILS_ERROR_INVALID_ARGUMENT, + _("'%s' is not a valid MAC address"), item); + return NULL; } - ret = nm_setting_wireless_remove_mac_blacklist_item_by_value (setting, mac); - if (!ret) - g_set_error (error, 1, 0, _("the property doesn't contain MAC address '%s'"), mac); - return ret; + return item; } -DEFINE_REMOVER_INDEX_OR_VALUE (_remove_fcn_wireless_mac_address_blacklist, - NM_SETTING_WIRELESS, - nm_setting_wireless_get_num_mac_blacklist_items, - nm_setting_wireless_remove_mac_blacklist_item, - _validate_and_remove_wifi_mac_blacklist_item) static gconstpointer _get_fcn_wireless_security_wep_key (ARGS_GET_FCN) @@ -4644,114 +3926,6 @@ _get_fcn_wireless_security_wep_key (ARGS_GET_FCN) RETURN_STR_TO_FREE (key); } -static const char *wifi_sec_valid_protos[] = { "wpa", "rsn", NULL }; - -DEFINE_SETTER_STR_LIST_MULTI (check_and_add_wifi_sec_proto, - NM_SETTING_WIRELESS_SECURITY, - nm_setting_wireless_security_add_proto) - -static gboolean -_set_fcn_wireless_security_proto (ARGS_SET_FCN) -{ - return check_and_add_wifi_sec_proto (setting, property_info->property_name, value, wifi_sec_valid_protos, error); -} - -static gboolean -_validate_and_remove_wifi_sec_proto (NMSettingWirelessSecurity *setting, - const char *proto, - GError **error) -{ - gboolean ret; - const char *valid; - - valid = nmc_string_is_valid (proto, wifi_sec_valid_protos, error); - if (!valid) - return FALSE; - - ret = nm_setting_wireless_security_remove_proto_by_value (setting, proto); - if (!ret) - g_set_error (error, 1, 0, - _("the property doesn't contain protocol '%s'"), proto); - return ret; -} -DEFINE_REMOVER_INDEX_OR_VALUE (_remove_fcn_wireless_security_proto, - NM_SETTING_WIRELESS_SECURITY, - nm_setting_wireless_security_get_num_protos, - nm_setting_wireless_security_remove_proto, - _validate_and_remove_wifi_sec_proto) - -static const char *wifi_sec_valid_pairwises[] = { "tkip", "ccmp", NULL }; - -DEFINE_SETTER_STR_LIST_MULTI (check_and_add_wifi_sec_pairwise, - NM_SETTING_WIRELESS_SECURITY, - nm_setting_wireless_security_add_pairwise) - -static gboolean -_set_fcn_wireless_security_pairwise (ARGS_SET_FCN) -{ - return check_and_add_wifi_sec_pairwise (setting, property_info->property_name, value, wifi_sec_valid_pairwises, error); -} - -static gboolean -_validate_and_remove_wifi_sec_pairwise (NMSettingWirelessSecurity *setting, - const char *pairwise, - GError **error) -{ - gboolean ret; - const char *valid; - - valid = nmc_string_is_valid (pairwise, wifi_sec_valid_pairwises, error); - if (!valid) - return FALSE; - - ret = nm_setting_wireless_security_remove_pairwise_by_value (setting, pairwise); - if (!ret) - g_set_error (error, 1, 0, - _("the property doesn't contain protocol '%s'"), pairwise); - return ret; -} -DEFINE_REMOVER_INDEX_OR_VALUE (_remove_fcn_wireless_security_pairwise, - NM_SETTING_WIRELESS_SECURITY, - nm_setting_wireless_security_get_num_pairwise, - nm_setting_wireless_security_remove_pairwise, - _validate_and_remove_wifi_sec_pairwise) - -static const char *wifi_sec_valid_groups[] = { "wep40", "wep104", "tkip", "ccmp", NULL }; - -DEFINE_SETTER_STR_LIST_MULTI (check_and_add_wifi_sec_group, - NM_SETTING_WIRELESS_SECURITY, - nm_setting_wireless_security_add_group) - -static gboolean -_set_fcn_wireless_security_group (ARGS_SET_FCN) -{ - return check_and_add_wifi_sec_group (setting, property_info->property_name, value, wifi_sec_valid_groups, error); -} - -static gboolean -_validate_and_remove_wifi_sec_group (NMSettingWirelessSecurity *setting, - const char *group, - GError **error) -{ - gboolean ret; - const char *valid; - - valid = nmc_string_is_valid (group, wifi_sec_valid_groups, error); - if (!valid) - return FALSE; - - ret = nm_setting_wireless_security_remove_group_by_value (setting, group); - if (!ret) - g_set_error (error, 1, 0, - _("the property doesn't contain protocol '%s'"), group); - return ret; -} -DEFINE_REMOVER_INDEX_OR_VALUE (_remove_fcn_wireless_security_group, - NM_SETTING_WIRELESS_SECURITY, - nm_setting_wireless_security_get_num_groups, - nm_setting_wireless_security_remove_group, - _validate_and_remove_wifi_sec_group) - static gboolean _set_fcn_wireless_wep_key (ARGS_SET_FCN) { @@ -4761,6 +3935,11 @@ _set_fcn_wireless_wep_key (ARGS_SET_FCN) nm_assert (!error || !*error); + if (_SET_FCN_DO_RESET_DEFAULT (property_info, modifier, value)) { + g_object_set (setting, property_info->property_name, NULL, NULL); + return TRUE; + } + /* Get currently set type */ type = nm_setting_wireless_security_get_wep_key_type (NM_SETTING_WIRELESS_SECURITY (setting)); @@ -4872,11 +4051,16 @@ _get_fcn_ethtool (ARGS_GET_FCN) static gboolean _set_fcn_ethtool (ARGS_SET_FCN) { - gs_free char *value_clone = NULL; + gs_free char *value_to_free = NULL; NMTernary val; NMEthtoolID ethtool_id = property_info->property_typ_data->subtype.ethtool.ethtool_id; - value = nm_strstrip_avoid_copy (value, &value_clone); + if (_SET_FCN_DO_RESET_DEFAULT (property_info, modifier, value)) { + val = NM_TERNARY_DEFAULT; + goto set; + } + + value = nm_strstrip_avoid_copy (value, &value_to_free); if (NM_IN_STRSET (value, "1", "yes", "true", "on")) val = NM_TERNARY_TRUE; @@ -4891,6 +4075,7 @@ _set_fcn_ethtool (ARGS_SET_FCN) return FALSE; } +set: nm_setting_ethtool_set_feature (NM_SETTING_ETHTOOL (setting), nm_ethtool_data[ethtool_id]->optname, val); @@ -5082,12 +4267,58 @@ static const NMMetaPropertyType _pt_gobject_devices = { .complete_fcn = _complete_fcn_gobject_devices, }; +static const NMMetaPropertyType _pt_dcb_flags = { + .get_fcn = _get_fcn_dcb_flags, + .set_fcn = _set_fcn_dcb_flags, +}; + +static const NMMetaPropertyType _pt_dcb_bool = { + .get_fcn = _get_fcn_dcb_bool, + .set_fcn = _set_fcn_dcb_bool, +}; + +static const NMMetaPropertyType _pt_dcb = { + .get_fcn = _get_fcn_dcb, + .set_fcn = _set_fcn_dcb, +}; + +static const NMMetaPropertyType _pt_cert_8021x = { + .get_fcn = _get_fcn_cert_8021x, + .set_fcn = _set_fcn_cert_8021x, +}; + static const NMMetaPropertyType _pt_ethtool = { .get_fcn = _get_fcn_ethtool, .set_fcn = _set_fcn_ethtool, .complete_fcn = _complete_fcn_ethtool, }; +static const NMMetaPropertyType _pt_multilist = { + .get_fcn = _get_fcn_gobject, + .set_fcn = _set_fcn_multilist, + .set_supports_remove = TRUE, +}; + +static const NMMetaPropertyType _pt_objlist = { + .get_fcn = _get_fcn_objlist, + .set_fcn = _set_fcn_objlist, + .set_supports_remove = TRUE, +}; + +#define MULTILIST_GET_NUM_FCN_U32(type, func) (((func) == ((guint32 (*) (type * )) (func))) ? ((guint32 (*) (NMSetting * )) (func)) : NULL) +#define MULTILIST_GET_NUM_FCN_U(type, func) (((func) == ((guint (*) (type * )) (func))) ? ((guint (*) (NMSetting * )) (func)) : NULL) +#define MULTILIST_ADD_FCN(type, func) (((func) == ((gboolean (*) (type *, const char *)) (func))) ? ((gboolean (*) (NMSetting *, const char *)) (func)) : NULL) +#define MULTILIST_ADD2_FCN(type, func) (((func) == ((void (*) (type *, const char *)) (func))) ? ((void (*) (NMSetting *, const char *)) (func)) : NULL) +#define MULTILIST_REMOVE_BY_IDX_FCN_U32(type, func) (((func) == ((void (*) (type *, guint32 )) (func))) ? ((void (*) (NMSetting *, guint32 )) (func)) : NULL) +#define MULTILIST_REMOVE_BY_IDX_FCN_S(type, func) (((func) == ((void (*) (type *, int )) (func))) ? ((void (*) (NMSetting *, int )) (func)) : NULL) +#define MULTILIST_REMOVE_BY_IDX_FCN_U(type, func) (((func) == ((void (*) (type *, guint )) (func))) ? ((void (*) (NMSetting *, guint )) (func)) : NULL) +#define MULTILIST_REMOVE_BY_VALUE_FCN(type, func) (((func) == ((gboolean (*) (type *, const char *)) (func))) ? ((gboolean (*) (NMSetting *, const char *)) (func)) : NULL) + +#define OBJLIST_GET_NUM_FCN(type, func) (((func) == ((guint (*) (type * )) (func))) ? ((guint (*) (NMSetting * )) (func)) : NULL) +#define OBJLIST_CLEAR_ALL_FCN(type, func) (((func) == ((void (*) (type * )) (func))) ? ((void (*) (NMSetting * )) (func)) : NULL) +#define OBJLIST_REMOVE_BY_IDX_FCN_U(type, func) (((func) == ((void (*) (type *, guint )) (func))) ? ((void (*) (NMSetting *, guint )) (func)) : NULL) +#define OBJLIST_REMOVE_BY_IDX_FCN_S(type, func) (((func) == ((void (*) (type *, int )) (func))) ? ((void (*) (NMSetting *, int )) (func)) : NULL) + /*****************************************************************************/ #include "settings-docs.h" @@ -5112,11 +4343,6 @@ static const NMMetaPropertyType _pt_ethtool = { #define ENUM_VALUE_INFOS(...) (((const NMUtilsEnumValueInfo []) { __VA_ARGS__ { .nick = NULL, }, })) #define INT_VALUE_INFOS(...) (((const NMMetaUtilsIntValueInfo []) { __VA_ARGS__ { .nick = NULL, }, })) -#define GET_FCN_WITH_DEFAULT(type, func) \ - /* macro that returns @func as const (gboolean(*)(NMSetting*)) type, but checks - * that the actual type is (gboolean(*)(type *)). */ \ - ((gboolean (*) (NMSetting *)) ((sizeof (func == ((gboolean (*) (type *)) func))) ? func : func) ) - #define MTU_GET_FCN(type, func) \ /* macro that returns @func as const (guint32(*)(NMSetting*)) type, but checks * that the actual type is (guint32(*)(type *)). */ \ @@ -5174,12 +4400,14 @@ static const NMMetaPropertyInfo *const property_infos_6LOWPAN[] = { #define _CURRENT_NM_META_SETTING_TYPE NM_META_SETTING_TYPE_802_1X static const NMMetaPropertyInfo *const property_infos_802_1X[] = { PROPERTY_INFO_WITH_DESC (NM_SETTING_802_1X_EAP, - .property_type = DEFINE_PROPERTY_TYPE ( - .get_fcn = _get_fcn_gobject, - .set_fcn = _set_fcn_802_1x_eap, - .remove_fcn = _remove_fcn_802_1x_eap, - ), + .property_type = &_pt_multilist, .property_typ_data = DEFINE_PROPERTY_TYP_DATA ( + PROPERTY_TYP_DATA_SUBTYPE (multilist, + .get_num_fcn_u32 = MULTILIST_GET_NUM_FCN_U32 (NMSetting8021x, nm_setting_802_1x_get_num_eap_methods), + .add_fcn = MULTILIST_ADD_FCN (NMSetting8021x, nm_setting_802_1x_add_eap_method), + .remove_by_idx_fcn_u32 = MULTILIST_REMOVE_BY_IDX_FCN_U32 (NMSetting8021x, nm_setting_802_1x_remove_eap_method), + .remove_by_value_fcn = MULTILIST_REMOVE_BY_VALUE_FCN (NMSetting8021x, nm_setting_802_1x_remove_eap_method_by_value), + ), .values_static = NM_MAKE_STRV ("leap", "md5", "tls", "peap", "ttls", "sim", "fast", "pwd"), ), ), @@ -5198,9 +4426,9 @@ static const NMMetaPropertyInfo *const property_infos_802_1X[] = { " [file://]<file path>\n" "Note that nmcli does not support specifying certificates as raw blob data.\n" "Example: /home/cimrman/cacert.crt\n"), - .property_type = DEFINE_PROPERTY_TYPE ( - .get_fcn = _get_fcn_802_1x_ca_cert, - .set_fcn = _set_fcn_802_1x_ca_cert, + .property_type = &_pt_cert_8021x, + .property_typ_data = DEFINE_PROPERTY_TYP_DATA_SUBTYPE (cert_8021x, + .scheme_type = NM_SETTING_802_1X_SCHEME_TYPE_CA_CERT, ), ), PROPERTY_INFO_WITH_DESC (NM_SETTING_802_1X_CA_CERT_PASSWORD, @@ -5217,10 +4445,14 @@ static const NMMetaPropertyInfo *const property_infos_802_1X[] = { .property_type = &_pt_gobject_string, ), PROPERTY_INFO_WITH_DESC (NM_SETTING_802_1X_ALTSUBJECT_MATCHES, - .property_type = DEFINE_PROPERTY_TYPE ( - .get_fcn = _get_fcn_gobject, - .set_fcn = _set_fcn_802_1x_altsubject_matches, - .remove_fcn = _remove_fcn_802_1x_altsubject_matches, + .property_type = &_pt_multilist, + .property_typ_data = DEFINE_PROPERTY_TYP_DATA ( + PROPERTY_TYP_DATA_SUBTYPE (multilist, + .get_num_fcn_u32 = MULTILIST_GET_NUM_FCN_U32 (NMSetting8021x, nm_setting_802_1x_get_num_altsubject_matches), + .add_fcn = MULTILIST_ADD_FCN (NMSetting8021x, nm_setting_802_1x_add_altsubject_match), + .remove_by_idx_fcn_u32 = MULTILIST_REMOVE_BY_IDX_FCN_U32 (NMSetting8021x, nm_setting_802_1x_remove_altsubject_match), + .remove_by_value_fcn = MULTILIST_REMOVE_BY_VALUE_FCN (NMSetting8021x, nm_setting_802_1x_remove_altsubject_match_by_value), + ), ), ), PROPERTY_INFO_WITH_DESC (NM_SETTING_802_1X_DOMAIN_SUFFIX_MATCH, @@ -5232,9 +4464,9 @@ static const NMMetaPropertyInfo *const property_infos_802_1X[] = { " [file://]<file path>\n" "Note that nmcli does not support specifying certificates as raw blob data.\n" "Example: /home/cimrman/jara.crt\n"), - .property_type = DEFINE_PROPERTY_TYPE ( - .get_fcn = _get_fcn_802_1x_client_cert, - .set_fcn = _set_fcn_802_1x_client_cert, + .property_type = &_pt_cert_8021x, + .property_typ_data = DEFINE_PROPERTY_TYP_DATA_SUBTYPE (cert_8021x, + .scheme_type = NM_SETTING_802_1X_SCHEME_TYPE_CLIENT_CERT, ), ), PROPERTY_INFO_WITH_DESC (NM_SETTING_802_1X_CLIENT_CERT_PASSWORD, @@ -5290,9 +4522,9 @@ static const NMMetaPropertyInfo *const property_infos_802_1X[] = { " [file://]<file path>\n" "Note that nmcli does not support specifying certificates as raw blob data.\n" "Example: /home/cimrman/ca-zweite-phase.crt\n"), - .property_type = DEFINE_PROPERTY_TYPE ( - .get_fcn = _get_fcn_802_1x_phase2_ca_cert, - .set_fcn = _set_fcn_802_1x_phase2_ca_cert, + .property_type = &_pt_cert_8021x, + .property_typ_data = DEFINE_PROPERTY_TYP_DATA_SUBTYPE (cert_8021x, + .scheme_type = NM_SETTING_802_1X_SCHEME_TYPE_PHASE2_CA_CERT, ), ), PROPERTY_INFO_WITH_DESC (NM_SETTING_802_1X_PHASE2_CA_CERT_PASSWORD, @@ -5309,10 +4541,14 @@ static const NMMetaPropertyInfo *const property_infos_802_1X[] = { .property_type = &_pt_gobject_string, ), PROPERTY_INFO_WITH_DESC (NM_SETTING_802_1X_PHASE2_ALTSUBJECT_MATCHES, - .property_type = DEFINE_PROPERTY_TYPE ( - .get_fcn = _get_fcn_gobject, - .set_fcn = _set_fcn_802_1x_phase2_altsubject_matches, - .remove_fcn = _remove_fcn_802_1x_phase2_altsubject_matches, + .property_type = &_pt_multilist, + .property_typ_data = DEFINE_PROPERTY_TYP_DATA ( + PROPERTY_TYP_DATA_SUBTYPE (multilist, + .get_num_fcn_u32 = MULTILIST_GET_NUM_FCN_U32 (NMSetting8021x, nm_setting_802_1x_get_num_phase2_altsubject_matches), + .add_fcn = MULTILIST_ADD_FCN (NMSetting8021x, nm_setting_802_1x_add_phase2_altsubject_match), + .remove_by_idx_fcn_u32 = MULTILIST_REMOVE_BY_IDX_FCN_U32 (NMSetting8021x, nm_setting_802_1x_remove_phase2_altsubject_match), + .remove_by_value_fcn = MULTILIST_REMOVE_BY_VALUE_FCN (NMSetting8021x, nm_setting_802_1x_remove_phase2_altsubject_match_by_value), + ), ), ), PROPERTY_INFO_WITH_DESC (NM_SETTING_802_1X_PHASE2_DOMAIN_SUFFIX_MATCH, @@ -5325,9 +4561,9 @@ static const NMMetaPropertyInfo *const property_infos_802_1X[] = { " [file://]<file path>\n" "Note that nmcli does not support specifying certificates as raw blob data.\n" "Example: /home/cimrman/jara-zweite-phase.crt\n"), - .property_type = DEFINE_PROPERTY_TYPE ( - .get_fcn = _get_fcn_802_1x_phase2_client_cert, - .set_fcn = _set_fcn_802_1x_phase2_client_cert, + .property_type = &_pt_cert_8021x, + .property_typ_data = DEFINE_PROPERTY_TYP_DATA_SUBTYPE (cert_8021x, + .scheme_type = NM_SETTING_802_1X_SCHEME_TYPE_PHASE2_CLIENT_CERT, ), ), PROPERTY_INFO_WITH_DESC (NM_SETTING_802_1X_PHASE2_CLIENT_CERT_PASSWORD, @@ -5368,9 +4604,9 @@ static const NMMetaPropertyInfo *const property_infos_802_1X[] = { " [file://]<file path> [<password>]\n" "Note that nmcli does not support specifying private key as raw blob data.\n" "Example: /home/cimrman/jara-priv-key Dardanely\n"), - .property_type = DEFINE_PROPERTY_TYPE ( - .get_fcn = _get_fcn_802_1x_private_key, - .set_fcn = _set_fcn_802_1x_private_key, + .property_type = &_pt_cert_8021x, + .property_typ_data = DEFINE_PROPERTY_TYP_DATA_SUBTYPE (cert_8021x, + .scheme_type = NM_SETTING_802_1X_SCHEME_TYPE_PRIVATE_KEY, ), ), PROPERTY_INFO_WITH_DESC (NM_SETTING_802_1X_PRIVATE_KEY_PASSWORD, @@ -5386,9 +4622,9 @@ static const NMMetaPropertyInfo *const property_infos_802_1X[] = { " [file://]<file path> [<password>]\n" "Note that nmcli does not support specifying private key as raw blob data.\n" "Example: /home/cimrman/jara-priv-key Dardanely\n"), - .property_type = DEFINE_PROPERTY_TYPE ( - .get_fcn = _get_fcn_802_1x_phase2_private_key, - .set_fcn = _set_fcn_802_1x_phase2_private_key, + .property_type = &_pt_cert_8021x, + .property_typ_data = DEFINE_PROPERTY_TYP_DATA_SUBTYPE (cert_8021x, + .scheme_type = NM_SETTING_802_1X_SCHEME_TYPE_PHASE2_PRIVATE_KEY, ), ), PROPERTY_INFO_WITH_DESC (NM_SETTING_802_1X_PHASE2_PRIVATE_KEY_PASSWORD, @@ -5498,11 +4734,14 @@ static const NMMetaPropertyInfo property_info_BOND_OPTIONS = .property_type = DEFINE_PROPERTY_TYPE ( .describe_fcn = _describe_fcn_bond_options, .get_fcn = _get_fcn_bond_options, - .set_fcn = _set_fcn_bond_options, - .remove_fcn = _remove_fcn_bond_options, + .set_fcn = _set_fcn_optionlist, + .set_supports_remove = TRUE, .values_fcn = _values_fcn_bond_options, ), .property_typ_data = DEFINE_PROPERTY_TYP_DATA ( + PROPERTY_TYP_DATA_SUBTYPE (optionlist, + .set_fcn = _optionlist_set_fcn_bond_options, + ), .nested = &nm_meta_property_typ_data_bond, ), ); @@ -5714,8 +4953,17 @@ static const NMMetaPropertyInfo *const property_infos_CONNECTION[] = { "Example: alice bob charlie\n"), .property_type = DEFINE_PROPERTY_TYPE ( .get_fcn = _get_fcn_connection_permissions, - .set_fcn = _set_fcn_connection_permissions, - .remove_fcn = _remove_fcn_connection_permissions, + .set_fcn = _set_fcn_multilist, + .set_supports_remove = TRUE, + ), + .property_typ_data = DEFINE_PROPERTY_TYP_DATA ( + PROPERTY_TYP_DATA_SUBTYPE (multilist, + .get_num_fcn_u32 = MULTILIST_GET_NUM_FCN_U32 (NMSettingConnection, nm_setting_connection_get_num_permissions), + .add_fcn = _multilist_set_fcn_connection_permissions, + .remove_by_idx_fcn_u32 = MULTILIST_REMOVE_BY_IDX_FCN_U32 (NMSettingConnection, nm_setting_connection_remove_permission), + .remove_by_value_fcn = _multilist_remove_by_value_fcn_connection_permissions, + .validate2_fcn = _multilist_validate2_fcn_connection_permissions, + ), ), ), PROPERTY_INFO_WITH_DESC (NM_SETTING_CONNECTION_ZONE, @@ -5756,10 +5004,15 @@ static const NMMetaPropertyInfo *const property_infos_CONNECTION[] = { "VPNs as secondary connections at the moment.\n" "The items can be separated by commas or spaces.\n\n" "Example: private-openvpn, fe6ba5d8-c2fc-4aae-b2e3-97efddd8d9a7\n"), - .property_type = DEFINE_PROPERTY_TYPE ( - .get_fcn = _get_fcn_gobject, - .set_fcn = _set_fcn_connection_secondaries, - .remove_fcn = _remove_fcn_connection_secondaries, + .property_type = &_pt_multilist, + .property_typ_data = DEFINE_PROPERTY_TYP_DATA ( + PROPERTY_TYP_DATA_SUBTYPE (multilist, + .get_num_fcn_u32 = MULTILIST_GET_NUM_FCN_U32 (NMSettingConnection, nm_setting_connection_get_num_secondaries), + .add_fcn = MULTILIST_ADD_FCN (NMSettingConnection, nm_setting_connection_add_secondary), + .remove_by_idx_fcn_u32 = MULTILIST_REMOVE_BY_IDX_FCN_U32 (NMSettingConnection, nm_setting_connection_remove_secondary), + .remove_by_value_fcn = MULTILIST_REMOVE_BY_VALUE_FCN (NMSettingConnection, nm_setting_connection_remove_secondary_by_value), + .validate2_fcn = _multilist_validate2_fcn_uuid, + ), ), ), PROPERTY_INFO_WITH_DESC (NM_SETTING_CONNECTION_GATEWAY_PING_TIMEOUT, @@ -5819,10 +5072,7 @@ static const NMMetaPropertyInfo *const property_infos_CONNECTION[] = { #define _CURRENT_NM_META_SETTING_TYPE NM_META_SETTING_TYPE_DCB static const NMMetaPropertyInfo *const property_infos_DCB[] = { PROPERTY_INFO_WITH_DESC (NM_SETTING_DCB_APP_FCOE_FLAGS, - .property_type = DEFINE_PROPERTY_TYPE ( - .get_fcn = _get_fcn_dcb_app_fcoe_flags, - .set_fcn = _set_fcn_dcb_flags, - ), + .property_type = &_pt_dcb_flags, ), PROPERTY_INFO_WITH_DESC (NM_SETTING_DCB_APP_FCOE_PRIORITY, DEFINE_DCB_PROPRITY_PROPERTY_TYPE @@ -5835,69 +5085,73 @@ static const NMMetaPropertyInfo *const property_infos_DCB[] = { ), ), PROPERTY_INFO_WITH_DESC (NM_SETTING_DCB_APP_ISCSI_FLAGS, - .property_type = DEFINE_PROPERTY_TYPE ( - .get_fcn = _get_fcn_dcb_app_iscsi_flags, - .set_fcn = _set_fcn_dcb_flags, - ), + .property_type = &_pt_dcb_flags, ), PROPERTY_INFO_WITH_DESC (NM_SETTING_DCB_APP_ISCSI_PRIORITY, DEFINE_DCB_PROPRITY_PROPERTY_TYPE ), PROPERTY_INFO_WITH_DESC (NM_SETTING_DCB_APP_FIP_FLAGS, - .property_type = DEFINE_PROPERTY_TYPE ( - .get_fcn = _get_fcn_dcb_app_fip_flags, - .set_fcn = _set_fcn_dcb_flags, - ), + .property_type = &_pt_dcb_flags, ), PROPERTY_INFO_WITH_DESC (NM_SETTING_DCB_APP_FIP_PRIORITY, DEFINE_DCB_PROPRITY_PROPERTY_TYPE ), PROPERTY_INFO_WITH_DESC (NM_SETTING_DCB_PRIORITY_FLOW_CONTROL_FLAGS, - .property_type = DEFINE_PROPERTY_TYPE ( - .get_fcn = _get_fcn_dcb_priority_flow_control_flags, - .set_fcn = _set_fcn_dcb_flags, - ), + .property_type = &_pt_dcb_flags, ), PROPERTY_INFO_WITH_DESC (NM_SETTING_DCB_PRIORITY_FLOW_CONTROL, - .property_type = DEFINE_PROPERTY_TYPE ( - .get_fcn = _get_fcn_dcb_priority_flow_control, - .set_fcn = _set_fcn_dcb_priority_flow_control, + .property_type = &_pt_dcb_bool, + .property_typ_data = DEFINE_PROPERTY_TYP_DATA_SUBTYPE (dcb_bool, + .get_fcn = nm_setting_dcb_get_priority_flow_control, + .set_fcn = nm_setting_dcb_set_priority_flow_control, + .with_flow_control_flags = TRUE, ), ), PROPERTY_INFO_WITH_DESC (NM_SETTING_DCB_PRIORITY_GROUP_FLAGS, - .property_type = DEFINE_PROPERTY_TYPE ( - .get_fcn = _get_fcn_dcb_priority_group_flags, - .set_fcn = _set_fcn_dcb_flags, - ), + .property_type = &_pt_dcb_flags, ), PROPERTY_INFO_WITH_DESC (NM_SETTING_DCB_PRIORITY_GROUP_ID, - .property_type = DEFINE_PROPERTY_TYPE ( - .get_fcn = _get_fcn_dcb_priority_group_id, - .set_fcn = _set_fcn_dcb_priority_group_id, + .property_type = &_pt_dcb, + .property_typ_data = DEFINE_PROPERTY_TYP_DATA_SUBTYPE (dcb, + .get_fcn = nm_setting_dcb_get_priority_group_id, + .set_fcn = nm_setting_dcb_set_priority_group_id, + .max = 7, + .other = 15, ), ), PROPERTY_INFO_WITH_DESC (NM_SETTING_DCB_PRIORITY_GROUP_BANDWIDTH, - .property_type = DEFINE_PROPERTY_TYPE ( - .get_fcn = _get_fcn_dcb_priority_group_bandwidth, - .set_fcn = _set_fcn_dcb_priority_group_bandwidth, + .property_type = &_pt_dcb, + .property_typ_data = DEFINE_PROPERTY_TYP_DATA_SUBTYPE (dcb, + .get_fcn = nm_setting_dcb_get_priority_group_bandwidth, + .set_fcn = nm_setting_dcb_set_priority_group_bandwidth, + .max = 100, + .other = 0, + .is_percent = TRUE, ), ), PROPERTY_INFO_WITH_DESC (NM_SETTING_DCB_PRIORITY_BANDWIDTH, - .property_type = DEFINE_PROPERTY_TYPE ( - .get_fcn = _get_fcn_dcb_priority_bandwidth, - .set_fcn = _set_fcn_dcb_priority_bandwidth, + .property_type = &_pt_dcb, + .property_typ_data = DEFINE_PROPERTY_TYP_DATA_SUBTYPE (dcb, + .get_fcn = nm_setting_dcb_get_priority_bandwidth, + .set_fcn = nm_setting_dcb_set_priority_bandwidth, + .max = 100, + .other = 0, ), ), PROPERTY_INFO_WITH_DESC (NM_SETTING_DCB_PRIORITY_STRICT_BANDWIDTH, - .property_type = DEFINE_PROPERTY_TYPE ( - .get_fcn = _get_fcn_dcb_priority_strict, - .set_fcn = _set_fcn_dcb_priority_strict, + .property_type = &_pt_dcb_bool, + .property_typ_data = DEFINE_PROPERTY_TYP_DATA_SUBTYPE (dcb_bool, + .get_fcn = nm_setting_dcb_get_priority_strict_bandwidth, + .set_fcn = nm_setting_dcb_set_priority_strict_bandwidth, ), ), PROPERTY_INFO_WITH_DESC (NM_SETTING_DCB_PRIORITY_TRAFFIC_CLASS, - .property_type = DEFINE_PROPERTY_TYPE ( - .get_fcn = _get_fcn_dcb_priority_traffic_class, - .set_fcn = _set_fcn_dcb_priority_traffic_class, + .property_type = &_pt_dcb, + .property_typ_data = DEFINE_PROPERTY_TYP_DATA_SUBTYPE (dcb, + .get_fcn = nm_setting_dcb_get_priority_traffic_class, + .set_fcn = nm_setting_dcb_set_priority_traffic_class, + .max = 7, + .other = 0, ), ), NULL @@ -6090,37 +5344,53 @@ static const NMMetaPropertyInfo *const property_infos_IP4_CONFIG[] = { PROPERTY_INFO (NM_SETTING_IP_CONFIG_METHOD, DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_METHOD, .property_type = DEFINE_PROPERTY_TYPE ( .get_fcn = _get_fcn_gobject, - .set_fcn = _set_fcn_ip4_config_method, + .set_fcn = _set_fcn_ip_config_method, ), .property_typ_data = DEFINE_PROPERTY_TYP_DATA ( - .values_static = ipv4_valid_methods, + .values_static = NM_MAKE_STRV (NM_SETTING_IP4_CONFIG_METHOD_AUTO, + NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL, + NM_SETTING_IP4_CONFIG_METHOD_MANUAL, + NM_SETTING_IP4_CONFIG_METHOD_SHARED, + NM_SETTING_IP4_CONFIG_METHOD_DISABLED), ), ), PROPERTY_INFO (NM_SETTING_IP_CONFIG_DNS, DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DNS, .describe_message = N_("Enter a list of IPv4 addresses of DNS servers.\n\n" "Example: 8.8.8.8, 8.8.4.4\n"), - .property_type = DEFINE_PROPERTY_TYPE ( - .get_fcn = _get_fcn_gobject, - .set_fcn = _set_fcn_ip4_config_dns, - .remove_fcn = _remove_fcn_ipv4_config_dns, + .property_type = &_pt_multilist, + .property_typ_data = DEFINE_PROPERTY_TYP_DATA ( + PROPERTY_TYP_DATA_SUBTYPE (multilist, + .get_num_fcn_u = MULTILIST_GET_NUM_FCN_U (NMSettingIPConfig, nm_setting_ip_config_get_num_dns), + .add_fcn = MULTILIST_ADD_FCN (NMSettingIPConfig, nm_setting_ip_config_add_dns), + .remove_by_idx_fcn_s = MULTILIST_REMOVE_BY_IDX_FCN_S (NMSettingIPConfig, nm_setting_ip_config_remove_dns), + .remove_by_value_fcn = MULTILIST_REMOVE_BY_VALUE_FCN (NMSettingIPConfig, nm_setting_ip_config_remove_dns_by_value), + .validate2_fcn = _multilist_validate2_fcn_ip_config_dns, + ), ), ), PROPERTY_INFO (NM_SETTING_IP_CONFIG_DNS_SEARCH, DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DNS_SEARCH, - .property_type = DEFINE_PROPERTY_TYPE ( - .get_fcn = _get_fcn_gobject, - .set_fcn = _set_fcn_ip_config_dns_search, - .remove_fcn = _remove_fcn_ip_config_dns_search, + .property_type = &_pt_multilist, + .property_typ_data = DEFINE_PROPERTY_TYP_DATA ( + PROPERTY_TYP_DATA_SUBTYPE (multilist, + .get_num_fcn_u = MULTILIST_GET_NUM_FCN_U (NMSettingIPConfig, nm_setting_ip_config_get_num_dns_searches), + .add_fcn = MULTILIST_ADD_FCN (NMSettingIPConfig, nm_setting_ip_config_add_dns_search), + .remove_by_idx_fcn_s = MULTILIST_REMOVE_BY_IDX_FCN_S (NMSettingIPConfig, nm_setting_ip_config_remove_dns_search), + .remove_by_value_fcn = MULTILIST_REMOVE_BY_VALUE_FCN (NMSettingIPConfig, nm_setting_ip_config_remove_dns_search_by_value), + .validate_fcn = _multilist_validate_fcn_is_domain, + ), ), ), PROPERTY_INFO (NM_SETTING_IP_CONFIG_DNS_OPTIONS, DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DNS_OPTIONS, - .property_type = DEFINE_PROPERTY_TYPE ( - .get_fcn = _get_fcn_nmc_with_default, - .set_fcn = _set_fcn_ip_config_dns_options, - .remove_fcn = _remove_fcn_ip_config_dns_options, - ), - .property_typ_data = DEFINE_PROPERTY_TYP_DATA_SUBTYPE (get_with_default, - .fcn = GET_FCN_WITH_DEFAULT (NMSettingIPConfig, _dns_options_is_default), + .property_type = &_pt_multilist, + .property_typ_data = DEFINE_PROPERTY_TYP_DATA ( + PROPERTY_TYP_DATA_SUBTYPE (multilist, + .get_num_fcn_u = MULTILIST_GET_NUM_FCN_U (NMSettingIPConfig, nm_setting_ip_config_get_num_dns_options), + .add_fcn = _multilist_add_fcn_ip_config_dns_options, + .remove_by_idx_fcn_s = MULTILIST_REMOVE_BY_IDX_FCN_S (NMSettingIPConfig, nm_setting_ip_config_remove_dns_option), + .remove_by_value_fcn = MULTILIST_REMOVE_BY_VALUE_FCN (NMSettingIPConfig, nm_setting_ip_config_remove_dns_option_by_value), + ), + .is_default_fcn = _is_default_func_ip_config_dns_options, ), ), PROPERTY_INFO (NM_SETTING_IP_CONFIG_DNS_PRIORITY, DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_DNS_PRIORITY, @@ -6136,10 +5406,15 @@ static const NMMetaPropertyInfo *const property_infos_IP4_CONFIG[] = { " ip[/prefix], ip[/prefix],...\n" "Missing prefix is regarded as prefix of 32.\n\n" "Example: 192.168.1.5/24, 10.0.0.11/24\n"), - .property_type = DEFINE_PROPERTY_TYPE ( - .get_fcn = _get_fcn_ip_config_addresses, - .set_fcn = _set_fcn_ip4_config_addresses, - .remove_fcn = _remove_fcn_ipv4_config_addresses, + .property_type = &_pt_objlist, + .property_typ_data = DEFINE_PROPERTY_TYP_DATA ( + PROPERTY_TYP_DATA_SUBTYPE (objlist, + .get_num_fcn = OBJLIST_GET_NUM_FCN (NMSettingIPConfig, nm_setting_ip_config_get_num_addresses), + .clear_all_fcn = OBJLIST_CLEAR_ALL_FCN (NMSettingIPConfig, nm_setting_ip_config_clear_addresses), + .obj_to_str_fcn = _objlist_obj_to_str_fcn_ip_config_addresses, + .set_fcn = _objlist_set_fcn_ip_config_addresses, + .remove_by_idx_fcn_s = OBJLIST_REMOVE_BY_IDX_FCN_S (NMSettingIPConfig, nm_setting_ip_config_remove_address), + ), ), ), PROPERTY_INFO (NM_SETTING_IP_CONFIG_GATEWAY, DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_GATEWAY, @@ -6148,7 +5423,7 @@ static const NMMetaPropertyInfo *const property_infos_IP4_CONFIG[] = { .prompt = N_("IPv4 gateway [none]"), .property_type = DEFINE_PROPERTY_TYPE ( .get_fcn = _get_fcn_gobject, - .set_fcn = _set_fcn_ip4_config_gateway, + .set_fcn = _set_fcn_ip_config_gateway, ), ), PROPERTY_INFO (NM_SETTING_IP_CONFIG_ROUTES, DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_ROUTES, @@ -6160,10 +5435,16 @@ static const NMMetaPropertyInfo *const property_infos_IP4_CONFIG[] = { "Missing metric means default (NM/kernel will set a default value).\n\n" "Examples: 192.168.2.0/24 192.168.2.1 3, 10.1.0.0/16 10.0.0.254\n" " 10.1.2.0/24\n"), - .property_type = DEFINE_PROPERTY_TYPE ( - .get_fcn = _get_fcn_ip_config_routes, - .set_fcn = _set_fcn_ip4_config_routes, - .remove_fcn = _remove_fcn_ipv4_config_routes, + .property_type = &_pt_objlist, + .property_typ_data = DEFINE_PROPERTY_TYP_DATA ( + PROPERTY_TYP_DATA_SUBTYPE (objlist, + .get_num_fcn = OBJLIST_GET_NUM_FCN (NMSettingIPConfig, nm_setting_ip_config_get_num_routes), + .clear_all_fcn = OBJLIST_CLEAR_ALL_FCN (NMSettingIPConfig, nm_setting_ip_config_clear_routes), + .obj_to_str_fcn = _objlist_obj_to_str_fcn_ip_config_routes, + .set_fcn = _objlist_set_fcn_ip_config_routes, + .remove_by_idx_fcn_s = OBJLIST_REMOVE_BY_IDX_FCN_S (NMSettingIPConfig, nm_setting_ip_config_remove_route), + .delimit_pretty_with_semicolon = TRUE, + ), ), ), PROPERTY_INFO (NM_SETTING_IP_CONFIG_ROUTE_METRIC, DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_ROUTE_METRIC, @@ -6247,10 +5528,15 @@ static const NMMetaPropertyInfo *const property_infos_IP6_CONFIG[] = { PROPERTY_INFO (NM_SETTING_IP_CONFIG_METHOD, DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_METHOD, .property_type = DEFINE_PROPERTY_TYPE ( .get_fcn = _get_fcn_gobject, - .set_fcn = _set_fcn_ip6_config_method, + .set_fcn = _set_fcn_ip_config_method, ), .property_typ_data = DEFINE_PROPERTY_TYP_DATA ( - .values_static = ipv6_valid_methods, + .values_static = NM_MAKE_STRV (NM_SETTING_IP6_CONFIG_METHOD_IGNORE, + NM_SETTING_IP6_CONFIG_METHOD_AUTO, + NM_SETTING_IP6_CONFIG_METHOD_DHCP, + NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL, + NM_SETTING_IP6_CONFIG_METHOD_MANUAL, + NM_SETTING_IP6_CONFIG_METHOD_SHARED), ), ), PROPERTY_INFO (NM_SETTING_IP_CONFIG_DNS, DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DNS, @@ -6263,27 +5549,39 @@ static const NMMetaPropertyInfo *const property_infos_IP6_CONFIG[] = { "all other IPv6 configuration methods, these DNS " "servers are used as the only DNS servers for this connection.\n\n" "Example: 2607:f0d0:1002:51::4, 2607:f0d0:1002:51::1\n"), - .property_type = DEFINE_PROPERTY_TYPE ( - .get_fcn = _get_fcn_gobject, - .set_fcn = _set_fcn_ip6_config_dns, - .remove_fcn = _remove_fcn_ipv6_config_dns, + .property_type = &_pt_multilist, + .property_typ_data = DEFINE_PROPERTY_TYP_DATA ( + PROPERTY_TYP_DATA_SUBTYPE (multilist, + .get_num_fcn_u = MULTILIST_GET_NUM_FCN_U (NMSettingIPConfig, nm_setting_ip_config_get_num_dns), + .add_fcn = MULTILIST_ADD_FCN (NMSettingIPConfig, nm_setting_ip_config_add_dns), + .remove_by_idx_fcn_s = MULTILIST_REMOVE_BY_IDX_FCN_S (NMSettingIPConfig, nm_setting_ip_config_remove_dns), + .remove_by_value_fcn = MULTILIST_REMOVE_BY_VALUE_FCN (NMSettingIPConfig, nm_setting_ip_config_remove_dns_by_value), + .validate2_fcn = _multilist_validate2_fcn_ip_config_dns, + ), ), ), PROPERTY_INFO (NM_SETTING_IP_CONFIG_DNS_SEARCH, DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DNS_SEARCH, - .property_type = DEFINE_PROPERTY_TYPE ( - .get_fcn = _get_fcn_gobject, - .set_fcn = _set_fcn_ip_config_dns_search, - .remove_fcn = _remove_fcn_ip_config_dns_search, + .property_type = &_pt_multilist, + .property_typ_data = DEFINE_PROPERTY_TYP_DATA ( + PROPERTY_TYP_DATA_SUBTYPE (multilist, + .get_num_fcn_u = MULTILIST_GET_NUM_FCN_U (NMSettingIPConfig, nm_setting_ip_config_get_num_dns_searches), + .add_fcn = MULTILIST_ADD_FCN (NMSettingIPConfig, nm_setting_ip_config_add_dns_search), + .remove_by_idx_fcn_s = MULTILIST_REMOVE_BY_IDX_FCN_S (NMSettingIPConfig, nm_setting_ip_config_remove_dns_search), + .remove_by_value_fcn = MULTILIST_REMOVE_BY_VALUE_FCN (NMSettingIPConfig, nm_setting_ip_config_remove_dns_search_by_value), + .validate_fcn = _multilist_validate_fcn_is_domain, + ), ), ), PROPERTY_INFO (NM_SETTING_IP_CONFIG_DNS_OPTIONS, DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DNS_OPTIONS, - .property_type = DEFINE_PROPERTY_TYPE ( - .get_fcn = _get_fcn_nmc_with_default, - .set_fcn = _set_fcn_ip_config_dns_options, - .remove_fcn = _remove_fcn_ip_config_dns_options, - ), - .property_typ_data = DEFINE_PROPERTY_TYP_DATA_SUBTYPE (get_with_default, - .fcn = GET_FCN_WITH_DEFAULT (NMSettingIPConfig, _dns_options_is_default), + .property_type = &_pt_multilist, + .property_typ_data = DEFINE_PROPERTY_TYP_DATA ( + PROPERTY_TYP_DATA_SUBTYPE (multilist, + .get_num_fcn_u = MULTILIST_GET_NUM_FCN_U (NMSettingIPConfig, nm_setting_ip_config_get_num_dns_options), + .add_fcn = _multilist_add_fcn_ip_config_dns_options, + .remove_by_idx_fcn_s = MULTILIST_REMOVE_BY_IDX_FCN_S (NMSettingIPConfig, nm_setting_ip_config_remove_dns_option), + .remove_by_value_fcn = MULTILIST_REMOVE_BY_VALUE_FCN (NMSettingIPConfig, nm_setting_ip_config_remove_dns_option_by_value), + ), + .is_default_fcn = _is_default_func_ip_config_dns_options, ), ), PROPERTY_INFO (NM_SETTING_IP_CONFIG_DNS_PRIORITY, DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_DNS_PRIORITY, @@ -6299,10 +5597,15 @@ static const NMMetaPropertyInfo *const property_infos_IP6_CONFIG[] = { " ip[/prefix], ip[/prefix],...\n" "Missing prefix is regarded as prefix of 128.\n\n" "Example: 2607:f0d0:1002:51::4/64, 1050:0:0:0:5:600:300c:326b\n"), - .property_type = DEFINE_PROPERTY_TYPE ( - .get_fcn = _get_fcn_ip_config_addresses, - .set_fcn = _set_fcn_ip6_config_addresses, - .remove_fcn = _remove_fcn_ipv6_config_addresses, + .property_type = &_pt_objlist, + .property_typ_data = DEFINE_PROPERTY_TYP_DATA ( + PROPERTY_TYP_DATA_SUBTYPE (objlist, + .get_num_fcn = OBJLIST_GET_NUM_FCN (NMSettingIPConfig, nm_setting_ip_config_get_num_addresses), + .clear_all_fcn = OBJLIST_CLEAR_ALL_FCN (NMSettingIPConfig, nm_setting_ip_config_clear_addresses), + .obj_to_str_fcn = _objlist_obj_to_str_fcn_ip_config_addresses, + .set_fcn = _objlist_set_fcn_ip_config_addresses, + .remove_by_idx_fcn_s = OBJLIST_REMOVE_BY_IDX_FCN_S (NMSettingIPConfig, nm_setting_ip_config_remove_address), + ), ), ), PROPERTY_INFO (NM_SETTING_IP_CONFIG_GATEWAY, DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_GATEWAY, @@ -6311,7 +5614,7 @@ static const NMMetaPropertyInfo *const property_infos_IP6_CONFIG[] = { .prompt = N_("IPv6 gateway [none]"), .property_type = DEFINE_PROPERTY_TYPE ( .get_fcn = _get_fcn_gobject, - .set_fcn = _set_fcn_ip6_config_gateway, + .set_fcn = _set_fcn_ip_config_gateway, ), ), PROPERTY_INFO (NM_SETTING_IP_CONFIG_ROUTES, DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_ROUTES, @@ -6323,10 +5626,16 @@ static const NMMetaPropertyInfo *const property_infos_IP6_CONFIG[] = { "Missing metric means default (NM/kernel will set a default value).\n\n" "Examples: 2001:db8:beef:2::/64 2001:db8:beef::2, 2001:db8:beef:3::/64 2001:db8:beef::3 2\n" " abbe::/64 55\n"), - .property_type = DEFINE_PROPERTY_TYPE ( - .get_fcn = _get_fcn_ip_config_routes, - .set_fcn = _set_fcn_ip6_config_routes, - .remove_fcn = _remove_fcn_ipv6_config_routes, + .property_type = &_pt_objlist, + .property_typ_data = DEFINE_PROPERTY_TYP_DATA ( + PROPERTY_TYP_DATA_SUBTYPE (objlist, + .get_num_fcn = OBJLIST_GET_NUM_FCN (NMSettingIPConfig, nm_setting_ip_config_get_num_routes), + .clear_all_fcn = OBJLIST_CLEAR_ALL_FCN (NMSettingIPConfig, nm_setting_ip_config_clear_routes), + .obj_to_str_fcn = _objlist_obj_to_str_fcn_ip_config_routes, + .set_fcn = _objlist_set_fcn_ip_config_routes, + .remove_by_idx_fcn_s = OBJLIST_REMOVE_BY_IDX_FCN_S (NMSettingIPConfig, nm_setting_ip_config_remove_route), + .delimit_pretty_with_semicolon = TRUE, + ), ), ), PROPERTY_INFO (NM_SETTING_IP_CONFIG_ROUTE_METRIC, DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_ROUTE_METRIC, @@ -6581,8 +5890,17 @@ static const NMMetaPropertyInfo *const property_infos_MATCH[] = { PROPERTY_INFO_WITH_DESC (NM_SETTING_MATCH_INTERFACE_NAME, .property_type = DEFINE_PROPERTY_TYPE ( .get_fcn = _get_fcn_match_interface_name, - .set_fcn = _set_fcn_match_interface_name, - .remove_fcn = _remove_fcn_match_interface_name, + .set_fcn = _set_fcn_multilist, + .set_supports_remove = TRUE, + ), + .property_typ_data = DEFINE_PROPERTY_TYP_DATA ( + PROPERTY_TYP_DATA_SUBTYPE (multilist, + .get_num_fcn_u = MULTILIST_GET_NUM_FCN_U (NMSettingMatch, nm_setting_match_get_num_interface_names), + .add2_fcn = MULTILIST_ADD2_FCN (NMSettingMatch, nm_setting_match_add_interface_name), + .remove_by_idx_fcn_s = MULTILIST_REMOVE_BY_IDX_FCN_S (NMSettingMatch, nm_setting_match_remove_interface_name), + .remove_by_value_fcn = MULTILIST_REMOVE_BY_VALUE_FCN (NMSettingMatch, nm_setting_match_remove_interface_name_by_value), + .with_escaped_spaces = TRUE, + ), ), ), NULL @@ -6893,10 +6211,14 @@ static const NMMetaPropertyInfo *const property_infos_SRIOV[] = { .property_type = &_pt_gobject_int, ), PROPERTY_INFO_WITH_DESC (NM_SETTING_SRIOV_VFS, - .property_type = DEFINE_PROPERTY_TYPE ( - .get_fcn = _get_fcn_sriov_vfs, - .set_fcn = _set_fcn_sriov_vfs, - .remove_fcn = _remove_fcn_sriov_vfs, + .property_type = &_pt_objlist, + .property_typ_data = DEFINE_PROPERTY_TYP_DATA ( + PROPERTY_TYP_DATA_SUBTYPE (objlist, + .get_num_fcn = OBJLIST_GET_NUM_FCN (NMSettingSriov, nm_setting_sriov_get_num_vfs), + .clear_all_fcn = OBJLIST_CLEAR_ALL_FCN (NMSettingSriov, nm_setting_sriov_clear_vfs), + .obj_to_str_fcn = _objlist_obj_to_str_fcn_sriov_vfs, + .set_fcn = _objlist_set_fcn_sriov_vfs, + ), ), ), PROPERTY_INFO_WITH_DESC (NM_SETTING_SRIOV_AUTOPROBE_DRIVERS, @@ -6909,17 +6231,27 @@ static const NMMetaPropertyInfo *const property_infos_SRIOV[] = { #define _CURRENT_NM_META_SETTING_TYPE NM_META_SETTING_TYPE_TC_CONFIG static const NMMetaPropertyInfo *const property_infos_TC_CONFIG[] = { PROPERTY_INFO (NM_SETTING_TC_CONFIG_QDISCS, DESCRIBE_DOC_NM_SETTING_TC_CONFIG_QDISCS, - .property_type = DEFINE_PROPERTY_TYPE ( - .get_fcn = _get_fcn_tc_config_qdiscs, - .set_fcn = _set_fcn_tc_config_qdiscs, - .remove_fcn = _remove_fcn_tc_config_qdiscs, + .property_type = &_pt_objlist, + .property_typ_data = DEFINE_PROPERTY_TYP_DATA ( + PROPERTY_TYP_DATA_SUBTYPE (objlist, + .get_num_fcn = OBJLIST_GET_NUM_FCN (NMSettingTCConfig, nm_setting_tc_config_get_num_qdiscs), + .clear_all_fcn = OBJLIST_CLEAR_ALL_FCN (NMSettingTCConfig, nm_setting_tc_config_clear_qdiscs), + .obj_to_str_fcn = _objlist_obj_to_str_fcn_tc_config_qdiscs, + .set_fcn = _objlist_set_fcn_tc_config_qdiscs, + .remove_by_idx_fcn_u = OBJLIST_REMOVE_BY_IDX_FCN_U (NMSettingTCConfig, nm_setting_tc_config_remove_qdisc), + ), ), ), PROPERTY_INFO (NM_SETTING_TC_CONFIG_TFILTERS, DESCRIBE_DOC_NM_SETTING_TC_CONFIG_TFILTERS, - .property_type = DEFINE_PROPERTY_TYPE ( - .get_fcn = _get_fcn_tc_config_tfilters, - .set_fcn = _set_fcn_tc_config_tfilters, - .remove_fcn = _remove_fcn_tc_config_tfilters, + .property_type = &_pt_objlist, + .property_typ_data = DEFINE_PROPERTY_TYP_DATA ( + PROPERTY_TYP_DATA_SUBTYPE (objlist, + .get_num_fcn = OBJLIST_GET_NUM_FCN (NMSettingTCConfig, nm_setting_tc_config_get_num_tfilters), + .clear_all_fcn = OBJLIST_CLEAR_ALL_FCN (NMSettingTCConfig, nm_setting_tc_config_clear_tfilters), + .obj_to_str_fcn = _objlist_obj_to_str_fcn_tc_config_tfilters, + .set_fcn = _objlist_set_fcn_tc_config_tfilters, + .remove_by_idx_fcn_u = OBJLIST_REMOVE_BY_IDX_FCN_U (NMSettingTCConfig, nm_setting_tc_config_remove_tfilter), + ), ), ), NULL @@ -7002,10 +6334,17 @@ static const NMMetaPropertyInfo *const property_infos_TEAM[] = { ), ), PROPERTY_INFO_WITH_DESC (NM_SETTING_TEAM_RUNNER_TX_HASH, - .property_type = DEFINE_PROPERTY_TYPE ( - .get_fcn = _get_fcn_gobject, - .set_fcn = _set_fcn_team_runner_tx_hash, - .remove_fcn = _remove_fcn_team_runner_tx_hash, + .property_type = &_pt_multilist, + .property_typ_data = DEFINE_PROPERTY_TYP_DATA ( + PROPERTY_TYP_DATA_SUBTYPE (multilist, + .get_num_fcn_u = MULTILIST_GET_NUM_FCN_U (NMSettingTeam, nm_setting_team_get_num_runner_tx_hash), + .clear_all_fcn = _multilist_clear_all_fcn_team_runner_tx_hash, + .add_fcn = MULTILIST_ADD_FCN (NMSettingTeam, nm_setting_team_add_runner_tx_hash), + .remove_by_idx_fcn_u = MULTILIST_REMOVE_BY_IDX_FCN_U (NMSettingTeam, nm_setting_team_remove_runner_tx_hash), + .remove_by_value_fcn = MULTILIST_REMOVE_BY_VALUE_FCN (NMSettingTeam, nm_setting_team_remove_runner_tx_hash_by_value), + ), + .values_static = NM_MAKE_STRV ("eth", "vlan", "ipv4", "ipv6", "ip", + "l3", "tcp", "udp", "sctp", "l4"), ), ), PROPERTY_INFO_WITH_DESC (NM_SETTING_TEAM_RUNNER_TX_BALANCER, @@ -7065,10 +6404,15 @@ static const NMMetaPropertyInfo *const property_infos_TEAM[] = { ), PROPERTY_INFO_WITH_DESC (NM_SETTING_TEAM_LINK_WATCHERS, .describe_message = TEAM_LINK_WATCHERS_DESCRIBE_MESSAGE, - .property_type = DEFINE_PROPERTY_TYPE ( - .get_fcn = _get_fcn_team_link_watchers, - .set_fcn = _set_fcn_team_link_watchers, - .remove_fcn = _remove_fcn_team_link_watchers, + .property_type = &_pt_objlist, + .property_typ_data = DEFINE_PROPERTY_TYP_DATA ( + PROPERTY_TYP_DATA_SUBTYPE (objlist, + .get_num_fcn = OBJLIST_GET_NUM_FCN (NMSettingTeam, nm_setting_team_get_num_link_watchers), + .clear_all_fcn = _objlist_clear_all_fcn_team_link_watchers, + .obj_to_str_fcn = _objlist_obj_to_str_fcn_team_link_watchers, + .set_fcn = _objlist_set_fcn_team_link_watchers, + .remove_by_idx_fcn_u = OBJLIST_REMOVE_BY_IDX_FCN_U (NMSettingTeam, nm_setting_team_remove_link_watcher), + ), ), ), NULL @@ -7136,10 +6480,15 @@ static const NMMetaPropertyInfo *const property_infos_TEAM_PORT[] = { ), PROPERTY_INFO_WITH_DESC (NM_SETTING_TEAM_PORT_LINK_WATCHERS, .describe_message = TEAM_LINK_WATCHERS_DESCRIBE_MESSAGE, - .property_type = DEFINE_PROPERTY_TYPE ( - .get_fcn = _get_fcn_team_port_link_watchers, - .set_fcn = _set_fcn_team_port_link_watchers, - .remove_fcn = _remove_fcn_team_port_link_watchers, + .property_type = &_pt_objlist, + .property_typ_data = DEFINE_PROPERTY_TYP_DATA ( + PROPERTY_TYP_DATA_SUBTYPE (objlist, + .get_num_fcn = OBJLIST_GET_NUM_FCN (NMSettingTeamPort, nm_setting_team_port_get_num_link_watchers), + .clear_all_fcn = _objlist_clear_all_fcn_team_link_watchers, + .obj_to_str_fcn = _objlist_obj_to_str_fcn_team_link_watchers, + .set_fcn = _objlist_set_fcn_team_link_watchers, + .remove_by_idx_fcn_u = OBJLIST_REMOVE_BY_IDX_FCN_U (NMSettingTeamPort, nm_setting_team_port_remove_link_watcher), + ), ), ), NULL @@ -7224,9 +6573,9 @@ static const NMMetaPropertyInfo *const property_infos_VLAN[] = { .property_alias = "ingress", .prompt = N_("Ingress priority maps [none]"), .property_type = DEFINE_PROPERTY_TYPE ( - .get_fcn = _get_fcn_vlan_ingress_priority_map, - .set_fcn = _set_fcn_vlan_ingress_priority_map, - .remove_fcn = _remove_fcn_vlan_ingress_priority_map, + .get_fcn = _get_fcn_vlan_xgress_priority_map, + .set_fcn = _set_fcn_vlan_xgress_priority_map, + .set_supports_remove = TRUE, ), ), PROPERTY_INFO_WITH_DESC (NM_SETTING_VLAN_EGRESS_PRIORITY_MAP, @@ -7234,9 +6583,9 @@ static const NMMetaPropertyInfo *const property_infos_VLAN[] = { .property_alias = "egress", .prompt = N_("Egress priority maps [none]"), .property_type = DEFINE_PROPERTY_TYPE ( - .get_fcn = _get_fcn_vlan_egress_priority_map, - .set_fcn = _set_fcn_vlan_egress_priority_map, - .remove_fcn = _remove_fcn_vlan_egress_priority_map, + .get_fcn = _get_fcn_vlan_xgress_priority_map, + .set_fcn = _set_fcn_vlan_xgress_priority_map, + .set_supports_remove = TRUE, ), ), NULL @@ -7266,16 +6615,24 @@ static const NMMetaPropertyInfo *const property_infos_VPN[] = { PROPERTY_INFO_WITH_DESC (NM_SETTING_VPN_DATA, .property_type = DEFINE_PROPERTY_TYPE ( .get_fcn = _get_fcn_vpn_data, - .set_fcn = _set_fcn_vpn_data, - .remove_fcn = _remove_fcn_vpn_data, + .set_fcn = _set_fcn_optionlist, + .set_supports_remove = TRUE, + ), + .property_typ_data = DEFINE_PROPERTY_TYP_DATA_SUBTYPE (optionlist, + .set_fcn = _optionlist_set_fcn_vpn_data, + .no_empty_value = TRUE, ), ), PROPERTY_INFO_WITH_DESC (NM_SETTING_VPN_SECRETS, .is_secret = TRUE, .property_type = DEFINE_PROPERTY_TYPE ( .get_fcn = _get_fcn_vpn_secrets, - .set_fcn = _set_fcn_vpn_secrets, - .remove_fcn = _remove_fcn_vpn_secrets, + .set_fcn = _set_fcn_optionlist, + .set_supports_remove = TRUE, + ), + .property_typ_data = DEFINE_PROPERTY_TYP_DATA_SUBTYPE (optionlist, + .set_fcn = _optionlist_set_fcn_vpn_secrets, + .no_empty_value = TRUE, ), ), PROPERTY_INFO_WITH_DESC (NM_SETTING_VPN_PERSISTENT, @@ -7448,10 +6805,15 @@ static const NMMetaPropertyInfo *const property_infos_WIRED[] = { .property_type = &_pt_gobject_string, ), PROPERTY_INFO_WITH_DESC (NM_SETTING_WIRED_MAC_ADDRESS_BLACKLIST, - .property_type = DEFINE_PROPERTY_TYPE ( - .get_fcn = _get_fcn_gobject, - .set_fcn = _set_fcn_wired_mac_address_blacklist, - .remove_fcn = _remove_fcn_wired_mac_address_blacklist, + .property_type = &_pt_multilist, + .property_typ_data = DEFINE_PROPERTY_TYP_DATA ( + PROPERTY_TYP_DATA_SUBTYPE (multilist, + .get_num_fcn_u32 = MULTILIST_GET_NUM_FCN_U32 (NMSettingWired, nm_setting_wired_get_num_mac_blacklist_items), + .add_fcn = MULTILIST_ADD_FCN (NMSettingWired, nm_setting_wired_add_mac_blacklist_item), + .remove_by_idx_fcn_u32 = MULTILIST_REMOVE_BY_IDX_FCN_U32 (NMSettingWired, nm_setting_wired_remove_mac_blacklist_item), + .remove_by_value_fcn = MULTILIST_REMOVE_BY_VALUE_FCN (NMSettingWired, nm_setting_wired_remove_mac_blacklist_item_by_value), + .validate2_fcn = _multilist_validate2_fcn_mac_addr, + ), ), ), PROPERTY_INFO_WITH_DESC (NM_SETTING_WIRED_MTU, @@ -7482,9 +6844,13 @@ static const NMMetaPropertyInfo *const property_infos_WIRED[] = { .property_type = DEFINE_PROPERTY_TYPE ( .describe_fcn = _describe_fcn_wired_s390_options, .get_fcn = _get_fcn_gobject, - .set_fcn = _set_fcn_wired_s390_options, - .remove_fcn = _remove_fcn_wired_s390_options, - .values_fcn = _values_fcn__wired_s390_options, + .set_fcn = _set_fcn_optionlist, + .set_supports_remove = TRUE, + .values_fcn = _values_fcn_wired_s390_options, + ), + .property_typ_data = DEFINE_PROPERTY_TYP_DATA_SUBTYPE (optionlist, + .set_fcn = _optionlist_set_fcn_wired_s390_options, + .no_empty_value = TRUE, ), ), PROPERTY_INFO_WITH_DESC (NM_SETTING_WIRED_WAKE_ON_LAN, @@ -7612,10 +6978,15 @@ static const NMMetaPropertyInfo *const property_infos_WIRELESS[] = { .property_type = &_pt_gobject_string, ), PROPERTY_INFO_WITH_DESC (NM_SETTING_WIRELESS_MAC_ADDRESS_BLACKLIST, - .property_type = DEFINE_PROPERTY_TYPE ( - .get_fcn = _get_fcn_gobject, - .set_fcn = _set_fcn_wireless_mac_address_blacklist, - .remove_fcn = _remove_fcn_wireless_mac_address_blacklist, + .property_type = &_pt_multilist, + .property_typ_data = DEFINE_PROPERTY_TYP_DATA ( + PROPERTY_TYP_DATA_SUBTYPE (multilist, + .get_num_fcn_u32 = MULTILIST_GET_NUM_FCN_U32 (NMSettingWireless, nm_setting_wireless_get_num_mac_blacklist_items), + .add_fcn = MULTILIST_ADD_FCN (NMSettingWireless, nm_setting_wireless_add_mac_blacklist_item), + .remove_by_idx_fcn_u32 = MULTILIST_REMOVE_BY_IDX_FCN_U32 (NMSettingWireless, nm_setting_wireless_remove_mac_blacklist_item), + .remove_by_value_fcn = MULTILIST_REMOVE_BY_VALUE_FCN (NMSettingWireless, nm_setting_wireless_remove_mac_blacklist_item_by_value), + .validate2_fcn = _multilist_validate2_fcn_mac_addr, + ), ), ), PROPERTY_INFO_WITH_DESC (NM_SETTING_WIRELESS_MAC_ADDRESS_RANDOMIZATION, @@ -7688,33 +7059,39 @@ static const NMMetaPropertyInfo *const property_infos_WIRELESS_SECURITY[] = { ), ), PROPERTY_INFO_WITH_DESC (NM_SETTING_WIRELESS_SECURITY_PROTO, - .property_type = DEFINE_PROPERTY_TYPE ( - .get_fcn = _get_fcn_gobject, - .set_fcn = _set_fcn_wireless_security_proto, - .remove_fcn = _remove_fcn_wireless_security_proto, - ), + .property_type = &_pt_multilist, .property_typ_data = DEFINE_PROPERTY_TYP_DATA ( - .values_static = wifi_sec_valid_protos, + PROPERTY_TYP_DATA_SUBTYPE (multilist, + .get_num_fcn_u32 = MULTILIST_GET_NUM_FCN_U32 (NMSettingWirelessSecurity, nm_setting_wireless_security_get_num_protos), + .add_fcn = MULTILIST_ADD_FCN (NMSettingWirelessSecurity, nm_setting_wireless_security_add_proto), + .remove_by_idx_fcn_u32 = MULTILIST_REMOVE_BY_IDX_FCN_U32 (NMSettingWirelessSecurity, nm_setting_wireless_security_remove_proto), + .remove_by_value_fcn = MULTILIST_REMOVE_BY_VALUE_FCN (NMSettingWirelessSecurity, nm_setting_wireless_security_remove_proto_by_value), + ), + .values_static = NM_MAKE_STRV ("wpa", "rsn"), ), ), PROPERTY_INFO_WITH_DESC (NM_SETTING_WIRELESS_SECURITY_PAIRWISE, - .property_type = DEFINE_PROPERTY_TYPE ( - .get_fcn = _get_fcn_gobject, - .set_fcn = _set_fcn_wireless_security_pairwise, - .remove_fcn = _remove_fcn_wireless_security_pairwise, - ), + .property_type = &_pt_multilist, .property_typ_data = DEFINE_PROPERTY_TYP_DATA ( - .values_static = wifi_sec_valid_pairwises, + PROPERTY_TYP_DATA_SUBTYPE (multilist, + .get_num_fcn_u32 = MULTILIST_GET_NUM_FCN_U32 (NMSettingWirelessSecurity, nm_setting_wireless_security_get_num_pairwise), + .add_fcn = MULTILIST_ADD_FCN (NMSettingWirelessSecurity, nm_setting_wireless_security_add_pairwise), + .remove_by_idx_fcn_u32 = MULTILIST_REMOVE_BY_IDX_FCN_U32 (NMSettingWirelessSecurity, nm_setting_wireless_security_remove_pairwise), + .remove_by_value_fcn = MULTILIST_REMOVE_BY_VALUE_FCN (NMSettingWirelessSecurity, nm_setting_wireless_security_remove_pairwise_by_value), + ), + .values_static = NM_MAKE_STRV ("tkip", "ccmp"), ), ), PROPERTY_INFO_WITH_DESC (NM_SETTING_WIRELESS_SECURITY_GROUP, - .property_type = DEFINE_PROPERTY_TYPE ( - .get_fcn = _get_fcn_gobject, - .set_fcn = _set_fcn_wireless_security_group, - .remove_fcn = _remove_fcn_wireless_security_group, - ), + .property_type = &_pt_multilist, .property_typ_data = DEFINE_PROPERTY_TYP_DATA ( - .values_static = wifi_sec_valid_groups, + PROPERTY_TYP_DATA_SUBTYPE (multilist, + .get_num_fcn_u32 = MULTILIST_GET_NUM_FCN_U32 (NMSettingWirelessSecurity, nm_setting_wireless_security_get_num_groups), + .add_fcn = MULTILIST_ADD_FCN (NMSettingWirelessSecurity, nm_setting_wireless_security_add_group), + .remove_by_idx_fcn_u32 = MULTILIST_REMOVE_BY_IDX_FCN_U32 (NMSettingWirelessSecurity, nm_setting_wireless_security_remove_group), + .remove_by_value_fcn = MULTILIST_REMOVE_BY_VALUE_FCN (NMSettingWirelessSecurity, nm_setting_wireless_security_remove_group_by_value), + ), + .values_static = NM_MAKE_STRV ("wep40", "wep104", "tkip", "ccmp"), ), ), PROPERTY_INFO_WITH_DESC (NM_SETTING_WIRELESS_SECURITY_PMF, diff --git a/clients/common/nm-meta-setting-desc.h b/clients/common/nm-meta-setting-desc.h index e3f9d230ee..cc94c2547d 100644 --- a/clients/common/nm-meta-setting-desc.h +++ b/clients/common/nm-meta-setting-desc.h @@ -209,15 +209,9 @@ struct _NMMetaPropertyType { const NMMetaEnvironment *environment, gpointer environment_user_data, NMSetting *setting, + char modifier, const char *value, GError **error); - gboolean (*remove_fcn) (const NMMetaPropertyInfo *property_info, - const NMMetaEnvironment *environment, - gpointer environment_user_data, - NMSetting *setting, - const char *option, - guint32 idx, - GError **error); const char *const*(*values_fcn) (const NMMetaPropertyInfo *property_info, char ***out_to_free); @@ -228,6 +222,10 @@ struct _NMMetaPropertyType { const NMMetaOperationContext *operation_context, const char *text, char ***out_to_free); + + /* Whether set_fcn() supports the '-' modifier. That is, whether the property + * is a list type. */ + bool set_supports_remove:1; }; struct _NMUtilsEnumValueInfo; @@ -245,9 +243,6 @@ typedef struct { struct _NMMetaPropertyTypData { union { struct { - gboolean (*fcn) (NMSetting *setting); - } get_with_default; - struct { GType (*get_gtype) (void); int min; int max; @@ -272,15 +267,77 @@ struct _NMMetaPropertyTypData { bool legacy_format:1; } gobject_bytes; struct { + guint32 (*get_num_fcn_u32) (NMSetting *setting); + guint (*get_num_fcn_u) (NMSetting *setting); + void (*clear_all_fcn) (NMSetting *setting); + gboolean (*add_fcn) (NMSetting *setting, + const char *item); + void (*add2_fcn) (NMSetting *setting, + const char *item); + const char *(*validate_fcn) (const char *item, GError **error); + const char *(*validate2_fcn) (NMSetting *setting, const char *item, GError **error); + void (*remove_by_idx_fcn_u32) (NMSetting *setting, guint32 idx); + void (*remove_by_idx_fcn_u) (NMSetting *setting, guint idx); + void (*remove_by_idx_fcn_s) (NMSetting *setting, int idx); + gboolean (*remove_by_value_fcn) (NMSetting *setting, const char *item); + + /* if true, separate the list by space and allow backslash escaping. */ + bool with_escaped_spaces:1; + } multilist; + struct { + guint (*get_num_fcn) (NMSetting *setting); + void (*obj_to_str_fcn) (NMMetaAccessorGetType get_type, + NMSetting *setting, + guint idx, + GString *str); + gboolean (*set_fcn) (NMSetting *setting, + gboolean do_add /* or else remove. */, + const char *value, + GError **error); + void (*clear_all_fcn) (NMSetting *setting); + void (*remove_by_idx_fcn_u) (NMSetting *setting, guint idx); + void (*remove_by_idx_fcn_s) (NMSetting *setting, int idx); + bool delimit_pretty_with_semicolon:1; + } objlist; + struct { + gboolean (*set_fcn) (NMSetting *setting, + const char *option, + const char *value, + GError **error); + bool no_empty_value:1; + } optionlist; + struct { guint32 (*get_fcn) (NMSetting *setting); } mtu; struct { + NMSetting8021xSchemeType scheme_type; + } cert_8021x; + struct { NMMetaPropertyTypeMacMode mode; } mac; struct { + guint (*get_fcn) (NMSettingDcb *setting, + guint user_priority); + void (*set_fcn) (NMSettingDcb *setting, + guint id, + guint value); + guint max; + guint other; + bool is_percent:1; + } dcb; + struct { + gboolean (*get_fcn) (NMSettingDcb *s_dcb, + guint priority); + void (*set_fcn) (NMSettingDcb *setting, + guint user_priority, + gboolean enabled); + bool with_flow_control_flags:1; + } dcb_bool; + struct { NMEthtoolID ethtool_id; } ethtool; } subtype; + gboolean (*is_default_fcn) (NMSetting *setting); const char *const*values_static; const NMMetaPropertyTypDataNested *nested; NMMetaPropertyTypFlags typ_flags; diff --git a/libnm-core/meson.build b/libnm-core/meson.build index d10dd1c551..beee290e78 100644 --- a/libnm-core/meson.build +++ b/libnm-core/meson.build @@ -189,6 +189,7 @@ libnm_core_sources_all = libnm_core_sources libnm_core_sources_all += libnm_core_enum libnm_core_sources_all += shared_nm_meta_setting_c libnm_core_sources_all += shared_nm_ethtool_utils_c +libnm_core_sources_all += shared_nm_libnm_core_utils_c libnm_core_sources_all += [version_header] libnm_core = static_library( diff --git a/libnm-core/nm-core-internal.h b/libnm-core/nm-core-internal.h index cf2be4a24d..394ecb5677 100644 --- a/libnm-core/nm-core-internal.h +++ b/libnm-core/nm-core-internal.h @@ -88,6 +88,7 @@ #include "nm-utils.h" #include "nm-vpn-dbus-interface.h" #include "nm-vpn-editor-plugin.h" +#include "nm-libnm-core-utils.h" /* IEEE 802.1D-1998 timer values */ #define NM_BR_MIN_HELLO_TIME 1 @@ -264,14 +265,6 @@ GHashTable *_nm_ip_route_get_attributes_direct (NMIPRoute *route); NMSriovVF *_nm_utils_sriov_vf_from_strparts (const char *index, const char *detail, gboolean ignore_unknown, GError **error); gboolean _nm_sriov_vf_attribute_validate_all (const NMSriovVF *vf, GError **error); -static inline void -_nm_auto_ip_route_unref (NMIPRoute **v) -{ - if (*v) - nm_ip_route_unref (*v); -} -#define nm_auto_ip_route_unref nm_auto (_nm_auto_ip_route_unref) - GPtrArray *_nm_utils_copy_array (const GPtrArray *array, NMUtilsCopyFunc copy_func, GDestroyNotify free_func); @@ -554,18 +547,6 @@ gboolean _nm_utils_team_config_set (char **conf, /*****************************************************************************/ -static inline int -nm_setting_ip_config_get_addr_family (NMSettingIPConfig *s_ip) -{ - if (NM_IS_SETTING_IP4_CONFIG (s_ip)) - return AF_INET; - if (NM_IS_SETTING_IP6_CONFIG (s_ip)) - return AF_INET6; - g_return_val_if_reached (AF_UNSPEC); -} - -/*****************************************************************************/ - guint32 _nm_utils_parse_tc_handle (const char *str, GError **error); void _nm_utils_string_append_tc_parent (GString *string, @@ -763,9 +744,6 @@ gboolean _nm_connection_find_secret (NMConnection *self, /*****************************************************************************/ -#define nm_auto_unref_wgpeer nm_auto(_nm_auto_unref_wgpeer) -NM_AUTO_DEFINE_FCN0 (NMWireGuardPeer *, _nm_auto_unref_wgpeer, nm_wireguard_peer_unref) - gboolean nm_utils_base64secret_normalize (const char *base64_key, gsize required_key_len, char **out_base64_key_norm); diff --git a/libnm-core/nm-setting-connection.c b/libnm-core/nm-setting-connection.c index e8d008e33d..e4fb70c247 100644 --- a/libnm-core/nm-setting-connection.c +++ b/libnm-core/nm-setting-connection.c @@ -397,8 +397,7 @@ nm_setting_connection_add_permission (NMSettingConnection *setting, GSList *iter; g_return_val_if_fail (NM_IS_SETTING_CONNECTION (setting), FALSE); - g_return_val_if_fail (ptype, FALSE); - g_return_val_if_fail (strlen (ptype) > 0, FALSE); + g_return_val_if_fail (ptype && ptype[0], FALSE); g_return_val_if_fail (detail == NULL, FALSE); /* Only "user" for now... */ @@ -470,9 +469,9 @@ nm_setting_connection_remove_permission_by_value (NMSettingConnection *setting, GSList *iter; g_return_val_if_fail (NM_IS_SETTING_CONNECTION (setting), FALSE); - g_return_val_if_fail (ptype, FALSE); - g_return_val_if_fail (strlen (ptype) > 0, FALSE); + g_return_val_if_fail (ptype && ptype[0], FALSE); g_return_val_if_fail (detail == NULL, FALSE); + g_return_val_if_fail (pitem != NULL, FALSE); /* Only "user" for now... */ g_return_val_if_fail (strcmp (ptype, "user") == 0, FALSE); diff --git a/libnm-core/nm-setting-team.c b/libnm-core/nm-setting-team.c index ec9d2ba02e..9fd070c1fe 100644 --- a/libnm-core/nm-setting-team.c +++ b/libnm-core/nm-setting-team.c @@ -1003,6 +1003,7 @@ nm_setting_team_get_runner_tx_hash (NMSettingTeam *setting, guint idx) NMSettingTeamPrivate *priv = NM_SETTING_TEAM_GET_PRIVATE (setting); g_return_val_if_fail (NM_IS_SETTING_TEAM (setting), NULL); + g_return_val_if_fail (priv->runner_tx_hash, NULL); g_return_val_if_fail (idx < priv->runner_tx_hash->len, NULL); return priv->runner_tx_hash->pdata[idx]; @@ -1023,6 +1024,7 @@ nm_setting_team_remove_runner_tx_hash (NMSettingTeam *setting, guint idx) NMSettingTeamPrivate *priv = NM_SETTING_TEAM_GET_PRIVATE (setting); g_return_if_fail (NM_IS_SETTING_TEAM (setting)); + g_return_if_fail (priv->runner_tx_hash); g_return_if_fail (idx < priv->runner_tx_hash->len); g_ptr_array_remove_index (priv->runner_tx_hash, idx); diff --git a/libnm-core/nm-setting-vlan.c b/libnm-core/nm-setting-vlan.c index 5b8a49d48b..f07504aa3e 100644 --- a/libnm-core/nm-setting-vlan.c +++ b/libnm-core/nm-setting-vlan.c @@ -25,6 +25,7 @@ #include <stdlib.h> +#include "nm-libnm-core-utils.h" #include "nm-utils.h" #include "nm-core-types-internal.h" #include "nm-setting-connection.h" @@ -106,48 +107,33 @@ nm_setting_vlan_get_flags (NMSettingVlan *setting) return NM_SETTING_VLAN_GET_PRIVATE (setting)->flags; } -static guint32 -get_max_prio (NMVlanPriorityMap map, gboolean from) +static NMVlanQosMapping * +priority_map_new (guint32 from, guint32 to) { - if (map == NM_VLAN_INGRESS_MAP) - return from ? MAX_8021P_PRIO : MAX_SKB_PRIO; - else if (map == NM_VLAN_EGRESS_MAP) - return from ? MAX_SKB_PRIO : MAX_8021P_PRIO; - g_assert_not_reached (); + NMVlanQosMapping *mapping; + + mapping = g_new (NMVlanQosMapping, 1); + *mapping = (NMVlanQosMapping) { + .from = from, + .to = to, + }; + return mapping; } static NMVlanQosMapping * priority_map_new_from_str (NMVlanPriorityMap map, const char *str) { - NMVlanQosMapping *p = NULL; - char **t = NULL; - guint32 len; - guint64 from, to; + guint32 from, to; - g_return_val_if_fail (str && str[0], NULL); - - t = g_strsplit (str, ":", 0); - len = g_strv_length (t); - if (len == 2) { - from = g_ascii_strtoull (t[0], NULL, 10); - to = g_ascii_strtoull (t[1], NULL, 10); - - if ((from <= get_max_prio (map, TRUE)) && (to <= get_max_prio (map, FALSE))) { - G_STATIC_ASSERT (sizeof (*p) == sizeof (p->from) + sizeof (p->to)); - p = g_malloc (sizeof (NMVlanQosMapping)); - p->from = from; - p->to = to; - } - } - - g_strfreev (t); - return p; + if (!nm_utils_vlan_priority_map_parse_str (map, str, FALSE, &from, &to, NULL)) + return NULL; + return priority_map_new (from, to); } static void priority_map_free (NMVlanQosMapping *map) { - g_return_if_fail (map != NULL); + nm_assert (map); g_free (map); } @@ -158,7 +144,7 @@ get_map (NMSettingVlan *self, NMVlanPriorityMap map) return NM_SETTING_VLAN_GET_PRIVATE (self)->ingress_priority_map; else if (map == NM_VLAN_EGRESS_MAP) return NM_SETTING_VLAN_GET_PRIVATE (self)->egress_priority_map; - g_assert_not_reached (); + nm_assert_not_reached (); return NULL; } @@ -207,7 +193,7 @@ set_map (NMSettingVlan *self, NMVlanPriorityMap map, GSList *list) NM_SETTING_VLAN_GET_PRIVATE (self)->egress_priority_map = list; _notify (self, PROP_EGRESS_PRIORITY_MAP); } else - g_assert_not_reached (); + nm_assert_not_reached (); } static gboolean @@ -489,6 +475,36 @@ nm_setting_vlan_remove_priority (NMSettingVlan *setting, set_map (setting, map, g_slist_delete_link (list, item)); } +static gboolean +priority_map_remove_by_value (NMSettingVlan *setting, + NMVlanPriorityMap map, + guint32 from, + guint32 to, + gboolean wildcard_to) +{ + GSList *list = NULL, *iter = NULL; + NMVlanQosMapping *item; + + nm_assert (NM_IS_SETTING_VLAN (setting)); + nm_assert (NM_IN_SET (map, NM_VLAN_INGRESS_MAP, NM_VLAN_EGRESS_MAP)); + + list = get_map (setting, map); + for (iter = list; iter; iter = g_slist_next (iter)) { + item = iter->data; + + if (item->from != from) + continue; + if ( !wildcard_to + && item->to != to) + continue; + + priority_map_free ((NMVlanQosMapping *) (iter->data)); + set_map (setting, map, g_slist_delete_link (list, iter)); + return TRUE; + } + return FALSE; +} + /** * nm_setting_vlan_remove_priority_by_value: * @setting: the #NMSettingVlan @@ -508,22 +524,10 @@ nm_setting_vlan_remove_priority_by_value (NMSettingVlan *setting, guint32 from, guint32 to) { - GSList *list = NULL, *iter = NULL; - NMVlanQosMapping *item; - g_return_val_if_fail (NM_IS_SETTING_VLAN (setting), FALSE); g_return_val_if_fail (map == NM_VLAN_INGRESS_MAP || map == NM_VLAN_EGRESS_MAP, FALSE); - list = get_map (setting, map); - for (iter = list; iter; iter = g_slist_next (iter)) { - item = iter->data; - if (item->from == from && item->to == to) { - priority_map_free ((NMVlanQosMapping *) (iter->data)); - set_map (setting, map, g_slist_delete_link (list, iter)); - return TRUE; - } - } - return FALSE; + return priority_map_remove_by_value (setting, map, from, to, FALSE); } /** @@ -543,19 +547,15 @@ nm_setting_vlan_remove_priority_str_by_value (NMSettingVlan *setting, NMVlanPriorityMap map, const char *str) { - NMVlanQosMapping *item; - gboolean found; + gboolean is_wildcard_to; + guint32 from, to; g_return_val_if_fail (NM_IS_SETTING_VLAN (setting), FALSE); g_return_val_if_fail (map == NM_VLAN_INGRESS_MAP || map == NM_VLAN_EGRESS_MAP, FALSE); - item = priority_map_new_from_str (map, str); - if (!item) + if (!nm_utils_vlan_priority_map_parse_str (map, str, TRUE, &from, &to, &is_wildcard_to)) return FALSE; - - found = nm_setting_vlan_remove_priority_by_value (setting, map, item->from, item->to); - g_free (item); - return found; + return priority_map_remove_by_value (setting, map, from, to, is_wildcard_to); } /** @@ -703,18 +703,16 @@ static GSList * priority_strv_to_maplist (NMVlanPriorityMap map, char **strv) { GSList *list = NULL; - int i; + gsize i; for (i = 0; strv && strv[i]; i++) { - NMVlanQosMapping *item; + guint32 from, to; - item = priority_map_new_from_str (map, strv[i]); - if (item) { - if (!check_replace_duplicate_priority (list, item->from, item->to)) - list = g_slist_prepend (list, item); - else - g_free (item); - } + if (!nm_utils_vlan_priority_map_parse_str (map, strv[i], FALSE, &from, &to, NULL)) + continue; + if (check_replace_duplicate_priority (list, from, to)) + continue; + list = g_slist_prepend (list, priority_map_new (from, to)); } return g_slist_sort (list, prio_map_compare); } diff --git a/libnm-core/nm-setting-vpn.c b/libnm-core/nm-setting-vpn.c index 20a0ae14a0..fc4b538ad2 100644 --- a/libnm-core/nm-setting-vpn.c +++ b/libnm-core/nm-setting-vpn.c @@ -173,10 +173,8 @@ nm_setting_vpn_add_data_item (NMSettingVpn *setting, const char *item) { g_return_if_fail (NM_IS_SETTING_VPN (setting)); - g_return_if_fail (key != NULL); - g_return_if_fail (strlen (key) > 0); - g_return_if_fail (item != NULL); - g_return_if_fail (strlen (item) > 0); + g_return_if_fail (key && key[0]); + g_return_if_fail (item && item[0]); g_hash_table_insert (NM_SETTING_VPN_GET_PRIVATE (setting)->data, g_strdup (key), g_strdup (item)); @@ -242,6 +240,7 @@ nm_setting_vpn_remove_data_item (NMSettingVpn *setting, const char *key) gboolean found; g_return_val_if_fail (NM_IS_SETTING_VPN (setting), FALSE); + g_return_val_if_fail (key, FALSE); found = g_hash_table_remove (NM_SETTING_VPN_GET_PRIVATE (setting)->data, key); if (found) @@ -350,10 +349,8 @@ nm_setting_vpn_add_secret (NMSettingVpn *setting, const char *secret) { g_return_if_fail (NM_IS_SETTING_VPN (setting)); - g_return_if_fail (key != NULL); - g_return_if_fail (strlen (key) > 0); - g_return_if_fail (secret != NULL); - g_return_if_fail (strlen (secret) > 0); + g_return_if_fail (key && key[0]); + g_return_if_fail (secret && secret[0]); g_hash_table_insert (NM_SETTING_VPN_GET_PRIVATE (setting)->secrets, g_strdup (key), g_strdup (secret)); @@ -419,6 +416,7 @@ nm_setting_vpn_remove_secret (NMSettingVpn *setting, const char *key) gboolean found; g_return_val_if_fail (NM_IS_SETTING_VPN (setting), FALSE); + g_return_val_if_fail (key, FALSE); found = g_hash_table_remove (NM_SETTING_VPN_GET_PRIVATE (setting)->secrets, key); if (found) diff --git a/libnm-core/nm-setting-wired.c b/libnm-core/nm-setting-wired.c index ef23294fda..7f0843046d 100644 --- a/libnm-core/nm-setting-wired.c +++ b/libnm-core/nm-setting-wired.c @@ -483,8 +483,7 @@ nm_setting_wired_get_s390_option_by_key (NMSettingWired *setting, const char *key) { g_return_val_if_fail (NM_IS_SETTING_WIRED (setting), NULL); - g_return_val_if_fail (key != NULL, NULL); - g_return_val_if_fail (strlen (key), NULL); + g_return_val_if_fail (key && key[0], NULL); return g_hash_table_lookup (NM_SETTING_WIRED_GET_PRIVATE (setting)->s390_options, key); } @@ -508,17 +507,11 @@ nm_setting_wired_add_s390_option (NMSettingWired *setting, const char *key, const char *value) { - size_t value_len; - g_return_val_if_fail (NM_IS_SETTING_WIRED (setting), FALSE); - g_return_val_if_fail (key != NULL, FALSE); - g_return_val_if_fail (strlen (key), FALSE); + g_return_val_if_fail (key && key[0], FALSE); g_return_val_if_fail (g_strv_contains (valid_s390_opts, key), FALSE); g_return_val_if_fail (value != NULL, FALSE); - value_len = strlen (value); - g_return_val_if_fail (value_len > 0 && value_len < 200, FALSE); - g_hash_table_insert (NM_SETTING_WIRED_GET_PRIVATE (setting)->s390_options, g_strdup (key), g_strdup (value)); @@ -544,8 +537,7 @@ nm_setting_wired_remove_s390_option (NMSettingWired *setting, gboolean found; g_return_val_if_fail (NM_IS_SETTING_WIRED (setting), FALSE); - g_return_val_if_fail (key != NULL, FALSE); - g_return_val_if_fail (strlen (key), FALSE); + g_return_val_if_fail (key && key[0], FALSE); found = g_hash_table_remove (NM_SETTING_WIRED_GET_PRIVATE (setting)->s390_options, key); if (found) @@ -683,7 +675,7 @@ verify (NMSetting *setting, NMConnection *connection, GError **error) g_hash_table_iter_init (&iter, priv->s390_options); while (g_hash_table_iter_next (&iter, (gpointer) &key, (gpointer) &value)) { if ( !g_strv_contains (valid_s390_opts, key) - || !strlen (value) + || value[0] == '\0' || (strlen (value) > 200)) { g_set_error (error, NM_CONNECTION_ERROR, diff --git a/libnm-core/nm-utils.c b/libnm-core/nm-utils.c index 854bfec794..9f3b209ccf 100644 --- a/libnm-core/nm-utils.c +++ b/libnm-core/nm-utils.c @@ -2962,8 +2962,7 @@ nm_utils_sriov_vf_from_str (const char *str, GError **error) detail = strchr (str, ' '); if (detail) { - index_free = g_strndup (str, detail - str); - str = index_free; + str = nm_strndup_a (200, str, detail - str, &index_free); detail++; } diff --git a/libnm-core/tests/test-general.c b/libnm-core/tests/test-general.c index 7d97296ab4..6d5eeb2810 100644 --- a/libnm-core/tests/test-general.c +++ b/libnm-core/tests/test-general.c @@ -80,6 +80,29 @@ G_STATIC_ASSERT (sizeof (bool) <= sizeof (int)); /*****************************************************************************/ +static void +test_nm_ascii_spaces (void) +{ + int i; + const char *const S = NM_ASCII_SPACES; + + for (i = 0; S[i]; i++) + g_assert (!strchr (&S[i + 1], S[i])); + + for (i = 0; S[i] != '\0'; i++) + g_assert (g_ascii_isspace (S[i])); + + g_assert (!g_ascii_isspace ((char) 0)); + for (i = 1; i < 0x100; i++) { + if (g_ascii_isspace ((char) i)) + g_assert (strchr (S, (char) i)); + else + g_assert (!strchr (S, (char) i)); + } +} + +/*****************************************************************************/ + typedef struct _nm_packed { int v0; char v1; @@ -809,54 +832,54 @@ test_setting_vpn_items (void) nm_setting_vpn_remove_data_item (s_vpn, "foobar4-flags"); /* Try to add some blank values and make sure they are rejected */ - NMTST_EXPECT_LIBNM_CRITICAL (NMTST_G_RETURN_MSG (key != NULL)); + NMTST_EXPECT_LIBNM_CRITICAL (NMTST_G_RETURN_MSG (key && key[0])); nm_setting_vpn_add_data_item (s_vpn, NULL, NULL); g_test_assert_expected_messages (); - NMTST_EXPECT_LIBNM_CRITICAL (NMTST_G_RETURN_MSG (strlen (key) > 0)); + NMTST_EXPECT_LIBNM_CRITICAL (NMTST_G_RETURN_MSG (key && key[0])); nm_setting_vpn_add_data_item (s_vpn, "", ""); g_test_assert_expected_messages (); - NMTST_EXPECT_LIBNM_CRITICAL (NMTST_G_RETURN_MSG (item != NULL)); + NMTST_EXPECT_LIBNM_CRITICAL (NMTST_G_RETURN_MSG (item && item[0])); nm_setting_vpn_add_data_item (s_vpn, "foobar1", NULL); g_test_assert_expected_messages (); - NMTST_EXPECT_LIBNM_CRITICAL (NMTST_G_RETURN_MSG (strlen (item) > 0)); + NMTST_EXPECT_LIBNM_CRITICAL (NMTST_G_RETURN_MSG (item && item[0])); nm_setting_vpn_add_data_item (s_vpn, "foobar1", ""); g_test_assert_expected_messages (); - NMTST_EXPECT_LIBNM_CRITICAL (NMTST_G_RETURN_MSG (key != NULL)); + NMTST_EXPECT_LIBNM_CRITICAL (NMTST_G_RETURN_MSG (key && key[0])); nm_setting_vpn_add_data_item (s_vpn, NULL, "blahblah1"); g_test_assert_expected_messages (); - NMTST_EXPECT_LIBNM_CRITICAL (NMTST_G_RETURN_MSG (strlen (key) > 0)); + NMTST_EXPECT_LIBNM_CRITICAL (NMTST_G_RETURN_MSG (key && key[0])); nm_setting_vpn_add_data_item (s_vpn, "", "blahblah1"); g_test_assert_expected_messages (); nm_setting_vpn_foreach_data_item (s_vpn, vpn_check_empty_func, NULL); /* Try to add some blank secrets and make sure they are rejected */ - NMTST_EXPECT_LIBNM_CRITICAL (NMTST_G_RETURN_MSG (key != NULL)); + NMTST_EXPECT_LIBNM_CRITICAL (NMTST_G_RETURN_MSG (key && key[0])); nm_setting_vpn_add_secret (s_vpn, NULL, NULL); g_test_assert_expected_messages (); - NMTST_EXPECT_LIBNM_CRITICAL (NMTST_G_RETURN_MSG (strlen (key) > 0)); + NMTST_EXPECT_LIBNM_CRITICAL (NMTST_G_RETURN_MSG (key && key[0])); nm_setting_vpn_add_secret (s_vpn, "", ""); g_test_assert_expected_messages (); - NMTST_EXPECT_LIBNM_CRITICAL (NMTST_G_RETURN_MSG (secret != NULL)); + NMTST_EXPECT_LIBNM_CRITICAL (NMTST_G_RETURN_MSG (secret && secret[0])); nm_setting_vpn_add_secret (s_vpn, "foobar1", NULL); g_test_assert_expected_messages (); - NMTST_EXPECT_LIBNM_CRITICAL (NMTST_G_RETURN_MSG (strlen (secret) > 0)); + NMTST_EXPECT_LIBNM_CRITICAL (NMTST_G_RETURN_MSG (secret && secret[0])); nm_setting_vpn_add_secret (s_vpn, "foobar1", ""); g_test_assert_expected_messages (); - NMTST_EXPECT_LIBNM_CRITICAL (NMTST_G_RETURN_MSG (key != NULL)); + NMTST_EXPECT_LIBNM_CRITICAL (NMTST_G_RETURN_MSG (key && key[0])); nm_setting_vpn_add_secret (s_vpn, NULL, "blahblah1"); g_test_assert_expected_messages (); - NMTST_EXPECT_LIBNM_CRITICAL (NMTST_G_RETURN_MSG (strlen (key) > 0)); + NMTST_EXPECT_LIBNM_CRITICAL (NMTST_G_RETURN_MSG (key && key[0])); nm_setting_vpn_add_secret (s_vpn, "", "blahblah1"); g_test_assert_expected_messages (); @@ -2347,7 +2370,7 @@ test_setting_connection_permissions_helpers (void) g_assert (!success); /* Ensure a bad [type] is rejected */ - NMTST_EXPECT_LIBNM_CRITICAL (NMTST_G_RETURN_MSG (ptype)); + NMTST_EXPECT_LIBNM_CRITICAL (NMTST_G_RETURN_MSG (ptype && ptype[0])); success = nm_setting_connection_add_permission (s_con, NULL, "blah", NULL); g_test_assert_expected_messages (); g_assert (!success); @@ -7734,23 +7757,72 @@ test_nm_utils_escape_spaces (void) } static void -test_nm_utils_unescape_spaces (void) +_do_test_unescape_spaces (const char *in, const char *out) { -#define CHECK_STR(in, out) \ - G_STMT_START { \ - gs_free char *str = g_strdup (in); \ - \ - g_assert_cmpstr (_nm_utils_unescape_spaces (str), ==, out); \ - } G_STMT_END + nm_auto_free_gstring GString *str_out = g_string_new (NULL); + nm_auto_free_gstring GString *str_in = g_string_new (NULL); + guint i; - CHECK_STR ("\\a", "\\a"); - CHECK_STR ("foobar", "foobar"); - CHECK_STR ("foo bar", "foo bar"); - CHECK_STR ("foo\\ bar", "foo bar"); - CHECK_STR ("foo\\", "foo\\"); - CHECK_STR ("\\\\\t", "\\\t"); + for (i = 0; i < 10; i++) { -#undef CHECK_STR + g_string_set_size (str_in, 0); + + g_string_append (str_in, in); + + if (i == 0) + g_assert_cmpstr (_nm_utils_unescape_spaces (str_in->str, FALSE), ==, out); + else if (i == 1) + g_assert_cmpstr (_nm_utils_unescape_spaces (str_in->str, TRUE), ==, out); + else { + bool do_strip = nmtst_get_rand_bool (); + guint n = nmtst_get_rand_int () % 20; + guint j; + + g_string_set_size (str_out, 0); + if (!do_strip) + g_string_append (str_out, out); + + for (j = 0; j < n; j++) { + gboolean append = nmtst_get_rand_bool (); + char ch = nmtst_rand_select (' ', '\t'); + + if (append && out[strlen (out) - 1] == '\\') + append = FALSE; + + g_string_insert_c (str_in, append ? -1 : 0, ch); + if (!do_strip) + g_string_insert_c (str_out, append ? -1 : 0, ch); + } + + if (do_strip) + g_assert_cmpstr (_nm_utils_unescape_spaces (str_in->str, TRUE), ==, out); + else + g_assert_cmpstr (_nm_utils_unescape_spaces (str_in->str, FALSE), ==, str_out->str); + } + } +} + +static void +test_nm_utils_unescape_spaces (void) +{ + _do_test_unescape_spaces ("", ""); + _do_test_unescape_spaces ("\\", "\\"); + _do_test_unescape_spaces ("\\ ", " "); + _do_test_unescape_spaces ("\\\t", "\t"); + _do_test_unescape_spaces ("a", "a"); + _do_test_unescape_spaces ("\\a", "\\a"); + _do_test_unescape_spaces ("foobar", "foobar"); + _do_test_unescape_spaces ("foo bar", "foo bar"); + _do_test_unescape_spaces ("foo\\ bar", "foo bar"); + _do_test_unescape_spaces ("foo\\", "foo\\"); + _do_test_unescape_spaces ("\\\\", "\\\\"); + _do_test_unescape_spaces ("foo bar", "foo bar"); + _do_test_unescape_spaces ("\\ foo bar", " foo bar"); + _do_test_unescape_spaces ("\\ foo bar\\ ", " foo bar "); + _do_test_unescape_spaces ("\\\tfoo bar\\\t", "\tfoo bar\t"); + _do_test_unescape_spaces ("\\\tfoo bar \\\t", "\tfoo bar \t"); + _do_test_unescape_spaces ("\\\t", "\t"); + _do_test_unescape_spaces ("\\\t \\ ", "\t "); } /*****************************************************************************/ @@ -7761,6 +7833,7 @@ int main (int argc, char **argv) { nmtst_init (&argc, &argv, TRUE); + g_test_add_func ("/core/general/test_nm_ascii_spaces", test_nm_ascii_spaces); g_test_add_func ("/core/general/test_nm_hash", test_nm_hash); g_test_add_func ("/core/general/test_nm_g_slice_free_fcn", test_nm_g_slice_free_fcn); g_test_add_func ("/core/general/test_c_list_sort", test_c_list_sort); diff --git a/libnm/nm-secret-agent-old.c b/libnm/nm-secret-agent-old.c index 56a88b004f..40485ab6c0 100644 --- a/libnm/nm-secret-agent-old.c +++ b/libnm/nm-secret-agent-old.c @@ -892,8 +892,7 @@ nm_secret_agent_old_get_secrets (NMSecretAgentOld *self, g_return_if_fail (NM_IS_SECRET_AGENT_OLD (self)); g_return_if_fail (NM_IS_CONNECTION (connection)); g_return_if_fail (nm_connection_get_path (connection)); - g_return_if_fail (setting_name != NULL); - g_return_if_fail (strlen (setting_name) > 0); + g_return_if_fail (setting_name && setting_name[0]); g_return_if_fail (!(flags & NM_SECRET_AGENT_GET_SECRETS_FLAG_ONLY_SYSTEM)); g_return_if_fail (!(flags & NM_SECRET_AGENT_GET_SECRETS_FLAG_NO_ERRORS)); g_return_if_fail (callback != NULL); diff --git a/shared/meson.build b/shared/meson.build index a6e94d6b88..f9d9e62bff 100644 --- a/shared/meson.build +++ b/shared/meson.build @@ -75,6 +75,8 @@ version_header = configure_file( shared_nm_ethtool_utils_c = files('nm-ethtool-utils.c') +shared_nm_libnm_core_utils_c = files('nm-libnm-core-utils.c') + shared_nm_meta_setting_c = files('nm-meta-setting.c') shared_nm_test_utils_impl_c = files('nm-test-utils-impl.c') diff --git a/shared/nm-libnm-core-utils.c b/shared/nm-libnm-core-utils.c new file mode 100644 index 0000000000..d1e5f75460 --- /dev/null +++ b/shared/nm-libnm-core-utils.c @@ -0,0 +1,76 @@ +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + */ + +#include "nm-default.h" + +#include "nm-libnm-core-utils.h" + +/*****************************************************************************/ + +gboolean +nm_utils_vlan_priority_map_parse_str (NMVlanPriorityMap map_type, + const char *str, + gboolean allow_wildcard_to, + guint32 *out_from, + guint32 *out_to, + gboolean *out_has_wildcard_to) +{ + const char *s2; + gint64 v1, v2; + + nm_assert (str); + + s2 = strchr (str, ':'); + + if (!s2) { + if (!allow_wildcard_to) + return FALSE; + v1 = _nm_utils_ascii_str_to_int64 (str, 10, 0, G_MAXUINT32, -1); + v2 = -1; + } else { + gs_free char *s1_free = NULL; + gsize s1_len = (s2 - str); + + s2 = nm_str_skip_leading_spaces (&s2[1]); + if ( s2[0] == '\0' + || ( s2[0] == '*' + && NM_STRCHAR_ALL (&s2[1], ch, g_ascii_isspace (ch)))) { + if (!allow_wildcard_to) + return FALSE; + v2 = -1; + } else { + v2 = _nm_utils_ascii_str_to_int64 (s2, 10, 0, G_MAXUINT32, -1); + if ( v2 < 0 + || (guint32) v2 > nm_utils_vlan_priority_map_get_max_prio (map_type, FALSE)) + return FALSE; + } + + v1 = _nm_utils_ascii_str_to_int64 (nm_strndup_a (100, str, s1_len, &s1_free), + 10, 0, G_MAXUINT32, -1); + } + + if ( v1 < 0 + || (guint32) v1 > nm_utils_vlan_priority_map_get_max_prio (map_type, TRUE)) + return FALSE; + + NM_SET_OUT (out_from, v1); + NM_SET_OUT (out_to, v2 < 0 + ? 0u + : (guint) v2); + NM_SET_OUT (out_has_wildcard_to, v2 < 0); + return TRUE; +} diff --git a/shared/nm-libnm-core-utils.h b/shared/nm-libnm-core-utils.h new file mode 100644 index 0000000000..3d06de00a2 --- /dev/null +++ b/shared/nm-libnm-core-utils.h @@ -0,0 +1,90 @@ +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + */ + +#ifndef __NM_LIBNM_SHARED_UTILS_H__ +#define __NM_LIBNM_SHARED_UTILS_H__ + +/****************************************************************************/ + +#include "nm-setting-connection.h" +#include "nm-setting-ip-config.h" +#include "nm-setting-ip4-config.h" +#include "nm-setting-ip6-config.h" +#include "nm-setting-sriov.h" +#include "nm-setting-team.h" +#include "nm-setting-vlan.h" +#include "nm-setting-wireguard.h" + +/****************************************************************************/ + +#define nm_auto_unref_ip_address nm_auto (_nm_ip_address_unref) +NM_AUTO_DEFINE_FCN0 (NMIPAddress *, _nm_ip_address_unref, nm_ip_address_unref) + +#define nm_auto_unref_ip_route nm_auto (_nm_auto_unref_ip_route) +NM_AUTO_DEFINE_FCN0 (NMIPRoute *, _nm_auto_unref_ip_route, nm_ip_route_unref) + +#define nm_auto_unref_sriov_vf nm_auto (_nm_auto_unref_sriov_vf) +NM_AUTO_DEFINE_FCN0 (NMSriovVF *, _nm_auto_unref_sriov_vf, nm_sriov_vf_unref) + +#define nm_auto_unref_tc_qdisc nm_auto (_nm_auto_unref_tc_qdisc) +NM_AUTO_DEFINE_FCN0 (NMTCQdisc *, _nm_auto_unref_tc_qdisc, nm_tc_qdisc_unref) + +#define nm_auto_unref_tc_tfilter nm_auto (_nm_auto_unref_tc_tfilter) +NM_AUTO_DEFINE_FCN0 (NMTCTfilter *, _nm_auto_unref_tc_tfilter, nm_tc_tfilter_unref) + +#define nm_auto_unref_team_link_watcher nm_auto (_nm_auto_unref_team_link_watcher) +NM_AUTO_DEFINE_FCN0 (NMTeamLinkWatcher *, _nm_auto_unref_team_link_watcher, nm_team_link_watcher_unref) + +#define nm_auto_unref_wgpeer nm_auto (_nm_auto_unref_wgpeer) +NM_AUTO_DEFINE_FCN0 (NMWireGuardPeer *, _nm_auto_unref_wgpeer, nm_wireguard_peer_unref) + +/****************************************************************************/ + +static inline guint32 +nm_utils_vlan_priority_map_get_max_prio (NMVlanPriorityMap map, gboolean from) +{ + if (map == NM_VLAN_INGRESS_MAP) { + return from + ? 7u /* MAX_8021P_PRIO */ + : (guint32) G_MAXUINT32 /* MAX_SKB_PRIO */; + } + nm_assert (map == NM_VLAN_EGRESS_MAP); + return from + ? (guint32) G_MAXUINT32 /* MAX_SKB_PRIO */ + : 7u /* MAX_8021P_PRIO */; +} + +gboolean nm_utils_vlan_priority_map_parse_str (NMVlanPriorityMap map_type, + const char *str, + gboolean allow_wildcard_to, + guint32 *out_from, + guint32 *out_to, + gboolean *out_has_wildcard_to); + +/*****************************************************************************/ + +static inline int +nm_setting_ip_config_get_addr_family (NMSettingIPConfig *s_ip) +{ + if (NM_IS_SETTING_IP4_CONFIG (s_ip)) + return AF_INET; + if (NM_IS_SETTING_IP6_CONFIG (s_ip)) + return AF_INET6; + g_return_val_if_reached (AF_UNSPEC); +} + +#endif /* __NM_LIBNM_SHARED_UTILS_H__ */ diff --git a/shared/nm-meta-setting.c b/shared/nm-meta-setting.c index e666e0b2a2..8d1d4ecd2a 100644 --- a/shared/nm-meta-setting.c +++ b/shared/nm-meta-setting.c @@ -82,6 +82,7 @@ const NMSetting8021xSchemeVtable nm_setting_8021x_scheme_vtable[] = { .uri_func = nm_setting_802_1x_get_ca_cert_uri, .passwd_func = nm_setting_802_1x_get_ca_cert_password, .pwflag_func = nm_setting_802_1x_get_ca_cert_password_flags, + .set_cert_func = nm_setting_802_1x_set_ca_cert, .file_suffix = "ca-cert", }, @@ -94,6 +95,7 @@ const NMSetting8021xSchemeVtable nm_setting_8021x_scheme_vtable[] = { .uri_func = nm_setting_802_1x_get_phase2_ca_cert_uri, .passwd_func = nm_setting_802_1x_get_phase2_ca_cert_password, .pwflag_func = nm_setting_802_1x_get_phase2_ca_cert_password_flags, + .set_cert_func = nm_setting_802_1x_set_phase2_ca_cert, .file_suffix = "inner-ca-cert", }, @@ -106,6 +108,7 @@ const NMSetting8021xSchemeVtable nm_setting_8021x_scheme_vtable[] = { .uri_func = nm_setting_802_1x_get_client_cert_uri, .passwd_func = nm_setting_802_1x_get_client_cert_password, .pwflag_func = nm_setting_802_1x_get_client_cert_password_flags, + .set_cert_func = nm_setting_802_1x_set_client_cert, .file_suffix = "client-cert", }, @@ -118,6 +121,7 @@ const NMSetting8021xSchemeVtable nm_setting_8021x_scheme_vtable[] = { .uri_func = nm_setting_802_1x_get_phase2_client_cert_uri, .passwd_func = nm_setting_802_1x_get_phase2_client_cert_password, .pwflag_func = nm_setting_802_1x_get_phase2_client_cert_password_flags, + .set_cert_func = nm_setting_802_1x_set_phase2_client_cert, .file_suffix = "inner-client-cert", }, @@ -130,7 +134,9 @@ const NMSetting8021xSchemeVtable nm_setting_8021x_scheme_vtable[] = { .uri_func = nm_setting_802_1x_get_private_key_uri, .passwd_func = nm_setting_802_1x_get_private_key_password, .pwflag_func = nm_setting_802_1x_get_private_key_password_flags, + .set_private_key_func = nm_setting_802_1x_set_private_key, .file_suffix = "private-key", + .is_secret = TRUE, }, [NM_SETTING_802_1X_SCHEME_TYPE_PHASE2_PRIVATE_KEY] = { @@ -142,7 +148,9 @@ const NMSetting8021xSchemeVtable nm_setting_8021x_scheme_vtable[] = { .uri_func = nm_setting_802_1x_get_phase2_private_key_uri, .passwd_func = nm_setting_802_1x_get_phase2_private_key_password, .pwflag_func = nm_setting_802_1x_get_phase2_private_key_password_flags, + .set_private_key_func = nm_setting_802_1x_set_phase2_private_key, .file_suffix = "inner-private-key", + .is_secret = TRUE, }, [NM_SETTING_802_1X_SCHEME_TYPE_UNKNOWN] = { NULL }, diff --git a/shared/nm-meta-setting.h b/shared/nm-meta-setting.h index 18727a1638..73ee103ee5 100644 --- a/shared/nm-meta-setting.h +++ b/shared/nm-meta-setting.h @@ -89,7 +89,19 @@ typedef struct { const char * (*uri_func) (NMSetting8021x *setting); const char * (*passwd_func) (NMSetting8021x *setting); NMSettingSecretFlags (*pwflag_func) (NMSetting8021x *setting); + gboolean (*set_cert_func) (NMSetting8021x *setting, + const char *value, + NMSetting8021xCKScheme scheme, + NMSetting8021xCKFormat *out_format, + GError **error); + gboolean (*set_private_key_func) (NMSetting8021x *setting, + const char *value, + const char *password, + NMSetting8021xCKScheme scheme, + NMSetting8021xCKFormat *out_format, + GError **error); const char *file_suffix; + bool is_secret:1; } NMSetting8021xSchemeVtable; extern const NMSetting8021xSchemeVtable nm_setting_8021x_scheme_vtable[_NM_SETTING_802_1X_SCHEME_TYPE_NUM + 1]; diff --git a/shared/nm-utils/nm-macros-internal.h b/shared/nm-utils/nm-macros-internal.h index 42299c9635..2f4fd86de7 100644 --- a/shared/nm-utils/nm-macros-internal.h +++ b/shared/nm-utils/nm-macros-internal.h @@ -1334,6 +1334,9 @@ _NM_BACKPORT_SYMBOL_IMPL(version, return_type, func, _##func##_##version, args_t /*****************************************************************************/ +/* mirrors g_ascii_isspace() and what we consider spaces in general. */ +#define NM_ASCII_SPACES "\t\n\f\r " + #define nm_str_skip_leading_spaces(str) \ ({ \ typeof (*(str)) *_str = (str); \ diff --git a/shared/nm-utils/nm-shared-utils.c b/shared/nm-utils/nm-shared-utils.c index 93e0b97e20..215a87b59b 100644 --- a/shared/nm-utils/nm-shared-utils.c +++ b/shared/nm-utils/nm-shared-utils.c @@ -635,8 +635,16 @@ nm_utils_parse_inaddr (int addr_family, NMIPAddr addrbin; char addrstr_buf[MAX (INET_ADDRSTRLEN, INET6_ADDRSTRLEN)]; - if (!nm_utils_parse_inaddr_bin (addr_family, text, &addr_family, &addrbin)) + g_return_val_if_fail (text, FALSE); + + if (addr_family == AF_UNSPEC) + addr_family = strchr (text, ':') ? AF_INET6 : AF_INET; + else + g_return_val_if_fail (NM_IN_SET (addr_family, AF_INET, AF_INET6), FALSE); + + if (inet_pton (addr_family, text, &addrbin) != 1) return FALSE; + NM_SET_OUT (out_addr, g_strdup (inet_ntop (addr_family, &addrbin, addrstr_buf, sizeof (addrstr_buf)))); return TRUE; } @@ -954,6 +962,15 @@ comp_l: /*****************************************************************************/ +static void +_char_lookup_table_init (guint8 lookup[static 256], + const char *candidates) +{ + memset (lookup, 0, 256); + while (candidates[0] != '\0') + lookup[(guint8) ((candidates++)[0])] = 1; +} + /** * nm_utils_strsplit_set: * @str: the string to split. @@ -979,6 +996,8 @@ comp_l: * The strings to which the result strv array points to are allocated * after the returned result itself. Don't free the strings themself, * but free everything with g_free(). + * It is however safe and allowed to modify the indiviual strings, + * like "g_strstrip((char *) iter[0])". */ const char ** nm_utils_strsplit_set (const char *str, const char *delimiters, gboolean allow_escaping) @@ -997,9 +1016,8 @@ nm_utils_strsplit_set (const char *str, const char *delimiters, gboolean allow_e /* initialize lookup table for delimiter */ if (!delimiters) delimiters = " \t\n"; - memset (delimiters_table, 0, sizeof (delimiters_table)); - for (i = 0; delimiters[i]; i++) - delimiters_table[(guint8) delimiters[i]] = 1; + + _char_lookup_table_init (delimiters_table, delimiters); #define _is_delimiter(ch, delimiters_table, allow_esc, esc) \ ((delimiters_table)[(guint8) (ch)] != 0 && (!allow_esc || !esc)) @@ -2412,23 +2430,26 @@ _nm_utils_user_data_unpack (gpointer user_data, int nargs, ...) /*****************************************************************************/ -#define IS_SPACE(c) NM_IN_SET ((c), ' ', '\t') +#define _CH_LOOKUP(ch_lookup, ch) (!!((ch_lookup)[(guint8) (ch)])) const char * -_nm_utils_escape_spaces (const char *str, char **to_free) +_nm_utils_escape_plain (const char *str, const char *candidates, char **to_free) { const char *ptr = str; char *ret, *r; + guint8 ch_lookup[256]; *to_free = NULL; if (!str) return NULL; + _char_lookup_table_init (ch_lookup, candidates ?: NM_ASCII_SPACES); + while (TRUE) { if (!*ptr) return str; - if (IS_SPACE (*ptr)) + if (_CH_LOOKUP (ch_lookup, *ptr)) break; ptr++; } @@ -2438,7 +2459,7 @@ _nm_utils_escape_spaces (const char *str, char **to_free) r = ret; *to_free = ret; while (*ptr) { - if (IS_SPACE (*ptr)) + if (_CH_LOOKUP (ch_lookup, *ptr)) *r++ = '\\'; *r++ = *ptr++; } @@ -2448,25 +2469,42 @@ _nm_utils_escape_spaces (const char *str, char **to_free) } char * -_nm_utils_unescape_spaces (char *str) +_nm_utils_unescape_plain (char *str, const char *candidates, gboolean do_strip) { - guint i, j = 0; + gsize i = 0; + gsize j = 0; + gsize preserve_space_at = 0; + guint8 ch_lookup[256]; if (!str) return NULL; - for (i = 0; str[i]; i++) { - if (str[i] == '\\' && IS_SPACE (str[i+1])) + _char_lookup_table_init (ch_lookup, candidates ?: NM_ASCII_SPACES); + + if (do_strip) { + while (str[i] && _CH_LOOKUP (ch_lookup, str[i])) i++; + } + + for (; str[i]; i++) { + if ( str[i] == '\\' + && _CH_LOOKUP (ch_lookup, str[i+1])) { + preserve_space_at = j; + i++; + } str[j++] = str[i]; } str[j] = '\0'; + if (do_strip && j > 0) { + while ( --j > preserve_space_at + && _CH_LOOKUP (ch_lookup, str[j])) + str[j] = '\0'; + } + return str; } -#undef IS_SPACE - /*****************************************************************************/ typedef struct { diff --git a/shared/nm-utils/nm-shared-utils.h b/shared/nm-utils/nm-shared-utils.h index 51e57ee03f..f48bfede7e 100644 --- a/shared/nm-utils/nm-shared-utils.h +++ b/shared/nm-utils/nm-shared-utils.h @@ -1084,8 +1084,20 @@ void _nm_utils_user_data_unpack (gpointer user_data, int nargs, ...); /*****************************************************************************/ -const char *_nm_utils_escape_spaces (const char *str, char **to_free); -char *_nm_utils_unescape_spaces (char *str); +const char *_nm_utils_escape_plain (const char *str, const char *candidates, char **to_free); +char *_nm_utils_unescape_plain (char *str, const char *candidates, gboolean do_strip); + +static inline const char * +_nm_utils_escape_spaces (const char *str, char **to_free) +{ + return _nm_utils_escape_plain (str, NM_ASCII_SPACES, to_free); +} + +static inline char * +_nm_utils_unescape_spaces (char *str, gboolean do_strip) +{ + return _nm_utils_unescape_plain (str, NM_ASCII_SPACES, do_strip); +} /*****************************************************************************/ diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c index 7c1db225c0..7779319b7f 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c @@ -820,7 +820,7 @@ parse_route_line (const char *line, NMIPRoute **out_route, GError **error) { - nm_auto_ip_route_unref NMIPRoute *route = NULL; + nm_auto_unref_ip_route NMIPRoute *route = NULL; gs_free const char **words_free = NULL; const char *const*words; const char *s; @@ -1284,7 +1284,7 @@ read_route_file (int addr_family, for (line = strtok_r (contents, "\n", &contents_rest); line; line = strtok_r (NULL, "\n", &contents_rest)) { - nm_auto_ip_route_unref NMIPRoute *route = NULL; + nm_auto_unref_ip_route NMIPRoute *route = NULL; gs_free_error GError *local = NULL; int e; @@ -1449,7 +1449,7 @@ make_match_setting (shvarFile *ifcfg) if (!s_match) s_match = (NMSettingMatch *) nm_setting_match_new (); nm_setting_match_add_interface_name (s_match, - _nm_utils_unescape_spaces ((char *) strv[i])); + _nm_utils_unescape_spaces ((char *) strv[i], TRUE)); } } |
