nmcli: merge branch 'th/nmcli-list-options'

https://github.com/NetworkManager/NetworkManager/pull/317
This commit is contained in:
Thomas Haller 2019-03-25 10:15:08 +01:00
commit f224d6a853
28 changed files with 2300 additions and 2737 deletions

View file

@ -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 \

View file

@ -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);

View file

@ -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,151 +528,67 @@ 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);
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))) {
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 (!value) {
/* No value argument sets default value */
nmc_property_set_default_value (setting, prop);
return TRUE;
}
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;
}
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;
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;
}
return _set_fcn_call (property_info,
setting,
value,
error);
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;
}
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);
}
}
/*
* 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;
}
}
g_set_error_literal (error, 1, 0, _("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.
*
@ -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

View file

@ -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);

View file

@ -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,

View file

@ -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))) {

View file

@ -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);

File diff suppressed because it is too large Load diff

View file

@ -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;
@ -244,9 +242,6 @@ typedef struct {
struct _NMMetaPropertyTypData {
union {
struct {
gboolean (*fcn) (NMSetting *setting);
} get_with_default;
struct {
GType (*get_gtype) (void);
int min;
@ -271,16 +266,78 @@ struct _NMMetaPropertyTypData {
struct {
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;

View file

@ -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(

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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);
}

View file

@ -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)

View file

@ -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,

View file

@ -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++;
}

View file

@ -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);
@ -7733,24 +7756,73 @@ test_nm_utils_escape_spaces (void)
g_free (to_free);
}
static void
_do_test_unescape_spaces (const char *in, const char *out)
{
nm_auto_free_gstring GString *str_out = g_string_new (NULL);
nm_auto_free_gstring GString *str_in = g_string_new (NULL);
guint i;
for (i = 0; i < 10; i++) {
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)
{
#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
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");
#undef CHECK_STR
_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);

View file

@ -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);

View file

@ -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')

View file

@ -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;
}

View file

@ -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__ */

View file

@ -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 },

View file

@ -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];

View file

@ -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); \

View file

@ -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 {

View file

@ -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);
}
/*****************************************************************************/

View file

@ -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));
}
}